aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/mac80211/ieee80211_i.h2
-rw-r--r--net/mac80211/mesh.h4
-rw-r--r--net/mac80211/rx.c89
-rw-r--r--net/mac80211/util.c73
-rw-r--r--net/mac80211/wme.c30
-rw-r--r--net/wireless/util.c305
6 files changed, 310 insertions, 193 deletions
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 8db8d16d206c..c088c46704a3 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1085,8 +1085,6 @@ static inline int __ieee80211_resume(struct ieee80211_hw *hw)
1085 1085
1086/* utility functions/constants */ 1086/* utility functions/constants */
1087extern void *mac80211_wiphy_privid; /* for wiphy privid */ 1087extern void *mac80211_wiphy_privid; /* for wiphy privid */
1088extern const unsigned char rfc1042_header[6];
1089extern const unsigned char bridge_tunnel_header[6];
1090u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len, 1088u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len,
1091 enum nl80211_iftype type); 1089 enum nl80211_iftype type);
1092int ieee80211_frame_duration(struct ieee80211_local *local, size_t len, 1090int ieee80211_frame_duration(struct ieee80211_local *local, size_t len,
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
index 832bb503ca9b..c7d72819cdd2 100644
--- a/net/mac80211/mesh.h
+++ b/net/mac80211/mesh.h
@@ -191,12 +191,8 @@ struct mesh_rmc {
191#define PLINK_CATEGORY 30 191#define PLINK_CATEGORY 30
192#define MESH_PATH_SEL_CATEGORY 32 192#define MESH_PATH_SEL_CATEGORY 32
193 193
194/* Mesh Header Flags */
195#define IEEE80211S_FLAGS_AE 0x3
196
197/* Public interfaces */ 194/* Public interfaces */
198/* Various */ 195/* Various */
199int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr);
200int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr, 196int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr,
201 struct ieee80211_sub_if_data *sdata); 197 struct ieee80211_sub_if_data *sdata);
202int mesh_rmc_check(u8 *addr, struct ieee80211s_hdr *mesh_hdr, 198int mesh_rmc_check(u8 *addr, struct ieee80211s_hdr *mesh_hdr,
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index f3a041cc5dcf..6a9b8e63a6bf 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -1247,93 +1247,12 @@ ieee80211_drop_unencrypted(struct ieee80211_rx_data *rx, __le16 fc)
1247} 1247}
1248 1248
1249static int 1249static int
1250ieee80211_data_to_8023(struct ieee80211_rx_data *rx) 1250__ieee80211_data_to_8023(struct ieee80211_rx_data *rx)
1251{ 1251{
1252 struct net_device *dev = rx->dev; 1252 struct net_device *dev = rx->dev;
1253 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data;
1254 u16 hdrlen, ethertype;
1255 u8 *payload;
1256 u8 dst[ETH_ALEN];
1257 u8 src[ETH_ALEN] __aligned(2);
1258 struct sk_buff *skb = rx->skb;
1259 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); 1253 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
1260 1254
1261 if (unlikely(!ieee80211_is_data_present(hdr->frame_control))) 1255 return ieee80211_data_to_8023(rx->skb, dev->dev_addr, sdata->vif.type);
1262 return -1;
1263
1264 hdrlen = ieee80211_hdrlen(hdr->frame_control);
1265
1266 /* convert IEEE 802.11 header + possible LLC headers into Ethernet
1267 * header
1268 * IEEE 802.11 address fields:
1269 * ToDS FromDS Addr1 Addr2 Addr3 Addr4
1270 * 0 0 DA SA BSSID n/a
1271 * 0 1 DA BSSID SA n/a
1272 * 1 0 BSSID SA DA n/a
1273 * 1 1 RA TA DA SA
1274 */
1275 memcpy(dst, ieee80211_get_DA(hdr), ETH_ALEN);
1276 memcpy(src, ieee80211_get_SA(hdr), ETH_ALEN);
1277
1278 switch (hdr->frame_control &
1279 cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) {
1280 case cpu_to_le16(IEEE80211_FCTL_TODS):
1281 if (unlikely(sdata->vif.type != NL80211_IFTYPE_AP &&
1282 sdata->vif.type != NL80211_IFTYPE_AP_VLAN))
1283 return -1;
1284 break;
1285 case cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS):
1286 if (unlikely(sdata->vif.type != NL80211_IFTYPE_WDS &&
1287 sdata->vif.type != NL80211_IFTYPE_MESH_POINT))
1288 return -1;
1289 if (ieee80211_vif_is_mesh(&sdata->vif)) {
1290 struct ieee80211s_hdr *meshdr = (struct ieee80211s_hdr *)
1291 (skb->data + hdrlen);
1292 hdrlen += ieee80211_get_mesh_hdrlen(meshdr);
1293 if (meshdr->flags & MESH_FLAGS_AE_A5_A6) {
1294 memcpy(dst, meshdr->eaddr1, ETH_ALEN);
1295 memcpy(src, meshdr->eaddr2, ETH_ALEN);
1296 }
1297 }
1298 break;
1299 case cpu_to_le16(IEEE80211_FCTL_FROMDS):
1300 if (sdata->vif.type != NL80211_IFTYPE_STATION ||
1301 (is_multicast_ether_addr(dst) &&
1302 !compare_ether_addr(src, dev->dev_addr)))
1303 return -1;
1304 break;
1305 case cpu_to_le16(0):
1306 if (sdata->vif.type != NL80211_IFTYPE_ADHOC)
1307 return -1;
1308 break;
1309 }
1310
1311 if (unlikely(skb->len - hdrlen < 8))
1312 return -1;
1313
1314 payload = skb->data + hdrlen;
1315 ethertype = (payload[6] << 8) | payload[7];
1316
1317 if (likely((compare_ether_addr(payload, rfc1042_header) == 0 &&
1318 ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) ||
1319 compare_ether_addr(payload, bridge_tunnel_header) == 0)) {
1320 /* remove RFC1042 or Bridge-Tunnel encapsulation and
1321 * replace EtherType */
1322 skb_pull(skb, hdrlen + 6);
1323 memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN);
1324 memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN);
1325 } else {
1326 struct ethhdr *ehdr;
1327 __be16 len;
1328
1329 skb_pull(skb, hdrlen);
1330 len = htons(skb->len);
1331 ehdr = (struct ethhdr *) skb_push(skb, sizeof(struct ethhdr));
1332 memcpy(ehdr->h_dest, dst, ETH_ALEN);
1333 memcpy(ehdr->h_source, src, ETH_ALEN);
1334 ehdr->h_proto = len;
1335 }
1336 return 0;
1337} 1256}
1338 1257
1339/* 1258/*
@@ -1472,7 +1391,7 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx)
1472 if (!(rx->flags & IEEE80211_RX_AMSDU)) 1391 if (!(rx->flags & IEEE80211_RX_AMSDU))
1473 return RX_CONTINUE; 1392 return RX_CONTINUE;
1474 1393
1475 err = ieee80211_data_to_8023(rx); 1394 err = __ieee80211_data_to_8023(rx);
1476 if (unlikely(err)) 1395 if (unlikely(err))
1477 return RX_DROP_UNUSABLE; 1396 return RX_DROP_UNUSABLE;
1478 1397
@@ -1658,7 +1577,7 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx)
1658 if (unlikely(!ieee80211_is_data_present(hdr->frame_control))) 1577 if (unlikely(!ieee80211_is_data_present(hdr->frame_control)))
1659 return RX_DROP_MONITOR; 1578 return RX_DROP_MONITOR;
1660 1579
1661 err = ieee80211_data_to_8023(rx); 1580 err = __ieee80211_data_to_8023(rx);
1662 if (unlikely(err)) 1581 if (unlikely(err))
1663 return RX_DROP_UNUSABLE; 1582 return RX_DROP_UNUSABLE;
1664 1583
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index ffb6e88f2ecd..949d857debd8 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -35,15 +35,6 @@
35/* privid for wiphys to determine whether they belong to us or not */ 35/* privid for wiphys to determine whether they belong to us or not */
36void *mac80211_wiphy_privid = &mac80211_wiphy_privid; 36void *mac80211_wiphy_privid = &mac80211_wiphy_privid;
37 37
38/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */
39/* Ethernet-II snap header (RFC1042 for most EtherTypes) */
40const unsigned char rfc1042_header[] __aligned(2) =
41 { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
42
43/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */
44const unsigned char bridge_tunnel_header[] __aligned(2) =
45 { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 };
46
47struct ieee80211_hw *wiphy_to_ieee80211_hw(struct wiphy *wiphy) 38struct ieee80211_hw *wiphy_to_ieee80211_hw(struct wiphy *wiphy)
48{ 39{
49 struct ieee80211_local *local; 40 struct ieee80211_local *local;
@@ -103,70 +94,6 @@ u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len,
103 return NULL; 94 return NULL;
104} 95}
105 96
106unsigned int ieee80211_hdrlen(__le16 fc)
107{
108 unsigned int hdrlen = 24;
109
110 if (ieee80211_is_data(fc)) {
111 if (ieee80211_has_a4(fc))
112 hdrlen = 30;
113 if (ieee80211_is_data_qos(fc))
114 hdrlen += IEEE80211_QOS_CTL_LEN;
115 goto out;
116 }
117
118 if (ieee80211_is_ctl(fc)) {
119 /*
120 * ACK and CTS are 10 bytes, all others 16. To see how
121 * to get this condition consider
122 * subtype mask: 0b0000000011110000 (0x00F0)
123 * ACK subtype: 0b0000000011010000 (0x00D0)
124 * CTS subtype: 0b0000000011000000 (0x00C0)
125 * bits that matter: ^^^ (0x00E0)
126 * value of those: 0b0000000011000000 (0x00C0)
127 */
128 if ((fc & cpu_to_le16(0x00E0)) == cpu_to_le16(0x00C0))
129 hdrlen = 10;
130 else
131 hdrlen = 16;
132 }
133out:
134 return hdrlen;
135}
136EXPORT_SYMBOL(ieee80211_hdrlen);
137
138unsigned int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb)
139{
140 const struct ieee80211_hdr *hdr = (const struct ieee80211_hdr *)skb->data;
141 unsigned int hdrlen;
142
143 if (unlikely(skb->len < 10))
144 return 0;
145 hdrlen = ieee80211_hdrlen(hdr->frame_control);
146 if (unlikely(hdrlen > skb->len))
147 return 0;
148 return hdrlen;
149}
150EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb);
151
152int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr)
153{
154 int ae = meshhdr->flags & IEEE80211S_FLAGS_AE;
155 /* 7.1.3.5a.2 */
156 switch (ae) {
157 case 0:
158 return 6;
159 case 1:
160 return 12;
161 case 2:
162 return 18;
163 case 3:
164 return 24;
165 default:
166 return 6;
167 }
168}
169
170void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx) 97void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx)
171{ 98{
172 struct sk_buff *skb = tx->skb; 99 struct sk_buff *skb = tx->skb;
diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c
index 45b74f38b867..694343b9102b 100644
--- a/net/mac80211/wme.c
+++ b/net/mac80211/wme.c
@@ -23,34 +23,6 @@
23 */ 23 */
24const int ieee802_1d_to_ac[8] = { 2, 3, 3, 2, 1, 1, 0, 0 }; 24const int ieee802_1d_to_ac[8] = { 2, 3, 3, 2, 1, 1, 0, 0 };
25 25
26static const char llc_ip_hdr[8] = {0xAA, 0xAA, 0x3, 0, 0, 0, 0x08, 0};
27
28/* Given a data frame determine the 802.1p/1d tag to use. */
29static unsigned int classify_1d(struct sk_buff *skb)
30{
31 unsigned int dscp;
32
33 /* skb->priority values from 256->263 are magic values to
34 * directly indicate a specific 802.1d priority. This is used
35 * to allow 802.1d priority to be passed directly in from VLAN
36 * tags, etc.
37 */
38 if (skb->priority >= 256 && skb->priority <= 263)
39 return skb->priority - 256;
40
41 switch (skb->protocol) {
42 case htons(ETH_P_IP):
43 dscp = ip_hdr(skb)->tos & 0xfc;
44 break;
45
46 default:
47 return 0;
48 }
49
50 return dscp >> 5;
51}
52
53
54static int wme_downgrade_ac(struct sk_buff *skb) 26static int wme_downgrade_ac(struct sk_buff *skb)
55{ 27{
56 switch (skb->priority) { 28 switch (skb->priority) {
@@ -94,7 +66,7 @@ static u16 classify80211(struct ieee80211_local *local, struct sk_buff *skb)
94 66
95 /* use the data classifier to determine what 802.1d tag the 67 /* use the data classifier to determine what 802.1d tag the
96 * data frame has */ 68 * data frame has */
97 skb->priority = classify_1d(skb); 69 skb->priority = cfg80211_classify8021d(skb);
98 70
99 /* in case we are a client verify acm is not set for this ac */ 71 /* in case we are a client verify acm is not set for this ac */
100 while (unlikely(local->wmm_acm & BIT(skb->priority))) { 72 while (unlikely(local->wmm_acm & BIT(skb->priority))) {
diff --git a/net/wireless/util.c b/net/wireless/util.c
index b94c8604ad7c..d072bff463aa 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -4,7 +4,9 @@
4 * Copyright 2007-2009 Johannes Berg <johannes@sipsolutions.net> 4 * Copyright 2007-2009 Johannes Berg <johannes@sipsolutions.net>
5 */ 5 */
6#include <linux/bitops.h> 6#include <linux/bitops.h>
7#include <linux/etherdevice.h>
7#include <net/cfg80211.h> 8#include <net/cfg80211.h>
9#include <net/ip.h>
8#include "core.h" 10#include "core.h"
9 11
10struct ieee80211_rate * 12struct ieee80211_rate *
@@ -198,3 +200,306 @@ int cfg80211_validate_key_settings(struct key_params *params, int key_idx,
198 200
199 return 0; 201 return 0;
200} 202}
203
204/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */
205/* Ethernet-II snap header (RFC1042 for most EtherTypes) */
206const unsigned char rfc1042_header[] __aligned(2) =
207 { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
208EXPORT_SYMBOL(rfc1042_header);
209
210/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */
211const unsigned char bridge_tunnel_header[] __aligned(2) =
212 { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 };
213EXPORT_SYMBOL(bridge_tunnel_header);
214
215unsigned int ieee80211_hdrlen(__le16 fc)
216{
217 unsigned int hdrlen = 24;
218
219 if (ieee80211_is_data(fc)) {
220 if (ieee80211_has_a4(fc))
221 hdrlen = 30;
222 if (ieee80211_is_data_qos(fc))
223 hdrlen += IEEE80211_QOS_CTL_LEN;
224 goto out;
225 }
226
227 if (ieee80211_is_ctl(fc)) {
228 /*
229 * ACK and CTS are 10 bytes, all others 16. To see how
230 * to get this condition consider
231 * subtype mask: 0b0000000011110000 (0x00F0)
232 * ACK subtype: 0b0000000011010000 (0x00D0)
233 * CTS subtype: 0b0000000011000000 (0x00C0)
234 * bits that matter: ^^^ (0x00E0)
235 * value of those: 0b0000000011000000 (0x00C0)
236 */
237 if ((fc & cpu_to_le16(0x00E0)) == cpu_to_le16(0x00C0))
238 hdrlen = 10;
239 else
240 hdrlen = 16;
241 }
242out:
243 return hdrlen;
244}
245EXPORT_SYMBOL(ieee80211_hdrlen);
246
247unsigned int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb)
248{
249 const struct ieee80211_hdr *hdr =
250 (const struct ieee80211_hdr *)skb->data;
251 unsigned int hdrlen;
252
253 if (unlikely(skb->len < 10))
254 return 0;
255 hdrlen = ieee80211_hdrlen(hdr->frame_control);
256 if (unlikely(hdrlen > skb->len))
257 return 0;
258 return hdrlen;
259}
260EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb);
261
262int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr)
263{
264 int ae = meshhdr->flags & MESH_FLAGS_AE;
265 /* 7.1.3.5a.2 */
266 switch (ae) {
267 case 0:
268 return 6;
269 case 1:
270 return 12;
271 case 2:
272 return 18;
273 case 3:
274 return 24;
275 default:
276 return 6;
277 }
278}
279
280int ieee80211_data_to_8023(struct sk_buff *skb, u8 *addr,
281 enum nl80211_iftype iftype)
282{
283 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
284 u16 hdrlen, ethertype;
285 u8 *payload;
286 u8 dst[ETH_ALEN];
287 u8 src[ETH_ALEN] __aligned(2);
288
289 if (unlikely(!ieee80211_is_data_present(hdr->frame_control)))
290 return -1;
291
292 hdrlen = ieee80211_hdrlen(hdr->frame_control);
293
294 /* convert IEEE 802.11 header + possible LLC headers into Ethernet
295 * header
296 * IEEE 802.11 address fields:
297 * ToDS FromDS Addr1 Addr2 Addr3 Addr4
298 * 0 0 DA SA BSSID n/a
299 * 0 1 DA BSSID SA n/a
300 * 1 0 BSSID SA DA n/a
301 * 1 1 RA TA DA SA
302 */
303 memcpy(dst, ieee80211_get_DA(hdr), ETH_ALEN);
304 memcpy(src, ieee80211_get_SA(hdr), ETH_ALEN);
305
306 switch (hdr->frame_control &
307 cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) {
308 case cpu_to_le16(IEEE80211_FCTL_TODS):
309 if (unlikely(iftype != NL80211_IFTYPE_AP &&
310 iftype != NL80211_IFTYPE_AP_VLAN))
311 return -1;
312 break;
313 case cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS):
314 if (unlikely(iftype != NL80211_IFTYPE_WDS &&
315 iftype != NL80211_IFTYPE_MESH_POINT))
316 return -1;
317 if (iftype == NL80211_IFTYPE_MESH_POINT) {
318 struct ieee80211s_hdr *meshdr =
319 (struct ieee80211s_hdr *) (skb->data + hdrlen);
320 hdrlen += ieee80211_get_mesh_hdrlen(meshdr);
321 if (meshdr->flags & MESH_FLAGS_AE_A5_A6) {
322 memcpy(dst, meshdr->eaddr1, ETH_ALEN);
323 memcpy(src, meshdr->eaddr2, ETH_ALEN);
324 }
325 }
326 break;
327 case cpu_to_le16(IEEE80211_FCTL_FROMDS):
328 if (iftype != NL80211_IFTYPE_STATION ||
329 (is_multicast_ether_addr(dst) &&
330 !compare_ether_addr(src, addr)))
331 return -1;
332 break;
333 case cpu_to_le16(0):
334 if (iftype != NL80211_IFTYPE_ADHOC)
335 return -1;
336 break;
337 }
338
339 if (unlikely(skb->len - hdrlen < 8))
340 return -1;
341
342 payload = skb->data + hdrlen;
343 ethertype = (payload[6] << 8) | payload[7];
344
345 if (likely((compare_ether_addr(payload, rfc1042_header) == 0 &&
346 ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) ||
347 compare_ether_addr(payload, bridge_tunnel_header) == 0)) {
348 /* remove RFC1042 or Bridge-Tunnel encapsulation and
349 * replace EtherType */
350 skb_pull(skb, hdrlen + 6);
351 memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN);
352 memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN);
353 } else {
354 struct ethhdr *ehdr;
355 __be16 len;
356
357 skb_pull(skb, hdrlen);
358 len = htons(skb->len);
359 ehdr = (struct ethhdr *) skb_push(skb, sizeof(struct ethhdr));
360 memcpy(ehdr->h_dest, dst, ETH_ALEN);
361 memcpy(ehdr->h_source, src, ETH_ALEN);
362 ehdr->h_proto = len;
363 }
364 return 0;
365}
366EXPORT_SYMBOL(ieee80211_data_to_8023);
367
368int ieee80211_data_from_8023(struct sk_buff *skb, u8 *addr,
369 enum nl80211_iftype iftype, u8 *bssid, bool qos)
370{
371 struct ieee80211_hdr hdr;
372 u16 hdrlen, ethertype;
373 __le16 fc;
374 const u8 *encaps_data;
375 int encaps_len, skip_header_bytes;
376 int nh_pos, h_pos;
377 int head_need;
378
379 if (unlikely(skb->len < ETH_HLEN))
380 return -EINVAL;
381
382 nh_pos = skb_network_header(skb) - skb->data;
383 h_pos = skb_transport_header(skb) - skb->data;
384
385 /* convert Ethernet header to proper 802.11 header (based on
386 * operation mode) */
387 ethertype = (skb->data[12] << 8) | skb->data[13];
388 fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA);
389
390 switch (iftype) {
391 case NL80211_IFTYPE_AP:
392 case NL80211_IFTYPE_AP_VLAN:
393 fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS);
394 /* DA BSSID SA */
395 memcpy(hdr.addr1, skb->data, ETH_ALEN);
396 memcpy(hdr.addr2, addr, ETH_ALEN);
397 memcpy(hdr.addr3, skb->data + ETH_ALEN, ETH_ALEN);
398 hdrlen = 24;
399 break;
400 case NL80211_IFTYPE_STATION:
401 fc |= cpu_to_le16(IEEE80211_FCTL_TODS);
402 /* BSSID SA DA */
403 memcpy(hdr.addr1, bssid, ETH_ALEN);
404 memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);
405 memcpy(hdr.addr3, skb->data, ETH_ALEN);
406 hdrlen = 24;
407 break;
408 case NL80211_IFTYPE_ADHOC:
409 /* DA SA BSSID */
410 memcpy(hdr.addr1, skb->data, ETH_ALEN);
411 memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);
412 memcpy(hdr.addr3, bssid, ETH_ALEN);
413 hdrlen = 24;
414 break;
415 default:
416 return -EOPNOTSUPP;
417 }
418
419 if (qos) {
420 fc |= cpu_to_le16(IEEE80211_STYPE_QOS_DATA);
421 hdrlen += 2;
422 }
423
424 hdr.frame_control = fc;
425 hdr.duration_id = 0;
426 hdr.seq_ctrl = 0;
427
428 skip_header_bytes = ETH_HLEN;
429 if (ethertype == ETH_P_AARP || ethertype == ETH_P_IPX) {
430 encaps_data = bridge_tunnel_header;
431 encaps_len = sizeof(bridge_tunnel_header);
432 skip_header_bytes -= 2;
433 } else if (ethertype > 0x600) {
434 encaps_data = rfc1042_header;
435 encaps_len = sizeof(rfc1042_header);
436 skip_header_bytes -= 2;
437 } else {
438 encaps_data = NULL;
439 encaps_len = 0;
440 }
441
442 skb_pull(skb, skip_header_bytes);
443 nh_pos -= skip_header_bytes;
444 h_pos -= skip_header_bytes;
445
446 head_need = hdrlen + encaps_len - skb_headroom(skb);
447
448 if (head_need > 0 || skb_cloned(skb)) {
449 head_need = max(head_need, 0);
450 if (head_need)
451 skb_orphan(skb);
452
453 if (pskb_expand_head(skb, head_need, 0, GFP_ATOMIC)) {
454 printk(KERN_ERR "failed to reallocate Tx buffer\n");
455 return -ENOMEM;
456 }
457 skb->truesize += head_need;
458 }
459
460 if (encaps_data) {
461 memcpy(skb_push(skb, encaps_len), encaps_data, encaps_len);
462 nh_pos += encaps_len;
463 h_pos += encaps_len;
464 }
465
466 memcpy(skb_push(skb, hdrlen), &hdr, hdrlen);
467
468 nh_pos += hdrlen;
469 h_pos += hdrlen;
470
471 /* Update skb pointers to various headers since this modified frame
472 * is going to go through Linux networking code that may potentially
473 * need things like pointer to IP header. */
474 skb_set_mac_header(skb, 0);
475 skb_set_network_header(skb, nh_pos);
476 skb_set_transport_header(skb, h_pos);
477
478 return 0;
479}
480EXPORT_SYMBOL(ieee80211_data_from_8023);
481
482/* Given a data frame determine the 802.1p/1d tag to use. */
483unsigned int cfg80211_classify8021d(struct sk_buff *skb)
484{
485 unsigned int dscp;
486
487 /* skb->priority values from 256->263 are magic values to
488 * directly indicate a specific 802.1d priority. This is used
489 * to allow 802.1d priority to be passed directly in from VLAN
490 * tags, etc.
491 */
492 if (skb->priority >= 256 && skb->priority <= 263)
493 return skb->priority - 256;
494
495 switch (skb->protocol) {
496 case htons(ETH_P_IP):
497 dscp = ip_hdr(skb)->tos & 0xfc;
498 break;
499 default:
500 return 0;
501 }
502
503 return dscp >> 5;
504}
505EXPORT_SYMBOL(cfg80211_classify8021d);