aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/rx.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2009-01-06 18:26:10 -0500
committerJohn W. Linville <linville@tuxdriver.com>2009-01-29 15:59:54 -0500
commitd1c3a37ceeb1a5ea02991a0476355f1a1d3b3e83 (patch)
tree9ddce7f3169bd77adbeba2d4627ec46ecde9a33e /net/mac80211/rx.c
parent2bf30fabadbdcb535b057afc92aba015884847dc (diff)
mac80211: clarify alignment docs, fix up alignment
Not all drivers are capable of passing properly aligned frames, in particular with mesh networking no hardware will support completely aligning it correctly. This patch adds code to align the data payload to a 4-byte boundary in memory for those platforms that require this, or when CONFIG_MAC80211_DEBUG_PACKET_ALIGNMENT is set. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/rx.c')
-rw-r--r--net/mac80211/rx.c110
1 files changed, 77 insertions, 33 deletions
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