diff options
-rw-r--r-- | Documentation/DocBook/mac80211.tmpl | 4 | ||||
-rw-r--r-- | net/mac80211/rx.c | 110 |
2 files changed, 79 insertions, 35 deletions
diff --git a/Documentation/DocBook/mac80211.tmpl b/Documentation/DocBook/mac80211.tmpl index 77c3c202991b..bdf908a6e545 100644 --- a/Documentation/DocBook/mac80211.tmpl +++ b/Documentation/DocBook/mac80211.tmpl | |||
@@ -165,8 +165,8 @@ usage should require reading the full document. | |||
165 | !Pinclude/net/mac80211.h Frame format | 165 | !Pinclude/net/mac80211.h Frame format |
166 | </sect1> | 166 | </sect1> |
167 | <sect1> | 167 | <sect1> |
168 | <title>Alignment issues</title> | 168 | <title>Packet alignment</title> |
169 | <para>TBD</para> | 169 | !Pnet/mac80211/rx.c Packet alignment |
170 | </sect1> | 170 | </sect1> |
171 | <sect1> | 171 | <sect1> |
172 | <title>Calling into mac80211 from interrupts</title> | 172 | <title>Calling into mac80211 from interrupts</title> |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index ddb966f58882..b68e082e99ce 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -102,7 +102,7 @@ ieee80211_rx_radiotap_len(struct ieee80211_local *local, | |||
102 | return len; | 102 | return len; |
103 | } | 103 | } |
104 | 104 | ||
105 | /** | 105 | /* |
106 | * ieee80211_add_rx_radiotap_header - add radiotap header | 106 | * ieee80211_add_rx_radiotap_header - add radiotap header |
107 | * | 107 | * |
108 | * add a radiotap header containing all the fields which the hardware provided. | 108 | * add a radiotap header containing all the fields which the hardware provided. |
@@ -371,39 +371,50 @@ static void ieee80211_parse_qos(struct ieee80211_rx_data *rx) | |||
371 | rx->skb->priority = (tid > 7) ? 0 : tid; | 371 | rx->skb->priority = (tid > 7) ? 0 : tid; |
372 | } | 372 | } |
373 | 373 | ||
374 | static void ieee80211_verify_ip_alignment(struct ieee80211_rx_data *rx) | 374 | /** |
375 | * DOC: Packet alignment | ||
376 | * | ||
377 | * Drivers always need to pass packets that are aligned to two-byte boundaries | ||
378 | * to the stack. | ||
379 | * | ||
380 | * Additionally, should, if possible, align the payload data in a way that | ||
381 | * guarantees that the contained IP header is aligned to a four-byte | ||
382 | * boundary. In the case of regular frames, this simply means aligning the | ||
383 | * payload to a four-byte boundary (because either the IP header is directly | ||
384 | * contained, or IV/RFC1042 headers that have a length divisible by four are | ||
385 | * in front of it). | ||
386 | * | ||
387 | * With A-MSDU frames, however, the payload data address must yield two modulo | ||
388 | * four because there are 14-byte 802.3 headers within the A-MSDU frames that | ||
389 | * push the IP header further back to a multiple of four again. Thankfully, the | ||
390 | * specs were sane enough this time around to require padding each A-MSDU | ||
391 | * subframe to a length that is a multiple of four. | ||
392 | * | ||
393 | * Padding like Atheros hardware adds which is inbetween the 802.11 header and | ||
394 | * the payload is not supported, the driver is required to move the 802.11 | ||
395 | * header to be directly in front of the payload in that case. | ||
396 | */ | ||
397 | static void ieee80211_verify_alignment(struct ieee80211_rx_data *rx) | ||
375 | { | 398 | { |
376 | #ifdef CONFIG_MAC80211_DEBUG_PACKET_ALIGNMENT | ||
377 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; | 399 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; |
378 | int hdrlen; | 400 | int hdrlen; |
379 | 401 | ||
402 | #ifndef CONFIG_MAC80211_DEBUG_PACKET_ALIGNMENT | ||
403 | return; | ||
404 | #endif | ||
405 | |||
406 | if (WARN_ONCE((unsigned long)rx->skb->data & 1, | ||
407 | "unaligned packet at 0x%p\n", rx->skb->data)) | ||
408 | return; | ||
409 | |||
380 | if (!ieee80211_is_data_present(hdr->frame_control)) | 410 | if (!ieee80211_is_data_present(hdr->frame_control)) |
381 | return; | 411 | return; |
382 | 412 | ||
383 | /* | ||
384 | * Drivers are required to align the payload data in a way that | ||
385 | * guarantees that the contained IP header is aligned to a four- | ||
386 | * byte boundary. In the case of regular frames, this simply means | ||
387 | * aligning the payload to a four-byte boundary (because either | ||
388 | * the IP header is directly contained, or IV/RFC1042 headers that | ||
389 | * have a length divisible by four are in front of it. | ||
390 | * | ||
391 | * With A-MSDU frames, however, the payload data address must | ||
392 | * yield two modulo four because there are 14-byte 802.3 headers | ||
393 | * within the A-MSDU frames that push the IP header further back | ||
394 | * to a multiple of four again. Thankfully, the specs were sane | ||
395 | * enough this time around to require padding each A-MSDU subframe | ||
396 | * to a length that is a multiple of four. | ||
397 | * | ||
398 | * Padding like atheros hardware adds which is inbetween the 802.11 | ||
399 | * header and the payload is not supported, the driver is required | ||
400 | * to move the 802.11 header further back in that case. | ||
401 | */ | ||
402 | hdrlen = ieee80211_hdrlen(hdr->frame_control); | 413 | hdrlen = ieee80211_hdrlen(hdr->frame_control); |
403 | if (rx->flags & IEEE80211_RX_AMSDU) | 414 | if (rx->flags & IEEE80211_RX_AMSDU) |
404 | hdrlen += ETH_HLEN; | 415 | hdrlen += ETH_HLEN; |
405 | WARN_ON_ONCE(((unsigned long)(rx->skb->data + hdrlen)) & 3); | 416 | WARN_ONCE(((unsigned long)(rx->skb->data + hdrlen)) & 3, |
406 | #endif | 417 | "unaligned IP payload at 0x%p\n", rx->skb->data + hdrlen); |
407 | } | 418 | } |
408 | 419 | ||
409 | 420 | ||
@@ -1267,10 +1278,37 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx) | |||
1267 | } | 1278 | } |
1268 | 1279 | ||
1269 | if (skb) { | 1280 | if (skb) { |
1270 | /* deliver to local stack */ | 1281 | int align __maybe_unused; |
1271 | skb->protocol = eth_type_trans(skb, dev); | 1282 | |
1272 | memset(skb->cb, 0, sizeof(skb->cb)); | 1283 | #if defined(CONFIG_MAC80211_DEBUG_PACKET_ALIGNMENT) || !defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) |
1273 | netif_rx(skb); | 1284 | /* |
1285 | * 'align' will only take the values 0 or 2 here | ||
1286 | * since all frames are required to be aligned | ||
1287 | * to 2-byte boundaries when being passed to | ||
1288 | * mac80211. That also explains the __skb_push() | ||
1289 | * below. | ||
1290 | */ | ||
1291 | align = (unsigned long)skb->data & 4; | ||
1292 | if (align) { | ||
1293 | if (WARN_ON(skb_headroom(skb) < 3)) { | ||
1294 | dev_kfree_skb(skb); | ||
1295 | skb = NULL; | ||
1296 | } else { | ||
1297 | u8 *data = skb->data; | ||
1298 | size_t len = skb->len; | ||
1299 | u8 *new = __skb_push(skb, align); | ||
1300 | memmove(new, data, len); | ||
1301 | __skb_trim(skb, len); | ||
1302 | } | ||
1303 | } | ||
1304 | #endif | ||
1305 | |||
1306 | if (skb) { | ||
1307 | /* deliver to local stack */ | ||
1308 | skb->protocol = eth_type_trans(skb, dev); | ||
1309 | memset(skb->cb, 0, sizeof(skb->cb)); | ||
1310 | netif_rx(skb); | ||
1311 | } | ||
1274 | } | 1312 | } |
1275 | 1313 | ||
1276 | if (xmit_skb) { | 1314 | if (xmit_skb) { |
@@ -1339,14 +1377,20 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx) | |||
1339 | if (remaining <= subframe_len + padding) | 1377 | if (remaining <= subframe_len + padding) |
1340 | frame = skb; | 1378 | frame = skb; |
1341 | else { | 1379 | else { |
1342 | frame = dev_alloc_skb(local->hw.extra_tx_headroom + | 1380 | /* |
1343 | subframe_len); | 1381 | * Allocate and reserve two bytes more for payload |
1382 | * alignment since sizeof(struct ethhdr) is 14. | ||
1383 | */ | ||
1384 | frame = dev_alloc_skb( | ||
1385 | ALIGN(local->hw.extra_tx_headroom, 4) + | ||
1386 | subframe_len + 2); | ||
1344 | 1387 | ||
1345 | if (frame == NULL) | 1388 | if (frame == NULL) |
1346 | return RX_DROP_UNUSABLE; | 1389 | return RX_DROP_UNUSABLE; |
1347 | 1390 | ||
1348 | skb_reserve(frame, local->hw.extra_tx_headroom + | 1391 | skb_reserve(frame, |
1349 | sizeof(struct ethhdr)); | 1392 | ALIGN(local->hw.extra_tx_headroom, 4) + |
1393 | sizeof(struct ethhdr) + 2); | ||
1350 | memcpy(skb_put(frame, ntohs(len)), skb->data, | 1394 | memcpy(skb_put(frame, ntohs(len)), skb->data, |
1351 | ntohs(len)); | 1395 | ntohs(len)); |
1352 | 1396 | ||
@@ -1976,7 +2020,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, | |||
1976 | rx.flags |= IEEE80211_RX_IN_SCAN; | 2020 | rx.flags |= IEEE80211_RX_IN_SCAN; |
1977 | 2021 | ||
1978 | ieee80211_parse_qos(&rx); | 2022 | ieee80211_parse_qos(&rx); |
1979 | ieee80211_verify_ip_alignment(&rx); | 2023 | ieee80211_verify_alignment(&rx); |
1980 | 2024 | ||
1981 | skb = rx.skb; | 2025 | skb = rx.skb; |
1982 | 2026 | ||