diff options
Diffstat (limited to 'net/mac80211')
-rw-r--r-- | net/mac80211/rx.c | 46 |
1 files changed, 33 insertions, 13 deletions
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 89e1e3070ec1..1ccd32933eb7 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -340,9 +340,42 @@ static u32 ieee80211_rx_load_stats(struct ieee80211_local *local, | |||
340 | return load; | 340 | return load; |
341 | } | 341 | } |
342 | 342 | ||
343 | static ieee80211_txrx_result | ||
344 | ieee80211_rx_h_verify_ip_alignment(struct ieee80211_txrx_data *rx) | ||
345 | { | ||
346 | int hdrlen; | ||
347 | |||
348 | /* | ||
349 | * Drivers are required to align the payload data in a way that | ||
350 | * guarantees that the contained IP header is aligned to a four- | ||
351 | * byte boundary. In the case of regular frames, this simply means | ||
352 | * aligning the payload to a four-byte boundary (because either | ||
353 | * the IP header is directly contained, or IV/RFC1042 headers that | ||
354 | * have a length divisible by four are in front of it. | ||
355 | * | ||
356 | * With A-MSDU frames, however, the payload data address must | ||
357 | * yield two modulo four because there are 14-byte 802.3 headers | ||
358 | * within the A-MSDU frames that push the IP header further back | ||
359 | * to a multiple of four again. Thankfully, the specs were sane | ||
360 | * enough this time around to require padding each A-MSDU subframe | ||
361 | * to a length that is a multiple of four. | ||
362 | * | ||
363 | * Padding like atheros hardware adds which is inbetween the 802.11 | ||
364 | * header and the payload is not supported, the driver is required | ||
365 | * to move the 802.11 header further back in that case. | ||
366 | */ | ||
367 | hdrlen = ieee80211_get_hdrlen(rx->fc); | ||
368 | if (rx->flags & IEEE80211_TXRXD_RX_AMSDU) | ||
369 | hdrlen += ETH_HLEN; | ||
370 | WARN_ON_ONCE(((unsigned long)(rx->skb->data + hdrlen)) & 3); | ||
371 | |||
372 | return TXRX_CONTINUE; | ||
373 | } | ||
374 | |||
343 | ieee80211_rx_handler ieee80211_rx_pre_handlers[] = | 375 | ieee80211_rx_handler ieee80211_rx_pre_handlers[] = |
344 | { | 376 | { |
345 | ieee80211_rx_h_parse_qos, | 377 | ieee80211_rx_h_parse_qos, |
378 | ieee80211_rx_h_verify_ip_alignment, | ||
346 | NULL | 379 | NULL |
347 | }; | 380 | }; |
348 | 381 | ||
@@ -1679,7 +1712,6 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, | |||
1679 | struct ieee80211_sub_if_data *prev = NULL; | 1712 | struct ieee80211_sub_if_data *prev = NULL; |
1680 | struct sk_buff *skb_new; | 1713 | struct sk_buff *skb_new; |
1681 | u8 *bssid; | 1714 | u8 *bssid; |
1682 | int hdrlen; | ||
1683 | 1715 | ||
1684 | hdr = (struct ieee80211_hdr *) skb->data; | 1716 | hdr = (struct ieee80211_hdr *) skb->data; |
1685 | memset(&rx, 0, sizeof(rx)); | 1717 | memset(&rx, 0, sizeof(rx)); |
@@ -1691,18 +1723,6 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, | |||
1691 | rx.fc = le16_to_cpu(hdr->frame_control); | 1723 | rx.fc = le16_to_cpu(hdr->frame_control); |
1692 | type = rx.fc & IEEE80211_FCTL_FTYPE; | 1724 | type = rx.fc & IEEE80211_FCTL_FTYPE; |
1693 | 1725 | ||
1694 | /* | ||
1695 | * Drivers are required to align the payload data to a four-byte | ||
1696 | * boundary, so the last two bits of the address where it starts | ||
1697 | * may not be set. The header is required to be directly before | ||
1698 | * the payload data, padding like atheros hardware adds which is | ||
1699 | * inbetween the 802.11 header and the payload is not supported, | ||
1700 | * the driver is required to move the 802.11 header further back | ||
1701 | * in that case. | ||
1702 | */ | ||
1703 | hdrlen = ieee80211_get_hdrlen(rx.fc); | ||
1704 | WARN_ON_ONCE(((unsigned long)(skb->data + hdrlen)) & 3); | ||
1705 | |||
1706 | if (type == IEEE80211_FTYPE_DATA || type == IEEE80211_FTYPE_MGMT) | 1726 | if (type == IEEE80211_FTYPE_DATA || type == IEEE80211_FTYPE_MGMT) |
1707 | local->dot11ReceivedFragmentCount++; | 1727 | local->dot11ReceivedFragmentCount++; |
1708 | 1728 | ||