diff options
Diffstat (limited to 'net/mac80211/rx.c')
-rw-r--r-- | net/mac80211/rx.c | 91 |
1 files changed, 68 insertions, 23 deletions
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index e0c944fb6fc9..72efbd87c1eb 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -39,7 +39,7 @@ static struct sk_buff *remove_monitor_info(struct ieee80211_local *local, | |||
39 | { | 39 | { |
40 | if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) { | 40 | if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) { |
41 | if (likely(skb->len > FCS_LEN)) | 41 | if (likely(skb->len > FCS_LEN)) |
42 | skb_trim(skb, skb->len - FCS_LEN); | 42 | __pskb_trim(skb, skb->len - FCS_LEN); |
43 | else { | 43 | else { |
44 | /* driver bug */ | 44 | /* driver bug */ |
45 | WARN_ON(1); | 45 | WARN_ON(1); |
@@ -228,6 +228,12 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, | |||
228 | if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) | 228 | if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) |
229 | present_fcs_len = FCS_LEN; | 229 | present_fcs_len = FCS_LEN; |
230 | 230 | ||
231 | /* make sure hdr->frame_control is on the linear part */ | ||
232 | if (!pskb_may_pull(origskb, 2)) { | ||
233 | dev_kfree_skb(origskb); | ||
234 | return NULL; | ||
235 | } | ||
236 | |||
231 | if (!local->monitors) { | 237 | if (!local->monitors) { |
232 | if (should_drop_frame(origskb, present_fcs_len)) { | 238 | if (should_drop_frame(origskb, present_fcs_len)) { |
233 | dev_kfree_skb(origskb); | 239 | dev_kfree_skb(origskb); |
@@ -485,7 +491,7 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) | |||
485 | 491 | ||
486 | if (ieee80211_is_action(hdr->frame_control)) { | 492 | if (ieee80211_is_action(hdr->frame_control)) { |
487 | mgmt = (struct ieee80211_mgmt *)hdr; | 493 | mgmt = (struct ieee80211_mgmt *)hdr; |
488 | if (mgmt->u.action.category != MESH_PLINK_CATEGORY) | 494 | if (mgmt->u.action.category != WLAN_CATEGORY_MESH_PLINK) |
489 | return RX_DROP_MONITOR; | 495 | return RX_DROP_MONITOR; |
490 | return RX_CONTINUE; | 496 | return RX_CONTINUE; |
491 | } | 497 | } |
@@ -715,14 +721,16 @@ static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx, | |||
715 | 721 | ||
716 | tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK; | 722 | tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK; |
717 | 723 | ||
718 | if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_OPERATIONAL) | 724 | spin_lock(&sta->lock); |
719 | goto dont_reorder; | 725 | |
726 | if (!sta->ampdu_mlme.tid_active_rx[tid]) | ||
727 | goto dont_reorder_unlock; | ||
720 | 728 | ||
721 | tid_agg_rx = sta->ampdu_mlme.tid_rx[tid]; | 729 | tid_agg_rx = sta->ampdu_mlme.tid_rx[tid]; |
722 | 730 | ||
723 | /* qos null data frames are excluded */ | 731 | /* qos null data frames are excluded */ |
724 | if (unlikely(hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_NULLFUNC))) | 732 | if (unlikely(hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_NULLFUNC))) |
725 | goto dont_reorder; | 733 | goto dont_reorder_unlock; |
726 | 734 | ||
727 | /* new, potentially un-ordered, ampdu frame - process it */ | 735 | /* new, potentially un-ordered, ampdu frame - process it */ |
728 | 736 | ||
@@ -734,15 +742,20 @@ static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx, | |||
734 | /* if this mpdu is fragmented - terminate rx aggregation session */ | 742 | /* if this mpdu is fragmented - terminate rx aggregation session */ |
735 | sc = le16_to_cpu(hdr->seq_ctrl); | 743 | sc = le16_to_cpu(hdr->seq_ctrl); |
736 | if (sc & IEEE80211_SCTL_FRAG) { | 744 | if (sc & IEEE80211_SCTL_FRAG) { |
737 | ieee80211_sta_stop_rx_ba_session(sta->sdata, sta->sta.addr, | 745 | spin_unlock(&sta->lock); |
738 | tid, 0, WLAN_REASON_QSTA_REQUIRE_SETUP); | 746 | __ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_RECIPIENT, |
747 | WLAN_REASON_QSTA_REQUIRE_SETUP); | ||
739 | dev_kfree_skb(skb); | 748 | dev_kfree_skb(skb); |
740 | return; | 749 | return; |
741 | } | 750 | } |
742 | 751 | ||
743 | if (ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb, frames)) | 752 | if (ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb, frames)) { |
753 | spin_unlock(&sta->lock); | ||
744 | return; | 754 | return; |
755 | } | ||
745 | 756 | ||
757 | dont_reorder_unlock: | ||
758 | spin_unlock(&sta->lock); | ||
746 | dont_reorder: | 759 | dont_reorder: |
747 | __skb_queue_tail(frames, skb); | 760 | __skb_queue_tail(frames, skb); |
748 | } | 761 | } |
@@ -889,6 +902,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) | |||
889 | rx->key = key; | 902 | rx->key = key; |
890 | return RX_CONTINUE; | 903 | return RX_CONTINUE; |
891 | } else { | 904 | } else { |
905 | u8 keyid; | ||
892 | /* | 906 | /* |
893 | * The device doesn't give us the IV so we won't be | 907 | * The device doesn't give us the IV so we won't be |
894 | * able to look up the key. That's ok though, we | 908 | * able to look up the key. That's ok though, we |
@@ -911,7 +925,8 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) | |||
911 | * no need to call ieee80211_wep_get_keyidx, | 925 | * no need to call ieee80211_wep_get_keyidx, |
912 | * it verifies a bunch of things we've done already | 926 | * it verifies a bunch of things we've done already |
913 | */ | 927 | */ |
914 | keyidx = rx->skb->data[hdrlen + 3] >> 6; | 928 | skb_copy_bits(rx->skb, hdrlen + 3, &keyid, 1); |
929 | keyidx = keyid >> 6; | ||
915 | 930 | ||
916 | rx->key = rcu_dereference(rx->sdata->keys[keyidx]); | 931 | rx->key = rcu_dereference(rx->sdata->keys[keyidx]); |
917 | 932 | ||
@@ -932,6 +947,11 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) | |||
932 | return RX_DROP_MONITOR; | 947 | return RX_DROP_MONITOR; |
933 | } | 948 | } |
934 | 949 | ||
950 | if (skb_linearize(rx->skb)) | ||
951 | return RX_DROP_UNUSABLE; | ||
952 | |||
953 | hdr = (struct ieee80211_hdr *)rx->skb->data; | ||
954 | |||
935 | /* Check for weak IVs if possible */ | 955 | /* Check for weak IVs if possible */ |
936 | if (rx->sta && rx->key->conf.alg == ALG_WEP && | 956 | if (rx->sta && rx->key->conf.alg == ALG_WEP && |
937 | ieee80211_is_data(hdr->frame_control) && | 957 | ieee80211_is_data(hdr->frame_control) && |
@@ -1232,6 +1252,9 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) | |||
1232 | } | 1252 | } |
1233 | I802_DEBUG_INC(rx->local->rx_handlers_fragments); | 1253 | I802_DEBUG_INC(rx->local->rx_handlers_fragments); |
1234 | 1254 | ||
1255 | if (skb_linearize(rx->skb)) | ||
1256 | return RX_DROP_UNUSABLE; | ||
1257 | |||
1235 | seq = (sc & IEEE80211_SCTL_SEQ) >> 4; | 1258 | seq = (sc & IEEE80211_SCTL_SEQ) >> 4; |
1236 | 1259 | ||
1237 | if (frag == 0) { | 1260 | if (frag == 0) { |
@@ -1397,21 +1420,24 @@ static int | |||
1397 | ieee80211_drop_unencrypted_mgmt(struct ieee80211_rx_data *rx) | 1420 | ieee80211_drop_unencrypted_mgmt(struct ieee80211_rx_data *rx) |
1398 | { | 1421 | { |
1399 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; | 1422 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; |
1423 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); | ||
1400 | __le16 fc = hdr->frame_control; | 1424 | __le16 fc = hdr->frame_control; |
1401 | int res; | ||
1402 | 1425 | ||
1403 | res = ieee80211_drop_unencrypted(rx, fc); | 1426 | /* |
1404 | if (unlikely(res)) | 1427 | * Pass through unencrypted frames if the hardware has |
1405 | return res; | 1428 | * decrypted them already. |
1429 | */ | ||
1430 | if (status->flag & RX_FLAG_DECRYPTED) | ||
1431 | return 0; | ||
1406 | 1432 | ||
1407 | if (rx->sta && test_sta_flags(rx->sta, WLAN_STA_MFP)) { | 1433 | if (rx->sta && test_sta_flags(rx->sta, WLAN_STA_MFP)) { |
1408 | if (unlikely(ieee80211_is_unicast_robust_mgmt_frame(rx->skb) && | 1434 | if (unlikely(!ieee80211_has_protected(fc) && |
1435 | ieee80211_is_unicast_robust_mgmt_frame(rx->skb) && | ||
1409 | rx->key)) | 1436 | rx->key)) |
1410 | return -EACCES; | 1437 | return -EACCES; |
1411 | /* BIP does not use Protected field, so need to check MMIE */ | 1438 | /* BIP does not use Protected field, so need to check MMIE */ |
1412 | if (unlikely(ieee80211_is_multicast_robust_mgmt_frame(rx->skb) && | 1439 | if (unlikely(ieee80211_is_multicast_robust_mgmt_frame(rx->skb) && |
1413 | ieee80211_get_mmie_keyidx(rx->skb) < 0 && | 1440 | ieee80211_get_mmie_keyidx(rx->skb) < 0)) |
1414 | rx->key)) | ||
1415 | return -EACCES; | 1441 | return -EACCES; |
1416 | /* | 1442 | /* |
1417 | * When using MFP, Action frames are not allowed prior to | 1443 | * When using MFP, Action frames are not allowed prior to |
@@ -1589,6 +1615,9 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx) | |||
1589 | skb->dev = dev; | 1615 | skb->dev = dev; |
1590 | __skb_queue_head_init(&frame_list); | 1616 | __skb_queue_head_init(&frame_list); |
1591 | 1617 | ||
1618 | if (skb_linearize(skb)) | ||
1619 | return RX_DROP_UNUSABLE; | ||
1620 | |||
1592 | ieee80211_amsdu_to_8023s(skb, &frame_list, dev->dev_addr, | 1621 | ieee80211_amsdu_to_8023s(skb, &frame_list, dev->dev_addr, |
1593 | rx->sdata->vif.type, | 1622 | rx->sdata->vif.type, |
1594 | rx->local->hw.extra_tx_headroom); | 1623 | rx->local->hw.extra_tx_headroom); |
@@ -1787,10 +1816,12 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx, struct sk_buff_head *frames) | |||
1787 | if (ieee80211_is_back_req(bar->frame_control)) { | 1816 | if (ieee80211_is_back_req(bar->frame_control)) { |
1788 | if (!rx->sta) | 1817 | if (!rx->sta) |
1789 | return RX_DROP_MONITOR; | 1818 | return RX_DROP_MONITOR; |
1819 | spin_lock(&rx->sta->lock); | ||
1790 | tid = le16_to_cpu(bar->control) >> 12; | 1820 | tid = le16_to_cpu(bar->control) >> 12; |
1791 | if (rx->sta->ampdu_mlme.tid_state_rx[tid] | 1821 | if (!rx->sta->ampdu_mlme.tid_active_rx[tid]) { |
1792 | != HT_AGG_STATE_OPERATIONAL) | 1822 | spin_unlock(&rx->sta->lock); |
1793 | return RX_DROP_MONITOR; | 1823 | return RX_DROP_MONITOR; |
1824 | } | ||
1794 | tid_agg_rx = rx->sta->ampdu_mlme.tid_rx[tid]; | 1825 | tid_agg_rx = rx->sta->ampdu_mlme.tid_rx[tid]; |
1795 | 1826 | ||
1796 | start_seq_num = le16_to_cpu(bar->start_seq_num) >> 4; | 1827 | start_seq_num = le16_to_cpu(bar->start_seq_num) >> 4; |
@@ -1804,6 +1835,7 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx, struct sk_buff_head *frames) | |||
1804 | ieee80211_release_reorder_frames(hw, tid_agg_rx, start_seq_num, | 1835 | ieee80211_release_reorder_frames(hw, tid_agg_rx, start_seq_num, |
1805 | frames); | 1836 | frames); |
1806 | kfree_skb(skb); | 1837 | kfree_skb(skb); |
1838 | spin_unlock(&rx->sta->lock); | ||
1807 | return RX_QUEUED; | 1839 | return RX_QUEUED; |
1808 | } | 1840 | } |
1809 | 1841 | ||
@@ -1965,8 +1997,8 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |||
1965 | goto handled; | 1997 | goto handled; |
1966 | } | 1998 | } |
1967 | break; | 1999 | break; |
1968 | case MESH_PLINK_CATEGORY: | 2000 | case WLAN_CATEGORY_MESH_PLINK: |
1969 | case MESH_PATH_SEL_CATEGORY: | 2001 | case WLAN_CATEGORY_MESH_PATH_SEL: |
1970 | if (ieee80211_vif_is_mesh(&sdata->vif)) | 2002 | if (ieee80211_vif_is_mesh(&sdata->vif)) |
1971 | return ieee80211_mesh_rx_mgmt(sdata, rx->skb); | 2003 | return ieee80211_mesh_rx_mgmt(sdata, rx->skb); |
1972 | break; | 2004 | break; |
@@ -2363,29 +2395,42 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, | |||
2363 | struct ieee80211_local *local = hw_to_local(hw); | 2395 | struct ieee80211_local *local = hw_to_local(hw); |
2364 | struct ieee80211_sub_if_data *sdata; | 2396 | struct ieee80211_sub_if_data *sdata; |
2365 | struct ieee80211_hdr *hdr; | 2397 | struct ieee80211_hdr *hdr; |
2398 | __le16 fc; | ||
2366 | struct ieee80211_rx_data rx; | 2399 | struct ieee80211_rx_data rx; |
2367 | int prepares; | 2400 | int prepares; |
2368 | struct ieee80211_sub_if_data *prev = NULL; | 2401 | struct ieee80211_sub_if_data *prev = NULL; |
2369 | struct sk_buff *skb_new; | 2402 | struct sk_buff *skb_new; |
2370 | struct sta_info *sta, *tmp; | 2403 | struct sta_info *sta, *tmp; |
2371 | bool found_sta = false; | 2404 | bool found_sta = false; |
2405 | int err = 0; | ||
2372 | 2406 | ||
2373 | hdr = (struct ieee80211_hdr *)skb->data; | 2407 | fc = ((struct ieee80211_hdr *)skb->data)->frame_control; |
2374 | memset(&rx, 0, sizeof(rx)); | 2408 | memset(&rx, 0, sizeof(rx)); |
2375 | rx.skb = skb; | 2409 | rx.skb = skb; |
2376 | rx.local = local; | 2410 | rx.local = local; |
2377 | 2411 | ||
2378 | if (ieee80211_is_data(hdr->frame_control) || ieee80211_is_mgmt(hdr->frame_control)) | 2412 | if (ieee80211_is_data(fc) || ieee80211_is_mgmt(fc)) |
2379 | local->dot11ReceivedFragmentCount++; | 2413 | local->dot11ReceivedFragmentCount++; |
2380 | 2414 | ||
2381 | if (unlikely(test_bit(SCAN_HW_SCANNING, &local->scanning) || | 2415 | if (unlikely(test_bit(SCAN_HW_SCANNING, &local->scanning) || |
2382 | test_bit(SCAN_OFF_CHANNEL, &local->scanning))) | 2416 | test_bit(SCAN_OFF_CHANNEL, &local->scanning))) |
2383 | rx.flags |= IEEE80211_RX_IN_SCAN; | 2417 | rx.flags |= IEEE80211_RX_IN_SCAN; |
2384 | 2418 | ||
2419 | if (ieee80211_is_mgmt(fc)) | ||
2420 | err = skb_linearize(skb); | ||
2421 | else | ||
2422 | err = !pskb_may_pull(skb, ieee80211_hdrlen(fc)); | ||
2423 | |||
2424 | if (err) { | ||
2425 | dev_kfree_skb(skb); | ||
2426 | return; | ||
2427 | } | ||
2428 | |||
2429 | hdr = (struct ieee80211_hdr *)skb->data; | ||
2385 | ieee80211_parse_qos(&rx); | 2430 | ieee80211_parse_qos(&rx); |
2386 | ieee80211_verify_alignment(&rx); | 2431 | ieee80211_verify_alignment(&rx); |
2387 | 2432 | ||
2388 | if (ieee80211_is_data(hdr->frame_control)) { | 2433 | if (ieee80211_is_data(fc)) { |
2389 | for_each_sta_info(local, hdr->addr2, sta, tmp) { | 2434 | for_each_sta_info(local, hdr->addr2, sta, tmp) { |
2390 | rx.sta = sta; | 2435 | rx.sta = sta; |
2391 | found_sta = true; | 2436 | found_sta = true; |