diff options
author | Zhu Yi <yi.zhu@intel.com> | 2010-03-29 05:35:07 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-03-31 14:39:34 -0400 |
commit | e3cf8b3f7b9eefbe1d39b160726d6e5c2cbb4c5d (patch) | |
tree | c59a6fcb8d0bcd88d848785a3dbe3978d1568274 /net/mac80211 | |
parent | e58b1253f1e850b4469964d7b92cf230196223c0 (diff) |
mac80211: support paged rx SKBs
Mac80211 drivers can now pass paged SKBs to mac80211 via
ieee80211_rx{_irqsafe}. The implementation currently use
skb_linearize() in a few places i.e. management frame
handling, software decryption, defragmentation and A-MSDU
process. We will optimize them one by one later.
Signed-off-by: Zhu Yi <yi.zhu@intel.com>
Cc: Kalle Valo <kalle.valo@iki.fi>
Cc: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211')
-rw-r--r-- | net/mac80211/rx.c | 36 |
1 files changed, 32 insertions, 4 deletions
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 1da57c8e849a..11ed5aa90f83 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -38,7 +38,7 @@ static struct sk_buff *remove_monitor_info(struct ieee80211_local *local, | |||
38 | { | 38 | { |
39 | if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) { | 39 | if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) { |
40 | if (likely(skb->len > FCS_LEN)) | 40 | if (likely(skb->len > FCS_LEN)) |
41 | skb_trim(skb, skb->len - FCS_LEN); | 41 | __pskb_trim(skb, skb->len - FCS_LEN); |
42 | else { | 42 | else { |
43 | /* driver bug */ | 43 | /* driver bug */ |
44 | WARN_ON(1); | 44 | WARN_ON(1); |
@@ -227,6 +227,12 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, | |||
227 | if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) | 227 | if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) |
228 | present_fcs_len = FCS_LEN; | 228 | present_fcs_len = FCS_LEN; |
229 | 229 | ||
230 | /* make sure hdr->frame_control is on the linear part */ | ||
231 | if (!pskb_may_pull(origskb, 2)) { | ||
232 | dev_kfree_skb(origskb); | ||
233 | return NULL; | ||
234 | } | ||
235 | |||
230 | if (!local->monitors) { | 236 | if (!local->monitors) { |
231 | if (should_drop_frame(origskb, present_fcs_len)) { | 237 | if (should_drop_frame(origskb, present_fcs_len)) { |
232 | dev_kfree_skb(origskb); | 238 | dev_kfree_skb(origskb); |
@@ -931,6 +937,9 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) | |||
931 | return RX_DROP_MONITOR; | 937 | return RX_DROP_MONITOR; |
932 | } | 938 | } |
933 | 939 | ||
940 | if (skb_linearize(rx->skb)) | ||
941 | return RX_DROP_UNUSABLE; | ||
942 | |||
934 | /* Check for weak IVs if possible */ | 943 | /* Check for weak IVs if possible */ |
935 | if (rx->sta && rx->key->conf.alg == ALG_WEP && | 944 | if (rx->sta && rx->key->conf.alg == ALG_WEP && |
936 | ieee80211_is_data(hdr->frame_control) && | 945 | ieee80211_is_data(hdr->frame_control) && |
@@ -1231,6 +1240,9 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) | |||
1231 | } | 1240 | } |
1232 | I802_DEBUG_INC(rx->local->rx_handlers_fragments); | 1241 | I802_DEBUG_INC(rx->local->rx_handlers_fragments); |
1233 | 1242 | ||
1243 | if (skb_linearize(rx->skb)) | ||
1244 | return RX_DROP_UNUSABLE; | ||
1245 | |||
1234 | seq = (sc & IEEE80211_SCTL_SEQ) >> 4; | 1246 | seq = (sc & IEEE80211_SCTL_SEQ) >> 4; |
1235 | 1247 | ||
1236 | if (frag == 0) { | 1248 | if (frag == 0) { |
@@ -1588,6 +1600,9 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx) | |||
1588 | skb->dev = dev; | 1600 | skb->dev = dev; |
1589 | __skb_queue_head_init(&frame_list); | 1601 | __skb_queue_head_init(&frame_list); |
1590 | 1602 | ||
1603 | if (skb_linearize(skb)) | ||
1604 | return RX_DROP_UNUSABLE; | ||
1605 | |||
1591 | ieee80211_amsdu_to_8023s(skb, &frame_list, dev->dev_addr, | 1606 | ieee80211_amsdu_to_8023s(skb, &frame_list, dev->dev_addr, |
1592 | rx->sdata->vif.type, | 1607 | rx->sdata->vif.type, |
1593 | rx->local->hw.extra_tx_headroom); | 1608 | rx->local->hw.extra_tx_headroom); |
@@ -2357,29 +2372,42 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, | |||
2357 | struct ieee80211_local *local = hw_to_local(hw); | 2372 | struct ieee80211_local *local = hw_to_local(hw); |
2358 | struct ieee80211_sub_if_data *sdata; | 2373 | struct ieee80211_sub_if_data *sdata; |
2359 | struct ieee80211_hdr *hdr; | 2374 | struct ieee80211_hdr *hdr; |
2375 | __le16 fc; | ||
2360 | struct ieee80211_rx_data rx; | 2376 | struct ieee80211_rx_data rx; |
2361 | int prepares; | 2377 | int prepares; |
2362 | struct ieee80211_sub_if_data *prev = NULL; | 2378 | struct ieee80211_sub_if_data *prev = NULL; |
2363 | struct sk_buff *skb_new; | 2379 | struct sk_buff *skb_new; |
2364 | struct sta_info *sta, *tmp; | 2380 | struct sta_info *sta, *tmp; |
2365 | bool found_sta = false; | 2381 | bool found_sta = false; |
2382 | int err = 0; | ||
2366 | 2383 | ||
2367 | hdr = (struct ieee80211_hdr *)skb->data; | 2384 | fc = ((struct ieee80211_hdr *)skb->data)->frame_control; |
2368 | memset(&rx, 0, sizeof(rx)); | 2385 | memset(&rx, 0, sizeof(rx)); |
2369 | rx.skb = skb; | 2386 | rx.skb = skb; |
2370 | rx.local = local; | 2387 | rx.local = local; |
2371 | 2388 | ||
2372 | if (ieee80211_is_data(hdr->frame_control) || ieee80211_is_mgmt(hdr->frame_control)) | 2389 | if (ieee80211_is_data(fc) || ieee80211_is_mgmt(fc)) |
2373 | local->dot11ReceivedFragmentCount++; | 2390 | local->dot11ReceivedFragmentCount++; |
2374 | 2391 | ||
2375 | if (unlikely(test_bit(SCAN_HW_SCANNING, &local->scanning) || | 2392 | if (unlikely(test_bit(SCAN_HW_SCANNING, &local->scanning) || |
2376 | test_bit(SCAN_OFF_CHANNEL, &local->scanning))) | 2393 | test_bit(SCAN_OFF_CHANNEL, &local->scanning))) |
2377 | rx.flags |= IEEE80211_RX_IN_SCAN; | 2394 | rx.flags |= IEEE80211_RX_IN_SCAN; |
2378 | 2395 | ||
2396 | if (ieee80211_is_mgmt(fc)) | ||
2397 | err = skb_linearize(skb); | ||
2398 | else | ||
2399 | err = !pskb_may_pull(skb, ieee80211_hdrlen(fc)); | ||
2400 | |||
2401 | if (err) { | ||
2402 | dev_kfree_skb(skb); | ||
2403 | return; | ||
2404 | } | ||
2405 | |||
2406 | hdr = (struct ieee80211_hdr *)skb->data; | ||
2379 | ieee80211_parse_qos(&rx); | 2407 | ieee80211_parse_qos(&rx); |
2380 | ieee80211_verify_alignment(&rx); | 2408 | ieee80211_verify_alignment(&rx); |
2381 | 2409 | ||
2382 | if (ieee80211_is_data(hdr->frame_control)) { | 2410 | if (ieee80211_is_data(fc)) { |
2383 | for_each_sta_info(local, hdr->addr2, sta, tmp) { | 2411 | for_each_sta_info(local, hdr->addr2, sta, tmp) { |
2384 | rx.sta = sta; | 2412 | rx.sta = sta; |
2385 | found_sta = true; | 2413 | found_sta = true; |