| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Copyright 2002-2005, Instant802 Networks, Inc. |
|---|
| 3 | 4 | * Copyright 2005-2006, Devicescape Software, Inc. |
|---|
| .. | .. |
|---|
| 6 | 7 | * Copyright 2013-2014 Intel Mobile Communications GmbH |
|---|
| 7 | 8 | * Copyright(c) 2015 - 2017 Intel Deutschland GmbH |
|---|
| 8 | 9 | * Copyright (C) 2018-2021 Intel Corporation |
|---|
| 9 | | - * |
|---|
| 10 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 11 | | - * it under the terms of the GNU General Public License version 2 as |
|---|
| 12 | | - * published by the Free Software Foundation. |
|---|
| 13 | 10 | */ |
|---|
| 14 | 11 | |
|---|
| 15 | 12 | #include <linux/jiffies.h> |
|---|
| .. | .. |
|---|
| 45 | 42 | u64_stats_update_end(&tstats->syncp); |
|---|
| 46 | 43 | } |
|---|
| 47 | 44 | |
|---|
| 48 | | -static u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len, |
|---|
| 49 | | - enum nl80211_iftype type) |
|---|
| 50 | | -{ |
|---|
| 51 | | - __le16 fc = hdr->frame_control; |
|---|
| 52 | | - |
|---|
| 53 | | - if (ieee80211_is_data(fc)) { |
|---|
| 54 | | - if (len < 24) /* drop incorrect hdr len (data) */ |
|---|
| 55 | | - return NULL; |
|---|
| 56 | | - |
|---|
| 57 | | - if (ieee80211_has_a4(fc)) |
|---|
| 58 | | - return NULL; |
|---|
| 59 | | - if (ieee80211_has_tods(fc)) |
|---|
| 60 | | - return hdr->addr1; |
|---|
| 61 | | - if (ieee80211_has_fromds(fc)) |
|---|
| 62 | | - return hdr->addr2; |
|---|
| 63 | | - |
|---|
| 64 | | - return hdr->addr3; |
|---|
| 65 | | - } |
|---|
| 66 | | - |
|---|
| 67 | | - if (ieee80211_is_mgmt(fc)) { |
|---|
| 68 | | - if (len < 24) /* drop incorrect hdr len (mgmt) */ |
|---|
| 69 | | - return NULL; |
|---|
| 70 | | - return hdr->addr3; |
|---|
| 71 | | - } |
|---|
| 72 | | - |
|---|
| 73 | | - if (ieee80211_is_ctl(fc)) { |
|---|
| 74 | | - if (ieee80211_is_pspoll(fc)) |
|---|
| 75 | | - return hdr->addr1; |
|---|
| 76 | | - |
|---|
| 77 | | - if (ieee80211_is_back_req(fc)) { |
|---|
| 78 | | - switch (type) { |
|---|
| 79 | | - case NL80211_IFTYPE_STATION: |
|---|
| 80 | | - return hdr->addr2; |
|---|
| 81 | | - case NL80211_IFTYPE_AP: |
|---|
| 82 | | - case NL80211_IFTYPE_AP_VLAN: |
|---|
| 83 | | - return hdr->addr1; |
|---|
| 84 | | - default: |
|---|
| 85 | | - break; /* fall through to the return */ |
|---|
| 86 | | - } |
|---|
| 87 | | - } |
|---|
| 88 | | - } |
|---|
| 89 | | - |
|---|
| 90 | | - return NULL; |
|---|
| 91 | | -} |
|---|
| 92 | | - |
|---|
| 93 | 45 | /* |
|---|
| 94 | 46 | * monitor mode reception |
|---|
| 95 | 47 | * |
|---|
| 96 | 48 | * This function cleans up the SKB, i.e. it removes all the stuff |
|---|
| 97 | 49 | * only useful for monitoring. |
|---|
| 98 | 50 | */ |
|---|
| 99 | | -static void remove_monitor_info(struct sk_buff *skb, |
|---|
| 100 | | - unsigned int present_fcs_len, |
|---|
| 101 | | - unsigned int rtap_space) |
|---|
| 51 | +static struct sk_buff *ieee80211_clean_skb(struct sk_buff *skb, |
|---|
| 52 | + unsigned int present_fcs_len, |
|---|
| 53 | + unsigned int rtap_space) |
|---|
| 102 | 54 | { |
|---|
| 55 | + struct ieee80211_hdr *hdr; |
|---|
| 56 | + unsigned int hdrlen; |
|---|
| 57 | + __le16 fc; |
|---|
| 58 | + |
|---|
| 103 | 59 | if (present_fcs_len) |
|---|
| 104 | 60 | __pskb_trim(skb, skb->len - present_fcs_len); |
|---|
| 105 | 61 | __pskb_pull(skb, rtap_space); |
|---|
| 62 | + |
|---|
| 63 | + hdr = (void *)skb->data; |
|---|
| 64 | + fc = hdr->frame_control; |
|---|
| 65 | + |
|---|
| 66 | + /* |
|---|
| 67 | + * Remove the HT-Control field (if present) on management |
|---|
| 68 | + * frames after we've sent the frame to monitoring. We |
|---|
| 69 | + * (currently) don't need it, and don't properly parse |
|---|
| 70 | + * frames with it present, due to the assumption of a |
|---|
| 71 | + * fixed management header length. |
|---|
| 72 | + */ |
|---|
| 73 | + if (likely(!ieee80211_is_mgmt(fc) || !ieee80211_has_order(fc))) |
|---|
| 74 | + return skb; |
|---|
| 75 | + |
|---|
| 76 | + hdrlen = ieee80211_hdrlen(fc); |
|---|
| 77 | + hdr->frame_control &= ~cpu_to_le16(IEEE80211_FCTL_ORDER); |
|---|
| 78 | + |
|---|
| 79 | + if (!pskb_may_pull(skb, hdrlen)) { |
|---|
| 80 | + dev_kfree_skb(skb); |
|---|
| 81 | + return NULL; |
|---|
| 82 | + } |
|---|
| 83 | + |
|---|
| 84 | + memmove(skb->data + IEEE80211_HT_CTL_LEN, skb->data, |
|---|
| 85 | + hdrlen - IEEE80211_HT_CTL_LEN); |
|---|
| 86 | + __pskb_pull(skb, IEEE80211_HT_CTL_LEN); |
|---|
| 87 | + |
|---|
| 88 | + return skb; |
|---|
| 106 | 89 | } |
|---|
| 107 | 90 | |
|---|
| 108 | 91 | static inline bool should_drop_frame(struct sk_buff *skb, int present_fcs_len, |
|---|
| .. | .. |
|---|
| 115 | 98 | |
|---|
| 116 | 99 | if (status->flag & (RX_FLAG_FAILED_FCS_CRC | |
|---|
| 117 | 100 | RX_FLAG_FAILED_PLCP_CRC | |
|---|
| 118 | | - RX_FLAG_ONLY_MONITOR)) |
|---|
| 101 | + RX_FLAG_ONLY_MONITOR | |
|---|
| 102 | + RX_FLAG_NO_PSDU)) |
|---|
| 119 | 103 | return true; |
|---|
| 120 | 104 | |
|---|
| 121 | 105 | if (unlikely(skb->len < 16 + present_fcs_len + rtap_space)) |
|---|
| .. | .. |
|---|
| 192 | 176 | BUILD_BUG_ON(sizeof(struct ieee80211_radiotap_he_mu) != 12); |
|---|
| 193 | 177 | } |
|---|
| 194 | 178 | |
|---|
| 179 | + if (status->flag & RX_FLAG_NO_PSDU) |
|---|
| 180 | + len += 1; |
|---|
| 181 | + |
|---|
| 182 | + if (status->flag & RX_FLAG_RADIOTAP_LSIG) { |
|---|
| 183 | + len = ALIGN(len, 2); |
|---|
| 184 | + len += 4; |
|---|
| 185 | + BUILD_BUG_ON(sizeof(struct ieee80211_radiotap_lsig) != 4); |
|---|
| 186 | + } |
|---|
| 187 | + |
|---|
| 195 | 188 | if (status->chains) { |
|---|
| 196 | 189 | /* antenna and antenna signal fields */ |
|---|
| 197 | 190 | len += 2 * hweight8(status->chains); |
|---|
| 198 | 191 | } |
|---|
| 199 | 192 | |
|---|
| 200 | 193 | if (status->flag & RX_FLAG_RADIOTAP_VENDOR_DATA) { |
|---|
| 201 | | - struct ieee80211_vendor_radiotap *rtap = (void *)skb->data; |
|---|
| 194 | + struct ieee80211_vendor_radiotap *rtap; |
|---|
| 195 | + int vendor_data_offset = 0; |
|---|
| 196 | + |
|---|
| 197 | + /* |
|---|
| 198 | + * The position to look at depends on the existence (or non- |
|---|
| 199 | + * existence) of other elements, so take that into account... |
|---|
| 200 | + */ |
|---|
| 201 | + if (status->flag & RX_FLAG_RADIOTAP_HE) |
|---|
| 202 | + vendor_data_offset += |
|---|
| 203 | + sizeof(struct ieee80211_radiotap_he); |
|---|
| 204 | + if (status->flag & RX_FLAG_RADIOTAP_HE_MU) |
|---|
| 205 | + vendor_data_offset += |
|---|
| 206 | + sizeof(struct ieee80211_radiotap_he_mu); |
|---|
| 207 | + if (status->flag & RX_FLAG_RADIOTAP_LSIG) |
|---|
| 208 | + vendor_data_offset += |
|---|
| 209 | + sizeof(struct ieee80211_radiotap_lsig); |
|---|
| 210 | + |
|---|
| 211 | + rtap = (void *)&skb->data[vendor_data_offset]; |
|---|
| 202 | 212 | |
|---|
| 203 | 213 | /* alignment for fixed 6-byte vendor data header */ |
|---|
| 204 | 214 | len = ALIGN(len, 2); |
|---|
| .. | .. |
|---|
| 280 | 290 | struct ieee80211_vendor_radiotap rtap = {}; |
|---|
| 281 | 291 | struct ieee80211_radiotap_he he = {}; |
|---|
| 282 | 292 | struct ieee80211_radiotap_he_mu he_mu = {}; |
|---|
| 293 | + struct ieee80211_radiotap_lsig lsig = {}; |
|---|
| 283 | 294 | |
|---|
| 284 | 295 | if (status->flag & RX_FLAG_RADIOTAP_HE) { |
|---|
| 285 | 296 | he = *(struct ieee80211_radiotap_he *)skb->data; |
|---|
| .. | .. |
|---|
| 290 | 301 | if (status->flag & RX_FLAG_RADIOTAP_HE_MU) { |
|---|
| 291 | 302 | he_mu = *(struct ieee80211_radiotap_he_mu *)skb->data; |
|---|
| 292 | 303 | skb_pull(skb, sizeof(he_mu)); |
|---|
| 304 | + } |
|---|
| 305 | + |
|---|
| 306 | + if (status->flag & RX_FLAG_RADIOTAP_LSIG) { |
|---|
| 307 | + lsig = *(struct ieee80211_radiotap_lsig *)skb->data; |
|---|
| 308 | + skb_pull(skb, sizeof(lsig)); |
|---|
| 293 | 309 | } |
|---|
| 294 | 310 | |
|---|
| 295 | 311 | if (status->flag & RX_FLAG_RADIOTAP_VENDOR_DATA) { |
|---|
| .. | .. |
|---|
| 382 | 398 | pos++; |
|---|
| 383 | 399 | |
|---|
| 384 | 400 | /* IEEE80211_RADIOTAP_CHANNEL */ |
|---|
| 401 | + /* TODO: frequency offset in KHz */ |
|---|
| 385 | 402 | put_unaligned_le16(status->freq, pos); |
|---|
| 386 | 403 | pos += 2; |
|---|
| 387 | 404 | if (status->bw == RATE_INFO_BW_10) |
|---|
| .. | .. |
|---|
| 389 | 406 | else if (status->bw == RATE_INFO_BW_5) |
|---|
| 390 | 407 | channel_flags |= IEEE80211_CHAN_QUARTER; |
|---|
| 391 | 408 | |
|---|
| 392 | | - if (status->band == NL80211_BAND_5GHZ) |
|---|
| 409 | + if (status->band == NL80211_BAND_5GHZ || |
|---|
| 410 | + status->band == NL80211_BAND_6GHZ) |
|---|
| 393 | 411 | channel_flags |= IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ; |
|---|
| 394 | 412 | else if (status->encoding != RX_ENC_LEGACY) |
|---|
| 395 | 413 | channel_flags |= IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ; |
|---|
| .. | .. |
|---|
| 550 | 568 | |
|---|
| 551 | 569 | if (status->encoding == RX_ENC_HE && |
|---|
| 552 | 570 | status->flag & RX_FLAG_RADIOTAP_HE) { |
|---|
| 553 | | -#define HE_PREP(f, val) cpu_to_le16(FIELD_PREP(IEEE80211_RADIOTAP_HE_##f, val)) |
|---|
| 571 | +#define HE_PREP(f, val) le16_encode_bits(val, IEEE80211_RADIOTAP_HE_##f) |
|---|
| 554 | 572 | |
|---|
| 555 | 573 | if (status->enc_flags & RX_ENC_FLAG_STBC_MASK) { |
|---|
| 556 | 574 | he.data6 |= HE_PREP(DATA6_NSTS, |
|---|
| .. | .. |
|---|
| 629 | 647 | rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_HE_MU); |
|---|
| 630 | 648 | memcpy(pos, &he_mu, sizeof(he_mu)); |
|---|
| 631 | 649 | pos += sizeof(he_mu); |
|---|
| 650 | + } |
|---|
| 651 | + |
|---|
| 652 | + if (status->flag & RX_FLAG_NO_PSDU) { |
|---|
| 653 | + rthdr->it_present |= |
|---|
| 654 | + cpu_to_le32(1 << IEEE80211_RADIOTAP_ZERO_LEN_PSDU); |
|---|
| 655 | + *pos++ = status->zero_length_psdu_type; |
|---|
| 656 | + } |
|---|
| 657 | + |
|---|
| 658 | + if (status->flag & RX_FLAG_RADIOTAP_LSIG) { |
|---|
| 659 | + /* ensure 2 byte alignment */ |
|---|
| 660 | + while ((pos - (u8 *)rthdr) & 1) |
|---|
| 661 | + pos++; |
|---|
| 662 | + rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_LSIG); |
|---|
| 663 | + memcpy(pos, &lsig, sizeof(lsig)); |
|---|
| 664 | + pos += sizeof(lsig); |
|---|
| 632 | 665 | } |
|---|
| 633 | 666 | |
|---|
| 634 | 667 | for_each_set_bit(chain, &chains, IEEE80211_MAX_CHAINS) { |
|---|
| .. | .. |
|---|
| 723 | 756 | struct ieee80211_sub_if_data *monitor_sdata = |
|---|
| 724 | 757 | rcu_dereference(local->monitor_sdata); |
|---|
| 725 | 758 | bool only_monitor = false; |
|---|
| 759 | + unsigned int min_head_len; |
|---|
| 726 | 760 | |
|---|
| 727 | 761 | if (status->flag & RX_FLAG_RADIOTAP_HE) |
|---|
| 728 | 762 | rtap_space += sizeof(struct ieee80211_radiotap_he); |
|---|
| .. | .. |
|---|
| 730 | 764 | if (status->flag & RX_FLAG_RADIOTAP_HE_MU) |
|---|
| 731 | 765 | rtap_space += sizeof(struct ieee80211_radiotap_he_mu); |
|---|
| 732 | 766 | |
|---|
| 767 | + if (status->flag & RX_FLAG_RADIOTAP_LSIG) |
|---|
| 768 | + rtap_space += sizeof(struct ieee80211_radiotap_lsig); |
|---|
| 769 | + |
|---|
| 733 | 770 | if (unlikely(status->flag & RX_FLAG_RADIOTAP_VENDOR_DATA)) { |
|---|
| 734 | | - struct ieee80211_vendor_radiotap *rtap = (void *)origskb->data; |
|---|
| 771 | + struct ieee80211_vendor_radiotap *rtap = |
|---|
| 772 | + (void *)(origskb->data + rtap_space); |
|---|
| 735 | 773 | |
|---|
| 736 | 774 | rtap_space += sizeof(*rtap) + rtap->len + rtap->pad; |
|---|
| 737 | 775 | } |
|---|
| 776 | + |
|---|
| 777 | + min_head_len = rtap_space; |
|---|
| 738 | 778 | |
|---|
| 739 | 779 | /* |
|---|
| 740 | 780 | * First, we may need to make a copy of the skb because |
|---|
| .. | .. |
|---|
| 745 | 785 | * the SKB because it has a bad FCS/PLCP checksum. |
|---|
| 746 | 786 | */ |
|---|
| 747 | 787 | |
|---|
| 748 | | - if (ieee80211_hw_check(&local->hw, RX_INCLUDES_FCS)) { |
|---|
| 749 | | - if (unlikely(origskb->len <= FCS_LEN)) { |
|---|
| 750 | | - /* driver bug */ |
|---|
| 751 | | - WARN_ON(1); |
|---|
| 752 | | - dev_kfree_skb(origskb); |
|---|
| 753 | | - return NULL; |
|---|
| 788 | + if (!(status->flag & RX_FLAG_NO_PSDU)) { |
|---|
| 789 | + if (ieee80211_hw_check(&local->hw, RX_INCLUDES_FCS)) { |
|---|
| 790 | + if (unlikely(origskb->len <= FCS_LEN + rtap_space)) { |
|---|
| 791 | + /* driver bug */ |
|---|
| 792 | + WARN_ON(1); |
|---|
| 793 | + dev_kfree_skb(origskb); |
|---|
| 794 | + return NULL; |
|---|
| 795 | + } |
|---|
| 796 | + present_fcs_len = FCS_LEN; |
|---|
| 754 | 797 | } |
|---|
| 755 | | - present_fcs_len = FCS_LEN; |
|---|
| 798 | + |
|---|
| 799 | + /* also consider the hdr->frame_control */ |
|---|
| 800 | + min_head_len += 2; |
|---|
| 756 | 801 | } |
|---|
| 757 | 802 | |
|---|
| 758 | | - /* ensure hdr->frame_control and vendor radiotap data are in skb head */ |
|---|
| 759 | | - if (!pskb_may_pull(origskb, 2 + rtap_space)) { |
|---|
| 803 | + /* ensure that the expected data elements are in skb head */ |
|---|
| 804 | + if (!pskb_may_pull(origskb, min_head_len)) { |
|---|
| 760 | 805 | dev_kfree_skb(origskb); |
|---|
| 761 | 806 | return NULL; |
|---|
| 762 | 807 | } |
|---|
| .. | .. |
|---|
| 769 | 814 | return NULL; |
|---|
| 770 | 815 | } |
|---|
| 771 | 816 | |
|---|
| 772 | | - remove_monitor_info(origskb, present_fcs_len, rtap_space); |
|---|
| 773 | | - return origskb; |
|---|
| 817 | + return ieee80211_clean_skb(origskb, present_fcs_len, |
|---|
| 818 | + rtap_space); |
|---|
| 774 | 819 | } |
|---|
| 775 | 820 | |
|---|
| 776 | 821 | ieee80211_handle_mu_mimo_mon(monitor_sdata, origskb, rtap_space); |
|---|
| .. | .. |
|---|
| 813 | 858 | if (!origskb) |
|---|
| 814 | 859 | return NULL; |
|---|
| 815 | 860 | |
|---|
| 816 | | - remove_monitor_info(origskb, present_fcs_len, rtap_space); |
|---|
| 817 | | - return origskb; |
|---|
| 861 | + return ieee80211_clean_skb(origskb, present_fcs_len, rtap_space); |
|---|
| 818 | 862 | } |
|---|
| 819 | 863 | |
|---|
| 820 | 864 | static void ieee80211_parse_qos(struct ieee80211_rx_data *rx) |
|---|
| .. | .. |
|---|
| 926 | 970 | if (skb->len < 24 + sizeof(*mmie) || !is_multicast_ether_addr(hdr->da)) |
|---|
| 927 | 971 | return -1; |
|---|
| 928 | 972 | |
|---|
| 929 | | - if (!ieee80211_is_robust_mgmt_frame(skb)) |
|---|
| 973 | + if (!ieee80211_is_robust_mgmt_frame(skb) && |
|---|
| 974 | + !ieee80211_is_beacon(hdr->frame_control)) |
|---|
| 930 | 975 | return -1; /* not a robust management frame */ |
|---|
| 931 | 976 | |
|---|
| 932 | 977 | mmie = (struct ieee80211_mmie *) |
|---|
| .. | .. |
|---|
| 945 | 990 | return -1; |
|---|
| 946 | 991 | } |
|---|
| 947 | 992 | |
|---|
| 948 | | -static int ieee80211_get_cs_keyid(const struct ieee80211_cipher_scheme *cs, |
|---|
| 949 | | - struct sk_buff *skb) |
|---|
| 993 | +static int ieee80211_get_keyid(struct sk_buff *skb, |
|---|
| 994 | + const struct ieee80211_cipher_scheme *cs) |
|---|
| 950 | 995 | { |
|---|
| 951 | 996 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; |
|---|
| 952 | 997 | __le16 fc; |
|---|
| 953 | 998 | int hdrlen; |
|---|
| 999 | + int minlen; |
|---|
| 1000 | + u8 key_idx_off; |
|---|
| 1001 | + u8 key_idx_shift; |
|---|
| 954 | 1002 | u8 keyid; |
|---|
| 955 | 1003 | |
|---|
| 956 | 1004 | fc = hdr->frame_control; |
|---|
| 957 | 1005 | hdrlen = ieee80211_hdrlen(fc); |
|---|
| 958 | 1006 | |
|---|
| 959 | | - if (skb->len < hdrlen + cs->hdr_len) |
|---|
| 1007 | + if (cs) { |
|---|
| 1008 | + minlen = hdrlen + cs->hdr_len; |
|---|
| 1009 | + key_idx_off = hdrlen + cs->key_idx_off; |
|---|
| 1010 | + key_idx_shift = cs->key_idx_shift; |
|---|
| 1011 | + } else { |
|---|
| 1012 | + /* WEP, TKIP, CCMP and GCMP */ |
|---|
| 1013 | + minlen = hdrlen + IEEE80211_WEP_IV_LEN; |
|---|
| 1014 | + key_idx_off = hdrlen + 3; |
|---|
| 1015 | + key_idx_shift = 6; |
|---|
| 1016 | + } |
|---|
| 1017 | + |
|---|
| 1018 | + if (unlikely(skb->len < minlen)) |
|---|
| 960 | 1019 | return -EINVAL; |
|---|
| 961 | 1020 | |
|---|
| 962 | | - skb_copy_bits(skb, hdrlen + cs->key_idx_off, &keyid, 1); |
|---|
| 963 | | - keyid &= cs->key_idx_mask; |
|---|
| 964 | | - keyid >>= cs->key_idx_shift; |
|---|
| 1021 | + skb_copy_bits(skb, key_idx_off, &keyid, 1); |
|---|
| 1022 | + |
|---|
| 1023 | + if (cs) |
|---|
| 1024 | + keyid &= cs->key_idx_mask; |
|---|
| 1025 | + keyid >>= key_idx_shift; |
|---|
| 1026 | + |
|---|
| 1027 | + /* cs could use more than the usual two bits for the keyid */ |
|---|
| 1028 | + if (unlikely(keyid >= NUM_DEFAULT_KEYS)) |
|---|
| 1029 | + return -EINVAL; |
|---|
| 965 | 1030 | |
|---|
| 966 | 1031 | return keyid; |
|---|
| 967 | 1032 | } |
|---|
| .. | .. |
|---|
| 1322 | 1387 | goto dont_reorder; |
|---|
| 1323 | 1388 | |
|---|
| 1324 | 1389 | /* not part of a BA session */ |
|---|
| 1325 | | - if (ack_policy != IEEE80211_QOS_CTL_ACK_POLICY_BLOCKACK && |
|---|
| 1326 | | - ack_policy != IEEE80211_QOS_CTL_ACK_POLICY_NORMAL) |
|---|
| 1390 | + if (ack_policy == IEEE80211_QOS_CTL_ACK_POLICY_NOACK) |
|---|
| 1327 | 1391 | goto dont_reorder; |
|---|
| 1328 | 1392 | |
|---|
| 1329 | 1393 | /* new, potentially un-ordered, ampdu frame - process it */ |
|---|
| .. | .. |
|---|
| 1506 | 1570 | if (!sta->sta.txq[0]) |
|---|
| 1507 | 1571 | return; |
|---|
| 1508 | 1572 | |
|---|
| 1509 | | - for (tid = 0; tid < ARRAY_SIZE(sta->sta.txq); tid++) { |
|---|
| 1510 | | - if (txq_has_queue(sta->sta.txq[tid])) |
|---|
| 1573 | + for (tid = 0; tid < IEEE80211_NUM_TIDS; tid++) { |
|---|
| 1574 | + struct ieee80211_txq *txq = sta->sta.txq[tid]; |
|---|
| 1575 | + struct txq_info *txqi = to_txq_info(txq); |
|---|
| 1576 | + |
|---|
| 1577 | + spin_lock(&local->active_txq_lock[txq->ac]); |
|---|
| 1578 | + if (!list_empty(&txqi->schedule_order)) |
|---|
| 1579 | + list_del_init(&txqi->schedule_order); |
|---|
| 1580 | + spin_unlock(&local->active_txq_lock[txq->ac]); |
|---|
| 1581 | + |
|---|
| 1582 | + if (txq_has_queue(txq)) |
|---|
| 1511 | 1583 | set_bit(tid, &sta->txq_buffered_tids); |
|---|
| 1512 | 1584 | else |
|---|
| 1513 | 1585 | clear_bit(tid, &sta->txq_buffered_tids); |
|---|
| .. | .. |
|---|
| 1684 | 1756 | } |
|---|
| 1685 | 1757 | } else if (rx->sdata->vif.type == NL80211_IFTYPE_OCB) { |
|---|
| 1686 | 1758 | sta->rx_stats.last_rx = jiffies; |
|---|
| 1687 | | - } else if (!is_multicast_ether_addr(hdr->addr1)) { |
|---|
| 1759 | + } else if (!ieee80211_is_s1g_beacon(hdr->frame_control) && |
|---|
| 1760 | + !is_multicast_ether_addr(hdr->addr1)) { |
|---|
| 1688 | 1761 | /* |
|---|
| 1689 | 1762 | * Mesh beacons will update last_rx when if they are found to |
|---|
| 1690 | 1763 | * match the current local configuration when processed. |
|---|
| .. | .. |
|---|
| 1693 | 1766 | if (ieee80211_is_data(hdr->frame_control)) |
|---|
| 1694 | 1767 | sta->rx_stats.last_rate = sta_stats_encode_rate(status); |
|---|
| 1695 | 1768 | } |
|---|
| 1696 | | - |
|---|
| 1697 | | - if (rx->sdata->vif.type == NL80211_IFTYPE_STATION) |
|---|
| 1698 | | - ieee80211_sta_rx_notify(rx->sdata, hdr); |
|---|
| 1699 | 1769 | |
|---|
| 1700 | 1770 | sta->rx_stats.fragments++; |
|---|
| 1701 | 1771 | |
|---|
| .. | .. |
|---|
| 1721 | 1791 | -signal); |
|---|
| 1722 | 1792 | } |
|---|
| 1723 | 1793 | } |
|---|
| 1794 | + |
|---|
| 1795 | + if (ieee80211_is_s1g_beacon(hdr->frame_control)) |
|---|
| 1796 | + return RX_CONTINUE; |
|---|
| 1724 | 1797 | |
|---|
| 1725 | 1798 | /* |
|---|
| 1726 | 1799 | * Change STA power saving mode only at the end of a frame |
|---|
| .. | .. |
|---|
| 1783 | 1856 | return RX_CONTINUE; |
|---|
| 1784 | 1857 | } /* ieee80211_rx_h_sta_process */ |
|---|
| 1785 | 1858 | |
|---|
| 1859 | +static struct ieee80211_key * |
|---|
| 1860 | +ieee80211_rx_get_bigtk(struct ieee80211_rx_data *rx, int idx) |
|---|
| 1861 | +{ |
|---|
| 1862 | + struct ieee80211_key *key = NULL; |
|---|
| 1863 | + struct ieee80211_sub_if_data *sdata = rx->sdata; |
|---|
| 1864 | + int idx2; |
|---|
| 1865 | + |
|---|
| 1866 | + /* Make sure key gets set if either BIGTK key index is set so that |
|---|
| 1867 | + * ieee80211_drop_unencrypted_mgmt() can properly drop both unprotected |
|---|
| 1868 | + * Beacon frames and Beacon frames that claim to use another BIGTK key |
|---|
| 1869 | + * index (i.e., a key that we do not have). |
|---|
| 1870 | + */ |
|---|
| 1871 | + |
|---|
| 1872 | + if (idx < 0) { |
|---|
| 1873 | + idx = NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS; |
|---|
| 1874 | + idx2 = idx + 1; |
|---|
| 1875 | + } else { |
|---|
| 1876 | + if (idx == NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS) |
|---|
| 1877 | + idx2 = idx + 1; |
|---|
| 1878 | + else |
|---|
| 1879 | + idx2 = idx - 1; |
|---|
| 1880 | + } |
|---|
| 1881 | + |
|---|
| 1882 | + if (rx->sta) |
|---|
| 1883 | + key = rcu_dereference(rx->sta->gtk[idx]); |
|---|
| 1884 | + if (!key) |
|---|
| 1885 | + key = rcu_dereference(sdata->keys[idx]); |
|---|
| 1886 | + if (!key && rx->sta) |
|---|
| 1887 | + key = rcu_dereference(rx->sta->gtk[idx2]); |
|---|
| 1888 | + if (!key) |
|---|
| 1889 | + key = rcu_dereference(sdata->keys[idx2]); |
|---|
| 1890 | + |
|---|
| 1891 | + return key; |
|---|
| 1892 | +} |
|---|
| 1893 | + |
|---|
| 1786 | 1894 | static ieee80211_rx_result debug_noinline |
|---|
| 1787 | 1895 | ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) |
|---|
| 1788 | 1896 | { |
|---|
| .. | .. |
|---|
| 1790 | 1898 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); |
|---|
| 1791 | 1899 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; |
|---|
| 1792 | 1900 | int keyidx; |
|---|
| 1793 | | - int hdrlen; |
|---|
| 1794 | 1901 | ieee80211_rx_result result = RX_DROP_UNUSABLE; |
|---|
| 1795 | 1902 | struct ieee80211_key *sta_ptk = NULL; |
|---|
| 1903 | + struct ieee80211_key *ptk_idx = NULL; |
|---|
| 1796 | 1904 | int mmie_keyidx = -1; |
|---|
| 1797 | 1905 | __le16 fc; |
|---|
| 1798 | 1906 | const struct ieee80211_cipher_scheme *cs = NULL; |
|---|
| 1799 | 1907 | |
|---|
| 1908 | + if (ieee80211_is_ext(hdr->frame_control)) |
|---|
| 1909 | + return RX_CONTINUE; |
|---|
| 1910 | + |
|---|
| 1800 | 1911 | /* |
|---|
| 1801 | 1912 | * Key selection 101 |
|---|
| 1802 | 1913 | * |
|---|
| 1803 | | - * There are four types of keys: |
|---|
| 1914 | + * There are five types of keys: |
|---|
| 1804 | 1915 | * - GTK (group keys) |
|---|
| 1805 | 1916 | * - IGTK (group keys for management frames) |
|---|
| 1917 | + * - BIGTK (group keys for Beacon frames) |
|---|
| 1806 | 1918 | * - PTK (pairwise keys) |
|---|
| 1807 | 1919 | * - STK (station-to-station pairwise keys) |
|---|
| 1808 | 1920 | * |
|---|
| 1809 | 1921 | * When selecting a key, we have to distinguish between multicast |
|---|
| 1810 | 1922 | * (including broadcast) and unicast frames, the latter can only |
|---|
| 1811 | | - * use PTKs and STKs while the former always use GTKs and IGTKs. |
|---|
| 1812 | | - * Unless, of course, actual WEP keys ("pre-RSNA") are used, then |
|---|
| 1813 | | - * unicast frames can also use key indices like GTKs. Hence, if we |
|---|
| 1923 | + * use PTKs and STKs while the former always use GTKs, IGTKs, and |
|---|
| 1924 | + * BIGTKs. Unless, of course, actual WEP keys ("pre-RSNA") are used, |
|---|
| 1925 | + * then unicast frames can also use key indices like GTKs. Hence, if we |
|---|
| 1814 | 1926 | * don't have a PTK/STK we check the key index for a WEP key. |
|---|
| 1815 | 1927 | * |
|---|
| 1816 | 1928 | * Note that in a regular BSS, multicast frames are sent by the |
|---|
| .. | .. |
|---|
| 1830 | 1942 | |
|---|
| 1831 | 1943 | if (rx->sta) { |
|---|
| 1832 | 1944 | int keyid = rx->sta->ptk_idx; |
|---|
| 1945 | + sta_ptk = rcu_dereference(rx->sta->ptk[keyid]); |
|---|
| 1833 | 1946 | |
|---|
| 1834 | | - if (ieee80211_has_protected(fc) && rx->sta->cipher_scheme) { |
|---|
| 1947 | + if (ieee80211_has_protected(fc) && |
|---|
| 1948 | + !(status->flag & RX_FLAG_IV_STRIPPED)) { |
|---|
| 1835 | 1949 | cs = rx->sta->cipher_scheme; |
|---|
| 1836 | | - keyid = ieee80211_get_cs_keyid(cs, rx->skb); |
|---|
| 1950 | + keyid = ieee80211_get_keyid(rx->skb, cs); |
|---|
| 1951 | + |
|---|
| 1837 | 1952 | if (unlikely(keyid < 0)) |
|---|
| 1838 | 1953 | return RX_DROP_UNUSABLE; |
|---|
| 1954 | + |
|---|
| 1955 | + ptk_idx = rcu_dereference(rx->sta->ptk[keyid]); |
|---|
| 1839 | 1956 | } |
|---|
| 1840 | | - sta_ptk = rcu_dereference(rx->sta->ptk[keyid]); |
|---|
| 1841 | 1957 | } |
|---|
| 1842 | 1958 | |
|---|
| 1843 | 1959 | if (!ieee80211_has_protected(fc)) |
|---|
| 1844 | 1960 | mmie_keyidx = ieee80211_get_mmie_keyidx(rx->skb); |
|---|
| 1845 | 1961 | |
|---|
| 1846 | 1962 | if (!is_multicast_ether_addr(hdr->addr1) && sta_ptk) { |
|---|
| 1847 | | - rx->key = sta_ptk; |
|---|
| 1963 | + rx->key = ptk_idx ? ptk_idx : sta_ptk; |
|---|
| 1848 | 1964 | if ((status->flag & RX_FLAG_DECRYPTED) && |
|---|
| 1849 | 1965 | (status->flag & RX_FLAG_IV_STRIPPED)) |
|---|
| 1850 | 1966 | return RX_CONTINUE; |
|---|
| 1851 | 1967 | /* Skip decryption if the frame is not protected. */ |
|---|
| 1852 | 1968 | if (!ieee80211_has_protected(fc)) |
|---|
| 1853 | 1969 | return RX_CONTINUE; |
|---|
| 1970 | + } else if (mmie_keyidx >= 0 && ieee80211_is_beacon(fc)) { |
|---|
| 1971 | + /* Broadcast/multicast robust management frame / BIP */ |
|---|
| 1972 | + if ((status->flag & RX_FLAG_DECRYPTED) && |
|---|
| 1973 | + (status->flag & RX_FLAG_IV_STRIPPED)) |
|---|
| 1974 | + return RX_CONTINUE; |
|---|
| 1975 | + |
|---|
| 1976 | + if (mmie_keyidx < NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS || |
|---|
| 1977 | + mmie_keyidx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS + |
|---|
| 1978 | + NUM_DEFAULT_BEACON_KEYS) { |
|---|
| 1979 | + if (rx->sdata->dev) |
|---|
| 1980 | + cfg80211_rx_unprot_mlme_mgmt(rx->sdata->dev, |
|---|
| 1981 | + skb->data, |
|---|
| 1982 | + skb->len); |
|---|
| 1983 | + return RX_DROP_MONITOR; /* unexpected BIP keyidx */ |
|---|
| 1984 | + } |
|---|
| 1985 | + |
|---|
| 1986 | + rx->key = ieee80211_rx_get_bigtk(rx, mmie_keyidx); |
|---|
| 1987 | + if (!rx->key) |
|---|
| 1988 | + return RX_CONTINUE; /* Beacon protection not in use */ |
|---|
| 1854 | 1989 | } else if (mmie_keyidx >= 0) { |
|---|
| 1855 | 1990 | /* Broadcast/multicast robust management frame / BIP */ |
|---|
| 1856 | 1991 | if ((status->flag & RX_FLAG_DECRYPTED) && |
|---|
| .. | .. |
|---|
| 1880 | 2015 | struct ieee80211_sub_if_data *sdata = rx->sdata; |
|---|
| 1881 | 2016 | int i; |
|---|
| 1882 | 2017 | |
|---|
| 1883 | | - if (ieee80211_is_mgmt(fc) && |
|---|
| 1884 | | - is_multicast_ether_addr(hdr->addr1) && |
|---|
| 1885 | | - (key = rcu_dereference(rx->sdata->default_mgmt_key))) |
|---|
| 1886 | | - rx->key = key; |
|---|
| 1887 | | - else { |
|---|
| 2018 | + if (ieee80211_is_beacon(fc)) { |
|---|
| 2019 | + key = ieee80211_rx_get_bigtk(rx, -1); |
|---|
| 2020 | + } else if (ieee80211_is_mgmt(fc) && |
|---|
| 2021 | + is_multicast_ether_addr(hdr->addr1)) { |
|---|
| 2022 | + key = rcu_dereference(rx->sdata->default_mgmt_key); |
|---|
| 2023 | + } else { |
|---|
| 1888 | 2024 | if (rx->sta) { |
|---|
| 1889 | 2025 | for (i = 0; i < NUM_DEFAULT_KEYS; i++) { |
|---|
| 1890 | 2026 | key = rcu_dereference(rx->sta->gtk[i]); |
|---|
| .. | .. |
|---|
| 1899 | 2035 | break; |
|---|
| 1900 | 2036 | } |
|---|
| 1901 | 2037 | } |
|---|
| 1902 | | - if (key) |
|---|
| 1903 | | - rx->key = key; |
|---|
| 1904 | 2038 | } |
|---|
| 2039 | + if (key) |
|---|
| 2040 | + rx->key = key; |
|---|
| 1905 | 2041 | return RX_CONTINUE; |
|---|
| 1906 | 2042 | } else { |
|---|
| 1907 | | - u8 keyid; |
|---|
| 1908 | | - |
|---|
| 1909 | 2043 | /* |
|---|
| 1910 | 2044 | * The device doesn't give us the IV so we won't be |
|---|
| 1911 | 2045 | * able to look up the key. That's ok though, we |
|---|
| .. | .. |
|---|
| 1919 | 2053 | (status->flag & RX_FLAG_IV_STRIPPED)) |
|---|
| 1920 | 2054 | return RX_CONTINUE; |
|---|
| 1921 | 2055 | |
|---|
| 1922 | | - hdrlen = ieee80211_hdrlen(fc); |
|---|
| 2056 | + keyidx = ieee80211_get_keyid(rx->skb, cs); |
|---|
| 1923 | 2057 | |
|---|
| 1924 | | - if (cs) { |
|---|
| 1925 | | - keyidx = ieee80211_get_cs_keyid(cs, rx->skb); |
|---|
| 1926 | | - |
|---|
| 1927 | | - if (unlikely(keyidx < 0)) |
|---|
| 1928 | | - return RX_DROP_UNUSABLE; |
|---|
| 1929 | | - } else { |
|---|
| 1930 | | - if (rx->skb->len < 8 + hdrlen) |
|---|
| 1931 | | - return RX_DROP_UNUSABLE; /* TODO: count this? */ |
|---|
| 1932 | | - /* |
|---|
| 1933 | | - * no need to call ieee80211_wep_get_keyidx, |
|---|
| 1934 | | - * it verifies a bunch of things we've done already |
|---|
| 1935 | | - */ |
|---|
| 1936 | | - skb_copy_bits(rx->skb, hdrlen + 3, &keyid, 1); |
|---|
| 1937 | | - keyidx = keyid >> 6; |
|---|
| 1938 | | - } |
|---|
| 2058 | + if (unlikely(keyidx < 0)) |
|---|
| 2059 | + return RX_DROP_UNUSABLE; |
|---|
| 1939 | 2060 | |
|---|
| 1940 | 2061 | /* check per-station GTK first, if multicast packet */ |
|---|
| 1941 | 2062 | if (is_multicast_ether_addr(hdr->addr1) && rx->sta) |
|---|
| .. | .. |
|---|
| 2006 | 2127 | /* either the frame has been decrypted or will be dropped */ |
|---|
| 2007 | 2128 | status->flag |= RX_FLAG_DECRYPTED; |
|---|
| 2008 | 2129 | |
|---|
| 2130 | + if (unlikely(ieee80211_is_beacon(fc) && result == RX_DROP_UNUSABLE && |
|---|
| 2131 | + rx->sdata->dev)) |
|---|
| 2132 | + cfg80211_rx_unprot_mlme_mgmt(rx->sdata->dev, |
|---|
| 2133 | + skb->data, skb->len); |
|---|
| 2134 | + |
|---|
| 2009 | 2135 | return result; |
|---|
| 2010 | 2136 | } |
|---|
| 2011 | 2137 | |
|---|
| .. | .. |
|---|
| 2061 | 2187 | idx = cache->next; |
|---|
| 2062 | 2188 | for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++) { |
|---|
| 2063 | 2189 | struct ieee80211_hdr *f_hdr; |
|---|
| 2190 | + struct sk_buff *f_skb; |
|---|
| 2064 | 2191 | |
|---|
| 2065 | 2192 | idx--; |
|---|
| 2066 | 2193 | if (idx < 0) |
|---|
| .. | .. |
|---|
| 2072 | 2199 | entry->last_frag + 1 != frag) |
|---|
| 2073 | 2200 | continue; |
|---|
| 2074 | 2201 | |
|---|
| 2075 | | - f_hdr = (struct ieee80211_hdr *)entry->skb_list.next->data; |
|---|
| 2202 | + f_skb = __skb_peek(&entry->skb_list); |
|---|
| 2203 | + f_hdr = (struct ieee80211_hdr *) f_skb->data; |
|---|
| 2076 | 2204 | |
|---|
| 2077 | 2205 | /* |
|---|
| 2078 | 2206 | * Check ftype and addresses are equal, else check next fragment |
|---|
| .. | .. |
|---|
| 2118 | 2246 | hdr = (struct ieee80211_hdr *)rx->skb->data; |
|---|
| 2119 | 2247 | fc = hdr->frame_control; |
|---|
| 2120 | 2248 | |
|---|
| 2121 | | - if (ieee80211_is_ctl(fc)) |
|---|
| 2249 | + if (ieee80211_is_ctl(fc) || ieee80211_is_ext(fc)) |
|---|
| 2122 | 2250 | return RX_CONTINUE; |
|---|
| 2123 | 2251 | |
|---|
| 2124 | 2252 | sc = le16_to_cpu(hdr->seq_ctrl); |
|---|
| .. | .. |
|---|
| 2352 | 2480 | rx->skb->len); |
|---|
| 2353 | 2481 | return -EACCES; |
|---|
| 2354 | 2482 | } |
|---|
| 2483 | + if (unlikely(ieee80211_is_beacon(fc) && rx->key && |
|---|
| 2484 | + ieee80211_get_mmie_keyidx(rx->skb) < 0)) { |
|---|
| 2485 | + cfg80211_rx_unprot_mlme_mgmt(rx->sdata->dev, |
|---|
| 2486 | + rx->skb->data, |
|---|
| 2487 | + rx->skb->len); |
|---|
| 2488 | + return -EACCES; |
|---|
| 2489 | + } |
|---|
| 2355 | 2490 | /* |
|---|
| 2356 | 2491 | * When using MFP, Action frames are not allowed prior to |
|---|
| 2357 | 2492 | * having configured keys. |
|---|
| .. | .. |
|---|
| 2383 | 2518 | |
|---|
| 2384 | 2519 | if (!sdata->u.mgd.use_4addr) |
|---|
| 2385 | 2520 | return -1; |
|---|
| 2386 | | - else |
|---|
| 2521 | + else if (!ether_addr_equal(hdr->addr1, sdata->vif.addr)) |
|---|
| 2387 | 2522 | check_port_control = true; |
|---|
| 2388 | 2523 | } |
|---|
| 2389 | 2524 | |
|---|
| .. | .. |
|---|
| 2436 | 2571 | struct net_device *dev = sdata->dev; |
|---|
| 2437 | 2572 | |
|---|
| 2438 | 2573 | if (unlikely((skb->protocol == sdata->control_port_protocol || |
|---|
| 2439 | | - skb->protocol == cpu_to_be16(ETH_P_PREAUTH)) && |
|---|
| 2574 | + (skb->protocol == cpu_to_be16(ETH_P_PREAUTH) && |
|---|
| 2575 | + !sdata->control_port_no_preauth)) && |
|---|
| 2440 | 2576 | sdata->control_port_over_nl80211)) { |
|---|
| 2441 | 2577 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); |
|---|
| 2442 | 2578 | bool noencrypt = !(status->flag & RX_FLAG_DECRYPTED); |
|---|
| .. | .. |
|---|
| 2467 | 2603 | ether_addr_copy(ehdr->h_dest, sdata->vif.addr); |
|---|
| 2468 | 2604 | |
|---|
| 2469 | 2605 | /* deliver to local stack */ |
|---|
| 2470 | | - if (rx->napi) |
|---|
| 2471 | | - napi_gro_receive(rx->napi, skb); |
|---|
| 2606 | + if (rx->list) |
|---|
| 2607 | + list_add_tail(&skb->list, rx->list); |
|---|
| 2472 | 2608 | else |
|---|
| 2473 | 2609 | netif_receive_skb(skb); |
|---|
| 2474 | 2610 | } |
|---|
| .. | .. |
|---|
| 2517 | 2653 | if (!xmit_skb) |
|---|
| 2518 | 2654 | net_info_ratelimited("%s: failed to clone multicast frame\n", |
|---|
| 2519 | 2655 | dev->name); |
|---|
| 2520 | | - } else if (!is_multicast_ether_addr(ehdr->h_dest)) { |
|---|
| 2521 | | - dsta = sta_info_get(sdata, skb->data); |
|---|
| 2656 | + } else if (!is_multicast_ether_addr(ehdr->h_dest) && |
|---|
| 2657 | + !ether_addr_equal(ehdr->h_dest, ehdr->h_source)) { |
|---|
| 2658 | + dsta = sta_info_get(sdata, ehdr->h_dest); |
|---|
| 2522 | 2659 | if (dsta) { |
|---|
| 2523 | 2660 | /* |
|---|
| 2524 | 2661 | * The destination station is associated to |
|---|
| .. | .. |
|---|
| 2774 | 2911 | ether_addr_equal(sdata->vif.addr, hdr->addr3)) |
|---|
| 2775 | 2912 | return RX_CONTINUE; |
|---|
| 2776 | 2913 | |
|---|
| 2777 | | - ac = ieee80211_select_queue_80211(sdata, skb, hdr); |
|---|
| 2914 | + ac = ieee802_1d_to_ac[skb->priority]; |
|---|
| 2778 | 2915 | q = sdata->vif.hw_queue[ac]; |
|---|
| 2779 | 2916 | if (ieee80211_queue_stopped(&local->hw, q)) { |
|---|
| 2780 | 2917 | IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_congestion); |
|---|
| 2781 | 2918 | return RX_DROP_MONITOR; |
|---|
| 2782 | 2919 | } |
|---|
| 2783 | | - skb_set_queue_mapping(skb, q); |
|---|
| 2920 | + skb_set_queue_mapping(skb, ac); |
|---|
| 2784 | 2921 | |
|---|
| 2785 | 2922 | if (!--mesh_hdr->ttl) { |
|---|
| 2786 | 2923 | if (!is_multicast_ether_addr(hdr->addr1)) |
|---|
| .. | .. |
|---|
| 2805 | 2942 | fwd_hdr->frame_control &= ~cpu_to_le16(IEEE80211_FCTL_RETRY); |
|---|
| 2806 | 2943 | info = IEEE80211_SKB_CB(fwd_skb); |
|---|
| 2807 | 2944 | memset(info, 0, sizeof(*info)); |
|---|
| 2808 | | - info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; |
|---|
| 2945 | + info->control.flags |= IEEE80211_TX_INTCFL_NEED_TXPROCESSING; |
|---|
| 2809 | 2946 | info->control.vif = &rx->sdata->vif; |
|---|
| 2810 | 2947 | info->control.jiffies = jiffies; |
|---|
| 2811 | 2948 | if (is_multicast_ether_addr(fwd_hdr->addr1)) { |
|---|
| .. | .. |
|---|
| 3037 | 3174 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data; |
|---|
| 3038 | 3175 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); |
|---|
| 3039 | 3176 | |
|---|
| 3177 | + if (ieee80211_is_s1g_beacon(mgmt->frame_control)) |
|---|
| 3178 | + return RX_CONTINUE; |
|---|
| 3179 | + |
|---|
| 3040 | 3180 | /* |
|---|
| 3041 | 3181 | * From here on, look only at management frames. |
|---|
| 3042 | 3182 | * Data and control frames are already handled, |
|---|
| .. | .. |
|---|
| 3057 | 3197 | !(status->flag & RX_FLAG_NO_SIGNAL_VAL)) |
|---|
| 3058 | 3198 | sig = status->signal; |
|---|
| 3059 | 3199 | |
|---|
| 3060 | | - cfg80211_report_obss_beacon(rx->local->hw.wiphy, |
|---|
| 3061 | | - rx->skb->data, rx->skb->len, |
|---|
| 3062 | | - status->freq, sig); |
|---|
| 3200 | + cfg80211_report_obss_beacon_khz(rx->local->hw.wiphy, |
|---|
| 3201 | + rx->skb->data, rx->skb->len, |
|---|
| 3202 | + ieee80211_rx_status_to_khz(status), |
|---|
| 3203 | + sig); |
|---|
| 3063 | 3204 | rx->flags |= IEEE80211_RX_BEACON_REPORTED; |
|---|
| 3064 | 3205 | } |
|---|
| 3065 | 3206 | |
|---|
| .. | .. |
|---|
| 3112 | 3253 | struct ieee80211_supported_band *sband; |
|---|
| 3113 | 3254 | enum ieee80211_smps_mode smps_mode; |
|---|
| 3114 | 3255 | struct sta_opmode_info sta_opmode = {}; |
|---|
| 3256 | + |
|---|
| 3257 | + if (sdata->vif.type != NL80211_IFTYPE_AP && |
|---|
| 3258 | + sdata->vif.type != NL80211_IFTYPE_AP_VLAN) |
|---|
| 3259 | + goto handled; |
|---|
| 3115 | 3260 | |
|---|
| 3116 | 3261 | /* convert to HT capability */ |
|---|
| 3117 | 3262 | switch (mgmt->u.action.u.ht_smps.smps_control) { |
|---|
| .. | .. |
|---|
| 3311 | 3456 | } |
|---|
| 3312 | 3457 | } |
|---|
| 3313 | 3458 | break; |
|---|
| 3314 | | - case WLAN_CATEGORY_SA_QUERY: |
|---|
| 3315 | | - if (len < (IEEE80211_MIN_ACTION_SIZE + |
|---|
| 3316 | | - sizeof(mgmt->u.action.u.sa_query))) |
|---|
| 3317 | | - break; |
|---|
| 3318 | | - |
|---|
| 3319 | | - switch (mgmt->u.action.u.sa_query.action) { |
|---|
| 3320 | | - case WLAN_ACTION_SA_QUERY_REQUEST: |
|---|
| 3321 | | - if (sdata->vif.type != NL80211_IFTYPE_STATION) |
|---|
| 3322 | | - break; |
|---|
| 3323 | | - ieee80211_process_sa_query_req(sdata, mgmt, len); |
|---|
| 3324 | | - goto handled; |
|---|
| 3325 | | - } |
|---|
| 3326 | | - break; |
|---|
| 3327 | 3459 | case WLAN_CATEGORY_SELF_PROTECTED: |
|---|
| 3328 | 3460 | if (len < (IEEE80211_MIN_ACTION_SIZE + |
|---|
| 3329 | 3461 | sizeof(mgmt->u.action.u.self_prot.action_code))) |
|---|
| .. | .. |
|---|
| 3401 | 3533 | !(status->flag & RX_FLAG_NO_SIGNAL_VAL)) |
|---|
| 3402 | 3534 | sig = status->signal; |
|---|
| 3403 | 3535 | |
|---|
| 3404 | | - if (cfg80211_rx_mgmt(&rx->sdata->wdev, status->freq, sig, |
|---|
| 3405 | | - rx->skb->data, rx->skb->len, 0)) { |
|---|
| 3536 | + if (cfg80211_rx_mgmt_khz(&rx->sdata->wdev, |
|---|
| 3537 | + ieee80211_rx_status_to_khz(status), sig, |
|---|
| 3538 | + rx->skb->data, rx->skb->len, 0)) { |
|---|
| 3406 | 3539 | if (rx->sta) |
|---|
| 3407 | 3540 | rx->sta->rx_stats.packets++; |
|---|
| 3408 | 3541 | dev_kfree_skb(rx->skb); |
|---|
| .. | .. |
|---|
| 3410 | 3543 | } |
|---|
| 3411 | 3544 | |
|---|
| 3412 | 3545 | return RX_CONTINUE; |
|---|
| 3546 | +} |
|---|
| 3547 | + |
|---|
| 3548 | +static ieee80211_rx_result debug_noinline |
|---|
| 3549 | +ieee80211_rx_h_action_post_userspace(struct ieee80211_rx_data *rx) |
|---|
| 3550 | +{ |
|---|
| 3551 | + struct ieee80211_sub_if_data *sdata = rx->sdata; |
|---|
| 3552 | + struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data; |
|---|
| 3553 | + int len = rx->skb->len; |
|---|
| 3554 | + |
|---|
| 3555 | + if (!ieee80211_is_action(mgmt->frame_control)) |
|---|
| 3556 | + return RX_CONTINUE; |
|---|
| 3557 | + |
|---|
| 3558 | + switch (mgmt->u.action.category) { |
|---|
| 3559 | + case WLAN_CATEGORY_SA_QUERY: |
|---|
| 3560 | + if (len < (IEEE80211_MIN_ACTION_SIZE + |
|---|
| 3561 | + sizeof(mgmt->u.action.u.sa_query))) |
|---|
| 3562 | + break; |
|---|
| 3563 | + |
|---|
| 3564 | + switch (mgmt->u.action.u.sa_query.action) { |
|---|
| 3565 | + case WLAN_ACTION_SA_QUERY_REQUEST: |
|---|
| 3566 | + if (sdata->vif.type != NL80211_IFTYPE_STATION) |
|---|
| 3567 | + break; |
|---|
| 3568 | + ieee80211_process_sa_query_req(sdata, mgmt, len); |
|---|
| 3569 | + goto handled; |
|---|
| 3570 | + } |
|---|
| 3571 | + break; |
|---|
| 3572 | + } |
|---|
| 3573 | + |
|---|
| 3574 | + return RX_CONTINUE; |
|---|
| 3575 | + |
|---|
| 3576 | + handled: |
|---|
| 3577 | + if (rx->sta) |
|---|
| 3578 | + rx->sta->rx_stats.packets++; |
|---|
| 3579 | + dev_kfree_skb(rx->skb); |
|---|
| 3580 | + return RX_QUEUED; |
|---|
| 3413 | 3581 | } |
|---|
| 3414 | 3582 | |
|---|
| 3415 | 3583 | static ieee80211_rx_result debug_noinline |
|---|
| .. | .. |
|---|
| 3469 | 3637 | } |
|---|
| 3470 | 3638 | |
|---|
| 3471 | 3639 | __ieee80211_tx_skb_tid_band(rx->sdata, nskb, 7, |
|---|
| 3472 | | - status->band, 0); |
|---|
| 3640 | + status->band); |
|---|
| 3473 | 3641 | } |
|---|
| 3474 | 3642 | dev_kfree_skb(rx->skb); |
|---|
| 3643 | + return RX_QUEUED; |
|---|
| 3644 | +} |
|---|
| 3645 | + |
|---|
| 3646 | +static ieee80211_rx_result debug_noinline |
|---|
| 3647 | +ieee80211_rx_h_ext(struct ieee80211_rx_data *rx) |
|---|
| 3648 | +{ |
|---|
| 3649 | + struct ieee80211_sub_if_data *sdata = rx->sdata; |
|---|
| 3650 | + struct ieee80211_hdr *hdr = (void *)rx->skb->data; |
|---|
| 3651 | + |
|---|
| 3652 | + if (!ieee80211_is_ext(hdr->frame_control)) |
|---|
| 3653 | + return RX_CONTINUE; |
|---|
| 3654 | + |
|---|
| 3655 | + if (sdata->vif.type != NL80211_IFTYPE_STATION) |
|---|
| 3656 | + return RX_DROP_MONITOR; |
|---|
| 3657 | + |
|---|
| 3658 | + /* for now only beacons are ext, so queue them */ |
|---|
| 3659 | + skb_queue_tail(&sdata->skb_queue, rx->skb); |
|---|
| 3660 | + ieee80211_queue_work(&rx->local->hw, &sdata->work); |
|---|
| 3661 | + if (rx->sta) |
|---|
| 3662 | + rx->sta->rx_stats.packets++; |
|---|
| 3663 | + |
|---|
| 3475 | 3664 | return RX_QUEUED; |
|---|
| 3476 | 3665 | } |
|---|
| 3477 | 3666 | |
|---|
| .. | .. |
|---|
| 3614 | 3803 | I802_DEBUG_INC(rx->sdata->local->rx_handlers_drop); |
|---|
| 3615 | 3804 | if (rx->sta) |
|---|
| 3616 | 3805 | rx->sta->rx_stats.dropped++; |
|---|
| 3617 | | - /* fall through */ |
|---|
| 3806 | + fallthrough; |
|---|
| 3618 | 3807 | case RX_CONTINUE: { |
|---|
| 3619 | 3808 | struct ieee80211_rate *rate = NULL; |
|---|
| 3620 | 3809 | struct ieee80211_supported_band *sband; |
|---|
| .. | .. |
|---|
| 3692 | 3881 | CALL_RXH(ieee80211_rx_h_mgmt_check); |
|---|
| 3693 | 3882 | CALL_RXH(ieee80211_rx_h_action); |
|---|
| 3694 | 3883 | CALL_RXH(ieee80211_rx_h_userspace_mgmt); |
|---|
| 3884 | + CALL_RXH(ieee80211_rx_h_action_post_userspace); |
|---|
| 3695 | 3885 | CALL_RXH(ieee80211_rx_h_action_return); |
|---|
| 3886 | + CALL_RXH(ieee80211_rx_h_ext); |
|---|
| 3696 | 3887 | CALL_RXH(ieee80211_rx_h_mgmt); |
|---|
| 3697 | 3888 | |
|---|
| 3698 | 3889 | rxh_next: |
|---|
| .. | .. |
|---|
| 3746 | 3937 | /* This is OK -- must be QoS data frame */ |
|---|
| 3747 | 3938 | .security_idx = tid, |
|---|
| 3748 | 3939 | .seqno_idx = tid, |
|---|
| 3749 | | - .napi = NULL, /* must be NULL to not have races */ |
|---|
| 3750 | 3940 | }; |
|---|
| 3751 | 3941 | struct tid_ampdu_rx *tid_agg_rx; |
|---|
| 3752 | 3942 | |
|---|
| .. | .. |
|---|
| 3860 | 4050 | struct ieee80211_hdr *hdr = (void *)skb->data; |
|---|
| 3861 | 4051 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); |
|---|
| 3862 | 4052 | u8 *bssid = ieee80211_get_bssid(hdr, skb->len, sdata->vif.type); |
|---|
| 3863 | | - bool multicast = is_multicast_ether_addr(hdr->addr1); |
|---|
| 4053 | + bool multicast = is_multicast_ether_addr(hdr->addr1) || |
|---|
| 4054 | + ieee80211_is_s1g_beacon(hdr->frame_control); |
|---|
| 3864 | 4055 | |
|---|
| 3865 | 4056 | switch (sdata->vif.type) { |
|---|
| 3866 | 4057 | case NL80211_IFTYPE_STATION: |
|---|
| .. | .. |
|---|
| 4027 | 4218 | fastrx.sa_offs = offsetof(struct ieee80211_hdr, addr2); |
|---|
| 4028 | 4219 | fastrx.expected_ds_bits = 0; |
|---|
| 4029 | 4220 | } else { |
|---|
| 4030 | | - fastrx.sta_notify = sdata->u.mgd.probe_send_count > 0; |
|---|
| 4031 | 4221 | fastrx.da_offs = offsetof(struct ieee80211_hdr, addr1); |
|---|
| 4032 | 4222 | fastrx.sa_offs = offsetof(struct ieee80211_hdr, addr3); |
|---|
| 4033 | 4223 | fastrx.expected_ds_bits = |
|---|
| .. | .. |
|---|
| 4098 | 4288 | case WLAN_CIPHER_SUITE_GCMP_256: |
|---|
| 4099 | 4289 | break; |
|---|
| 4100 | 4290 | default: |
|---|
| 4101 | | - /* we also don't want to deal with WEP or cipher scheme |
|---|
| 4102 | | - * since those require looking up the key idx in the |
|---|
| 4103 | | - * frame, rather than assuming the PTK is used |
|---|
| 4104 | | - * (we need to revisit this once we implement the real |
|---|
| 4105 | | - * PTK index, which is now valid in the spec, but we |
|---|
| 4106 | | - * haven't implemented that part yet) |
|---|
| 4291 | + /* We also don't want to deal with |
|---|
| 4292 | + * WEP or cipher scheme. |
|---|
| 4107 | 4293 | */ |
|---|
| 4108 | 4294 | goto clear_rcu; |
|---|
| 4109 | 4295 | } |
|---|
| .. | .. |
|---|
| 4263 | 4449 | pskb_trim(skb, skb->len - fast_rx->icv_len)) |
|---|
| 4264 | 4450 | goto drop; |
|---|
| 4265 | 4451 | |
|---|
| 4266 | | - if (unlikely(fast_rx->sta_notify)) { |
|---|
| 4267 | | - ieee80211_sta_rx_notify(rx->sdata, hdr); |
|---|
| 4268 | | - fast_rx->sta_notify = false; |
|---|
| 4269 | | - } |
|---|
| 4270 | | - |
|---|
| 4271 | 4452 | /* statistics part of ieee80211_rx_h_sta_process() */ |
|---|
| 4272 | 4453 | if (!(status->flag & RX_FLAG_NO_SIGNAL_VAL)) { |
|---|
| 4273 | 4454 | stats->last_signal = status->signal; |
|---|
| .. | .. |
|---|
| 4335 | 4516 | |
|---|
| 4336 | 4517 | if (fast_rx->internal_forward) { |
|---|
| 4337 | 4518 | struct sk_buff *xmit_skb = NULL; |
|---|
| 4338 | | - bool multicast = is_multicast_ether_addr(skb->data); |
|---|
| 4339 | | - |
|---|
| 4340 | | - if (multicast) { |
|---|
| 4519 | + if (is_multicast_ether_addr(addrs.da)) { |
|---|
| 4341 | 4520 | xmit_skb = skb_copy(skb, GFP_ATOMIC); |
|---|
| 4342 | | - } else if (sta_info_get(rx->sdata, skb->data)) { |
|---|
| 4521 | + } else if (!ether_addr_equal(addrs.da, addrs.sa) && |
|---|
| 4522 | + sta_info_get(rx->sdata, addrs.da)) { |
|---|
| 4343 | 4523 | xmit_skb = skb; |
|---|
| 4344 | 4524 | skb = NULL; |
|---|
| 4345 | 4525 | } |
|---|
| .. | .. |
|---|
| 4364 | 4544 | /* deliver to local stack */ |
|---|
| 4365 | 4545 | skb->protocol = eth_type_trans(skb, fast_rx->dev); |
|---|
| 4366 | 4546 | memset(skb->cb, 0, sizeof(skb->cb)); |
|---|
| 4367 | | - if (rx->napi) |
|---|
| 4368 | | - napi_gro_receive(rx->napi, skb); |
|---|
| 4547 | + if (rx->list) |
|---|
| 4548 | + list_add_tail(&skb->list, rx->list); |
|---|
| 4369 | 4549 | else |
|---|
| 4370 | 4550 | netif_receive_skb(skb); |
|---|
| 4371 | 4551 | |
|---|
| .. | .. |
|---|
| 4432 | 4612 | static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, |
|---|
| 4433 | 4613 | struct ieee80211_sta *pubsta, |
|---|
| 4434 | 4614 | struct sk_buff *skb, |
|---|
| 4435 | | - struct napi_struct *napi) |
|---|
| 4615 | + struct list_head *list) |
|---|
| 4436 | 4616 | { |
|---|
| 4437 | 4617 | struct ieee80211_local *local = hw_to_local(hw); |
|---|
| 4438 | 4618 | struct ieee80211_sub_if_data *sdata; |
|---|
| .. | .. |
|---|
| 4447 | 4627 | memset(&rx, 0, sizeof(rx)); |
|---|
| 4448 | 4628 | rx.skb = skb; |
|---|
| 4449 | 4629 | rx.local = local; |
|---|
| 4450 | | - rx.napi = napi; |
|---|
| 4630 | + rx.list = list; |
|---|
| 4451 | 4631 | |
|---|
| 4452 | 4632 | if (ieee80211_is_data(fc) || ieee80211_is_mgmt(fc)) |
|---|
| 4453 | 4633 | I802_DEBUG_INC(local->dot11ReceivedFragmentCount); |
|---|
| .. | .. |
|---|
| 4472 | 4652 | ieee80211_verify_alignment(&rx); |
|---|
| 4473 | 4653 | |
|---|
| 4474 | 4654 | if (unlikely(ieee80211_is_probe_resp(hdr->frame_control) || |
|---|
| 4475 | | - ieee80211_is_beacon(hdr->frame_control))) |
|---|
| 4655 | + ieee80211_is_beacon(hdr->frame_control) || |
|---|
| 4656 | + ieee80211_is_s1g_beacon(hdr->frame_control))) |
|---|
| 4476 | 4657 | ieee80211_scan_rx(local, skb); |
|---|
| 4477 | 4658 | |
|---|
| 4478 | 4659 | if (ieee80211_is_data(fc)) { |
|---|
| .. | .. |
|---|
| 4555 | 4736 | * This is the receive path handler. It is called by a low level driver when an |
|---|
| 4556 | 4737 | * 802.11 MPDU is received from the hardware. |
|---|
| 4557 | 4738 | */ |
|---|
| 4558 | | -void ieee80211_rx_napi(struct ieee80211_hw *hw, struct ieee80211_sta *pubsta, |
|---|
| 4559 | | - struct sk_buff *skb, struct napi_struct *napi) |
|---|
| 4739 | +void ieee80211_rx_list(struct ieee80211_hw *hw, struct ieee80211_sta *pubsta, |
|---|
| 4740 | + struct sk_buff *skb, struct list_head *list) |
|---|
| 4560 | 4741 | { |
|---|
| 4561 | 4742 | struct ieee80211_local *local = hw_to_local(hw); |
|---|
| 4562 | 4743 | struct ieee80211_rate *rate = NULL; |
|---|
| .. | .. |
|---|
| 4605 | 4786 | * rate_idx is MCS index, which can be [0-76] |
|---|
| 4606 | 4787 | * as documented on: |
|---|
| 4607 | 4788 | * |
|---|
| 4608 | | - * http://wireless.kernel.org/en/developers/Documentation/ieee80211/802.11n |
|---|
| 4789 | + * https://wireless.wiki.kernel.org/en/developers/Documentation/ieee80211/802.11n |
|---|
| 4609 | 4790 | * |
|---|
| 4610 | 4791 | * Anything else would be some sort of driver or |
|---|
| 4611 | 4792 | * hardware error. The driver should catch hardware |
|---|
| .. | .. |
|---|
| 4637 | 4818 | break; |
|---|
| 4638 | 4819 | default: |
|---|
| 4639 | 4820 | WARN_ON_ONCE(1); |
|---|
| 4640 | | - /* fall through */ |
|---|
| 4821 | + fallthrough; |
|---|
| 4641 | 4822 | case RX_ENC_LEGACY: |
|---|
| 4642 | 4823 | if (WARN_ON(status->rate_idx >= sband->n_bitrates)) |
|---|
| 4643 | 4824 | goto drop; |
|---|
| .. | .. |
|---|
| 4648 | 4829 | status->rx_flags = 0; |
|---|
| 4649 | 4830 | |
|---|
| 4650 | 4831 | /* |
|---|
| 4651 | | - * key references and virtual interfaces are protected using RCU |
|---|
| 4652 | | - * and this requires that we are in a read-side RCU section during |
|---|
| 4653 | | - * receive processing |
|---|
| 4654 | | - */ |
|---|
| 4655 | | - rcu_read_lock(); |
|---|
| 4656 | | - |
|---|
| 4657 | | - /* |
|---|
| 4658 | 4832 | * Frames with failed FCS/PLCP checksum are not returned, |
|---|
| 4659 | 4833 | * all other frames are returned without radiotap header |
|---|
| 4660 | 4834 | * if it was previously present. |
|---|
| 4661 | 4835 | * Also, frames with less than 16 bytes are dropped. |
|---|
| 4662 | 4836 | */ |
|---|
| 4663 | 4837 | skb = ieee80211_rx_monitor(local, skb, rate); |
|---|
| 4664 | | - if (!skb) { |
|---|
| 4665 | | - rcu_read_unlock(); |
|---|
| 4838 | + if (!skb) |
|---|
| 4666 | 4839 | return; |
|---|
| 4667 | | - } |
|---|
| 4668 | 4840 | |
|---|
| 4669 | 4841 | ieee80211_tpt_led_trig_rx(local, |
|---|
| 4670 | 4842 | ((struct ieee80211_hdr *)skb->data)->frame_control, |
|---|
| 4671 | 4843 | skb->len); |
|---|
| 4672 | 4844 | |
|---|
| 4673 | | - __ieee80211_rx_handle_packet(hw, pubsta, skb, napi); |
|---|
| 4674 | | - |
|---|
| 4675 | | - rcu_read_unlock(); |
|---|
| 4845 | + __ieee80211_rx_handle_packet(hw, pubsta, skb, list); |
|---|
| 4676 | 4846 | |
|---|
| 4677 | 4847 | return; |
|---|
| 4678 | 4848 | drop: |
|---|
| 4679 | 4849 | kfree_skb(skb); |
|---|
| 4680 | 4850 | } |
|---|
| 4851 | +EXPORT_SYMBOL(ieee80211_rx_list); |
|---|
| 4852 | + |
|---|
| 4853 | +void ieee80211_rx_napi(struct ieee80211_hw *hw, struct ieee80211_sta *pubsta, |
|---|
| 4854 | + struct sk_buff *skb, struct napi_struct *napi) |
|---|
| 4855 | +{ |
|---|
| 4856 | + struct sk_buff *tmp; |
|---|
| 4857 | + LIST_HEAD(list); |
|---|
| 4858 | + |
|---|
| 4859 | + |
|---|
| 4860 | + /* |
|---|
| 4861 | + * key references and virtual interfaces are protected using RCU |
|---|
| 4862 | + * and this requires that we are in a read-side RCU section during |
|---|
| 4863 | + * receive processing |
|---|
| 4864 | + */ |
|---|
| 4865 | + rcu_read_lock(); |
|---|
| 4866 | + ieee80211_rx_list(hw, pubsta, skb, &list); |
|---|
| 4867 | + rcu_read_unlock(); |
|---|
| 4868 | + |
|---|
| 4869 | + if (!napi) { |
|---|
| 4870 | + netif_receive_skb_list(&list); |
|---|
| 4871 | + return; |
|---|
| 4872 | + } |
|---|
| 4873 | + |
|---|
| 4874 | + list_for_each_entry_safe(skb, tmp, &list, list) { |
|---|
| 4875 | + skb_list_del_init(skb); |
|---|
| 4876 | + napi_gro_receive(napi, skb); |
|---|
| 4877 | + } |
|---|
| 4878 | +} |
|---|
| 4681 | 4879 | EXPORT_SYMBOL(ieee80211_rx_napi); |
|---|
| 4682 | 4880 | |
|---|
| 4683 | 4881 | /* This is a version of the rx handler that can be called from hard irq |
|---|