1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2571ecf67SJohannes Berg /*
3571ecf67SJohannes Berg * Copyright 2002-2005, Instant802 Networks, Inc.
4571ecf67SJohannes Berg * Copyright 2005-2006, Devicescape Software, Inc.
5571ecf67SJohannes Berg * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
684040805SJohannes Berg * Copyright 2007-2010 Johannes Berg <johannes@sipsolutions.net>
7d98ad83eSJohannes Berg * Copyright 2013-2014 Intel Mobile Communications GmbH
8b7540d8fSSara Sharon * Copyright(c) 2015 - 2017 Intel Deutschland GmbH
90e966d9aSJohannes Berg * Copyright (C) 2018-2023 Intel Corporation
10571ecf67SJohannes Berg */
11571ecf67SJohannes Berg
12ab46623eSS.Çağlar Onur #include <linux/jiffies.h>
135a0e3ad6STejun Heo #include <linux/slab.h>
14571ecf67SJohannes Berg #include <linux/kernel.h>
15571ecf67SJohannes Berg #include <linux/skbuff.h>
16571ecf67SJohannes Berg #include <linux/netdevice.h>
17571ecf67SJohannes Berg #include <linux/etherdevice.h>
18d4e46a3dSJohannes Berg #include <linux/rcupdate.h>
19bc3b2d7fSPaul Gortmaker #include <linux/export.h>
20183f47fcSSebastian Andrzej Siewior #include <linux/kcov.h>
2106470f74SSara Sharon #include <linux/bitops.h>
22571ecf67SJohannes Berg #include <net/mac80211.h>
23571ecf67SJohannes Berg #include <net/ieee80211_radiotap.h>
24d26ad377SJohannes Berg #include <asm/unaligned.h>
25571ecf67SJohannes Berg
26571ecf67SJohannes Berg #include "ieee80211_i.h"
2724487981SJohannes Berg #include "driver-ops.h"
282c8dccc7SJohannes Berg #include "led.h"
2933b64eb2SLuis Carlos Cobo #include "mesh.h"
30571ecf67SJohannes Berg #include "wep.h"
31571ecf67SJohannes Berg #include "wpa.h"
32571ecf67SJohannes Berg #include "tkip.h"
33571ecf67SJohannes Berg #include "wme.h"
341d8d3decSJohannes Berg #include "rate.h"
35571ecf67SJohannes Berg
36b2e7771eSJohannes Berg /*
37b2e7771eSJohannes Berg * monitor mode reception
38b2e7771eSJohannes Berg *
39b2e7771eSJohannes Berg * This function cleans up the SKB, i.e. it removes all the stuff
40b2e7771eSJohannes Berg * only useful for monitoring.
41b2e7771eSJohannes Berg */
ieee80211_clean_skb(struct sk_buff * skb,unsigned int present_fcs_len,unsigned int rtap_space)42c1129924SJohannes Berg static struct sk_buff *ieee80211_clean_skb(struct sk_buff *skb,
4330841f5cSJohannes Berg unsigned int present_fcs_len,
44c096b92aSJohannes Berg unsigned int rtap_space)
45b2e7771eSJohannes Berg {
463a867c7eSMordechay Goodstein struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
47c1129924SJohannes Berg struct ieee80211_hdr *hdr;
48c1129924SJohannes Berg unsigned int hdrlen;
49c1129924SJohannes Berg __le16 fc;
50c1129924SJohannes Berg
5130841f5cSJohannes Berg if (present_fcs_len)
5230841f5cSJohannes Berg __pskb_trim(skb, skb->len - present_fcs_len);
53d427c899SRichard Gobert pskb_pull(skb, rtap_space);
54c1129924SJohannes Berg
553a867c7eSMordechay Goodstein /* After pulling radiotap header, clear all flags that indicate
563a867c7eSMordechay Goodstein * info in skb->data.
573a867c7eSMordechay Goodstein */
589179dff8SMordechay Goodstein status->flag &= ~(RX_FLAG_RADIOTAP_TLV_AT_END |
593a867c7eSMordechay Goodstein RX_FLAG_RADIOTAP_LSIG |
603a867c7eSMordechay Goodstein RX_FLAG_RADIOTAP_HE_MU |
613a867c7eSMordechay Goodstein RX_FLAG_RADIOTAP_HE);
623a867c7eSMordechay Goodstein
63c1129924SJohannes Berg hdr = (void *)skb->data;
64c1129924SJohannes Berg fc = hdr->frame_control;
65c1129924SJohannes Berg
66c1129924SJohannes Berg /*
67c1129924SJohannes Berg * Remove the HT-Control field (if present) on management
68c1129924SJohannes Berg * frames after we've sent the frame to monitoring. We
69c1129924SJohannes Berg * (currently) don't need it, and don't properly parse
70c1129924SJohannes Berg * frames with it present, due to the assumption of a
71c1129924SJohannes Berg * fixed management header length.
72c1129924SJohannes Berg */
73c1129924SJohannes Berg if (likely(!ieee80211_is_mgmt(fc) || !ieee80211_has_order(fc)))
74c1129924SJohannes Berg return skb;
75c1129924SJohannes Berg
76c1129924SJohannes Berg hdrlen = ieee80211_hdrlen(fc);
77c1129924SJohannes Berg hdr->frame_control &= ~cpu_to_le16(IEEE80211_FCTL_ORDER);
78c1129924SJohannes Berg
79c1129924SJohannes Berg if (!pskb_may_pull(skb, hdrlen)) {
80c1129924SJohannes Berg dev_kfree_skb(skb);
81c1129924SJohannes Berg return NULL;
82c1129924SJohannes Berg }
83c1129924SJohannes Berg
84c1129924SJohannes Berg memmove(skb->data + IEEE80211_HT_CTL_LEN, skb->data,
85c1129924SJohannes Berg hdrlen - IEEE80211_HT_CTL_LEN);
86d427c899SRichard Gobert pskb_pull(skb, IEEE80211_HT_CTL_LEN);
87c1129924SJohannes Berg
88c1129924SJohannes Berg return skb;
89b2e7771eSJohannes Berg }
90b2e7771eSJohannes Berg
should_drop_frame(struct sk_buff * skb,int present_fcs_len,unsigned int rtap_space)911f7bba79SJohannes Berg static inline bool should_drop_frame(struct sk_buff *skb, int present_fcs_len,
92c096b92aSJohannes Berg unsigned int rtap_space)
93b2e7771eSJohannes Berg {
94f1d58c25SJohannes Berg struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
951f7bba79SJohannes Berg struct ieee80211_hdr *hdr;
961f7bba79SJohannes Berg
97c096b92aSJohannes Berg hdr = (void *)(skb->data + rtap_space);
98b2e7771eSJohannes Berg
994c298677SJohannes Berg if (status->flag & (RX_FLAG_FAILED_FCS_CRC |
10017883048SGrzegorz Bajorski RX_FLAG_FAILED_PLCP_CRC |
101c3d1f875SShaul Triebitz RX_FLAG_ONLY_MONITOR |
102c3d1f875SShaul Triebitz RX_FLAG_NO_PSDU))
1036b59db7dSZhao, Gang return true;
1046b59db7dSZhao, Gang
105c096b92aSJohannes Berg if (unlikely(skb->len < 16 + present_fcs_len + rtap_space))
1066b59db7dSZhao, Gang return true;
1076b59db7dSZhao, Gang
10887228f57SHarvey Harrison if (ieee80211_is_ctl(hdr->frame_control) &&
10987228f57SHarvey Harrison !ieee80211_is_pspoll(hdr->frame_control) &&
11087228f57SHarvey Harrison !ieee80211_is_back_req(hdr->frame_control))
1116b59db7dSZhao, Gang return true;
1126b59db7dSZhao, Gang
1136b59db7dSZhao, Gang return false;
114b2e7771eSJohannes Berg }
115b2e7771eSJohannes Berg
116601ae7f2SBruno Randolf static int
ieee80211_rx_radiotap_hdrlen(struct ieee80211_local * local,struct ieee80211_rx_status * status,struct sk_buff * skb)1171f7bba79SJohannes Berg ieee80211_rx_radiotap_hdrlen(struct ieee80211_local *local,
1181f7bba79SJohannes Berg struct ieee80211_rx_status *status,
1191f7bba79SJohannes Berg struct sk_buff *skb)
120601ae7f2SBruno Randolf {
121601ae7f2SBruno Randolf int len;
122601ae7f2SBruno Randolf
123601ae7f2SBruno Randolf /* always present fields */
124a144f378SJohannes Berg len = sizeof(struct ieee80211_radiotap_header) + 8;
125601ae7f2SBruno Randolf
126a144f378SJohannes Berg /* allocate extra bitmaps */
127a144f378SJohannes Berg if (status->chains)
128a144f378SJohannes Berg len += 4 * hweight8(status->chains);
12990b9e446SJohannes Berg
13090b9e446SJohannes Berg if (ieee80211_have_rx_timestamp(status)) {
13190b9e446SJohannes Berg len = ALIGN(len, 8);
132601ae7f2SBruno Randolf len += 8;
13390b9e446SJohannes Berg }
13430686bf7SJohannes Berg if (ieee80211_hw_check(&local->hw, SIGNAL_DBM))
135601ae7f2SBruno Randolf len += 1;
136601ae7f2SBruno Randolf
137a144f378SJohannes Berg /* antenna field, if we don't have per-chain info */
138a144f378SJohannes Berg if (!status->chains)
139a144f378SJohannes Berg len += 1;
140a144f378SJohannes Berg
14190b9e446SJohannes Berg /* padding for RX_FLAGS if necessary */
14290b9e446SJohannes Berg len = ALIGN(len, 2);
143601ae7f2SBruno Randolf
144da6a4352SJohannes Berg if (status->encoding == RX_ENC_HT) /* HT info */
1456d744bacSJohannes Berg len += 3;
1466d744bacSJohannes Berg
1474c298677SJohannes Berg if (status->flag & RX_FLAG_AMPDU_DETAILS) {
14890b9e446SJohannes Berg len = ALIGN(len, 4);
1494c298677SJohannes Berg len += 8;
1504c298677SJohannes Berg }
1514c298677SJohannes Berg
152da6a4352SJohannes Berg if (status->encoding == RX_ENC_VHT) {
15351648921SJohannes Berg len = ALIGN(len, 2);
15451648921SJohannes Berg len += 12;
15551648921SJohannes Berg }
15651648921SJohannes Berg
15799ee7caeSJohannes Berg if (local->hw.radiotap_timestamp.units_pos >= 0) {
15899ee7caeSJohannes Berg len = ALIGN(len, 8);
15999ee7caeSJohannes Berg len += 12;
16099ee7caeSJohannes Berg }
16199ee7caeSJohannes Berg
16241cbb0f5SLuca Coelho if (status->encoding == RX_ENC_HE &&
16341cbb0f5SLuca Coelho status->flag & RX_FLAG_RADIOTAP_HE) {
16441cbb0f5SLuca Coelho len = ALIGN(len, 2);
16541cbb0f5SLuca Coelho len += 12;
16641cbb0f5SLuca Coelho BUILD_BUG_ON(sizeof(struct ieee80211_radiotap_he) != 12);
16741cbb0f5SLuca Coelho }
16841cbb0f5SLuca Coelho
16941cbb0f5SLuca Coelho if (status->encoding == RX_ENC_HE &&
17041cbb0f5SLuca Coelho status->flag & RX_FLAG_RADIOTAP_HE_MU) {
17141cbb0f5SLuca Coelho len = ALIGN(len, 2);
17241cbb0f5SLuca Coelho len += 12;
17341cbb0f5SLuca Coelho BUILD_BUG_ON(sizeof(struct ieee80211_radiotap_he_mu) != 12);
17441cbb0f5SLuca Coelho }
17541cbb0f5SLuca Coelho
176c3d1f875SShaul Triebitz if (status->flag & RX_FLAG_NO_PSDU)
177c3d1f875SShaul Triebitz len += 1;
178c3d1f875SShaul Triebitz
179d1332e7bSShaul Triebitz if (status->flag & RX_FLAG_RADIOTAP_LSIG) {
180d1332e7bSShaul Triebitz len = ALIGN(len, 2);
181d1332e7bSShaul Triebitz len += 4;
182d1332e7bSShaul Triebitz BUILD_BUG_ON(sizeof(struct ieee80211_radiotap_lsig) != 4);
183d1332e7bSShaul Triebitz }
184d1332e7bSShaul Triebitz
185a144f378SJohannes Berg if (status->chains) {
186a144f378SJohannes Berg /* antenna and antenna signal fields */
187a144f378SJohannes Berg len += 2 * hweight8(status->chains);
188a144f378SJohannes Berg }
189a144f378SJohannes Berg
1909179dff8SMordechay Goodstein if (status->flag & RX_FLAG_RADIOTAP_TLV_AT_END) {
1919179dff8SMordechay Goodstein int tlv_offset = 0;
192c15353beSLiad Kaufman
193c15353beSLiad Kaufman /*
194c15353beSLiad Kaufman * The position to look at depends on the existence (or non-
195c15353beSLiad Kaufman * existence) of other elements, so take that into account...
196c15353beSLiad Kaufman */
197c15353beSLiad Kaufman if (status->flag & RX_FLAG_RADIOTAP_HE)
1989179dff8SMordechay Goodstein tlv_offset +=
199c15353beSLiad Kaufman sizeof(struct ieee80211_radiotap_he);
200c15353beSLiad Kaufman if (status->flag & RX_FLAG_RADIOTAP_HE_MU)
2019179dff8SMordechay Goodstein tlv_offset +=
202c15353beSLiad Kaufman sizeof(struct ieee80211_radiotap_he_mu);
203c15353beSLiad Kaufman if (status->flag & RX_FLAG_RADIOTAP_LSIG)
2049179dff8SMordechay Goodstein tlv_offset +=
205c15353beSLiad Kaufman sizeof(struct ieee80211_radiotap_lsig);
206c15353beSLiad Kaufman
2079179dff8SMordechay Goodstein /* ensure 4 byte alignment for TLV */
2089179dff8SMordechay Goodstein len = ALIGN(len, 4);
2091f7bba79SJohannes Berg
2109179dff8SMordechay Goodstein /* TLVs until the mac header */
2119179dff8SMordechay Goodstein len += skb_mac_header(skb) - &skb->data[tlv_offset];
2121f7bba79SJohannes Berg }
2131f7bba79SJohannes Berg
214601ae7f2SBruno Randolf return len;
215601ae7f2SBruno Randolf }
216601ae7f2SBruno Randolf
__ieee80211_queue_skb_to_iface(struct ieee80211_sub_if_data * sdata,int link_id,struct sta_info * sta,struct sk_buff * skb)217f057d140SJohannes Berg static void __ieee80211_queue_skb_to_iface(struct ieee80211_sub_if_data *sdata,
2184f6c78deSJohannes Berg int link_id,
2190044cc17SJohannes Berg struct sta_info *sta,
2200044cc17SJohannes Berg struct sk_buff *skb)
2210044cc17SJohannes Berg {
2224f6c78deSJohannes Berg struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
2234f6c78deSJohannes Berg
2244f6c78deSJohannes Berg if (link_id >= 0) {
2254f6c78deSJohannes Berg status->link_valid = 1;
2264f6c78deSJohannes Berg status->link_id = link_id;
2274f6c78deSJohannes Berg } else {
2284f6c78deSJohannes Berg status->link_valid = 0;
2294f6c78deSJohannes Berg }
2304f6c78deSJohannes Berg
2310044cc17SJohannes Berg skb_queue_tail(&sdata->skb_queue, skb);
23216114496SJohannes Berg wiphy_work_queue(sdata->local->hw.wiphy, &sdata->work);
2330044cc17SJohannes Berg if (sta)
234046d2e7cSSriram R sta->deflink.rx_stats.packets++;
2350044cc17SJohannes Berg }
2360044cc17SJohannes Berg
ieee80211_queue_skb_to_iface(struct ieee80211_sub_if_data * sdata,int link_id,struct sta_info * sta,struct sk_buff * skb)237f057d140SJohannes Berg static void ieee80211_queue_skb_to_iface(struct ieee80211_sub_if_data *sdata,
2384f6c78deSJohannes Berg int link_id,
239f057d140SJohannes Berg struct sta_info *sta,
240f057d140SJohannes Berg struct sk_buff *skb)
241f057d140SJohannes Berg {
242f057d140SJohannes Berg skb->protocol = 0;
2434f6c78deSJohannes Berg __ieee80211_queue_skb_to_iface(sdata, link_id, sta, skb);
244f057d140SJohannes Berg }
245f057d140SJohannes Berg
ieee80211_handle_mu_mimo_mon(struct ieee80211_sub_if_data * sdata,struct sk_buff * skb,int rtap_space)2469e478066SJohannes Berg static void ieee80211_handle_mu_mimo_mon(struct ieee80211_sub_if_data *sdata,
2479e478066SJohannes Berg struct sk_buff *skb,
248c096b92aSJohannes Berg int rtap_space)
2499e478066SJohannes Berg {
2509e478066SJohannes Berg struct {
2519e478066SJohannes Berg struct ieee80211_hdr_3addr hdr;
2529e478066SJohannes Berg u8 category;
2539e478066SJohannes Berg u8 action_code;
2547c53eb5dSMathieu Malaterre } __packed __aligned(2) action;
2559e478066SJohannes Berg
2569e478066SJohannes Berg if (!sdata)
2579e478066SJohannes Berg return;
2589e478066SJohannes Berg
2599e478066SJohannes Berg BUILD_BUG_ON(sizeof(action) != IEEE80211_MIN_ACTION_SIZE + 1);
2609e478066SJohannes Berg
261c096b92aSJohannes Berg if (skb->len < rtap_space + sizeof(action) +
2629e478066SJohannes Berg VHT_MUMIMO_GROUPS_DATA_LEN)
2639e478066SJohannes Berg return;
2649e478066SJohannes Berg
2659e478066SJohannes Berg if (!is_valid_ether_addr(sdata->u.mntr.mu_follow_addr))
2669e478066SJohannes Berg return;
2679e478066SJohannes Berg
268c096b92aSJohannes Berg skb_copy_bits(skb, rtap_space, &action, sizeof(action));
2699e478066SJohannes Berg
2709e478066SJohannes Berg if (!ieee80211_is_action(action.hdr.frame_control))
2719e478066SJohannes Berg return;
2729e478066SJohannes Berg
2739e478066SJohannes Berg if (action.category != WLAN_CATEGORY_VHT)
2749e478066SJohannes Berg return;
2759e478066SJohannes Berg
2769e478066SJohannes Berg if (action.action_code != WLAN_VHT_ACTION_GROUPID_MGMT)
2779e478066SJohannes Berg return;
2789e478066SJohannes Berg
2799e478066SJohannes Berg if (!ether_addr_equal(action.hdr.addr1, sdata->u.mntr.mu_follow_addr))
2809e478066SJohannes Berg return;
2819e478066SJohannes Berg
2829e478066SJohannes Berg skb = skb_copy(skb, GFP_ATOMIC);
2839e478066SJohannes Berg if (!skb)
2849e478066SJohannes Berg return;
2859e478066SJohannes Berg
2864f6c78deSJohannes Berg ieee80211_queue_skb_to_iface(sdata, -1, NULL, skb);
2879e478066SJohannes Berg }
2889e478066SJohannes Berg
28900ea6debSJohannes Berg /*
290601ae7f2SBruno Randolf * ieee80211_add_rx_radiotap_header - add radiotap header
291601ae7f2SBruno Randolf *
292601ae7f2SBruno Randolf * add a radiotap header containing all the fields which the hardware provided.
293601ae7f2SBruno Randolf */
294601ae7f2SBruno Randolf static void
ieee80211_add_rx_radiotap_header(struct ieee80211_local * local,struct sk_buff * skb,struct ieee80211_rate * rate,int rtap_len,bool has_fcs)295601ae7f2SBruno Randolf ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
296601ae7f2SBruno Randolf struct sk_buff *skb,
297601ae7f2SBruno Randolf struct ieee80211_rate *rate,
298973ef21aSFelix Fietkau int rtap_len, bool has_fcs)
299601ae7f2SBruno Randolf {
300f1d58c25SJohannes Berg struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
301601ae7f2SBruno Randolf struct ieee80211_radiotap_header *rthdr;
302601ae7f2SBruno Randolf unsigned char *pos;
303a144f378SJohannes Berg __le32 *it_present;
304a144f378SJohannes Berg u32 it_present_val;
3056a86b9c7SJohannes Berg u16 rx_flags = 0;
306a5e70697SSimon Wunderlich u16 channel_flags = 0;
3079179dff8SMordechay Goodstein u32 tlvs_len = 0;
308a144f378SJohannes Berg int mpdulen, chain;
309a144f378SJohannes Berg unsigned long chains = status->chains;
31041cbb0f5SLuca Coelho struct ieee80211_radiotap_he he = {};
31141cbb0f5SLuca Coelho struct ieee80211_radiotap_he_mu he_mu = {};
312d1332e7bSShaul Triebitz struct ieee80211_radiotap_lsig lsig = {};
31341cbb0f5SLuca Coelho
31441cbb0f5SLuca Coelho if (status->flag & RX_FLAG_RADIOTAP_HE) {
31541cbb0f5SLuca Coelho he = *(struct ieee80211_radiotap_he *)skb->data;
31641cbb0f5SLuca Coelho skb_pull(skb, sizeof(he));
31741cbb0f5SLuca Coelho WARN_ON_ONCE(status->encoding != RX_ENC_HE);
31841cbb0f5SLuca Coelho }
31941cbb0f5SLuca Coelho
32041cbb0f5SLuca Coelho if (status->flag & RX_FLAG_RADIOTAP_HE_MU) {
32141cbb0f5SLuca Coelho he_mu = *(struct ieee80211_radiotap_he_mu *)skb->data;
32241cbb0f5SLuca Coelho skb_pull(skb, sizeof(he_mu));
32341cbb0f5SLuca Coelho }
3241f7bba79SJohannes Berg
325d1332e7bSShaul Triebitz if (status->flag & RX_FLAG_RADIOTAP_LSIG) {
326d1332e7bSShaul Triebitz lsig = *(struct ieee80211_radiotap_lsig *)skb->data;
327d1332e7bSShaul Triebitz skb_pull(skb, sizeof(lsig));
328d1332e7bSShaul Triebitz }
329d1332e7bSShaul Triebitz
3309179dff8SMordechay Goodstein if (status->flag & RX_FLAG_RADIOTAP_TLV_AT_END) {
3319179dff8SMordechay Goodstein /* data is pointer at tlv all other info was pulled off */
3329179dff8SMordechay Goodstein tlvs_len = skb_mac_header(skb) - skb->data;
3331f7bba79SJohannes Berg }
334f4bda337SThomas Pedersen
335f4bda337SThomas Pedersen mpdulen = skb->len;
33630686bf7SJohannes Berg if (!(has_fcs && ieee80211_hw_check(&local->hw, RX_INCLUDES_FCS)))
337f4bda337SThomas Pedersen mpdulen += FCS_LEN;
338601ae7f2SBruno Randolf
3399179dff8SMordechay Goodstein rthdr = skb_push(skb, rtap_len - tlvs_len);
3409179dff8SMordechay Goodstein memset(rthdr, 0, rtap_len - tlvs_len);
341a144f378SJohannes Berg it_present = &rthdr->it_present;
342601ae7f2SBruno Randolf
343601ae7f2SBruno Randolf /* radiotap header, set always present flags */
3440059b2b1SEmmanuel Grumbach rthdr->it_len = cpu_to_le16(rtap_len);
345a144f378SJohannes Berg it_present_val = BIT(IEEE80211_RADIOTAP_FLAGS) |
346a144f378SJohannes Berg BIT(IEEE80211_RADIOTAP_CHANNEL) |
347a144f378SJohannes Berg BIT(IEEE80211_RADIOTAP_RX_FLAGS);
348601ae7f2SBruno Randolf
349a144f378SJohannes Berg if (!status->chains)
350a144f378SJohannes Berg it_present_val |= BIT(IEEE80211_RADIOTAP_ANTENNA);
351a144f378SJohannes Berg
352a144f378SJohannes Berg for_each_set_bit(chain, &chains, IEEE80211_MAX_CHAINS) {
353a144f378SJohannes Berg it_present_val |=
354a144f378SJohannes Berg BIT(IEEE80211_RADIOTAP_EXT) |
355a144f378SJohannes Berg BIT(IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE);
356a144f378SJohannes Berg put_unaligned_le32(it_present_val, it_present);
357a144f378SJohannes Berg it_present++;
358a144f378SJohannes Berg it_present_val = BIT(IEEE80211_RADIOTAP_ANTENNA) |
359a144f378SJohannes Berg BIT(IEEE80211_RADIOTAP_DBM_ANTSIGNAL);
360a144f378SJohannes Berg }
361601ae7f2SBruno Randolf
3629179dff8SMordechay Goodstein if (status->flag & RX_FLAG_RADIOTAP_TLV_AT_END)
3639179dff8SMordechay Goodstein it_present_val |= BIT(IEEE80211_RADIOTAP_TLV);
3641f7bba79SJohannes Berg
365a144f378SJohannes Berg put_unaligned_le32(it_present_val, it_present);
366a144f378SJohannes Berg
3678c89f7b3SKees Cook /* This references through an offset into it_optional[] rather
3688c89f7b3SKees Cook * than via it_present otherwise later uses of pos will cause
3698c89f7b3SKees Cook * the compiler to think we have walked past the end of the
3708c89f7b3SKees Cook * struct member.
3718c89f7b3SKees Cook */
372c033a38aSJohannes Berg pos = (void *)&rthdr->it_optional[it_present + 1 - rthdr->it_optional];
373a144f378SJohannes Berg
374601ae7f2SBruno Randolf /* the order of the following fields is important */
375601ae7f2SBruno Randolf
376601ae7f2SBruno Randolf /* IEEE80211_RADIOTAP_TSFT */
377f4bda337SThomas Pedersen if (ieee80211_have_rx_timestamp(status)) {
37890b9e446SJohannes Berg /* padding */
37990b9e446SJohannes Berg while ((pos - (u8 *)rthdr) & 7)
38090b9e446SJohannes Berg *pos++ = 0;
381f4bda337SThomas Pedersen put_unaligned_le64(
382f4bda337SThomas Pedersen ieee80211_calculate_rx_timestamp(local, status,
383f4bda337SThomas Pedersen mpdulen, 0),
384f4bda337SThomas Pedersen pos);
3855cafd378SKees Cook rthdr->it_present |= cpu_to_le32(BIT(IEEE80211_RADIOTAP_TSFT));
386601ae7f2SBruno Randolf pos += 8;
387601ae7f2SBruno Randolf }
388601ae7f2SBruno Randolf
389601ae7f2SBruno Randolf /* IEEE80211_RADIOTAP_FLAGS */
39030686bf7SJohannes Berg if (has_fcs && ieee80211_hw_check(&local->hw, RX_INCLUDES_FCS))
391601ae7f2SBruno Randolf *pos |= IEEE80211_RADIOTAP_F_FCS;
392aae89831SJohannes Berg if (status->flag & (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC))
393aae89831SJohannes Berg *pos |= IEEE80211_RADIOTAP_F_BADFCS;
3947fdd69c5SJohannes Berg if (status->enc_flags & RX_ENC_FLAG_SHORTPRE)
395b4f28bbbSBruno Randolf *pos |= IEEE80211_RADIOTAP_F_SHORTPRE;
396601ae7f2SBruno Randolf pos++;
397601ae7f2SBruno Randolf
398601ae7f2SBruno Randolf /* IEEE80211_RADIOTAP_RATE */
399da6a4352SJohannes Berg if (!rate || status->encoding != RX_ENC_LEGACY) {
4000fb8ca45SJouni Malinen /*
401f8d1ccf1SJohannes Berg * Without rate information don't add it. If we have,
40238f37be2SMohammed Shafi Shajakhan * MCS information is a separate field in radiotap,
40373b48099SJohannes Berg * added below. The byte here is needed as padding
40473b48099SJohannes Berg * for the channel though, so initialise it to 0.
4050fb8ca45SJouni Malinen */
4060fb8ca45SJouni Malinen *pos = 0;
4078d6f658eSJouni Malinen } else {
4082103dec1SSimon Wunderlich int shift = 0;
4095cafd378SKees Cook rthdr->it_present |= cpu_to_le32(BIT(IEEE80211_RADIOTAP_RATE));
410da6a4352SJohannes Berg if (status->bw == RATE_INFO_BW_10)
4112103dec1SSimon Wunderlich shift = 1;
412da6a4352SJohannes Berg else if (status->bw == RATE_INFO_BW_5)
4132103dec1SSimon Wunderlich shift = 2;
4142103dec1SSimon Wunderlich *pos = DIV_ROUND_UP(rate->bitrate, 5 * (1 << shift));
4158d6f658eSJouni Malinen }
416601ae7f2SBruno Randolf pos++;
417601ae7f2SBruno Randolf
418601ae7f2SBruno Randolf /* IEEE80211_RADIOTAP_CHANNEL */
4193b23c184SThomas Pedersen /* TODO: frequency offset in KHz */
4206a86b9c7SJohannes Berg put_unaligned_le16(status->freq, pos);
421601ae7f2SBruno Randolf pos += 2;
422da6a4352SJohannes Berg if (status->bw == RATE_INFO_BW_10)
423a5e70697SSimon Wunderlich channel_flags |= IEEE80211_CHAN_HALF;
424da6a4352SJohannes Berg else if (status->bw == RATE_INFO_BW_5)
425a5e70697SSimon Wunderlich channel_flags |= IEEE80211_CHAN_QUARTER;
426a5e70697SSimon Wunderlich
427412a84b5SAloka Dixit if (status->band == NL80211_BAND_5GHZ ||
428412a84b5SAloka Dixit status->band == NL80211_BAND_6GHZ)
429a5e70697SSimon Wunderlich channel_flags |= IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ;
430da6a4352SJohannes Berg else if (status->encoding != RX_ENC_LEGACY)
431a5e70697SSimon Wunderlich channel_flags |= IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ;
432f8d1ccf1SJohannes Berg else if (rate && rate->flags & IEEE80211_RATE_ERP_G)
433a5e70697SSimon Wunderlich channel_flags |= IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ;
434f8d1ccf1SJohannes Berg else if (rate)
4353a5c5e81SMathy Vanhoef channel_flags |= IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ;
436f8d1ccf1SJohannes Berg else
437a5e70697SSimon Wunderlich channel_flags |= IEEE80211_CHAN_2GHZ;
438a5e70697SSimon Wunderlich put_unaligned_le16(channel_flags, pos);
439601ae7f2SBruno Randolf pos += 2;
440601ae7f2SBruno Randolf
441601ae7f2SBruno Randolf /* IEEE80211_RADIOTAP_DBM_ANTSIGNAL */
44230686bf7SJohannes Berg if (ieee80211_hw_check(&local->hw, SIGNAL_DBM) &&
443fe8431f8SFelix Fietkau !(status->flag & RX_FLAG_NO_SIGNAL_VAL)) {
444601ae7f2SBruno Randolf *pos = status->signal;
445601ae7f2SBruno Randolf rthdr->it_present |=
4465cafd378SKees Cook cpu_to_le32(BIT(IEEE80211_RADIOTAP_DBM_ANTSIGNAL));
447601ae7f2SBruno Randolf pos++;
448601ae7f2SBruno Randolf }
449601ae7f2SBruno Randolf
450601ae7f2SBruno Randolf /* IEEE80211_RADIOTAP_LOCK_QUALITY is missing */
451601ae7f2SBruno Randolf
452a144f378SJohannes Berg if (!status->chains) {
453601ae7f2SBruno Randolf /* IEEE80211_RADIOTAP_ANTENNA */
454601ae7f2SBruno Randolf *pos = status->antenna;
455601ae7f2SBruno Randolf pos++;
456a144f378SJohannes Berg }
457601ae7f2SBruno Randolf
458601ae7f2SBruno Randolf /* IEEE80211_RADIOTAP_DB_ANTNOISE is not used */
459601ae7f2SBruno Randolf
460601ae7f2SBruno Randolf /* IEEE80211_RADIOTAP_RX_FLAGS */
461601ae7f2SBruno Randolf /* ensure 2 byte alignment for the 2 byte field as required */
4626a86b9c7SJohannes Berg if ((pos - (u8 *)rthdr) & 1)
46390b9e446SJohannes Berg *pos++ = 0;
464aae89831SJohannes Berg if (status->flag & RX_FLAG_FAILED_PLCP_CRC)
4656a86b9c7SJohannes Berg rx_flags |= IEEE80211_RADIOTAP_F_RX_BADPLCP;
4666a86b9c7SJohannes Berg put_unaligned_le16(rx_flags, pos);
467601ae7f2SBruno Randolf pos += 2;
4686d744bacSJohannes Berg
469da6a4352SJohannes Berg if (status->encoding == RX_ENC_HT) {
470786677d1SOleksij Rempel unsigned int stbc;
471786677d1SOleksij Rempel
4725cafd378SKees Cook rthdr->it_present |= cpu_to_le32(BIT(IEEE80211_RADIOTAP_MCS));
47357553c3aSP Praneesh *pos = local->hw.radiotap_mcs_details;
47457553c3aSP Praneesh if (status->enc_flags & RX_ENC_FLAG_HT_GF)
47557553c3aSP Praneesh *pos |= IEEE80211_RADIOTAP_MCS_HAVE_FMT;
47657553c3aSP Praneesh if (status->enc_flags & RX_ENC_FLAG_LDPC)
47757553c3aSP Praneesh *pos |= IEEE80211_RADIOTAP_MCS_HAVE_FEC;
47857553c3aSP Praneesh pos++;
4796d744bacSJohannes Berg *pos = 0;
4807fdd69c5SJohannes Berg if (status->enc_flags & RX_ENC_FLAG_SHORT_GI)
4816d744bacSJohannes Berg *pos |= IEEE80211_RADIOTAP_MCS_SGI;
482da6a4352SJohannes Berg if (status->bw == RATE_INFO_BW_40)
4836d744bacSJohannes Berg *pos |= IEEE80211_RADIOTAP_MCS_BW_40;
4847fdd69c5SJohannes Berg if (status->enc_flags & RX_ENC_FLAG_HT_GF)
485ac55d2feSJohannes Berg *pos |= IEEE80211_RADIOTAP_MCS_FMT_GF;
4867fdd69c5SJohannes Berg if (status->enc_flags & RX_ENC_FLAG_LDPC)
48763c361f5SEmmanuel Grumbach *pos |= IEEE80211_RADIOTAP_MCS_FEC_LDPC;
4887fdd69c5SJohannes Berg stbc = (status->enc_flags & RX_ENC_FLAG_STBC_MASK) >> RX_ENC_FLAG_STBC_SHIFT;
489786677d1SOleksij Rempel *pos |= stbc << IEEE80211_RADIOTAP_MCS_STBC_SHIFT;
4906d744bacSJohannes Berg pos++;
4916d744bacSJohannes Berg *pos++ = status->rate_idx;
4926d744bacSJohannes Berg }
4934c298677SJohannes Berg
4944c298677SJohannes Berg if (status->flag & RX_FLAG_AMPDU_DETAILS) {
4954c298677SJohannes Berg u16 flags = 0;
4964c298677SJohannes Berg
4974c298677SJohannes Berg /* ensure 4 byte alignment */
4984c298677SJohannes Berg while ((pos - (u8 *)rthdr) & 3)
4994c298677SJohannes Berg pos++;
5004c298677SJohannes Berg rthdr->it_present |=
5015cafd378SKees Cook cpu_to_le32(BIT(IEEE80211_RADIOTAP_AMPDU_STATUS));
5024c298677SJohannes Berg put_unaligned_le32(status->ampdu_reference, pos);
5034c298677SJohannes Berg pos += 4;
5044c298677SJohannes Berg if (status->flag & RX_FLAG_AMPDU_LAST_KNOWN)
5054c298677SJohannes Berg flags |= IEEE80211_RADIOTAP_AMPDU_LAST_KNOWN;
5064c298677SJohannes Berg if (status->flag & RX_FLAG_AMPDU_IS_LAST)
5074c298677SJohannes Berg flags |= IEEE80211_RADIOTAP_AMPDU_IS_LAST;
5084c298677SJohannes Berg if (status->flag & RX_FLAG_AMPDU_DELIM_CRC_ERROR)
5094c298677SJohannes Berg flags |= IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_ERR;
5104c298677SJohannes Berg if (status->flag & RX_FLAG_AMPDU_DELIM_CRC_KNOWN)
5114c298677SJohannes Berg flags |= IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_KNOWN;
5127299d6f7SJohannes Berg if (status->flag & RX_FLAG_AMPDU_EOF_BIT_KNOWN)
5137299d6f7SJohannes Berg flags |= IEEE80211_RADIOTAP_AMPDU_EOF_KNOWN;
5147299d6f7SJohannes Berg if (status->flag & RX_FLAG_AMPDU_EOF_BIT)
5157299d6f7SJohannes Berg flags |= IEEE80211_RADIOTAP_AMPDU_EOF;
5164c298677SJohannes Berg put_unaligned_le16(flags, pos);
5174c298677SJohannes Berg pos += 2;
5184c298677SJohannes Berg if (status->flag & RX_FLAG_AMPDU_DELIM_CRC_KNOWN)
5194c298677SJohannes Berg *pos++ = status->ampdu_delimiter_crc;
5204c298677SJohannes Berg else
5214c298677SJohannes Berg *pos++ = 0;
5224c298677SJohannes Berg *pos++ = 0;
5234c298677SJohannes Berg }
52490b9e446SJohannes Berg
525da6a4352SJohannes Berg if (status->encoding == RX_ENC_VHT) {
52651648921SJohannes Berg u16 known = local->hw.radiotap_vht_details;
52751648921SJohannes Berg
5285cafd378SKees Cook rthdr->it_present |= cpu_to_le32(BIT(IEEE80211_RADIOTAP_VHT));
52951648921SJohannes Berg put_unaligned_le16(known, pos);
53051648921SJohannes Berg pos += 2;
53151648921SJohannes Berg /* flags */
5327fdd69c5SJohannes Berg if (status->enc_flags & RX_ENC_FLAG_SHORT_GI)
53351648921SJohannes Berg *pos |= IEEE80211_RADIOTAP_VHT_FLAG_SGI;
53463c361f5SEmmanuel Grumbach /* in VHT, STBC is binary */
5357fdd69c5SJohannes Berg if (status->enc_flags & RX_ENC_FLAG_STBC_MASK)
53663c361f5SEmmanuel Grumbach *pos |= IEEE80211_RADIOTAP_VHT_FLAG_STBC;
5377fdd69c5SJohannes Berg if (status->enc_flags & RX_ENC_FLAG_BF)
538fb378c23SEmmanuel Grumbach *pos |= IEEE80211_RADIOTAP_VHT_FLAG_BEAMFORMED;
53951648921SJohannes Berg pos++;
54051648921SJohannes Berg /* bandwidth */
541da6a4352SJohannes Berg switch (status->bw) {
542da6a4352SJohannes Berg case RATE_INFO_BW_80:
54351648921SJohannes Berg *pos++ = 4;
544da6a4352SJohannes Berg break;
545da6a4352SJohannes Berg case RATE_INFO_BW_160:
54651648921SJohannes Berg *pos++ = 11;
547da6a4352SJohannes Berg break;
548da6a4352SJohannes Berg case RATE_INFO_BW_40:
54951648921SJohannes Berg *pos++ = 1;
550da6a4352SJohannes Berg break;
551da6a4352SJohannes Berg default:
55251648921SJohannes Berg *pos++ = 0;
553da6a4352SJohannes Berg }
55451648921SJohannes Berg /* MCS/NSS */
5558613c948SJohannes Berg *pos = (status->rate_idx << 4) | status->nss;
55651648921SJohannes Berg pos += 4;
55751648921SJohannes Berg /* coding field */
5587fdd69c5SJohannes Berg if (status->enc_flags & RX_ENC_FLAG_LDPC)
55963c361f5SEmmanuel Grumbach *pos |= IEEE80211_RADIOTAP_CODING_LDPC_USER0;
56051648921SJohannes Berg pos++;
56151648921SJohannes Berg /* group ID */
56251648921SJohannes Berg pos++;
56351648921SJohannes Berg /* partial_aid */
56451648921SJohannes Berg pos += 2;
56551648921SJohannes Berg }
56651648921SJohannes Berg
56799ee7caeSJohannes Berg if (local->hw.radiotap_timestamp.units_pos >= 0) {
56899ee7caeSJohannes Berg u16 accuracy = 0;
56999ee7caeSJohannes Berg u8 flags = IEEE80211_RADIOTAP_TIMESTAMP_FLAG_32BIT;
57099ee7caeSJohannes Berg
57199ee7caeSJohannes Berg rthdr->it_present |=
5725cafd378SKees Cook cpu_to_le32(BIT(IEEE80211_RADIOTAP_TIMESTAMP));
57399ee7caeSJohannes Berg
57499ee7caeSJohannes Berg /* ensure 8 byte alignment */
57599ee7caeSJohannes Berg while ((pos - (u8 *)rthdr) & 7)
57699ee7caeSJohannes Berg pos++;
57799ee7caeSJohannes Berg
57899ee7caeSJohannes Berg put_unaligned_le64(status->device_timestamp, pos);
57999ee7caeSJohannes Berg pos += sizeof(u64);
58099ee7caeSJohannes Berg
58199ee7caeSJohannes Berg if (local->hw.radiotap_timestamp.accuracy >= 0) {
58299ee7caeSJohannes Berg accuracy = local->hw.radiotap_timestamp.accuracy;
58399ee7caeSJohannes Berg flags |= IEEE80211_RADIOTAP_TIMESTAMP_FLAG_ACCURACY;
58499ee7caeSJohannes Berg }
58599ee7caeSJohannes Berg put_unaligned_le16(accuracy, pos);
58699ee7caeSJohannes Berg pos += sizeof(u16);
58799ee7caeSJohannes Berg
58899ee7caeSJohannes Berg *pos++ = local->hw.radiotap_timestamp.units_pos;
58999ee7caeSJohannes Berg *pos++ = flags;
59099ee7caeSJohannes Berg }
59199ee7caeSJohannes Berg
59241cbb0f5SLuca Coelho if (status->encoding == RX_ENC_HE &&
59341cbb0f5SLuca Coelho status->flag & RX_FLAG_RADIOTAP_HE) {
594331aead5SJohannes Berg #define HE_PREP(f, val) le16_encode_bits(val, IEEE80211_RADIOTAP_HE_##f)
59541cbb0f5SLuca Coelho
59641cbb0f5SLuca Coelho if (status->enc_flags & RX_ENC_FLAG_STBC_MASK) {
59741cbb0f5SLuca Coelho he.data6 |= HE_PREP(DATA6_NSTS,
59841cbb0f5SLuca Coelho FIELD_GET(RX_ENC_FLAG_STBC_MASK,
59941cbb0f5SLuca Coelho status->enc_flags));
60041cbb0f5SLuca Coelho he.data3 |= HE_PREP(DATA3_STBC, 1);
60141cbb0f5SLuca Coelho } else {
60241cbb0f5SLuca Coelho he.data6 |= HE_PREP(DATA6_NSTS, status->nss);
60341cbb0f5SLuca Coelho }
60441cbb0f5SLuca Coelho
60541cbb0f5SLuca Coelho #define CHECK_GI(s) \
60641cbb0f5SLuca Coelho BUILD_BUG_ON(IEEE80211_RADIOTAP_HE_DATA5_GI_##s != \
60741cbb0f5SLuca Coelho (int)NL80211_RATE_INFO_HE_GI_##s)
60841cbb0f5SLuca Coelho
60941cbb0f5SLuca Coelho CHECK_GI(0_8);
61041cbb0f5SLuca Coelho CHECK_GI(1_6);
61141cbb0f5SLuca Coelho CHECK_GI(3_2);
61241cbb0f5SLuca Coelho
61341cbb0f5SLuca Coelho he.data3 |= HE_PREP(DATA3_DATA_MCS, status->rate_idx);
61441cbb0f5SLuca Coelho he.data3 |= HE_PREP(DATA3_DATA_DCM, status->he_dcm);
61541cbb0f5SLuca Coelho he.data3 |= HE_PREP(DATA3_CODING,
61641cbb0f5SLuca Coelho !!(status->enc_flags & RX_ENC_FLAG_LDPC));
61741cbb0f5SLuca Coelho
61841cbb0f5SLuca Coelho he.data5 |= HE_PREP(DATA5_GI, status->he_gi);
61941cbb0f5SLuca Coelho
62041cbb0f5SLuca Coelho switch (status->bw) {
62141cbb0f5SLuca Coelho case RATE_INFO_BW_20:
62241cbb0f5SLuca Coelho he.data5 |= HE_PREP(DATA5_DATA_BW_RU_ALLOC,
62341cbb0f5SLuca Coelho IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_20MHZ);
62441cbb0f5SLuca Coelho break;
62541cbb0f5SLuca Coelho case RATE_INFO_BW_40:
62641cbb0f5SLuca Coelho he.data5 |= HE_PREP(DATA5_DATA_BW_RU_ALLOC,
62741cbb0f5SLuca Coelho IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_40MHZ);
62841cbb0f5SLuca Coelho break;
62941cbb0f5SLuca Coelho case RATE_INFO_BW_80:
63041cbb0f5SLuca Coelho he.data5 |= HE_PREP(DATA5_DATA_BW_RU_ALLOC,
63141cbb0f5SLuca Coelho IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_80MHZ);
63241cbb0f5SLuca Coelho break;
63341cbb0f5SLuca Coelho case RATE_INFO_BW_160:
63441cbb0f5SLuca Coelho he.data5 |= HE_PREP(DATA5_DATA_BW_RU_ALLOC,
63541cbb0f5SLuca Coelho IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_160MHZ);
63641cbb0f5SLuca Coelho break;
63741cbb0f5SLuca Coelho case RATE_INFO_BW_HE_RU:
63841cbb0f5SLuca Coelho #define CHECK_RU_ALLOC(s) \
63941cbb0f5SLuca Coelho BUILD_BUG_ON(IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_##s##T != \
64041cbb0f5SLuca Coelho NL80211_RATE_INFO_HE_RU_ALLOC_##s + 4)
64141cbb0f5SLuca Coelho
64241cbb0f5SLuca Coelho CHECK_RU_ALLOC(26);
64341cbb0f5SLuca Coelho CHECK_RU_ALLOC(52);
64441cbb0f5SLuca Coelho CHECK_RU_ALLOC(106);
64541cbb0f5SLuca Coelho CHECK_RU_ALLOC(242);
64641cbb0f5SLuca Coelho CHECK_RU_ALLOC(484);
64741cbb0f5SLuca Coelho CHECK_RU_ALLOC(996);
64841cbb0f5SLuca Coelho CHECK_RU_ALLOC(2x996);
64941cbb0f5SLuca Coelho
65041cbb0f5SLuca Coelho he.data5 |= HE_PREP(DATA5_DATA_BW_RU_ALLOC,
65141cbb0f5SLuca Coelho status->he_ru + 4);
65241cbb0f5SLuca Coelho break;
65341cbb0f5SLuca Coelho default:
65441cbb0f5SLuca Coelho WARN_ONCE(1, "Invalid SU BW %d\n", status->bw);
65541cbb0f5SLuca Coelho }
65641cbb0f5SLuca Coelho
65741cbb0f5SLuca Coelho /* ensure 2 byte alignment */
65841cbb0f5SLuca Coelho while ((pos - (u8 *)rthdr) & 1)
65941cbb0f5SLuca Coelho pos++;
6605cafd378SKees Cook rthdr->it_present |= cpu_to_le32(BIT(IEEE80211_RADIOTAP_HE));
66141cbb0f5SLuca Coelho memcpy(pos, &he, sizeof(he));
66241cbb0f5SLuca Coelho pos += sizeof(he);
66341cbb0f5SLuca Coelho }
66441cbb0f5SLuca Coelho
66541cbb0f5SLuca Coelho if (status->encoding == RX_ENC_HE &&
66641cbb0f5SLuca Coelho status->flag & RX_FLAG_RADIOTAP_HE_MU) {
66741cbb0f5SLuca Coelho /* ensure 2 byte alignment */
66841cbb0f5SLuca Coelho while ((pos - (u8 *)rthdr) & 1)
66941cbb0f5SLuca Coelho pos++;
6705cafd378SKees Cook rthdr->it_present |= cpu_to_le32(BIT(IEEE80211_RADIOTAP_HE_MU));
67141cbb0f5SLuca Coelho memcpy(pos, &he_mu, sizeof(he_mu));
67241cbb0f5SLuca Coelho pos += sizeof(he_mu);
67341cbb0f5SLuca Coelho }
67441cbb0f5SLuca Coelho
675c3d1f875SShaul Triebitz if (status->flag & RX_FLAG_NO_PSDU) {
676c3d1f875SShaul Triebitz rthdr->it_present |=
6775cafd378SKees Cook cpu_to_le32(BIT(IEEE80211_RADIOTAP_ZERO_LEN_PSDU));
678c3d1f875SShaul Triebitz *pos++ = status->zero_length_psdu_type;
679c3d1f875SShaul Triebitz }
680c3d1f875SShaul Triebitz
681d1332e7bSShaul Triebitz if (status->flag & RX_FLAG_RADIOTAP_LSIG) {
682d1332e7bSShaul Triebitz /* ensure 2 byte alignment */
683d1332e7bSShaul Triebitz while ((pos - (u8 *)rthdr) & 1)
684d1332e7bSShaul Triebitz pos++;
6855cafd378SKees Cook rthdr->it_present |= cpu_to_le32(BIT(IEEE80211_RADIOTAP_LSIG));
686d1332e7bSShaul Triebitz memcpy(pos, &lsig, sizeof(lsig));
687d1332e7bSShaul Triebitz pos += sizeof(lsig);
688d1332e7bSShaul Triebitz }
689d1332e7bSShaul Triebitz
690a144f378SJohannes Berg for_each_set_bit(chain, &chains, IEEE80211_MAX_CHAINS) {
691a144f378SJohannes Berg *pos++ = status->chain_signal[chain];
692a144f378SJohannes Berg *pos++ = chain;
693a144f378SJohannes Berg }
694601ae7f2SBruno Randolf }
695601ae7f2SBruno Randolf
696127f60bfSJohannes Berg static struct sk_buff *
ieee80211_make_monitor_skb(struct ieee80211_local * local,struct sk_buff ** origskb,struct ieee80211_rate * rate,int rtap_space,bool use_origskb)697127f60bfSJohannes Berg ieee80211_make_monitor_skb(struct ieee80211_local *local,
698127f60bfSJohannes Berg struct sk_buff **origskb,
699127f60bfSJohannes Berg struct ieee80211_rate *rate,
700c096b92aSJohannes Berg int rtap_space, bool use_origskb)
701127f60bfSJohannes Berg {
702127f60bfSJohannes Berg struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(*origskb);
703127f60bfSJohannes Berg int rt_hdrlen, needed_headroom;
704127f60bfSJohannes Berg struct sk_buff *skb;
705127f60bfSJohannes Berg
706127f60bfSJohannes Berg /* room for the radiotap header based on driver features */
707127f60bfSJohannes Berg rt_hdrlen = ieee80211_rx_radiotap_hdrlen(local, status, *origskb);
708c096b92aSJohannes Berg needed_headroom = rt_hdrlen - rtap_space;
709127f60bfSJohannes Berg
710127f60bfSJohannes Berg if (use_origskb) {
711127f60bfSJohannes Berg /* only need to expand headroom if necessary */
712127f60bfSJohannes Berg skb = *origskb;
713127f60bfSJohannes Berg *origskb = NULL;
714127f60bfSJohannes Berg
715127f60bfSJohannes Berg /*
716127f60bfSJohannes Berg * This shouldn't trigger often because most devices have an
717127f60bfSJohannes Berg * RX header they pull before we get here, and that should
718127f60bfSJohannes Berg * be big enough for our radiotap information. We should
719127f60bfSJohannes Berg * probably export the length to drivers so that we can have
720127f60bfSJohannes Berg * them allocate enough headroom to start with.
721127f60bfSJohannes Berg */
722127f60bfSJohannes Berg if (skb_headroom(skb) < needed_headroom &&
723127f60bfSJohannes Berg pskb_expand_head(skb, needed_headroom, 0, GFP_ATOMIC)) {
724127f60bfSJohannes Berg dev_kfree_skb(skb);
725127f60bfSJohannes Berg return NULL;
726127f60bfSJohannes Berg }
727127f60bfSJohannes Berg } else {
728127f60bfSJohannes Berg /*
729127f60bfSJohannes Berg * Need to make a copy and possibly remove radiotap header
730127f60bfSJohannes Berg * and FCS from the original.
731127f60bfSJohannes Berg */
732ec61cd49SJohan Almbladh skb = skb_copy_expand(*origskb, needed_headroom + NET_SKB_PAD,
733ec61cd49SJohan Almbladh 0, GFP_ATOMIC);
734127f60bfSJohannes Berg
735127f60bfSJohannes Berg if (!skb)
736127f60bfSJohannes Berg return NULL;
737127f60bfSJohannes Berg }
738127f60bfSJohannes Berg
739127f60bfSJohannes Berg /* prepend radiotap information */
740127f60bfSJohannes Berg ieee80211_add_rx_radiotap_header(local, skb, rate, rt_hdrlen, true);
741127f60bfSJohannes Berg
742127f60bfSJohannes Berg skb_reset_mac_header(skb);
743127f60bfSJohannes Berg skb->ip_summed = CHECKSUM_UNNECESSARY;
744127f60bfSJohannes Berg skb->pkt_type = PACKET_OTHERHOST;
745127f60bfSJohannes Berg skb->protocol = htons(ETH_P_802_2);
746127f60bfSJohannes Berg
747127f60bfSJohannes Berg return skb;
748127f60bfSJohannes Berg }
749127f60bfSJohannes Berg
750b2e7771eSJohannes Berg /*
751b2e7771eSJohannes Berg * This function copies a received frame to all monitor interfaces and
752b2e7771eSJohannes Berg * returns a cleaned-up SKB that no longer includes the FCS nor the
753b2e7771eSJohannes Berg * radiotap header the driver might have added.
754b2e7771eSJohannes Berg */
755b2e7771eSJohannes Berg static struct sk_buff *
ieee80211_rx_monitor(struct ieee80211_local * local,struct sk_buff * origskb,struct ieee80211_rate * rate)756b2e7771eSJohannes Berg ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
7578318d78aSJohannes Berg struct ieee80211_rate *rate)
758b2e7771eSJohannes Berg {
759f1d58c25SJohannes Berg struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(origskb);
760b2e7771eSJohannes Berg struct ieee80211_sub_if_data *sdata;
761127f60bfSJohannes Berg struct sk_buff *monskb = NULL;
762b2e7771eSJohannes Berg int present_fcs_len = 0;
763c096b92aSJohannes Berg unsigned int rtap_space = 0;
76442bd20d9SAviya Erenfeld struct ieee80211_sub_if_data *monitor_sdata =
76542bd20d9SAviya Erenfeld rcu_dereference(local->monitor_sdata);
766127f60bfSJohannes Berg bool only_monitor = false;
7678020919aSIlan Peer unsigned int min_head_len;
7681f7bba79SJohannes Berg
7699179dff8SMordechay Goodstein if (WARN_ON_ONCE(status->flag & RX_FLAG_RADIOTAP_TLV_AT_END &&
7709179dff8SMordechay Goodstein !skb_mac_header_was_set(origskb))) {
7719179dff8SMordechay Goodstein /* with this skb no way to know where frame payload starts */
7729179dff8SMordechay Goodstein dev_kfree_skb(origskb);
7739179dff8SMordechay Goodstein return NULL;
7749179dff8SMordechay Goodstein }
7759179dff8SMordechay Goodstein
77641cbb0f5SLuca Coelho if (status->flag & RX_FLAG_RADIOTAP_HE)
77741cbb0f5SLuca Coelho rtap_space += sizeof(struct ieee80211_radiotap_he);
77841cbb0f5SLuca Coelho
77941cbb0f5SLuca Coelho if (status->flag & RX_FLAG_RADIOTAP_HE_MU)
78041cbb0f5SLuca Coelho rtap_space += sizeof(struct ieee80211_radiotap_he_mu);
78141cbb0f5SLuca Coelho
782d359bbceSIlan Peer if (status->flag & RX_FLAG_RADIOTAP_LSIG)
783d359bbceSIlan Peer rtap_space += sizeof(struct ieee80211_radiotap_lsig);
784d359bbceSIlan Peer
7859179dff8SMordechay Goodstein if (status->flag & RX_FLAG_RADIOTAP_TLV_AT_END)
7869179dff8SMordechay Goodstein rtap_space += skb_mac_header(origskb) - &origskb->data[rtap_space];
787b2e7771eSJohannes Berg
7888020919aSIlan Peer min_head_len = rtap_space;
7898020919aSIlan Peer
790b2e7771eSJohannes Berg /*
791b2e7771eSJohannes Berg * First, we may need to make a copy of the skb because
792b2e7771eSJohannes Berg * (1) we need to modify it for radiotap (if not present), and
793b2e7771eSJohannes Berg * (2) the other RX handlers will modify the skb we got.
794b2e7771eSJohannes Berg *
795b2e7771eSJohannes Berg * We don't need to, of course, if we aren't going to return
796b2e7771eSJohannes Berg * the SKB because it has a bad FCS/PLCP checksum.
797b2e7771eSJohannes Berg */
7980869aea0SJohannes Berg
7998020919aSIlan Peer if (!(status->flag & RX_FLAG_NO_PSDU)) {
80030841f5cSJohannes Berg if (ieee80211_hw_check(&local->hw, RX_INCLUDES_FCS)) {
8018020919aSIlan Peer if (unlikely(origskb->len <= FCS_LEN + rtap_space)) {
80230841f5cSJohannes Berg /* driver bug */
80330841f5cSJohannes Berg WARN_ON(1);
80430841f5cSJohannes Berg dev_kfree_skb(origskb);
80530841f5cSJohannes Berg return NULL;
80630841f5cSJohannes Berg }
807b2e7771eSJohannes Berg present_fcs_len = FCS_LEN;
80830841f5cSJohannes Berg }
809b2e7771eSJohannes Berg
8108020919aSIlan Peer /* also consider the hdr->frame_control */
8118020919aSIlan Peer min_head_len += 2;
8128020919aSIlan Peer }
8138020919aSIlan Peer
8148020919aSIlan Peer /* ensure that the expected data elements are in skb head */
8158020919aSIlan Peer if (!pskb_may_pull(origskb, min_head_len)) {
816e3cf8b3fSZhu Yi dev_kfree_skb(origskb);
817e3cf8b3fSZhu Yi return NULL;
818e3cf8b3fSZhu Yi }
819e3cf8b3fSZhu Yi
820c096b92aSJohannes Berg only_monitor = should_drop_frame(origskb, present_fcs_len, rtap_space);
821127f60bfSJohannes Berg
82217883048SGrzegorz Bajorski if (!local->monitors || (status->flag & RX_FLAG_SKIP_MONITOR)) {
823127f60bfSJohannes Berg if (only_monitor) {
824b2e7771eSJohannes Berg dev_kfree_skb(origskb);
825b2e7771eSJohannes Berg return NULL;
826b2e7771eSJohannes Berg }
827b2e7771eSJohannes Berg
828c1129924SJohannes Berg return ieee80211_clean_skb(origskb, present_fcs_len,
829c1129924SJohannes Berg rtap_space);
830b2e7771eSJohannes Berg }
831b2e7771eSJohannes Berg
832c096b92aSJohannes Berg ieee80211_handle_mu_mimo_mon(monitor_sdata, origskb, rtap_space);
8339e478066SJohannes Berg
834f64331d5SJohannes Berg list_for_each_entry_rcu(sdata, &local->mon_list, u.mntr.list) {
835127f60bfSJohannes Berg bool last_monitor = list_is_last(&sdata->u.mntr.list,
836127f60bfSJohannes Berg &local->mon_list);
837127f60bfSJohannes Berg
838127f60bfSJohannes Berg if (!monskb)
839127f60bfSJohannes Berg monskb = ieee80211_make_monitor_skb(local, &origskb,
840c096b92aSJohannes Berg rate, rtap_space,
841127f60bfSJohannes Berg only_monitor &&
842127f60bfSJohannes Berg last_monitor);
843127f60bfSJohannes Berg
844127f60bfSJohannes Berg if (monskb) {
845127f60bfSJohannes Berg struct sk_buff *skb;
846127f60bfSJohannes Berg
847127f60bfSJohannes Berg if (last_monitor) {
848127f60bfSJohannes Berg skb = monskb;
849127f60bfSJohannes Berg monskb = NULL;
850127f60bfSJohannes Berg } else {
851127f60bfSJohannes Berg skb = skb_clone(monskb, GFP_ATOMIC);
852b2e7771eSJohannes Berg }
853b2e7771eSJohannes Berg
854127f60bfSJohannes Berg if (skb) {
855127f60bfSJohannes Berg skb->dev = sdata->dev;
85636ec144fSLev Stipakov dev_sw_netstats_rx_add(skb->dev, skb->len);
8575548a8a1SJohn W. Linville netif_receive_skb(skb);
858127f60bfSJohannes Berg }
859127f60bfSJohannes Berg }
860b2e7771eSJohannes Berg
861127f60bfSJohannes Berg if (last_monitor)
862127f60bfSJohannes Berg break;
863127f60bfSJohannes Berg }
864127f60bfSJohannes Berg
865127f60bfSJohannes Berg /* this happens if last_monitor was erroneously false */
866127f60bfSJohannes Berg dev_kfree_skb(monskb);
867127f60bfSJohannes Berg
868127f60bfSJohannes Berg /* ditto */
869127f60bfSJohannes Berg if (!origskb)
870127f60bfSJohannes Berg return NULL;
871127f60bfSJohannes Berg
872c1129924SJohannes Berg return ieee80211_clean_skb(origskb, present_fcs_len, rtap_space);
873b2e7771eSJohannes Berg }
874b2e7771eSJohannes Berg
ieee80211_parse_qos(struct ieee80211_rx_data * rx)8755cf121c3SJohannes Berg static void ieee80211_parse_qos(struct ieee80211_rx_data *rx)
8766e0d114dSJohannes Berg {
877238f74a2SHarvey Harrison struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
878554891e6SJohannes Berg struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
8799e26297aSJohannes Berg int tid, seqno_idx, security_idx;
8806e0d114dSJohannes Berg
8816e0d114dSJohannes Berg /* does the frame have a qos control field? */
882238f74a2SHarvey Harrison if (ieee80211_is_data_qos(hdr->frame_control)) {
883238f74a2SHarvey Harrison u8 *qc = ieee80211_get_qos_ctl(hdr);
8846e0d114dSJohannes Berg /* frame has qos control */
885238f74a2SHarvey Harrison tid = *qc & IEEE80211_QOS_CTL_TID_MASK;
88604b7dcf9SJohannes Berg if (*qc & IEEE80211_QOS_CTL_A_MSDU_PRESENT)
887554891e6SJohannes Berg status->rx_flags |= IEEE80211_RX_AMSDU;
8889e26297aSJohannes Berg
8899e26297aSJohannes Berg seqno_idx = tid;
8909e26297aSJohannes Berg security_idx = tid;
8916e0d114dSJohannes Berg } else {
8921411f9b5SJohannes Berg /*
8931411f9b5SJohannes Berg * IEEE 802.11-2007, 7.1.3.4.1 ("Sequence Number field"):
8941411f9b5SJohannes Berg *
8951411f9b5SJohannes Berg * Sequence numbers for management frames, QoS data
8961411f9b5SJohannes Berg * frames with a broadcast/multicast address in the
8971411f9b5SJohannes Berg * Address 1 field, and all non-QoS data frames sent
8981411f9b5SJohannes Berg * by QoS STAs are assigned using an additional single
8991411f9b5SJohannes Berg * modulo-4096 counter, [...]
9001411f9b5SJohannes Berg *
9011411f9b5SJohannes Berg * We also use that counter for non-QoS STAs.
9021411f9b5SJohannes Berg */
9035a306f58SJohannes Berg seqno_idx = IEEE80211_NUM_TIDS;
9049e26297aSJohannes Berg security_idx = 0;
9059e26297aSJohannes Berg if (ieee80211_is_mgmt(hdr->frame_control))
9065a306f58SJohannes Berg security_idx = IEEE80211_NUM_TIDS;
9079e26297aSJohannes Berg tid = 0;
9086e0d114dSJohannes Berg }
90952865dfdSJohannes Berg
9109e26297aSJohannes Berg rx->seqno_idx = seqno_idx;
9119e26297aSJohannes Berg rx->security_idx = security_idx;
9126e0d114dSJohannes Berg /* Set skb->priority to 1d tag if highest order bit of TID is not set.
9136e0d114dSJohannes Berg * For now, set skb->priority to 0 for other cases. */
9146e0d114dSJohannes Berg rx->skb->priority = (tid > 7) ? 0 : tid;
91538f3714dSJohannes Berg }
9166e0d114dSJohannes Berg
917d1c3a37cSJohannes Berg /**
918d1c3a37cSJohannes Berg * DOC: Packet alignment
919d1c3a37cSJohannes Berg *
920d1c3a37cSJohannes Berg * Drivers always need to pass packets that are aligned to two-byte boundaries
921d1c3a37cSJohannes Berg * to the stack.
922d1c3a37cSJohannes Berg *
923d1c3a37cSJohannes Berg * Additionally, should, if possible, align the payload data in a way that
924d1c3a37cSJohannes Berg * guarantees that the contained IP header is aligned to a four-byte
925d1c3a37cSJohannes Berg * boundary. In the case of regular frames, this simply means aligning the
926d1c3a37cSJohannes Berg * payload to a four-byte boundary (because either the IP header is directly
927d1c3a37cSJohannes Berg * contained, or IV/RFC1042 headers that have a length divisible by four are
92859d9cb07SKalle Valo * in front of it). If the payload data is not properly aligned and the
92959d9cb07SKalle Valo * architecture doesn't support efficient unaligned operations, mac80211
93059d9cb07SKalle Valo * will align the data.
931d1c3a37cSJohannes Berg *
932d1c3a37cSJohannes Berg * With A-MSDU frames, however, the payload data address must yield two modulo
933d1c3a37cSJohannes Berg * four because there are 14-byte 802.3 headers within the A-MSDU frames that
934d1c3a37cSJohannes Berg * push the IP header further back to a multiple of four again. Thankfully, the
935d1c3a37cSJohannes Berg * specs were sane enough this time around to require padding each A-MSDU
936d1c3a37cSJohannes Berg * subframe to a length that is a multiple of four.
937d1c3a37cSJohannes Berg *
93825985edcSLucas De Marchi * Padding like Atheros hardware adds which is between the 802.11 header and
939d1c3a37cSJohannes Berg * the payload is not supported, the driver is required to move the 802.11
940d1c3a37cSJohannes Berg * header to be directly in front of the payload in that case.
941d1c3a37cSJohannes Berg */
ieee80211_verify_alignment(struct ieee80211_rx_data * rx)942d1c3a37cSJohannes Berg static void ieee80211_verify_alignment(struct ieee80211_rx_data *rx)
94338f3714dSJohannes Berg {
94459d9cb07SKalle Valo #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
945441275e1SJohannes Berg WARN_ON_ONCE((unsigned long)rx->skb->data & 1);
946d1c3a37cSJohannes Berg #endif
9476e0d114dSJohannes Berg }
9486e0d114dSJohannes Berg
9496368e4b1SRon Rindjunsky
950571ecf67SJohannes Berg /* rx handlers */
951571ecf67SJohannes Berg
ieee80211_is_unicast_robust_mgmt_frame(struct sk_buff * skb)9523cfcf6acSJouni Malinen static int ieee80211_is_unicast_robust_mgmt_frame(struct sk_buff *skb)
9533cfcf6acSJouni Malinen {
9543cfcf6acSJouni Malinen struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
9553cfcf6acSJouni Malinen
956d8ca16dbSJohannes Berg if (is_multicast_ether_addr(hdr->addr1))
9573cfcf6acSJouni Malinen return 0;
9583cfcf6acSJouni Malinen
959d8ca16dbSJohannes Berg return ieee80211_is_robust_mgmt_frame(skb);
9603cfcf6acSJouni Malinen }
9613cfcf6acSJouni Malinen
9623cfcf6acSJouni Malinen
ieee80211_is_multicast_robust_mgmt_frame(struct sk_buff * skb)9633cfcf6acSJouni Malinen static int ieee80211_is_multicast_robust_mgmt_frame(struct sk_buff *skb)
9643cfcf6acSJouni Malinen {
9653cfcf6acSJouni Malinen struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
9663cfcf6acSJouni Malinen
967d8ca16dbSJohannes Berg if (!is_multicast_ether_addr(hdr->addr1))
9683cfcf6acSJouni Malinen return 0;
9693cfcf6acSJouni Malinen
970d8ca16dbSJohannes Berg return ieee80211_is_robust_mgmt_frame(skb);
9713cfcf6acSJouni Malinen }
9723cfcf6acSJouni Malinen
9733cfcf6acSJouni Malinen
9743cfcf6acSJouni Malinen /* Get the BIP key index from MMIE; return -1 if this is not a BIP frame */
ieee80211_get_mmie_keyidx(struct sk_buff * skb)9753cfcf6acSJouni Malinen static int ieee80211_get_mmie_keyidx(struct sk_buff *skb)
9763cfcf6acSJouni Malinen {
9773cfcf6acSJouni Malinen struct ieee80211_mgmt *hdr = (struct ieee80211_mgmt *) skb->data;
9783cfcf6acSJouni Malinen struct ieee80211_mmie *mmie;
97956c52da2SJouni Malinen struct ieee80211_mmie_16 *mmie16;
9803cfcf6acSJouni Malinen
9811df332e8SJohannes Berg if (skb->len < 24 + sizeof(*mmie) || !is_multicast_ether_addr(hdr->da))
9823cfcf6acSJouni Malinen return -1;
9833cfcf6acSJouni Malinen
984af2d14b0SJouni Malinen if (!ieee80211_is_robust_mgmt_frame(skb) &&
985af2d14b0SJouni Malinen !ieee80211_is_beacon(hdr->frame_control))
9863cfcf6acSJouni Malinen return -1; /* not a robust management frame */
9873cfcf6acSJouni Malinen
9883cfcf6acSJouni Malinen mmie = (struct ieee80211_mmie *)
9893cfcf6acSJouni Malinen (skb->data + skb->len - sizeof(*mmie));
99056c52da2SJouni Malinen if (mmie->element_id == WLAN_EID_MMIE &&
99156c52da2SJouni Malinen mmie->length == sizeof(*mmie) - 2)
9923cfcf6acSJouni Malinen return le16_to_cpu(mmie->key_id);
99356c52da2SJouni Malinen
99456c52da2SJouni Malinen mmie16 = (struct ieee80211_mmie_16 *)
99556c52da2SJouni Malinen (skb->data + skb->len - sizeof(*mmie16));
99656c52da2SJouni Malinen if (skb->len >= 24 + sizeof(*mmie16) &&
99756c52da2SJouni Malinen mmie16->element_id == WLAN_EID_MMIE &&
99856c52da2SJouni Malinen mmie16->length == sizeof(*mmie16) - 2)
99956c52da2SJouni Malinen return le16_to_cpu(mmie16->key_id);
100056c52da2SJouni Malinen
100156c52da2SJouni Malinen return -1;
10023cfcf6acSJouni Malinen }
10033cfcf6acSJouni Malinen
ieee80211_get_keyid(struct sk_buff * skb)100423a5f0afSJohannes Berg static int ieee80211_get_keyid(struct sk_buff *skb)
10052475b1ccSMax Stepanov {
10062475b1ccSMax Stepanov struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
100723a5f0afSJohannes Berg __le16 fc = hdr->frame_control;
100823a5f0afSJohannes Berg int hdrlen = ieee80211_hdrlen(fc);
10092475b1ccSMax Stepanov u8 keyid;
10102475b1ccSMax Stepanov
101196fc6efbSAlexander Wetzel /* WEP, TKIP, CCMP and GCMP */
101223a5f0afSJohannes Berg if (unlikely(skb->len < hdrlen + IEEE80211_WEP_IV_LEN))
10132475b1ccSMax Stepanov return -EINVAL;
10142475b1ccSMax Stepanov
101523a5f0afSJohannes Berg skb_copy_bits(skb, hdrlen + 3, &keyid, 1);
101696fc6efbSAlexander Wetzel
101723a5f0afSJohannes Berg keyid >>= 6;
10182475b1ccSMax Stepanov
10192475b1ccSMax Stepanov return keyid;
10202475b1ccSMax Stepanov }
10212475b1ccSMax Stepanov
ieee80211_rx_mesh_check(struct ieee80211_rx_data * rx)10221df332e8SJohannes Berg static ieee80211_rx_result ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
102333b64eb2SLuis Carlos Cobo {
102433b64eb2SLuis Carlos Cobo struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
102547846c9bSJohannes Berg char *dev_addr = rx->sdata->vif.addr;
1026d6d1a5a7SJohannes Berg
1027a7767f95SHarvey Harrison if (ieee80211_is_data(hdr->frame_control)) {
10283c5772a5SJavier Cardona if (is_multicast_ether_addr(hdr->addr1)) {
10293c5772a5SJavier Cardona if (ieee80211_has_tods(hdr->frame_control) ||
10303c5772a5SJavier Cardona !ieee80211_has_fromds(hdr->frame_control))
10313c5772a5SJavier Cardona return RX_DROP_MONITOR;
1032b203ca39SJoe Perches if (ether_addr_equal(hdr->addr3, dev_addr))
10333c5772a5SJavier Cardona return RX_DROP_MONITOR;
10343c5772a5SJavier Cardona } else {
1035a7767f95SHarvey Harrison if (!ieee80211_has_a4(hdr->frame_control))
103633b64eb2SLuis Carlos Cobo return RX_DROP_MONITOR;
1037b203ca39SJoe Perches if (ether_addr_equal(hdr->addr4, dev_addr))
103833b64eb2SLuis Carlos Cobo return RX_DROP_MONITOR;
103933b64eb2SLuis Carlos Cobo }
10403c5772a5SJavier Cardona }
104133b64eb2SLuis Carlos Cobo
104233b64eb2SLuis Carlos Cobo /* If there is not an established peer link and this is not a peer link
104333b64eb2SLuis Carlos Cobo * establisment frame, beacon or probe, drop the frame.
104433b64eb2SLuis Carlos Cobo */
104533b64eb2SLuis Carlos Cobo
104657cf8043SJavier Cardona if (!rx->sta || sta_plink_state(rx->sta) != NL80211_PLINK_ESTAB) {
104733b64eb2SLuis Carlos Cobo struct ieee80211_mgmt *mgmt;
1048d6d1a5a7SJohannes Berg
1049a7767f95SHarvey Harrison if (!ieee80211_is_mgmt(hdr->frame_control))
105033b64eb2SLuis Carlos Cobo return RX_DROP_MONITOR;
105133b64eb2SLuis Carlos Cobo
1052a7767f95SHarvey Harrison if (ieee80211_is_action(hdr->frame_control)) {
1053d3aaec8aSJavier Cardona u8 category;
10549b395bc3SJohannes Berg
10559b395bc3SJohannes Berg /* make sure category field is present */
10569b395bc3SJohannes Berg if (rx->skb->len < IEEE80211_MIN_ACTION_SIZE)
10579b395bc3SJohannes Berg return RX_DROP_MONITOR;
10589b395bc3SJohannes Berg
105933b64eb2SLuis Carlos Cobo mgmt = (struct ieee80211_mgmt *)hdr;
1060d3aaec8aSJavier Cardona category = mgmt->u.action.category;
1061d3aaec8aSJavier Cardona if (category != WLAN_CATEGORY_MESH_ACTION &&
1062d3aaec8aSJavier Cardona category != WLAN_CATEGORY_SELF_PROTECTED)
106333b64eb2SLuis Carlos Cobo return RX_DROP_MONITOR;
106433b64eb2SLuis Carlos Cobo return RX_CONTINUE;
106533b64eb2SLuis Carlos Cobo }
106633b64eb2SLuis Carlos Cobo
1067a7767f95SHarvey Harrison if (ieee80211_is_probe_req(hdr->frame_control) ||
1068a7767f95SHarvey Harrison ieee80211_is_probe_resp(hdr->frame_control) ||
106971839121SJavier Cardona ieee80211_is_beacon(hdr->frame_control) ||
107071839121SJavier Cardona ieee80211_is_auth(hdr->frame_control))
1071a7767f95SHarvey Harrison return RX_CONTINUE;
1072a7767f95SHarvey Harrison
1073a7767f95SHarvey Harrison return RX_DROP_MONITOR;
1074a7767f95SHarvey Harrison }
1075a7767f95SHarvey Harrison
1076902acc78SJohannes Berg return RX_CONTINUE;
1077902acc78SJohannes Berg }
107833b64eb2SLuis Carlos Cobo
ieee80211_rx_reorder_ready(struct tid_ampdu_rx * tid_agg_rx,int index)1079fb4ea054SJohannes Berg static inline bool ieee80211_rx_reorder_ready(struct tid_ampdu_rx *tid_agg_rx,
1080fb4ea054SJohannes Berg int index)
1081fb4ea054SJohannes Berg {
1082fb4ea054SJohannes Berg struct sk_buff_head *frames = &tid_agg_rx->reorder_buf[index];
1083fb4ea054SJohannes Berg struct sk_buff *tail = skb_peek_tail(frames);
1084fb4ea054SJohannes Berg struct ieee80211_rx_status *status;
1085fb4ea054SJohannes Berg
1086b98c1610SPing-Ke Shih if (tid_agg_rx->reorder_buf_filtered &&
1087b98c1610SPing-Ke Shih tid_agg_rx->reorder_buf_filtered & BIT_ULL(index))
108806470f74SSara Sharon return true;
108906470f74SSara Sharon
1090fb4ea054SJohannes Berg if (!tail)
1091fb4ea054SJohannes Berg return false;
1092fb4ea054SJohannes Berg
1093fb4ea054SJohannes Berg status = IEEE80211_SKB_RXCB(tail);
1094fb4ea054SJohannes Berg if (status->flag & RX_FLAG_AMSDU_MORE)
1095fb4ea054SJohannes Berg return false;
1096fb4ea054SJohannes Berg
1097fb4ea054SJohannes Berg return true;
1098fb4ea054SJohannes Berg }
1099fb4ea054SJohannes Berg
ieee80211_release_reorder_frame(struct ieee80211_sub_if_data * sdata,struct tid_ampdu_rx * tid_agg_rx,int index,struct sk_buff_head * frames)1100d3b2fb53SJohannes Berg static void ieee80211_release_reorder_frame(struct ieee80211_sub_if_data *sdata,
11011edfb1afSJohannes Berg struct tid_ampdu_rx *tid_agg_rx,
1102f9e124fbSChristian Lamparter int index,
1103f9e124fbSChristian Lamparter struct sk_buff_head *frames)
11041edfb1afSJohannes Berg {
110583eb935eSMichal Kazior struct sk_buff_head *skb_list = &tid_agg_rx->reorder_buf[index];
110683eb935eSMichal Kazior struct sk_buff *skb;
11074cfda47bSChristian Lamparter struct ieee80211_rx_status *status;
11081edfb1afSJohannes Berg
1109dd318575SJohannes Berg lockdep_assert_held(&tid_agg_rx->reorder_lock);
1110dd318575SJohannes Berg
111183eb935eSMichal Kazior if (skb_queue_empty(skb_list))
11121edfb1afSJohannes Berg goto no_frame;
11131edfb1afSJohannes Berg
1114fb4ea054SJohannes Berg if (!ieee80211_rx_reorder_ready(tid_agg_rx, index)) {
111583eb935eSMichal Kazior __skb_queue_purge(skb_list);
111683eb935eSMichal Kazior goto no_frame;
111783eb935eSMichal Kazior }
111883eb935eSMichal Kazior
111983eb935eSMichal Kazior /* release frames from the reorder ring buffer */
11201edfb1afSJohannes Berg tid_agg_rx->stored_mpdu_num--;
112183eb935eSMichal Kazior while ((skb = __skb_dequeue(skb_list))) {
11224cfda47bSChristian Lamparter status = IEEE80211_SKB_RXCB(skb);
11234cfda47bSChristian Lamparter status->rx_flags |= IEEE80211_RX_DEFERRED_RELEASE;
1124f9e124fbSChristian Lamparter __skb_queue_tail(frames, skb);
112583eb935eSMichal Kazior }
11261edfb1afSJohannes Berg
11271edfb1afSJohannes Berg no_frame:
1128b98c1610SPing-Ke Shih if (tid_agg_rx->reorder_buf_filtered)
112906470f74SSara Sharon tid_agg_rx->reorder_buf_filtered &= ~BIT_ULL(index);
11309a886586SJohannes Berg tid_agg_rx->head_seq_num = ieee80211_sn_inc(tid_agg_rx->head_seq_num);
11311edfb1afSJohannes Berg }
11321edfb1afSJohannes Berg
ieee80211_release_reorder_frames(struct ieee80211_sub_if_data * sdata,struct tid_ampdu_rx * tid_agg_rx,u16 head_seq_num,struct sk_buff_head * frames)1133d3b2fb53SJohannes Berg static void ieee80211_release_reorder_frames(struct ieee80211_sub_if_data *sdata,
11341edfb1afSJohannes Berg struct tid_ampdu_rx *tid_agg_rx,
1135f9e124fbSChristian Lamparter u16 head_seq_num,
1136f9e124fbSChristian Lamparter struct sk_buff_head *frames)
11371edfb1afSJohannes Berg {
11381edfb1afSJohannes Berg int index;
11391edfb1afSJohannes Berg
1140dd318575SJohannes Berg lockdep_assert_held(&tid_agg_rx->reorder_lock);
1141dd318575SJohannes Berg
11429a886586SJohannes Berg while (ieee80211_sn_less(tid_agg_rx->head_seq_num, head_seq_num)) {
11432e3049b7SKarl Beldan index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size;
1144f9e124fbSChristian Lamparter ieee80211_release_reorder_frame(sdata, tid_agg_rx, index,
1145f9e124fbSChristian Lamparter frames);
11461edfb1afSJohannes Berg }
11471edfb1afSJohannes Berg }
11481edfb1afSJohannes Berg
11491edfb1afSJohannes Berg /*
11501edfb1afSJohannes Berg * Timeout (in jiffies) for skb's that are waiting in the RX reorder buffer. If
11511edfb1afSJohannes Berg * the skb was added to the buffer longer than this time ago, the earlier
11521edfb1afSJohannes Berg * frames that have not yet been received are assumed to be lost and the skb
11531edfb1afSJohannes Berg * can be released for processing. This may also release other skb's from the
11541edfb1afSJohannes Berg * reorder buffer if there are no additional gaps between the frames.
11552bff8ebfSChristian Lamparter *
11562bff8ebfSChristian Lamparter * Callers must hold tid_agg_rx->reorder_lock.
11571edfb1afSJohannes Berg */
11581edfb1afSJohannes Berg #define HT_RX_REORDER_BUF_TIMEOUT (HZ / 10)
11591edfb1afSJohannes Berg
ieee80211_sta_reorder_release(struct ieee80211_sub_if_data * sdata,struct tid_ampdu_rx * tid_agg_rx,struct sk_buff_head * frames)1160d3b2fb53SJohannes Berg static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata,
1161f9e124fbSChristian Lamparter struct tid_ampdu_rx *tid_agg_rx,
1162f9e124fbSChristian Lamparter struct sk_buff_head *frames)
1163aa0c8636SChristian Lamparter {
116483eb935eSMichal Kazior int index, i, j;
1165aa0c8636SChristian Lamparter
1166dd318575SJohannes Berg lockdep_assert_held(&tid_agg_rx->reorder_lock);
1167dd318575SJohannes Berg
1168aa0c8636SChristian Lamparter /* release the buffer until next missing frame */
11692e3049b7SKarl Beldan index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size;
1170fb4ea054SJohannes Berg if (!ieee80211_rx_reorder_ready(tid_agg_rx, index) &&
117107ae2dfcSEliad Peller tid_agg_rx->stored_mpdu_num) {
1172aa0c8636SChristian Lamparter /*
1173aa0c8636SChristian Lamparter * No buffers ready to be released, but check whether any
1174aa0c8636SChristian Lamparter * frames in the reorder buffer have timed out.
1175aa0c8636SChristian Lamparter */
1176aa0c8636SChristian Lamparter int skipped = 1;
1177aa0c8636SChristian Lamparter for (j = (index + 1) % tid_agg_rx->buf_size; j != index;
1178aa0c8636SChristian Lamparter j = (j + 1) % tid_agg_rx->buf_size) {
1179fb4ea054SJohannes Berg if (!ieee80211_rx_reorder_ready(tid_agg_rx, j)) {
1180aa0c8636SChristian Lamparter skipped++;
1181aa0c8636SChristian Lamparter continue;
1182aa0c8636SChristian Lamparter }
1183499fe9a4SDaniel Halperin if (skipped &&
1184499fe9a4SDaniel Halperin !time_after(jiffies, tid_agg_rx->reorder_time[j] +
1185aa0c8636SChristian Lamparter HT_RX_REORDER_BUF_TIMEOUT))
11862bff8ebfSChristian Lamparter goto set_release_timer;
1187aa0c8636SChristian Lamparter
118883eb935eSMichal Kazior /* don't leave incomplete A-MSDUs around */
118983eb935eSMichal Kazior for (i = (index + 1) % tid_agg_rx->buf_size; i != j;
119083eb935eSMichal Kazior i = (i + 1) % tid_agg_rx->buf_size)
119183eb935eSMichal Kazior __skb_queue_purge(&tid_agg_rx->reorder_buf[i]);
119283eb935eSMichal Kazior
1193bdcbd8e0SJohannes Berg ht_dbg_ratelimited(sdata,
11940fb9a9ecSJoe Perches "release an RX reorder frame due to timeout on earlier frames\n");
1195f9e124fbSChristian Lamparter ieee80211_release_reorder_frame(sdata, tid_agg_rx, j,
1196f9e124fbSChristian Lamparter frames);
1197aa0c8636SChristian Lamparter
1198aa0c8636SChristian Lamparter /*
1199aa0c8636SChristian Lamparter * Increment the head seq# also for the skipped slots.
1200aa0c8636SChristian Lamparter */
1201aa0c8636SChristian Lamparter tid_agg_rx->head_seq_num =
12029a886586SJohannes Berg (tid_agg_rx->head_seq_num +
12039a886586SJohannes Berg skipped) & IEEE80211_SN_MASK;
1204aa0c8636SChristian Lamparter skipped = 0;
1205aa0c8636SChristian Lamparter }
1206fb4ea054SJohannes Berg } else while (ieee80211_rx_reorder_ready(tid_agg_rx, index)) {
1207f9e124fbSChristian Lamparter ieee80211_release_reorder_frame(sdata, tid_agg_rx, index,
1208f9e124fbSChristian Lamparter frames);
12092e3049b7SKarl Beldan index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size;
1210aa0c8636SChristian Lamparter }
12112bff8ebfSChristian Lamparter
12122bff8ebfSChristian Lamparter if (tid_agg_rx->stored_mpdu_num) {
12132e3049b7SKarl Beldan j = index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size;
12142bff8ebfSChristian Lamparter
12152bff8ebfSChristian Lamparter for (; j != (index - 1) % tid_agg_rx->buf_size;
12162bff8ebfSChristian Lamparter j = (j + 1) % tid_agg_rx->buf_size) {
1217fb4ea054SJohannes Berg if (ieee80211_rx_reorder_ready(tid_agg_rx, j))
12182bff8ebfSChristian Lamparter break;
12192bff8ebfSChristian Lamparter }
12202bff8ebfSChristian Lamparter
12212bff8ebfSChristian Lamparter set_release_timer:
12222bff8ebfSChristian Lamparter
1223788211d8SJohannes Berg if (!tid_agg_rx->removed)
12242bff8ebfSChristian Lamparter mod_timer(&tid_agg_rx->reorder_timer,
1225334df731SChristian Lamparter tid_agg_rx->reorder_time[j] + 1 +
12262bff8ebfSChristian Lamparter HT_RX_REORDER_BUF_TIMEOUT);
12272bff8ebfSChristian Lamparter } else {
12282bff8ebfSChristian Lamparter del_timer(&tid_agg_rx->reorder_timer);
12292bff8ebfSChristian Lamparter }
1230aa0c8636SChristian Lamparter }
1231aa0c8636SChristian Lamparter
12321edfb1afSJohannes Berg /*
12331edfb1afSJohannes Berg * As this function belongs to the RX path it must be under
12341edfb1afSJohannes Berg * rcu_read_lock protection. It returns false if the frame
12351edfb1afSJohannes Berg * can be processed immediately, true if it was consumed.
12361edfb1afSJohannes Berg */
ieee80211_sta_manage_reorder_buf(struct ieee80211_sub_if_data * sdata,struct tid_ampdu_rx * tid_agg_rx,struct sk_buff * skb,struct sk_buff_head * frames)1237d3b2fb53SJohannes Berg static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_sub_if_data *sdata,
12381edfb1afSJohannes Berg struct tid_ampdu_rx *tid_agg_rx,
1239f9e124fbSChristian Lamparter struct sk_buff *skb,
1240f9e124fbSChristian Lamparter struct sk_buff_head *frames)
12411edfb1afSJohannes Berg {
12421edfb1afSJohannes Berg struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
124383eb935eSMichal Kazior struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
12441edfb1afSJohannes Berg u16 sc = le16_to_cpu(hdr->seq_ctrl);
12451edfb1afSJohannes Berg u16 mpdu_seq_num = (sc & IEEE80211_SCTL_SEQ) >> 4;
12461edfb1afSJohannes Berg u16 head_seq_num, buf_size;
12471edfb1afSJohannes Berg int index;
12482bff8ebfSChristian Lamparter bool ret = true;
12491edfb1afSJohannes Berg
1250dd318575SJohannes Berg spin_lock(&tid_agg_rx->reorder_lock);
1251dd318575SJohannes Berg
12524549cf2bSMichal Kazior /*
12534549cf2bSMichal Kazior * Offloaded BA sessions have no known starting sequence number so pick
12544549cf2bSMichal Kazior * one from first Rxed frame for this tid after BA was started.
12554549cf2bSMichal Kazior */
12564549cf2bSMichal Kazior if (unlikely(tid_agg_rx->auto_seq)) {
12574549cf2bSMichal Kazior tid_agg_rx->auto_seq = false;
12584549cf2bSMichal Kazior tid_agg_rx->ssn = mpdu_seq_num;
12594549cf2bSMichal Kazior tid_agg_rx->head_seq_num = mpdu_seq_num;
12604549cf2bSMichal Kazior }
12614549cf2bSMichal Kazior
12621edfb1afSJohannes Berg buf_size = tid_agg_rx->buf_size;
12631edfb1afSJohannes Berg head_seq_num = tid_agg_rx->head_seq_num;
12641edfb1afSJohannes Berg
1265b7540d8fSSara Sharon /*
1266b7540d8fSSara Sharon * If the current MPDU's SN is smaller than the SSN, it shouldn't
1267b7540d8fSSara Sharon * be reordered.
1268b7540d8fSSara Sharon */
1269b7540d8fSSara Sharon if (unlikely(!tid_agg_rx->started)) {
1270b7540d8fSSara Sharon if (ieee80211_sn_less(mpdu_seq_num, head_seq_num)) {
1271b7540d8fSSara Sharon ret = false;
1272b7540d8fSSara Sharon goto out;
1273b7540d8fSSara Sharon }
1274b7540d8fSSara Sharon tid_agg_rx->started = true;
1275b7540d8fSSara Sharon }
1276b7540d8fSSara Sharon
12771edfb1afSJohannes Berg /* frame with out of date sequence number */
12789a886586SJohannes Berg if (ieee80211_sn_less(mpdu_seq_num, head_seq_num)) {
12791edfb1afSJohannes Berg dev_kfree_skb(skb);
12802bff8ebfSChristian Lamparter goto out;
12811edfb1afSJohannes Berg }
12821edfb1afSJohannes Berg
12831edfb1afSJohannes Berg /*
12841edfb1afSJohannes Berg * If frame the sequence number exceeds our buffering window
12851edfb1afSJohannes Berg * size release some previous frames to make room for this one.
12861edfb1afSJohannes Berg */
12879a886586SJohannes Berg if (!ieee80211_sn_less(mpdu_seq_num, head_seq_num + buf_size)) {
12889a886586SJohannes Berg head_seq_num = ieee80211_sn_inc(
12899a886586SJohannes Berg ieee80211_sn_sub(mpdu_seq_num, buf_size));
12901edfb1afSJohannes Berg /* release stored frames up to new head to stack */
1291d3b2fb53SJohannes Berg ieee80211_release_reorder_frames(sdata, tid_agg_rx,
1292f9e124fbSChristian Lamparter head_seq_num, frames);
12931edfb1afSJohannes Berg }
12941edfb1afSJohannes Berg
12951edfb1afSJohannes Berg /* Now the new frame is always in the range of the reordering buffer */
12961edfb1afSJohannes Berg
12972e3049b7SKarl Beldan index = mpdu_seq_num % tid_agg_rx->buf_size;
12981edfb1afSJohannes Berg
12991edfb1afSJohannes Berg /* check if we already stored this frame */
1300fb4ea054SJohannes Berg if (ieee80211_rx_reorder_ready(tid_agg_rx, index)) {
13011edfb1afSJohannes Berg dev_kfree_skb(skb);
13022bff8ebfSChristian Lamparter goto out;
13031edfb1afSJohannes Berg }
13041edfb1afSJohannes Berg
13051edfb1afSJohannes Berg /*
13061edfb1afSJohannes Berg * If the current MPDU is in the right order and nothing else
13071edfb1afSJohannes Berg * is stored we can process it directly, no need to buffer it.
1308c835b214SJohannes Berg * If it is first but there's something stored, we may be able
1309c835b214SJohannes Berg * to release frames after this one.
13101edfb1afSJohannes Berg */
13111edfb1afSJohannes Berg if (mpdu_seq_num == tid_agg_rx->head_seq_num &&
13121edfb1afSJohannes Berg tid_agg_rx->stored_mpdu_num == 0) {
131383eb935eSMichal Kazior if (!(status->flag & RX_FLAG_AMSDU_MORE))
13149a886586SJohannes Berg tid_agg_rx->head_seq_num =
13159a886586SJohannes Berg ieee80211_sn_inc(tid_agg_rx->head_seq_num);
13162bff8ebfSChristian Lamparter ret = false;
13172bff8ebfSChristian Lamparter goto out;
13181edfb1afSJohannes Berg }
13191edfb1afSJohannes Berg
13201edfb1afSJohannes Berg /* put the frame in the reordering buffer */
132183eb935eSMichal Kazior __skb_queue_tail(&tid_agg_rx->reorder_buf[index], skb);
132283eb935eSMichal Kazior if (!(status->flag & RX_FLAG_AMSDU_MORE)) {
13231edfb1afSJohannes Berg tid_agg_rx->reorder_time[index] = jiffies;
13241edfb1afSJohannes Berg tid_agg_rx->stored_mpdu_num++;
1325f9e124fbSChristian Lamparter ieee80211_sta_reorder_release(sdata, tid_agg_rx, frames);
132683eb935eSMichal Kazior }
13271edfb1afSJohannes Berg
13282bff8ebfSChristian Lamparter out:
13292bff8ebfSChristian Lamparter spin_unlock(&tid_agg_rx->reorder_lock);
13302bff8ebfSChristian Lamparter return ret;
13311edfb1afSJohannes Berg }
13321edfb1afSJohannes Berg
13331edfb1afSJohannes Berg /*
13341edfb1afSJohannes Berg * Reorder MPDUs from A-MPDUs, keeping them on a buffer. Returns
13351edfb1afSJohannes Berg * true if the MPDU was buffered, false if it should be processed.
13361edfb1afSJohannes Berg */
ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data * rx,struct sk_buff_head * frames)1337f9e124fbSChristian Lamparter static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx,
1338f9e124fbSChristian Lamparter struct sk_buff_head *frames)
13391edfb1afSJohannes Berg {
13402569a826SJohannes Berg struct sk_buff *skb = rx->skb;
13411edfb1afSJohannes Berg struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
13422569a826SJohannes Berg struct sta_info *sta = rx->sta;
13431edfb1afSJohannes Berg struct tid_ampdu_rx *tid_agg_rx;
13441edfb1afSJohannes Berg u16 sc;
13456cc00d54SThomas Pedersen u8 tid, ack_policy;
13461edfb1afSJohannes Berg
1347051a41faSJohannes Berg if (!ieee80211_is_data_qos(hdr->frame_control) ||
1348051a41faSJohannes Berg is_multicast_ether_addr(hdr->addr1))
13492569a826SJohannes Berg goto dont_reorder;
13501edfb1afSJohannes Berg
13511edfb1afSJohannes Berg /*
13521edfb1afSJohannes Berg * filter the QoS data rx stream according to
13531edfb1afSJohannes Berg * STA/TID and check if this STA/TID is on aggregation
13541edfb1afSJohannes Berg */
13551edfb1afSJohannes Berg
13561edfb1afSJohannes Berg if (!sta)
13572569a826SJohannes Berg goto dont_reorder;
13581edfb1afSJohannes Berg
13596cc00d54SThomas Pedersen ack_policy = *ieee80211_get_qos_ctl(hdr) &
13606cc00d54SThomas Pedersen IEEE80211_QOS_CTL_ACK_POLICY_MASK;
1361a1f2ba04SSara Sharon tid = ieee80211_get_tid(hdr);
13621edfb1afSJohannes Berg
1363a87f736dSJohannes Berg tid_agg_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[tid]);
1364bfe40fa3SJohannes Berg if (!tid_agg_rx) {
1365bfe40fa3SJohannes Berg if (ack_policy == IEEE80211_QOS_CTL_ACK_POLICY_BLOCKACK &&
1366bfe40fa3SJohannes Berg !test_bit(tid, rx->sta->ampdu_mlme.agg_session_valid) &&
1367bfe40fa3SJohannes Berg !test_and_set_bit(tid, rx->sta->ampdu_mlme.unexpected_agg))
1368bfe40fa3SJohannes Berg ieee80211_send_delba(rx->sdata, rx->sta->sta.addr, tid,
1369bfe40fa3SJohannes Berg WLAN_BACK_RECIPIENT,
1370bfe40fa3SJohannes Berg WLAN_REASON_QSTA_REQUIRE_SETUP);
1371a87f736dSJohannes Berg goto dont_reorder;
1372bfe40fa3SJohannes Berg }
13731edfb1afSJohannes Berg
13741edfb1afSJohannes Berg /* qos null data frames are excluded */
13751edfb1afSJohannes Berg if (unlikely(hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_NULLFUNC)))
1376a87f736dSJohannes Berg goto dont_reorder;
13771edfb1afSJohannes Berg
13786cc00d54SThomas Pedersen /* not part of a BA session */
13795e469ed9SFelix Fietkau if (ack_policy == IEEE80211_QOS_CTL_ACK_POLICY_NOACK)
13806cc00d54SThomas Pedersen goto dont_reorder;
13816cc00d54SThomas Pedersen
13821edfb1afSJohannes Berg /* new, potentially un-ordered, ampdu frame - process it */
13831edfb1afSJohannes Berg
13841edfb1afSJohannes Berg /* reset session timer */
13851edfb1afSJohannes Berg if (tid_agg_rx->timeout)
138612d3952fSFelix Fietkau tid_agg_rx->last_rx = jiffies;
13871edfb1afSJohannes Berg
13881edfb1afSJohannes Berg /* if this mpdu is fragmented - terminate rx aggregation session */
13891edfb1afSJohannes Berg sc = le16_to_cpu(hdr->seq_ctrl);
13901edfb1afSJohannes Berg if (sc & IEEE80211_SCTL_FRAG) {
13914f6c78deSJohannes Berg ieee80211_queue_skb_to_iface(rx->sdata, rx->link_id, NULL, skb);
13922569a826SJohannes Berg return;
13931edfb1afSJohannes Berg }
13941edfb1afSJohannes Berg
1395a87f736dSJohannes Berg /*
1396a87f736dSJohannes Berg * No locking needed -- we will only ever process one
1397a87f736dSJohannes Berg * RX packet at a time, and thus own tid_agg_rx. All
1398a87f736dSJohannes Berg * other code manipulating it needs to (and does) make
1399a87f736dSJohannes Berg * sure that we cannot get to it any more before doing
1400a87f736dSJohannes Berg * anything with it.
1401a87f736dSJohannes Berg */
1402f9e124fbSChristian Lamparter if (ieee80211_sta_manage_reorder_buf(rx->sdata, tid_agg_rx, skb,
1403f9e124fbSChristian Lamparter frames))
14042569a826SJohannes Berg return;
14052569a826SJohannes Berg
14062569a826SJohannes Berg dont_reorder:
1407f9e124fbSChristian Lamparter __skb_queue_tail(frames, skb);
14081edfb1afSJohannes Berg }
140933b64eb2SLuis Carlos Cobo
141049461622SJohannes Berg static ieee80211_rx_result debug_noinline
ieee80211_rx_h_check_dup(struct ieee80211_rx_data * rx)14110395442aSJohannes Berg ieee80211_rx_h_check_dup(struct ieee80211_rx_data *rx)
1412571ecf67SJohannes Berg {
1413a7767f95SHarvey Harrison struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
1414554891e6SJohannes Berg struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
1415571ecf67SJohannes Berg
1416f9cfa5f3SSara Sharon if (status->flag & RX_FLAG_DUP_VALIDATED)
1417f9cfa5f3SSara Sharon return RX_CONTINUE;
1418f9cfa5f3SSara Sharon
14196b0f3274SJohannes Berg /*
14206b0f3274SJohannes Berg * Drop duplicate 802.11 retransmissions
14216b0f3274SJohannes Berg * (IEEE 802.11-2012: 9.3.2.10 "Duplicate detection and recovery")
14226b0f3274SJohannes Berg */
14230395442aSJohannes Berg
14240395442aSJohannes Berg if (rx->skb->len < 24)
14250395442aSJohannes Berg return RX_CONTINUE;
14260395442aSJohannes Berg
14270395442aSJohannes Berg if (ieee80211_is_ctl(hdr->frame_control) ||
142830b2f0beSThomas Pedersen ieee80211_is_any_nullfunc(hdr->frame_control) ||
14290395442aSJohannes Berg is_multicast_ether_addr(hdr->addr1))
14300395442aSJohannes Berg return RX_CONTINUE;
14310395442aSJohannes Berg
1432a732fa70SJohannes Berg if (!rx->sta)
1433a732fa70SJohannes Berg return RX_CONTINUE;
1434a732fa70SJohannes Berg
1435a7767f95SHarvey Harrison if (unlikely(ieee80211_has_retry(hdr->frame_control) &&
1436a732fa70SJohannes Berg rx->sta->last_seq_ctrl[rx->seqno_idx] == hdr->seq_ctrl)) {
1437c206ca67SJohannes Berg I802_DEBUG_INC(rx->local->dot11FrameDuplicateCount);
1438b320d6c4SBenjamin Berg rx->link_sta->rx_stats.num_duplicates++;
1439b1f93314SFelix Fietkau return RX_DROP_UNUSABLE;
14400cfcefefSMichal Kazior } else if (!(status->flag & RX_FLAG_AMSDU_MORE)) {
14419e26297aSJohannes Berg rx->sta->last_seq_ctrl[rx->seqno_idx] = hdr->seq_ctrl;
1442571ecf67SJohannes Berg }
1443571ecf67SJohannes Berg
14440395442aSJohannes Berg return RX_CONTINUE;
14450395442aSJohannes Berg }
14460395442aSJohannes Berg
14470395442aSJohannes Berg static ieee80211_rx_result debug_noinline
ieee80211_rx_h_check(struct ieee80211_rx_data * rx)14480395442aSJohannes Berg ieee80211_rx_h_check(struct ieee80211_rx_data *rx)
14490395442aSJohannes Berg {
14500395442aSJohannes Berg struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
14510395442aSJohannes Berg
1452571ecf67SJohannes Berg /* Drop disallowed frame classes based on STA auth/assoc state;
1453571ecf67SJohannes Berg * IEEE 802.11, Chap 5.5.
1454571ecf67SJohannes Berg *
1455ccd7b362SJohannes Berg * mac80211 filters only based on association state, i.e. it drops
1456ccd7b362SJohannes Berg * Class 3 frames from not associated stations. hostapd sends
1457571ecf67SJohannes Berg * deauth/disassoc frames when needed. In addition, hostapd is
1458571ecf67SJohannes Berg * responsible for filtering on both auth and assoc states.
1459571ecf67SJohannes Berg */
146033b64eb2SLuis Carlos Cobo
1461902acc78SJohannes Berg if (ieee80211_vif_is_mesh(&rx->sdata->vif))
146233b64eb2SLuis Carlos Cobo return ieee80211_rx_mesh_check(rx);
146333b64eb2SLuis Carlos Cobo
1464a7767f95SHarvey Harrison if (unlikely((ieee80211_is_data(hdr->frame_control) ||
1465a7767f95SHarvey Harrison ieee80211_is_pspoll(hdr->frame_control)) &&
146605c914feSJohannes Berg rx->sdata->vif.type != NL80211_IFTYPE_ADHOC &&
1467239281f8SRostislav Lisovy rx->sdata->vif.type != NL80211_IFTYPE_OCB &&
1468c2c98fdeSJohannes Berg (!rx->sta || !test_sta_flag(rx->sta, WLAN_STA_ASSOC)))) {
14697852e361SJohannes Berg /*
14707852e361SJohannes Berg * accept port control frames from the AP even when it's not
14717852e361SJohannes Berg * yet marked ASSOC to prevent a race where we don't set the
14727852e361SJohannes Berg * assoc bit quickly enough before it sends the first frame
14737852e361SJohannes Berg */
14747852e361SJohannes Berg if (rx->sta && rx->sdata->vif.type == NL80211_IFTYPE_STATION &&
14752a33bee2SGuy Eilam ieee80211_is_data_present(hdr->frame_control)) {
14766dbda2d0SJohannes Berg unsigned int hdrlen;
14776dbda2d0SJohannes Berg __be16 ethertype;
14782a33bee2SGuy Eilam
14796dbda2d0SJohannes Berg hdrlen = ieee80211_hdrlen(hdr->frame_control);
14806dbda2d0SJohannes Berg
14816dbda2d0SJohannes Berg if (rx->skb->len < hdrlen + 8)
14826dbda2d0SJohannes Berg return RX_DROP_MONITOR;
14836dbda2d0SJohannes Berg
14846dbda2d0SJohannes Berg skb_copy_bits(rx->skb, hdrlen + 6, ðertype, 2);
14856dbda2d0SJohannes Berg if (ethertype == rx->sdata->control_port_protocol)
14862a33bee2SGuy Eilam return RX_CONTINUE;
14872a33bee2SGuy Eilam }
148821fc7560SJohannes Berg
148921fc7560SJohannes Berg if (rx->sdata->vif.type == NL80211_IFTYPE_AP &&
149021fc7560SJohannes Berg cfg80211_rx_spurious_frame(rx->sdata->dev,
149121fc7560SJohannes Berg hdr->addr2,
149221fc7560SJohannes Berg GFP_ATOMIC))
149321fc7560SJohannes Berg return RX_DROP_UNUSABLE;
149421fc7560SJohannes Berg
1495e4c26addSJohannes Berg return RX_DROP_MONITOR;
14962a33bee2SGuy Eilam }
1497571ecf67SJohannes Berg
14989ae54c84SJohannes Berg return RX_CONTINUE;
1499570bd537SJohannes Berg }
1500570bd537SJohannes Berg
1501570bd537SJohannes Berg
150249461622SJohannes Berg static ieee80211_rx_result debug_noinline
ieee80211_rx_h_check_more_data(struct ieee80211_rx_data * rx)1503572e0012SKalle Valo ieee80211_rx_h_check_more_data(struct ieee80211_rx_data *rx)
1504572e0012SKalle Valo {
1505572e0012SKalle Valo struct ieee80211_local *local;
1506572e0012SKalle Valo struct ieee80211_hdr *hdr;
1507572e0012SKalle Valo struct sk_buff *skb;
1508572e0012SKalle Valo
1509572e0012SKalle Valo local = rx->local;
1510572e0012SKalle Valo skb = rx->skb;
1511572e0012SKalle Valo hdr = (struct ieee80211_hdr *) skb->data;
1512572e0012SKalle Valo
1513572e0012SKalle Valo if (!local->pspolling)
1514572e0012SKalle Valo return RX_CONTINUE;
1515572e0012SKalle Valo
1516572e0012SKalle Valo if (!ieee80211_has_fromds(hdr->frame_control))
1517572e0012SKalle Valo /* this is not from AP */
1518572e0012SKalle Valo return RX_CONTINUE;
1519572e0012SKalle Valo
1520572e0012SKalle Valo if (!ieee80211_is_data(hdr->frame_control))
1521572e0012SKalle Valo return RX_CONTINUE;
1522572e0012SKalle Valo
1523572e0012SKalle Valo if (!ieee80211_has_moredata(hdr->frame_control)) {
1524572e0012SKalle Valo /* AP has no more frames buffered for us */
1525572e0012SKalle Valo local->pspolling = false;
1526572e0012SKalle Valo return RX_CONTINUE;
1527572e0012SKalle Valo }
1528572e0012SKalle Valo
1529572e0012SKalle Valo /* more data bit is set, let's request a new frame from the AP */
1530572e0012SKalle Valo ieee80211_send_pspoll(local, rx->sdata);
1531572e0012SKalle Valo
1532572e0012SKalle Valo return RX_CONTINUE;
1533572e0012SKalle Valo }
1534572e0012SKalle Valo
sta_ps_start(struct sta_info * sta)1535d012a605SMarco Porsch static void sta_ps_start(struct sta_info *sta)
1536571ecf67SJohannes Berg {
1537133b8226SJohannes Berg struct ieee80211_sub_if_data *sdata = sta->sdata;
15384571d3bfSChristian Lamparter struct ieee80211_local *local = sdata->local;
1539d012a605SMarco Porsch struct ps_data *ps;
1540ba8c3d6fSFelix Fietkau int tid;
15410795af57SJoe Perches
1542d012a605SMarco Porsch if (sta->sdata->vif.type == NL80211_IFTYPE_AP ||
1543d012a605SMarco Porsch sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
1544d012a605SMarco Porsch ps = &sdata->bss->ps;
1545d012a605SMarco Porsch else
1546d012a605SMarco Porsch return;
1547d012a605SMarco Porsch
1548d012a605SMarco Porsch atomic_inc(&ps->num_sta_ps);
1549c2c98fdeSJohannes Berg set_sta_flag(sta, WLAN_STA_PS_STA);
155030686bf7SJohannes Berg if (!ieee80211_hw_check(&local->hw, AP_LINK_PS))
155112375ef9SJohannes Berg drv_sta_notify(local, sdata, STA_NOTIFY_SLEEP, &sta->sta);
1552bdcbd8e0SJohannes Berg ps_dbg(sdata, "STA %pM aid %d enters power save mode\n",
1553bdcbd8e0SJohannes Berg sta->sta.addr, sta->sta.aid);
1554ba8c3d6fSFelix Fietkau
155517c18bf8SJohannes Berg ieee80211_clear_fast_xmit(sta);
155617c18bf8SJohannes Berg
1557adf8ed01SJohannes Berg for (tid = 0; tid < IEEE80211_NUM_TIDS; tid++) {
1558b49c15e1SFelix Fietkau struct ieee80211_txq *txq = sta->sta.txq[tid];
1559942741daSFelix Fietkau struct txq_info *txqi = to_txq_info(txq);
1560b49c15e1SFelix Fietkau
1561942741daSFelix Fietkau spin_lock(&local->active_txq_lock[txq->ac]);
1562942741daSFelix Fietkau if (!list_empty(&txqi->schedule_order))
1563942741daSFelix Fietkau list_del_init(&txqi->schedule_order);
1564942741daSFelix Fietkau spin_unlock(&local->active_txq_lock[txq->ac]);
1565b49c15e1SFelix Fietkau
1566b49c15e1SFelix Fietkau if (txq_has_queue(txq))
1567ba8c3d6fSFelix Fietkau set_bit(tid, &sta->txq_buffered_tids);
1568ba8c3d6fSFelix Fietkau else
1569ba8c3d6fSFelix Fietkau clear_bit(tid, &sta->txq_buffered_tids);
1570ba8c3d6fSFelix Fietkau }
1571571ecf67SJohannes Berg }
1572571ecf67SJohannes Berg
sta_ps_end(struct sta_info * sta)1573d012a605SMarco Porsch static void sta_ps_end(struct sta_info *sta)
1574571ecf67SJohannes Berg {
1575bdcbd8e0SJohannes Berg ps_dbg(sta->sdata, "STA %pM aid %d exits power save mode\n",
1576bdcbd8e0SJohannes Berg sta->sta.addr, sta->sta.aid);
1577004c872eSJohannes Berg
1578c2c98fdeSJohannes Berg if (test_sta_flag(sta, WLAN_STA_PS_DRIVER)) {
1579e3685e03SJohannes Berg /*
1580e3685e03SJohannes Berg * Clear the flag only if the other one is still set
1581e3685e03SJohannes Berg * so that the TX path won't start TX'ing new frames
1582e3685e03SJohannes Berg * directly ... In the case that the driver flag isn't
1583e3685e03SJohannes Berg * set ieee80211_sta_ps_deliver_wakeup() will clear it.
1584e3685e03SJohannes Berg */
1585e3685e03SJohannes Berg clear_sta_flag(sta, WLAN_STA_PS_STA);
1586bdcbd8e0SJohannes Berg ps_dbg(sta->sdata, "STA %pM aid %d driver-ps-blocked\n",
1587bdcbd8e0SJohannes Berg sta->sta.addr, sta->sta.aid);
1588af818581SJohannes Berg return;
1589af818581SJohannes Berg }
1590af818581SJohannes Berg
15915ac2e350SJohannes Berg set_sta_flag(sta, WLAN_STA_PS_DELIVER);
15925ac2e350SJohannes Berg clear_sta_flag(sta, WLAN_STA_PS_STA);
1593af818581SJohannes Berg ieee80211_sta_ps_deliver_wakeup(sta);
1594571ecf67SJohannes Berg }
1595571ecf67SJohannes Berg
ieee80211_sta_ps_transition(struct ieee80211_sta * pubsta,bool start)1596cf47161aSJohannes Berg int ieee80211_sta_ps_transition(struct ieee80211_sta *pubsta, bool start)
1597d057e5a3SArik Nemtsov {
1598cf47161aSJohannes Berg struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
1599d057e5a3SArik Nemtsov bool in_ps;
1600d057e5a3SArik Nemtsov
1601cf47161aSJohannes Berg WARN_ON(!ieee80211_hw_check(&sta->local->hw, AP_LINK_PS));
1602d057e5a3SArik Nemtsov
1603d057e5a3SArik Nemtsov /* Don't let the same PS state be set twice */
1604cf47161aSJohannes Berg in_ps = test_sta_flag(sta, WLAN_STA_PS_STA);
1605d057e5a3SArik Nemtsov if ((start && in_ps) || (!start && !in_ps))
1606d057e5a3SArik Nemtsov return -EINVAL;
1607d057e5a3SArik Nemtsov
1608d057e5a3SArik Nemtsov if (start)
1609cf47161aSJohannes Berg sta_ps_start(sta);
1610d057e5a3SArik Nemtsov else
1611cf47161aSJohannes Berg sta_ps_end(sta);
1612d057e5a3SArik Nemtsov
1613d057e5a3SArik Nemtsov return 0;
1614d057e5a3SArik Nemtsov }
1615d057e5a3SArik Nemtsov EXPORT_SYMBOL(ieee80211_sta_ps_transition);
1616d057e5a3SArik Nemtsov
ieee80211_sta_pspoll(struct ieee80211_sta * pubsta)161746fa38e8SJohannes Berg void ieee80211_sta_pspoll(struct ieee80211_sta *pubsta)
161846fa38e8SJohannes Berg {
161946fa38e8SJohannes Berg struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
162046fa38e8SJohannes Berg
162146fa38e8SJohannes Berg if (test_sta_flag(sta, WLAN_STA_SP))
162246fa38e8SJohannes Berg return;
162346fa38e8SJohannes Berg
162446fa38e8SJohannes Berg if (!test_sta_flag(sta, WLAN_STA_PS_DRIVER))
162546fa38e8SJohannes Berg ieee80211_sta_ps_deliver_poll_response(sta);
162646fa38e8SJohannes Berg else
162746fa38e8SJohannes Berg set_sta_flag(sta, WLAN_STA_PSPOLL);
162846fa38e8SJohannes Berg }
162946fa38e8SJohannes Berg EXPORT_SYMBOL(ieee80211_sta_pspoll);
163046fa38e8SJohannes Berg
ieee80211_sta_uapsd_trigger(struct ieee80211_sta * pubsta,u8 tid)163146fa38e8SJohannes Berg void ieee80211_sta_uapsd_trigger(struct ieee80211_sta *pubsta, u8 tid)
163246fa38e8SJohannes Berg {
163346fa38e8SJohannes Berg struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
1634731977e9SAmadeusz Sławiński int ac = ieee80211_ac_from_tid(tid);
163546fa38e8SJohannes Berg
163646fa38e8SJohannes Berg /*
16370aa419ecSEmmanuel Grumbach * If this AC is not trigger-enabled do nothing unless the
16380aa419ecSEmmanuel Grumbach * driver is calling us after it already checked.
163946fa38e8SJohannes Berg *
164046fa38e8SJohannes Berg * NB: This could/should check a separate bitmap of trigger-
164146fa38e8SJohannes Berg * enabled queues, but for now we only implement uAPSD w/o
164246fa38e8SJohannes Berg * TSPEC changes to the ACs, so they're always the same.
164346fa38e8SJohannes Berg */
1644f438ceb8SEmmanuel Grumbach if (!(sta->sta.uapsd_queues & ieee80211_ac_to_qos_mask[ac]) &&
1645f438ceb8SEmmanuel Grumbach tid != IEEE80211_NUM_TIDS)
164646fa38e8SJohannes Berg return;
164746fa38e8SJohannes Berg
164846fa38e8SJohannes Berg /* if we are in a service period, do nothing */
164946fa38e8SJohannes Berg if (test_sta_flag(sta, WLAN_STA_SP))
165046fa38e8SJohannes Berg return;
165146fa38e8SJohannes Berg
165246fa38e8SJohannes Berg if (!test_sta_flag(sta, WLAN_STA_PS_DRIVER))
165346fa38e8SJohannes Berg ieee80211_sta_ps_deliver_uapsd(sta);
165446fa38e8SJohannes Berg else
165546fa38e8SJohannes Berg set_sta_flag(sta, WLAN_STA_UAPSD);
165646fa38e8SJohannes Berg }
165746fa38e8SJohannes Berg EXPORT_SYMBOL(ieee80211_sta_uapsd_trigger);
165846fa38e8SJohannes Berg
165949461622SJohannes Berg static ieee80211_rx_result debug_noinline
ieee80211_rx_h_uapsd_and_pspoll(struct ieee80211_rx_data * rx)166047086fc5SJohannes Berg ieee80211_rx_h_uapsd_and_pspoll(struct ieee80211_rx_data *rx)
166147086fc5SJohannes Berg {
166247086fc5SJohannes Berg struct ieee80211_sub_if_data *sdata = rx->sdata;
166347086fc5SJohannes Berg struct ieee80211_hdr *hdr = (void *)rx->skb->data;
166447086fc5SJohannes Berg struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
166547086fc5SJohannes Berg
16665c90067cSJohannes Berg if (!rx->sta)
166747086fc5SJohannes Berg return RX_CONTINUE;
166847086fc5SJohannes Berg
166947086fc5SJohannes Berg if (sdata->vif.type != NL80211_IFTYPE_AP &&
167047086fc5SJohannes Berg sdata->vif.type != NL80211_IFTYPE_AP_VLAN)
167147086fc5SJohannes Berg return RX_CONTINUE;
167247086fc5SJohannes Berg
167347086fc5SJohannes Berg /*
167447086fc5SJohannes Berg * The device handles station powersave, so don't do anything about
167547086fc5SJohannes Berg * uAPSD and PS-Poll frames (the latter shouldn't even come up from
167647086fc5SJohannes Berg * it to mac80211 since they're handled.)
167747086fc5SJohannes Berg */
167830686bf7SJohannes Berg if (ieee80211_hw_check(&sdata->local->hw, AP_LINK_PS))
167947086fc5SJohannes Berg return RX_CONTINUE;
168047086fc5SJohannes Berg
168147086fc5SJohannes Berg /*
168247086fc5SJohannes Berg * Don't do anything if the station isn't already asleep. In
168347086fc5SJohannes Berg * the uAPSD case, the station will probably be marked asleep,
168447086fc5SJohannes Berg * in the PS-Poll case the station must be confused ...
168547086fc5SJohannes Berg */
1686c2c98fdeSJohannes Berg if (!test_sta_flag(rx->sta, WLAN_STA_PS_STA))
168747086fc5SJohannes Berg return RX_CONTINUE;
168847086fc5SJohannes Berg
168947086fc5SJohannes Berg if (unlikely(ieee80211_is_pspoll(hdr->frame_control))) {
169046fa38e8SJohannes Berg ieee80211_sta_pspoll(&rx->sta->sta);
169147086fc5SJohannes Berg
169247086fc5SJohannes Berg /* Free PS Poll skb here instead of returning RX_DROP that would
169347086fc5SJohannes Berg * count as an dropped frame. */
169447086fc5SJohannes Berg dev_kfree_skb(rx->skb);
169547086fc5SJohannes Berg
169647086fc5SJohannes Berg return RX_QUEUED;
169747086fc5SJohannes Berg } else if (!ieee80211_has_morefrags(hdr->frame_control) &&
169847086fc5SJohannes Berg !(status->rx_flags & IEEE80211_RX_DEFERRED_RELEASE) &&
169947086fc5SJohannes Berg ieee80211_has_pm(hdr->frame_control) &&
170047086fc5SJohannes Berg (ieee80211_is_data_qos(hdr->frame_control) ||
170147086fc5SJohannes Berg ieee80211_is_qos_nullfunc(hdr->frame_control))) {
1702a1f2ba04SSara Sharon u8 tid = ieee80211_get_tid(hdr);
170347086fc5SJohannes Berg
170446fa38e8SJohannes Berg ieee80211_sta_uapsd_trigger(&rx->sta->sta, tid);
170547086fc5SJohannes Berg }
170647086fc5SJohannes Berg
170747086fc5SJohannes Berg return RX_CONTINUE;
170847086fc5SJohannes Berg }
170947086fc5SJohannes Berg
171047086fc5SJohannes Berg static ieee80211_rx_result debug_noinline
ieee80211_rx_h_sta_process(struct ieee80211_rx_data * rx)17115cf121c3SJohannes Berg ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
1712571ecf67SJohannes Berg {
1713571ecf67SJohannes Berg struct sta_info *sta = rx->sta;
1714b320d6c4SBenjamin Berg struct link_sta_info *link_sta = rx->link_sta;
1715eb9fb5b8SJohannes Berg struct sk_buff *skb = rx->skb;
1716eb9fb5b8SJohannes Berg struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
1717eb9fb5b8SJohannes Berg struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
1718ef0621e8SFelix Fietkau int i;
1719571ecf67SJohannes Berg
1720b320d6c4SBenjamin Berg if (!sta || !link_sta)
17219ae54c84SJohannes Berg return RX_CONTINUE;
1722571ecf67SJohannes Berg
1723b291ba11SJohannes Berg /*
1724b291ba11SJohannes Berg * Update last_rx only for IBSS packets which are for the current
1725e584da5eSAntonio Quartulli * BSSID and for station already AUTHORIZED to avoid keeping the
1726e584da5eSAntonio Quartulli * current IBSS network alive in cases where other STAs start
1727e584da5eSAntonio Quartulli * using different BSSID. This will also give the station another
1728e584da5eSAntonio Quartulli * chance to restart the authentication/authorization in case
1729e584da5eSAntonio Quartulli * something went wrong the first time.
1730b291ba11SJohannes Berg */
173105c914feSJohannes Berg if (rx->sdata->vif.type == NL80211_IFTYPE_ADHOC) {
173271364716SRon Rindjunsky u8 *bssid = ieee80211_get_bssid(hdr, rx->skb->len,
173305c914feSJohannes Berg NL80211_IFTYPE_ADHOC);
1734e584da5eSAntonio Quartulli if (ether_addr_equal(bssid, rx->sdata->u.ibss.bssid) &&
1735e584da5eSAntonio Quartulli test_sta_flag(sta, WLAN_STA_AUTHORIZED)) {
1736b320d6c4SBenjamin Berg link_sta->rx_stats.last_rx = jiffies;
17370e966d9aSJohannes Berg if (ieee80211_is_data_present(hdr->frame_control) &&
17384f6b1b3dSJohannes Berg !is_multicast_ether_addr(hdr->addr1))
1739b320d6c4SBenjamin Berg link_sta->rx_stats.last_rate =
17404f6b1b3dSJohannes Berg sta_stats_encode_rate(status);
17413af6334cSFelix Fietkau }
1742239281f8SRostislav Lisovy } else if (rx->sdata->vif.type == NL80211_IFTYPE_OCB) {
1743b320d6c4SBenjamin Berg link_sta->rx_stats.last_rx = jiffies;
174409a740ceSThomas Pedersen } else if (!ieee80211_is_s1g_beacon(hdr->frame_control) &&
1745f879ac8eSWen Gong !is_multicast_ether_addr(hdr->addr1)) {
1746b291ba11SJohannes Berg /*
174733b64eb2SLuis Carlos Cobo * Mesh beacons will update last_rx when if they are found to
174833b64eb2SLuis Carlos Cobo * match the current local configuration when processed.
1749571ecf67SJohannes Berg */
1750b320d6c4SBenjamin Berg link_sta->rx_stats.last_rx = jiffies;
17510e966d9aSJohannes Berg if (ieee80211_is_data_present(hdr->frame_control))
1752b320d6c4SBenjamin Berg link_sta->rx_stats.last_rate = sta_stats_encode_rate(status);
1753571ecf67SJohannes Berg }
1754571ecf67SJohannes Berg
1755b320d6c4SBenjamin Berg link_sta->rx_stats.fragments++;
17560f9c5a61SJohannes Berg
1757b320d6c4SBenjamin Berg u64_stats_update_begin(&link_sta->rx_stats.syncp);
1758b320d6c4SBenjamin Berg link_sta->rx_stats.bytes += rx->skb->len;
1759b320d6c4SBenjamin Berg u64_stats_update_end(&link_sta->rx_stats.syncp);
17600f9c5a61SJohannes Berg
1761fe8431f8SFelix Fietkau if (!(status->flag & RX_FLAG_NO_SIGNAL_VAL)) {
1762b320d6c4SBenjamin Berg link_sta->rx_stats.last_signal = status->signal;
1763b320d6c4SBenjamin Berg ewma_signal_add(&link_sta->rx_stats_avg.signal,
1764046d2e7cSSriram R -status->signal);
1765fe8431f8SFelix Fietkau }
1766571ecf67SJohannes Berg
1767ef0621e8SFelix Fietkau if (status->chains) {
1768b320d6c4SBenjamin Berg link_sta->rx_stats.chains = status->chains;
1769ef0621e8SFelix Fietkau for (i = 0; i < ARRAY_SIZE(status->chain_signal); i++) {
1770ef0621e8SFelix Fietkau int signal = status->chain_signal[i];
1771ef0621e8SFelix Fietkau
1772ef0621e8SFelix Fietkau if (!(status->chains & BIT(i)))
1773ef0621e8SFelix Fietkau continue;
1774ef0621e8SFelix Fietkau
1775b320d6c4SBenjamin Berg link_sta->rx_stats.chain_signal_last[i] = signal;
1776b320d6c4SBenjamin Berg ewma_signal_add(&link_sta->rx_stats_avg.chain_signal[i],
1777e5a9f8d0SJohannes Berg -signal);
1778ef0621e8SFelix Fietkau }
1779ef0621e8SFelix Fietkau }
1780ef0621e8SFelix Fietkau
178109a740ceSThomas Pedersen if (ieee80211_is_s1g_beacon(hdr->frame_control))
178209a740ceSThomas Pedersen return RX_CONTINUE;
178309a740ceSThomas Pedersen
178472eaa43aSJohannes Berg /*
178572eaa43aSJohannes Berg * Change STA power saving mode only at the end of a frame
17869fef6544SEmmanuel Grumbach * exchange sequence, and only for a data or management
17879fef6544SEmmanuel Grumbach * frame as specified in IEEE 802.11-2016 11.2.3.2
178872eaa43aSJohannes Berg */
178930686bf7SJohannes Berg if (!ieee80211_hw_check(&sta->local->hw, AP_LINK_PS) &&
1790d057e5a3SArik Nemtsov !ieee80211_has_morefrags(hdr->frame_control) &&
179120932750SEmmanuel Grumbach !is_multicast_ether_addr(hdr->addr1) &&
17929fef6544SEmmanuel Grumbach (ieee80211_is_mgmt(hdr->frame_control) ||
17939fef6544SEmmanuel Grumbach ieee80211_is_data(hdr->frame_control)) &&
17944cfda47bSChristian Lamparter !(status->rx_flags & IEEE80211_RX_DEFERRED_RELEASE) &&
179505c914feSJohannes Berg (rx->sdata->vif.type == NL80211_IFTYPE_AP ||
17969fef6544SEmmanuel Grumbach rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)) {
1797b4ba544cSJohannes Berg if (test_sta_flag(sta, WLAN_STA_PS_STA)) {
1798b4ba544cSJohannes Berg if (!ieee80211_has_pm(hdr->frame_control))
1799d012a605SMarco Porsch sta_ps_end(sta);
180072eaa43aSJohannes Berg } else {
180172eaa43aSJohannes Berg if (ieee80211_has_pm(hdr->frame_control))
1802d012a605SMarco Porsch sta_ps_start(sta);
1803571ecf67SJohannes Berg }
180472eaa43aSJohannes Berg }
1805571ecf67SJohannes Berg
18063f52b7e3SMarco Porsch /* mesh power save support */
18073f52b7e3SMarco Porsch if (ieee80211_vif_is_mesh(&rx->sdata->vif))
18083f52b7e3SMarco Porsch ieee80211_mps_rx_h_sta_process(sta, hdr);
18093f52b7e3SMarco Porsch
181022403defSJohannes Berg /*
181122403defSJohannes Berg * Drop (qos-)data::nullfunc frames silently, since they
181222403defSJohannes Berg * are used only to control station power saving mode.
181322403defSJohannes Berg */
181430b2f0beSThomas Pedersen if (ieee80211_is_any_nullfunc(hdr->frame_control)) {
1815571ecf67SJohannes Berg I802_DEBUG_INC(rx->local->rx_handlers_drop_nullfunc);
1816d524215fSFelix Fietkau
1817d524215fSFelix Fietkau /*
1818d524215fSFelix Fietkau * If we receive a 4-addr nullfunc frame from a STA
1819e7f4a940SJohannes Berg * that was not moved to a 4-addr STA vlan yet send
1820e7f4a940SJohannes Berg * the event to userspace and for older hostapd drop
1821e7f4a940SJohannes Berg * the frame to the monitor interface.
1822d524215fSFelix Fietkau */
1823d524215fSFelix Fietkau if (ieee80211_has_a4(hdr->frame_control) &&
1824d524215fSFelix Fietkau (rx->sdata->vif.type == NL80211_IFTYPE_AP ||
1825d524215fSFelix Fietkau (rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
1826e7f4a940SJohannes Berg !rx->sdata->u.vlan.sta))) {
1827e7f4a940SJohannes Berg if (!test_and_set_sta_flag(sta, WLAN_STA_4ADDR_EVENT))
1828e7f4a940SJohannes Berg cfg80211_rx_unexpected_4addr_frame(
1829e7f4a940SJohannes Berg rx->sdata->dev, sta->sta.addr,
1830e7f4a940SJohannes Berg GFP_ATOMIC);
1831baa951a1SJohannes Berg return RX_DROP_M_UNEXPECTED_4ADDR_FRAME;
1832e7f4a940SJohannes Berg }
183322403defSJohannes Berg /*
183422403defSJohannes Berg * Update counter and free packet here to avoid
183522403defSJohannes Berg * counting this as a dropped packed.
183622403defSJohannes Berg */
1837b320d6c4SBenjamin Berg link_sta->rx_stats.packets++;
1838571ecf67SJohannes Berg dev_kfree_skb(rx->skb);
18399ae54c84SJohannes Berg return RX_QUEUED;
1840571ecf67SJohannes Berg }
1841571ecf67SJohannes Berg
18429ae54c84SJohannes Berg return RX_CONTINUE;
1843571ecf67SJohannes Berg } /* ieee80211_rx_h_sta_process */
1844571ecf67SJohannes Berg
1845af2d14b0SJouni Malinen static struct ieee80211_key *
ieee80211_rx_get_bigtk(struct ieee80211_rx_data * rx,int idx)1846af2d14b0SJouni Malinen ieee80211_rx_get_bigtk(struct ieee80211_rx_data *rx, int idx)
1847af2d14b0SJouni Malinen {
1848af2d14b0SJouni Malinen struct ieee80211_key *key = NULL;
1849af2d14b0SJouni Malinen int idx2;
1850af2d14b0SJouni Malinen
1851af2d14b0SJouni Malinen /* Make sure key gets set if either BIGTK key index is set so that
1852af2d14b0SJouni Malinen * ieee80211_drop_unencrypted_mgmt() can properly drop both unprotected
1853af2d14b0SJouni Malinen * Beacon frames and Beacon frames that claim to use another BIGTK key
1854af2d14b0SJouni Malinen * index (i.e., a key that we do not have).
1855af2d14b0SJouni Malinen */
1856af2d14b0SJouni Malinen
1857af2d14b0SJouni Malinen if (idx < 0) {
1858af2d14b0SJouni Malinen idx = NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS;
1859af2d14b0SJouni Malinen idx2 = idx + 1;
1860af2d14b0SJouni Malinen } else {
1861af2d14b0SJouni Malinen if (idx == NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS)
1862af2d14b0SJouni Malinen idx2 = idx + 1;
1863af2d14b0SJouni Malinen else
1864af2d14b0SJouni Malinen idx2 = idx - 1;
1865af2d14b0SJouni Malinen }
1866af2d14b0SJouni Malinen
1867ccdde7c7SJohannes Berg if (rx->link_sta)
1868ccdde7c7SJohannes Berg key = rcu_dereference(rx->link_sta->gtk[idx]);
1869af2d14b0SJouni Malinen if (!key)
1870ccdde7c7SJohannes Berg key = rcu_dereference(rx->link->gtk[idx]);
1871ccdde7c7SJohannes Berg if (!key && rx->link_sta)
1872ccdde7c7SJohannes Berg key = rcu_dereference(rx->link_sta->gtk[idx2]);
1873af2d14b0SJouni Malinen if (!key)
1874ccdde7c7SJohannes Berg key = rcu_dereference(rx->link->gtk[idx2]);
1875af2d14b0SJouni Malinen
1876af2d14b0SJouni Malinen return key;
1877af2d14b0SJouni Malinen }
1878af2d14b0SJouni Malinen
187986c228a7SJohan Almbladh static ieee80211_rx_result debug_noinline
ieee80211_rx_h_decrypt(struct ieee80211_rx_data * rx)188086c228a7SJohan Almbladh ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
188186c228a7SJohan Almbladh {
188286c228a7SJohan Almbladh struct sk_buff *skb = rx->skb;
188386c228a7SJohan Almbladh struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
188486c228a7SJohan Almbladh struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
188586c228a7SJohan Almbladh int keyidx;
188686c228a7SJohan Almbladh ieee80211_rx_result result = RX_DROP_UNUSABLE;
188786c228a7SJohan Almbladh struct ieee80211_key *sta_ptk = NULL;
188896fc6efbSAlexander Wetzel struct ieee80211_key *ptk_idx = NULL;
188986c228a7SJohan Almbladh int mmie_keyidx = -1;
189086c228a7SJohan Almbladh __le16 fc;
189186c228a7SJohan Almbladh
189209a740ceSThomas Pedersen if (ieee80211_is_ext(hdr->frame_control))
189309a740ceSThomas Pedersen return RX_CONTINUE;
189409a740ceSThomas Pedersen
189586c228a7SJohan Almbladh /*
189686c228a7SJohan Almbladh * Key selection 101
189786c228a7SJohan Almbladh *
1898af2d14b0SJouni Malinen * There are five types of keys:
189986c228a7SJohan Almbladh * - GTK (group keys)
190086c228a7SJohan Almbladh * - IGTK (group keys for management frames)
1901af2d14b0SJouni Malinen * - BIGTK (group keys for Beacon frames)
190286c228a7SJohan Almbladh * - PTK (pairwise keys)
190386c228a7SJohan Almbladh * - STK (station-to-station pairwise keys)
190486c228a7SJohan Almbladh *
190586c228a7SJohan Almbladh * When selecting a key, we have to distinguish between multicast
190686c228a7SJohan Almbladh * (including broadcast) and unicast frames, the latter can only
1907af2d14b0SJouni Malinen * use PTKs and STKs while the former always use GTKs, IGTKs, and
1908af2d14b0SJouni Malinen * BIGTKs. Unless, of course, actual WEP keys ("pre-RSNA") are used,
1909af2d14b0SJouni Malinen * then unicast frames can also use key indices like GTKs. Hence, if we
191086c228a7SJohan Almbladh * don't have a PTK/STK we check the key index for a WEP key.
191186c228a7SJohan Almbladh *
191286c228a7SJohan Almbladh * Note that in a regular BSS, multicast frames are sent by the
191386c228a7SJohan Almbladh * AP only, associated stations unicast the frame to the AP first
191486c228a7SJohan Almbladh * which then multicasts it on their behalf.
191586c228a7SJohan Almbladh *
191686c228a7SJohan Almbladh * There is also a slight problem in IBSS mode: GTKs are negotiated
191786c228a7SJohan Almbladh * with each station, that is something we don't currently handle.
191886c228a7SJohan Almbladh * The spec seems to expect that one negotiates the same key with
191986c228a7SJohan Almbladh * every station but there's no such requirement; VLANs could be
192086c228a7SJohan Almbladh * possible.
192186c228a7SJohan Almbladh */
192286c228a7SJohan Almbladh
192386c228a7SJohan Almbladh /* start without a key */
192486c228a7SJohan Almbladh rx->key = NULL;
192586c228a7SJohan Almbladh fc = hdr->frame_control;
192686c228a7SJohan Almbladh
19272475b1ccSMax Stepanov if (rx->sta) {
19282475b1ccSMax Stepanov int keyid = rx->sta->ptk_idx;
192996fc6efbSAlexander Wetzel sta_ptk = rcu_dereference(rx->sta->ptk[keyid]);
19302475b1ccSMax Stepanov
193177dfc2bcSXing Song if (ieee80211_has_protected(fc) &&
193277dfc2bcSXing Song !(status->flag & RX_FLAG_IV_STRIPPED)) {
193323a5f0afSJohannes Berg keyid = ieee80211_get_keyid(rx->skb);
193496fc6efbSAlexander Wetzel
19352475b1ccSMax Stepanov if (unlikely(keyid < 0))
19362475b1ccSMax Stepanov return RX_DROP_UNUSABLE;
193796fc6efbSAlexander Wetzel
193896fc6efbSAlexander Wetzel ptk_idx = rcu_dereference(rx->sta->ptk[keyid]);
19392475b1ccSMax Stepanov }
19402475b1ccSMax Stepanov }
19412475b1ccSMax Stepanov
194286c228a7SJohan Almbladh if (!ieee80211_has_protected(fc))
194386c228a7SJohan Almbladh mmie_keyidx = ieee80211_get_mmie_keyidx(rx->skb);
194486c228a7SJohan Almbladh
194586c228a7SJohan Almbladh if (!is_multicast_ether_addr(hdr->addr1) && sta_ptk) {
194696fc6efbSAlexander Wetzel rx->key = ptk_idx ? ptk_idx : sta_ptk;
194786c228a7SJohan Almbladh if ((status->flag & RX_FLAG_DECRYPTED) &&
194886c228a7SJohan Almbladh (status->flag & RX_FLAG_IV_STRIPPED))
194986c228a7SJohan Almbladh return RX_CONTINUE;
195086c228a7SJohan Almbladh /* Skip decryption if the frame is not protected. */
195186c228a7SJohan Almbladh if (!ieee80211_has_protected(fc))
195286c228a7SJohan Almbladh return RX_CONTINUE;
1953af2d14b0SJouni Malinen } else if (mmie_keyidx >= 0 && ieee80211_is_beacon(fc)) {
1954af2d14b0SJouni Malinen /* Broadcast/multicast robust management frame / BIP */
1955af2d14b0SJouni Malinen if ((status->flag & RX_FLAG_DECRYPTED) &&
1956af2d14b0SJouni Malinen (status->flag & RX_FLAG_IV_STRIPPED))
1957af2d14b0SJouni Malinen return RX_CONTINUE;
1958af2d14b0SJouni Malinen
1959af2d14b0SJouni Malinen if (mmie_keyidx < NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS ||
1960af2d14b0SJouni Malinen mmie_keyidx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS +
19619eaf183aSJouni Malinen NUM_DEFAULT_BEACON_KEYS) {
1962b2d03cabSJohannes Berg if (rx->sdata->dev)
19639eaf183aSJouni Malinen cfg80211_rx_unprot_mlme_mgmt(rx->sdata->dev,
19649eaf183aSJouni Malinen skb->data,
19659eaf183aSJouni Malinen skb->len);
1966baa951a1SJohannes Berg return RX_DROP_M_BAD_BCN_KEYIDX;
19679eaf183aSJouni Malinen }
1968af2d14b0SJouni Malinen
1969af2d14b0SJouni Malinen rx->key = ieee80211_rx_get_bigtk(rx, mmie_keyidx);
1970af2d14b0SJouni Malinen if (!rx->key)
1971af2d14b0SJouni Malinen return RX_CONTINUE; /* Beacon protection not in use */
197286c228a7SJohan Almbladh } else if (mmie_keyidx >= 0) {
197386c228a7SJohan Almbladh /* Broadcast/multicast robust management frame / BIP */
197486c228a7SJohan Almbladh if ((status->flag & RX_FLAG_DECRYPTED) &&
197586c228a7SJohan Almbladh (status->flag & RX_FLAG_IV_STRIPPED))
197686c228a7SJohan Almbladh return RX_CONTINUE;
197786c228a7SJohan Almbladh
197886c228a7SJohan Almbladh if (mmie_keyidx < NUM_DEFAULT_KEYS ||
197986c228a7SJohan Almbladh mmie_keyidx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS)
1980baa951a1SJohannes Berg return RX_DROP_M_BAD_MGMT_KEYIDX; /* unexpected BIP keyidx */
1981ccdde7c7SJohannes Berg if (rx->link_sta) {
198246f6b060SMasashi Honma if (ieee80211_is_group_privacy_action(skb) &&
198346f6b060SMasashi Honma test_sta_flag(rx->sta, WLAN_STA_MFP))
198446f6b060SMasashi Honma return RX_DROP_MONITOR;
198546f6b060SMasashi Honma
1986ccdde7c7SJohannes Berg rx->key = rcu_dereference(rx->link_sta->gtk[mmie_keyidx]);
198746f6b060SMasashi Honma }
198886c228a7SJohan Almbladh if (!rx->key)
1989ccdde7c7SJohannes Berg rx->key = rcu_dereference(rx->link->gtk[mmie_keyidx]);
199086c228a7SJohan Almbladh } else if (!ieee80211_has_protected(fc)) {
199186c228a7SJohan Almbladh /*
199286c228a7SJohan Almbladh * The frame was not protected, so skip decryption. However, we
199386c228a7SJohan Almbladh * need to set rx->key if there is a key that could have been
199486c228a7SJohan Almbladh * used so that the frame may be dropped if encryption would
199586c228a7SJohan Almbladh * have been expected.
199686c228a7SJohan Almbladh */
199786c228a7SJohan Almbladh struct ieee80211_key *key = NULL;
199886c228a7SJohan Almbladh int i;
199986c228a7SJohan Almbladh
2000af2d14b0SJouni Malinen if (ieee80211_is_beacon(fc)) {
2001af2d14b0SJouni Malinen key = ieee80211_rx_get_bigtk(rx, -1);
2002af2d14b0SJouni Malinen } else if (ieee80211_is_mgmt(fc) &&
2003af2d14b0SJouni Malinen is_multicast_ether_addr(hdr->addr1)) {
2004ccdde7c7SJohannes Berg key = rcu_dereference(rx->link->default_mgmt_key);
2005af2d14b0SJouni Malinen } else {
2006ccdde7c7SJohannes Berg if (rx->link_sta) {
200786c228a7SJohan Almbladh for (i = 0; i < NUM_DEFAULT_KEYS; i++) {
2008ccdde7c7SJohannes Berg key = rcu_dereference(rx->link_sta->gtk[i]);
200986c228a7SJohan Almbladh if (key)
201086c228a7SJohan Almbladh break;
201186c228a7SJohan Almbladh }
201286c228a7SJohan Almbladh }
201386c228a7SJohan Almbladh if (!key) {
201486c228a7SJohan Almbladh for (i = 0; i < NUM_DEFAULT_KEYS; i++) {
2015ccdde7c7SJohannes Berg key = rcu_dereference(rx->link->gtk[i]);
201686c228a7SJohan Almbladh if (key)
201786c228a7SJohan Almbladh break;
201886c228a7SJohan Almbladh }
201986c228a7SJohan Almbladh }
2020af2d14b0SJouni Malinen }
202186c228a7SJohan Almbladh if (key)
202286c228a7SJohan Almbladh rx->key = key;
202386c228a7SJohan Almbladh return RX_CONTINUE;
202486c228a7SJohan Almbladh } else {
202586c228a7SJohan Almbladh /*
202686c228a7SJohan Almbladh * The device doesn't give us the IV so we won't be
202786c228a7SJohan Almbladh * able to look up the key. That's ok though, we
202886c228a7SJohan Almbladh * don't need to decrypt the frame, we just won't
202986c228a7SJohan Almbladh * be able to keep statistics accurate.
203086c228a7SJohan Almbladh * Except for key threshold notifications, should
203186c228a7SJohan Almbladh * we somehow allow the driver to tell us which key
203286c228a7SJohan Almbladh * the hardware used if this flag is set?
203386c228a7SJohan Almbladh */
203486c228a7SJohan Almbladh if ((status->flag & RX_FLAG_DECRYPTED) &&
203586c228a7SJohan Almbladh (status->flag & RX_FLAG_IV_STRIPPED))
203686c228a7SJohan Almbladh return RX_CONTINUE;
203786c228a7SJohan Almbladh
203823a5f0afSJohannes Berg keyidx = ieee80211_get_keyid(rx->skb);
20392475b1ccSMax Stepanov
20402475b1ccSMax Stepanov if (unlikely(keyidx < 0))
20412475b1ccSMax Stepanov return RX_DROP_UNUSABLE;
204286c228a7SJohan Almbladh
204386c228a7SJohan Almbladh /* check per-station GTK first, if multicast packet */
2044ccdde7c7SJohannes Berg if (is_multicast_ether_addr(hdr->addr1) && rx->link_sta)
2045ccdde7c7SJohannes Berg rx->key = rcu_dereference(rx->link_sta->gtk[keyidx]);
204686c228a7SJohan Almbladh
204786c228a7SJohan Almbladh /* if not found, try default key */
204886c228a7SJohan Almbladh if (!rx->key) {
2049bfd8403aSJohannes Berg if (is_multicast_ether_addr(hdr->addr1))
2050ccdde7c7SJohannes Berg rx->key = rcu_dereference(rx->link->gtk[keyidx]);
2051bfd8403aSJohannes Berg if (!rx->key)
205286c228a7SJohan Almbladh rx->key = rcu_dereference(rx->sdata->keys[keyidx]);
205386c228a7SJohan Almbladh
205486c228a7SJohan Almbladh /*
205586c228a7SJohan Almbladh * RSNA-protected unicast frames should always be
205686c228a7SJohan Almbladh * sent with pairwise or station-to-station keys,
205786c228a7SJohan Almbladh * but for WEP we allow using a key index as well.
205886c228a7SJohan Almbladh */
205986c228a7SJohan Almbladh if (rx->key &&
206086c228a7SJohan Almbladh rx->key->conf.cipher != WLAN_CIPHER_SUITE_WEP40 &&
206186c228a7SJohan Almbladh rx->key->conf.cipher != WLAN_CIPHER_SUITE_WEP104 &&
206286c228a7SJohan Almbladh !is_multicast_ether_addr(hdr->addr1))
206386c228a7SJohan Almbladh rx->key = NULL;
206486c228a7SJohan Almbladh }
206586c228a7SJohan Almbladh }
206686c228a7SJohan Almbladh
206786c228a7SJohan Almbladh if (rx->key) {
206886c228a7SJohan Almbladh if (unlikely(rx->key->flags & KEY_FLAG_TAINTED))
206986c228a7SJohan Almbladh return RX_DROP_MONITOR;
207086c228a7SJohan Almbladh
207186c228a7SJohan Almbladh /* TODO: add threshold stuff again */
207286c228a7SJohan Almbladh } else {
207386c228a7SJohan Almbladh return RX_DROP_MONITOR;
207486c228a7SJohan Almbladh }
207586c228a7SJohan Almbladh
207686c228a7SJohan Almbladh switch (rx->key->conf.cipher) {
207786c228a7SJohan Almbladh case WLAN_CIPHER_SUITE_WEP40:
207886c228a7SJohan Almbladh case WLAN_CIPHER_SUITE_WEP104:
207986c228a7SJohan Almbladh result = ieee80211_crypto_wep_decrypt(rx);
208086c228a7SJohan Almbladh break;
208186c228a7SJohan Almbladh case WLAN_CIPHER_SUITE_TKIP:
208286c228a7SJohan Almbladh result = ieee80211_crypto_tkip_decrypt(rx);
208386c228a7SJohan Almbladh break;
208486c228a7SJohan Almbladh case WLAN_CIPHER_SUITE_CCMP:
20852b2ba0dbSJouni Malinen result = ieee80211_crypto_ccmp_decrypt(
20862b2ba0dbSJouni Malinen rx, IEEE80211_CCMP_MIC_LEN);
20872b2ba0dbSJouni Malinen break;
20882b2ba0dbSJouni Malinen case WLAN_CIPHER_SUITE_CCMP_256:
20892b2ba0dbSJouni Malinen result = ieee80211_crypto_ccmp_decrypt(
20902b2ba0dbSJouni Malinen rx, IEEE80211_CCMP_256_MIC_LEN);
209186c228a7SJohan Almbladh break;
209286c228a7SJohan Almbladh case WLAN_CIPHER_SUITE_AES_CMAC:
209386c228a7SJohan Almbladh result = ieee80211_crypto_aes_cmac_decrypt(rx);
209486c228a7SJohan Almbladh break;
209556c52da2SJouni Malinen case WLAN_CIPHER_SUITE_BIP_CMAC_256:
209656c52da2SJouni Malinen result = ieee80211_crypto_aes_cmac_256_decrypt(rx);
209756c52da2SJouni Malinen break;
20988ade538bSJouni Malinen case WLAN_CIPHER_SUITE_BIP_GMAC_128:
20998ade538bSJouni Malinen case WLAN_CIPHER_SUITE_BIP_GMAC_256:
21008ade538bSJouni Malinen result = ieee80211_crypto_aes_gmac_decrypt(rx);
21018ade538bSJouni Malinen break;
210200b9cfa3SJouni Malinen case WLAN_CIPHER_SUITE_GCMP:
210300b9cfa3SJouni Malinen case WLAN_CIPHER_SUITE_GCMP_256:
210400b9cfa3SJouni Malinen result = ieee80211_crypto_gcmp_decrypt(rx);
210500b9cfa3SJouni Malinen break;
210686c228a7SJohan Almbladh default:
210723a5f0afSJohannes Berg result = RX_DROP_UNUSABLE;
210886c228a7SJohan Almbladh }
210986c228a7SJohan Almbladh
211086c228a7SJohan Almbladh /* the hdr variable is invalid after the decrypt handlers */
211186c228a7SJohan Almbladh
211286c228a7SJohan Almbladh /* either the frame has been decrypted or will be dropped */
211386c228a7SJohan Almbladh status->flag |= RX_FLAG_DECRYPTED;
211486c228a7SJohan Almbladh
21152fa71edbSJohannes Berg if (unlikely(ieee80211_is_beacon(fc) && RX_RES_IS_UNUSABLE(result) &&
2116b2d03cabSJohannes Berg rx->sdata->dev))
21179eaf183aSJouni Malinen cfg80211_rx_unprot_mlme_mgmt(rx->sdata->dev,
21189eaf183aSJouni Malinen skb->data, skb->len);
21199eaf183aSJouni Malinen
212086c228a7SJohan Almbladh return result;
212186c228a7SJohan Almbladh }
212286c228a7SJohan Almbladh
ieee80211_init_frag_cache(struct ieee80211_fragment_cache * cache)21233a11ce08SJohannes Berg void ieee80211_init_frag_cache(struct ieee80211_fragment_cache *cache)
21243a11ce08SJohannes Berg {
21253a11ce08SJohannes Berg int i;
21263a11ce08SJohannes Berg
21273a11ce08SJohannes Berg for (i = 0; i < ARRAY_SIZE(cache->entries); i++)
21283a11ce08SJohannes Berg skb_queue_head_init(&cache->entries[i].skb_list);
21293a11ce08SJohannes Berg }
21303a11ce08SJohannes Berg
ieee80211_destroy_frag_cache(struct ieee80211_fragment_cache * cache)21313a11ce08SJohannes Berg void ieee80211_destroy_frag_cache(struct ieee80211_fragment_cache *cache)
21323a11ce08SJohannes Berg {
21333a11ce08SJohannes Berg int i;
21343a11ce08SJohannes Berg
21353a11ce08SJohannes Berg for (i = 0; i < ARRAY_SIZE(cache->entries); i++)
21363a11ce08SJohannes Berg __skb_queue_purge(&cache->entries[i].skb_list);
21373a11ce08SJohannes Berg }
21383a11ce08SJohannes Berg
2139571ecf67SJohannes Berg static inline struct ieee80211_fragment_entry *
ieee80211_reassemble_add(struct ieee80211_fragment_cache * cache,unsigned int frag,unsigned int seq,int rx_queue,struct sk_buff ** skb)21403a11ce08SJohannes Berg ieee80211_reassemble_add(struct ieee80211_fragment_cache *cache,
2141571ecf67SJohannes Berg unsigned int frag, unsigned int seq, int rx_queue,
2142571ecf67SJohannes Berg struct sk_buff **skb)
2143571ecf67SJohannes Berg {
2144571ecf67SJohannes Berg struct ieee80211_fragment_entry *entry;
2145571ecf67SJohannes Berg
21463a11ce08SJohannes Berg entry = &cache->entries[cache->next++];
21473a11ce08SJohannes Berg if (cache->next >= IEEE80211_FRAGMENT_MAX)
21483a11ce08SJohannes Berg cache->next = 0;
2149571ecf67SJohannes Berg
2150571ecf67SJohannes Berg __skb_queue_purge(&entry->skb_list);
2151571ecf67SJohannes Berg
2152571ecf67SJohannes Berg __skb_queue_tail(&entry->skb_list, *skb); /* no need for locking */
2153571ecf67SJohannes Berg *skb = NULL;
2154571ecf67SJohannes Berg entry->first_frag_time = jiffies;
2155571ecf67SJohannes Berg entry->seq = seq;
2156571ecf67SJohannes Berg entry->rx_queue = rx_queue;
2157571ecf67SJohannes Berg entry->last_frag = frag;
21589acc54beSJohannes Berg entry->check_sequential_pn = false;
2159571ecf67SJohannes Berg entry->extra_len = 0;
2160571ecf67SJohannes Berg
2161571ecf67SJohannes Berg return entry;
2162571ecf67SJohannes Berg }
2163571ecf67SJohannes Berg
2164571ecf67SJohannes Berg static inline struct ieee80211_fragment_entry *
ieee80211_reassemble_find(struct ieee80211_fragment_cache * cache,unsigned int frag,unsigned int seq,int rx_queue,struct ieee80211_hdr * hdr)21653a11ce08SJohannes Berg ieee80211_reassemble_find(struct ieee80211_fragment_cache *cache,
2166b73d70adSHarvey Harrison unsigned int frag, unsigned int seq,
2167571ecf67SJohannes Berg int rx_queue, struct ieee80211_hdr *hdr)
2168571ecf67SJohannes Berg {
2169571ecf67SJohannes Berg struct ieee80211_fragment_entry *entry;
2170571ecf67SJohannes Berg int i, idx;
2171571ecf67SJohannes Berg
21723a11ce08SJohannes Berg idx = cache->next;
2173571ecf67SJohannes Berg for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++) {
2174571ecf67SJohannes Berg struct ieee80211_hdr *f_hdr;
21757957a9deSDavid S. Miller struct sk_buff *f_skb;
2176571ecf67SJohannes Berg
2177571ecf67SJohannes Berg idx--;
2178571ecf67SJohannes Berg if (idx < 0)
2179571ecf67SJohannes Berg idx = IEEE80211_FRAGMENT_MAX - 1;
2180571ecf67SJohannes Berg
21813a11ce08SJohannes Berg entry = &cache->entries[idx];
2182571ecf67SJohannes Berg if (skb_queue_empty(&entry->skb_list) || entry->seq != seq ||
2183571ecf67SJohannes Berg entry->rx_queue != rx_queue ||
2184571ecf67SJohannes Berg entry->last_frag + 1 != frag)
2185571ecf67SJohannes Berg continue;
2186571ecf67SJohannes Berg
21877957a9deSDavid S. Miller f_skb = __skb_peek(&entry->skb_list);
21887957a9deSDavid S. Miller f_hdr = (struct ieee80211_hdr *) f_skb->data;
2189571ecf67SJohannes Berg
2190b73d70adSHarvey Harrison /*
2191b73d70adSHarvey Harrison * Check ftype and addresses are equal, else check next fragment
2192b73d70adSHarvey Harrison */
2193b73d70adSHarvey Harrison if (((hdr->frame_control ^ f_hdr->frame_control) &
2194b73d70adSHarvey Harrison cpu_to_le16(IEEE80211_FCTL_FTYPE)) ||
2195b203ca39SJoe Perches !ether_addr_equal(hdr->addr1, f_hdr->addr1) ||
2196b203ca39SJoe Perches !ether_addr_equal(hdr->addr2, f_hdr->addr2))
2197571ecf67SJohannes Berg continue;
2198571ecf67SJohannes Berg
2199ab46623eSS.Çağlar Onur if (time_after(jiffies, entry->first_frag_time + 2 * HZ)) {
2200571ecf67SJohannes Berg __skb_queue_purge(&entry->skb_list);
2201571ecf67SJohannes Berg continue;
2202571ecf67SJohannes Berg }
2203571ecf67SJohannes Berg return entry;
2204571ecf67SJohannes Berg }
2205571ecf67SJohannes Berg
2206571ecf67SJohannes Berg return NULL;
2207571ecf67SJohannes Berg }
2208571ecf67SJohannes Berg
requires_sequential_pn(struct ieee80211_rx_data * rx,__le16 fc)2209965a7d72SMathy Vanhoef static bool requires_sequential_pn(struct ieee80211_rx_data *rx, __le16 fc)
2210965a7d72SMathy Vanhoef {
2211965a7d72SMathy Vanhoef return rx->key &&
2212965a7d72SMathy Vanhoef (rx->key->conf.cipher == WLAN_CIPHER_SUITE_CCMP ||
2213965a7d72SMathy Vanhoef rx->key->conf.cipher == WLAN_CIPHER_SUITE_CCMP_256 ||
2214965a7d72SMathy Vanhoef rx->key->conf.cipher == WLAN_CIPHER_SUITE_GCMP ||
2215965a7d72SMathy Vanhoef rx->key->conf.cipher == WLAN_CIPHER_SUITE_GCMP_256) &&
2216965a7d72SMathy Vanhoef ieee80211_has_protected(fc);
2217965a7d72SMathy Vanhoef }
2218965a7d72SMathy Vanhoef
221949461622SJohannes Berg static ieee80211_rx_result debug_noinline
ieee80211_rx_h_defragment(struct ieee80211_rx_data * rx)22205cf121c3SJohannes Berg ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
2221571ecf67SJohannes Berg {
22223a11ce08SJohannes Berg struct ieee80211_fragment_cache *cache = &rx->sdata->frags;
2223571ecf67SJohannes Berg struct ieee80211_hdr *hdr;
2224571ecf67SJohannes Berg u16 sc;
2225358c8d9dSHarvey Harrison __le16 fc;
2226571ecf67SJohannes Berg unsigned int frag, seq;
2227571ecf67SJohannes Berg struct ieee80211_fragment_entry *entry;
2228571ecf67SJohannes Berg struct sk_buff *skb;
22293edc6b0dSWen Gong struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
2230571ecf67SJohannes Berg
2231571ecf67SJohannes Berg hdr = (struct ieee80211_hdr *)rx->skb->data;
2232358c8d9dSHarvey Harrison fc = hdr->frame_control;
2233f7fbf70eSJavier Cardona
223409a740ceSThomas Pedersen if (ieee80211_is_ctl(fc) || ieee80211_is_ext(fc))
2235f7fbf70eSJavier Cardona return RX_CONTINUE;
2236f7fbf70eSJavier Cardona
2237571ecf67SJohannes Berg sc = le16_to_cpu(hdr->seq_ctrl);
2238571ecf67SJohannes Berg frag = sc & IEEE80211_SCTL_FRAG;
2239571ecf67SJohannes Berg
22403a11ce08SJohannes Berg if (rx->sta)
22413a11ce08SJohannes Berg cache = &rx->sta->frags;
22423a11ce08SJohannes Berg
2243d025933eSAndreas Müller if (likely(!ieee80211_has_morefrags(fc) && frag == 0))
2244d025933eSAndreas Müller goto out;
2245d025933eSAndreas Müller
2246a9799541SJohannes Berg if (is_multicast_ether_addr(hdr->addr1))
2247a9799541SJohannes Berg return RX_DROP_MONITOR;
2248a9799541SJohannes Berg
2249571ecf67SJohannes Berg I802_DEBUG_INC(rx->local->rx_handlers_fragments);
2250571ecf67SJohannes Berg
2251e3cf8b3fSZhu Yi if (skb_linearize(rx->skb))
2252e3cf8b3fSZhu Yi return RX_DROP_UNUSABLE;
2253e3cf8b3fSZhu Yi
2254058897a4SAbhijeet Kolekar /*
2255058897a4SAbhijeet Kolekar * skb_linearize() might change the skb->data and
2256058897a4SAbhijeet Kolekar * previously cached variables (in this case, hdr) need to
2257058897a4SAbhijeet Kolekar * be refreshed with the new data.
2258058897a4SAbhijeet Kolekar */
2259058897a4SAbhijeet Kolekar hdr = (struct ieee80211_hdr *)rx->skb->data;
2260571ecf67SJohannes Berg seq = (sc & IEEE80211_SCTL_SEQ) >> 4;
2261571ecf67SJohannes Berg
2262571ecf67SJohannes Berg if (frag == 0) {
2263571ecf67SJohannes Berg /* This is the first fragment of a new frame. */
22643a11ce08SJohannes Berg entry = ieee80211_reassemble_add(cache, frag, seq,
22659e26297aSJohannes Berg rx->seqno_idx, &(rx->skb));
2266965a7d72SMathy Vanhoef if (requires_sequential_pn(rx, fc)) {
22679e26297aSJohannes Berg int queue = rx->security_idx;
22689acc54beSJohannes Berg
22699acc54beSJohannes Berg /* Store CCMP/GCMP PN so that we can verify that the
22709acc54beSJohannes Berg * next fragment has a sequential PN value.
22719acc54beSJohannes Berg */
22729acc54beSJohannes Berg entry->check_sequential_pn = true;
22737e44a0b5SJohannes Berg entry->is_protected = true;
227494034c40SMathy Vanhoef entry->key_color = rx->key->color;
2275571ecf67SJohannes Berg memcpy(entry->last_pn,
22769190252cSJouni Malinen rx->key->u.ccmp.rx_pn[queue],
22774325f6caSJohannes Berg IEEE80211_CCMP_PN_LEN);
22789acc54beSJohannes Berg BUILD_BUG_ON(offsetof(struct ieee80211_key,
22799acc54beSJohannes Berg u.ccmp.rx_pn) !=
22809acc54beSJohannes Berg offsetof(struct ieee80211_key,
22819acc54beSJohannes Berg u.gcmp.rx_pn));
22829acc54beSJohannes Berg BUILD_BUG_ON(sizeof(rx->key->u.ccmp.rx_pn[queue]) !=
22839acc54beSJohannes Berg sizeof(rx->key->u.gcmp.rx_pn[queue]));
22849acc54beSJohannes Berg BUILD_BUG_ON(IEEE80211_CCMP_PN_LEN !=
22859acc54beSJohannes Berg IEEE80211_GCMP_PN_LEN);
22863edc6b0dSWen Gong } else if (rx->key &&
22873edc6b0dSWen Gong (ieee80211_has_protected(fc) ||
22883edc6b0dSWen Gong (status->flag & RX_FLAG_DECRYPTED))) {
22897e44a0b5SJohannes Berg entry->is_protected = true;
22907e44a0b5SJohannes Berg entry->key_color = rx->key->color;
2291571ecf67SJohannes Berg }
22929ae54c84SJohannes Berg return RX_QUEUED;
2293571ecf67SJohannes Berg }
2294571ecf67SJohannes Berg
2295571ecf67SJohannes Berg /* This is a fragment for a frame that should already be pending in
2296571ecf67SJohannes Berg * fragment cache. Add this fragment to the end of the pending entry.
2297571ecf67SJohannes Berg */
22983a11ce08SJohannes Berg entry = ieee80211_reassemble_find(cache, frag, seq,
22999e26297aSJohannes Berg rx->seqno_idx, hdr);
2300571ecf67SJohannes Berg if (!entry) {
2301571ecf67SJohannes Berg I802_DEBUG_INC(rx->local->rx_handlers_drop_defrag);
2302e4c26addSJohannes Berg return RX_DROP_MONITOR;
2303571ecf67SJohannes Berg }
2304571ecf67SJohannes Berg
23059acc54beSJohannes Berg /* "The receiver shall discard MSDUs and MMPDUs whose constituent
23069acc54beSJohannes Berg * MPDU PN values are not incrementing in steps of 1."
23079acc54beSJohannes Berg * see IEEE P802.11-REVmc/D5.0, 12.5.3.4.4, item d (for CCMP)
23089acc54beSJohannes Berg * and IEEE P802.11-REVmc/D5.0, 12.5.5.4.4, item d (for GCMP)
23099acc54beSJohannes Berg */
23109acc54beSJohannes Berg if (entry->check_sequential_pn) {
2311571ecf67SJohannes Berg int i;
23124325f6caSJohannes Berg u8 pn[IEEE80211_CCMP_PN_LEN], *rpn;
23139acc54beSJohannes Berg
2314965a7d72SMathy Vanhoef if (!requires_sequential_pn(rx, fc))
2315e4c26addSJohannes Berg return RX_DROP_UNUSABLE;
231694034c40SMathy Vanhoef
231794034c40SMathy Vanhoef /* Prevent mixed key and fragment cache attacks */
231894034c40SMathy Vanhoef if (entry->key_color != rx->key->color)
231994034c40SMathy Vanhoef return RX_DROP_UNUSABLE;
232094034c40SMathy Vanhoef
23214325f6caSJohannes Berg memcpy(pn, entry->last_pn, IEEE80211_CCMP_PN_LEN);
23224325f6caSJohannes Berg for (i = IEEE80211_CCMP_PN_LEN - 1; i >= 0; i--) {
2323571ecf67SJohannes Berg pn[i]++;
2324571ecf67SJohannes Berg if (pn[i])
2325571ecf67SJohannes Berg break;
2326571ecf67SJohannes Berg }
2327bf30ca92SJohannes Berg
2328bf30ca92SJohannes Berg rpn = rx->ccm_gcm.pn;
23294325f6caSJohannes Berg if (memcmp(pn, rpn, IEEE80211_CCMP_PN_LEN))
2330e4c26addSJohannes Berg return RX_DROP_UNUSABLE;
23314325f6caSJohannes Berg memcpy(entry->last_pn, pn, IEEE80211_CCMP_PN_LEN);
23327e44a0b5SJohannes Berg } else if (entry->is_protected &&
23333edc6b0dSWen Gong (!rx->key ||
23343edc6b0dSWen Gong (!ieee80211_has_protected(fc) &&
23353edc6b0dSWen Gong !(status->flag & RX_FLAG_DECRYPTED)) ||
23367e44a0b5SJohannes Berg rx->key->color != entry->key_color)) {
23377e44a0b5SJohannes Berg /* Drop this as a mixed key or fragment cache attack, even
23387e44a0b5SJohannes Berg * if for TKIP Michael MIC should protect us, and WEP is a
23397e44a0b5SJohannes Berg * lost cause anyway.
23407e44a0b5SJohannes Berg */
23417e44a0b5SJohannes Berg return RX_DROP_UNUSABLE;
23423edc6b0dSWen Gong } else if (entry->is_protected && rx->key &&
23433edc6b0dSWen Gong entry->key_color != rx->key->color &&
23443edc6b0dSWen Gong (status->flag & RX_FLAG_DECRYPTED)) {
23453edc6b0dSWen Gong return RX_DROP_UNUSABLE;
2346571ecf67SJohannes Berg }
2347571ecf67SJohannes Berg
2348358c8d9dSHarvey Harrison skb_pull(rx->skb, ieee80211_hdrlen(fc));
2349571ecf67SJohannes Berg __skb_queue_tail(&entry->skb_list, rx->skb);
2350571ecf67SJohannes Berg entry->last_frag = frag;
2351571ecf67SJohannes Berg entry->extra_len += rx->skb->len;
2352358c8d9dSHarvey Harrison if (ieee80211_has_morefrags(fc)) {
2353571ecf67SJohannes Berg rx->skb = NULL;
23549ae54c84SJohannes Berg return RX_QUEUED;
2355571ecf67SJohannes Berg }
2356571ecf67SJohannes Berg
2357571ecf67SJohannes Berg rx->skb = __skb_dequeue(&entry->skb_list);
2358571ecf67SJohannes Berg if (skb_tailroom(rx->skb) < entry->extra_len) {
2359f1160434SJohannes Berg I802_DEBUG_INC(rx->local->rx_expand_skb_head_defrag);
2360571ecf67SJohannes Berg if (unlikely(pskb_expand_head(rx->skb, 0, entry->extra_len,
2361571ecf67SJohannes Berg GFP_ATOMIC))) {
2362571ecf67SJohannes Berg I802_DEBUG_INC(rx->local->rx_handlers_drop_defrag);
2363571ecf67SJohannes Berg __skb_queue_purge(&entry->skb_list);
2364e4c26addSJohannes Berg return RX_DROP_UNUSABLE;
2365571ecf67SJohannes Berg }
2366571ecf67SJohannes Berg }
2367571ecf67SJohannes Berg while ((skb = __skb_dequeue(&entry->skb_list))) {
236859ae1d12SJohannes Berg skb_put_data(rx->skb, skb->data, skb->len);
2369571ecf67SJohannes Berg dev_kfree_skb(skb);
2370571ecf67SJohannes Berg }
2371571ecf67SJohannes Berg
2372571ecf67SJohannes Berg out:
2373d025933eSAndreas Müller ieee80211_led_rx(rx->local);
2374571ecf67SJohannes Berg if (rx->sta)
2375b320d6c4SBenjamin Berg rx->link_sta->rx_stats.packets++;
23769ae54c84SJohannes Berg return RX_CONTINUE;
2377571ecf67SJohannes Berg }
2378571ecf67SJohannes Berg
ieee80211_802_1x_port_control(struct ieee80211_rx_data * rx)23791df332e8SJohannes Berg static int ieee80211_802_1x_port_control(struct ieee80211_rx_data *rx)
2380571ecf67SJohannes Berg {
23811df332e8SJohannes Berg if (unlikely(!rx->sta || !test_sta_flag(rx->sta, WLAN_STA_AUTHORIZED)))
238276ee65bfSRon Rindjunsky return -EACCES;
2383571ecf67SJohannes Berg
238476ee65bfSRon Rindjunsky return 0;
2385571ecf67SJohannes Berg }
2386571ecf67SJohannes Berg
ieee80211_drop_unencrypted(struct ieee80211_rx_data * rx,__le16 fc)23871df332e8SJohannes Berg static int ieee80211_drop_unencrypted(struct ieee80211_rx_data *rx, __le16 fc)
2388571ecf67SJohannes Berg {
2389eb9fb5b8SJohannes Berg struct sk_buff *skb = rx->skb;
2390eb9fb5b8SJohannes Berg struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
2391eb9fb5b8SJohannes Berg
23923017b80bSJohannes Berg /*
23937848ba7dSJohannes Berg * Pass through unencrypted frames if the hardware has
23947848ba7dSJohannes Berg * decrypted them already.
23953017b80bSJohannes Berg */
2396eb9fb5b8SJohannes Berg if (status->flag & RX_FLAG_DECRYPTED)
239776ee65bfSRon Rindjunsky return 0;
2398571ecf67SJohannes Berg
2399571ecf67SJohannes Berg /* Drop unencrypted frames if key is set. */
2400358c8d9dSHarvey Harrison if (unlikely(!ieee80211_has_protected(fc) &&
240130b2f0beSThomas Pedersen !ieee80211_is_any_nullfunc(fc) &&
2402e8f4fb7cSJohannes Berg ieee80211_is_data(fc) && rx->key))
24033cfcf6acSJouni Malinen return -EACCES;
2404bef5d1c7SJohannes Berg
2405bef5d1c7SJohannes Berg return 0;
2406bef5d1c7SJohannes Berg }
2407bef5d1c7SJohannes Berg
ieee80211_drop_unencrypted_mgmt(struct ieee80211_rx_data * rx)24081df332e8SJohannes Berg static int ieee80211_drop_unencrypted_mgmt(struct ieee80211_rx_data *rx)
2409bef5d1c7SJohannes Berg {
2410e3efca0aSJouni Malinen struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
241176a3059cSJohannes Berg struct ieee80211_mgmt *mgmt = (void *)rx->skb->data;
241276a3059cSJohannes Berg __le16 fc = mgmt->frame_control;
2413bef5d1c7SJohannes Berg
2414e3efca0aSJouni Malinen /*
2415e3efca0aSJouni Malinen * Pass through unencrypted frames if the hardware has
2416e3efca0aSJouni Malinen * decrypted them already.
2417e3efca0aSJouni Malinen */
2418e3efca0aSJouni Malinen if (status->flag & RX_FLAG_DECRYPTED)
2419e3efca0aSJouni Malinen return 0;
2420bef5d1c7SJohannes Berg
242176a3059cSJohannes Berg /* drop unicast protected dual (that wasn't protected) */
242276a3059cSJohannes Berg if (ieee80211_is_action(fc) &&
242376a3059cSJohannes Berg mgmt->u.action.category == WLAN_CATEGORY_PROTECTED_DUAL_OF_ACTION)
242476a3059cSJohannes Berg return -EACCES;
242576a3059cSJohannes Berg
2426c2c98fdeSJohannes Berg if (rx->sta && test_sta_flag(rx->sta, WLAN_STA_MFP)) {
2427d211e90eSJouni Malinen if (unlikely(!ieee80211_has_protected(fc) &&
24287339e0f2SAlon Giladi ieee80211_is_unicast_robust_mgmt_frame(rx->skb))) {
24296ff57cf8SJohannes Berg if (ieee80211_is_deauth(fc) ||
24307339e0f2SAlon Giladi ieee80211_is_disassoc(fc)) {
24317339e0f2SAlon Giladi /*
24327339e0f2SAlon Giladi * Permit unprotected deauth/disassoc frames
24337339e0f2SAlon Giladi * during 4-way-HS (key is installed after HS).
24347339e0f2SAlon Giladi */
24357339e0f2SAlon Giladi if (!rx->key)
24367339e0f2SAlon Giladi return 0;
24377339e0f2SAlon Giladi
24386ff57cf8SJohannes Berg cfg80211_rx_unprot_mlme_mgmt(rx->sdata->dev,
2439cf4e594eSJouni Malinen rx->skb->data,
2440cf4e594eSJouni Malinen rx->skb->len);
24417339e0f2SAlon Giladi }
2442f2ca3ea4SJouni Malinen return -EACCES;
2443cf4e594eSJouni Malinen }
24443cfcf6acSJouni Malinen /* BIP does not use Protected field, so need to check MMIE */
2445f64f9e71SJoe Perches if (unlikely(ieee80211_is_multicast_robust_mgmt_frame(rx->skb) &&
2446cf4e594eSJouni Malinen ieee80211_get_mmie_keyidx(rx->skb) < 0)) {
24476ff57cf8SJohannes Berg if (ieee80211_is_deauth(fc) ||
24486ff57cf8SJohannes Berg ieee80211_is_disassoc(fc))
24496ff57cf8SJohannes Berg cfg80211_rx_unprot_mlme_mgmt(rx->sdata->dev,
2450cf4e594eSJouni Malinen rx->skb->data,
2451cf4e594eSJouni Malinen rx->skb->len);
245276ee65bfSRon Rindjunsky return -EACCES;
2453cf4e594eSJouni Malinen }
2454af2d14b0SJouni Malinen if (unlikely(ieee80211_is_beacon(fc) && rx->key &&
24559eaf183aSJouni Malinen ieee80211_get_mmie_keyidx(rx->skb) < 0)) {
24569eaf183aSJouni Malinen cfg80211_rx_unprot_mlme_mgmt(rx->sdata->dev,
24579eaf183aSJouni Malinen rx->skb->data,
24589eaf183aSJouni Malinen rx->skb->len);
2459af2d14b0SJouni Malinen return -EACCES;
24609eaf183aSJouni Malinen }
2461f2ca3ea4SJouni Malinen /*
2462f2ca3ea4SJouni Malinen * When using MFP, Action frames are not allowed prior to
2463f2ca3ea4SJouni Malinen * having configured keys.
2464f2ca3ea4SJouni Malinen */
2465f2ca3ea4SJouni Malinen if (unlikely(ieee80211_is_action(fc) && !rx->key &&
2466d8ca16dbSJohannes Berg ieee80211_is_robust_mgmt_frame(rx->skb)))
2467f2ca3ea4SJouni Malinen return -EACCES;
246876a3059cSJohannes Berg
246976a3059cSJohannes Berg /* drop unicast public action frames when using MPF */
247076a3059cSJohannes Berg if (is_unicast_ether_addr(mgmt->da) &&
247191535613SAvraham Stern ieee80211_is_protected_dual_of_public_action(rx->skb))
247276a3059cSJohannes Berg return -EACCES;
2473f2ca3ea4SJouni Malinen }
2474b3fc9c6cSJohannes Berg
247576ee65bfSRon Rindjunsky return 0;
2476571ecf67SJohannes Berg }
2477571ecf67SJohannes Berg
247876ee65bfSRon Rindjunsky static int
__ieee80211_data_to_8023(struct ieee80211_rx_data * rx,bool * port_control)24794114fa21SFelix Fietkau __ieee80211_data_to_8023(struct ieee80211_rx_data *rx, bool *port_control)
2480571ecf67SJohannes Berg {
2481eb9fb5b8SJohannes Berg struct ieee80211_sub_if_data *sdata = rx->sdata;
2482f14543eeSFelix Fietkau struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
2483fbb327c5SFelix Fietkau bool check_port_control = false;
2484fbb327c5SFelix Fietkau struct ethhdr *ehdr;
2485fbb327c5SFelix Fietkau int ret;
2486f14543eeSFelix Fietkau
24874114fa21SFelix Fietkau *port_control = false;
24889bc383deSJohannes Berg if (ieee80211_has_a4(hdr->frame_control) &&
24899bc383deSJohannes Berg sdata->vif.type == NL80211_IFTYPE_AP_VLAN && !sdata->u.vlan.sta)
2490f14543eeSFelix Fietkau return -1;
24919bc383deSJohannes Berg
2492fbb327c5SFelix Fietkau if (sdata->vif.type == NL80211_IFTYPE_STATION &&
2493fbb327c5SFelix Fietkau !!sdata->u.mgd.use_4addr != !!ieee80211_has_a4(hdr->frame_control)) {
2494fbb327c5SFelix Fietkau
2495fbb327c5SFelix Fietkau if (!sdata->u.mgd.use_4addr)
2496fbb327c5SFelix Fietkau return -1;
24971ecef20cSSathishkumar Muruganandam else if (!ether_addr_equal(hdr->addr1, sdata->vif.addr))
2498fbb327c5SFelix Fietkau check_port_control = true;
2499fbb327c5SFelix Fietkau }
2500fbb327c5SFelix Fietkau
25019bc383deSJohannes Berg if (is_multicast_ether_addr(hdr->addr1) &&
2502fbb327c5SFelix Fietkau sdata->vif.type == NL80211_IFTYPE_AP_VLAN && sdata->u.vlan.sta)
2503f14543eeSFelix Fietkau return -1;
2504571ecf67SJohannes Berg
2505fbb327c5SFelix Fietkau ret = ieee80211_data_to_8023(rx->skb, sdata->vif.addr, sdata->vif.type);
25064114fa21SFelix Fietkau if (ret < 0)
2507fbb327c5SFelix Fietkau return ret;
2508fbb327c5SFelix Fietkau
2509fbb327c5SFelix Fietkau ehdr = (struct ethhdr *) rx->skb->data;
25104114fa21SFelix Fietkau if (ehdr->h_proto == rx->sdata->control_port_protocol)
25114114fa21SFelix Fietkau *port_control = true;
25124114fa21SFelix Fietkau else if (check_port_control)
2513fbb327c5SFelix Fietkau return -1;
2514fbb327c5SFelix Fietkau
2515fbb327c5SFelix Fietkau return 0;
251676ee65bfSRon Rindjunsky }
2517571ecf67SJohannes Berg
ieee80211_is_our_addr(struct ieee80211_sub_if_data * sdata,const u8 * addr,int * out_link_id)25180d5891e3SAndrei Otcheretianski bool ieee80211_is_our_addr(struct ieee80211_sub_if_data *sdata,
2519d06faef1SAndrei Otcheretianski const u8 *addr, int *out_link_id)
2520d06faef1SAndrei Otcheretianski {
2521d06faef1SAndrei Otcheretianski unsigned int link_id;
2522d06faef1SAndrei Otcheretianski
2523d06faef1SAndrei Otcheretianski /* non-MLO, or MLD address replaced by hardware */
2524d06faef1SAndrei Otcheretianski if (ether_addr_equal(sdata->vif.addr, addr))
2525d06faef1SAndrei Otcheretianski return true;
2526d06faef1SAndrei Otcheretianski
2527f1871abdSIlan Peer if (!ieee80211_vif_is_mld(&sdata->vif))
2528d06faef1SAndrei Otcheretianski return false;
2529d06faef1SAndrei Otcheretianski
2530d06faef1SAndrei Otcheretianski for (link_id = 0; link_id < ARRAY_SIZE(sdata->vif.link_conf); link_id++) {
2531d06faef1SAndrei Otcheretianski struct ieee80211_bss_conf *conf;
2532d06faef1SAndrei Otcheretianski
2533d06faef1SAndrei Otcheretianski conf = rcu_dereference(sdata->vif.link_conf[link_id]);
2534d06faef1SAndrei Otcheretianski
2535d06faef1SAndrei Otcheretianski if (!conf)
2536d06faef1SAndrei Otcheretianski continue;
2537d06faef1SAndrei Otcheretianski if (ether_addr_equal(conf->addr, addr)) {
2538d06faef1SAndrei Otcheretianski if (out_link_id)
2539d06faef1SAndrei Otcheretianski *out_link_id = link_id;
2540d06faef1SAndrei Otcheretianski return true;
2541d06faef1SAndrei Otcheretianski }
2542d06faef1SAndrei Otcheretianski }
2543d06faef1SAndrei Otcheretianski
2544d06faef1SAndrei Otcheretianski return false;
2545d06faef1SAndrei Otcheretianski }
2546d06faef1SAndrei Otcheretianski
2547ce3edf6dSJohannes Berg /*
2548ce3edf6dSJohannes Berg * requires that rx->skb is a frame with ethernet header
2549ce3edf6dSJohannes Berg */
ieee80211_frame_allowed(struct ieee80211_rx_data * rx,__le16 fc)2550358c8d9dSHarvey Harrison static bool ieee80211_frame_allowed(struct ieee80211_rx_data *rx, __le16 fc)
2551ce3edf6dSJohannes Berg {
2552c97c23e3SSenthil Balasubramanian static const u8 pae_group_addr[ETH_ALEN] __aligned(2)
2553ce3edf6dSJohannes Berg = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x03 };
2554ce3edf6dSJohannes Berg struct ethhdr *ehdr = (struct ethhdr *) rx->skb->data;
2555ce3edf6dSJohannes Berg
2556ce3edf6dSJohannes Berg /*
2557a8c4d76aSJohannes Berg * Allow EAPOL frames to us/the PAE group address regardless of
2558a8c4d76aSJohannes Berg * whether the frame was encrypted or not, and always disallow
2559a8c4d76aSJohannes Berg * all other destination addresses for them.
2560ce3edf6dSJohannes Berg */
2561a8c4d76aSJohannes Berg if (unlikely(ehdr->h_proto == rx->sdata->control_port_protocol))
2562d06faef1SAndrei Otcheretianski return ieee80211_is_our_addr(rx->sdata, ehdr->h_dest, NULL) ||
2563a8c4d76aSJohannes Berg ether_addr_equal(ehdr->h_dest, pae_group_addr);
2564ce3edf6dSJohannes Berg
2565ce3edf6dSJohannes Berg if (ieee80211_802_1x_port_control(rx) ||
2566358c8d9dSHarvey Harrison ieee80211_drop_unencrypted(rx, fc))
2567ce3edf6dSJohannes Berg return false;
2568ce3edf6dSJohannes Berg
2569ce3edf6dSJohannes Berg return true;
2570ce3edf6dSJohannes Berg }
2571ce3edf6dSJohannes Berg
ieee80211_deliver_skb_to_local_stack(struct sk_buff * skb,struct ieee80211_rx_data * rx)2572018f6fbfSDenis Kenzior static void ieee80211_deliver_skb_to_local_stack(struct sk_buff *skb,
2573018f6fbfSDenis Kenzior struct ieee80211_rx_data *rx)
2574018f6fbfSDenis Kenzior {
2575018f6fbfSDenis Kenzior struct ieee80211_sub_if_data *sdata = rx->sdata;
2576018f6fbfSDenis Kenzior struct net_device *dev = sdata->dev;
2577018f6fbfSDenis Kenzior
2578018f6fbfSDenis Kenzior if (unlikely((skb->protocol == sdata->control_port_protocol ||
25797f3f96ceSMarkus Theil (skb->protocol == cpu_to_be16(ETH_P_PREAUTH) &&
25807f3f96ceSMarkus Theil !sdata->control_port_no_preauth)) &&
2581018f6fbfSDenis Kenzior sdata->control_port_over_nl80211)) {
2582018f6fbfSDenis Kenzior struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
2583f8b43c5cSDenis Kenzior bool noencrypt = !(status->flag & RX_FLAG_DECRYPTED);
2584018f6fbfSDenis Kenzior
25854c532321SJohannes Berg cfg80211_rx_control_port(dev, skb, noencrypt, rx->link_id);
2586018f6fbfSDenis Kenzior dev_kfree_skb(skb);
2587018f6fbfSDenis Kenzior } else {
2588a8c4d76aSJohannes Berg struct ethhdr *ehdr = (void *)skb_mac_header(skb);
2589a8c4d76aSJohannes Berg
2590c8a41c6aSDenis Kenzior memset(skb->cb, 0, sizeof(skb->cb));
2591c8a41c6aSDenis Kenzior
2592a8c4d76aSJohannes Berg /*
2593a8c4d76aSJohannes Berg * 802.1X over 802.11 requires that the authenticator address
2594a8c4d76aSJohannes Berg * be used for EAPOL frames. However, 802.1X allows the use of
2595a8c4d76aSJohannes Berg * the PAE group address instead. If the interface is part of
2596a8c4d76aSJohannes Berg * a bridge and we pass the frame with the PAE group address,
2597a8c4d76aSJohannes Berg * then the bridge will forward it to the network (even if the
2598a8c4d76aSJohannes Berg * client was not associated yet), which isn't supposed to
2599a8c4d76aSJohannes Berg * happen.
2600a8c4d76aSJohannes Berg * To avoid that, rewrite the destination address to our own
2601a8c4d76aSJohannes Berg * address, so that the authenticator (e.g. hostapd) will see
2602a8c4d76aSJohannes Berg * the frame, but bridge won't forward it anywhere else. Note
2603a8c4d76aSJohannes Berg * that due to earlier filtering, the only other address can
2604610d086dSDeren Wu * be the PAE group address, unless the hardware allowed them
2605610d086dSDeren Wu * through in 802.3 offloaded mode.
2606a8c4d76aSJohannes Berg */
2607a8c4d76aSJohannes Berg if (unlikely(skb->protocol == sdata->control_port_protocol &&
2608a8c4d76aSJohannes Berg !ether_addr_equal(ehdr->h_dest, sdata->vif.addr)))
2609a8c4d76aSJohannes Berg ether_addr_copy(ehdr->h_dest, sdata->vif.addr);
2610a8c4d76aSJohannes Berg
2611018f6fbfSDenis Kenzior /* deliver to local stack */
2612c5d1686bSFelix Fietkau if (rx->list)
2613c5d1686bSFelix Fietkau list_add_tail(&skb->list, rx->list);
2614018f6fbfSDenis Kenzior else
2615018f6fbfSDenis Kenzior netif_receive_skb(skb);
2616018f6fbfSDenis Kenzior }
2617018f6fbfSDenis Kenzior }
2618018f6fbfSDenis Kenzior
2619ce3edf6dSJohannes Berg /*
2620ce3edf6dSJohannes Berg * requires that rx->skb is a frame with ethernet header
2621ce3edf6dSJohannes Berg */
262276ee65bfSRon Rindjunsky static void
ieee80211_deliver_skb(struct ieee80211_rx_data * rx)26235cf121c3SJohannes Berg ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
262476ee65bfSRon Rindjunsky {
2625eb9fb5b8SJohannes Berg struct ieee80211_sub_if_data *sdata = rx->sdata;
2626eb9fb5b8SJohannes Berg struct net_device *dev = sdata->dev;
262776ee65bfSRon Rindjunsky struct sk_buff *skb, *xmit_skb;
2628ce3edf6dSJohannes Berg struct ethhdr *ehdr = (struct ethhdr *) rx->skb->data;
2629ce3edf6dSJohannes Berg struct sta_info *dsta;
2630571ecf67SJohannes Berg
263176ee65bfSRon Rindjunsky skb = rx->skb;
263276ee65bfSRon Rindjunsky xmit_skb = NULL;
2633571ecf67SJohannes Berg
263436ec144fSLev Stipakov dev_sw_netstats_rx_add(dev, skb->len);
26355a490510SJohannes Berg
2636de8f18d3SJohannes Berg if (rx->sta) {
2637de8f18d3SJohannes Berg /* The seqno index has the same property as needed
2638de8f18d3SJohannes Berg * for the rx_msdu field, i.e. it is IEEE80211_NUM_TIDS
2639de8f18d3SJohannes Berg * for non-QoS-data frames. Here we know it's a data
2640de8f18d3SJohannes Berg * frame, so count MSDUs.
2641de8f18d3SJohannes Berg */
2642b320d6c4SBenjamin Berg u64_stats_update_begin(&rx->link_sta->rx_stats.syncp);
2643b320d6c4SBenjamin Berg rx->link_sta->rx_stats.msdu[rx->seqno_idx]++;
2644b320d6c4SBenjamin Berg u64_stats_update_end(&rx->link_sta->rx_stats.syncp);
2645de8f18d3SJohannes Berg }
2646de8f18d3SJohannes Berg
264705c914feSJohannes Berg if ((sdata->vif.type == NL80211_IFTYPE_AP ||
264805c914feSJohannes Berg sdata->vif.type == NL80211_IFTYPE_AP_VLAN) &&
2649213cd118SJohannes Berg !(sdata->flags & IEEE80211_SDATA_DONT_BRIDGE_PACKETS) &&
2650a8c4d76aSJohannes Berg ehdr->h_proto != rx->sdata->control_port_protocol &&
26519bc383deSJohannes Berg (sdata->vif.type != NL80211_IFTYPE_AP_VLAN || !sdata->u.vlan.sta)) {
265272f15d53SMichael Braun if (is_multicast_ether_addr(ehdr->h_dest) &&
265372f15d53SMichael Braun ieee80211_vif_get_num_mcast_if(sdata) != 0) {
2654ce3edf6dSJohannes Berg /*
2655ce3edf6dSJohannes Berg * send multicast frames both to higher layers in
2656ce3edf6dSJohannes Berg * local net stack and back to the wireless medium
2657ce3edf6dSJohannes Berg */
265876ee65bfSRon Rindjunsky xmit_skb = skb_copy(skb, GFP_ATOMIC);
2659e87cc472SJoe Perches if (!xmit_skb)
2660bdcbd8e0SJohannes Berg net_info_ratelimited("%s: failed to clone multicast frame\n",
2661e87cc472SJoe Perches dev->name);
266242dca5efSJohannes Berg } else if (!is_multicast_ether_addr(ehdr->h_dest) &&
266342dca5efSJohannes Berg !ether_addr_equal(ehdr->h_dest, ehdr->h_source)) {
266442dca5efSJohannes Berg dsta = sta_info_get(sdata, ehdr->h_dest);
2665abe60632SJohannes Berg if (dsta) {
2666ce3edf6dSJohannes Berg /*
2667ce3edf6dSJohannes Berg * The destination station is associated to
2668ce3edf6dSJohannes Berg * this AP (in this VLAN), so send the frame
2669ce3edf6dSJohannes Berg * directly to it and do not pass it to local
2670ce3edf6dSJohannes Berg * net stack.
2671571ecf67SJohannes Berg */
267276ee65bfSRon Rindjunsky xmit_skb = skb;
2673571ecf67SJohannes Berg skb = NULL;
2674571ecf67SJohannes Berg }
2675571ecf67SJohannes Berg }
2676571ecf67SJohannes Berg }
2677571ecf67SJohannes Berg
267859d9cb07SKalle Valo #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
26799e890a1fSJohannes Berg if (skb) {
26809e890a1fSJohannes Berg /* 'align' will only take the values 0 or 2 here since all
26819e890a1fSJohannes Berg * frames are required to be aligned to 2-byte boundaries
26829e890a1fSJohannes Berg * when being passed to mac80211; the code here works just
26839e890a1fSJohannes Berg * as well if that isn't true, but mac80211 assumes it can
26849e890a1fSJohannes Berg * access fields as 2-byte aligned (e.g. for ether_addr_equal)
2685d1c3a37cSJohannes Berg */
26869e890a1fSJohannes Berg int align;
26879e890a1fSJohannes Berg
26889e890a1fSJohannes Berg align = (unsigned long)(skb->data + sizeof(struct ethhdr)) & 3;
2689d1c3a37cSJohannes Berg if (align) {
2690d1c3a37cSJohannes Berg if (WARN_ON(skb_headroom(skb) < 3)) {
2691d1c3a37cSJohannes Berg dev_kfree_skb(skb);
2692d1c3a37cSJohannes Berg skb = NULL;
2693d1c3a37cSJohannes Berg } else {
2694d1c3a37cSJohannes Berg u8 *data = skb->data;
26958ce0b589SZhu Yi size_t len = skb_headlen(skb);
26968ce0b589SZhu Yi skb->data -= align;
26978ce0b589SZhu Yi memmove(skb->data, data, len);
26988ce0b589SZhu Yi skb_set_tail_pointer(skb, len);
2699d1c3a37cSJohannes Berg }
2700d1c3a37cSJohannes Berg }
27019e890a1fSJohannes Berg }
2702d1c3a37cSJohannes Berg #endif
2703d1c3a37cSJohannes Berg
2704d1c3a37cSJohannes Berg if (skb) {
2705571ecf67SJohannes Berg skb->protocol = eth_type_trans(skb, dev);
2706018f6fbfSDenis Kenzior ieee80211_deliver_skb_to_local_stack(skb, rx);
2707571ecf67SJohannes Berg }
2708571ecf67SJohannes Berg
270976ee65bfSRon Rindjunsky if (xmit_skb) {
2710aef6c928SHelmut Schaa /*
2711aef6c928SHelmut Schaa * Send to wireless media and increase priority by 256 to
2712aef6c928SHelmut Schaa * keep the received priority instead of reclassifying
2713aef6c928SHelmut Schaa * the frame (see cfg80211_classify8021d).
2714aef6c928SHelmut Schaa */
2715aef6c928SHelmut Schaa xmit_skb->priority += 256;
2716f831e909SYOSHIFUJI Hideaki xmit_skb->protocol = htons(ETH_P_802_3);
2717ce3edf6dSJohannes Berg skb_reset_network_header(xmit_skb);
2718ce3edf6dSJohannes Berg skb_reset_mac_header(xmit_skb);
271976ee65bfSRon Rindjunsky dev_queue_xmit(xmit_skb);
2720571ecf67SJohannes Berg }
272176ee65bfSRon Rindjunsky }
272276ee65bfSRon Rindjunsky
27238b0f5cb6SFelix Fietkau #ifdef CONFIG_MAC80211_MESH
27248b0f5cb6SFelix Fietkau static bool
ieee80211_rx_mesh_fast_forward(struct ieee80211_sub_if_data * sdata,struct sk_buff * skb,int hdrlen)27258b0f5cb6SFelix Fietkau ieee80211_rx_mesh_fast_forward(struct ieee80211_sub_if_data *sdata,
27268b0f5cb6SFelix Fietkau struct sk_buff *skb, int hdrlen)
27278b0f5cb6SFelix Fietkau {
27288b0f5cb6SFelix Fietkau struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
2729154be74eSFelix Fietkau struct ieee80211_mesh_fast_tx_key key = {
2730154be74eSFelix Fietkau .type = MESH_FAST_TX_TYPE_FORWARDED
2731154be74eSFelix Fietkau };
2732154be74eSFelix Fietkau struct ieee80211_mesh_fast_tx *entry;
27338b0f5cb6SFelix Fietkau struct ieee80211s_hdr *mesh_hdr;
27348b0f5cb6SFelix Fietkau struct tid_ampdu_tx *tid_tx;
27358b0f5cb6SFelix Fietkau struct sta_info *sta;
27368b0f5cb6SFelix Fietkau struct ethhdr eth;
27378b0f5cb6SFelix Fietkau u8 tid;
27388b0f5cb6SFelix Fietkau
27398b0f5cb6SFelix Fietkau mesh_hdr = (struct ieee80211s_hdr *)(skb->data + sizeof(eth));
27408b0f5cb6SFelix Fietkau if ((mesh_hdr->flags & MESH_FLAGS_AE) == MESH_FLAGS_AE_A5_A6)
2741154be74eSFelix Fietkau ether_addr_copy(key.addr, mesh_hdr->eaddr1);
27428b0f5cb6SFelix Fietkau else if (!(mesh_hdr->flags & MESH_FLAGS_AE))
2743154be74eSFelix Fietkau ether_addr_copy(key.addr, skb->data);
2744154be74eSFelix Fietkau else
2745154be74eSFelix Fietkau return false;
2746154be74eSFelix Fietkau
2747154be74eSFelix Fietkau entry = mesh_fast_tx_get(sdata, &key);
27488b0f5cb6SFelix Fietkau if (!entry)
27498b0f5cb6SFelix Fietkau return false;
27508b0f5cb6SFelix Fietkau
27518b0f5cb6SFelix Fietkau sta = rcu_dereference(entry->mpath->next_hop);
27528b0f5cb6SFelix Fietkau if (!sta)
27538b0f5cb6SFelix Fietkau return false;
27548b0f5cb6SFelix Fietkau
27558b0f5cb6SFelix Fietkau if (skb_linearize(skb))
27568b0f5cb6SFelix Fietkau return false;
27578b0f5cb6SFelix Fietkau
27588b0f5cb6SFelix Fietkau tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
27598b0f5cb6SFelix Fietkau tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[tid]);
27608b0f5cb6SFelix Fietkau if (tid_tx) {
27618b0f5cb6SFelix Fietkau if (!test_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state))
27628b0f5cb6SFelix Fietkau return false;
27638b0f5cb6SFelix Fietkau
27648b0f5cb6SFelix Fietkau if (tid_tx->timeout)
27658b0f5cb6SFelix Fietkau tid_tx->last_tx = jiffies;
27668b0f5cb6SFelix Fietkau }
27678b0f5cb6SFelix Fietkau
27688b0f5cb6SFelix Fietkau ieee80211_aggr_check(sdata, sta, skb);
27698b0f5cb6SFelix Fietkau
27708b0f5cb6SFelix Fietkau if (ieee80211_get_8023_tunnel_proto(skb->data + hdrlen,
27718b0f5cb6SFelix Fietkau &skb->protocol))
27728b0f5cb6SFelix Fietkau hdrlen += ETH_ALEN;
27738b0f5cb6SFelix Fietkau else
27748b0f5cb6SFelix Fietkau skb->protocol = htons(skb->len - hdrlen);
27758b0f5cb6SFelix Fietkau skb_set_network_header(skb, hdrlen + 2);
27768b0f5cb6SFelix Fietkau
27778b0f5cb6SFelix Fietkau skb->dev = sdata->dev;
27788b0f5cb6SFelix Fietkau memcpy(ð, skb->data, ETH_HLEN - 2);
27798b0f5cb6SFelix Fietkau skb_pull(skb, 2);
27808b0f5cb6SFelix Fietkau __ieee80211_xmit_fast(sdata, sta, &entry->fast_tx, skb, tid_tx,
27818b0f5cb6SFelix Fietkau eth.h_dest, eth.h_source);
27828b0f5cb6SFelix Fietkau IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_unicast);
27838b0f5cb6SFelix Fietkau IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_frames);
27848b0f5cb6SFelix Fietkau
27858b0f5cb6SFelix Fietkau return true;
27868b0f5cb6SFelix Fietkau }
27878b0f5cb6SFelix Fietkau #endif
27888b0f5cb6SFelix Fietkau
2789986e43b1SFelix Fietkau static ieee80211_rx_result
ieee80211_rx_mesh_data(struct ieee80211_sub_if_data * sdata,struct sta_info * sta,struct sk_buff * skb)2790986e43b1SFelix Fietkau ieee80211_rx_mesh_data(struct ieee80211_sub_if_data *sdata, struct sta_info *sta,
2791986e43b1SFelix Fietkau struct sk_buff *skb)
2792986e43b1SFelix Fietkau {
2793986e43b1SFelix Fietkau #ifdef CONFIG_MAC80211_MESH
2794986e43b1SFelix Fietkau struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
2795986e43b1SFelix Fietkau struct ieee80211_local *local = sdata->local;
2796986e43b1SFelix Fietkau uint16_t fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_DATA;
2797986e43b1SFelix Fietkau struct ieee80211_hdr hdr = {
2798986e43b1SFelix Fietkau .frame_control = cpu_to_le16(fc)
2799986e43b1SFelix Fietkau };
2800986e43b1SFelix Fietkau struct ieee80211_hdr *fwd_hdr;
2801986e43b1SFelix Fietkau struct ieee80211s_hdr *mesh_hdr;
2802986e43b1SFelix Fietkau struct ieee80211_tx_info *info;
2803986e43b1SFelix Fietkau struct sk_buff *fwd_skb;
2804986e43b1SFelix Fietkau struct ethhdr *eth;
2805986e43b1SFelix Fietkau bool multicast;
2806986e43b1SFelix Fietkau int tailroom = 0;
2807986e43b1SFelix Fietkau int hdrlen, mesh_hdrlen;
2808986e43b1SFelix Fietkau u8 *qos;
2809986e43b1SFelix Fietkau
2810986e43b1SFelix Fietkau if (!ieee80211_vif_is_mesh(&sdata->vif))
2811986e43b1SFelix Fietkau return RX_CONTINUE;
2812986e43b1SFelix Fietkau
2813986e43b1SFelix Fietkau if (!pskb_may_pull(skb, sizeof(*eth) + 6))
2814986e43b1SFelix Fietkau return RX_DROP_MONITOR;
2815986e43b1SFelix Fietkau
2816986e43b1SFelix Fietkau mesh_hdr = (struct ieee80211s_hdr *)(skb->data + sizeof(*eth));
2817986e43b1SFelix Fietkau mesh_hdrlen = ieee80211_get_mesh_hdrlen(mesh_hdr);
2818986e43b1SFelix Fietkau
2819986e43b1SFelix Fietkau if (!pskb_may_pull(skb, sizeof(*eth) + mesh_hdrlen))
2820986e43b1SFelix Fietkau return RX_DROP_MONITOR;
2821986e43b1SFelix Fietkau
2822986e43b1SFelix Fietkau eth = (struct ethhdr *)skb->data;
2823986e43b1SFelix Fietkau multicast = is_multicast_ether_addr(eth->h_dest);
2824986e43b1SFelix Fietkau
2825986e43b1SFelix Fietkau mesh_hdr = (struct ieee80211s_hdr *)(eth + 1);
2826986e43b1SFelix Fietkau if (!mesh_hdr->ttl)
2827986e43b1SFelix Fietkau return RX_DROP_MONITOR;
2828986e43b1SFelix Fietkau
2829986e43b1SFelix Fietkau /* frame is in RMC, don't forward */
2830986e43b1SFelix Fietkau if (is_multicast_ether_addr(eth->h_dest) &&
2831986e43b1SFelix Fietkau mesh_rmc_check(sdata, eth->h_source, mesh_hdr))
2832986e43b1SFelix Fietkau return RX_DROP_MONITOR;
2833986e43b1SFelix Fietkau
2834986e43b1SFelix Fietkau /* forward packet */
2835986e43b1SFelix Fietkau if (sdata->crypto_tx_tailroom_needed_cnt)
2836986e43b1SFelix Fietkau tailroom = IEEE80211_ENCRYPT_TAILROOM;
2837986e43b1SFelix Fietkau
2838986e43b1SFelix Fietkau if (mesh_hdr->flags & MESH_FLAGS_AE) {
2839986e43b1SFelix Fietkau struct mesh_path *mppath;
2840986e43b1SFelix Fietkau char *proxied_addr;
2841d5edb9aeSFelix Fietkau bool update = false;
2842986e43b1SFelix Fietkau
2843986e43b1SFelix Fietkau if (multicast)
2844986e43b1SFelix Fietkau proxied_addr = mesh_hdr->eaddr1;
2845986e43b1SFelix Fietkau else if ((mesh_hdr->flags & MESH_FLAGS_AE) == MESH_FLAGS_AE_A5_A6)
2846986e43b1SFelix Fietkau /* has_a4 already checked in ieee80211_rx_mesh_check */
2847986e43b1SFelix Fietkau proxied_addr = mesh_hdr->eaddr2;
2848986e43b1SFelix Fietkau else
2849986e43b1SFelix Fietkau return RX_DROP_MONITOR;
2850986e43b1SFelix Fietkau
2851986e43b1SFelix Fietkau rcu_read_lock();
2852986e43b1SFelix Fietkau mppath = mpp_path_lookup(sdata, proxied_addr);
2853986e43b1SFelix Fietkau if (!mppath) {
2854986e43b1SFelix Fietkau mpp_path_add(sdata, proxied_addr, eth->h_source);
2855986e43b1SFelix Fietkau } else {
2856986e43b1SFelix Fietkau spin_lock_bh(&mppath->state_lock);
2857d5edb9aeSFelix Fietkau if (!ether_addr_equal(mppath->mpp, eth->h_source)) {
2858986e43b1SFelix Fietkau memcpy(mppath->mpp, eth->h_source, ETH_ALEN);
2859d5edb9aeSFelix Fietkau update = true;
2860d5edb9aeSFelix Fietkau }
2861986e43b1SFelix Fietkau mppath->exp_time = jiffies;
2862986e43b1SFelix Fietkau spin_unlock_bh(&mppath->state_lock);
2863986e43b1SFelix Fietkau }
2864d5edb9aeSFelix Fietkau
2865d5edb9aeSFelix Fietkau /* flush fast xmit cache if the address path changed */
2866d5edb9aeSFelix Fietkau if (update)
2867d5edb9aeSFelix Fietkau mesh_fast_tx_flush_addr(sdata, proxied_addr);
2868d5edb9aeSFelix Fietkau
2869986e43b1SFelix Fietkau rcu_read_unlock();
2870986e43b1SFelix Fietkau }
2871986e43b1SFelix Fietkau
2872f355f701SFelix Fietkau /* Frame has reached destination. Don't forward */
2873f355f701SFelix Fietkau if (ether_addr_equal(sdata->vif.addr, eth->h_dest))
2874f355f701SFelix Fietkau goto rx_accept;
2875f355f701SFelix Fietkau
2876e26c0946SFelix Fietkau if (!--mesh_hdr->ttl) {
2877e26c0946SFelix Fietkau if (multicast)
2878e26c0946SFelix Fietkau goto rx_accept;
2879e26c0946SFelix Fietkau
2880e26c0946SFelix Fietkau IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_ttl);
2881e26c0946SFelix Fietkau return RX_DROP_MONITOR;
2882e26c0946SFelix Fietkau }
2883e26c0946SFelix Fietkau
2884f355f701SFelix Fietkau if (!ifmsh->mshcfg.dot11MeshForwarding) {
2885f355f701SFelix Fietkau if (is_multicast_ether_addr(eth->h_dest))
2886f355f701SFelix Fietkau goto rx_accept;
2887f355f701SFelix Fietkau
2888f355f701SFelix Fietkau return RX_DROP_MONITOR;
2889f355f701SFelix Fietkau }
2890f355f701SFelix Fietkau
2891986e43b1SFelix Fietkau skb_set_queue_mapping(skb, ieee802_1d_to_ac[skb->priority]);
2892986e43b1SFelix Fietkau
28938b0f5cb6SFelix Fietkau if (!multicast &&
28948b0f5cb6SFelix Fietkau ieee80211_rx_mesh_fast_forward(sdata, skb, mesh_hdrlen))
28958b0f5cb6SFelix Fietkau return RX_QUEUED;
28968b0f5cb6SFelix Fietkau
2897986e43b1SFelix Fietkau ieee80211_fill_mesh_addresses(&hdr, &hdr.frame_control,
2898986e43b1SFelix Fietkau eth->h_dest, eth->h_source);
2899986e43b1SFelix Fietkau hdrlen = ieee80211_hdrlen(hdr.frame_control);
2900986e43b1SFelix Fietkau if (multicast) {
2901986e43b1SFelix Fietkau int extra_head = sizeof(struct ieee80211_hdr) - sizeof(*eth);
2902986e43b1SFelix Fietkau
2903986e43b1SFelix Fietkau fwd_skb = skb_copy_expand(skb, local->tx_headroom + extra_head +
2904986e43b1SFelix Fietkau IEEE80211_ENCRYPT_HEADROOM,
2905986e43b1SFelix Fietkau tailroom, GFP_ATOMIC);
2906986e43b1SFelix Fietkau if (!fwd_skb)
2907986e43b1SFelix Fietkau goto rx_accept;
2908986e43b1SFelix Fietkau } else {
2909986e43b1SFelix Fietkau fwd_skb = skb;
2910986e43b1SFelix Fietkau skb = NULL;
2911986e43b1SFelix Fietkau
2912986e43b1SFelix Fietkau if (skb_cow_head(fwd_skb, hdrlen - sizeof(struct ethhdr)))
2913986e43b1SFelix Fietkau return RX_DROP_UNUSABLE;
29148f0149a8SFelix Fietkau
29158f0149a8SFelix Fietkau if (skb_linearize(fwd_skb))
29168f0149a8SFelix Fietkau return RX_DROP_UNUSABLE;
2917986e43b1SFelix Fietkau }
2918986e43b1SFelix Fietkau
2919986e43b1SFelix Fietkau fwd_hdr = skb_push(fwd_skb, hdrlen - sizeof(struct ethhdr));
2920986e43b1SFelix Fietkau memcpy(fwd_hdr, &hdr, hdrlen - 2);
2921986e43b1SFelix Fietkau qos = ieee80211_get_qos_ctl(fwd_hdr);
2922986e43b1SFelix Fietkau qos[0] = qos[1] = 0;
2923986e43b1SFelix Fietkau
2924986e43b1SFelix Fietkau skb_reset_mac_header(fwd_skb);
2925986e43b1SFelix Fietkau hdrlen += mesh_hdrlen;
2926986e43b1SFelix Fietkau if (ieee80211_get_8023_tunnel_proto(fwd_skb->data + hdrlen,
2927986e43b1SFelix Fietkau &fwd_skb->protocol))
2928986e43b1SFelix Fietkau hdrlen += ETH_ALEN;
2929986e43b1SFelix Fietkau else
2930986e43b1SFelix Fietkau fwd_skb->protocol = htons(fwd_skb->len - hdrlen);
2931899c2c11SFelix Fietkau skb_set_network_header(fwd_skb, hdrlen + 2);
2932986e43b1SFelix Fietkau
2933986e43b1SFelix Fietkau info = IEEE80211_SKB_CB(fwd_skb);
2934986e43b1SFelix Fietkau memset(info, 0, sizeof(*info));
2935986e43b1SFelix Fietkau info->control.flags |= IEEE80211_TX_INTCFL_NEED_TXPROCESSING;
2936986e43b1SFelix Fietkau info->control.vif = &sdata->vif;
2937986e43b1SFelix Fietkau info->control.jiffies = jiffies;
29388b0f5cb6SFelix Fietkau fwd_skb->dev = sdata->dev;
2939986e43b1SFelix Fietkau if (multicast) {
2940986e43b1SFelix Fietkau IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_mcast);
2941986e43b1SFelix Fietkau memcpy(fwd_hdr->addr2, sdata->vif.addr, ETH_ALEN);
2942986e43b1SFelix Fietkau /* update power mode indication when forwarding */
2943986e43b1SFelix Fietkau ieee80211_mps_set_frame_flags(sdata, NULL, fwd_hdr);
2944986e43b1SFelix Fietkau } else if (!mesh_nexthop_lookup(sdata, fwd_skb)) {
2945986e43b1SFelix Fietkau /* mesh power mode flags updated in mesh_nexthop_lookup */
2946986e43b1SFelix Fietkau IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_unicast);
2947986e43b1SFelix Fietkau } else {
2948986e43b1SFelix Fietkau /* unable to resolve next hop */
2949986e43b1SFelix Fietkau if (sta)
2950986e43b1SFelix Fietkau mesh_path_error_tx(sdata, ifmsh->mshcfg.element_ttl,
2951986e43b1SFelix Fietkau hdr.addr3, 0,
2952986e43b1SFelix Fietkau WLAN_REASON_MESH_PATH_NOFORWARD,
2953986e43b1SFelix Fietkau sta->sta.addr);
2954986e43b1SFelix Fietkau IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_no_route);
2955986e43b1SFelix Fietkau kfree_skb(fwd_skb);
2956986e43b1SFelix Fietkau goto rx_accept;
2957986e43b1SFelix Fietkau }
2958986e43b1SFelix Fietkau
2959986e43b1SFelix Fietkau IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_frames);
2960*69226421SAndy Strohman ieee80211_set_qos_hdr(sdata, fwd_skb);
2961986e43b1SFelix Fietkau ieee80211_add_pending_skb(local, fwd_skb);
2962986e43b1SFelix Fietkau
2963986e43b1SFelix Fietkau rx_accept:
2964986e43b1SFelix Fietkau if (!skb)
2965986e43b1SFelix Fietkau return RX_QUEUED;
2966986e43b1SFelix Fietkau
2967986e43b1SFelix Fietkau ieee80211_strip_8023_mesh_hdr(skb);
2968986e43b1SFelix Fietkau #endif
2969986e43b1SFelix Fietkau
2970986e43b1SFelix Fietkau return RX_CONTINUE;
2971986e43b1SFelix Fietkau }
2972986e43b1SFelix Fietkau
297349461622SJohannes Berg static ieee80211_rx_result debug_noinline
__ieee80211_rx_h_amsdu(struct ieee80211_rx_data * rx,u8 data_offset)297424bba078SFelix Fietkau __ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx, u8 data_offset)
2975fd4c7f2fSRon Rindjunsky {
2976eb9fb5b8SJohannes Berg struct net_device *dev = rx->sdata->dev;
2977eaf85ca7SZhu Yi struct sk_buff *skb = rx->skb;
2978358c8d9dSHarvey Harrison struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
2979358c8d9dSHarvey Harrison __le16 fc = hdr->frame_control;
2980eaf85ca7SZhu Yi struct sk_buff_head frame_list;
29814d78e032SFelix Fietkau ieee80211_rx_result res;
29827f6990c8SJohannes Berg struct ethhdr ethhdr;
2983e2b5227fSJohannes Berg const u8 *check_da = ethhdr.h_dest, *check_sa = ethhdr.h_source;
2984fd4c7f2fSRon Rindjunsky
2985ea720935SJohannes Berg if (unlikely(ieee80211_has_a4(hdr->frame_control))) {
2986e2b5227fSJohannes Berg check_da = NULL;
2987e2b5227fSJohannes Berg check_sa = NULL;
2988e2b5227fSJohannes Berg } else switch (rx->sdata->vif.type) {
2989e2b5227fSJohannes Berg case NL80211_IFTYPE_AP:
2990e2b5227fSJohannes Berg case NL80211_IFTYPE_AP_VLAN:
2991e2b5227fSJohannes Berg check_da = NULL;
2992e2b5227fSJohannes Berg break;
2993e2b5227fSJohannes Berg case NL80211_IFTYPE_STATION:
2994e2b5227fSJohannes Berg if (!rx->sta ||
2995e2b5227fSJohannes Berg !test_sta_flag(rx->sta, WLAN_STA_TDLS_PEER))
2996e2b5227fSJohannes Berg check_sa = NULL;
2997e2b5227fSJohannes Berg break;
2998e2b5227fSJohannes Berg case NL80211_IFTYPE_MESH_POINT:
2999e2b5227fSJohannes Berg check_sa = NULL;
3000986e43b1SFelix Fietkau check_da = NULL;
3001e2b5227fSJohannes Berg break;
3002e2b5227fSJohannes Berg default:
3003e2b5227fSJohannes Berg break;
3004ea720935SJohannes Berg }
3005eaf85ca7SZhu Yi
3006fd4c7f2fSRon Rindjunsky skb->dev = dev;
3007eaf85ca7SZhu Yi __skb_queue_head_init(&frame_list);
3008fd4c7f2fSRon Rindjunsky
30097f6990c8SJohannes Berg if (ieee80211_data_to_8023_exthdr(skb, ðhdr,
30107f6990c8SJohannes Berg rx->sdata->vif.addr,
301124bba078SFelix Fietkau rx->sdata->vif.type,
3012a1d5ff56SMathy Vanhoef data_offset, true))
30137f6990c8SJohannes Berg return RX_DROP_UNUSABLE;
30147f6990c8SJohannes Berg
3015a16fc383SFelix Fietkau if (rx->sta->amsdu_mesh_control < 0) {
3016fe4a6d2dSFelix Fietkau s8 valid = -1;
3017fe4a6d2dSFelix Fietkau int i;
30186e4c0d04SFelix Fietkau
3019fe4a6d2dSFelix Fietkau for (i = 0; i <= 2; i++) {
3020fe4a6d2dSFelix Fietkau if (!ieee80211_is_valid_amsdu(skb, i))
3021fe4a6d2dSFelix Fietkau continue;
3022fe4a6d2dSFelix Fietkau
3023fe4a6d2dSFelix Fietkau if (valid >= 0) {
3024fe4a6d2dSFelix Fietkau /* ambiguous */
3025fe4a6d2dSFelix Fietkau valid = -1;
3026fe4a6d2dSFelix Fietkau break;
3027fe4a6d2dSFelix Fietkau }
3028fe4a6d2dSFelix Fietkau
3029fe4a6d2dSFelix Fietkau valid = i;
3030fe4a6d2dSFelix Fietkau }
3031fe4a6d2dSFelix Fietkau
3032fe4a6d2dSFelix Fietkau rx->sta->amsdu_mesh_control = valid;
30336e4c0d04SFelix Fietkau }
30346e4c0d04SFelix Fietkau
3035eaf85ca7SZhu Yi ieee80211_amsdu_to_8023s(skb, &frame_list, dev->dev_addr,
3036eaf85ca7SZhu Yi rx->sdata->vif.type,
30378b935ee2SJohannes Berg rx->local->hw.extra_tx_headroom,
30386e4c0d04SFelix Fietkau check_da, check_sa,
30396e4c0d04SFelix Fietkau rx->sta->amsdu_mesh_control);
3040fd4c7f2fSRon Rindjunsky
3041eaf85ca7SZhu Yi while (!skb_queue_empty(&frame_list)) {
3042eaf85ca7SZhu Yi rx->skb = __skb_dequeue(&frame_list);
3043fd4c7f2fSRon Rindjunsky
3044986e43b1SFelix Fietkau res = ieee80211_rx_mesh_data(rx->sdata, rx->sta, rx->skb);
3045986e43b1SFelix Fietkau switch (res) {
3046986e43b1SFelix Fietkau case RX_QUEUED:
3047ce3edf6dSJohannes Berg continue;
3048986e43b1SFelix Fietkau case RX_CONTINUE:
3049986e43b1SFelix Fietkau break;
3050986e43b1SFelix Fietkau default:
3051986e43b1SFelix Fietkau goto free;
3052ce3edf6dSJohannes Berg }
3053fd4c7f2fSRon Rindjunsky
3054986e43b1SFelix Fietkau if (!ieee80211_frame_allowed(rx, fc))
3055986e43b1SFelix Fietkau goto free;
3056986e43b1SFelix Fietkau
3057fd4c7f2fSRon Rindjunsky ieee80211_deliver_skb(rx);
3058986e43b1SFelix Fietkau continue;
3059986e43b1SFelix Fietkau
3060986e43b1SFelix Fietkau free:
3061986e43b1SFelix Fietkau dev_kfree_skb(rx->skb);
3062fd4c7f2fSRon Rindjunsky }
3063fd4c7f2fSRon Rindjunsky
30649ae54c84SJohannes Berg return RX_QUEUED;
3065fd4c7f2fSRon Rindjunsky }
3066fd4c7f2fSRon Rindjunsky
306724bba078SFelix Fietkau static ieee80211_rx_result debug_noinline
ieee80211_rx_h_amsdu(struct ieee80211_rx_data * rx)306824bba078SFelix Fietkau ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx)
306924bba078SFelix Fietkau {
307024bba078SFelix Fietkau struct sk_buff *skb = rx->skb;
307124bba078SFelix Fietkau struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
307224bba078SFelix Fietkau struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
307324bba078SFelix Fietkau __le16 fc = hdr->frame_control;
307424bba078SFelix Fietkau
307524bba078SFelix Fietkau if (!(status->rx_flags & IEEE80211_RX_AMSDU))
307624bba078SFelix Fietkau return RX_CONTINUE;
307724bba078SFelix Fietkau
307824bba078SFelix Fietkau if (unlikely(!ieee80211_is_data(fc)))
307924bba078SFelix Fietkau return RX_CONTINUE;
308024bba078SFelix Fietkau
308124bba078SFelix Fietkau if (unlikely(!ieee80211_is_data_present(fc)))
308224bba078SFelix Fietkau return RX_DROP_MONITOR;
308324bba078SFelix Fietkau
308424bba078SFelix Fietkau if (unlikely(ieee80211_has_a4(hdr->frame_control))) {
308524bba078SFelix Fietkau switch (rx->sdata->vif.type) {
308624bba078SFelix Fietkau case NL80211_IFTYPE_AP_VLAN:
308724bba078SFelix Fietkau if (!rx->sdata->u.vlan.sta)
308824bba078SFelix Fietkau return RX_DROP_UNUSABLE;
308924bba078SFelix Fietkau break;
309024bba078SFelix Fietkau case NL80211_IFTYPE_STATION:
309124bba078SFelix Fietkau if (!rx->sdata->u.mgd.use_4addr)
309224bba078SFelix Fietkau return RX_DROP_UNUSABLE;
309324bba078SFelix Fietkau break;
3094986e43b1SFelix Fietkau case NL80211_IFTYPE_MESH_POINT:
3095986e43b1SFelix Fietkau break;
309624bba078SFelix Fietkau default:
309724bba078SFelix Fietkau return RX_DROP_UNUSABLE;
309824bba078SFelix Fietkau }
309924bba078SFelix Fietkau }
310024bba078SFelix Fietkau
3101a16fc383SFelix Fietkau if (is_multicast_ether_addr(hdr->addr1) || !rx->sta)
310224bba078SFelix Fietkau return RX_DROP_UNUSABLE;
310324bba078SFelix Fietkau
3104270032a2SJohannes Berg if (rx->key) {
3105270032a2SJohannes Berg /*
3106270032a2SJohannes Berg * We should not receive A-MSDUs on pre-HT connections,
3107270032a2SJohannes Berg * and HT connections cannot use old ciphers. Thus drop
3108270032a2SJohannes Berg * them, as in those cases we couldn't even have SPP
3109270032a2SJohannes Berg * A-MSDUs or such.
3110270032a2SJohannes Berg */
3111270032a2SJohannes Berg switch (rx->key->conf.cipher) {
3112270032a2SJohannes Berg case WLAN_CIPHER_SUITE_WEP40:
3113270032a2SJohannes Berg case WLAN_CIPHER_SUITE_WEP104:
3114270032a2SJohannes Berg case WLAN_CIPHER_SUITE_TKIP:
3115270032a2SJohannes Berg return RX_DROP_UNUSABLE;
3116270032a2SJohannes Berg default:
3117270032a2SJohannes Berg break;
3118270032a2SJohannes Berg }
3119270032a2SJohannes Berg }
3120270032a2SJohannes Berg
312124bba078SFelix Fietkau return __ieee80211_rx_h_amsdu(rx, 0);
312224bba078SFelix Fietkau }
312324bba078SFelix Fietkau
3124e32f85f7SLuis Carlos Cobo static ieee80211_rx_result debug_noinline
ieee80211_rx_h_data(struct ieee80211_rx_data * rx)31255cf121c3SJohannes Berg ieee80211_rx_h_data(struct ieee80211_rx_data *rx)
312676ee65bfSRon Rindjunsky {
3127eb9fb5b8SJohannes Berg struct ieee80211_sub_if_data *sdata = rx->sdata;
3128e15276a4SVivek Natarajan struct ieee80211_local *local = rx->local;
3129eb9fb5b8SJohannes Berg struct net_device *dev = sdata->dev;
3130358c8d9dSHarvey Harrison struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
3131358c8d9dSHarvey Harrison __le16 fc = hdr->frame_control;
31324d78e032SFelix Fietkau ieee80211_rx_result res;
31334114fa21SFelix Fietkau bool port_control;
3134ce3edf6dSJohannes Berg int err;
313576ee65bfSRon Rindjunsky
3136358c8d9dSHarvey Harrison if (unlikely(!ieee80211_is_data(hdr->frame_control)))
31379ae54c84SJohannes Berg return RX_CONTINUE;
313876ee65bfSRon Rindjunsky
3139358c8d9dSHarvey Harrison if (unlikely(!ieee80211_is_data_present(hdr->frame_control)))
3140e4c26addSJohannes Berg return RX_DROP_MONITOR;
314176ee65bfSRon Rindjunsky
3142f14543eeSFelix Fietkau /*
3143e7f4a940SJohannes Berg * Send unexpected-4addr-frame event to hostapd. For older versions,
3144e7f4a940SJohannes Berg * also drop the frame to cooked monitor interfaces.
3145f14543eeSFelix Fietkau */
3146f14543eeSFelix Fietkau if (ieee80211_has_a4(hdr->frame_control) &&
3147e7f4a940SJohannes Berg sdata->vif.type == NL80211_IFTYPE_AP) {
3148e7f4a940SJohannes Berg if (rx->sta &&
3149e7f4a940SJohannes Berg !test_and_set_sta_flag(rx->sta, WLAN_STA_4ADDR_EVENT))
3150e7f4a940SJohannes Berg cfg80211_rx_unexpected_4addr_frame(
3151e7f4a940SJohannes Berg rx->sdata->dev, rx->sta->sta.addr, GFP_ATOMIC);
3152f14543eeSFelix Fietkau return RX_DROP_MONITOR;
3153e7f4a940SJohannes Berg }
3154f14543eeSFelix Fietkau
31554114fa21SFelix Fietkau err = __ieee80211_data_to_8023(rx, &port_control);
315676ee65bfSRon Rindjunsky if (unlikely(err))
3157e4c26addSJohannes Berg return RX_DROP_UNUSABLE;
315876ee65bfSRon Rindjunsky
3159986e43b1SFelix Fietkau res = ieee80211_rx_mesh_data(rx->sdata, rx->sta, rx->skb);
3160986e43b1SFelix Fietkau if (res != RX_CONTINUE)
3161986e43b1SFelix Fietkau return res;
3162986e43b1SFelix Fietkau
3163358c8d9dSHarvey Harrison if (!ieee80211_frame_allowed(rx, fc))
3164e4c26addSJohannes Berg return RX_DROP_MONITOR;
3165ce3edf6dSJohannes Berg
31668a4d32f3SArik Nemtsov /* directly handle TDLS channel switch requests/responses */
31678a4d32f3SArik Nemtsov if (unlikely(((struct ethhdr *)rx->skb->data)->h_proto ==
31688a4d32f3SArik Nemtsov cpu_to_be16(ETH_P_TDLS))) {
31698a4d32f3SArik Nemtsov struct ieee80211_tdls_data *tf = (void *)rx->skb->data;
31708a4d32f3SArik Nemtsov
31718a4d32f3SArik Nemtsov if (pskb_may_pull(rx->skb,
31728a4d32f3SArik Nemtsov offsetof(struct ieee80211_tdls_data, u)) &&
31738a4d32f3SArik Nemtsov tf->payload_type == WLAN_TDLS_SNAP_RFTYPE &&
31748a4d32f3SArik Nemtsov tf->category == WLAN_CATEGORY_TDLS &&
31758a4d32f3SArik Nemtsov (tf->action_code == WLAN_TDLS_CHANNEL_SWITCH_REQUEST ||
31768a4d32f3SArik Nemtsov tf->action_code == WLAN_TDLS_CHANNEL_SWITCH_RESPONSE)) {
3177f057d140SJohannes Berg rx->skb->protocol = cpu_to_be16(ETH_P_TDLS);
31784f6c78deSJohannes Berg __ieee80211_queue_skb_to_iface(sdata, rx->link_id,
31794f6c78deSJohannes Berg rx->sta, rx->skb);
31808a4d32f3SArik Nemtsov return RX_QUEUED;
31818a4d32f3SArik Nemtsov }
31828a4d32f3SArik Nemtsov }
31838a4d32f3SArik Nemtsov
31844114fa21SFelix Fietkau if (rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
31854114fa21SFelix Fietkau unlikely(port_control) && sdata->bss) {
31864114fa21SFelix Fietkau sdata = container_of(sdata->bss, struct ieee80211_sub_if_data,
31874114fa21SFelix Fietkau u.ap);
31884114fa21SFelix Fietkau dev = sdata->dev;
31894114fa21SFelix Fietkau rx->sdata = sdata;
31904114fa21SFelix Fietkau }
31914114fa21SFelix Fietkau
319276ee65bfSRon Rindjunsky rx->skb->dev = dev;
319376ee65bfSRon Rindjunsky
3194602fae42SJohannes Berg if (!ieee80211_hw_check(&local->hw, SUPPORTS_DYNAMIC_PS) &&
3195602fae42SJohannes Berg local->ps_sdata && local->hw.conf.dynamic_ps_timeout > 0 &&
31968c99f691SRajkumar Manoharan !is_multicast_ether_addr(
31978c99f691SRajkumar Manoharan ((struct ethhdr *)rx->skb->data)->h_dest) &&
31988c99f691SRajkumar Manoharan (!local->scanning &&
3199602fae42SJohannes Berg !test_bit(SDATA_STATE_OFFCHANNEL, &sdata->state)))
3200e15276a4SVivek Natarajan mod_timer(&local->dynamic_ps_timer, jiffies +
3201e15276a4SVivek Natarajan msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout));
3202e15276a4SVivek Natarajan
320376ee65bfSRon Rindjunsky ieee80211_deliver_skb(rx);
3204571ecf67SJohannes Berg
32059ae54c84SJohannes Berg return RX_QUEUED;
3206571ecf67SJohannes Berg }
3207571ecf67SJohannes Berg
320849461622SJohannes Berg static ieee80211_rx_result debug_noinline
ieee80211_rx_h_ctrl(struct ieee80211_rx_data * rx,struct sk_buff_head * frames)3209f9e124fbSChristian Lamparter ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx, struct sk_buff_head *frames)
321071364716SRon Rindjunsky {
321171364716SRon Rindjunsky struct sk_buff *skb = rx->skb;
321271364716SRon Rindjunsky struct ieee80211_bar *bar = (struct ieee80211_bar *)skb->data;
321371364716SRon Rindjunsky struct tid_ampdu_rx *tid_agg_rx;
321471364716SRon Rindjunsky u16 start_seq_num;
321571364716SRon Rindjunsky u16 tid;
321671364716SRon Rindjunsky
3217a7767f95SHarvey Harrison if (likely(!ieee80211_is_ctl(bar->frame_control)))
32189ae54c84SJohannes Berg return RX_CONTINUE;
321971364716SRon Rindjunsky
3220a7767f95SHarvey Harrison if (ieee80211_is_back_req(bar->frame_control)) {
32218ae5977fSJohannes Berg struct {
32228ae5977fSJohannes Berg __le16 control, start_seq_num;
32238ae5977fSJohannes Berg } __packed bar_data;
32246382246eSEmmanuel Grumbach struct ieee80211_event event = {
32256382246eSEmmanuel Grumbach .type = BAR_RX_EVENT,
32266382246eSEmmanuel Grumbach };
32278ae5977fSJohannes Berg
322871364716SRon Rindjunsky if (!rx->sta)
3229a02ae758SJohannes Berg return RX_DROP_MONITOR;
32308ae5977fSJohannes Berg
32318ae5977fSJohannes Berg if (skb_copy_bits(skb, offsetof(struct ieee80211_bar, control),
32328ae5977fSJohannes Berg &bar_data, sizeof(bar_data)))
32338ae5977fSJohannes Berg return RX_DROP_MONITOR;
32348ae5977fSJohannes Berg
32358ae5977fSJohannes Berg tid = le16_to_cpu(bar_data.control) >> 12;
3236a87f736dSJohannes Berg
323753f24974SJohannes Berg if (!test_bit(tid, rx->sta->ampdu_mlme.agg_session_valid) &&
323853f24974SJohannes Berg !test_and_set_bit(tid, rx->sta->ampdu_mlme.unexpected_agg))
323953f24974SJohannes Berg ieee80211_send_delba(rx->sdata, rx->sta->sta.addr, tid,
324053f24974SJohannes Berg WLAN_BACK_RECIPIENT,
324153f24974SJohannes Berg WLAN_REASON_QSTA_REQUIRE_SETUP);
324253f24974SJohannes Berg
3243a87f736dSJohannes Berg tid_agg_rx = rcu_dereference(rx->sta->ampdu_mlme.tid_rx[tid]);
3244a87f736dSJohannes Berg if (!tid_agg_rx)
3245a02ae758SJohannes Berg return RX_DROP_MONITOR;
324671364716SRon Rindjunsky
32478ae5977fSJohannes Berg start_seq_num = le16_to_cpu(bar_data.start_seq_num) >> 4;
32486382246eSEmmanuel Grumbach event.u.ba.tid = tid;
32496382246eSEmmanuel Grumbach event.u.ba.ssn = start_seq_num;
32506382246eSEmmanuel Grumbach event.u.ba.sta = &rx->sta->sta;
325171364716SRon Rindjunsky
325271364716SRon Rindjunsky /* reset session timer */
325320ad19d0SJohannes Berg if (tid_agg_rx->timeout)
325420ad19d0SJohannes Berg mod_timer(&tid_agg_rx->session_timer,
325520ad19d0SJohannes Berg TU_TO_EXP_TIME(tid_agg_rx->timeout));
325671364716SRon Rindjunsky
3257dd318575SJohannes Berg spin_lock(&tid_agg_rx->reorder_lock);
3258a02ae758SJohannes Berg /* release stored frames up to start of BAR */
3259d3b2fb53SJohannes Berg ieee80211_release_reorder_frames(rx->sdata, tid_agg_rx,
3260f9e124fbSChristian Lamparter start_seq_num, frames);
3261dd318575SJohannes Berg spin_unlock(&tid_agg_rx->reorder_lock);
3262dd318575SJohannes Berg
32636382246eSEmmanuel Grumbach drv_event_callback(rx->local, rx->sdata, &event);
32646382246eSEmmanuel Grumbach
3265a02ae758SJohannes Berg kfree_skb(skb);
3266a02ae758SJohannes Berg return RX_QUEUED;
326771364716SRon Rindjunsky }
326871364716SRon Rindjunsky
326908daecaeSJohannes Berg /*
327008daecaeSJohannes Berg * After this point, we only want management frames,
327108daecaeSJohannes Berg * so we can drop all remaining control frames to
327208daecaeSJohannes Berg * cooked monitor interfaces.
327308daecaeSJohannes Berg */
327408daecaeSJohannes Berg return RX_DROP_MONITOR;
327571364716SRon Rindjunsky }
327671364716SRon Rindjunsky
ieee80211_process_sa_query_req(struct ieee80211_sub_if_data * sdata,struct ieee80211_mgmt * mgmt,size_t len)3277f4f727a6SJouni Malinen static void ieee80211_process_sa_query_req(struct ieee80211_sub_if_data *sdata,
3278fea14732SJouni Malinen struct ieee80211_mgmt *mgmt,
3279fea14732SJouni Malinen size_t len)
3280fea14732SJouni Malinen {
3281fea14732SJouni Malinen struct ieee80211_local *local = sdata->local;
3282fea14732SJouni Malinen struct sk_buff *skb;
3283fea14732SJouni Malinen struct ieee80211_mgmt *resp;
3284fea14732SJouni Malinen
3285b203ca39SJoe Perches if (!ether_addr_equal(mgmt->da, sdata->vif.addr)) {
3286fea14732SJouni Malinen /* Not to own unicast address */
3287fea14732SJouni Malinen return;
3288fea14732SJouni Malinen }
3289fea14732SJouni Malinen
3290bfd8403aSJohannes Berg if (!ether_addr_equal(mgmt->sa, sdata->deflink.u.mgd.bssid) ||
3291bfd8403aSJohannes Berg !ether_addr_equal(mgmt->bssid, sdata->deflink.u.mgd.bssid)) {
329277fdaa12SJohannes Berg /* Not from the current AP or not associated yet. */
3293fea14732SJouni Malinen return;
3294fea14732SJouni Malinen }
3295fea14732SJouni Malinen
3296fea14732SJouni Malinen if (len < 24 + 1 + sizeof(resp->u.action.u.sa_query)) {
3297fea14732SJouni Malinen /* Too short SA Query request frame */
3298fea14732SJouni Malinen return;
3299fea14732SJouni Malinen }
3300fea14732SJouni Malinen
3301fea14732SJouni Malinen skb = dev_alloc_skb(sizeof(*resp) + local->hw.extra_tx_headroom);
3302fea14732SJouni Malinen if (skb == NULL)
3303fea14732SJouni Malinen return;
3304fea14732SJouni Malinen
3305fea14732SJouni Malinen skb_reserve(skb, local->hw.extra_tx_headroom);
3306b080db58SJohannes Berg resp = skb_put_zero(skb, 24);
3307fea14732SJouni Malinen memcpy(resp->da, mgmt->sa, ETH_ALEN);
330847846c9bSJohannes Berg memcpy(resp->sa, sdata->vif.addr, ETH_ALEN);
3309bfd8403aSJohannes Berg memcpy(resp->bssid, sdata->deflink.u.mgd.bssid, ETH_ALEN);
3310fea14732SJouni Malinen resp->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
3311fea14732SJouni Malinen IEEE80211_STYPE_ACTION);
3312fea14732SJouni Malinen skb_put(skb, 1 + sizeof(resp->u.action.u.sa_query));
3313fea14732SJouni Malinen resp->u.action.category = WLAN_CATEGORY_SA_QUERY;
3314fea14732SJouni Malinen resp->u.action.u.sa_query.action = WLAN_ACTION_SA_QUERY_RESPONSE;
3315fea14732SJouni Malinen memcpy(resp->u.action.u.sa_query.trans_id,
3316fea14732SJouni Malinen mgmt->u.action.u.sa_query.trans_id,
3317fea14732SJouni Malinen WLAN_SA_QUERY_TR_ID_LEN);
3318fea14732SJouni Malinen
331962ae67beSJohannes Berg ieee80211_tx_skb(sdata, skb);
3320fea14732SJouni Malinen }
3321fea14732SJouni Malinen
33226d945a33SLorenzo Bianconi static void
ieee80211_rx_check_bss_color_collision(struct ieee80211_rx_data * rx)33236d945a33SLorenzo Bianconi ieee80211_rx_check_bss_color_collision(struct ieee80211_rx_data *rx)
33246d945a33SLorenzo Bianconi {
33256d945a33SLorenzo Bianconi struct ieee80211_mgmt *mgmt = (void *)rx->skb->data;
33266d945a33SLorenzo Bianconi const struct element *ie;
33276d945a33SLorenzo Bianconi size_t baselen;
33286d945a33SLorenzo Bianconi
33296d945a33SLorenzo Bianconi if (!wiphy_ext_feature_isset(rx->local->hw.wiphy,
33306d945a33SLorenzo Bianconi NL80211_EXT_FEATURE_BSS_COLOR))
33316d945a33SLorenzo Bianconi return;
33326d945a33SLorenzo Bianconi
33336d945a33SLorenzo Bianconi if (ieee80211_hw_check(&rx->local->hw, DETECTS_COLOR_COLLISION))
33346d945a33SLorenzo Bianconi return;
33356d945a33SLorenzo Bianconi
3336d0a9123eSJohannes Berg if (rx->sdata->vif.bss_conf.csa_active)
33376d945a33SLorenzo Bianconi return;
33386d945a33SLorenzo Bianconi
33396d945a33SLorenzo Bianconi baselen = mgmt->u.beacon.variable - rx->skb->data;
33406d945a33SLorenzo Bianconi if (baselen > rx->skb->len)
33416d945a33SLorenzo Bianconi return;
33426d945a33SLorenzo Bianconi
33436d945a33SLorenzo Bianconi ie = cfg80211_find_ext_elem(WLAN_EID_EXT_HE_OPERATION,
33446d945a33SLorenzo Bianconi mgmt->u.beacon.variable,
33456d945a33SLorenzo Bianconi rx->skb->len - baselen);
33466d945a33SLorenzo Bianconi if (ie && ie->datalen >= sizeof(struct ieee80211_he_operation) &&
33476d945a33SLorenzo Bianconi ie->datalen >= ieee80211_he_oper_size(ie->data + 1)) {
33486d945a33SLorenzo Bianconi struct ieee80211_bss_conf *bss_conf = &rx->sdata->vif.bss_conf;
33496d945a33SLorenzo Bianconi const struct ieee80211_he_operation *he_oper;
33506d945a33SLorenzo Bianconi u8 color;
33516d945a33SLorenzo Bianconi
33526d945a33SLorenzo Bianconi he_oper = (void *)(ie->data + 1);
33536d945a33SLorenzo Bianconi if (le32_get_bits(he_oper->he_oper_params,
33546d945a33SLorenzo Bianconi IEEE80211_HE_OPERATION_BSS_COLOR_DISABLED))
33556d945a33SLorenzo Bianconi return;
33566d945a33SLorenzo Bianconi
33576d945a33SLorenzo Bianconi color = le32_get_bits(he_oper->he_oper_params,
33586d945a33SLorenzo Bianconi IEEE80211_HE_OPERATION_BSS_COLOR_MASK);
33596d945a33SLorenzo Bianconi if (color == bss_conf->he_bss_color.color)
336082253ddaSJohannes Berg ieee80211_obss_color_collision_notify(&rx->sdata->vif,
336103895c84SLorenzo Bianconi BIT_ULL(color),
336203895c84SLorenzo Bianconi GFP_ATOMIC);
33636d945a33SLorenzo Bianconi }
33646d945a33SLorenzo Bianconi }
33656d945a33SLorenzo Bianconi
336649461622SJohannes Berg static ieee80211_rx_result debug_noinline
ieee80211_rx_h_mgmt_check(struct ieee80211_rx_data * rx)33672e161f78SJohannes Berg ieee80211_rx_h_mgmt_check(struct ieee80211_rx_data *rx)
33682e161f78SJohannes Berg {
33692e161f78SJohannes Berg struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data;
3370554891e6SJohannes Berg struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
33712e161f78SJohannes Berg
337209a740ceSThomas Pedersen if (ieee80211_is_s1g_beacon(mgmt->frame_control))
337309a740ceSThomas Pedersen return RX_CONTINUE;
337409a740ceSThomas Pedersen
33752e161f78SJohannes Berg /*
33762e161f78SJohannes Berg * From here on, look only at management frames.
33772e161f78SJohannes Berg * Data and control frames are already handled,
33782e161f78SJohannes Berg * and unknown (reserved) frames are useless.
33792e161f78SJohannes Berg */
33802e161f78SJohannes Berg if (rx->skb->len < 24)
33812e161f78SJohannes Berg return RX_DROP_MONITOR;
33822e161f78SJohannes Berg
33832e161f78SJohannes Berg if (!ieee80211_is_mgmt(mgmt->frame_control))
33842e161f78SJohannes Berg return RX_DROP_MONITOR;
33852e161f78SJohannes Berg
33862cc7add3SJohannes Berg /* drop too small action frames */
33872cc7add3SJohannes Berg if (ieee80211_is_action(mgmt->frame_control) &&
33882cc7add3SJohannes Berg rx->skb->len < IEEE80211_MIN_ACTION_SIZE)
33892cc7add3SJohannes Berg return RX_DROP_UNUSABLE;
33902cc7add3SJohannes Berg
3391ee971924SJohannes Berg if (rx->sdata->vif.type == NL80211_IFTYPE_AP &&
3392ee971924SJohannes Berg ieee80211_is_beacon(mgmt->frame_control) &&
3393ee971924SJohannes Berg !(rx->flags & IEEE80211_RX_BEACON_REPORTED)) {
3394804483e9SJohannes Berg int sig = 0;
3395804483e9SJohannes Berg
33966d945a33SLorenzo Bianconi /* sw bss color collision detection */
33976d945a33SLorenzo Bianconi ieee80211_rx_check_bss_color_collision(rx);
33986d945a33SLorenzo Bianconi
33991ad22fb5STosoni if (ieee80211_hw_check(&rx->local->hw, SIGNAL_DBM) &&
34001ad22fb5STosoni !(status->flag & RX_FLAG_NO_SIGNAL_VAL))
3401804483e9SJohannes Berg sig = status->signal;
3402804483e9SJohannes Berg
3403e76fede8SThomas Pedersen cfg80211_report_obss_beacon_khz(rx->local->hw.wiphy,
3404ee971924SJohannes Berg rx->skb->data, rx->skb->len,
3405e76fede8SThomas Pedersen ieee80211_rx_status_to_khz(status),
3406e76fede8SThomas Pedersen sig);
3407ee971924SJohannes Berg rx->flags |= IEEE80211_RX_BEACON_REPORTED;
3408ee971924SJohannes Berg }
3409ee971924SJohannes Berg
34102e161f78SJohannes Berg if (ieee80211_drop_unencrypted_mgmt(rx))
34112e161f78SJohannes Berg return RX_DROP_UNUSABLE;
34122e161f78SJohannes Berg
34132e161f78SJohannes Berg return RX_CONTINUE;
34142e161f78SJohannes Berg }
34152e161f78SJohannes Berg
3416f5a4c24eSLorenzo Bianconi static bool
ieee80211_process_rx_twt_action(struct ieee80211_rx_data * rx)3417f5a4c24eSLorenzo Bianconi ieee80211_process_rx_twt_action(struct ieee80211_rx_data *rx)
3418f5a4c24eSLorenzo Bianconi {
3419f5a4c24eSLorenzo Bianconi struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)rx->skb->data;
3420f5a4c24eSLorenzo Bianconi struct ieee80211_sub_if_data *sdata = rx->sdata;
3421f5a4c24eSLorenzo Bianconi
3422f5a4c24eSLorenzo Bianconi /* TWT actions are only supported in AP for the moment */
3423f5a4c24eSLorenzo Bianconi if (sdata->vif.type != NL80211_IFTYPE_AP)
3424f5a4c24eSLorenzo Bianconi return false;
3425f5a4c24eSLorenzo Bianconi
3426f5a4c24eSLorenzo Bianconi if (!rx->local->ops->add_twt_setup)
3427f5a4c24eSLorenzo Bianconi return false;
3428f5a4c24eSLorenzo Bianconi
342968ba1131SLorenzo Bianconi if (!sdata->vif.bss_conf.twt_responder)
3430f5a4c24eSLorenzo Bianconi return false;
3431f5a4c24eSLorenzo Bianconi
3432f5a4c24eSLorenzo Bianconi if (!rx->sta)
3433f5a4c24eSLorenzo Bianconi return false;
3434f5a4c24eSLorenzo Bianconi
3435f5a4c24eSLorenzo Bianconi switch (mgmt->u.action.u.s1g.action_code) {
3436f5a4c24eSLorenzo Bianconi case WLAN_S1G_TWT_SETUP: {
3437f5a4c24eSLorenzo Bianconi struct ieee80211_twt_setup *twt;
3438f5a4c24eSLorenzo Bianconi
3439f5a4c24eSLorenzo Bianconi if (rx->skb->len < IEEE80211_MIN_ACTION_SIZE +
3440f5a4c24eSLorenzo Bianconi 1 + /* action code */
3441f5a4c24eSLorenzo Bianconi sizeof(struct ieee80211_twt_setup) +
3442f5a4c24eSLorenzo Bianconi 2 /* TWT req_type agrt */)
3443f5a4c24eSLorenzo Bianconi break;
3444f5a4c24eSLorenzo Bianconi
3445f5a4c24eSLorenzo Bianconi twt = (void *)mgmt->u.action.u.s1g.variable;
3446f5a4c24eSLorenzo Bianconi if (twt->element_id != WLAN_EID_S1G_TWT)
3447f5a4c24eSLorenzo Bianconi break;
3448f5a4c24eSLorenzo Bianconi
3449f5a4c24eSLorenzo Bianconi if (rx->skb->len < IEEE80211_MIN_ACTION_SIZE +
3450f5a4c24eSLorenzo Bianconi 4 + /* action code + token + tlv */
3451f5a4c24eSLorenzo Bianconi twt->length)
3452f5a4c24eSLorenzo Bianconi break;
3453f5a4c24eSLorenzo Bianconi
3454f5a4c24eSLorenzo Bianconi return true; /* queue the frame */
3455f5a4c24eSLorenzo Bianconi }
3456f5a4c24eSLorenzo Bianconi case WLAN_S1G_TWT_TEARDOWN:
3457f5a4c24eSLorenzo Bianconi if (rx->skb->len < IEEE80211_MIN_ACTION_SIZE + 2)
3458f5a4c24eSLorenzo Bianconi break;
3459f5a4c24eSLorenzo Bianconi
3460f5a4c24eSLorenzo Bianconi return true; /* queue the frame */
3461f5a4c24eSLorenzo Bianconi default:
3462f5a4c24eSLorenzo Bianconi break;
3463f5a4c24eSLorenzo Bianconi }
3464f5a4c24eSLorenzo Bianconi
3465f5a4c24eSLorenzo Bianconi return false;
3466f5a4c24eSLorenzo Bianconi }
3467f5a4c24eSLorenzo Bianconi
34682e161f78SJohannes Berg static ieee80211_rx_result debug_noinline
ieee80211_rx_h_action(struct ieee80211_rx_data * rx)3469de1ede7aSJohannes Berg ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
3470de1ede7aSJohannes Berg {
3471de1ede7aSJohannes Berg struct ieee80211_local *local = rx->local;
3472eb9fb5b8SJohannes Berg struct ieee80211_sub_if_data *sdata = rx->sdata;
3473de1ede7aSJohannes Berg struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data;
3474554891e6SJohannes Berg struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
3475de1ede7aSJohannes Berg int len = rx->skb->len;
3476de1ede7aSJohannes Berg
3477de1ede7aSJohannes Berg if (!ieee80211_is_action(mgmt->frame_control))
3478de1ede7aSJohannes Berg return RX_CONTINUE;
3479de1ede7aSJohannes Berg
3480815b8092SMarco Porsch if (!rx->sta && mgmt->u.action.category != WLAN_CATEGORY_PUBLIC &&
3481cd7760e6SSimon Wunderlich mgmt->u.action.category != WLAN_CATEGORY_SELF_PROTECTED &&
3482cd7760e6SSimon Wunderlich mgmt->u.action.category != WLAN_CATEGORY_SPECTRUM_MGMT)
348384040805SJohannes Berg return RX_DROP_UNUSABLE;
3484de1ede7aSJohannes Berg
3485de1ede7aSJohannes Berg switch (mgmt->u.action.category) {
34861d8d3decSJohannes Berg case WLAN_CATEGORY_HT:
34871d8d3decSJohannes Berg /* reject HT action frames from stations not supporting HT */
3488b320d6c4SBenjamin Berg if (!rx->link_sta->pub->ht_cap.ht_supported)
34891d8d3decSJohannes Berg goto invalid;
34901d8d3decSJohannes Berg
34911d8d3decSJohannes Berg if (sdata->vif.type != NL80211_IFTYPE_STATION &&
34921d8d3decSJohannes Berg sdata->vif.type != NL80211_IFTYPE_MESH_POINT &&
34931d8d3decSJohannes Berg sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
34941d8d3decSJohannes Berg sdata->vif.type != NL80211_IFTYPE_AP &&
34951d8d3decSJohannes Berg sdata->vif.type != NL80211_IFTYPE_ADHOC)
34961d8d3decSJohannes Berg break;
34971d8d3decSJohannes Berg
3498ec61cd63SJohannes Berg /* verify action & smps_control/chanwidth are present */
34991d8d3decSJohannes Berg if (len < IEEE80211_MIN_ACTION_SIZE + 2)
35001d8d3decSJohannes Berg goto invalid;
35011d8d3decSJohannes Berg
35021d8d3decSJohannes Berg switch (mgmt->u.action.u.ht_smps.action) {
35031d8d3decSJohannes Berg case WLAN_HT_ACTION_SMPS: {
35041d8d3decSJohannes Berg struct ieee80211_supported_band *sband;
3505af0ed69bSJohannes Berg enum ieee80211_smps_mode smps_mode;
3506ff84e7bfStamizhr@codeaurora.org struct sta_opmode_info sta_opmode = {};
35071d8d3decSJohannes Berg
3508c4d800dcSIlan Peer if (sdata->vif.type != NL80211_IFTYPE_AP &&
3509c4d800dcSIlan Peer sdata->vif.type != NL80211_IFTYPE_AP_VLAN)
3510c4d800dcSIlan Peer goto handled;
3511c4d800dcSIlan Peer
35121d8d3decSJohannes Berg /* convert to HT capability */
35131d8d3decSJohannes Berg switch (mgmt->u.action.u.ht_smps.smps_control) {
35141d8d3decSJohannes Berg case WLAN_HT_SMPS_CONTROL_DISABLED:
3515af0ed69bSJohannes Berg smps_mode = IEEE80211_SMPS_OFF;
35161d8d3decSJohannes Berg break;
35171d8d3decSJohannes Berg case WLAN_HT_SMPS_CONTROL_STATIC:
3518af0ed69bSJohannes Berg smps_mode = IEEE80211_SMPS_STATIC;
35191d8d3decSJohannes Berg break;
35201d8d3decSJohannes Berg case WLAN_HT_SMPS_CONTROL_DYNAMIC:
3521af0ed69bSJohannes Berg smps_mode = IEEE80211_SMPS_DYNAMIC;
35221d8d3decSJohannes Berg break;
35231d8d3decSJohannes Berg default:
35241d8d3decSJohannes Berg goto invalid;
35251d8d3decSJohannes Berg }
35261d8d3decSJohannes Berg
35271d8d3decSJohannes Berg /* if no change do nothing */
3528261ce887SBenjamin Berg if (rx->link_sta->pub->smps_mode == smps_mode)
35291d8d3decSJohannes Berg goto handled;
3530261ce887SBenjamin Berg rx->link_sta->pub->smps_mode = smps_mode;
353157566b20Stamizhr@codeaurora.org sta_opmode.smps_mode =
353257566b20Stamizhr@codeaurora.org ieee80211_smps_mode_to_smps_mode(smps_mode);
3533ff84e7bfStamizhr@codeaurora.org sta_opmode.changed = STA_OPMODE_SMPS_MODE_CHANGED;
35341d8d3decSJohannes Berg
35351d8d3decSJohannes Berg sband = rx->local->hw.wiphy->bands[status->band];
35361d8d3decSJohannes Berg
3537b4f85443SJohannes Berg rate_control_rate_update(local, sband, rx->sta, 0,
353864f68e5dSJohannes Berg IEEE80211_RC_SMPS_CHANGED);
3539ff84e7bfStamizhr@codeaurora.org cfg80211_sta_opmode_change_notify(sdata->dev,
3540ff84e7bfStamizhr@codeaurora.org rx->sta->addr,
3541ff84e7bfStamizhr@codeaurora.org &sta_opmode,
3542c752cac9SYan-Hsuan Chuang GFP_ATOMIC);
35431d8d3decSJohannes Berg goto handled;
35441d8d3decSJohannes Berg }
3545ec61cd63SJohannes Berg case WLAN_HT_ACTION_NOTIFY_CHANWIDTH: {
3546ec61cd63SJohannes Berg struct ieee80211_supported_band *sband;
3547ec61cd63SJohannes Berg u8 chanwidth = mgmt->u.action.u.ht_notify_cw.chanwidth;
35481c45c5ceSEliad Peller enum ieee80211_sta_rx_bandwidth max_bw, new_bw;
3549ff84e7bfStamizhr@codeaurora.org struct sta_opmode_info sta_opmode = {};
3550ec61cd63SJohannes Berg
3551ec61cd63SJohannes Berg /* If it doesn't support 40 MHz it can't change ... */
3552b320d6c4SBenjamin Berg if (!(rx->link_sta->pub->ht_cap.cap &
3553e1a0c6b3SJohannes Berg IEEE80211_HT_CAP_SUP_WIDTH_20_40))
3554ec61cd63SJohannes Berg goto handled;
3555ec61cd63SJohannes Berg
3556e1a0c6b3SJohannes Berg if (chanwidth == IEEE80211_HT_CHANWIDTH_20MHZ)
35571c45c5ceSEliad Peller max_bw = IEEE80211_STA_RX_BW_20;
3558ec61cd63SJohannes Berg else
3559b320d6c4SBenjamin Berg max_bw = ieee80211_sta_cap_rx_bw(rx->link_sta);
35601c45c5ceSEliad Peller
35611c45c5ceSEliad Peller /* set cur_max_bandwidth and recalc sta bw */
3562b320d6c4SBenjamin Berg rx->link_sta->cur_max_bandwidth = max_bw;
3563b320d6c4SBenjamin Berg new_bw = ieee80211_sta_cur_vht_bw(rx->link_sta);
3564e1a0c6b3SJohannes Berg
3565b320d6c4SBenjamin Berg if (rx->link_sta->pub->bandwidth == new_bw)
3566e1a0c6b3SJohannes Berg goto handled;
3567ec61cd63SJohannes Berg
3568b320d6c4SBenjamin Berg rx->link_sta->pub->bandwidth = new_bw;
3569ec61cd63SJohannes Berg sband = rx->local->hw.wiphy->bands[status->band];
357097f5f425Stamizhr@codeaurora.org sta_opmode.bw =
3571b320d6c4SBenjamin Berg ieee80211_sta_rx_bw_to_chan_width(rx->link_sta);
3572ff84e7bfStamizhr@codeaurora.org sta_opmode.changed = STA_OPMODE_MAX_BW_CHANGED;
3573ec61cd63SJohannes Berg
3574b4f85443SJohannes Berg rate_control_rate_update(local, sband, rx->sta, 0,
3575ec61cd63SJohannes Berg IEEE80211_RC_BW_CHANGED);
3576ff84e7bfStamizhr@codeaurora.org cfg80211_sta_opmode_change_notify(sdata->dev,
3577ff84e7bfStamizhr@codeaurora.org rx->sta->addr,
3578ff84e7bfStamizhr@codeaurora.org &sta_opmode,
3579c752cac9SYan-Hsuan Chuang GFP_ATOMIC);
3580ec61cd63SJohannes Berg goto handled;
3581ec61cd63SJohannes Berg }
35821d8d3decSJohannes Berg default:
35831d8d3decSJohannes Berg goto invalid;
35841d8d3decSJohannes Berg }
35851d8d3decSJohannes Berg
35861d8d3decSJohannes Berg break;
35871b3a2e49SJohannes Berg case WLAN_CATEGORY_PUBLIC:
35881b3a2e49SJohannes Berg if (len < IEEE80211_MIN_ACTION_SIZE + 1)
35891b3a2e49SJohannes Berg goto invalid;
35901b3a2e49SJohannes Berg if (sdata->vif.type != NL80211_IFTYPE_STATION)
35911b3a2e49SJohannes Berg break;
35921b3a2e49SJohannes Berg if (!rx->sta)
35931b3a2e49SJohannes Berg break;
3594bfd8403aSJohannes Berg if (!ether_addr_equal(mgmt->bssid, sdata->deflink.u.mgd.bssid))
35951b3a2e49SJohannes Berg break;
35961b3a2e49SJohannes Berg if (mgmt->u.action.u.ext_chan_switch.action_code !=
35971b3a2e49SJohannes Berg WLAN_PUB_ACTION_EXT_CHANSW_ANN)
35981b3a2e49SJohannes Berg break;
35991b3a2e49SJohannes Berg if (len < offsetof(struct ieee80211_mgmt,
36001b3a2e49SJohannes Berg u.action.u.ext_chan_switch.variable))
36011b3a2e49SJohannes Berg goto invalid;
36021b3a2e49SJohannes Berg goto queue;
36030af83d3dSJohannes Berg case WLAN_CATEGORY_VHT:
36040af83d3dSJohannes Berg if (sdata->vif.type != NL80211_IFTYPE_STATION &&
36050af83d3dSJohannes Berg sdata->vif.type != NL80211_IFTYPE_MESH_POINT &&
36060af83d3dSJohannes Berg sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
36070af83d3dSJohannes Berg sdata->vif.type != NL80211_IFTYPE_AP &&
36080af83d3dSJohannes Berg sdata->vif.type != NL80211_IFTYPE_ADHOC)
36090af83d3dSJohannes Berg break;
36100af83d3dSJohannes Berg
36110af83d3dSJohannes Berg /* verify action code is present */
36120af83d3dSJohannes Berg if (len < IEEE80211_MIN_ACTION_SIZE + 1)
36130af83d3dSJohannes Berg goto invalid;
36140af83d3dSJohannes Berg
36150af83d3dSJohannes Berg switch (mgmt->u.action.u.vht_opmode_notif.action_code) {
36160af83d3dSJohannes Berg case WLAN_VHT_ACTION_OPMODE_NOTIF: {
36170af83d3dSJohannes Berg /* verify opmode is present */
36180af83d3dSJohannes Berg if (len < IEEE80211_MIN_ACTION_SIZE + 2)
36190af83d3dSJohannes Berg goto invalid;
3620d2941df8SJohannes Berg goto queue;
36210af83d3dSJohannes Berg }
362223a1f8d4SSara Sharon case WLAN_VHT_ACTION_GROUPID_MGMT: {
362323a1f8d4SSara Sharon if (len < IEEE80211_MIN_ACTION_SIZE + 25)
362423a1f8d4SSara Sharon goto invalid;
362523a1f8d4SSara Sharon goto queue;
362623a1f8d4SSara Sharon }
36270af83d3dSJohannes Berg default:
36280af83d3dSJohannes Berg break;
36290af83d3dSJohannes Berg }
36300af83d3dSJohannes Berg break;
3631de1ede7aSJohannes Berg case WLAN_CATEGORY_BACK:
36328abd3f9bSJohannes Berg if (sdata->vif.type != NL80211_IFTYPE_STATION &&
3633ae2772b3SThomas Pedersen sdata->vif.type != NL80211_IFTYPE_MESH_POINT &&
36348abd3f9bSJohannes Berg sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
363513c40c54SAlexander Simon sdata->vif.type != NL80211_IFTYPE_AP &&
363613c40c54SAlexander Simon sdata->vif.type != NL80211_IFTYPE_ADHOC)
363784040805SJohannes Berg break;
36388abd3f9bSJohannes Berg
3639026331c4SJouni Malinen /* verify action_code is present */
3640026331c4SJouni Malinen if (len < IEEE80211_MIN_ACTION_SIZE + 1)
3641026331c4SJouni Malinen break;
3642026331c4SJouni Malinen
3643de1ede7aSJohannes Berg switch (mgmt->u.action.u.addba_req.action_code) {
3644de1ede7aSJohannes Berg case WLAN_ACTION_ADDBA_REQ:
3645de1ede7aSJohannes Berg if (len < (IEEE80211_MIN_ACTION_SIZE +
3646de1ede7aSJohannes Berg sizeof(mgmt->u.action.u.addba_req)))
3647bed7ee6eSJohannes Berg goto invalid;
3648bed7ee6eSJohannes Berg break;
3649de1ede7aSJohannes Berg case WLAN_ACTION_ADDBA_RESP:
3650de1ede7aSJohannes Berg if (len < (IEEE80211_MIN_ACTION_SIZE +
3651de1ede7aSJohannes Berg sizeof(mgmt->u.action.u.addba_resp)))
3652bed7ee6eSJohannes Berg goto invalid;
3653de1ede7aSJohannes Berg break;
3654de1ede7aSJohannes Berg case WLAN_ACTION_DELBA:
3655de1ede7aSJohannes Berg if (len < (IEEE80211_MIN_ACTION_SIZE +
3656de1ede7aSJohannes Berg sizeof(mgmt->u.action.u.delba)))
3657bed7ee6eSJohannes Berg goto invalid;
3658de1ede7aSJohannes Berg break;
3659bed7ee6eSJohannes Berg default:
3660bed7ee6eSJohannes Berg goto invalid;
3661de1ede7aSJohannes Berg }
3662bed7ee6eSJohannes Berg
36638b58ff83SJohannes Berg goto queue;
366439192c0bSJohannes Berg case WLAN_CATEGORY_SPECTRUM_MGMT:
3665026331c4SJouni Malinen /* verify action_code is present */
3666026331c4SJouni Malinen if (len < IEEE80211_MIN_ACTION_SIZE + 1)
3667026331c4SJouni Malinen break;
3668026331c4SJouni Malinen
366939192c0bSJohannes Berg switch (mgmt->u.action.u.measurement.action_code) {
367039192c0bSJohannes Berg case WLAN_ACTION_SPCT_MSR_REQ:
367157fbcce3SJohannes Berg if (status->band != NL80211_BAND_5GHZ)
3672cd7760e6SSimon Wunderlich break;
3673cd7760e6SSimon Wunderlich
367439192c0bSJohannes Berg if (len < (IEEE80211_MIN_ACTION_SIZE +
367539192c0bSJohannes Berg sizeof(mgmt->u.action.u.measurement)))
367639192c0bSJohannes Berg break;
3677cd7760e6SSimon Wunderlich
3678cc32abd4SJohannes Berg if (sdata->vif.type != NL80211_IFTYPE_STATION)
367984040805SJohannes Berg break;
3680cc32abd4SJohannes Berg
3681cd7760e6SSimon Wunderlich ieee80211_process_measurement_req(sdata, mgmt, len);
3682cd7760e6SSimon Wunderlich goto handled;
3683cd7760e6SSimon Wunderlich case WLAN_ACTION_SPCT_CHL_SWITCH: {
3684cd7760e6SSimon Wunderlich u8 *bssid;
3685cd7760e6SSimon Wunderlich if (len < (IEEE80211_MIN_ACTION_SIZE +
3686cd7760e6SSimon Wunderlich sizeof(mgmt->u.action.u.chan_switch)))
3687cd7760e6SSimon Wunderlich break;
3688cd7760e6SSimon Wunderlich
3689cd7760e6SSimon Wunderlich if (sdata->vif.type != NL80211_IFTYPE_STATION &&
3690b8456a14SChun-Yeow Yeoh sdata->vif.type != NL80211_IFTYPE_ADHOC &&
3691b8456a14SChun-Yeow Yeoh sdata->vif.type != NL80211_IFTYPE_MESH_POINT)
3692cd7760e6SSimon Wunderlich break;
3693cd7760e6SSimon Wunderlich
3694cd7760e6SSimon Wunderlich if (sdata->vif.type == NL80211_IFTYPE_STATION)
3695bfd8403aSJohannes Berg bssid = sdata->deflink.u.mgd.bssid;
3696cd7760e6SSimon Wunderlich else if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
3697cd7760e6SSimon Wunderlich bssid = sdata->u.ibss.bssid;
3698b8456a14SChun-Yeow Yeoh else if (sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
3699b8456a14SChun-Yeow Yeoh bssid = mgmt->sa;
3700cd7760e6SSimon Wunderlich else
3701cd7760e6SSimon Wunderlich break;
3702cd7760e6SSimon Wunderlich
3703cd7760e6SSimon Wunderlich if (!ether_addr_equal(mgmt->bssid, bssid))
370484040805SJohannes Berg break;
3705c481ec97SSujith
37068b58ff83SJohannes Berg goto queue;
370739192c0bSJohannes Berg }
3708cd7760e6SSimon Wunderlich }
370939192c0bSJohannes Berg break;
37108db09850SThomas Pedersen case WLAN_CATEGORY_SELF_PROTECTED:
37119b395bc3SJohannes Berg if (len < (IEEE80211_MIN_ACTION_SIZE +
37129b395bc3SJohannes Berg sizeof(mgmt->u.action.u.self_prot.action_code)))
37139b395bc3SJohannes Berg break;
37149b395bc3SJohannes Berg
37158db09850SThomas Pedersen switch (mgmt->u.action.u.self_prot.action_code) {
37168db09850SThomas Pedersen case WLAN_SP_MESH_PEERING_OPEN:
37178db09850SThomas Pedersen case WLAN_SP_MESH_PEERING_CLOSE:
37188db09850SThomas Pedersen case WLAN_SP_MESH_PEERING_CONFIRM:
37198db09850SThomas Pedersen if (!ieee80211_vif_is_mesh(&sdata->vif))
37208db09850SThomas Pedersen goto invalid;
3721a6dad6a2SThomas Pedersen if (sdata->u.mesh.user_mpm)
37228db09850SThomas Pedersen /* userspace handles this frame */
37238db09850SThomas Pedersen break;
37248db09850SThomas Pedersen goto queue;
37258db09850SThomas Pedersen case WLAN_SP_MGK_INFORM:
37268db09850SThomas Pedersen case WLAN_SP_MGK_ACK:
37278db09850SThomas Pedersen if (!ieee80211_vif_is_mesh(&sdata->vif))
37288db09850SThomas Pedersen goto invalid;
37298db09850SThomas Pedersen break;
37308db09850SThomas Pedersen }
37318db09850SThomas Pedersen break;
3732d3aaec8aSJavier Cardona case WLAN_CATEGORY_MESH_ACTION:
37339b395bc3SJohannes Berg if (len < (IEEE80211_MIN_ACTION_SIZE +
37349b395bc3SJohannes Berg sizeof(mgmt->u.action.u.mesh_action.action_code)))
37359b395bc3SJohannes Berg break;
37369b395bc3SJohannes Berg
373777a121c3SJohannes Berg if (!ieee80211_vif_is_mesh(&sdata->vif))
37381cb561f8SJavier Cardona break;
373925d49e4dSThomas Pedersen if (mesh_action_is_path_sel(mgmt) &&
37401df332e8SJohannes Berg !mesh_path_sel_is_hwmp(sdata))
3741c7108a71SJavier Cardona break;
3742c7108a71SJavier Cardona goto queue;
3743f5a4c24eSLorenzo Bianconi case WLAN_CATEGORY_S1G:
374419e4a47eSJohannes Berg if (len < offsetofend(typeof(*mgmt),
374519e4a47eSJohannes Berg u.action.u.s1g.action_code))
374619e4a47eSJohannes Berg break;
374719e4a47eSJohannes Berg
3748f5a4c24eSLorenzo Bianconi switch (mgmt->u.action.u.s1g.action_code) {
3749f5a4c24eSLorenzo Bianconi case WLAN_S1G_TWT_SETUP:
3750f5a4c24eSLorenzo Bianconi case WLAN_S1G_TWT_TEARDOWN:
3751f5a4c24eSLorenzo Bianconi if (ieee80211_process_rx_twt_action(rx))
3752f5a4c24eSLorenzo Bianconi goto queue;
3753f5a4c24eSLorenzo Bianconi break;
3754f5a4c24eSLorenzo Bianconi default:
3755f5a4c24eSLorenzo Bianconi break;
3756f5a4c24eSLorenzo Bianconi }
3757f5a4c24eSLorenzo Bianconi break;
375884040805SJohannes Berg }
3759026331c4SJouni Malinen
37602e161f78SJohannes Berg return RX_CONTINUE;
37612e161f78SJohannes Berg
3762bed7ee6eSJohannes Berg invalid:
3763554891e6SJohannes Berg status->rx_flags |= IEEE80211_RX_MALFORMED_ACTION_FRM;
37642e161f78SJohannes Berg /* will return in the next handlers */
37652e161f78SJohannes Berg return RX_CONTINUE;
37662e161f78SJohannes Berg
37672e161f78SJohannes Berg handled:
37682e161f78SJohannes Berg if (rx->sta)
3769b320d6c4SBenjamin Berg rx->link_sta->rx_stats.packets++;
37702e161f78SJohannes Berg dev_kfree_skb(rx->skb);
37712e161f78SJohannes Berg return RX_QUEUED;
37722e161f78SJohannes Berg
37732e161f78SJohannes Berg queue:
37744f6c78deSJohannes Berg ieee80211_queue_skb_to_iface(sdata, rx->link_id, rx->sta, rx->skb);
37752e161f78SJohannes Berg return RX_QUEUED;
37762e161f78SJohannes Berg }
37772e161f78SJohannes Berg
37782e161f78SJohannes Berg static ieee80211_rx_result debug_noinline
ieee80211_rx_h_userspace_mgmt(struct ieee80211_rx_data * rx)37792e161f78SJohannes Berg ieee80211_rx_h_userspace_mgmt(struct ieee80211_rx_data *rx)
37802e161f78SJohannes Berg {
3781554891e6SJohannes Berg struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
3782f9202638SAvraham Stern struct cfg80211_rx_info info = {
3783f9202638SAvraham Stern .freq = ieee80211_rx_status_to_khz(status),
3784f9202638SAvraham Stern .buf = rx->skb->data,
37852ec833a5SJohannes Berg .len = rx->skb->len,
37862ec833a5SJohannes Berg .link_id = rx->link_id,
37872ec833a5SJohannes Berg .have_link_id = rx->link_id >= 0,
3788f9202638SAvraham Stern };
37892e161f78SJohannes Berg
37902e161f78SJohannes Berg /* skip known-bad action frames and return them in the next handler */
3791554891e6SJohannes Berg if (status->rx_flags & IEEE80211_RX_MALFORMED_ACTION_FRM)
37922e161f78SJohannes Berg return RX_CONTINUE;
3793d7907448SFelix Fietkau
3794026331c4SJouni Malinen /*
3795026331c4SJouni Malinen * Getting here means the kernel doesn't know how to handle
3796026331c4SJouni Malinen * it, but maybe userspace does ... include returned frames
3797026331c4SJouni Malinen * so userspace can register for those to know whether ones
3798026331c4SJouni Malinen * it transmitted were processed or returned.
3799026331c4SJouni Malinen */
3800026331c4SJouni Malinen
38011ad22fb5STosoni if (ieee80211_hw_check(&rx->local->hw, SIGNAL_DBM) &&
38021ad22fb5STosoni !(status->flag & RX_FLAG_NO_SIGNAL_VAL))
3803f9202638SAvraham Stern info.sig_dbm = status->signal;
3804804483e9SJohannes Berg
3805f9202638SAvraham Stern if (ieee80211_is_timing_measurement(rx->skb) ||
3806f9202638SAvraham Stern ieee80211_is_ftm(rx->skb)) {
3807f9202638SAvraham Stern info.rx_tstamp = ktime_to_ns(skb_hwtstamps(rx->skb)->hwtstamp);
3808f9202638SAvraham Stern info.ack_tstamp = ktime_to_ns(status->ack_tx_hwtstamp);
3809f9202638SAvraham Stern }
3810f9202638SAvraham Stern
3811f9202638SAvraham Stern if (cfg80211_rx_mgmt_ext(&rx->sdata->wdev, &info)) {
38122e161f78SJohannes Berg if (rx->sta)
3813b320d6c4SBenjamin Berg rx->link_sta->rx_stats.packets++;
38142e161f78SJohannes Berg dev_kfree_skb(rx->skb);
38152e161f78SJohannes Berg return RX_QUEUED;
38162e161f78SJohannes Berg }
38172e161f78SJohannes Berg
38182e161f78SJohannes Berg return RX_CONTINUE;
38192e161f78SJohannes Berg }
38202e161f78SJohannes Berg
38212e161f78SJohannes Berg static ieee80211_rx_result debug_noinline
ieee80211_rx_h_action_post_userspace(struct ieee80211_rx_data * rx)38221ea02224SJohannes Berg ieee80211_rx_h_action_post_userspace(struct ieee80211_rx_data *rx)
38231ea02224SJohannes Berg {
38241ea02224SJohannes Berg struct ieee80211_sub_if_data *sdata = rx->sdata;
38251ea02224SJohannes Berg struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data;
38261ea02224SJohannes Berg int len = rx->skb->len;
38271ea02224SJohannes Berg
38281ea02224SJohannes Berg if (!ieee80211_is_action(mgmt->frame_control))
38291ea02224SJohannes Berg return RX_CONTINUE;
38301ea02224SJohannes Berg
38311ea02224SJohannes Berg switch (mgmt->u.action.category) {
38321ea02224SJohannes Berg case WLAN_CATEGORY_SA_QUERY:
38331ea02224SJohannes Berg if (len < (IEEE80211_MIN_ACTION_SIZE +
38341ea02224SJohannes Berg sizeof(mgmt->u.action.u.sa_query)))
38351ea02224SJohannes Berg break;
38361ea02224SJohannes Berg
38371ea02224SJohannes Berg switch (mgmt->u.action.u.sa_query.action) {
38381ea02224SJohannes Berg case WLAN_ACTION_SA_QUERY_REQUEST:
38391ea02224SJohannes Berg if (sdata->vif.type != NL80211_IFTYPE_STATION)
38401ea02224SJohannes Berg break;
38411ea02224SJohannes Berg ieee80211_process_sa_query_req(sdata, mgmt, len);
38421ea02224SJohannes Berg goto handled;
38431ea02224SJohannes Berg }
38441ea02224SJohannes Berg break;
38451ea02224SJohannes Berg }
38461ea02224SJohannes Berg
38471ea02224SJohannes Berg return RX_CONTINUE;
38481ea02224SJohannes Berg
38491ea02224SJohannes Berg handled:
38501ea02224SJohannes Berg if (rx->sta)
3851b320d6c4SBenjamin Berg rx->link_sta->rx_stats.packets++;
38521ea02224SJohannes Berg dev_kfree_skb(rx->skb);
38531ea02224SJohannes Berg return RX_QUEUED;
38541ea02224SJohannes Berg }
38551ea02224SJohannes Berg
38561ea02224SJohannes Berg static ieee80211_rx_result debug_noinline
ieee80211_rx_h_action_return(struct ieee80211_rx_data * rx)38572e161f78SJohannes Berg ieee80211_rx_h_action_return(struct ieee80211_rx_data *rx)
38582e161f78SJohannes Berg {
38592e161f78SJohannes Berg struct ieee80211_local *local = rx->local;
38602e161f78SJohannes Berg struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data;
38612e161f78SJohannes Berg struct sk_buff *nskb;
38622e161f78SJohannes Berg struct ieee80211_sub_if_data *sdata = rx->sdata;
3863554891e6SJohannes Berg struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
38642e161f78SJohannes Berg
38652e161f78SJohannes Berg if (!ieee80211_is_action(mgmt->frame_control))
38662e161f78SJohannes Berg return RX_CONTINUE;
38672e161f78SJohannes Berg
38682e161f78SJohannes Berg /*
38692e161f78SJohannes Berg * For AP mode, hostapd is responsible for handling any action
38702e161f78SJohannes Berg * frames that we didn't handle, including returning unknown
38712e161f78SJohannes Berg * ones. For all other modes we will return them to the sender,
38722e161f78SJohannes Berg * setting the 0x80 bit in the action category, as required by
38734b5ebcccSJohannes Berg * 802.11-2012 9.24.4.
38742e161f78SJohannes Berg * Newer versions of hostapd shall also use the management frame
38752e161f78SJohannes Berg * registration mechanisms, but older ones still use cooked
38762e161f78SJohannes Berg * monitor interfaces so push all frames there.
38772e161f78SJohannes Berg */
3878554891e6SJohannes Berg if (!(status->rx_flags & IEEE80211_RX_MALFORMED_ACTION_FRM) &&
38792e161f78SJohannes Berg (sdata->vif.type == NL80211_IFTYPE_AP ||
38802e161f78SJohannes Berg sdata->vif.type == NL80211_IFTYPE_AP_VLAN))
38812e161f78SJohannes Berg return RX_DROP_MONITOR;
3882026331c4SJouni Malinen
38834b5ebcccSJohannes Berg if (is_multicast_ether_addr(mgmt->da))
38844b5ebcccSJohannes Berg return RX_DROP_MONITOR;
38854b5ebcccSJohannes Berg
388684040805SJohannes Berg /* do not return rejected action frames */
388784040805SJohannes Berg if (mgmt->u.action.category & 0x80)
388884040805SJohannes Berg return RX_DROP_UNUSABLE;
388984040805SJohannes Berg
389084040805SJohannes Berg nskb = skb_copy_expand(rx->skb, local->hw.extra_tx_headroom, 0,
389184040805SJohannes Berg GFP_ATOMIC);
389284040805SJohannes Berg if (nskb) {
3893292b4df6SJohn W. Linville struct ieee80211_mgmt *nmgmt = (void *)nskb->data;
389484040805SJohannes Berg
3895292b4df6SJohn W. Linville nmgmt->u.action.category |= 0x80;
3896292b4df6SJohn W. Linville memcpy(nmgmt->da, nmgmt->sa, ETH_ALEN);
3897292b4df6SJohn W. Linville memcpy(nmgmt->sa, rx->sdata->vif.addr, ETH_ALEN);
389884040805SJohannes Berg
389984040805SJohannes Berg memset(nskb->cb, 0, sizeof(nskb->cb));
390084040805SJohannes Berg
390107e5a5f5SJohannes Berg if (rx->sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE) {
390207e5a5f5SJohannes Berg struct ieee80211_tx_info *info = IEEE80211_SKB_CB(nskb);
390307e5a5f5SJohannes Berg
390407e5a5f5SJohannes Berg info->flags = IEEE80211_TX_CTL_TX_OFFCHAN |
390507e5a5f5SJohannes Berg IEEE80211_TX_INTFL_OFFCHAN_TX_OK |
390607e5a5f5SJohannes Berg IEEE80211_TX_CTL_NO_CCK_RATE;
390730686bf7SJohannes Berg if (ieee80211_hw_check(&local->hw, QUEUE_CONTROL))
390807e5a5f5SJohannes Berg info->hw_queue =
390907e5a5f5SJohannes Berg local->hw.offchannel_tx_hw_queue;
391007e5a5f5SJohannes Berg }
391107e5a5f5SJohannes Berg
3912e1e68b14SJohannes Berg __ieee80211_tx_skb_tid_band(rx->sdata, nskb, 7, -1,
391308aca29aSMathy Vanhoef status->band);
391439192c0bSJohannes Berg }
3915de1ede7aSJohannes Berg dev_kfree_skb(rx->skb);
3916de1ede7aSJohannes Berg return RX_QUEUED;
3917de1ede7aSJohannes Berg }
3918de1ede7aSJohannes Berg
3919de1ede7aSJohannes Berg static ieee80211_rx_result debug_noinline
ieee80211_rx_h_ext(struct ieee80211_rx_data * rx)392009a740ceSThomas Pedersen ieee80211_rx_h_ext(struct ieee80211_rx_data *rx)
392109a740ceSThomas Pedersen {
392209a740ceSThomas Pedersen struct ieee80211_sub_if_data *sdata = rx->sdata;
392309a740ceSThomas Pedersen struct ieee80211_hdr *hdr = (void *)rx->skb->data;
392409a740ceSThomas Pedersen
392509a740ceSThomas Pedersen if (!ieee80211_is_ext(hdr->frame_control))
392609a740ceSThomas Pedersen return RX_CONTINUE;
392709a740ceSThomas Pedersen
392809a740ceSThomas Pedersen if (sdata->vif.type != NL80211_IFTYPE_STATION)
392909a740ceSThomas Pedersen return RX_DROP_MONITOR;
393009a740ceSThomas Pedersen
393109a740ceSThomas Pedersen /* for now only beacons are ext, so queue them */
39324f6c78deSJohannes Berg ieee80211_queue_skb_to_iface(sdata, rx->link_id, rx->sta, rx->skb);
393309a740ceSThomas Pedersen
393409a740ceSThomas Pedersen return RX_QUEUED;
393509a740ceSThomas Pedersen }
393609a740ceSThomas Pedersen
393709a740ceSThomas Pedersen static ieee80211_rx_result debug_noinline
ieee80211_rx_h_mgmt(struct ieee80211_rx_data * rx)39385cf121c3SJohannes Berg ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx)
3939571ecf67SJohannes Berg {
3940eb9fb5b8SJohannes Berg struct ieee80211_sub_if_data *sdata = rx->sdata;
394177a121c3SJohannes Berg struct ieee80211_mgmt *mgmt = (void *)rx->skb->data;
394277a121c3SJohannes Berg __le16 stype;
3943571ecf67SJohannes Berg
394477a121c3SJohannes Berg stype = mgmt->frame_control & cpu_to_le16(IEEE80211_FCTL_STYPE);
3945472dbc45SJohannes Berg
394677a121c3SJohannes Berg if (!ieee80211_vif_is_mesh(&sdata->vif) &&
394777a121c3SJohannes Berg sdata->vif.type != NL80211_IFTYPE_ADHOC &&
3948239281f8SRostislav Lisovy sdata->vif.type != NL80211_IFTYPE_OCB &&
394977a121c3SJohannes Berg sdata->vif.type != NL80211_IFTYPE_STATION)
39507986cf95SJohannes Berg return RX_DROP_MONITOR;
395177a121c3SJohannes Berg
395277a121c3SJohannes Berg switch (stype) {
395366e67e41SJohannes Berg case cpu_to_le16(IEEE80211_STYPE_AUTH):
395477a121c3SJohannes Berg case cpu_to_le16(IEEE80211_STYPE_BEACON):
395577a121c3SJohannes Berg case cpu_to_le16(IEEE80211_STYPE_PROBE_RESP):
395677a121c3SJohannes Berg /* process for all: mesh, mlme, ibss */
395777a121c3SJohannes Berg break;
395895697f99SJohannes Berg case cpu_to_le16(IEEE80211_STYPE_DEAUTH):
395995697f99SJohannes Berg if (is_multicast_ether_addr(mgmt->da) &&
396095697f99SJohannes Berg !is_broadcast_ether_addr(mgmt->da))
396195697f99SJohannes Berg return RX_DROP_MONITOR;
396295697f99SJohannes Berg
396395697f99SJohannes Berg /* process only for station/IBSS */
396495697f99SJohannes Berg if (sdata->vif.type != NL80211_IFTYPE_STATION &&
396595697f99SJohannes Berg sdata->vif.type != NL80211_IFTYPE_ADHOC)
396695697f99SJohannes Berg return RX_DROP_MONITOR;
396795697f99SJohannes Berg break;
396866e67e41SJohannes Berg case cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP):
396966e67e41SJohannes Berg case cpu_to_le16(IEEE80211_STYPE_REASSOC_RESP):
397077a121c3SJohannes Berg case cpu_to_le16(IEEE80211_STYPE_DISASSOC):
39712c31333aSChristian Lamparter if (is_multicast_ether_addr(mgmt->da) &&
39722c31333aSChristian Lamparter !is_broadcast_ether_addr(mgmt->da))
39732c31333aSChristian Lamparter return RX_DROP_MONITOR;
39742c31333aSChristian Lamparter
397577a121c3SJohannes Berg /* process only for station */
397677a121c3SJohannes Berg if (sdata->vif.type != NL80211_IFTYPE_STATION)
397777a121c3SJohannes Berg return RX_DROP_MONITOR;
397877a121c3SJohannes Berg break;
397977a121c3SJohannes Berg case cpu_to_le16(IEEE80211_STYPE_PROBE_REQ):
39809fb04b50SThomas Pedersen /* process only for ibss and mesh */
39819fb04b50SThomas Pedersen if (sdata->vif.type != NL80211_IFTYPE_ADHOC &&
39829fb04b50SThomas Pedersen sdata->vif.type != NL80211_IFTYPE_MESH_POINT)
398377a121c3SJohannes Berg return RX_DROP_MONITOR;
398477a121c3SJohannes Berg break;
398577a121c3SJohannes Berg default:
398677a121c3SJohannes Berg return RX_DROP_MONITOR;
398777a121c3SJohannes Berg }
398877a121c3SJohannes Berg
39894f6c78deSJohannes Berg ieee80211_queue_skb_to_iface(sdata, rx->link_id, rx->sta, rx->skb);
399077a121c3SJohannes Berg
399177a121c3SJohannes Berg return RX_QUEUED;
3992571ecf67SJohannes Berg }
3993571ecf67SJohannes Berg
ieee80211_rx_cooked_monitor(struct ieee80211_rx_data * rx,struct ieee80211_rate * rate,ieee80211_rx_result reason)39945f0b7de5SJohannes Berg static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx,
3995baa951a1SJohannes Berg struct ieee80211_rate *rate,
3996baa951a1SJohannes Berg ieee80211_rx_result reason)
39973d30d949SMichael Wu {
39983d30d949SMichael Wu struct ieee80211_sub_if_data *sdata;
39993d30d949SMichael Wu struct ieee80211_local *local = rx->local;
40003d30d949SMichael Wu struct sk_buff *skb = rx->skb, *skb2;
40013d30d949SMichael Wu struct net_device *prev_dev = NULL;
4002eb9fb5b8SJohannes Berg struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
4003293702a3SJohannes Berg int needed_headroom;
40043d30d949SMichael Wu
4005554891e6SJohannes Berg /*
4006554891e6SJohannes Berg * If cooked monitor has been processed already, then
4007554891e6SJohannes Berg * don't do it again. If not, set the flag.
4008554891e6SJohannes Berg */
4009554891e6SJohannes Berg if (rx->flags & IEEE80211_RX_CMNTR)
40107c1e1831SJohn W. Linville goto out_free_skb;
4011554891e6SJohannes Berg rx->flags |= IEEE80211_RX_CMNTR;
40127c1e1831SJohn W. Linville
4013152c477aSJohannes Berg /* If there are no cooked monitor interfaces, just free the SKB */
4014152c477aSJohannes Berg if (!local->cooked_mntrs)
4015152c477aSJohannes Berg goto out_free_skb;
4016152c477aSJohannes Berg
4017293702a3SJohannes Berg /* room for the radiotap header based on driver features */
40181f7bba79SJohannes Berg needed_headroom = ieee80211_rx_radiotap_hdrlen(local, status, skb);
4019293702a3SJohannes Berg
4020293702a3SJohannes Berg if (skb_headroom(skb) < needed_headroom &&
4021293702a3SJohannes Berg pskb_expand_head(skb, needed_headroom, 0, GFP_ATOMIC))
40223d30d949SMichael Wu goto out_free_skb;
40233d30d949SMichael Wu
4024293702a3SJohannes Berg /* prepend radiotap information */
4025973ef21aSFelix Fietkau ieee80211_add_rx_radiotap_header(local, skb, rate, needed_headroom,
4026973ef21aSFelix Fietkau false);
40273d30d949SMichael Wu
4028d57a544dSZhang Shengju skb_reset_mac_header(skb);
40293d30d949SMichael Wu skb->ip_summed = CHECKSUM_UNNECESSARY;
40303d30d949SMichael Wu skb->pkt_type = PACKET_OTHERHOST;
40313d30d949SMichael Wu skb->protocol = htons(ETH_P_802_2);
40323d30d949SMichael Wu
40333d30d949SMichael Wu list_for_each_entry_rcu(sdata, &local->interfaces, list) {
40349607e6b6SJohannes Berg if (!ieee80211_sdata_running(sdata))
40353d30d949SMichael Wu continue;
40363d30d949SMichael Wu
403705c914feSJohannes Berg if (sdata->vif.type != NL80211_IFTYPE_MONITOR ||
4038d8212184SAviya Erenfeld !(sdata->u.mntr.flags & MONITOR_FLAG_COOK_FRAMES))
40393d30d949SMichael Wu continue;
40403d30d949SMichael Wu
40413d30d949SMichael Wu if (prev_dev) {
40423d30d949SMichael Wu skb2 = skb_clone(skb, GFP_ATOMIC);
40433d30d949SMichael Wu if (skb2) {
40443d30d949SMichael Wu skb2->dev = prev_dev;
40455548a8a1SJohn W. Linville netif_receive_skb(skb2);
40463d30d949SMichael Wu }
40473d30d949SMichael Wu }
40483d30d949SMichael Wu
40493d30d949SMichael Wu prev_dev = sdata->dev;
405036ec144fSLev Stipakov dev_sw_netstats_rx_add(sdata->dev, skb->len);
40513d30d949SMichael Wu }
40523d30d949SMichael Wu
40533d30d949SMichael Wu if (prev_dev) {
40543d30d949SMichael Wu skb->dev = prev_dev;
40555548a8a1SJohn W. Linville netif_receive_skb(skb);
40563d30d949SMichael Wu return;
4057554891e6SJohannes Berg }
40583d30d949SMichael Wu
40593d30d949SMichael Wu out_free_skb:
4060baa951a1SJohannes Berg kfree_skb_reason(skb, (__force u32)reason);
40613d30d949SMichael Wu }
40623d30d949SMichael Wu
ieee80211_rx_handlers_result(struct ieee80211_rx_data * rx,ieee80211_rx_result res)4063aa0c8636SChristian Lamparter static void ieee80211_rx_handlers_result(struct ieee80211_rx_data *rx,
4064aa0c8636SChristian Lamparter ieee80211_rx_result res)
4065aa0c8636SChristian Lamparter {
4066baa951a1SJohannes Berg struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
4067baa951a1SJohannes Berg struct ieee80211_supported_band *sband;
4068baa951a1SJohannes Berg struct ieee80211_rate *rate = NULL;
4069baa951a1SJohannes Berg
4070baa951a1SJohannes Berg if (res == RX_QUEUED) {
4071baa951a1SJohannes Berg I802_DEBUG_INC(rx->sdata->local->rx_handlers_queued);
4072baa951a1SJohannes Berg return;
4073baa951a1SJohannes Berg }
4074baa951a1SJohannes Berg
4075baa951a1SJohannes Berg if (res != RX_CONTINUE) {
4076aa0c8636SChristian Lamparter I802_DEBUG_INC(rx->sdata->local->rx_handlers_drop);
4077aa0c8636SChristian Lamparter if (rx->sta)
4078b320d6c4SBenjamin Berg rx->link_sta->rx_stats.dropped++;
4079baa951a1SJohannes Berg }
4080aa0c8636SChristian Lamparter
4081baa951a1SJohannes Berg if (u32_get_bits((__force u32)res, SKB_DROP_REASON_SUBSYS_MASK) ==
4082baa951a1SJohannes Berg SKB_DROP_REASON_SUBSYS_MAC80211_UNUSABLE) {
4083baa951a1SJohannes Berg kfree_skb_reason(rx->skb, (__force u32)res);
4084baa951a1SJohannes Berg return;
4085baa951a1SJohannes Berg }
4086aa0c8636SChristian Lamparter
4087aa0c8636SChristian Lamparter sband = rx->local->hw.wiphy->bands[status->band];
408841cbb0f5SLuca Coelho if (status->encoding == RX_ENC_LEGACY)
4089aa0c8636SChristian Lamparter rate = &sband->bitrates[status->rate_idx];
4090aa0c8636SChristian Lamparter
4091baa951a1SJohannes Berg ieee80211_rx_cooked_monitor(rx, rate, res);
4092aa0c8636SChristian Lamparter }
4093aa0c8636SChristian Lamparter
ieee80211_rx_handlers(struct ieee80211_rx_data * rx,struct sk_buff_head * frames)4094f9e124fbSChristian Lamparter static void ieee80211_rx_handlers(struct ieee80211_rx_data *rx,
4095f9e124fbSChristian Lamparter struct sk_buff_head *frames)
4096aa0c8636SChristian Lamparter {
4097aa0c8636SChristian Lamparter ieee80211_rx_result res = RX_DROP_MONITOR;
4098aa0c8636SChristian Lamparter struct sk_buff *skb;
4099aa0c8636SChristian Lamparter
4100aa0c8636SChristian Lamparter #define CALL_RXH(rxh) \
4101aa0c8636SChristian Lamparter do { \
4102aa0c8636SChristian Lamparter res = rxh(rx); \
4103aa0c8636SChristian Lamparter if (res != RX_CONTINUE) \
4104aa0c8636SChristian Lamparter goto rxh_next; \
41058ebaa5b0SJohannes Berg } while (0)
4106aa0c8636SChristian Lamparter
410745ceeee8SJohannes Berg /* Lock here to avoid hitting all of the data used in the RX
410845ceeee8SJohannes Berg * path (e.g. key data, station data, ...) concurrently when
410945ceeee8SJohannes Berg * a frame is released from the reorder buffer due to timeout
411045ceeee8SJohannes Berg * from the timer, potentially concurrently with RX from the
411145ceeee8SJohannes Berg * driver.
411245ceeee8SJohannes Berg */
4113f9e124fbSChristian Lamparter spin_lock_bh(&rx->local->rx_path_lock);
411424a8fdadSChristian Lamparter
4115f9e124fbSChristian Lamparter while ((skb = __skb_dequeue(frames))) {
4116aa0c8636SChristian Lamparter /*
4117aa0c8636SChristian Lamparter * all the other fields are valid across frames
4118aa0c8636SChristian Lamparter * that belong to an aMPDU since they are on the
4119aa0c8636SChristian Lamparter * same TID from the same station
4120aa0c8636SChristian Lamparter */
4121aa0c8636SChristian Lamparter rx->skb = skb;
4122aa0c8636SChristian Lamparter
412356057da4SJohannes Berg if (WARN_ON_ONCE(!rx->link))
412456057da4SJohannes Berg goto rxh_next;
412556057da4SJohannes Berg
41268ebaa5b0SJohannes Berg CALL_RXH(ieee80211_rx_h_check_more_data);
41278ebaa5b0SJohannes Berg CALL_RXH(ieee80211_rx_h_uapsd_and_pspoll);
41288ebaa5b0SJohannes Berg CALL_RXH(ieee80211_rx_h_sta_process);
41298ebaa5b0SJohannes Berg CALL_RXH(ieee80211_rx_h_decrypt);
41308ebaa5b0SJohannes Berg CALL_RXH(ieee80211_rx_h_defragment);
41318ebaa5b0SJohannes Berg CALL_RXH(ieee80211_rx_h_michael_mic_verify);
4132aa0c8636SChristian Lamparter /* must be after MMIC verify so header is counted in MPDU mic */
41338ebaa5b0SJohannes Berg CALL_RXH(ieee80211_rx_h_amsdu);
41348ebaa5b0SJohannes Berg CALL_RXH(ieee80211_rx_h_data);
4135f9e124fbSChristian Lamparter
4136f9e124fbSChristian Lamparter /* special treatment -- needs the queue */
4137f9e124fbSChristian Lamparter res = ieee80211_rx_h_ctrl(rx, frames);
4138f9e124fbSChristian Lamparter if (res != RX_CONTINUE)
4139f9e124fbSChristian Lamparter goto rxh_next;
4140f9e124fbSChristian Lamparter
41418ebaa5b0SJohannes Berg CALL_RXH(ieee80211_rx_h_mgmt_check);
41428ebaa5b0SJohannes Berg CALL_RXH(ieee80211_rx_h_action);
41438ebaa5b0SJohannes Berg CALL_RXH(ieee80211_rx_h_userspace_mgmt);
41441ea02224SJohannes Berg CALL_RXH(ieee80211_rx_h_action_post_userspace);
41458ebaa5b0SJohannes Berg CALL_RXH(ieee80211_rx_h_action_return);
414609a740ceSThomas Pedersen CALL_RXH(ieee80211_rx_h_ext);
41478ebaa5b0SJohannes Berg CALL_RXH(ieee80211_rx_h_mgmt);
4148aa0c8636SChristian Lamparter
4149aa0c8636SChristian Lamparter rxh_next:
4150aa0c8636SChristian Lamparter ieee80211_rx_handlers_result(rx, res);
4151f9e124fbSChristian Lamparter
4152aa0c8636SChristian Lamparter #undef CALL_RXH
4153aa0c8636SChristian Lamparter }
415424a8fdadSChristian Lamparter
4155f9e124fbSChristian Lamparter spin_unlock_bh(&rx->local->rx_path_lock);
4156aa0c8636SChristian Lamparter }
4157571ecf67SJohannes Berg
ieee80211_invoke_rx_handlers(struct ieee80211_rx_data * rx)41584406c376SJohannes Berg static void ieee80211_invoke_rx_handlers(struct ieee80211_rx_data *rx)
415958905290SJohannes Berg {
4160f9e124fbSChristian Lamparter struct sk_buff_head reorder_release;
416158905290SJohannes Berg ieee80211_rx_result res = RX_DROP_MONITOR;
416258905290SJohannes Berg
4163f9e124fbSChristian Lamparter __skb_queue_head_init(&reorder_release);
4164f9e124fbSChristian Lamparter
416549461622SJohannes Berg #define CALL_RXH(rxh) \
4166e32f85f7SLuis Carlos Cobo do { \
416749461622SJohannes Berg res = rxh(rx); \
416849461622SJohannes Berg if (res != RX_CONTINUE) \
41692569a826SJohannes Berg goto rxh_next; \
41708ebaa5b0SJohannes Berg } while (0)
417158905290SJohannes Berg
41728ebaa5b0SJohannes Berg CALL_RXH(ieee80211_rx_h_check_dup);
41738ebaa5b0SJohannes Berg CALL_RXH(ieee80211_rx_h_check);
41742569a826SJohannes Berg
4175f9e124fbSChristian Lamparter ieee80211_rx_reorder_ampdu(rx, &reorder_release);
41762569a826SJohannes Berg
4177f9e124fbSChristian Lamparter ieee80211_rx_handlers(rx, &reorder_release);
4178aa0c8636SChristian Lamparter return;
417949461622SJohannes Berg
41802569a826SJohannes Berg rxh_next:
4181aa0c8636SChristian Lamparter ieee80211_rx_handlers_result(rx, res);
4182aa0c8636SChristian Lamparter
4183aa0c8636SChristian Lamparter #undef CALL_RXH
41842569a826SJohannes Berg }
418558905290SJohannes Berg
4186e66b7920SFelix Fietkau static bool
ieee80211_rx_is_valid_sta_link_id(struct ieee80211_sta * sta,u8 link_id)4187e66b7920SFelix Fietkau ieee80211_rx_is_valid_sta_link_id(struct ieee80211_sta *sta, u8 link_id)
4188e66b7920SFelix Fietkau {
4189e66b7920SFelix Fietkau return !!(sta->valid_links & BIT(link_id));
4190e66b7920SFelix Fietkau }
4191e66b7920SFelix Fietkau
ieee80211_rx_data_set_link(struct ieee80211_rx_data * rx,u8 link_id)4192e66b7920SFelix Fietkau static bool ieee80211_rx_data_set_link(struct ieee80211_rx_data *rx,
4193e66b7920SFelix Fietkau u8 link_id)
4194e66b7920SFelix Fietkau {
4195e66b7920SFelix Fietkau rx->link_id = link_id;
4196e66b7920SFelix Fietkau rx->link = rcu_dereference(rx->sdata->link[link_id]);
4197e66b7920SFelix Fietkau
4198e66b7920SFelix Fietkau if (!rx->sta)
4199e66b7920SFelix Fietkau return rx->link;
4200e66b7920SFelix Fietkau
4201e66b7920SFelix Fietkau if (!ieee80211_rx_is_valid_sta_link_id(&rx->sta->sta, link_id))
4202e66b7920SFelix Fietkau return false;
4203e66b7920SFelix Fietkau
4204e66b7920SFelix Fietkau rx->link_sta = rcu_dereference(rx->sta->link[link_id]);
4205e66b7920SFelix Fietkau
4206e66b7920SFelix Fietkau return rx->link && rx->link_sta;
4207e66b7920SFelix Fietkau }
4208e66b7920SFelix Fietkau
ieee80211_rx_data_set_sta(struct ieee80211_rx_data * rx,struct sta_info * sta,int link_id)4209e66b7920SFelix Fietkau static bool ieee80211_rx_data_set_sta(struct ieee80211_rx_data *rx,
42100d846bdcSJohannes Berg struct sta_info *sta, int link_id)
4211e66b7920SFelix Fietkau {
4212e66b7920SFelix Fietkau rx->link_id = link_id;
4213e66b7920SFelix Fietkau rx->sta = sta;
4214e66b7920SFelix Fietkau
4215e66b7920SFelix Fietkau if (sta) {
4216e66b7920SFelix Fietkau rx->local = sta->sdata->local;
4217e66b7920SFelix Fietkau if (!rx->sdata)
4218e66b7920SFelix Fietkau rx->sdata = sta->sdata;
4219e66b7920SFelix Fietkau rx->link_sta = &sta->deflink;
4220ab5f171eSJohannes Berg } else {
4221ab5f171eSJohannes Berg rx->link_sta = NULL;
4222e66b7920SFelix Fietkau }
4223e66b7920SFelix Fietkau
4224e66b7920SFelix Fietkau if (link_id < 0)
4225e66b7920SFelix Fietkau rx->link = &rx->sdata->deflink;
4226e66b7920SFelix Fietkau else if (!ieee80211_rx_data_set_link(rx, link_id))
4227e66b7920SFelix Fietkau return false;
4228e66b7920SFelix Fietkau
4229e66b7920SFelix Fietkau return true;
4230e66b7920SFelix Fietkau }
4231e66b7920SFelix Fietkau
42322bff8ebfSChristian Lamparter /*
4233dd318575SJohannes Berg * This function makes calls into the RX path, therefore
4234dd318575SJohannes Berg * it has to be invoked under RCU read lock.
42352bff8ebfSChristian Lamparter */
ieee80211_release_reorder_timeout(struct sta_info * sta,int tid)42362bff8ebfSChristian Lamparter void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid)
42372bff8ebfSChristian Lamparter {
4238f9e124fbSChristian Lamparter struct sk_buff_head frames;
4239554891e6SJohannes Berg struct ieee80211_rx_data rx = {
42409e26297aSJohannes Berg /* This is OK -- must be QoS data frame */
42419e26297aSJohannes Berg .security_idx = tid,
42429e26297aSJohannes Berg .seqno_idx = tid,
4243554891e6SJohannes Berg };
42442c15a0cfSChristian Lamparter struct tid_ampdu_rx *tid_agg_rx;
4245e66b7920SFelix Fietkau int link_id = -1;
4246e66b7920SFelix Fietkau
4247e66b7920SFelix Fietkau /* FIXME: statistics won't be right with this */
4248e66b7920SFelix Fietkau if (sta->sta.valid_links)
4249e66b7920SFelix Fietkau link_id = ffs(sta->sta.valid_links) - 1;
4250e66b7920SFelix Fietkau
42510d846bdcSJohannes Berg if (!ieee80211_rx_data_set_sta(&rx, sta, link_id))
4252e66b7920SFelix Fietkau return;
42532c15a0cfSChristian Lamparter
42542c15a0cfSChristian Lamparter tid_agg_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[tid]);
42552c15a0cfSChristian Lamparter if (!tid_agg_rx)
42562c15a0cfSChristian Lamparter return;
42572bff8ebfSChristian Lamparter
4258f9e124fbSChristian Lamparter __skb_queue_head_init(&frames);
4259f9e124fbSChristian Lamparter
42602c15a0cfSChristian Lamparter spin_lock(&tid_agg_rx->reorder_lock);
4261f9e124fbSChristian Lamparter ieee80211_sta_reorder_release(sta->sdata, tid_agg_rx, &frames);
42622c15a0cfSChristian Lamparter spin_unlock(&tid_agg_rx->reorder_lock);
42632bff8ebfSChristian Lamparter
4264b497de63SEmmanuel Grumbach if (!skb_queue_empty(&frames)) {
4265b497de63SEmmanuel Grumbach struct ieee80211_event event = {
4266b497de63SEmmanuel Grumbach .type = BA_FRAME_TIMEOUT,
4267b497de63SEmmanuel Grumbach .u.ba.tid = tid,
4268b497de63SEmmanuel Grumbach .u.ba.sta = &sta->sta,
4269b497de63SEmmanuel Grumbach };
4270b497de63SEmmanuel Grumbach drv_event_callback(rx.local, rx.sdata, &event);
4271b497de63SEmmanuel Grumbach }
4272b497de63SEmmanuel Grumbach
4273f9e124fbSChristian Lamparter ieee80211_rx_handlers(&rx, &frames);
42742bff8ebfSChristian Lamparter }
42752bff8ebfSChristian Lamparter
ieee80211_mark_rx_ba_filtered_frames(struct ieee80211_sta * pubsta,u8 tid,u16 ssn,u64 filtered,u16 received_mpdus)427606470f74SSara Sharon void ieee80211_mark_rx_ba_filtered_frames(struct ieee80211_sta *pubsta, u8 tid,
427706470f74SSara Sharon u16 ssn, u64 filtered,
427806470f74SSara Sharon u16 received_mpdus)
427906470f74SSara Sharon {
4280b98c1610SPing-Ke Shih struct ieee80211_local *local;
428106470f74SSara Sharon struct sta_info *sta;
428206470f74SSara Sharon struct tid_ampdu_rx *tid_agg_rx;
428306470f74SSara Sharon struct sk_buff_head frames;
428406470f74SSara Sharon struct ieee80211_rx_data rx = {
428506470f74SSara Sharon /* This is OK -- must be QoS data frame */
428606470f74SSara Sharon .security_idx = tid,
428706470f74SSara Sharon .seqno_idx = tid,
428806470f74SSara Sharon };
428906470f74SSara Sharon int i, diff;
429006470f74SSara Sharon
429106470f74SSara Sharon if (WARN_ON(!pubsta || tid >= IEEE80211_NUM_TIDS))
429206470f74SSara Sharon return;
429306470f74SSara Sharon
429406470f74SSara Sharon __skb_queue_head_init(&frames);
429506470f74SSara Sharon
429606470f74SSara Sharon sta = container_of(pubsta, struct sta_info, sta);
429706470f74SSara Sharon
4298b98c1610SPing-Ke Shih local = sta->sdata->local;
4299b98c1610SPing-Ke Shih WARN_ONCE(local->hw.max_rx_aggregation_subframes > 64,
4300b98c1610SPing-Ke Shih "RX BA marker can't support max_rx_aggregation_subframes %u > 64\n",
4301b98c1610SPing-Ke Shih local->hw.max_rx_aggregation_subframes);
4302b98c1610SPing-Ke Shih
43030d846bdcSJohannes Berg if (!ieee80211_rx_data_set_sta(&rx, sta, -1))
4304e66b7920SFelix Fietkau return;
430506470f74SSara Sharon
430606470f74SSara Sharon rcu_read_lock();
430706470f74SSara Sharon tid_agg_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[tid]);
430806470f74SSara Sharon if (!tid_agg_rx)
430906470f74SSara Sharon goto out;
431006470f74SSara Sharon
431106470f74SSara Sharon spin_lock_bh(&tid_agg_rx->reorder_lock);
431206470f74SSara Sharon
431306470f74SSara Sharon if (received_mpdus >= IEEE80211_SN_MODULO >> 1) {
431406470f74SSara Sharon int release;
431506470f74SSara Sharon
431606470f74SSara Sharon /* release all frames in the reorder buffer */
431706470f74SSara Sharon release = (tid_agg_rx->head_seq_num + tid_agg_rx->buf_size) %
431806470f74SSara Sharon IEEE80211_SN_MODULO;
431906470f74SSara Sharon ieee80211_release_reorder_frames(sta->sdata, tid_agg_rx,
432006470f74SSara Sharon release, &frames);
432106470f74SSara Sharon /* update ssn to match received ssn */
432206470f74SSara Sharon tid_agg_rx->head_seq_num = ssn;
432306470f74SSara Sharon } else {
432406470f74SSara Sharon ieee80211_release_reorder_frames(sta->sdata, tid_agg_rx, ssn,
432506470f74SSara Sharon &frames);
432606470f74SSara Sharon }
432706470f74SSara Sharon
432806470f74SSara Sharon /* handle the case that received ssn is behind the mac ssn.
432906470f74SSara Sharon * it can be tid_agg_rx->buf_size behind and still be valid */
433006470f74SSara Sharon diff = (tid_agg_rx->head_seq_num - ssn) & IEEE80211_SN_MASK;
433106470f74SSara Sharon if (diff >= tid_agg_rx->buf_size) {
433206470f74SSara Sharon tid_agg_rx->reorder_buf_filtered = 0;
433306470f74SSara Sharon goto release;
433406470f74SSara Sharon }
433506470f74SSara Sharon filtered = filtered >> diff;
433606470f74SSara Sharon ssn += diff;
433706470f74SSara Sharon
433806470f74SSara Sharon /* update bitmap */
433906470f74SSara Sharon for (i = 0; i < tid_agg_rx->buf_size; i++) {
434006470f74SSara Sharon int index = (ssn + i) % tid_agg_rx->buf_size;
434106470f74SSara Sharon
434206470f74SSara Sharon tid_agg_rx->reorder_buf_filtered &= ~BIT_ULL(index);
434306470f74SSara Sharon if (filtered & BIT_ULL(i))
434406470f74SSara Sharon tid_agg_rx->reorder_buf_filtered |= BIT_ULL(index);
434506470f74SSara Sharon }
434606470f74SSara Sharon
434706470f74SSara Sharon /* now process also frames that the filter marking released */
434806470f74SSara Sharon ieee80211_sta_reorder_release(sta->sdata, tid_agg_rx, &frames);
434906470f74SSara Sharon
435006470f74SSara Sharon release:
435106470f74SSara Sharon spin_unlock_bh(&tid_agg_rx->reorder_lock);
435206470f74SSara Sharon
435306470f74SSara Sharon ieee80211_rx_handlers(&rx, &frames);
435406470f74SSara Sharon
435506470f74SSara Sharon out:
435606470f74SSara Sharon rcu_read_unlock();
435706470f74SSara Sharon }
435806470f74SSara Sharon EXPORT_SYMBOL(ieee80211_mark_rx_ba_filtered_frames);
435906470f74SSara Sharon
4360571ecf67SJohannes Berg /* main receive path */
4361571ecf67SJohannes Berg
ieee80211_bssid_match(const u8 * raddr,const u8 * addr)43627e60096fSJohannes Berg static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr)
43637e60096fSJohannes Berg {
43647e60096fSJohannes Berg return ether_addr_equal(raddr, addr) ||
43657e60096fSJohannes Berg is_broadcast_ether_addr(raddr);
43667e60096fSJohannes Berg }
43677e60096fSJohannes Berg
ieee80211_accept_frame(struct ieee80211_rx_data * rx)4368a58fbe1aSJohannes Berg static bool ieee80211_accept_frame(struct ieee80211_rx_data *rx)
436923a24defSJohannes Berg {
437020b01f80SJohannes Berg struct ieee80211_sub_if_data *sdata = rx->sdata;
4371eb9fb5b8SJohannes Berg struct sk_buff *skb = rx->skb;
4372a58fbe1aSJohannes Berg struct ieee80211_hdr *hdr = (void *)skb->data;
4373eb9fb5b8SJohannes Berg struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
4374eb9fb5b8SJohannes Berg u8 *bssid = ieee80211_get_bssid(hdr, skb->len, sdata->vif.type);
437509a740ceSThomas Pedersen bool multicast = is_multicast_ether_addr(hdr->addr1) ||
437609a740ceSThomas Pedersen ieee80211_is_s1g_beacon(hdr->frame_control);
437723a24defSJohannes Berg
437851fb61e7SJohannes Berg switch (sdata->vif.type) {
437905c914feSJohannes Berg case NL80211_IFTYPE_STATION:
43809bc383deSJohannes Berg if (!bssid && !sdata->u.mgd.use_4addr)
43813c2723f5SJohannes Berg return false;
4382e6f5dcb7SGilad Itzkovitch if (ieee80211_is_first_frag(hdr->seq_ctrl) &&
4383e6f5dcb7SGilad Itzkovitch ieee80211_is_robust_mgmt_frame(skb) && !rx->sta)
4384588f7d39SJohannes Berg return false;
4385a58fbe1aSJohannes Berg if (multicast)
4386a58fbe1aSJohannes Berg return true;
4387892b3bceSJohannes Berg return ieee80211_is_our_addr(sdata, hdr->addr1, &rx->link_id);
438805c914feSJohannes Berg case NL80211_IFTYPE_ADHOC:
438923a24defSJohannes Berg if (!bssid)
43903c2723f5SJohannes Berg return false;
43916329b8d9SFelix Fietkau if (ether_addr_equal(sdata->vif.addr, hdr->addr2) ||
4392a6555f84SYueHaibing ether_addr_equal(sdata->u.ibss.bssid, hdr->addr2) ||
4393a6555f84SYueHaibing !is_valid_ether_addr(hdr->addr2))
43943c2723f5SJohannes Berg return false;
4395a58fbe1aSJohannes Berg if (ieee80211_is_beacon(hdr->frame_control))
43963c2723f5SJohannes Berg return true;
4397a58fbe1aSJohannes Berg if (!ieee80211_bssid_match(bssid, sdata->u.ibss.bssid))
43983c2723f5SJohannes Berg return false;
4399a58fbe1aSJohannes Berg if (!multicast &&
4400a58fbe1aSJohannes Berg !ether_addr_equal(sdata->vif.addr, hdr->addr1))
44013c2723f5SJohannes Berg return false;
4402a58fbe1aSJohannes Berg if (!rx->sta) {
44030fb8ca45SJouni Malinen int rate_idx;
4404da6a4352SJohannes Berg if (status->encoding != RX_ENC_LEGACY)
44055614618eSJohannes Berg rate_idx = 0; /* TODO: HT/VHT rates */
44060fb8ca45SJouni Malinen else
4407eb9fb5b8SJohannes Berg rate_idx = status->rate_idx;
44088bf11d8dSJohannes Berg ieee80211_ibss_rx_no_sta(sdata, bssid, hdr->addr2,
44098bf11d8dSJohannes Berg BIT(rate_idx));
44100fb8ca45SJouni Malinen }
4411a58fbe1aSJohannes Berg return true;
4412239281f8SRostislav Lisovy case NL80211_IFTYPE_OCB:
4413239281f8SRostislav Lisovy if (!bssid)
4414239281f8SRostislav Lisovy return false;
4415cc117298SBertold Van den Bergh if (!ieee80211_is_data_present(hdr->frame_control))
4416239281f8SRostislav Lisovy return false;
4417a58fbe1aSJohannes Berg if (!is_broadcast_ether_addr(bssid))
4418239281f8SRostislav Lisovy return false;
4419a58fbe1aSJohannes Berg if (!multicast &&
4420a58fbe1aSJohannes Berg !ether_addr_equal(sdata->dev->dev_addr, hdr->addr1))
4421239281f8SRostislav Lisovy return false;
4422a58fbe1aSJohannes Berg if (!rx->sta) {
4423239281f8SRostislav Lisovy int rate_idx;
4424da6a4352SJohannes Berg if (status->encoding != RX_ENC_LEGACY)
4425239281f8SRostislav Lisovy rate_idx = 0; /* TODO: HT rates */
4426239281f8SRostislav Lisovy else
4427239281f8SRostislav Lisovy rate_idx = status->rate_idx;
4428239281f8SRostislav Lisovy ieee80211_ocb_rx_no_sta(sdata, bssid, hdr->addr2,
4429239281f8SRostislav Lisovy BIT(rate_idx));
4430239281f8SRostislav Lisovy }
4431a58fbe1aSJohannes Berg return true;
443205c914feSJohannes Berg case NL80211_IFTYPE_MESH_POINT:
4433736a80bbSJohannes Berg if (ether_addr_equal(sdata->vif.addr, hdr->addr2))
4434736a80bbSJohannes Berg return false;
4435a58fbe1aSJohannes Berg if (multicast)
4436a58fbe1aSJohannes Berg return true;
4437a58fbe1aSJohannes Berg return ether_addr_equal(sdata->vif.addr, hdr->addr1);
443805c914feSJohannes Berg case NL80211_IFTYPE_AP_VLAN:
443905c914feSJohannes Berg case NL80211_IFTYPE_AP:
4440a58fbe1aSJohannes Berg if (!bssid)
4441892b3bceSJohannes Berg return ieee80211_is_our_addr(sdata, hdr->addr1,
4442892b3bceSJohannes Berg &rx->link_id);
4443a58fbe1aSJohannes Berg
4444892b3bceSJohannes Berg if (!is_broadcast_ether_addr(bssid) &&
4445892b3bceSJohannes Berg !ieee80211_is_our_addr(sdata, bssid, NULL)) {
44463df6eaeaSJohannes Berg /*
44473df6eaeaSJohannes Berg * Accept public action frames even when the
44483df6eaeaSJohannes Berg * BSSID doesn't match, this is used for P2P
44493df6eaeaSJohannes Berg * and location updates. Note that mac80211
44503df6eaeaSJohannes Berg * itself never looks at these frames.
44513df6eaeaSJohannes Berg */
44522b9ccd4eSJohannes Berg if (!multicast &&
4453892b3bceSJohannes Berg !ieee80211_is_our_addr(sdata, hdr->addr1,
4454892b3bceSJohannes Berg &rx->link_id))
44553c2723f5SJohannes Berg return false;
4456d48b2968SJohannes Berg if (ieee80211_is_public_action(hdr, skb->len))
44573c2723f5SJohannes Berg return true;
44585c90067cSJohannes Berg return ieee80211_is_beacon(hdr->frame_control);
4459a58fbe1aSJohannes Berg }
4460a58fbe1aSJohannes Berg
4461a58fbe1aSJohannes Berg if (!ieee80211_has_tods(hdr->frame_control)) {
4462db8e1732SArik Nemtsov /* ignore data frames to TDLS-peers */
4463db8e1732SArik Nemtsov if (ieee80211_is_data(hdr->frame_control))
4464db8e1732SArik Nemtsov return false;
4465db8e1732SArik Nemtsov /* ignore action frames to TDLS-peers */
4466db8e1732SArik Nemtsov if (ieee80211_is_action(hdr->frame_control) &&
44671ec7bae8SJouni Malinen !is_broadcast_ether_addr(bssid) &&
4468db8e1732SArik Nemtsov !ether_addr_equal(bssid, hdr->addr1))
4469db8e1732SArik Nemtsov return false;
447023a24defSJohannes Berg }
44713018e947SJohannes Berg
44723018e947SJohannes Berg /*
44733018e947SJohannes Berg * 802.11-2016 Table 9-26 says that for data frames, A1 must be
44743018e947SJohannes Berg * the BSSID - we've checked that already but may have accepted
44753018e947SJohannes Berg * the wildcard (ff:ff:ff:ff:ff:ff).
44763018e947SJohannes Berg *
44773018e947SJohannes Berg * It also says:
44783018e947SJohannes Berg * The BSSID of the Data frame is determined as follows:
44793018e947SJohannes Berg * a) If the STA is contained within an AP or is associated
44803018e947SJohannes Berg * with an AP, the BSSID is the address currently in use
44813018e947SJohannes Berg * by the STA contained in the AP.
44823018e947SJohannes Berg *
44833018e947SJohannes Berg * So we should not accept data frames with an address that's
44843018e947SJohannes Berg * multicast.
44853018e947SJohannes Berg *
44863018e947SJohannes Berg * Accepting it also opens a security problem because stations
44873018e947SJohannes Berg * could encrypt it with the GTK and inject traffic that way.
44883018e947SJohannes Berg */
44893018e947SJohannes Berg if (ieee80211_is_data(hdr->frame_control) && multicast)
44903018e947SJohannes Berg return false;
44913018e947SJohannes Berg
4492a58fbe1aSJohannes Berg return true;
4493f142c6b9SJohannes Berg case NL80211_IFTYPE_P2P_DEVICE:
4494a58fbe1aSJohannes Berg return ieee80211_is_public_action(hdr, skb->len) ||
4495a58fbe1aSJohannes Berg ieee80211_is_probe_req(hdr->frame_control) ||
4496a58fbe1aSJohannes Berg ieee80211_is_probe_resp(hdr->frame_control) ||
4497a58fbe1aSJohannes Berg ieee80211_is_beacon(hdr->frame_control);
4498cb3b7d87SAyala Beker case NL80211_IFTYPE_NAN:
4499cb3b7d87SAyala Beker /* Currently no frames on NAN interface are allowed */
4500cb3b7d87SAyala Beker return false;
45012ca27bcfSJohannes Berg default:
4502fb1c1cd6SJohannes Berg break;
450323a24defSJohannes Berg }
450423a24defSJohannes Berg
4505a58fbe1aSJohannes Berg WARN_ON_ONCE(1);
4506a58fbe1aSJohannes Berg return false;
450723a24defSJohannes Berg }
450823a24defSJohannes Berg
ieee80211_check_fast_rx(struct sta_info * sta)450949ddf8e6SJohannes Berg void ieee80211_check_fast_rx(struct sta_info *sta)
451049ddf8e6SJohannes Berg {
451149ddf8e6SJohannes Berg struct ieee80211_sub_if_data *sdata = sta->sdata;
451249ddf8e6SJohannes Berg struct ieee80211_local *local = sdata->local;
451349ddf8e6SJohannes Berg struct ieee80211_key *key;
451449ddf8e6SJohannes Berg struct ieee80211_fast_rx fastrx = {
451549ddf8e6SJohannes Berg .dev = sdata->dev,
451649ddf8e6SJohannes Berg .vif_type = sdata->vif.type,
451749ddf8e6SJohannes Berg .control_port_protocol = sdata->control_port_protocol,
451849ddf8e6SJohannes Berg }, *old, *new = NULL;
45193bf9e30eSFelix Fietkau u32 offload_flags;
452080a915ecSFelix Fietkau bool set_offload = false;
452149ddf8e6SJohannes Berg bool assign = false;
452280a915ecSFelix Fietkau bool offload;
452349ddf8e6SJohannes Berg
452449ddf8e6SJohannes Berg /* use sparse to check that we don't return without updating */
452549ddf8e6SJohannes Berg __acquire(check_fast_rx);
452649ddf8e6SJohannes Berg
452749ddf8e6SJohannes Berg BUILD_BUG_ON(sizeof(fastrx.rfc1042_hdr) != sizeof(rfc1042_header));
452849ddf8e6SJohannes Berg BUILD_BUG_ON(sizeof(fastrx.rfc1042_hdr) != ETH_ALEN);
452949ddf8e6SJohannes Berg ether_addr_copy(fastrx.rfc1042_hdr, rfc1042_header);
453049ddf8e6SJohannes Berg ether_addr_copy(fastrx.vif_addr, sdata->vif.addr);
453149ddf8e6SJohannes Berg
4532c9c5962bSJohannes Berg fastrx.uses_rss = ieee80211_hw_check(&local->hw, USES_RSS);
4533c9c5962bSJohannes Berg
453449ddf8e6SJohannes Berg /* fast-rx doesn't do reordering */
453549ddf8e6SJohannes Berg if (ieee80211_hw_check(&local->hw, AMPDU_AGGREGATION) &&
453649ddf8e6SJohannes Berg !ieee80211_hw_check(&local->hw, SUPPORTS_REORDERING_BUFFER))
453749ddf8e6SJohannes Berg goto clear;
453849ddf8e6SJohannes Berg
453949ddf8e6SJohannes Berg switch (sdata->vif.type) {
454049ddf8e6SJohannes Berg case NL80211_IFTYPE_STATION:
454149ddf8e6SJohannes Berg if (sta->sta.tdls) {
454249ddf8e6SJohannes Berg fastrx.da_offs = offsetof(struct ieee80211_hdr, addr1);
454349ddf8e6SJohannes Berg fastrx.sa_offs = offsetof(struct ieee80211_hdr, addr2);
454449ddf8e6SJohannes Berg fastrx.expected_ds_bits = 0;
454549ddf8e6SJohannes Berg } else {
454649ddf8e6SJohannes Berg fastrx.da_offs = offsetof(struct ieee80211_hdr, addr1);
454749ddf8e6SJohannes Berg fastrx.sa_offs = offsetof(struct ieee80211_hdr, addr3);
454849ddf8e6SJohannes Berg fastrx.expected_ds_bits =
454949ddf8e6SJohannes Berg cpu_to_le16(IEEE80211_FCTL_FROMDS);
455049ddf8e6SJohannes Berg }
45511d870162SFelix Fietkau
45529251a473SFelix Fietkau if (sdata->u.mgd.use_4addr && !sta->sta.tdls) {
45539251a473SFelix Fietkau fastrx.expected_ds_bits |=
45549251a473SFelix Fietkau cpu_to_le16(IEEE80211_FCTL_TODS);
45559251a473SFelix Fietkau fastrx.da_offs = offsetof(struct ieee80211_hdr, addr3);
45569251a473SFelix Fietkau fastrx.sa_offs = offsetof(struct ieee80211_hdr, addr4);
45579251a473SFelix Fietkau }
45589251a473SFelix Fietkau
45591d870162SFelix Fietkau if (!sdata->u.mgd.powersave)
45601d870162SFelix Fietkau break;
45611d870162SFelix Fietkau
45621d870162SFelix Fietkau /* software powersave is a huge mess, avoid all of it */
45631d870162SFelix Fietkau if (ieee80211_hw_check(&local->hw, PS_NULLFUNC_STACK))
45641d870162SFelix Fietkau goto clear;
45651d870162SFelix Fietkau if (ieee80211_hw_check(&local->hw, SUPPORTS_PS) &&
45661d870162SFelix Fietkau !ieee80211_hw_check(&local->hw, SUPPORTS_DYNAMIC_PS))
45671d870162SFelix Fietkau goto clear;
456849ddf8e6SJohannes Berg break;
456949ddf8e6SJohannes Berg case NL80211_IFTYPE_AP_VLAN:
457049ddf8e6SJohannes Berg case NL80211_IFTYPE_AP:
457149ddf8e6SJohannes Berg /* parallel-rx requires this, at least with calls to
457249ddf8e6SJohannes Berg * ieee80211_sta_ps_transition()
457349ddf8e6SJohannes Berg */
457449ddf8e6SJohannes Berg if (!ieee80211_hw_check(&local->hw, AP_LINK_PS))
457549ddf8e6SJohannes Berg goto clear;
457649ddf8e6SJohannes Berg fastrx.da_offs = offsetof(struct ieee80211_hdr, addr3);
457749ddf8e6SJohannes Berg fastrx.sa_offs = offsetof(struct ieee80211_hdr, addr2);
457849ddf8e6SJohannes Berg fastrx.expected_ds_bits = cpu_to_le16(IEEE80211_FCTL_TODS);
457949ddf8e6SJohannes Berg
458049ddf8e6SJohannes Berg fastrx.internal_forward =
458149ddf8e6SJohannes Berg !(sdata->flags & IEEE80211_SDATA_DONT_BRIDGE_PACKETS) &&
458249ddf8e6SJohannes Berg (sdata->vif.type != NL80211_IFTYPE_AP_VLAN ||
458349ddf8e6SJohannes Berg !sdata->u.vlan.sta);
458459cae5b9SFelix Fietkau
458559cae5b9SFelix Fietkau if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
458659cae5b9SFelix Fietkau sdata->u.vlan.sta) {
458759cae5b9SFelix Fietkau fastrx.expected_ds_bits |=
458859cae5b9SFelix Fietkau cpu_to_le16(IEEE80211_FCTL_FROMDS);
458959cae5b9SFelix Fietkau fastrx.sa_offs = offsetof(struct ieee80211_hdr, addr4);
459059cae5b9SFelix Fietkau fastrx.internal_forward = 0;
459159cae5b9SFelix Fietkau }
459259cae5b9SFelix Fietkau
459349ddf8e6SJohannes Berg break;
45943468e1e0SFelix Fietkau case NL80211_IFTYPE_MESH_POINT:
45953468e1e0SFelix Fietkau fastrx.expected_ds_bits = cpu_to_le16(IEEE80211_FCTL_FROMDS |
45963468e1e0SFelix Fietkau IEEE80211_FCTL_TODS);
45973468e1e0SFelix Fietkau fastrx.da_offs = offsetof(struct ieee80211_hdr, addr3);
45983468e1e0SFelix Fietkau fastrx.sa_offs = offsetof(struct ieee80211_hdr, addr4);
45993468e1e0SFelix Fietkau break;
460049ddf8e6SJohannes Berg default:
460149ddf8e6SJohannes Berg goto clear;
460249ddf8e6SJohannes Berg }
460349ddf8e6SJohannes Berg
460449ddf8e6SJohannes Berg if (!test_sta_flag(sta, WLAN_STA_AUTHORIZED))
460549ddf8e6SJohannes Berg goto clear;
460649ddf8e6SJohannes Berg
460749ddf8e6SJohannes Berg rcu_read_lock();
460849ddf8e6SJohannes Berg key = rcu_dereference(sta->ptk[sta->ptk_idx]);
4609622d3b4eSFelix Fietkau if (!key)
4610622d3b4eSFelix Fietkau key = rcu_dereference(sdata->default_unicast_key);
461149ddf8e6SJohannes Berg if (key) {
461249ddf8e6SJohannes Berg switch (key->conf.cipher) {
461349ddf8e6SJohannes Berg case WLAN_CIPHER_SUITE_TKIP:
461449ddf8e6SJohannes Berg /* we don't want to deal with MMIC in fast-rx */
461549ddf8e6SJohannes Berg goto clear_rcu;
461649ddf8e6SJohannes Berg case WLAN_CIPHER_SUITE_CCMP:
461749ddf8e6SJohannes Berg case WLAN_CIPHER_SUITE_CCMP_256:
461849ddf8e6SJohannes Berg case WLAN_CIPHER_SUITE_GCMP:
461949ddf8e6SJohannes Berg case WLAN_CIPHER_SUITE_GCMP_256:
462049ddf8e6SJohannes Berg break;
462149ddf8e6SJohannes Berg default:
462296fc6efbSAlexander Wetzel /* We also don't want to deal with
462396fc6efbSAlexander Wetzel * WEP or cipher scheme.
462449ddf8e6SJohannes Berg */
462549ddf8e6SJohannes Berg goto clear_rcu;
462649ddf8e6SJohannes Berg }
462749ddf8e6SJohannes Berg
462849ddf8e6SJohannes Berg fastrx.key = true;
462949ddf8e6SJohannes Berg fastrx.icv_len = key->conf.icv_len;
463049ddf8e6SJohannes Berg }
463149ddf8e6SJohannes Berg
463249ddf8e6SJohannes Berg assign = true;
463349ddf8e6SJohannes Berg clear_rcu:
463449ddf8e6SJohannes Berg rcu_read_unlock();
463549ddf8e6SJohannes Berg clear:
463649ddf8e6SJohannes Berg __release(check_fast_rx);
463749ddf8e6SJohannes Berg
463849ddf8e6SJohannes Berg if (assign)
463949ddf8e6SJohannes Berg new = kmemdup(&fastrx, sizeof(fastrx), GFP_KERNEL);
464049ddf8e6SJohannes Berg
46413bf9e30eSFelix Fietkau offload_flags = get_bss_sdata(sdata)->vif.offload_flags;
46423bf9e30eSFelix Fietkau offload = offload_flags & IEEE80211_OFFLOAD_DECAP_ENABLED;
464380a915ecSFelix Fietkau
46443bf9e30eSFelix Fietkau if (assign && offload)
464580a915ecSFelix Fietkau set_offload = !test_and_set_sta_flag(sta, WLAN_STA_DECAP_OFFLOAD);
464680a915ecSFelix Fietkau else
464780a915ecSFelix Fietkau set_offload = test_and_clear_sta_flag(sta, WLAN_STA_DECAP_OFFLOAD);
464880a915ecSFelix Fietkau
464980a915ecSFelix Fietkau if (set_offload)
465080a915ecSFelix Fietkau drv_sta_set_decap_offload(local, sdata, &sta->sta, assign);
465180a915ecSFelix Fietkau
465249ddf8e6SJohannes Berg spin_lock_bh(&sta->lock);
465349ddf8e6SJohannes Berg old = rcu_dereference_protected(sta->fast_rx, true);
465449ddf8e6SJohannes Berg rcu_assign_pointer(sta->fast_rx, new);
465549ddf8e6SJohannes Berg spin_unlock_bh(&sta->lock);
465649ddf8e6SJohannes Berg
465749ddf8e6SJohannes Berg if (old)
465849ddf8e6SJohannes Berg kfree_rcu(old, rcu_head);
465949ddf8e6SJohannes Berg }
466049ddf8e6SJohannes Berg
ieee80211_clear_fast_rx(struct sta_info * sta)466149ddf8e6SJohannes Berg void ieee80211_clear_fast_rx(struct sta_info *sta)
466249ddf8e6SJohannes Berg {
466349ddf8e6SJohannes Berg struct ieee80211_fast_rx *old;
466449ddf8e6SJohannes Berg
466549ddf8e6SJohannes Berg spin_lock_bh(&sta->lock);
466649ddf8e6SJohannes Berg old = rcu_dereference_protected(sta->fast_rx, true);
466749ddf8e6SJohannes Berg RCU_INIT_POINTER(sta->fast_rx, NULL);
466849ddf8e6SJohannes Berg spin_unlock_bh(&sta->lock);
466949ddf8e6SJohannes Berg
467049ddf8e6SJohannes Berg if (old)
467149ddf8e6SJohannes Berg kfree_rcu(old, rcu_head);
467249ddf8e6SJohannes Berg }
467349ddf8e6SJohannes Berg
__ieee80211_check_fast_rx_iface(struct ieee80211_sub_if_data * sdata)467449ddf8e6SJohannes Berg void __ieee80211_check_fast_rx_iface(struct ieee80211_sub_if_data *sdata)
467549ddf8e6SJohannes Berg {
467649ddf8e6SJohannes Berg struct ieee80211_local *local = sdata->local;
467749ddf8e6SJohannes Berg struct sta_info *sta;
467849ddf8e6SJohannes Berg
467949ddf8e6SJohannes Berg lockdep_assert_held(&local->sta_mtx);
468049ddf8e6SJohannes Berg
4681253216ffSMadhuparna Bhowmik list_for_each_entry(sta, &local->sta_list, list) {
468249ddf8e6SJohannes Berg if (sdata != sta->sdata &&
468349ddf8e6SJohannes Berg (!sta->sdata->bss || sta->sdata->bss != sdata->bss))
468449ddf8e6SJohannes Berg continue;
468549ddf8e6SJohannes Berg ieee80211_check_fast_rx(sta);
468649ddf8e6SJohannes Berg }
468749ddf8e6SJohannes Berg }
468849ddf8e6SJohannes Berg
ieee80211_check_fast_rx_iface(struct ieee80211_sub_if_data * sdata)468949ddf8e6SJohannes Berg void ieee80211_check_fast_rx_iface(struct ieee80211_sub_if_data *sdata)
469049ddf8e6SJohannes Berg {
469149ddf8e6SJohannes Berg struct ieee80211_local *local = sdata->local;
469249ddf8e6SJohannes Berg
469349ddf8e6SJohannes Berg mutex_lock(&local->sta_mtx);
469449ddf8e6SJohannes Berg __ieee80211_check_fast_rx_iface(sdata);
469549ddf8e6SJohannes Berg mutex_unlock(&local->sta_mtx);
469649ddf8e6SJohannes Berg }
469749ddf8e6SJohannes Berg
ieee80211_rx_8023(struct ieee80211_rx_data * rx,struct ieee80211_fast_rx * fast_rx,int orig_len)469880a915ecSFelix Fietkau static void ieee80211_rx_8023(struct ieee80211_rx_data *rx,
469980a915ecSFelix Fietkau struct ieee80211_fast_rx *fast_rx,
470080a915ecSFelix Fietkau int orig_len)
470180a915ecSFelix Fietkau {
470280a915ecSFelix Fietkau struct ieee80211_sta_rx_stats *stats;
470380a915ecSFelix Fietkau struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
470480a915ecSFelix Fietkau struct sta_info *sta = rx->sta;
470543635a5aSVasanthakumar Thiagarajan struct link_sta_info *link_sta;
470680a915ecSFelix Fietkau struct sk_buff *skb = rx->skb;
470780a915ecSFelix Fietkau void *sa = skb->data + ETH_ALEN;
470880a915ecSFelix Fietkau void *da = skb->data;
470980a915ecSFelix Fietkau
471043635a5aSVasanthakumar Thiagarajan if (rx->link_id >= 0) {
471143635a5aSVasanthakumar Thiagarajan link_sta = rcu_dereference(sta->link[rx->link_id]);
471243635a5aSVasanthakumar Thiagarajan if (WARN_ON_ONCE(!link_sta)) {
471343635a5aSVasanthakumar Thiagarajan dev_kfree_skb(rx->skb);
471443635a5aSVasanthakumar Thiagarajan return;
471543635a5aSVasanthakumar Thiagarajan }
471643635a5aSVasanthakumar Thiagarajan } else {
471743635a5aSVasanthakumar Thiagarajan link_sta = &sta->deflink;
471843635a5aSVasanthakumar Thiagarajan }
471943635a5aSVasanthakumar Thiagarajan
472043635a5aSVasanthakumar Thiagarajan stats = &link_sta->rx_stats;
472180a915ecSFelix Fietkau if (fast_rx->uses_rss)
472243635a5aSVasanthakumar Thiagarajan stats = this_cpu_ptr(link_sta->pcpu_rx_stats);
472380a915ecSFelix Fietkau
472480a915ecSFelix Fietkau /* statistics part of ieee80211_rx_h_sta_process() */
472580a915ecSFelix Fietkau if (!(status->flag & RX_FLAG_NO_SIGNAL_VAL)) {
472680a915ecSFelix Fietkau stats->last_signal = status->signal;
472780a915ecSFelix Fietkau if (!fast_rx->uses_rss)
472843635a5aSVasanthakumar Thiagarajan ewma_signal_add(&link_sta->rx_stats_avg.signal,
472980a915ecSFelix Fietkau -status->signal);
473080a915ecSFelix Fietkau }
473180a915ecSFelix Fietkau
473280a915ecSFelix Fietkau if (status->chains) {
473380a915ecSFelix Fietkau int i;
473480a915ecSFelix Fietkau
473580a915ecSFelix Fietkau stats->chains = status->chains;
473680a915ecSFelix Fietkau for (i = 0; i < ARRAY_SIZE(status->chain_signal); i++) {
473780a915ecSFelix Fietkau int signal = status->chain_signal[i];
473880a915ecSFelix Fietkau
473980a915ecSFelix Fietkau if (!(status->chains & BIT(i)))
474080a915ecSFelix Fietkau continue;
474180a915ecSFelix Fietkau
474280a915ecSFelix Fietkau stats->chain_signal_last[i] = signal;
474380a915ecSFelix Fietkau if (!fast_rx->uses_rss)
474443635a5aSVasanthakumar Thiagarajan ewma_signal_add(&link_sta->rx_stats_avg.chain_signal[i],
474580a915ecSFelix Fietkau -signal);
474680a915ecSFelix Fietkau }
474780a915ecSFelix Fietkau }
474880a915ecSFelix Fietkau /* end of statistics */
474980a915ecSFelix Fietkau
475080a915ecSFelix Fietkau stats->last_rx = jiffies;
475180a915ecSFelix Fietkau stats->last_rate = sta_stats_encode_rate(status);
475280a915ecSFelix Fietkau
475380a915ecSFelix Fietkau stats->fragments++;
475480a915ecSFelix Fietkau stats->packets++;
475580a915ecSFelix Fietkau
475680a915ecSFelix Fietkau skb->dev = fast_rx->dev;
475780a915ecSFelix Fietkau
475880a915ecSFelix Fietkau dev_sw_netstats_rx_add(fast_rx->dev, skb->len);
475980a915ecSFelix Fietkau
476080a915ecSFelix Fietkau /* The seqno index has the same property as needed
476180a915ecSFelix Fietkau * for the rx_msdu field, i.e. it is IEEE80211_NUM_TIDS
476280a915ecSFelix Fietkau * for non-QoS-data frames. Here we know it's a data
476380a915ecSFelix Fietkau * frame, so count MSDUs.
476480a915ecSFelix Fietkau */
476580a915ecSFelix Fietkau u64_stats_update_begin(&stats->syncp);
476680a915ecSFelix Fietkau stats->msdu[rx->seqno_idx]++;
476780a915ecSFelix Fietkau stats->bytes += orig_len;
476880a915ecSFelix Fietkau u64_stats_update_end(&stats->syncp);
476980a915ecSFelix Fietkau
477080a915ecSFelix Fietkau if (fast_rx->internal_forward) {
477180a915ecSFelix Fietkau struct sk_buff *xmit_skb = NULL;
477280a915ecSFelix Fietkau if (is_multicast_ether_addr(da)) {
477380a915ecSFelix Fietkau xmit_skb = skb_copy(skb, GFP_ATOMIC);
477480a915ecSFelix Fietkau } else if (!ether_addr_equal(da, sa) &&
477580a915ecSFelix Fietkau sta_info_get(rx->sdata, da)) {
477680a915ecSFelix Fietkau xmit_skb = skb;
477780a915ecSFelix Fietkau skb = NULL;
477880a915ecSFelix Fietkau }
477980a915ecSFelix Fietkau
478080a915ecSFelix Fietkau if (xmit_skb) {
478180a915ecSFelix Fietkau /*
478280a915ecSFelix Fietkau * Send to wireless media and increase priority by 256
478380a915ecSFelix Fietkau * to keep the received priority instead of
478480a915ecSFelix Fietkau * reclassifying the frame (see cfg80211_classify8021d).
478580a915ecSFelix Fietkau */
478680a915ecSFelix Fietkau xmit_skb->priority += 256;
478780a915ecSFelix Fietkau xmit_skb->protocol = htons(ETH_P_802_3);
478880a915ecSFelix Fietkau skb_reset_network_header(xmit_skb);
478980a915ecSFelix Fietkau skb_reset_mac_header(xmit_skb);
479080a915ecSFelix Fietkau dev_queue_xmit(xmit_skb);
479180a915ecSFelix Fietkau }
479280a915ecSFelix Fietkau
479380a915ecSFelix Fietkau if (!skb)
479480a915ecSFelix Fietkau return;
479580a915ecSFelix Fietkau }
479680a915ecSFelix Fietkau
479780a915ecSFelix Fietkau /* deliver to local stack */
479880a915ecSFelix Fietkau skb->protocol = eth_type_trans(skb, fast_rx->dev);
4799610d086dSDeren Wu ieee80211_deliver_skb_to_local_stack(skb, rx);
480080a915ecSFelix Fietkau }
480180a915ecSFelix Fietkau
ieee80211_invoke_fast_rx(struct ieee80211_rx_data * rx,struct ieee80211_fast_rx * fast_rx)480249ddf8e6SJohannes Berg static bool ieee80211_invoke_fast_rx(struct ieee80211_rx_data *rx,
480349ddf8e6SJohannes Berg struct ieee80211_fast_rx *fast_rx)
480449ddf8e6SJohannes Berg {
480549ddf8e6SJohannes Berg struct sk_buff *skb = rx->skb;
480649ddf8e6SJohannes Berg struct ieee80211_hdr *hdr = (void *)skb->data;
480749ddf8e6SJohannes Berg struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
48083468e1e0SFelix Fietkau static ieee80211_rx_result res;
480949ddf8e6SJohannes Berg int orig_len = skb->len;
481024bba078SFelix Fietkau int hdrlen = ieee80211_hdrlen(hdr->frame_control);
481124bba078SFelix Fietkau int snap_offs = hdrlen;
481249ddf8e6SJohannes Berg struct {
481349ddf8e6SJohannes Berg u8 snap[sizeof(rfc1042_header)];
481449ddf8e6SJohannes Berg __be16 proto;
481549ddf8e6SJohannes Berg } *payload __aligned(2);
481649ddf8e6SJohannes Berg struct {
481749ddf8e6SJohannes Berg u8 da[ETH_ALEN];
481849ddf8e6SJohannes Berg u8 sa[ETH_ALEN];
481949ddf8e6SJohannes Berg } addrs __aligned(2);
482043635a5aSVasanthakumar Thiagarajan struct ieee80211_sta_rx_stats *stats;
4821c9c5962bSJohannes Berg
482249ddf8e6SJohannes Berg /* for parallel-rx, we need to have DUP_VALIDATED, otherwise we write
482349ddf8e6SJohannes Berg * to a common data structure; drivers can implement that per queue
482449ddf8e6SJohannes Berg * but we don't have that information in mac80211
482549ddf8e6SJohannes Berg */
482649ddf8e6SJohannes Berg if (!(status->flag & RX_FLAG_DUP_VALIDATED))
482749ddf8e6SJohannes Berg return false;
482849ddf8e6SJohannes Berg
482949ddf8e6SJohannes Berg #define FAST_RX_CRYPT_FLAGS (RX_FLAG_PN_VALIDATED | RX_FLAG_DECRYPTED)
483049ddf8e6SJohannes Berg
483149ddf8e6SJohannes Berg /* If using encryption, we also need to have:
483249ddf8e6SJohannes Berg * - PN_VALIDATED: similar, but the implementation is tricky
483349ddf8e6SJohannes Berg * - DECRYPTED: necessary for PN_VALIDATED
483449ddf8e6SJohannes Berg */
483549ddf8e6SJohannes Berg if (fast_rx->key &&
483649ddf8e6SJohannes Berg (status->flag & FAST_RX_CRYPT_FLAGS) != FAST_RX_CRYPT_FLAGS)
483749ddf8e6SJohannes Berg return false;
483849ddf8e6SJohannes Berg
483949ddf8e6SJohannes Berg if (unlikely(!ieee80211_is_data_present(hdr->frame_control)))
484049ddf8e6SJohannes Berg return false;
484149ddf8e6SJohannes Berg
484249ddf8e6SJohannes Berg if (unlikely(ieee80211_is_frag(hdr)))
484349ddf8e6SJohannes Berg return false;
484449ddf8e6SJohannes Berg
484549ddf8e6SJohannes Berg /* Since our interface address cannot be multicast, this
484649ddf8e6SJohannes Berg * implicitly also rejects multicast frames without the
484749ddf8e6SJohannes Berg * explicit check.
484849ddf8e6SJohannes Berg *
484949ddf8e6SJohannes Berg * We shouldn't get any *data* frames not addressed to us
485049ddf8e6SJohannes Berg * (AP mode will accept multicast *management* frames), but
485149ddf8e6SJohannes Berg * punting here will make it go through the full checks in
485249ddf8e6SJohannes Berg * ieee80211_accept_frame().
485349ddf8e6SJohannes Berg */
485449ddf8e6SJohannes Berg if (!ether_addr_equal(fast_rx->vif_addr, hdr->addr1))
485549ddf8e6SJohannes Berg return false;
485649ddf8e6SJohannes Berg
485749ddf8e6SJohannes Berg if ((hdr->frame_control & cpu_to_le16(IEEE80211_FCTL_FROMDS |
485849ddf8e6SJohannes Berg IEEE80211_FCTL_TODS)) !=
485949ddf8e6SJohannes Berg fast_rx->expected_ds_bits)
4860b323ac19SFelix Fietkau return false;
486149ddf8e6SJohannes Berg
486249ddf8e6SJohannes Berg /* assign the key to drop unencrypted frames (later)
486349ddf8e6SJohannes Berg * and strip the IV/MIC if necessary
486449ddf8e6SJohannes Berg */
486549ddf8e6SJohannes Berg if (fast_rx->key && !(status->flag & RX_FLAG_IV_STRIPPED)) {
486649ddf8e6SJohannes Berg /* GCMP header length is the same */
486749ddf8e6SJohannes Berg snap_offs += IEEE80211_CCMP_HDR_LEN;
486849ddf8e6SJohannes Berg }
486949ddf8e6SJohannes Berg
48703468e1e0SFelix Fietkau if (!ieee80211_vif_is_mesh(&rx->sdata->vif) &&
48713468e1e0SFelix Fietkau !(status->rx_flags & IEEE80211_RX_AMSDU)) {
487249ddf8e6SJohannes Berg if (!pskb_may_pull(skb, snap_offs + sizeof(*payload)))
4873f5369dcfSFelix Fietkau return false;
487424bba078SFelix Fietkau
487549ddf8e6SJohannes Berg payload = (void *)(skb->data + snap_offs);
487649ddf8e6SJohannes Berg
487749ddf8e6SJohannes Berg if (!ether_addr_equal(payload->snap, fast_rx->rfc1042_hdr))
487849ddf8e6SJohannes Berg return false;
487949ddf8e6SJohannes Berg
488049ddf8e6SJohannes Berg /* Don't handle these here since they require special code.
488149ddf8e6SJohannes Berg * Accept AARP and IPX even though they should come with a
488249ddf8e6SJohannes Berg * bridge-tunnel header - but if we get them this way then
488349ddf8e6SJohannes Berg * there's little point in discarding them.
488449ddf8e6SJohannes Berg */
488549ddf8e6SJohannes Berg if (unlikely(payload->proto == cpu_to_be16(ETH_P_TDLS) ||
488649ddf8e6SJohannes Berg payload->proto == fast_rx->control_port_protocol))
488749ddf8e6SJohannes Berg return false;
488824bba078SFelix Fietkau }
488949ddf8e6SJohannes Berg
489049ddf8e6SJohannes Berg /* after this point, don't punt to the slowpath! */
489149ddf8e6SJohannes Berg
489249ddf8e6SJohannes Berg if (rx->key && !(status->flag & RX_FLAG_MIC_STRIPPED) &&
489349ddf8e6SJohannes Berg pskb_trim(skb, skb->len - fast_rx->icv_len))
489449ddf8e6SJohannes Berg goto drop;
489549ddf8e6SJohannes Berg
489649ddf8e6SJohannes Berg if (rx->key && !ieee80211_has_protected(hdr->frame_control))
489749ddf8e6SJohannes Berg goto drop;
489849ddf8e6SJohannes Berg
489924bba078SFelix Fietkau if (status->rx_flags & IEEE80211_RX_AMSDU) {
490024bba078SFelix Fietkau if (__ieee80211_rx_h_amsdu(rx, snap_offs - hdrlen) !=
490124bba078SFelix Fietkau RX_QUEUED)
490224bba078SFelix Fietkau goto drop;
490324bba078SFelix Fietkau
490424bba078SFelix Fietkau return true;
490524bba078SFelix Fietkau }
490624bba078SFelix Fietkau
490749ddf8e6SJohannes Berg /* do the header conversion - first grab the addresses */
490849ddf8e6SJohannes Berg ether_addr_copy(addrs.da, skb->data + fast_rx->da_offs);
490949ddf8e6SJohannes Berg ether_addr_copy(addrs.sa, skb->data + fast_rx->sa_offs);
49103468e1e0SFelix Fietkau if (ieee80211_vif_is_mesh(&rx->sdata->vif)) {
49113468e1e0SFelix Fietkau skb_pull(skb, snap_offs - 2);
49123468e1e0SFelix Fietkau put_unaligned_be16(skb->len - 2, skb->data);
49133468e1e0SFelix Fietkau } else {
4914667aa742SJohannes Berg skb_postpull_rcsum(skb, skb->data + snap_offs,
4915667aa742SJohannes Berg sizeof(rfc1042_header) + 2);
49163468e1e0SFelix Fietkau
491749ddf8e6SJohannes Berg /* remove the SNAP but leave the ethertype */
491849ddf8e6SJohannes Berg skb_pull(skb, snap_offs + sizeof(rfc1042_header));
49193468e1e0SFelix Fietkau }
492049ddf8e6SJohannes Berg /* push the addresses in front */
492149ddf8e6SJohannes Berg memcpy(skb_push(skb, sizeof(addrs)), &addrs, sizeof(addrs));
492249ddf8e6SJohannes Berg
49233468e1e0SFelix Fietkau res = ieee80211_rx_mesh_data(rx->sdata, rx->sta, rx->skb);
49243468e1e0SFelix Fietkau switch (res) {
49253468e1e0SFelix Fietkau case RX_QUEUED:
49263468e1e0SFelix Fietkau return true;
49273468e1e0SFelix Fietkau case RX_CONTINUE:
49283468e1e0SFelix Fietkau break;
49293468e1e0SFelix Fietkau default:
49303468e1e0SFelix Fietkau goto drop;
49313468e1e0SFelix Fietkau }
49323468e1e0SFelix Fietkau
493380a915ecSFelix Fietkau ieee80211_rx_8023(rx, fast_rx, orig_len);
493449ddf8e6SJohannes Berg
493549ddf8e6SJohannes Berg return true;
493649ddf8e6SJohannes Berg drop:
493749ddf8e6SJohannes Berg dev_kfree_skb(skb);
493843635a5aSVasanthakumar Thiagarajan
493980a915ecSFelix Fietkau if (fast_rx->uses_rss)
4940e66b7920SFelix Fietkau stats = this_cpu_ptr(rx->link_sta->pcpu_rx_stats);
494143635a5aSVasanthakumar Thiagarajan else
4942e66b7920SFelix Fietkau stats = &rx->link_sta->rx_stats;
494380a915ecSFelix Fietkau
4944c9c5962bSJohannes Berg stats->dropped++;
494549ddf8e6SJohannes Berg return true;
494649ddf8e6SJohannes Berg }
494749ddf8e6SJohannes Berg
4948571ecf67SJohannes Berg /*
49494406c376SJohannes Berg * This function returns whether or not the SKB
49504406c376SJohannes Berg * was destined for RX processing or not, which,
49514406c376SJohannes Berg * if consume is true, is equivalent to whether
49524406c376SJohannes Berg * or not the skb was consumed.
49534406c376SJohannes Berg */
ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data * rx,struct sk_buff * skb,bool consume)49544406c376SJohannes Berg static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx,
49554406c376SJohannes Berg struct sk_buff *skb, bool consume)
49564406c376SJohannes Berg {
49574406c376SJohannes Berg struct ieee80211_local *local = rx->local;
49584406c376SJohannes Berg struct ieee80211_sub_if_data *sdata = rx->sdata;
495942fb9148SJohannes Berg struct ieee80211_hdr *hdr = (void *)skb->data;
4960e66b7920SFelix Fietkau struct link_sta_info *link_sta = rx->link_sta;
4961e66b7920SFelix Fietkau struct ieee80211_link_data *link = rx->link;
49624406c376SJohannes Berg
49634406c376SJohannes Berg rx->skb = skb;
49644406c376SJohannes Berg
496549ddf8e6SJohannes Berg /* See if we can do fast-rx; if we have to copy we already lost,
496649ddf8e6SJohannes Berg * so punt in that case. We should never have to deliver a data
496749ddf8e6SJohannes Berg * frame to multiple interfaces anyway.
496849ddf8e6SJohannes Berg *
496949ddf8e6SJohannes Berg * We skip the ieee80211_accept_frame() call and do the necessary
497049ddf8e6SJohannes Berg * checking inside ieee80211_invoke_fast_rx().
497149ddf8e6SJohannes Berg */
497249ddf8e6SJohannes Berg if (consume && rx->sta) {
497349ddf8e6SJohannes Berg struct ieee80211_fast_rx *fast_rx;
497449ddf8e6SJohannes Berg
497549ddf8e6SJohannes Berg fast_rx = rcu_dereference(rx->sta->fast_rx);
497649ddf8e6SJohannes Berg if (fast_rx && ieee80211_invoke_fast_rx(rx, fast_rx))
497749ddf8e6SJohannes Berg return true;
497849ddf8e6SJohannes Berg }
497949ddf8e6SJohannes Berg
4980a58fbe1aSJohannes Berg if (!ieee80211_accept_frame(rx))
49814406c376SJohannes Berg return false;
49824406c376SJohannes Berg
49834406c376SJohannes Berg if (!consume) {
4984f9202638SAvraham Stern struct skb_shared_hwtstamps *shwt;
4985f9202638SAvraham Stern
4986f9202638SAvraham Stern rx->skb = skb_copy(skb, GFP_ATOMIC);
4987f9202638SAvraham Stern if (!rx->skb) {
49884406c376SJohannes Berg if (net_ratelimit())
49894406c376SJohannes Berg wiphy_debug(local->hw.wiphy,
4990b305dae4SBen Greear "failed to copy skb for %s\n",
49914406c376SJohannes Berg sdata->name);
49924406c376SJohannes Berg return true;
49934406c376SJohannes Berg }
49944406c376SJohannes Berg
4995f9202638SAvraham Stern /* skb_copy() does not copy the hw timestamps, so copy it
4996f9202638SAvraham Stern * explicitly
4997f9202638SAvraham Stern */
4998f9202638SAvraham Stern shwt = skb_hwtstamps(rx->skb);
4999f9202638SAvraham Stern shwt->hwtstamp = skb_hwtstamps(skb)->hwtstamp;
5000fa22b51aSSriram R
5001fa22b51aSSriram R /* Update the hdr pointer to the new skb for translation below */
5002fa22b51aSSriram R hdr = (struct ieee80211_hdr *)rx->skb->data;
50034406c376SJohannes Berg }
50044406c376SJohannes Berg
5005daf8fb42SAndrei Otcheretianski if (unlikely(rx->sta && rx->sta->sta.mlo) &&
500647c171a4SJohannes Berg is_unicast_ether_addr(hdr->addr1) &&
500747c171a4SJohannes Berg !ieee80211_is_probe_resp(hdr->frame_control) &&
500847c171a4SJohannes Berg !ieee80211_is_beacon(hdr->frame_control)) {
500942fb9148SJohannes Berg /* translate to MLD addresses */
501042fb9148SJohannes Berg if (ether_addr_equal(link->conf->addr, hdr->addr1))
501142fb9148SJohannes Berg ether_addr_copy(hdr->addr1, rx->sdata->vif.addr);
501242fb9148SJohannes Berg if (ether_addr_equal(link_sta->addr, hdr->addr2))
501342fb9148SJohannes Berg ether_addr_copy(hdr->addr2, rx->sta->addr);
50141f638944SJohannes Berg /* translate A3 only if it's the BSSID */
50151f638944SJohannes Berg if (!ieee80211_has_tods(hdr->frame_control) &&
50161f638944SJohannes Berg !ieee80211_has_fromds(hdr->frame_control)) {
501742fb9148SJohannes Berg if (ether_addr_equal(link_sta->addr, hdr->addr3))
501842fb9148SJohannes Berg ether_addr_copy(hdr->addr3, rx->sta->addr);
501942fb9148SJohannes Berg else if (ether_addr_equal(link->conf->addr, hdr->addr3))
502042fb9148SJohannes Berg ether_addr_copy(hdr->addr3, rx->sdata->vif.addr);
50211f638944SJohannes Berg }
502242fb9148SJohannes Berg /* not needed for A4 since it can only carry the SA */
502342fb9148SJohannes Berg }
502442fb9148SJohannes Berg
50254406c376SJohannes Berg ieee80211_invoke_rx_handlers(rx);
50264406c376SJohannes Berg return true;
50274406c376SJohannes Berg }
50284406c376SJohannes Berg
__ieee80211_rx_handle_8023(struct ieee80211_hw * hw,struct ieee80211_sta * pubsta,struct sk_buff * skb,struct list_head * list)502980a915ecSFelix Fietkau static void __ieee80211_rx_handle_8023(struct ieee80211_hw *hw,
503080a915ecSFelix Fietkau struct ieee80211_sta *pubsta,
503180a915ecSFelix Fietkau struct sk_buff *skb,
503280a915ecSFelix Fietkau struct list_head *list)
503380a915ecSFelix Fietkau {
503480a915ecSFelix Fietkau struct ieee80211_local *local = hw_to_local(hw);
5035ea9d807bSVasanthakumar Thiagarajan struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
503680a915ecSFelix Fietkau struct ieee80211_fast_rx *fast_rx;
503780a915ecSFelix Fietkau struct ieee80211_rx_data rx;
50380d846bdcSJohannes Berg struct sta_info *sta;
5039e66b7920SFelix Fietkau int link_id = -1;
504080a915ecSFelix Fietkau
504180a915ecSFelix Fietkau memset(&rx, 0, sizeof(rx));
504280a915ecSFelix Fietkau rx.skb = skb;
504380a915ecSFelix Fietkau rx.local = local;
504480a915ecSFelix Fietkau rx.list = list;
5045892b3bceSJohannes Berg rx.link_id = -1;
504680a915ecSFelix Fietkau
504780a915ecSFelix Fietkau I802_DEBUG_INC(local->dot11ReceivedFragmentCount);
504880a915ecSFelix Fietkau
504980a915ecSFelix Fietkau /* drop frame if too short for header */
505080a915ecSFelix Fietkau if (skb->len < sizeof(struct ethhdr))
505180a915ecSFelix Fietkau goto drop;
505280a915ecSFelix Fietkau
505380a915ecSFelix Fietkau if (!pubsta)
505480a915ecSFelix Fietkau goto drop;
505580a915ecSFelix Fietkau
5056e66b7920SFelix Fietkau if (status->link_valid)
5057e66b7920SFelix Fietkau link_id = status->link_id;
5058ea9d807bSVasanthakumar Thiagarajan
5059ea9d807bSVasanthakumar Thiagarajan /*
5060ea9d807bSVasanthakumar Thiagarajan * TODO: Should the frame be dropped if the right link_id is not
5061ea9d807bSVasanthakumar Thiagarajan * available? Or may be it is fine in the current form to proceed with
5062ea9d807bSVasanthakumar Thiagarajan * the frame processing because with frame being in 802.3 format,
5063ea9d807bSVasanthakumar Thiagarajan * link_id is used only for stats purpose and updating the stats on
5064ea9d807bSVasanthakumar Thiagarajan * the deflink is fine?
5065ea9d807bSVasanthakumar Thiagarajan */
50660d846bdcSJohannes Berg sta = container_of(pubsta, struct sta_info, sta);
50670d846bdcSJohannes Berg if (!ieee80211_rx_data_set_sta(&rx, sta, link_id))
5068ea9d807bSVasanthakumar Thiagarajan goto drop;
506980a915ecSFelix Fietkau
507080a915ecSFelix Fietkau fast_rx = rcu_dereference(rx.sta->fast_rx);
507180a915ecSFelix Fietkau if (!fast_rx)
507280a915ecSFelix Fietkau goto drop;
507380a915ecSFelix Fietkau
507480a915ecSFelix Fietkau ieee80211_rx_8023(&rx, fast_rx, skb->len);
507580a915ecSFelix Fietkau return;
507680a915ecSFelix Fietkau
507780a915ecSFelix Fietkau drop:
507880a915ecSFelix Fietkau dev_kfree_skb(skb);
507980a915ecSFelix Fietkau }
508080a915ecSFelix Fietkau
ieee80211_rx_for_interface(struct ieee80211_rx_data * rx,struct sk_buff * skb,bool consume)5081892b3bceSJohannes Berg static bool ieee80211_rx_for_interface(struct ieee80211_rx_data *rx,
5082892b3bceSJohannes Berg struct sk_buff *skb, bool consume)
5083892b3bceSJohannes Berg {
5084892b3bceSJohannes Berg struct link_sta_info *link_sta;
5085892b3bceSJohannes Berg struct ieee80211_hdr *hdr = (void *)skb->data;
5086e66b7920SFelix Fietkau struct sta_info *sta;
5087e66b7920SFelix Fietkau int link_id = -1;
5088892b3bceSJohannes Berg
5089892b3bceSJohannes Berg /*
5090892b3bceSJohannes Berg * Look up link station first, in case there's a
5091892b3bceSJohannes Berg * chance that they might have a link address that
5092892b3bceSJohannes Berg * is identical to the MLD address, that way we'll
5093892b3bceSJohannes Berg * have the link information if needed.
5094892b3bceSJohannes Berg */
5095892b3bceSJohannes Berg link_sta = link_sta_info_get_bss(rx->sdata, hdr->addr2);
5096892b3bceSJohannes Berg if (link_sta) {
5097e66b7920SFelix Fietkau sta = link_sta->sta;
5098e66b7920SFelix Fietkau link_id = link_sta->link_id;
5099892b3bceSJohannes Berg } else {
5100ea9d807bSVasanthakumar Thiagarajan struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
5101ea9d807bSVasanthakumar Thiagarajan
5102e66b7920SFelix Fietkau sta = sta_info_get_bss(rx->sdata, hdr->addr2);
5103e66b7920SFelix Fietkau if (status->link_valid)
5104e66b7920SFelix Fietkau link_id = status->link_id;
5105e66b7920SFelix Fietkau }
5106ea9d807bSVasanthakumar Thiagarajan
51070d846bdcSJohannes Berg if (!ieee80211_rx_data_set_sta(rx, sta, link_id))
5108e66b7920SFelix Fietkau return false;
5109892b3bceSJohannes Berg
5110892b3bceSJohannes Berg return ieee80211_prepare_and_rx_handle(rx, skb, consume);
5111892b3bceSJohannes Berg }
5112892b3bceSJohannes Berg
51134406c376SJohannes Berg /*
51146b59db7dSZhao, Gang * This is the actual Rx frames handler. as it belongs to Rx path it must
51156368e4b1SRon Rindjunsky * be called with rcu_read_lock protection.
5116571ecf67SJohannes Berg */
__ieee80211_rx_handle_packet(struct ieee80211_hw * hw,struct ieee80211_sta * pubsta,struct sk_buff * skb,struct list_head * list)511771ebb4aaSRon Rindjunsky static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
5118d63b548fSJohannes Berg struct ieee80211_sta *pubsta,
5119af9f9b22SJohannes Berg struct sk_buff *skb,
5120c5d1686bSFelix Fietkau struct list_head *list)
5121571ecf67SJohannes Berg {
5122571ecf67SJohannes Berg struct ieee80211_local *local = hw_to_local(hw);
5123ea9d807bSVasanthakumar Thiagarajan struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
5124571ecf67SJohannes Berg struct ieee80211_sub_if_data *sdata;
5125571ecf67SJohannes Berg struct ieee80211_hdr *hdr;
5126e3cf8b3fSZhu Yi __le16 fc;
51275cf121c3SJohannes Berg struct ieee80211_rx_data rx;
51284406c376SJohannes Berg struct ieee80211_sub_if_data *prev;
512983e7e4ceSHerbert Xu struct rhlist_head *tmp;
5130e3cf8b3fSZhu Yi int err = 0;
5131571ecf67SJohannes Berg
5132e3cf8b3fSZhu Yi fc = ((struct ieee80211_hdr *)skb->data)->frame_control;
5133571ecf67SJohannes Berg memset(&rx, 0, sizeof(rx));
5134571ecf67SJohannes Berg rx.skb = skb;
5135571ecf67SJohannes Berg rx.local = local;
5136c5d1686bSFelix Fietkau rx.list = list;
5137892b3bceSJohannes Berg rx.link_id = -1;
513872abd81bSJohannes Berg
5139e3cf8b3fSZhu Yi if (ieee80211_is_data(fc) || ieee80211_is_mgmt(fc))
5140c206ca67SJohannes Berg I802_DEBUG_INC(local->dot11ReceivedFragmentCount);
5141571ecf67SJohannes Berg
51424a4f1a58SJohannes Berg if (ieee80211_is_mgmt(fc)) {
51434a4f1a58SJohannes Berg /* drop frame if too short for header */
51444a4f1a58SJohannes Berg if (skb->len < ieee80211_hdrlen(fc))
51454a4f1a58SJohannes Berg err = -ENOBUFS;
5146e3cf8b3fSZhu Yi else
51474a4f1a58SJohannes Berg err = skb_linearize(skb);
51484a4f1a58SJohannes Berg } else {
5149e3cf8b3fSZhu Yi err = !pskb_may_pull(skb, ieee80211_hdrlen(fc));
51504a4f1a58SJohannes Berg }
5151e3cf8b3fSZhu Yi
5152e3cf8b3fSZhu Yi if (err) {
5153e3cf8b3fSZhu Yi dev_kfree_skb(skb);
5154e3cf8b3fSZhu Yi return;
5155e3cf8b3fSZhu Yi }
5156e3cf8b3fSZhu Yi
5157e3cf8b3fSZhu Yi hdr = (struct ieee80211_hdr *)skb->data;
515838f3714dSJohannes Berg ieee80211_parse_qos(&rx);
5159d1c3a37cSJohannes Berg ieee80211_verify_alignment(&rx);
516038f3714dSJohannes Berg
5161d48b2968SJohannes Berg if (unlikely(ieee80211_is_probe_resp(hdr->frame_control) ||
5162cd418ba6SThomas Pedersen ieee80211_is_beacon(hdr->frame_control) ||
5163cd418ba6SThomas Pedersen ieee80211_is_s1g_beacon(hdr->frame_control)))
5164d48b2968SJohannes Berg ieee80211_scan_rx(local, skb);
5165d48b2968SJohannes Berg
516619d19e96SJohannes Berg if (ieee80211_is_data(fc)) {
516719d19e96SJohannes Berg struct sta_info *sta, *prev_sta;
5168e66b7920SFelix Fietkau int link_id = -1;
5169ea9d807bSVasanthakumar Thiagarajan
5170ea9d807bSVasanthakumar Thiagarajan if (status->link_valid)
5171e66b7920SFelix Fietkau link_id = status->link_id;
5172e66b7920SFelix Fietkau
5173e66b7920SFelix Fietkau if (pubsta) {
51740d846bdcSJohannes Berg sta = container_of(pubsta, struct sta_info, sta);
51750d846bdcSJohannes Berg if (!ieee80211_rx_data_set_sta(&rx, sta, link_id))
5176e66b7920SFelix Fietkau goto out;
5177ea9d807bSVasanthakumar Thiagarajan
5178ea9d807bSVasanthakumar Thiagarajan /*
5179ea9d807bSVasanthakumar Thiagarajan * In MLO connection, fetch the link_id using addr2
5180ea9d807bSVasanthakumar Thiagarajan * when the driver does not pass link_id in status.
5181ea9d807bSVasanthakumar Thiagarajan * When the address translation is already performed by
5182ea9d807bSVasanthakumar Thiagarajan * driver/hw, the valid link_id must be passed in
5183ea9d807bSVasanthakumar Thiagarajan * status.
5184ea9d807bSVasanthakumar Thiagarajan */
5185ea9d807bSVasanthakumar Thiagarajan
5186ea9d807bSVasanthakumar Thiagarajan if (!status->link_valid && pubsta->mlo) {
5187ea9d807bSVasanthakumar Thiagarajan struct ieee80211_hdr *hdr = (void *)skb->data;
5188ea9d807bSVasanthakumar Thiagarajan struct link_sta_info *link_sta;
5189ea9d807bSVasanthakumar Thiagarajan
5190ea9d807bSVasanthakumar Thiagarajan link_sta = link_sta_info_get_bss(rx.sdata,
5191ea9d807bSVasanthakumar Thiagarajan hdr->addr2);
5192ea9d807bSVasanthakumar Thiagarajan if (!link_sta)
5193ea9d807bSVasanthakumar Thiagarajan goto out;
5194ea9d807bSVasanthakumar Thiagarajan
5195e66b7920SFelix Fietkau ieee80211_rx_data_set_link(&rx, link_sta->link_id);
5196ea9d807bSVasanthakumar Thiagarajan }
5197ea9d807bSVasanthakumar Thiagarajan
5198d63b548fSJohannes Berg if (ieee80211_prepare_and_rx_handle(&rx, skb, true))
5199d63b548fSJohannes Berg return;
5200d63b548fSJohannes Berg goto out;
520119d19e96SJohannes Berg }
52027bedd0cfSJohannes Berg
520356af3268SBen Greear prev_sta = NULL;
52044406c376SJohannes Berg
520583e7e4ceSHerbert Xu for_each_sta_info(local, hdr->addr2, sta, tmp) {
520656af3268SBen Greear if (!prev_sta) {
520756af3268SBen Greear prev_sta = sta;
520856af3268SBen Greear continue;
520956af3268SBen Greear }
521056af3268SBen Greear
5211e66b7920SFelix Fietkau rx.sdata = prev_sta->sdata;
52120d846bdcSJohannes Berg if (!ieee80211_rx_data_set_sta(&rx, prev_sta, link_id))
5213e66b7920SFelix Fietkau goto out;
5214e66b7920SFelix Fietkau
5215e66b7920SFelix Fietkau if (!status->link_valid && prev_sta->sta.mlo)
5216ea9d807bSVasanthakumar Thiagarajan continue;
5217ea9d807bSVasanthakumar Thiagarajan
52184406c376SJohannes Berg ieee80211_prepare_and_rx_handle(&rx, skb, false);
5219571ecf67SJohannes Berg
522056af3268SBen Greear prev_sta = sta;
52214406c376SJohannes Berg }
522256af3268SBen Greear
522356af3268SBen Greear if (prev_sta) {
5224e66b7920SFelix Fietkau rx.sdata = prev_sta->sdata;
52250d846bdcSJohannes Berg if (!ieee80211_rx_data_set_sta(&rx, prev_sta, link_id))
5226ea9d807bSVasanthakumar Thiagarajan goto out;
5227ea9d807bSVasanthakumar Thiagarajan
5228e66b7920SFelix Fietkau if (!status->link_valid && prev_sta->sta.mlo)
5229e66b7920SFelix Fietkau goto out;
523056af3268SBen Greear
52314406c376SJohannes Berg if (ieee80211_prepare_and_rx_handle(&rx, skb, true))
523256af3268SBen Greear return;
52338e26d5adSSenthil Balasubramanian goto out;
5234abe60632SJohannes Berg }
523556af3268SBen Greear }
52364406c376SJohannes Berg
52374406c376SJohannes Berg prev = NULL;
52384406c376SJohannes Berg
5239abe60632SJohannes Berg list_for_each_entry_rcu(sdata, &local->interfaces, list) {
52409607e6b6SJohannes Berg if (!ieee80211_sdata_running(sdata))
52412a8a9a88SJohannes Berg continue;
52422a8a9a88SJohannes Berg
5243fbc44bf7SJohannes Berg if (sdata->vif.type == NL80211_IFTYPE_MONITOR ||
5244fbc44bf7SJohannes Berg sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
5245b2e7771eSJohannes Berg continue;
5246b2e7771eSJohannes Berg
5247340e11f3SJohannes Berg /*
5248abe60632SJohannes Berg * frame is destined for this interface, but if it's
5249abe60632SJohannes Berg * not also for the previous one we handle that after
5250abe60632SJohannes Berg * the loop to avoid copying the SKB once too much
5251340e11f3SJohannes Berg */
5252340e11f3SJohannes Berg
5253340e11f3SJohannes Berg if (!prev) {
5254340e11f3SJohannes Berg prev = sdata;
5255340e11f3SJohannes Berg continue;
5256340e11f3SJohannes Berg }
5257340e11f3SJohannes Berg
525820b01f80SJohannes Berg rx.sdata = prev;
5259892b3bceSJohannes Berg ieee80211_rx_for_interface(&rx, skb, false);
52604bb29f8cSFelix Fietkau
5261571ecf67SJohannes Berg prev = sdata;
5262571ecf67SJohannes Berg }
52634bb29f8cSFelix Fietkau
52644bb29f8cSFelix Fietkau if (prev) {
526520b01f80SJohannes Berg rx.sdata = prev;
52664bb29f8cSFelix Fietkau
5267892b3bceSJohannes Berg if (ieee80211_rx_for_interface(&rx, skb, true))
52684406c376SJohannes Berg return;
52694406c376SJohannes Berg }
52704bb29f8cSFelix Fietkau
52718e26d5adSSenthil Balasubramanian out:
5272571ecf67SJohannes Berg dev_kfree_skb(skb);
5273571ecf67SJohannes Berg }
52746368e4b1SRon Rindjunsky
52756368e4b1SRon Rindjunsky /*
52766368e4b1SRon Rindjunsky * This is the receive path handler. It is called by a low level driver when an
52776368e4b1SRon Rindjunsky * 802.11 MPDU is received from the hardware.
52786368e4b1SRon Rindjunsky */
ieee80211_rx_list(struct ieee80211_hw * hw,struct ieee80211_sta * pubsta,struct sk_buff * skb,struct list_head * list)5279c5d1686bSFelix Fietkau void ieee80211_rx_list(struct ieee80211_hw *hw, struct ieee80211_sta *pubsta,
5280c5d1686bSFelix Fietkau struct sk_buff *skb, struct list_head *list)
52816368e4b1SRon Rindjunsky {
52826368e4b1SRon Rindjunsky struct ieee80211_local *local = hw_to_local(hw);
52838318d78aSJohannes Berg struct ieee80211_rate *rate = NULL;
52848318d78aSJohannes Berg struct ieee80211_supported_band *sband;
5285f1d58c25SJohannes Berg struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
528630f6cf96SFelix Fietkau struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
52878318d78aSJohannes Berg
5288d20ef63dSJohannes Berg WARN_ON_ONCE(softirq_count() == 0);
5289d20ef63dSJohannes Berg
529057fbcce3SJohannes Berg if (WARN_ON(status->band >= NUM_NL80211_BANDS))
529177a980dcSJohannes Berg goto drop;
52928318d78aSJohannes Berg
52938318d78aSJohannes Berg sband = local->hw.wiphy->bands[status->band];
529477a980dcSJohannes Berg if (WARN_ON(!sband))
529577a980dcSJohannes Berg goto drop;
52968318d78aSJohannes Berg
529789c3a8acSJohannes Berg /*
529889c3a8acSJohannes Berg * If we're suspending, it is possible although not too likely
529989c3a8acSJohannes Berg * that we'd be receiving frames after having already partially
530089c3a8acSJohannes Berg * quiesced the stack. We can't process such frames then since
530189c3a8acSJohannes Berg * that might, for example, cause stations to be added or other
530289c3a8acSJohannes Berg * driver callbacks be invoked.
530389c3a8acSJohannes Berg */
530477a980dcSJohannes Berg if (unlikely(local->quiescing || local->suspended))
530577a980dcSJohannes Berg goto drop;
530689c3a8acSJohannes Berg
530704800adaSArik Nemtsov /* We might be during a HW reconfig, prevent Rx for the same reason */
530804800adaSArik Nemtsov if (unlikely(local->in_reconfig))
530904800adaSArik Nemtsov goto drop;
531004800adaSArik Nemtsov
5311ea77f12fSJohannes Berg /*
5312ea77f12fSJohannes Berg * The same happens when we're not even started,
5313ea77f12fSJohannes Berg * but that's worth a warning.
5314ea77f12fSJohannes Berg */
531577a980dcSJohannes Berg if (WARN_ON(!local->started))
531677a980dcSJohannes Berg goto drop;
5317ea77f12fSJohannes Berg
5318fc885189SJohannes Berg if (likely(!(status->flag & RX_FLAG_FAILED_PLCP_CRC))) {
5319fc885189SJohannes Berg /*
5320fc885189SJohannes Berg * Validate the rate, unless a PLCP error means that
5321fc885189SJohannes Berg * we probably can't have a valid rate here anyway.
5322fc885189SJohannes Berg */
5323fc885189SJohannes Berg
5324da6a4352SJohannes Berg switch (status->encoding) {
5325da6a4352SJohannes Berg case RX_ENC_HT:
5326e5d6eb83SLuis R. Rodriguez /*
5327fc885189SJohannes Berg * rate_idx is MCS index, which can be [0-76]
5328fc885189SJohannes Berg * as documented on:
5329e5d6eb83SLuis R. Rodriguez *
533059d4bfc1SFlavio Suligoi * https://wireless.wiki.kernel.org/en/developers/Documentation/ieee80211/802.11n
5331e5d6eb83SLuis R. Rodriguez *
5332fc885189SJohannes Berg * Anything else would be some sort of driver or
5333fc885189SJohannes Berg * hardware error. The driver should catch hardware
5334fc885189SJohannes Berg * errors.
5335e5d6eb83SLuis R. Rodriguez */
5336444e3803SJohannes Berg if (WARN(status->rate_idx > 76,
5337e5d6eb83SLuis R. Rodriguez "Rate marked as an HT rate but passed "
5338e5d6eb83SLuis R. Rodriguez "status->rate_idx is not "
5339e5d6eb83SLuis R. Rodriguez "an MCS index [0-76]: %d (0x%02x)\n",
5340e5d6eb83SLuis R. Rodriguez status->rate_idx,
5341e5d6eb83SLuis R. Rodriguez status->rate_idx))
534277a980dcSJohannes Berg goto drop;
5343da6a4352SJohannes Berg break;
5344da6a4352SJohannes Berg case RX_ENC_VHT:
534504be6d33SPing-Ke Shih if (WARN_ONCE(status->rate_idx > 11 ||
53468613c948SJohannes Berg !status->nss ||
53478613c948SJohannes Berg status->nss > 8,
53485614618eSJohannes Berg "Rate marked as a VHT rate but data is invalid: MCS: %d, NSS: %d\n",
53498613c948SJohannes Berg status->rate_idx, status->nss))
53505614618eSJohannes Berg goto drop;
5351da6a4352SJohannes Berg break;
535241cbb0f5SLuca Coelho case RX_ENC_HE:
535341cbb0f5SLuca Coelho if (WARN_ONCE(status->rate_idx > 11 ||
535441cbb0f5SLuca Coelho !status->nss ||
535541cbb0f5SLuca Coelho status->nss > 8,
535641cbb0f5SLuca Coelho "Rate marked as an HE rate but data is invalid: MCS: %d, NSS: %d\n",
535741cbb0f5SLuca Coelho status->rate_idx, status->nss))
535841cbb0f5SLuca Coelho goto drop;
535941cbb0f5SLuca Coelho break;
5360f66c48afSJohannes Berg case RX_ENC_EHT:
5361f66c48afSJohannes Berg if (WARN_ONCE(status->rate_idx > 15 ||
5362f66c48afSJohannes Berg !status->nss ||
5363f66c48afSJohannes Berg status->nss > 8 ||
5364f66c48afSJohannes Berg status->eht.gi > NL80211_RATE_INFO_EHT_GI_3_2,
5365f66c48afSJohannes Berg "Rate marked as an EHT rate but data is invalid: MCS:%d, NSS:%d, GI:%d\n",
5366f66c48afSJohannes Berg status->rate_idx, status->nss, status->eht.gi))
5367f66c48afSJohannes Berg goto drop;
5368f66c48afSJohannes Berg break;
5369da6a4352SJohannes Berg default:
5370da6a4352SJohannes Berg WARN_ON_ONCE(1);
5371fc0561dcSGustavo A. R. Silva fallthrough;
5372da6a4352SJohannes Berg case RX_ENC_LEGACY:
5373444e3803SJohannes Berg if (WARN_ON(status->rate_idx >= sband->n_bitrates))
537477a980dcSJohannes Berg goto drop;
53758318d78aSJohannes Berg rate = &sband->bitrates[status->rate_idx];
53760fb8ca45SJouni Malinen }
5377fc885189SJohannes Berg }
53786368e4b1SRon Rindjunsky
5379ea9d807bSVasanthakumar Thiagarajan if (WARN_ON_ONCE(status->link_id >= IEEE80211_LINK_UNSPECIFIED))
5380ea9d807bSVasanthakumar Thiagarajan goto drop;
5381ea9d807bSVasanthakumar Thiagarajan
5382554891e6SJohannes Berg status->rx_flags = 0;
5383554891e6SJohannes Berg
5384261e411bSAleksandr Nogikh kcov_remote_start_common(skb_get_kcov_handle(skb));
5385261e411bSAleksandr Nogikh
53866368e4b1SRon Rindjunsky /*
53876368e4b1SRon Rindjunsky * Frames with failed FCS/PLCP checksum are not returned,
53886368e4b1SRon Rindjunsky * all other frames are returned without radiotap header
53896368e4b1SRon Rindjunsky * if it was previously present.
53906368e4b1SRon Rindjunsky * Also, frames with less than 16 bytes are dropped.
53916368e4b1SRon Rindjunsky */
539280a915ecSFelix Fietkau if (!(status->flag & RX_FLAG_8023))
5393f1d58c25SJohannes Berg skb = ieee80211_rx_monitor(local, skb, rate);
5394261e411bSAleksandr Nogikh if (skb) {
539530f6cf96SFelix Fietkau if ((status->flag & RX_FLAG_8023) ||
539630f6cf96SFelix Fietkau ieee80211_is_data_present(hdr->frame_control))
539730f6cf96SFelix Fietkau ieee80211_tpt_led_trig_rx(local, skb->len);
5398d63b548fSJohannes Berg
539980a915ecSFelix Fietkau if (status->flag & RX_FLAG_8023)
540080a915ecSFelix Fietkau __ieee80211_rx_handle_8023(hw, pubsta, skb, list);
540180a915ecSFelix Fietkau else
5402c5d1686bSFelix Fietkau __ieee80211_rx_handle_packet(hw, pubsta, skb, list);
5403261e411bSAleksandr Nogikh }
540477a980dcSJohannes Berg
5405261e411bSAleksandr Nogikh kcov_remote_stop();
540677a980dcSJohannes Berg return;
540777a980dcSJohannes Berg drop:
540877a980dcSJohannes Berg kfree_skb(skb);
54096368e4b1SRon Rindjunsky }
5410c5d1686bSFelix Fietkau EXPORT_SYMBOL(ieee80211_rx_list);
5411c5d1686bSFelix Fietkau
ieee80211_rx_napi(struct ieee80211_hw * hw,struct ieee80211_sta * pubsta,struct sk_buff * skb,struct napi_struct * napi)5412c5d1686bSFelix Fietkau void ieee80211_rx_napi(struct ieee80211_hw *hw, struct ieee80211_sta *pubsta,
5413c5d1686bSFelix Fietkau struct sk_buff *skb, struct napi_struct *napi)
5414c5d1686bSFelix Fietkau {
5415c5d1686bSFelix Fietkau struct sk_buff *tmp;
5416c5d1686bSFelix Fietkau LIST_HEAD(list);
5417c5d1686bSFelix Fietkau
5418c5d1686bSFelix Fietkau
5419c5d1686bSFelix Fietkau /*
5420c5d1686bSFelix Fietkau * key references and virtual interfaces are protected using RCU
5421c5d1686bSFelix Fietkau * and this requires that we are in a read-side RCU section during
5422c5d1686bSFelix Fietkau * receive processing
5423c5d1686bSFelix Fietkau */
5424c5d1686bSFelix Fietkau rcu_read_lock();
5425c5d1686bSFelix Fietkau ieee80211_rx_list(hw, pubsta, skb, &list);
5426c5d1686bSFelix Fietkau rcu_read_unlock();
5427c5d1686bSFelix Fietkau
5428c5d1686bSFelix Fietkau if (!napi) {
5429c5d1686bSFelix Fietkau netif_receive_skb_list(&list);
5430c5d1686bSFelix Fietkau return;
5431c5d1686bSFelix Fietkau }
5432c5d1686bSFelix Fietkau
5433c5d1686bSFelix Fietkau list_for_each_entry_safe(skb, tmp, &list, list) {
5434c5d1686bSFelix Fietkau skb_list_del_init(skb);
5435c5d1686bSFelix Fietkau napi_gro_receive(napi, skb);
5436c5d1686bSFelix Fietkau }
5437c5d1686bSFelix Fietkau }
5438af9f9b22SJohannes Berg EXPORT_SYMBOL(ieee80211_rx_napi);
5439571ecf67SJohannes Berg
5440571ecf67SJohannes Berg /* This is a version of the rx handler that can be called from hard irq
5441571ecf67SJohannes Berg * context. Post the skb on the queue and schedule the tasklet */
ieee80211_rx_irqsafe(struct ieee80211_hw * hw,struct sk_buff * skb)5442f1d58c25SJohannes Berg void ieee80211_rx_irqsafe(struct ieee80211_hw *hw, struct sk_buff *skb)
5443571ecf67SJohannes Berg {
5444571ecf67SJohannes Berg struct ieee80211_local *local = hw_to_local(hw);
5445571ecf67SJohannes Berg
5446571ecf67SJohannes Berg BUILD_BUG_ON(sizeof(struct ieee80211_rx_status) > sizeof(skb->cb));
5447571ecf67SJohannes Berg
5448571ecf67SJohannes Berg skb->pkt_type = IEEE80211_RX_MSG;
5449571ecf67SJohannes Berg skb_queue_tail(&local->skb_queue, skb);
5450571ecf67SJohannes Berg tasklet_schedule(&local->tasklet);
5451571ecf67SJohannes Berg }
5452571ecf67SJohannes Berg EXPORT_SYMBOL(ieee80211_rx_irqsafe);
5453