aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/DocBook/mac80211.tmpl4
-rw-r--r--net/mac80211/rx.c110
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
374static 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 */
397static 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