18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright 2002-2005, Instant802 Networks, Inc. 48c2ecf20Sopenharmony_ci * Copyright 2005-2006, Devicescape Software, Inc. 58c2ecf20Sopenharmony_ci * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> 68c2ecf20Sopenharmony_ci * Copyright 2007-2010 Johannes Berg <johannes@sipsolutions.net> 78c2ecf20Sopenharmony_ci * Copyright 2013-2014 Intel Mobile Communications GmbH 88c2ecf20Sopenharmony_ci * Copyright(c) 2015 - 2017 Intel Deutschland GmbH 98c2ecf20Sopenharmony_ci * Copyright (C) 2018-2021 Intel Corporation 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/jiffies.h> 138c2ecf20Sopenharmony_ci#include <linux/slab.h> 148c2ecf20Sopenharmony_ci#include <linux/kernel.h> 158c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 168c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 178c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 188c2ecf20Sopenharmony_ci#include <linux/rcupdate.h> 198c2ecf20Sopenharmony_ci#include <linux/export.h> 208c2ecf20Sopenharmony_ci#include <linux/bitops.h> 218c2ecf20Sopenharmony_ci#include <net/mac80211.h> 228c2ecf20Sopenharmony_ci#include <net/ieee80211_radiotap.h> 238c2ecf20Sopenharmony_ci#include <asm/unaligned.h> 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#include "ieee80211_i.h" 268c2ecf20Sopenharmony_ci#include "driver-ops.h" 278c2ecf20Sopenharmony_ci#include "led.h" 288c2ecf20Sopenharmony_ci#include "mesh.h" 298c2ecf20Sopenharmony_ci#include "wep.h" 308c2ecf20Sopenharmony_ci#include "wpa.h" 318c2ecf20Sopenharmony_ci#include "tkip.h" 328c2ecf20Sopenharmony_ci#include "wme.h" 338c2ecf20Sopenharmony_ci#include "rate.h" 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistatic inline void ieee80211_rx_stats(struct net_device *dev, u32 len) 368c2ecf20Sopenharmony_ci{ 378c2ecf20Sopenharmony_ci struct pcpu_sw_netstats *tstats = this_cpu_ptr(dev->tstats); 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci u64_stats_update_begin(&tstats->syncp); 408c2ecf20Sopenharmony_ci tstats->rx_packets++; 418c2ecf20Sopenharmony_ci tstats->rx_bytes += len; 428c2ecf20Sopenharmony_ci u64_stats_update_end(&tstats->syncp); 438c2ecf20Sopenharmony_ci} 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci/* 468c2ecf20Sopenharmony_ci * monitor mode reception 478c2ecf20Sopenharmony_ci * 488c2ecf20Sopenharmony_ci * This function cleans up the SKB, i.e. it removes all the stuff 498c2ecf20Sopenharmony_ci * only useful for monitoring. 508c2ecf20Sopenharmony_ci */ 518c2ecf20Sopenharmony_cistatic struct sk_buff *ieee80211_clean_skb(struct sk_buff *skb, 528c2ecf20Sopenharmony_ci unsigned int present_fcs_len, 538c2ecf20Sopenharmony_ci unsigned int rtap_space) 548c2ecf20Sopenharmony_ci{ 558c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr; 568c2ecf20Sopenharmony_ci unsigned int hdrlen; 578c2ecf20Sopenharmony_ci __le16 fc; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci if (present_fcs_len) 608c2ecf20Sopenharmony_ci __pskb_trim(skb, skb->len - present_fcs_len); 618c2ecf20Sopenharmony_ci __pskb_pull(skb, rtap_space); 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci hdr = (void *)skb->data; 648c2ecf20Sopenharmony_ci fc = hdr->frame_control; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci /* 678c2ecf20Sopenharmony_ci * Remove the HT-Control field (if present) on management 688c2ecf20Sopenharmony_ci * frames after we've sent the frame to monitoring. We 698c2ecf20Sopenharmony_ci * (currently) don't need it, and don't properly parse 708c2ecf20Sopenharmony_ci * frames with it present, due to the assumption of a 718c2ecf20Sopenharmony_ci * fixed management header length. 728c2ecf20Sopenharmony_ci */ 738c2ecf20Sopenharmony_ci if (likely(!ieee80211_is_mgmt(fc) || !ieee80211_has_order(fc))) 748c2ecf20Sopenharmony_ci return skb; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci hdrlen = ieee80211_hdrlen(fc); 778c2ecf20Sopenharmony_ci hdr->frame_control &= ~cpu_to_le16(IEEE80211_FCTL_ORDER); 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci if (!pskb_may_pull(skb, hdrlen)) { 808c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 818c2ecf20Sopenharmony_ci return NULL; 828c2ecf20Sopenharmony_ci } 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci memmove(skb->data + IEEE80211_HT_CTL_LEN, skb->data, 858c2ecf20Sopenharmony_ci hdrlen - IEEE80211_HT_CTL_LEN); 868c2ecf20Sopenharmony_ci __pskb_pull(skb, IEEE80211_HT_CTL_LEN); 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci return skb; 898c2ecf20Sopenharmony_ci} 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_cistatic inline bool should_drop_frame(struct sk_buff *skb, int present_fcs_len, 928c2ecf20Sopenharmony_ci unsigned int rtap_space) 938c2ecf20Sopenharmony_ci{ 948c2ecf20Sopenharmony_ci struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); 958c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci hdr = (void *)(skb->data + rtap_space); 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci if (status->flag & (RX_FLAG_FAILED_FCS_CRC | 1008c2ecf20Sopenharmony_ci RX_FLAG_FAILED_PLCP_CRC | 1018c2ecf20Sopenharmony_ci RX_FLAG_ONLY_MONITOR | 1028c2ecf20Sopenharmony_ci RX_FLAG_NO_PSDU)) 1038c2ecf20Sopenharmony_ci return true; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci if (unlikely(skb->len < 16 + present_fcs_len + rtap_space)) 1068c2ecf20Sopenharmony_ci return true; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci if (ieee80211_is_ctl(hdr->frame_control) && 1098c2ecf20Sopenharmony_ci !ieee80211_is_pspoll(hdr->frame_control) && 1108c2ecf20Sopenharmony_ci !ieee80211_is_back_req(hdr->frame_control)) 1118c2ecf20Sopenharmony_ci return true; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci return false; 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistatic int 1178c2ecf20Sopenharmony_ciieee80211_rx_radiotap_hdrlen(struct ieee80211_local *local, 1188c2ecf20Sopenharmony_ci struct ieee80211_rx_status *status, 1198c2ecf20Sopenharmony_ci struct sk_buff *skb) 1208c2ecf20Sopenharmony_ci{ 1218c2ecf20Sopenharmony_ci int len; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci /* always present fields */ 1248c2ecf20Sopenharmony_ci len = sizeof(struct ieee80211_radiotap_header) + 8; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci /* allocate extra bitmaps */ 1278c2ecf20Sopenharmony_ci if (status->chains) 1288c2ecf20Sopenharmony_ci len += 4 * hweight8(status->chains); 1298c2ecf20Sopenharmony_ci /* vendor presence bitmap */ 1308c2ecf20Sopenharmony_ci if (status->flag & RX_FLAG_RADIOTAP_VENDOR_DATA) 1318c2ecf20Sopenharmony_ci len += 4; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci if (ieee80211_have_rx_timestamp(status)) { 1348c2ecf20Sopenharmony_ci len = ALIGN(len, 8); 1358c2ecf20Sopenharmony_ci len += 8; 1368c2ecf20Sopenharmony_ci } 1378c2ecf20Sopenharmony_ci if (ieee80211_hw_check(&local->hw, SIGNAL_DBM)) 1388c2ecf20Sopenharmony_ci len += 1; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci /* antenna field, if we don't have per-chain info */ 1418c2ecf20Sopenharmony_ci if (!status->chains) 1428c2ecf20Sopenharmony_ci len += 1; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci /* padding for RX_FLAGS if necessary */ 1458c2ecf20Sopenharmony_ci len = ALIGN(len, 2); 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci if (status->encoding == RX_ENC_HT) /* HT info */ 1488c2ecf20Sopenharmony_ci len += 3; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci if (status->flag & RX_FLAG_AMPDU_DETAILS) { 1518c2ecf20Sopenharmony_ci len = ALIGN(len, 4); 1528c2ecf20Sopenharmony_ci len += 8; 1538c2ecf20Sopenharmony_ci } 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci if (status->encoding == RX_ENC_VHT) { 1568c2ecf20Sopenharmony_ci len = ALIGN(len, 2); 1578c2ecf20Sopenharmony_ci len += 12; 1588c2ecf20Sopenharmony_ci } 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci if (local->hw.radiotap_timestamp.units_pos >= 0) { 1618c2ecf20Sopenharmony_ci len = ALIGN(len, 8); 1628c2ecf20Sopenharmony_ci len += 12; 1638c2ecf20Sopenharmony_ci } 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci if (status->encoding == RX_ENC_HE && 1668c2ecf20Sopenharmony_ci status->flag & RX_FLAG_RADIOTAP_HE) { 1678c2ecf20Sopenharmony_ci len = ALIGN(len, 2); 1688c2ecf20Sopenharmony_ci len += 12; 1698c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(struct ieee80211_radiotap_he) != 12); 1708c2ecf20Sopenharmony_ci } 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci if (status->encoding == RX_ENC_HE && 1738c2ecf20Sopenharmony_ci status->flag & RX_FLAG_RADIOTAP_HE_MU) { 1748c2ecf20Sopenharmony_ci len = ALIGN(len, 2); 1758c2ecf20Sopenharmony_ci len += 12; 1768c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(struct ieee80211_radiotap_he_mu) != 12); 1778c2ecf20Sopenharmony_ci } 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci if (status->flag & RX_FLAG_NO_PSDU) 1808c2ecf20Sopenharmony_ci len += 1; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci if (status->flag & RX_FLAG_RADIOTAP_LSIG) { 1838c2ecf20Sopenharmony_ci len = ALIGN(len, 2); 1848c2ecf20Sopenharmony_ci len += 4; 1858c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(struct ieee80211_radiotap_lsig) != 4); 1868c2ecf20Sopenharmony_ci } 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci if (status->chains) { 1898c2ecf20Sopenharmony_ci /* antenna and antenna signal fields */ 1908c2ecf20Sopenharmony_ci len += 2 * hweight8(status->chains); 1918c2ecf20Sopenharmony_ci } 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci if (status->flag & RX_FLAG_RADIOTAP_VENDOR_DATA) { 1948c2ecf20Sopenharmony_ci struct ieee80211_vendor_radiotap *rtap; 1958c2ecf20Sopenharmony_ci int vendor_data_offset = 0; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci /* 1988c2ecf20Sopenharmony_ci * The position to look at depends on the existence (or non- 1998c2ecf20Sopenharmony_ci * existence) of other elements, so take that into account... 2008c2ecf20Sopenharmony_ci */ 2018c2ecf20Sopenharmony_ci if (status->flag & RX_FLAG_RADIOTAP_HE) 2028c2ecf20Sopenharmony_ci vendor_data_offset += 2038c2ecf20Sopenharmony_ci sizeof(struct ieee80211_radiotap_he); 2048c2ecf20Sopenharmony_ci if (status->flag & RX_FLAG_RADIOTAP_HE_MU) 2058c2ecf20Sopenharmony_ci vendor_data_offset += 2068c2ecf20Sopenharmony_ci sizeof(struct ieee80211_radiotap_he_mu); 2078c2ecf20Sopenharmony_ci if (status->flag & RX_FLAG_RADIOTAP_LSIG) 2088c2ecf20Sopenharmony_ci vendor_data_offset += 2098c2ecf20Sopenharmony_ci sizeof(struct ieee80211_radiotap_lsig); 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci rtap = (void *)&skb->data[vendor_data_offset]; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci /* alignment for fixed 6-byte vendor data header */ 2148c2ecf20Sopenharmony_ci len = ALIGN(len, 2); 2158c2ecf20Sopenharmony_ci /* vendor data header */ 2168c2ecf20Sopenharmony_ci len += 6; 2178c2ecf20Sopenharmony_ci if (WARN_ON(rtap->align == 0)) 2188c2ecf20Sopenharmony_ci rtap->align = 1; 2198c2ecf20Sopenharmony_ci len = ALIGN(len, rtap->align); 2208c2ecf20Sopenharmony_ci len += rtap->len + rtap->pad; 2218c2ecf20Sopenharmony_ci } 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci return len; 2248c2ecf20Sopenharmony_ci} 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_cistatic void ieee80211_handle_mu_mimo_mon(struct ieee80211_sub_if_data *sdata, 2278c2ecf20Sopenharmony_ci struct sk_buff *skb, 2288c2ecf20Sopenharmony_ci int rtap_space) 2298c2ecf20Sopenharmony_ci{ 2308c2ecf20Sopenharmony_ci struct { 2318c2ecf20Sopenharmony_ci struct ieee80211_hdr_3addr hdr; 2328c2ecf20Sopenharmony_ci u8 category; 2338c2ecf20Sopenharmony_ci u8 action_code; 2348c2ecf20Sopenharmony_ci } __packed __aligned(2) action; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci if (!sdata) 2378c2ecf20Sopenharmony_ci return; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(action) != IEEE80211_MIN_ACTION_SIZE + 1); 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci if (skb->len < rtap_space + sizeof(action) + 2428c2ecf20Sopenharmony_ci VHT_MUMIMO_GROUPS_DATA_LEN) 2438c2ecf20Sopenharmony_ci return; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci if (!is_valid_ether_addr(sdata->u.mntr.mu_follow_addr)) 2468c2ecf20Sopenharmony_ci return; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci skb_copy_bits(skb, rtap_space, &action, sizeof(action)); 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci if (!ieee80211_is_action(action.hdr.frame_control)) 2518c2ecf20Sopenharmony_ci return; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci if (action.category != WLAN_CATEGORY_VHT) 2548c2ecf20Sopenharmony_ci return; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci if (action.action_code != WLAN_VHT_ACTION_GROUPID_MGMT) 2578c2ecf20Sopenharmony_ci return; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci if (!ether_addr_equal(action.hdr.addr1, sdata->u.mntr.mu_follow_addr)) 2608c2ecf20Sopenharmony_ci return; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci skb = skb_copy(skb, GFP_ATOMIC); 2638c2ecf20Sopenharmony_ci if (!skb) 2648c2ecf20Sopenharmony_ci return; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci skb_queue_tail(&sdata->skb_queue, skb); 2678c2ecf20Sopenharmony_ci ieee80211_queue_work(&sdata->local->hw, &sdata->work); 2688c2ecf20Sopenharmony_ci} 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci/* 2718c2ecf20Sopenharmony_ci * ieee80211_add_rx_radiotap_header - add radiotap header 2728c2ecf20Sopenharmony_ci * 2738c2ecf20Sopenharmony_ci * add a radiotap header containing all the fields which the hardware provided. 2748c2ecf20Sopenharmony_ci */ 2758c2ecf20Sopenharmony_cistatic void 2768c2ecf20Sopenharmony_ciieee80211_add_rx_radiotap_header(struct ieee80211_local *local, 2778c2ecf20Sopenharmony_ci struct sk_buff *skb, 2788c2ecf20Sopenharmony_ci struct ieee80211_rate *rate, 2798c2ecf20Sopenharmony_ci int rtap_len, bool has_fcs) 2808c2ecf20Sopenharmony_ci{ 2818c2ecf20Sopenharmony_ci struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); 2828c2ecf20Sopenharmony_ci struct ieee80211_radiotap_header *rthdr; 2838c2ecf20Sopenharmony_ci unsigned char *pos; 2848c2ecf20Sopenharmony_ci __le32 *it_present; 2858c2ecf20Sopenharmony_ci u32 it_present_val; 2868c2ecf20Sopenharmony_ci u16 rx_flags = 0; 2878c2ecf20Sopenharmony_ci u16 channel_flags = 0; 2888c2ecf20Sopenharmony_ci int mpdulen, chain; 2898c2ecf20Sopenharmony_ci unsigned long chains = status->chains; 2908c2ecf20Sopenharmony_ci struct ieee80211_vendor_radiotap rtap = {}; 2918c2ecf20Sopenharmony_ci struct ieee80211_radiotap_he he = {}; 2928c2ecf20Sopenharmony_ci struct ieee80211_radiotap_he_mu he_mu = {}; 2938c2ecf20Sopenharmony_ci struct ieee80211_radiotap_lsig lsig = {}; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci if (status->flag & RX_FLAG_RADIOTAP_HE) { 2968c2ecf20Sopenharmony_ci he = *(struct ieee80211_radiotap_he *)skb->data; 2978c2ecf20Sopenharmony_ci skb_pull(skb, sizeof(he)); 2988c2ecf20Sopenharmony_ci WARN_ON_ONCE(status->encoding != RX_ENC_HE); 2998c2ecf20Sopenharmony_ci } 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci if (status->flag & RX_FLAG_RADIOTAP_HE_MU) { 3028c2ecf20Sopenharmony_ci he_mu = *(struct ieee80211_radiotap_he_mu *)skb->data; 3038c2ecf20Sopenharmony_ci skb_pull(skb, sizeof(he_mu)); 3048c2ecf20Sopenharmony_ci } 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci if (status->flag & RX_FLAG_RADIOTAP_LSIG) { 3078c2ecf20Sopenharmony_ci lsig = *(struct ieee80211_radiotap_lsig *)skb->data; 3088c2ecf20Sopenharmony_ci skb_pull(skb, sizeof(lsig)); 3098c2ecf20Sopenharmony_ci } 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci if (status->flag & RX_FLAG_RADIOTAP_VENDOR_DATA) { 3128c2ecf20Sopenharmony_ci rtap = *(struct ieee80211_vendor_radiotap *)skb->data; 3138c2ecf20Sopenharmony_ci /* rtap.len and rtap.pad are undone immediately */ 3148c2ecf20Sopenharmony_ci skb_pull(skb, sizeof(rtap) + rtap.len + rtap.pad); 3158c2ecf20Sopenharmony_ci } 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci mpdulen = skb->len; 3188c2ecf20Sopenharmony_ci if (!(has_fcs && ieee80211_hw_check(&local->hw, RX_INCLUDES_FCS))) 3198c2ecf20Sopenharmony_ci mpdulen += FCS_LEN; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci rthdr = skb_push(skb, rtap_len); 3228c2ecf20Sopenharmony_ci memset(rthdr, 0, rtap_len - rtap.len - rtap.pad); 3238c2ecf20Sopenharmony_ci it_present = &rthdr->it_present; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci /* radiotap header, set always present flags */ 3268c2ecf20Sopenharmony_ci rthdr->it_len = cpu_to_le16(rtap_len); 3278c2ecf20Sopenharmony_ci it_present_val = BIT(IEEE80211_RADIOTAP_FLAGS) | 3288c2ecf20Sopenharmony_ci BIT(IEEE80211_RADIOTAP_CHANNEL) | 3298c2ecf20Sopenharmony_ci BIT(IEEE80211_RADIOTAP_RX_FLAGS); 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci if (!status->chains) 3328c2ecf20Sopenharmony_ci it_present_val |= BIT(IEEE80211_RADIOTAP_ANTENNA); 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci for_each_set_bit(chain, &chains, IEEE80211_MAX_CHAINS) { 3358c2ecf20Sopenharmony_ci it_present_val |= 3368c2ecf20Sopenharmony_ci BIT(IEEE80211_RADIOTAP_EXT) | 3378c2ecf20Sopenharmony_ci BIT(IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE); 3388c2ecf20Sopenharmony_ci put_unaligned_le32(it_present_val, it_present); 3398c2ecf20Sopenharmony_ci it_present++; 3408c2ecf20Sopenharmony_ci it_present_val = BIT(IEEE80211_RADIOTAP_ANTENNA) | 3418c2ecf20Sopenharmony_ci BIT(IEEE80211_RADIOTAP_DBM_ANTSIGNAL); 3428c2ecf20Sopenharmony_ci } 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci if (status->flag & RX_FLAG_RADIOTAP_VENDOR_DATA) { 3458c2ecf20Sopenharmony_ci it_present_val |= BIT(IEEE80211_RADIOTAP_VENDOR_NAMESPACE) | 3468c2ecf20Sopenharmony_ci BIT(IEEE80211_RADIOTAP_EXT); 3478c2ecf20Sopenharmony_ci put_unaligned_le32(it_present_val, it_present); 3488c2ecf20Sopenharmony_ci it_present++; 3498c2ecf20Sopenharmony_ci it_present_val = rtap.present; 3508c2ecf20Sopenharmony_ci } 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci put_unaligned_le32(it_present_val, it_present); 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci pos = (void *)(it_present + 1); 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci /* the order of the following fields is important */ 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci /* IEEE80211_RADIOTAP_TSFT */ 3598c2ecf20Sopenharmony_ci if (ieee80211_have_rx_timestamp(status)) { 3608c2ecf20Sopenharmony_ci /* padding */ 3618c2ecf20Sopenharmony_ci while ((pos - (u8 *)rthdr) & 7) 3628c2ecf20Sopenharmony_ci *pos++ = 0; 3638c2ecf20Sopenharmony_ci put_unaligned_le64( 3648c2ecf20Sopenharmony_ci ieee80211_calculate_rx_timestamp(local, status, 3658c2ecf20Sopenharmony_ci mpdulen, 0), 3668c2ecf20Sopenharmony_ci pos); 3678c2ecf20Sopenharmony_ci rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_TSFT); 3688c2ecf20Sopenharmony_ci pos += 8; 3698c2ecf20Sopenharmony_ci } 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci /* IEEE80211_RADIOTAP_FLAGS */ 3728c2ecf20Sopenharmony_ci if (has_fcs && ieee80211_hw_check(&local->hw, RX_INCLUDES_FCS)) 3738c2ecf20Sopenharmony_ci *pos |= IEEE80211_RADIOTAP_F_FCS; 3748c2ecf20Sopenharmony_ci if (status->flag & (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC)) 3758c2ecf20Sopenharmony_ci *pos |= IEEE80211_RADIOTAP_F_BADFCS; 3768c2ecf20Sopenharmony_ci if (status->enc_flags & RX_ENC_FLAG_SHORTPRE) 3778c2ecf20Sopenharmony_ci *pos |= IEEE80211_RADIOTAP_F_SHORTPRE; 3788c2ecf20Sopenharmony_ci pos++; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci /* IEEE80211_RADIOTAP_RATE */ 3818c2ecf20Sopenharmony_ci if (!rate || status->encoding != RX_ENC_LEGACY) { 3828c2ecf20Sopenharmony_ci /* 3838c2ecf20Sopenharmony_ci * Without rate information don't add it. If we have, 3848c2ecf20Sopenharmony_ci * MCS information is a separate field in radiotap, 3858c2ecf20Sopenharmony_ci * added below. The byte here is needed as padding 3868c2ecf20Sopenharmony_ci * for the channel though, so initialise it to 0. 3878c2ecf20Sopenharmony_ci */ 3888c2ecf20Sopenharmony_ci *pos = 0; 3898c2ecf20Sopenharmony_ci } else { 3908c2ecf20Sopenharmony_ci int shift = 0; 3918c2ecf20Sopenharmony_ci rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_RATE); 3928c2ecf20Sopenharmony_ci if (status->bw == RATE_INFO_BW_10) 3938c2ecf20Sopenharmony_ci shift = 1; 3948c2ecf20Sopenharmony_ci else if (status->bw == RATE_INFO_BW_5) 3958c2ecf20Sopenharmony_ci shift = 2; 3968c2ecf20Sopenharmony_ci *pos = DIV_ROUND_UP(rate->bitrate, 5 * (1 << shift)); 3978c2ecf20Sopenharmony_ci } 3988c2ecf20Sopenharmony_ci pos++; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci /* IEEE80211_RADIOTAP_CHANNEL */ 4018c2ecf20Sopenharmony_ci /* TODO: frequency offset in KHz */ 4028c2ecf20Sopenharmony_ci put_unaligned_le16(status->freq, pos); 4038c2ecf20Sopenharmony_ci pos += 2; 4048c2ecf20Sopenharmony_ci if (status->bw == RATE_INFO_BW_10) 4058c2ecf20Sopenharmony_ci channel_flags |= IEEE80211_CHAN_HALF; 4068c2ecf20Sopenharmony_ci else if (status->bw == RATE_INFO_BW_5) 4078c2ecf20Sopenharmony_ci channel_flags |= IEEE80211_CHAN_QUARTER; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci if (status->band == NL80211_BAND_5GHZ || 4108c2ecf20Sopenharmony_ci status->band == NL80211_BAND_6GHZ) 4118c2ecf20Sopenharmony_ci channel_flags |= IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ; 4128c2ecf20Sopenharmony_ci else if (status->encoding != RX_ENC_LEGACY) 4138c2ecf20Sopenharmony_ci channel_flags |= IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ; 4148c2ecf20Sopenharmony_ci else if (rate && rate->flags & IEEE80211_RATE_ERP_G) 4158c2ecf20Sopenharmony_ci channel_flags |= IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ; 4168c2ecf20Sopenharmony_ci else if (rate) 4178c2ecf20Sopenharmony_ci channel_flags |= IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ; 4188c2ecf20Sopenharmony_ci else 4198c2ecf20Sopenharmony_ci channel_flags |= IEEE80211_CHAN_2GHZ; 4208c2ecf20Sopenharmony_ci put_unaligned_le16(channel_flags, pos); 4218c2ecf20Sopenharmony_ci pos += 2; 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci /* IEEE80211_RADIOTAP_DBM_ANTSIGNAL */ 4248c2ecf20Sopenharmony_ci if (ieee80211_hw_check(&local->hw, SIGNAL_DBM) && 4258c2ecf20Sopenharmony_ci !(status->flag & RX_FLAG_NO_SIGNAL_VAL)) { 4268c2ecf20Sopenharmony_ci *pos = status->signal; 4278c2ecf20Sopenharmony_ci rthdr->it_present |= 4288c2ecf20Sopenharmony_ci cpu_to_le32(1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL); 4298c2ecf20Sopenharmony_ci pos++; 4308c2ecf20Sopenharmony_ci } 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci /* IEEE80211_RADIOTAP_LOCK_QUALITY is missing */ 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci if (!status->chains) { 4358c2ecf20Sopenharmony_ci /* IEEE80211_RADIOTAP_ANTENNA */ 4368c2ecf20Sopenharmony_ci *pos = status->antenna; 4378c2ecf20Sopenharmony_ci pos++; 4388c2ecf20Sopenharmony_ci } 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci /* IEEE80211_RADIOTAP_DB_ANTNOISE is not used */ 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci /* IEEE80211_RADIOTAP_RX_FLAGS */ 4438c2ecf20Sopenharmony_ci /* ensure 2 byte alignment for the 2 byte field as required */ 4448c2ecf20Sopenharmony_ci if ((pos - (u8 *)rthdr) & 1) 4458c2ecf20Sopenharmony_ci *pos++ = 0; 4468c2ecf20Sopenharmony_ci if (status->flag & RX_FLAG_FAILED_PLCP_CRC) 4478c2ecf20Sopenharmony_ci rx_flags |= IEEE80211_RADIOTAP_F_RX_BADPLCP; 4488c2ecf20Sopenharmony_ci put_unaligned_le16(rx_flags, pos); 4498c2ecf20Sopenharmony_ci pos += 2; 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci if (status->encoding == RX_ENC_HT) { 4528c2ecf20Sopenharmony_ci unsigned int stbc; 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_MCS); 4558c2ecf20Sopenharmony_ci *pos++ = local->hw.radiotap_mcs_details; 4568c2ecf20Sopenharmony_ci *pos = 0; 4578c2ecf20Sopenharmony_ci if (status->enc_flags & RX_ENC_FLAG_SHORT_GI) 4588c2ecf20Sopenharmony_ci *pos |= IEEE80211_RADIOTAP_MCS_SGI; 4598c2ecf20Sopenharmony_ci if (status->bw == RATE_INFO_BW_40) 4608c2ecf20Sopenharmony_ci *pos |= IEEE80211_RADIOTAP_MCS_BW_40; 4618c2ecf20Sopenharmony_ci if (status->enc_flags & RX_ENC_FLAG_HT_GF) 4628c2ecf20Sopenharmony_ci *pos |= IEEE80211_RADIOTAP_MCS_FMT_GF; 4638c2ecf20Sopenharmony_ci if (status->enc_flags & RX_ENC_FLAG_LDPC) 4648c2ecf20Sopenharmony_ci *pos |= IEEE80211_RADIOTAP_MCS_FEC_LDPC; 4658c2ecf20Sopenharmony_ci stbc = (status->enc_flags & RX_ENC_FLAG_STBC_MASK) >> RX_ENC_FLAG_STBC_SHIFT; 4668c2ecf20Sopenharmony_ci *pos |= stbc << IEEE80211_RADIOTAP_MCS_STBC_SHIFT; 4678c2ecf20Sopenharmony_ci pos++; 4688c2ecf20Sopenharmony_ci *pos++ = status->rate_idx; 4698c2ecf20Sopenharmony_ci } 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci if (status->flag & RX_FLAG_AMPDU_DETAILS) { 4728c2ecf20Sopenharmony_ci u16 flags = 0; 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci /* ensure 4 byte alignment */ 4758c2ecf20Sopenharmony_ci while ((pos - (u8 *)rthdr) & 3) 4768c2ecf20Sopenharmony_ci pos++; 4778c2ecf20Sopenharmony_ci rthdr->it_present |= 4788c2ecf20Sopenharmony_ci cpu_to_le32(1 << IEEE80211_RADIOTAP_AMPDU_STATUS); 4798c2ecf20Sopenharmony_ci put_unaligned_le32(status->ampdu_reference, pos); 4808c2ecf20Sopenharmony_ci pos += 4; 4818c2ecf20Sopenharmony_ci if (status->flag & RX_FLAG_AMPDU_LAST_KNOWN) 4828c2ecf20Sopenharmony_ci flags |= IEEE80211_RADIOTAP_AMPDU_LAST_KNOWN; 4838c2ecf20Sopenharmony_ci if (status->flag & RX_FLAG_AMPDU_IS_LAST) 4848c2ecf20Sopenharmony_ci flags |= IEEE80211_RADIOTAP_AMPDU_IS_LAST; 4858c2ecf20Sopenharmony_ci if (status->flag & RX_FLAG_AMPDU_DELIM_CRC_ERROR) 4868c2ecf20Sopenharmony_ci flags |= IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_ERR; 4878c2ecf20Sopenharmony_ci if (status->flag & RX_FLAG_AMPDU_DELIM_CRC_KNOWN) 4888c2ecf20Sopenharmony_ci flags |= IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_KNOWN; 4898c2ecf20Sopenharmony_ci if (status->flag & RX_FLAG_AMPDU_EOF_BIT_KNOWN) 4908c2ecf20Sopenharmony_ci flags |= IEEE80211_RADIOTAP_AMPDU_EOF_KNOWN; 4918c2ecf20Sopenharmony_ci if (status->flag & RX_FLAG_AMPDU_EOF_BIT) 4928c2ecf20Sopenharmony_ci flags |= IEEE80211_RADIOTAP_AMPDU_EOF; 4938c2ecf20Sopenharmony_ci put_unaligned_le16(flags, pos); 4948c2ecf20Sopenharmony_ci pos += 2; 4958c2ecf20Sopenharmony_ci if (status->flag & RX_FLAG_AMPDU_DELIM_CRC_KNOWN) 4968c2ecf20Sopenharmony_ci *pos++ = status->ampdu_delimiter_crc; 4978c2ecf20Sopenharmony_ci else 4988c2ecf20Sopenharmony_ci *pos++ = 0; 4998c2ecf20Sopenharmony_ci *pos++ = 0; 5008c2ecf20Sopenharmony_ci } 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci if (status->encoding == RX_ENC_VHT) { 5038c2ecf20Sopenharmony_ci u16 known = local->hw.radiotap_vht_details; 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_VHT); 5068c2ecf20Sopenharmony_ci put_unaligned_le16(known, pos); 5078c2ecf20Sopenharmony_ci pos += 2; 5088c2ecf20Sopenharmony_ci /* flags */ 5098c2ecf20Sopenharmony_ci if (status->enc_flags & RX_ENC_FLAG_SHORT_GI) 5108c2ecf20Sopenharmony_ci *pos |= IEEE80211_RADIOTAP_VHT_FLAG_SGI; 5118c2ecf20Sopenharmony_ci /* in VHT, STBC is binary */ 5128c2ecf20Sopenharmony_ci if (status->enc_flags & RX_ENC_FLAG_STBC_MASK) 5138c2ecf20Sopenharmony_ci *pos |= IEEE80211_RADIOTAP_VHT_FLAG_STBC; 5148c2ecf20Sopenharmony_ci if (status->enc_flags & RX_ENC_FLAG_BF) 5158c2ecf20Sopenharmony_ci *pos |= IEEE80211_RADIOTAP_VHT_FLAG_BEAMFORMED; 5168c2ecf20Sopenharmony_ci pos++; 5178c2ecf20Sopenharmony_ci /* bandwidth */ 5188c2ecf20Sopenharmony_ci switch (status->bw) { 5198c2ecf20Sopenharmony_ci case RATE_INFO_BW_80: 5208c2ecf20Sopenharmony_ci *pos++ = 4; 5218c2ecf20Sopenharmony_ci break; 5228c2ecf20Sopenharmony_ci case RATE_INFO_BW_160: 5238c2ecf20Sopenharmony_ci *pos++ = 11; 5248c2ecf20Sopenharmony_ci break; 5258c2ecf20Sopenharmony_ci case RATE_INFO_BW_40: 5268c2ecf20Sopenharmony_ci *pos++ = 1; 5278c2ecf20Sopenharmony_ci break; 5288c2ecf20Sopenharmony_ci default: 5298c2ecf20Sopenharmony_ci *pos++ = 0; 5308c2ecf20Sopenharmony_ci } 5318c2ecf20Sopenharmony_ci /* MCS/NSS */ 5328c2ecf20Sopenharmony_ci *pos = (status->rate_idx << 4) | status->nss; 5338c2ecf20Sopenharmony_ci pos += 4; 5348c2ecf20Sopenharmony_ci /* coding field */ 5358c2ecf20Sopenharmony_ci if (status->enc_flags & RX_ENC_FLAG_LDPC) 5368c2ecf20Sopenharmony_ci *pos |= IEEE80211_RADIOTAP_CODING_LDPC_USER0; 5378c2ecf20Sopenharmony_ci pos++; 5388c2ecf20Sopenharmony_ci /* group ID */ 5398c2ecf20Sopenharmony_ci pos++; 5408c2ecf20Sopenharmony_ci /* partial_aid */ 5418c2ecf20Sopenharmony_ci pos += 2; 5428c2ecf20Sopenharmony_ci } 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci if (local->hw.radiotap_timestamp.units_pos >= 0) { 5458c2ecf20Sopenharmony_ci u16 accuracy = 0; 5468c2ecf20Sopenharmony_ci u8 flags = IEEE80211_RADIOTAP_TIMESTAMP_FLAG_32BIT; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci rthdr->it_present |= 5498c2ecf20Sopenharmony_ci cpu_to_le32(1 << IEEE80211_RADIOTAP_TIMESTAMP); 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci /* ensure 8 byte alignment */ 5528c2ecf20Sopenharmony_ci while ((pos - (u8 *)rthdr) & 7) 5538c2ecf20Sopenharmony_ci pos++; 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci put_unaligned_le64(status->device_timestamp, pos); 5568c2ecf20Sopenharmony_ci pos += sizeof(u64); 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci if (local->hw.radiotap_timestamp.accuracy >= 0) { 5598c2ecf20Sopenharmony_ci accuracy = local->hw.radiotap_timestamp.accuracy; 5608c2ecf20Sopenharmony_ci flags |= IEEE80211_RADIOTAP_TIMESTAMP_FLAG_ACCURACY; 5618c2ecf20Sopenharmony_ci } 5628c2ecf20Sopenharmony_ci put_unaligned_le16(accuracy, pos); 5638c2ecf20Sopenharmony_ci pos += sizeof(u16); 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci *pos++ = local->hw.radiotap_timestamp.units_pos; 5668c2ecf20Sopenharmony_ci *pos++ = flags; 5678c2ecf20Sopenharmony_ci } 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci if (status->encoding == RX_ENC_HE && 5708c2ecf20Sopenharmony_ci status->flag & RX_FLAG_RADIOTAP_HE) { 5718c2ecf20Sopenharmony_ci#define HE_PREP(f, val) le16_encode_bits(val, IEEE80211_RADIOTAP_HE_##f) 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci if (status->enc_flags & RX_ENC_FLAG_STBC_MASK) { 5748c2ecf20Sopenharmony_ci he.data6 |= HE_PREP(DATA6_NSTS, 5758c2ecf20Sopenharmony_ci FIELD_GET(RX_ENC_FLAG_STBC_MASK, 5768c2ecf20Sopenharmony_ci status->enc_flags)); 5778c2ecf20Sopenharmony_ci he.data3 |= HE_PREP(DATA3_STBC, 1); 5788c2ecf20Sopenharmony_ci } else { 5798c2ecf20Sopenharmony_ci he.data6 |= HE_PREP(DATA6_NSTS, status->nss); 5808c2ecf20Sopenharmony_ci } 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci#define CHECK_GI(s) \ 5838c2ecf20Sopenharmony_ci BUILD_BUG_ON(IEEE80211_RADIOTAP_HE_DATA5_GI_##s != \ 5848c2ecf20Sopenharmony_ci (int)NL80211_RATE_INFO_HE_GI_##s) 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci CHECK_GI(0_8); 5878c2ecf20Sopenharmony_ci CHECK_GI(1_6); 5888c2ecf20Sopenharmony_ci CHECK_GI(3_2); 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci he.data3 |= HE_PREP(DATA3_DATA_MCS, status->rate_idx); 5918c2ecf20Sopenharmony_ci he.data3 |= HE_PREP(DATA3_DATA_DCM, status->he_dcm); 5928c2ecf20Sopenharmony_ci he.data3 |= HE_PREP(DATA3_CODING, 5938c2ecf20Sopenharmony_ci !!(status->enc_flags & RX_ENC_FLAG_LDPC)); 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci he.data5 |= HE_PREP(DATA5_GI, status->he_gi); 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci switch (status->bw) { 5988c2ecf20Sopenharmony_ci case RATE_INFO_BW_20: 5998c2ecf20Sopenharmony_ci he.data5 |= HE_PREP(DATA5_DATA_BW_RU_ALLOC, 6008c2ecf20Sopenharmony_ci IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_20MHZ); 6018c2ecf20Sopenharmony_ci break; 6028c2ecf20Sopenharmony_ci case RATE_INFO_BW_40: 6038c2ecf20Sopenharmony_ci he.data5 |= HE_PREP(DATA5_DATA_BW_RU_ALLOC, 6048c2ecf20Sopenharmony_ci IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_40MHZ); 6058c2ecf20Sopenharmony_ci break; 6068c2ecf20Sopenharmony_ci case RATE_INFO_BW_80: 6078c2ecf20Sopenharmony_ci he.data5 |= HE_PREP(DATA5_DATA_BW_RU_ALLOC, 6088c2ecf20Sopenharmony_ci IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_80MHZ); 6098c2ecf20Sopenharmony_ci break; 6108c2ecf20Sopenharmony_ci case RATE_INFO_BW_160: 6118c2ecf20Sopenharmony_ci he.data5 |= HE_PREP(DATA5_DATA_BW_RU_ALLOC, 6128c2ecf20Sopenharmony_ci IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_160MHZ); 6138c2ecf20Sopenharmony_ci break; 6148c2ecf20Sopenharmony_ci case RATE_INFO_BW_HE_RU: 6158c2ecf20Sopenharmony_ci#define CHECK_RU_ALLOC(s) \ 6168c2ecf20Sopenharmony_ci BUILD_BUG_ON(IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_##s##T != \ 6178c2ecf20Sopenharmony_ci NL80211_RATE_INFO_HE_RU_ALLOC_##s + 4) 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci CHECK_RU_ALLOC(26); 6208c2ecf20Sopenharmony_ci CHECK_RU_ALLOC(52); 6218c2ecf20Sopenharmony_ci CHECK_RU_ALLOC(106); 6228c2ecf20Sopenharmony_ci CHECK_RU_ALLOC(242); 6238c2ecf20Sopenharmony_ci CHECK_RU_ALLOC(484); 6248c2ecf20Sopenharmony_ci CHECK_RU_ALLOC(996); 6258c2ecf20Sopenharmony_ci CHECK_RU_ALLOC(2x996); 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci he.data5 |= HE_PREP(DATA5_DATA_BW_RU_ALLOC, 6288c2ecf20Sopenharmony_ci status->he_ru + 4); 6298c2ecf20Sopenharmony_ci break; 6308c2ecf20Sopenharmony_ci default: 6318c2ecf20Sopenharmony_ci WARN_ONCE(1, "Invalid SU BW %d\n", status->bw); 6328c2ecf20Sopenharmony_ci } 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci /* ensure 2 byte alignment */ 6358c2ecf20Sopenharmony_ci while ((pos - (u8 *)rthdr) & 1) 6368c2ecf20Sopenharmony_ci pos++; 6378c2ecf20Sopenharmony_ci rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_HE); 6388c2ecf20Sopenharmony_ci memcpy(pos, &he, sizeof(he)); 6398c2ecf20Sopenharmony_ci pos += sizeof(he); 6408c2ecf20Sopenharmony_ci } 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci if (status->encoding == RX_ENC_HE && 6438c2ecf20Sopenharmony_ci status->flag & RX_FLAG_RADIOTAP_HE_MU) { 6448c2ecf20Sopenharmony_ci /* ensure 2 byte alignment */ 6458c2ecf20Sopenharmony_ci while ((pos - (u8 *)rthdr) & 1) 6468c2ecf20Sopenharmony_ci pos++; 6478c2ecf20Sopenharmony_ci rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_HE_MU); 6488c2ecf20Sopenharmony_ci memcpy(pos, &he_mu, sizeof(he_mu)); 6498c2ecf20Sopenharmony_ci pos += sizeof(he_mu); 6508c2ecf20Sopenharmony_ci } 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci if (status->flag & RX_FLAG_NO_PSDU) { 6538c2ecf20Sopenharmony_ci rthdr->it_present |= 6548c2ecf20Sopenharmony_ci cpu_to_le32(1 << IEEE80211_RADIOTAP_ZERO_LEN_PSDU); 6558c2ecf20Sopenharmony_ci *pos++ = status->zero_length_psdu_type; 6568c2ecf20Sopenharmony_ci } 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci if (status->flag & RX_FLAG_RADIOTAP_LSIG) { 6598c2ecf20Sopenharmony_ci /* ensure 2 byte alignment */ 6608c2ecf20Sopenharmony_ci while ((pos - (u8 *)rthdr) & 1) 6618c2ecf20Sopenharmony_ci pos++; 6628c2ecf20Sopenharmony_ci rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_LSIG); 6638c2ecf20Sopenharmony_ci memcpy(pos, &lsig, sizeof(lsig)); 6648c2ecf20Sopenharmony_ci pos += sizeof(lsig); 6658c2ecf20Sopenharmony_ci } 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci for_each_set_bit(chain, &chains, IEEE80211_MAX_CHAINS) { 6688c2ecf20Sopenharmony_ci *pos++ = status->chain_signal[chain]; 6698c2ecf20Sopenharmony_ci *pos++ = chain; 6708c2ecf20Sopenharmony_ci } 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci if (status->flag & RX_FLAG_RADIOTAP_VENDOR_DATA) { 6738c2ecf20Sopenharmony_ci /* ensure 2 byte alignment for the vendor field as required */ 6748c2ecf20Sopenharmony_ci if ((pos - (u8 *)rthdr) & 1) 6758c2ecf20Sopenharmony_ci *pos++ = 0; 6768c2ecf20Sopenharmony_ci *pos++ = rtap.oui[0]; 6778c2ecf20Sopenharmony_ci *pos++ = rtap.oui[1]; 6788c2ecf20Sopenharmony_ci *pos++ = rtap.oui[2]; 6798c2ecf20Sopenharmony_ci *pos++ = rtap.subns; 6808c2ecf20Sopenharmony_ci put_unaligned_le16(rtap.len, pos); 6818c2ecf20Sopenharmony_ci pos += 2; 6828c2ecf20Sopenharmony_ci /* align the actual payload as requested */ 6838c2ecf20Sopenharmony_ci while ((pos - (u8 *)rthdr) & (rtap.align - 1)) 6848c2ecf20Sopenharmony_ci *pos++ = 0; 6858c2ecf20Sopenharmony_ci /* data (and possible padding) already follows */ 6868c2ecf20Sopenharmony_ci } 6878c2ecf20Sopenharmony_ci} 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_cistatic struct sk_buff * 6908c2ecf20Sopenharmony_ciieee80211_make_monitor_skb(struct ieee80211_local *local, 6918c2ecf20Sopenharmony_ci struct sk_buff **origskb, 6928c2ecf20Sopenharmony_ci struct ieee80211_rate *rate, 6938c2ecf20Sopenharmony_ci int rtap_space, bool use_origskb) 6948c2ecf20Sopenharmony_ci{ 6958c2ecf20Sopenharmony_ci struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(*origskb); 6968c2ecf20Sopenharmony_ci int rt_hdrlen, needed_headroom; 6978c2ecf20Sopenharmony_ci struct sk_buff *skb; 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci /* room for the radiotap header based on driver features */ 7008c2ecf20Sopenharmony_ci rt_hdrlen = ieee80211_rx_radiotap_hdrlen(local, status, *origskb); 7018c2ecf20Sopenharmony_ci needed_headroom = rt_hdrlen - rtap_space; 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci if (use_origskb) { 7048c2ecf20Sopenharmony_ci /* only need to expand headroom if necessary */ 7058c2ecf20Sopenharmony_ci skb = *origskb; 7068c2ecf20Sopenharmony_ci *origskb = NULL; 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci /* 7098c2ecf20Sopenharmony_ci * This shouldn't trigger often because most devices have an 7108c2ecf20Sopenharmony_ci * RX header they pull before we get here, and that should 7118c2ecf20Sopenharmony_ci * be big enough for our radiotap information. We should 7128c2ecf20Sopenharmony_ci * probably export the length to drivers so that we can have 7138c2ecf20Sopenharmony_ci * them allocate enough headroom to start with. 7148c2ecf20Sopenharmony_ci */ 7158c2ecf20Sopenharmony_ci if (skb_headroom(skb) < needed_headroom && 7168c2ecf20Sopenharmony_ci pskb_expand_head(skb, needed_headroom, 0, GFP_ATOMIC)) { 7178c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 7188c2ecf20Sopenharmony_ci return NULL; 7198c2ecf20Sopenharmony_ci } 7208c2ecf20Sopenharmony_ci } else { 7218c2ecf20Sopenharmony_ci /* 7228c2ecf20Sopenharmony_ci * Need to make a copy and possibly remove radiotap header 7238c2ecf20Sopenharmony_ci * and FCS from the original. 7248c2ecf20Sopenharmony_ci */ 7258c2ecf20Sopenharmony_ci skb = skb_copy_expand(*origskb, needed_headroom, 0, GFP_ATOMIC); 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci if (!skb) 7288c2ecf20Sopenharmony_ci return NULL; 7298c2ecf20Sopenharmony_ci } 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci /* prepend radiotap information */ 7328c2ecf20Sopenharmony_ci ieee80211_add_rx_radiotap_header(local, skb, rate, rt_hdrlen, true); 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci skb_reset_mac_header(skb); 7358c2ecf20Sopenharmony_ci skb->ip_summed = CHECKSUM_UNNECESSARY; 7368c2ecf20Sopenharmony_ci skb->pkt_type = PACKET_OTHERHOST; 7378c2ecf20Sopenharmony_ci skb->protocol = htons(ETH_P_802_2); 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci return skb; 7408c2ecf20Sopenharmony_ci} 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci/* 7438c2ecf20Sopenharmony_ci * This function copies a received frame to all monitor interfaces and 7448c2ecf20Sopenharmony_ci * returns a cleaned-up SKB that no longer includes the FCS nor the 7458c2ecf20Sopenharmony_ci * radiotap header the driver might have added. 7468c2ecf20Sopenharmony_ci */ 7478c2ecf20Sopenharmony_cistatic struct sk_buff * 7488c2ecf20Sopenharmony_ciieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, 7498c2ecf20Sopenharmony_ci struct ieee80211_rate *rate) 7508c2ecf20Sopenharmony_ci{ 7518c2ecf20Sopenharmony_ci struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(origskb); 7528c2ecf20Sopenharmony_ci struct ieee80211_sub_if_data *sdata; 7538c2ecf20Sopenharmony_ci struct sk_buff *monskb = NULL; 7548c2ecf20Sopenharmony_ci int present_fcs_len = 0; 7558c2ecf20Sopenharmony_ci unsigned int rtap_space = 0; 7568c2ecf20Sopenharmony_ci struct ieee80211_sub_if_data *monitor_sdata = 7578c2ecf20Sopenharmony_ci rcu_dereference(local->monitor_sdata); 7588c2ecf20Sopenharmony_ci bool only_monitor = false; 7598c2ecf20Sopenharmony_ci unsigned int min_head_len; 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci if (status->flag & RX_FLAG_RADIOTAP_HE) 7628c2ecf20Sopenharmony_ci rtap_space += sizeof(struct ieee80211_radiotap_he); 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci if (status->flag & RX_FLAG_RADIOTAP_HE_MU) 7658c2ecf20Sopenharmony_ci rtap_space += sizeof(struct ieee80211_radiotap_he_mu); 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci if (status->flag & RX_FLAG_RADIOTAP_LSIG) 7688c2ecf20Sopenharmony_ci rtap_space += sizeof(struct ieee80211_radiotap_lsig); 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci if (unlikely(status->flag & RX_FLAG_RADIOTAP_VENDOR_DATA)) { 7718c2ecf20Sopenharmony_ci struct ieee80211_vendor_radiotap *rtap = 7728c2ecf20Sopenharmony_ci (void *)(origskb->data + rtap_space); 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci rtap_space += sizeof(*rtap) + rtap->len + rtap->pad; 7758c2ecf20Sopenharmony_ci } 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci min_head_len = rtap_space; 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci /* 7808c2ecf20Sopenharmony_ci * First, we may need to make a copy of the skb because 7818c2ecf20Sopenharmony_ci * (1) we need to modify it for radiotap (if not present), and 7828c2ecf20Sopenharmony_ci * (2) the other RX handlers will modify the skb we got. 7838c2ecf20Sopenharmony_ci * 7848c2ecf20Sopenharmony_ci * We don't need to, of course, if we aren't going to return 7858c2ecf20Sopenharmony_ci * the SKB because it has a bad FCS/PLCP checksum. 7868c2ecf20Sopenharmony_ci */ 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci if (!(status->flag & RX_FLAG_NO_PSDU)) { 7898c2ecf20Sopenharmony_ci if (ieee80211_hw_check(&local->hw, RX_INCLUDES_FCS)) { 7908c2ecf20Sopenharmony_ci if (unlikely(origskb->len <= FCS_LEN + rtap_space)) { 7918c2ecf20Sopenharmony_ci /* driver bug */ 7928c2ecf20Sopenharmony_ci WARN_ON(1); 7938c2ecf20Sopenharmony_ci dev_kfree_skb(origskb); 7948c2ecf20Sopenharmony_ci return NULL; 7958c2ecf20Sopenharmony_ci } 7968c2ecf20Sopenharmony_ci present_fcs_len = FCS_LEN; 7978c2ecf20Sopenharmony_ci } 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci /* also consider the hdr->frame_control */ 8008c2ecf20Sopenharmony_ci min_head_len += 2; 8018c2ecf20Sopenharmony_ci } 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci /* ensure that the expected data elements are in skb head */ 8048c2ecf20Sopenharmony_ci if (!pskb_may_pull(origskb, min_head_len)) { 8058c2ecf20Sopenharmony_ci dev_kfree_skb(origskb); 8068c2ecf20Sopenharmony_ci return NULL; 8078c2ecf20Sopenharmony_ci } 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci only_monitor = should_drop_frame(origskb, present_fcs_len, rtap_space); 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci if (!local->monitors || (status->flag & RX_FLAG_SKIP_MONITOR)) { 8128c2ecf20Sopenharmony_ci if (only_monitor) { 8138c2ecf20Sopenharmony_ci dev_kfree_skb(origskb); 8148c2ecf20Sopenharmony_ci return NULL; 8158c2ecf20Sopenharmony_ci } 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci return ieee80211_clean_skb(origskb, present_fcs_len, 8188c2ecf20Sopenharmony_ci rtap_space); 8198c2ecf20Sopenharmony_ci } 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci ieee80211_handle_mu_mimo_mon(monitor_sdata, origskb, rtap_space); 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci list_for_each_entry_rcu(sdata, &local->mon_list, u.mntr.list) { 8248c2ecf20Sopenharmony_ci bool last_monitor = list_is_last(&sdata->u.mntr.list, 8258c2ecf20Sopenharmony_ci &local->mon_list); 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci if (!monskb) 8288c2ecf20Sopenharmony_ci monskb = ieee80211_make_monitor_skb(local, &origskb, 8298c2ecf20Sopenharmony_ci rate, rtap_space, 8308c2ecf20Sopenharmony_ci only_monitor && 8318c2ecf20Sopenharmony_ci last_monitor); 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci if (monskb) { 8348c2ecf20Sopenharmony_ci struct sk_buff *skb; 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci if (last_monitor) { 8378c2ecf20Sopenharmony_ci skb = monskb; 8388c2ecf20Sopenharmony_ci monskb = NULL; 8398c2ecf20Sopenharmony_ci } else { 8408c2ecf20Sopenharmony_ci skb = skb_clone(monskb, GFP_ATOMIC); 8418c2ecf20Sopenharmony_ci } 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci if (skb) { 8448c2ecf20Sopenharmony_ci skb->dev = sdata->dev; 8458c2ecf20Sopenharmony_ci ieee80211_rx_stats(skb->dev, skb->len); 8468c2ecf20Sopenharmony_ci netif_receive_skb(skb); 8478c2ecf20Sopenharmony_ci } 8488c2ecf20Sopenharmony_ci } 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci if (last_monitor) 8518c2ecf20Sopenharmony_ci break; 8528c2ecf20Sopenharmony_ci } 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci /* this happens if last_monitor was erroneously false */ 8558c2ecf20Sopenharmony_ci dev_kfree_skb(monskb); 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci /* ditto */ 8588c2ecf20Sopenharmony_ci if (!origskb) 8598c2ecf20Sopenharmony_ci return NULL; 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ci return ieee80211_clean_skb(origskb, present_fcs_len, rtap_space); 8628c2ecf20Sopenharmony_ci} 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_cistatic void ieee80211_parse_qos(struct ieee80211_rx_data *rx) 8658c2ecf20Sopenharmony_ci{ 8668c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; 8678c2ecf20Sopenharmony_ci struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); 8688c2ecf20Sopenharmony_ci int tid, seqno_idx, security_idx; 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci /* does the frame have a qos control field? */ 8718c2ecf20Sopenharmony_ci if (ieee80211_is_data_qos(hdr->frame_control)) { 8728c2ecf20Sopenharmony_ci u8 *qc = ieee80211_get_qos_ctl(hdr); 8738c2ecf20Sopenharmony_ci /* frame has qos control */ 8748c2ecf20Sopenharmony_ci tid = *qc & IEEE80211_QOS_CTL_TID_MASK; 8758c2ecf20Sopenharmony_ci if (*qc & IEEE80211_QOS_CTL_A_MSDU_PRESENT) 8768c2ecf20Sopenharmony_ci status->rx_flags |= IEEE80211_RX_AMSDU; 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci seqno_idx = tid; 8798c2ecf20Sopenharmony_ci security_idx = tid; 8808c2ecf20Sopenharmony_ci } else { 8818c2ecf20Sopenharmony_ci /* 8828c2ecf20Sopenharmony_ci * IEEE 802.11-2007, 7.1.3.4.1 ("Sequence Number field"): 8838c2ecf20Sopenharmony_ci * 8848c2ecf20Sopenharmony_ci * Sequence numbers for management frames, QoS data 8858c2ecf20Sopenharmony_ci * frames with a broadcast/multicast address in the 8868c2ecf20Sopenharmony_ci * Address 1 field, and all non-QoS data frames sent 8878c2ecf20Sopenharmony_ci * by QoS STAs are assigned using an additional single 8888c2ecf20Sopenharmony_ci * modulo-4096 counter, [...] 8898c2ecf20Sopenharmony_ci * 8908c2ecf20Sopenharmony_ci * We also use that counter for non-QoS STAs. 8918c2ecf20Sopenharmony_ci */ 8928c2ecf20Sopenharmony_ci seqno_idx = IEEE80211_NUM_TIDS; 8938c2ecf20Sopenharmony_ci security_idx = 0; 8948c2ecf20Sopenharmony_ci if (ieee80211_is_mgmt(hdr->frame_control)) 8958c2ecf20Sopenharmony_ci security_idx = IEEE80211_NUM_TIDS; 8968c2ecf20Sopenharmony_ci tid = 0; 8978c2ecf20Sopenharmony_ci } 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci rx->seqno_idx = seqno_idx; 9008c2ecf20Sopenharmony_ci rx->security_idx = security_idx; 9018c2ecf20Sopenharmony_ci /* Set skb->priority to 1d tag if highest order bit of TID is not set. 9028c2ecf20Sopenharmony_ci * For now, set skb->priority to 0 for other cases. */ 9038c2ecf20Sopenharmony_ci rx->skb->priority = (tid > 7) ? 0 : tid; 9048c2ecf20Sopenharmony_ci} 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci/** 9078c2ecf20Sopenharmony_ci * DOC: Packet alignment 9088c2ecf20Sopenharmony_ci * 9098c2ecf20Sopenharmony_ci * Drivers always need to pass packets that are aligned to two-byte boundaries 9108c2ecf20Sopenharmony_ci * to the stack. 9118c2ecf20Sopenharmony_ci * 9128c2ecf20Sopenharmony_ci * Additionally, should, if possible, align the payload data in a way that 9138c2ecf20Sopenharmony_ci * guarantees that the contained IP header is aligned to a four-byte 9148c2ecf20Sopenharmony_ci * boundary. In the case of regular frames, this simply means aligning the 9158c2ecf20Sopenharmony_ci * payload to a four-byte boundary (because either the IP header is directly 9168c2ecf20Sopenharmony_ci * contained, or IV/RFC1042 headers that have a length divisible by four are 9178c2ecf20Sopenharmony_ci * in front of it). If the payload data is not properly aligned and the 9188c2ecf20Sopenharmony_ci * architecture doesn't support efficient unaligned operations, mac80211 9198c2ecf20Sopenharmony_ci * will align the data. 9208c2ecf20Sopenharmony_ci * 9218c2ecf20Sopenharmony_ci * With A-MSDU frames, however, the payload data address must yield two modulo 9228c2ecf20Sopenharmony_ci * four because there are 14-byte 802.3 headers within the A-MSDU frames that 9238c2ecf20Sopenharmony_ci * push the IP header further back to a multiple of four again. Thankfully, the 9248c2ecf20Sopenharmony_ci * specs were sane enough this time around to require padding each A-MSDU 9258c2ecf20Sopenharmony_ci * subframe to a length that is a multiple of four. 9268c2ecf20Sopenharmony_ci * 9278c2ecf20Sopenharmony_ci * Padding like Atheros hardware adds which is between the 802.11 header and 9288c2ecf20Sopenharmony_ci * the payload is not supported, the driver is required to move the 802.11 9298c2ecf20Sopenharmony_ci * header to be directly in front of the payload in that case. 9308c2ecf20Sopenharmony_ci */ 9318c2ecf20Sopenharmony_cistatic void ieee80211_verify_alignment(struct ieee80211_rx_data *rx) 9328c2ecf20Sopenharmony_ci{ 9338c2ecf20Sopenharmony_ci#ifdef CONFIG_MAC80211_VERBOSE_DEBUG 9348c2ecf20Sopenharmony_ci WARN_ON_ONCE((unsigned long)rx->skb->data & 1); 9358c2ecf20Sopenharmony_ci#endif 9368c2ecf20Sopenharmony_ci} 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci/* rx handlers */ 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_cistatic int ieee80211_is_unicast_robust_mgmt_frame(struct sk_buff *skb) 9428c2ecf20Sopenharmony_ci{ 9438c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_ci if (is_multicast_ether_addr(hdr->addr1)) 9468c2ecf20Sopenharmony_ci return 0; 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci return ieee80211_is_robust_mgmt_frame(skb); 9498c2ecf20Sopenharmony_ci} 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_cistatic int ieee80211_is_multicast_robust_mgmt_frame(struct sk_buff *skb) 9538c2ecf20Sopenharmony_ci{ 9548c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci if (!is_multicast_ether_addr(hdr->addr1)) 9578c2ecf20Sopenharmony_ci return 0; 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ci return ieee80211_is_robust_mgmt_frame(skb); 9608c2ecf20Sopenharmony_ci} 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_ci/* Get the BIP key index from MMIE; return -1 if this is not a BIP frame */ 9648c2ecf20Sopenharmony_cistatic int ieee80211_get_mmie_keyidx(struct sk_buff *skb) 9658c2ecf20Sopenharmony_ci{ 9668c2ecf20Sopenharmony_ci struct ieee80211_mgmt *hdr = (struct ieee80211_mgmt *) skb->data; 9678c2ecf20Sopenharmony_ci struct ieee80211_mmie *mmie; 9688c2ecf20Sopenharmony_ci struct ieee80211_mmie_16 *mmie16; 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_ci if (skb->len < 24 + sizeof(*mmie) || !is_multicast_ether_addr(hdr->da)) 9718c2ecf20Sopenharmony_ci return -1; 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ci if (!ieee80211_is_robust_mgmt_frame(skb) && 9748c2ecf20Sopenharmony_ci !ieee80211_is_beacon(hdr->frame_control)) 9758c2ecf20Sopenharmony_ci return -1; /* not a robust management frame */ 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ci mmie = (struct ieee80211_mmie *) 9788c2ecf20Sopenharmony_ci (skb->data + skb->len - sizeof(*mmie)); 9798c2ecf20Sopenharmony_ci if (mmie->element_id == WLAN_EID_MMIE && 9808c2ecf20Sopenharmony_ci mmie->length == sizeof(*mmie) - 2) 9818c2ecf20Sopenharmony_ci return le16_to_cpu(mmie->key_id); 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci mmie16 = (struct ieee80211_mmie_16 *) 9848c2ecf20Sopenharmony_ci (skb->data + skb->len - sizeof(*mmie16)); 9858c2ecf20Sopenharmony_ci if (skb->len >= 24 + sizeof(*mmie16) && 9868c2ecf20Sopenharmony_ci mmie16->element_id == WLAN_EID_MMIE && 9878c2ecf20Sopenharmony_ci mmie16->length == sizeof(*mmie16) - 2) 9888c2ecf20Sopenharmony_ci return le16_to_cpu(mmie16->key_id); 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci return -1; 9918c2ecf20Sopenharmony_ci} 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_cistatic int ieee80211_get_keyid(struct sk_buff *skb, 9948c2ecf20Sopenharmony_ci const struct ieee80211_cipher_scheme *cs) 9958c2ecf20Sopenharmony_ci{ 9968c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; 9978c2ecf20Sopenharmony_ci __le16 fc; 9988c2ecf20Sopenharmony_ci int hdrlen; 9998c2ecf20Sopenharmony_ci int minlen; 10008c2ecf20Sopenharmony_ci u8 key_idx_off; 10018c2ecf20Sopenharmony_ci u8 key_idx_shift; 10028c2ecf20Sopenharmony_ci u8 keyid; 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci fc = hdr->frame_control; 10058c2ecf20Sopenharmony_ci hdrlen = ieee80211_hdrlen(fc); 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci if (cs) { 10088c2ecf20Sopenharmony_ci minlen = hdrlen + cs->hdr_len; 10098c2ecf20Sopenharmony_ci key_idx_off = hdrlen + cs->key_idx_off; 10108c2ecf20Sopenharmony_ci key_idx_shift = cs->key_idx_shift; 10118c2ecf20Sopenharmony_ci } else { 10128c2ecf20Sopenharmony_ci /* WEP, TKIP, CCMP and GCMP */ 10138c2ecf20Sopenharmony_ci minlen = hdrlen + IEEE80211_WEP_IV_LEN; 10148c2ecf20Sopenharmony_ci key_idx_off = hdrlen + 3; 10158c2ecf20Sopenharmony_ci key_idx_shift = 6; 10168c2ecf20Sopenharmony_ci } 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ci if (unlikely(skb->len < minlen)) 10198c2ecf20Sopenharmony_ci return -EINVAL; 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ci skb_copy_bits(skb, key_idx_off, &keyid, 1); 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_ci if (cs) 10248c2ecf20Sopenharmony_ci keyid &= cs->key_idx_mask; 10258c2ecf20Sopenharmony_ci keyid >>= key_idx_shift; 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci /* cs could use more than the usual two bits for the keyid */ 10288c2ecf20Sopenharmony_ci if (unlikely(keyid >= NUM_DEFAULT_KEYS)) 10298c2ecf20Sopenharmony_ci return -EINVAL; 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci return keyid; 10328c2ecf20Sopenharmony_ci} 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_cistatic ieee80211_rx_result ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) 10358c2ecf20Sopenharmony_ci{ 10368c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; 10378c2ecf20Sopenharmony_ci char *dev_addr = rx->sdata->vif.addr; 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_ci if (ieee80211_is_data(hdr->frame_control)) { 10408c2ecf20Sopenharmony_ci if (is_multicast_ether_addr(hdr->addr1)) { 10418c2ecf20Sopenharmony_ci if (ieee80211_has_tods(hdr->frame_control) || 10428c2ecf20Sopenharmony_ci !ieee80211_has_fromds(hdr->frame_control)) 10438c2ecf20Sopenharmony_ci return RX_DROP_MONITOR; 10448c2ecf20Sopenharmony_ci if (ether_addr_equal(hdr->addr3, dev_addr)) 10458c2ecf20Sopenharmony_ci return RX_DROP_MONITOR; 10468c2ecf20Sopenharmony_ci } else { 10478c2ecf20Sopenharmony_ci if (!ieee80211_has_a4(hdr->frame_control)) 10488c2ecf20Sopenharmony_ci return RX_DROP_MONITOR; 10498c2ecf20Sopenharmony_ci if (ether_addr_equal(hdr->addr4, dev_addr)) 10508c2ecf20Sopenharmony_ci return RX_DROP_MONITOR; 10518c2ecf20Sopenharmony_ci } 10528c2ecf20Sopenharmony_ci } 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_ci /* If there is not an established peer link and this is not a peer link 10558c2ecf20Sopenharmony_ci * establisment frame, beacon or probe, drop the frame. 10568c2ecf20Sopenharmony_ci */ 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_ci if (!rx->sta || sta_plink_state(rx->sta) != NL80211_PLINK_ESTAB) { 10598c2ecf20Sopenharmony_ci struct ieee80211_mgmt *mgmt; 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_ci if (!ieee80211_is_mgmt(hdr->frame_control)) 10628c2ecf20Sopenharmony_ci return RX_DROP_MONITOR; 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_ci if (ieee80211_is_action(hdr->frame_control)) { 10658c2ecf20Sopenharmony_ci u8 category; 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_ci /* make sure category field is present */ 10688c2ecf20Sopenharmony_ci if (rx->skb->len < IEEE80211_MIN_ACTION_SIZE) 10698c2ecf20Sopenharmony_ci return RX_DROP_MONITOR; 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci mgmt = (struct ieee80211_mgmt *)hdr; 10728c2ecf20Sopenharmony_ci category = mgmt->u.action.category; 10738c2ecf20Sopenharmony_ci if (category != WLAN_CATEGORY_MESH_ACTION && 10748c2ecf20Sopenharmony_ci category != WLAN_CATEGORY_SELF_PROTECTED) 10758c2ecf20Sopenharmony_ci return RX_DROP_MONITOR; 10768c2ecf20Sopenharmony_ci return RX_CONTINUE; 10778c2ecf20Sopenharmony_ci } 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_ci if (ieee80211_is_probe_req(hdr->frame_control) || 10808c2ecf20Sopenharmony_ci ieee80211_is_probe_resp(hdr->frame_control) || 10818c2ecf20Sopenharmony_ci ieee80211_is_beacon(hdr->frame_control) || 10828c2ecf20Sopenharmony_ci ieee80211_is_auth(hdr->frame_control)) 10838c2ecf20Sopenharmony_ci return RX_CONTINUE; 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ci return RX_DROP_MONITOR; 10868c2ecf20Sopenharmony_ci } 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_ci return RX_CONTINUE; 10898c2ecf20Sopenharmony_ci} 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_cistatic inline bool ieee80211_rx_reorder_ready(struct tid_ampdu_rx *tid_agg_rx, 10928c2ecf20Sopenharmony_ci int index) 10938c2ecf20Sopenharmony_ci{ 10948c2ecf20Sopenharmony_ci struct sk_buff_head *frames = &tid_agg_rx->reorder_buf[index]; 10958c2ecf20Sopenharmony_ci struct sk_buff *tail = skb_peek_tail(frames); 10968c2ecf20Sopenharmony_ci struct ieee80211_rx_status *status; 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci if (tid_agg_rx->reorder_buf_filtered & BIT_ULL(index)) 10998c2ecf20Sopenharmony_ci return true; 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci if (!tail) 11028c2ecf20Sopenharmony_ci return false; 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_ci status = IEEE80211_SKB_RXCB(tail); 11058c2ecf20Sopenharmony_ci if (status->flag & RX_FLAG_AMSDU_MORE) 11068c2ecf20Sopenharmony_ci return false; 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci return true; 11098c2ecf20Sopenharmony_ci} 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_cistatic void ieee80211_release_reorder_frame(struct ieee80211_sub_if_data *sdata, 11128c2ecf20Sopenharmony_ci struct tid_ampdu_rx *tid_agg_rx, 11138c2ecf20Sopenharmony_ci int index, 11148c2ecf20Sopenharmony_ci struct sk_buff_head *frames) 11158c2ecf20Sopenharmony_ci{ 11168c2ecf20Sopenharmony_ci struct sk_buff_head *skb_list = &tid_agg_rx->reorder_buf[index]; 11178c2ecf20Sopenharmony_ci struct sk_buff *skb; 11188c2ecf20Sopenharmony_ci struct ieee80211_rx_status *status; 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_ci lockdep_assert_held(&tid_agg_rx->reorder_lock); 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_ci if (skb_queue_empty(skb_list)) 11238c2ecf20Sopenharmony_ci goto no_frame; 11248c2ecf20Sopenharmony_ci 11258c2ecf20Sopenharmony_ci if (!ieee80211_rx_reorder_ready(tid_agg_rx, index)) { 11268c2ecf20Sopenharmony_ci __skb_queue_purge(skb_list); 11278c2ecf20Sopenharmony_ci goto no_frame; 11288c2ecf20Sopenharmony_ci } 11298c2ecf20Sopenharmony_ci 11308c2ecf20Sopenharmony_ci /* release frames from the reorder ring buffer */ 11318c2ecf20Sopenharmony_ci tid_agg_rx->stored_mpdu_num--; 11328c2ecf20Sopenharmony_ci while ((skb = __skb_dequeue(skb_list))) { 11338c2ecf20Sopenharmony_ci status = IEEE80211_SKB_RXCB(skb); 11348c2ecf20Sopenharmony_ci status->rx_flags |= IEEE80211_RX_DEFERRED_RELEASE; 11358c2ecf20Sopenharmony_ci __skb_queue_tail(frames, skb); 11368c2ecf20Sopenharmony_ci } 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_cino_frame: 11398c2ecf20Sopenharmony_ci tid_agg_rx->reorder_buf_filtered &= ~BIT_ULL(index); 11408c2ecf20Sopenharmony_ci tid_agg_rx->head_seq_num = ieee80211_sn_inc(tid_agg_rx->head_seq_num); 11418c2ecf20Sopenharmony_ci} 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_cistatic void ieee80211_release_reorder_frames(struct ieee80211_sub_if_data *sdata, 11448c2ecf20Sopenharmony_ci struct tid_ampdu_rx *tid_agg_rx, 11458c2ecf20Sopenharmony_ci u16 head_seq_num, 11468c2ecf20Sopenharmony_ci struct sk_buff_head *frames) 11478c2ecf20Sopenharmony_ci{ 11488c2ecf20Sopenharmony_ci int index; 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_ci lockdep_assert_held(&tid_agg_rx->reorder_lock); 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_ci while (ieee80211_sn_less(tid_agg_rx->head_seq_num, head_seq_num)) { 11538c2ecf20Sopenharmony_ci index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size; 11548c2ecf20Sopenharmony_ci ieee80211_release_reorder_frame(sdata, tid_agg_rx, index, 11558c2ecf20Sopenharmony_ci frames); 11568c2ecf20Sopenharmony_ci } 11578c2ecf20Sopenharmony_ci} 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_ci/* 11608c2ecf20Sopenharmony_ci * Timeout (in jiffies) for skb's that are waiting in the RX reorder buffer. If 11618c2ecf20Sopenharmony_ci * the skb was added to the buffer longer than this time ago, the earlier 11628c2ecf20Sopenharmony_ci * frames that have not yet been received are assumed to be lost and the skb 11638c2ecf20Sopenharmony_ci * can be released for processing. This may also release other skb's from the 11648c2ecf20Sopenharmony_ci * reorder buffer if there are no additional gaps between the frames. 11658c2ecf20Sopenharmony_ci * 11668c2ecf20Sopenharmony_ci * Callers must hold tid_agg_rx->reorder_lock. 11678c2ecf20Sopenharmony_ci */ 11688c2ecf20Sopenharmony_ci#define HT_RX_REORDER_BUF_TIMEOUT (HZ / 10) 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_cistatic void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata, 11718c2ecf20Sopenharmony_ci struct tid_ampdu_rx *tid_agg_rx, 11728c2ecf20Sopenharmony_ci struct sk_buff_head *frames) 11738c2ecf20Sopenharmony_ci{ 11748c2ecf20Sopenharmony_ci int index, i, j; 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_ci lockdep_assert_held(&tid_agg_rx->reorder_lock); 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_ci /* release the buffer until next missing frame */ 11798c2ecf20Sopenharmony_ci index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size; 11808c2ecf20Sopenharmony_ci if (!ieee80211_rx_reorder_ready(tid_agg_rx, index) && 11818c2ecf20Sopenharmony_ci tid_agg_rx->stored_mpdu_num) { 11828c2ecf20Sopenharmony_ci /* 11838c2ecf20Sopenharmony_ci * No buffers ready to be released, but check whether any 11848c2ecf20Sopenharmony_ci * frames in the reorder buffer have timed out. 11858c2ecf20Sopenharmony_ci */ 11868c2ecf20Sopenharmony_ci int skipped = 1; 11878c2ecf20Sopenharmony_ci for (j = (index + 1) % tid_agg_rx->buf_size; j != index; 11888c2ecf20Sopenharmony_ci j = (j + 1) % tid_agg_rx->buf_size) { 11898c2ecf20Sopenharmony_ci if (!ieee80211_rx_reorder_ready(tid_agg_rx, j)) { 11908c2ecf20Sopenharmony_ci skipped++; 11918c2ecf20Sopenharmony_ci continue; 11928c2ecf20Sopenharmony_ci } 11938c2ecf20Sopenharmony_ci if (skipped && 11948c2ecf20Sopenharmony_ci !time_after(jiffies, tid_agg_rx->reorder_time[j] + 11958c2ecf20Sopenharmony_ci HT_RX_REORDER_BUF_TIMEOUT)) 11968c2ecf20Sopenharmony_ci goto set_release_timer; 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_ci /* don't leave incomplete A-MSDUs around */ 11998c2ecf20Sopenharmony_ci for (i = (index + 1) % tid_agg_rx->buf_size; i != j; 12008c2ecf20Sopenharmony_ci i = (i + 1) % tid_agg_rx->buf_size) 12018c2ecf20Sopenharmony_ci __skb_queue_purge(&tid_agg_rx->reorder_buf[i]); 12028c2ecf20Sopenharmony_ci 12038c2ecf20Sopenharmony_ci ht_dbg_ratelimited(sdata, 12048c2ecf20Sopenharmony_ci "release an RX reorder frame due to timeout on earlier frames\n"); 12058c2ecf20Sopenharmony_ci ieee80211_release_reorder_frame(sdata, tid_agg_rx, j, 12068c2ecf20Sopenharmony_ci frames); 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_ci /* 12098c2ecf20Sopenharmony_ci * Increment the head seq# also for the skipped slots. 12108c2ecf20Sopenharmony_ci */ 12118c2ecf20Sopenharmony_ci tid_agg_rx->head_seq_num = 12128c2ecf20Sopenharmony_ci (tid_agg_rx->head_seq_num + 12138c2ecf20Sopenharmony_ci skipped) & IEEE80211_SN_MASK; 12148c2ecf20Sopenharmony_ci skipped = 0; 12158c2ecf20Sopenharmony_ci } 12168c2ecf20Sopenharmony_ci } else while (ieee80211_rx_reorder_ready(tid_agg_rx, index)) { 12178c2ecf20Sopenharmony_ci ieee80211_release_reorder_frame(sdata, tid_agg_rx, index, 12188c2ecf20Sopenharmony_ci frames); 12198c2ecf20Sopenharmony_ci index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size; 12208c2ecf20Sopenharmony_ci } 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_ci if (tid_agg_rx->stored_mpdu_num) { 12238c2ecf20Sopenharmony_ci j = index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size; 12248c2ecf20Sopenharmony_ci 12258c2ecf20Sopenharmony_ci for (; j != (index - 1) % tid_agg_rx->buf_size; 12268c2ecf20Sopenharmony_ci j = (j + 1) % tid_agg_rx->buf_size) { 12278c2ecf20Sopenharmony_ci if (ieee80211_rx_reorder_ready(tid_agg_rx, j)) 12288c2ecf20Sopenharmony_ci break; 12298c2ecf20Sopenharmony_ci } 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_ci set_release_timer: 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_ci if (!tid_agg_rx->removed) 12348c2ecf20Sopenharmony_ci mod_timer(&tid_agg_rx->reorder_timer, 12358c2ecf20Sopenharmony_ci tid_agg_rx->reorder_time[j] + 1 + 12368c2ecf20Sopenharmony_ci HT_RX_REORDER_BUF_TIMEOUT); 12378c2ecf20Sopenharmony_ci } else { 12388c2ecf20Sopenharmony_ci del_timer(&tid_agg_rx->reorder_timer); 12398c2ecf20Sopenharmony_ci } 12408c2ecf20Sopenharmony_ci} 12418c2ecf20Sopenharmony_ci 12428c2ecf20Sopenharmony_ci/* 12438c2ecf20Sopenharmony_ci * As this function belongs to the RX path it must be under 12448c2ecf20Sopenharmony_ci * rcu_read_lock protection. It returns false if the frame 12458c2ecf20Sopenharmony_ci * can be processed immediately, true if it was consumed. 12468c2ecf20Sopenharmony_ci */ 12478c2ecf20Sopenharmony_cistatic bool ieee80211_sta_manage_reorder_buf(struct ieee80211_sub_if_data *sdata, 12488c2ecf20Sopenharmony_ci struct tid_ampdu_rx *tid_agg_rx, 12498c2ecf20Sopenharmony_ci struct sk_buff *skb, 12508c2ecf20Sopenharmony_ci struct sk_buff_head *frames) 12518c2ecf20Sopenharmony_ci{ 12528c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; 12538c2ecf20Sopenharmony_ci struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); 12548c2ecf20Sopenharmony_ci u16 sc = le16_to_cpu(hdr->seq_ctrl); 12558c2ecf20Sopenharmony_ci u16 mpdu_seq_num = (sc & IEEE80211_SCTL_SEQ) >> 4; 12568c2ecf20Sopenharmony_ci u16 head_seq_num, buf_size; 12578c2ecf20Sopenharmony_ci int index; 12588c2ecf20Sopenharmony_ci bool ret = true; 12598c2ecf20Sopenharmony_ci 12608c2ecf20Sopenharmony_ci spin_lock(&tid_agg_rx->reorder_lock); 12618c2ecf20Sopenharmony_ci 12628c2ecf20Sopenharmony_ci /* 12638c2ecf20Sopenharmony_ci * Offloaded BA sessions have no known starting sequence number so pick 12648c2ecf20Sopenharmony_ci * one from first Rxed frame for this tid after BA was started. 12658c2ecf20Sopenharmony_ci */ 12668c2ecf20Sopenharmony_ci if (unlikely(tid_agg_rx->auto_seq)) { 12678c2ecf20Sopenharmony_ci tid_agg_rx->auto_seq = false; 12688c2ecf20Sopenharmony_ci tid_agg_rx->ssn = mpdu_seq_num; 12698c2ecf20Sopenharmony_ci tid_agg_rx->head_seq_num = mpdu_seq_num; 12708c2ecf20Sopenharmony_ci } 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci buf_size = tid_agg_rx->buf_size; 12738c2ecf20Sopenharmony_ci head_seq_num = tid_agg_rx->head_seq_num; 12748c2ecf20Sopenharmony_ci 12758c2ecf20Sopenharmony_ci /* 12768c2ecf20Sopenharmony_ci * If the current MPDU's SN is smaller than the SSN, it shouldn't 12778c2ecf20Sopenharmony_ci * be reordered. 12788c2ecf20Sopenharmony_ci */ 12798c2ecf20Sopenharmony_ci if (unlikely(!tid_agg_rx->started)) { 12808c2ecf20Sopenharmony_ci if (ieee80211_sn_less(mpdu_seq_num, head_seq_num)) { 12818c2ecf20Sopenharmony_ci ret = false; 12828c2ecf20Sopenharmony_ci goto out; 12838c2ecf20Sopenharmony_ci } 12848c2ecf20Sopenharmony_ci tid_agg_rx->started = true; 12858c2ecf20Sopenharmony_ci } 12868c2ecf20Sopenharmony_ci 12878c2ecf20Sopenharmony_ci /* frame with out of date sequence number */ 12888c2ecf20Sopenharmony_ci if (ieee80211_sn_less(mpdu_seq_num, head_seq_num)) { 12898c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 12908c2ecf20Sopenharmony_ci goto out; 12918c2ecf20Sopenharmony_ci } 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_ci /* 12948c2ecf20Sopenharmony_ci * If frame the sequence number exceeds our buffering window 12958c2ecf20Sopenharmony_ci * size release some previous frames to make room for this one. 12968c2ecf20Sopenharmony_ci */ 12978c2ecf20Sopenharmony_ci if (!ieee80211_sn_less(mpdu_seq_num, head_seq_num + buf_size)) { 12988c2ecf20Sopenharmony_ci head_seq_num = ieee80211_sn_inc( 12998c2ecf20Sopenharmony_ci ieee80211_sn_sub(mpdu_seq_num, buf_size)); 13008c2ecf20Sopenharmony_ci /* release stored frames up to new head to stack */ 13018c2ecf20Sopenharmony_ci ieee80211_release_reorder_frames(sdata, tid_agg_rx, 13028c2ecf20Sopenharmony_ci head_seq_num, frames); 13038c2ecf20Sopenharmony_ci } 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_ci /* Now the new frame is always in the range of the reordering buffer */ 13068c2ecf20Sopenharmony_ci 13078c2ecf20Sopenharmony_ci index = mpdu_seq_num % tid_agg_rx->buf_size; 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_ci /* check if we already stored this frame */ 13108c2ecf20Sopenharmony_ci if (ieee80211_rx_reorder_ready(tid_agg_rx, index)) { 13118c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 13128c2ecf20Sopenharmony_ci goto out; 13138c2ecf20Sopenharmony_ci } 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_ci /* 13168c2ecf20Sopenharmony_ci * If the current MPDU is in the right order and nothing else 13178c2ecf20Sopenharmony_ci * is stored we can process it directly, no need to buffer it. 13188c2ecf20Sopenharmony_ci * If it is first but there's something stored, we may be able 13198c2ecf20Sopenharmony_ci * to release frames after this one. 13208c2ecf20Sopenharmony_ci */ 13218c2ecf20Sopenharmony_ci if (mpdu_seq_num == tid_agg_rx->head_seq_num && 13228c2ecf20Sopenharmony_ci tid_agg_rx->stored_mpdu_num == 0) { 13238c2ecf20Sopenharmony_ci if (!(status->flag & RX_FLAG_AMSDU_MORE)) 13248c2ecf20Sopenharmony_ci tid_agg_rx->head_seq_num = 13258c2ecf20Sopenharmony_ci ieee80211_sn_inc(tid_agg_rx->head_seq_num); 13268c2ecf20Sopenharmony_ci ret = false; 13278c2ecf20Sopenharmony_ci goto out; 13288c2ecf20Sopenharmony_ci } 13298c2ecf20Sopenharmony_ci 13308c2ecf20Sopenharmony_ci /* put the frame in the reordering buffer */ 13318c2ecf20Sopenharmony_ci __skb_queue_tail(&tid_agg_rx->reorder_buf[index], skb); 13328c2ecf20Sopenharmony_ci if (!(status->flag & RX_FLAG_AMSDU_MORE)) { 13338c2ecf20Sopenharmony_ci tid_agg_rx->reorder_time[index] = jiffies; 13348c2ecf20Sopenharmony_ci tid_agg_rx->stored_mpdu_num++; 13358c2ecf20Sopenharmony_ci ieee80211_sta_reorder_release(sdata, tid_agg_rx, frames); 13368c2ecf20Sopenharmony_ci } 13378c2ecf20Sopenharmony_ci 13388c2ecf20Sopenharmony_ci out: 13398c2ecf20Sopenharmony_ci spin_unlock(&tid_agg_rx->reorder_lock); 13408c2ecf20Sopenharmony_ci return ret; 13418c2ecf20Sopenharmony_ci} 13428c2ecf20Sopenharmony_ci 13438c2ecf20Sopenharmony_ci/* 13448c2ecf20Sopenharmony_ci * Reorder MPDUs from A-MPDUs, keeping them on a buffer. Returns 13458c2ecf20Sopenharmony_ci * true if the MPDU was buffered, false if it should be processed. 13468c2ecf20Sopenharmony_ci */ 13478c2ecf20Sopenharmony_cistatic void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx, 13488c2ecf20Sopenharmony_ci struct sk_buff_head *frames) 13498c2ecf20Sopenharmony_ci{ 13508c2ecf20Sopenharmony_ci struct sk_buff *skb = rx->skb; 13518c2ecf20Sopenharmony_ci struct ieee80211_local *local = rx->local; 13528c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; 13538c2ecf20Sopenharmony_ci struct sta_info *sta = rx->sta; 13548c2ecf20Sopenharmony_ci struct tid_ampdu_rx *tid_agg_rx; 13558c2ecf20Sopenharmony_ci u16 sc; 13568c2ecf20Sopenharmony_ci u8 tid, ack_policy; 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_ci if (!ieee80211_is_data_qos(hdr->frame_control) || 13598c2ecf20Sopenharmony_ci is_multicast_ether_addr(hdr->addr1)) 13608c2ecf20Sopenharmony_ci goto dont_reorder; 13618c2ecf20Sopenharmony_ci 13628c2ecf20Sopenharmony_ci /* 13638c2ecf20Sopenharmony_ci * filter the QoS data rx stream according to 13648c2ecf20Sopenharmony_ci * STA/TID and check if this STA/TID is on aggregation 13658c2ecf20Sopenharmony_ci */ 13668c2ecf20Sopenharmony_ci 13678c2ecf20Sopenharmony_ci if (!sta) 13688c2ecf20Sopenharmony_ci goto dont_reorder; 13698c2ecf20Sopenharmony_ci 13708c2ecf20Sopenharmony_ci ack_policy = *ieee80211_get_qos_ctl(hdr) & 13718c2ecf20Sopenharmony_ci IEEE80211_QOS_CTL_ACK_POLICY_MASK; 13728c2ecf20Sopenharmony_ci tid = ieee80211_get_tid(hdr); 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_ci tid_agg_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[tid]); 13758c2ecf20Sopenharmony_ci if (!tid_agg_rx) { 13768c2ecf20Sopenharmony_ci if (ack_policy == IEEE80211_QOS_CTL_ACK_POLICY_BLOCKACK && 13778c2ecf20Sopenharmony_ci !test_bit(tid, rx->sta->ampdu_mlme.agg_session_valid) && 13788c2ecf20Sopenharmony_ci !test_and_set_bit(tid, rx->sta->ampdu_mlme.unexpected_agg)) 13798c2ecf20Sopenharmony_ci ieee80211_send_delba(rx->sdata, rx->sta->sta.addr, tid, 13808c2ecf20Sopenharmony_ci WLAN_BACK_RECIPIENT, 13818c2ecf20Sopenharmony_ci WLAN_REASON_QSTA_REQUIRE_SETUP); 13828c2ecf20Sopenharmony_ci goto dont_reorder; 13838c2ecf20Sopenharmony_ci } 13848c2ecf20Sopenharmony_ci 13858c2ecf20Sopenharmony_ci /* qos null data frames are excluded */ 13868c2ecf20Sopenharmony_ci if (unlikely(hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_NULLFUNC))) 13878c2ecf20Sopenharmony_ci goto dont_reorder; 13888c2ecf20Sopenharmony_ci 13898c2ecf20Sopenharmony_ci /* not part of a BA session */ 13908c2ecf20Sopenharmony_ci if (ack_policy == IEEE80211_QOS_CTL_ACK_POLICY_NOACK) 13918c2ecf20Sopenharmony_ci goto dont_reorder; 13928c2ecf20Sopenharmony_ci 13938c2ecf20Sopenharmony_ci /* new, potentially un-ordered, ampdu frame - process it */ 13948c2ecf20Sopenharmony_ci 13958c2ecf20Sopenharmony_ci /* reset session timer */ 13968c2ecf20Sopenharmony_ci if (tid_agg_rx->timeout) 13978c2ecf20Sopenharmony_ci tid_agg_rx->last_rx = jiffies; 13988c2ecf20Sopenharmony_ci 13998c2ecf20Sopenharmony_ci /* if this mpdu is fragmented - terminate rx aggregation session */ 14008c2ecf20Sopenharmony_ci sc = le16_to_cpu(hdr->seq_ctrl); 14018c2ecf20Sopenharmony_ci if (sc & IEEE80211_SCTL_FRAG) { 14028c2ecf20Sopenharmony_ci skb_queue_tail(&rx->sdata->skb_queue, skb); 14038c2ecf20Sopenharmony_ci ieee80211_queue_work(&local->hw, &rx->sdata->work); 14048c2ecf20Sopenharmony_ci return; 14058c2ecf20Sopenharmony_ci } 14068c2ecf20Sopenharmony_ci 14078c2ecf20Sopenharmony_ci /* 14088c2ecf20Sopenharmony_ci * No locking needed -- we will only ever process one 14098c2ecf20Sopenharmony_ci * RX packet at a time, and thus own tid_agg_rx. All 14108c2ecf20Sopenharmony_ci * other code manipulating it needs to (and does) make 14118c2ecf20Sopenharmony_ci * sure that we cannot get to it any more before doing 14128c2ecf20Sopenharmony_ci * anything with it. 14138c2ecf20Sopenharmony_ci */ 14148c2ecf20Sopenharmony_ci if (ieee80211_sta_manage_reorder_buf(rx->sdata, tid_agg_rx, skb, 14158c2ecf20Sopenharmony_ci frames)) 14168c2ecf20Sopenharmony_ci return; 14178c2ecf20Sopenharmony_ci 14188c2ecf20Sopenharmony_ci dont_reorder: 14198c2ecf20Sopenharmony_ci __skb_queue_tail(frames, skb); 14208c2ecf20Sopenharmony_ci} 14218c2ecf20Sopenharmony_ci 14228c2ecf20Sopenharmony_cistatic ieee80211_rx_result debug_noinline 14238c2ecf20Sopenharmony_ciieee80211_rx_h_check_dup(struct ieee80211_rx_data *rx) 14248c2ecf20Sopenharmony_ci{ 14258c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; 14268c2ecf20Sopenharmony_ci struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); 14278c2ecf20Sopenharmony_ci 14288c2ecf20Sopenharmony_ci if (status->flag & RX_FLAG_DUP_VALIDATED) 14298c2ecf20Sopenharmony_ci return RX_CONTINUE; 14308c2ecf20Sopenharmony_ci 14318c2ecf20Sopenharmony_ci /* 14328c2ecf20Sopenharmony_ci * Drop duplicate 802.11 retransmissions 14338c2ecf20Sopenharmony_ci * (IEEE 802.11-2012: 9.3.2.10 "Duplicate detection and recovery") 14348c2ecf20Sopenharmony_ci */ 14358c2ecf20Sopenharmony_ci 14368c2ecf20Sopenharmony_ci if (rx->skb->len < 24) 14378c2ecf20Sopenharmony_ci return RX_CONTINUE; 14388c2ecf20Sopenharmony_ci 14398c2ecf20Sopenharmony_ci if (ieee80211_is_ctl(hdr->frame_control) || 14408c2ecf20Sopenharmony_ci ieee80211_is_any_nullfunc(hdr->frame_control) || 14418c2ecf20Sopenharmony_ci is_multicast_ether_addr(hdr->addr1)) 14428c2ecf20Sopenharmony_ci return RX_CONTINUE; 14438c2ecf20Sopenharmony_ci 14448c2ecf20Sopenharmony_ci if (!rx->sta) 14458c2ecf20Sopenharmony_ci return RX_CONTINUE; 14468c2ecf20Sopenharmony_ci 14478c2ecf20Sopenharmony_ci if (unlikely(ieee80211_has_retry(hdr->frame_control) && 14488c2ecf20Sopenharmony_ci rx->sta->last_seq_ctrl[rx->seqno_idx] == hdr->seq_ctrl)) { 14498c2ecf20Sopenharmony_ci I802_DEBUG_INC(rx->local->dot11FrameDuplicateCount); 14508c2ecf20Sopenharmony_ci rx->sta->rx_stats.num_duplicates++; 14518c2ecf20Sopenharmony_ci return RX_DROP_UNUSABLE; 14528c2ecf20Sopenharmony_ci } else if (!(status->flag & RX_FLAG_AMSDU_MORE)) { 14538c2ecf20Sopenharmony_ci rx->sta->last_seq_ctrl[rx->seqno_idx] = hdr->seq_ctrl; 14548c2ecf20Sopenharmony_ci } 14558c2ecf20Sopenharmony_ci 14568c2ecf20Sopenharmony_ci return RX_CONTINUE; 14578c2ecf20Sopenharmony_ci} 14588c2ecf20Sopenharmony_ci 14598c2ecf20Sopenharmony_cistatic ieee80211_rx_result debug_noinline 14608c2ecf20Sopenharmony_ciieee80211_rx_h_check(struct ieee80211_rx_data *rx) 14618c2ecf20Sopenharmony_ci{ 14628c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; 14638c2ecf20Sopenharmony_ci 14648c2ecf20Sopenharmony_ci /* Drop disallowed frame classes based on STA auth/assoc state; 14658c2ecf20Sopenharmony_ci * IEEE 802.11, Chap 5.5. 14668c2ecf20Sopenharmony_ci * 14678c2ecf20Sopenharmony_ci * mac80211 filters only based on association state, i.e. it drops 14688c2ecf20Sopenharmony_ci * Class 3 frames from not associated stations. hostapd sends 14698c2ecf20Sopenharmony_ci * deauth/disassoc frames when needed. In addition, hostapd is 14708c2ecf20Sopenharmony_ci * responsible for filtering on both auth and assoc states. 14718c2ecf20Sopenharmony_ci */ 14728c2ecf20Sopenharmony_ci 14738c2ecf20Sopenharmony_ci if (ieee80211_vif_is_mesh(&rx->sdata->vif)) 14748c2ecf20Sopenharmony_ci return ieee80211_rx_mesh_check(rx); 14758c2ecf20Sopenharmony_ci 14768c2ecf20Sopenharmony_ci if (unlikely((ieee80211_is_data(hdr->frame_control) || 14778c2ecf20Sopenharmony_ci ieee80211_is_pspoll(hdr->frame_control)) && 14788c2ecf20Sopenharmony_ci rx->sdata->vif.type != NL80211_IFTYPE_ADHOC && 14798c2ecf20Sopenharmony_ci rx->sdata->vif.type != NL80211_IFTYPE_WDS && 14808c2ecf20Sopenharmony_ci rx->sdata->vif.type != NL80211_IFTYPE_OCB && 14818c2ecf20Sopenharmony_ci (!rx->sta || !test_sta_flag(rx->sta, WLAN_STA_ASSOC)))) { 14828c2ecf20Sopenharmony_ci /* 14838c2ecf20Sopenharmony_ci * accept port control frames from the AP even when it's not 14848c2ecf20Sopenharmony_ci * yet marked ASSOC to prevent a race where we don't set the 14858c2ecf20Sopenharmony_ci * assoc bit quickly enough before it sends the first frame 14868c2ecf20Sopenharmony_ci */ 14878c2ecf20Sopenharmony_ci if (rx->sta && rx->sdata->vif.type == NL80211_IFTYPE_STATION && 14888c2ecf20Sopenharmony_ci ieee80211_is_data_present(hdr->frame_control)) { 14898c2ecf20Sopenharmony_ci unsigned int hdrlen; 14908c2ecf20Sopenharmony_ci __be16 ethertype; 14918c2ecf20Sopenharmony_ci 14928c2ecf20Sopenharmony_ci hdrlen = ieee80211_hdrlen(hdr->frame_control); 14938c2ecf20Sopenharmony_ci 14948c2ecf20Sopenharmony_ci if (rx->skb->len < hdrlen + 8) 14958c2ecf20Sopenharmony_ci return RX_DROP_MONITOR; 14968c2ecf20Sopenharmony_ci 14978c2ecf20Sopenharmony_ci skb_copy_bits(rx->skb, hdrlen + 6, ðertype, 2); 14988c2ecf20Sopenharmony_ci if (ethertype == rx->sdata->control_port_protocol) 14998c2ecf20Sopenharmony_ci return RX_CONTINUE; 15008c2ecf20Sopenharmony_ci } 15018c2ecf20Sopenharmony_ci 15028c2ecf20Sopenharmony_ci if (rx->sdata->vif.type == NL80211_IFTYPE_AP && 15038c2ecf20Sopenharmony_ci cfg80211_rx_spurious_frame(rx->sdata->dev, 15048c2ecf20Sopenharmony_ci hdr->addr2, 15058c2ecf20Sopenharmony_ci GFP_ATOMIC)) 15068c2ecf20Sopenharmony_ci return RX_DROP_UNUSABLE; 15078c2ecf20Sopenharmony_ci 15088c2ecf20Sopenharmony_ci return RX_DROP_MONITOR; 15098c2ecf20Sopenharmony_ci } 15108c2ecf20Sopenharmony_ci 15118c2ecf20Sopenharmony_ci return RX_CONTINUE; 15128c2ecf20Sopenharmony_ci} 15138c2ecf20Sopenharmony_ci 15148c2ecf20Sopenharmony_ci 15158c2ecf20Sopenharmony_cistatic ieee80211_rx_result debug_noinline 15168c2ecf20Sopenharmony_ciieee80211_rx_h_check_more_data(struct ieee80211_rx_data *rx) 15178c2ecf20Sopenharmony_ci{ 15188c2ecf20Sopenharmony_ci struct ieee80211_local *local; 15198c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr; 15208c2ecf20Sopenharmony_ci struct sk_buff *skb; 15218c2ecf20Sopenharmony_ci 15228c2ecf20Sopenharmony_ci local = rx->local; 15238c2ecf20Sopenharmony_ci skb = rx->skb; 15248c2ecf20Sopenharmony_ci hdr = (struct ieee80211_hdr *) skb->data; 15258c2ecf20Sopenharmony_ci 15268c2ecf20Sopenharmony_ci if (!local->pspolling) 15278c2ecf20Sopenharmony_ci return RX_CONTINUE; 15288c2ecf20Sopenharmony_ci 15298c2ecf20Sopenharmony_ci if (!ieee80211_has_fromds(hdr->frame_control)) 15308c2ecf20Sopenharmony_ci /* this is not from AP */ 15318c2ecf20Sopenharmony_ci return RX_CONTINUE; 15328c2ecf20Sopenharmony_ci 15338c2ecf20Sopenharmony_ci if (!ieee80211_is_data(hdr->frame_control)) 15348c2ecf20Sopenharmony_ci return RX_CONTINUE; 15358c2ecf20Sopenharmony_ci 15368c2ecf20Sopenharmony_ci if (!ieee80211_has_moredata(hdr->frame_control)) { 15378c2ecf20Sopenharmony_ci /* AP has no more frames buffered for us */ 15388c2ecf20Sopenharmony_ci local->pspolling = false; 15398c2ecf20Sopenharmony_ci return RX_CONTINUE; 15408c2ecf20Sopenharmony_ci } 15418c2ecf20Sopenharmony_ci 15428c2ecf20Sopenharmony_ci /* more data bit is set, let's request a new frame from the AP */ 15438c2ecf20Sopenharmony_ci ieee80211_send_pspoll(local, rx->sdata); 15448c2ecf20Sopenharmony_ci 15458c2ecf20Sopenharmony_ci return RX_CONTINUE; 15468c2ecf20Sopenharmony_ci} 15478c2ecf20Sopenharmony_ci 15488c2ecf20Sopenharmony_cistatic void sta_ps_start(struct sta_info *sta) 15498c2ecf20Sopenharmony_ci{ 15508c2ecf20Sopenharmony_ci struct ieee80211_sub_if_data *sdata = sta->sdata; 15518c2ecf20Sopenharmony_ci struct ieee80211_local *local = sdata->local; 15528c2ecf20Sopenharmony_ci struct ps_data *ps; 15538c2ecf20Sopenharmony_ci int tid; 15548c2ecf20Sopenharmony_ci 15558c2ecf20Sopenharmony_ci if (sta->sdata->vif.type == NL80211_IFTYPE_AP || 15568c2ecf20Sopenharmony_ci sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN) 15578c2ecf20Sopenharmony_ci ps = &sdata->bss->ps; 15588c2ecf20Sopenharmony_ci else 15598c2ecf20Sopenharmony_ci return; 15608c2ecf20Sopenharmony_ci 15618c2ecf20Sopenharmony_ci atomic_inc(&ps->num_sta_ps); 15628c2ecf20Sopenharmony_ci set_sta_flag(sta, WLAN_STA_PS_STA); 15638c2ecf20Sopenharmony_ci if (!ieee80211_hw_check(&local->hw, AP_LINK_PS)) 15648c2ecf20Sopenharmony_ci drv_sta_notify(local, sdata, STA_NOTIFY_SLEEP, &sta->sta); 15658c2ecf20Sopenharmony_ci ps_dbg(sdata, "STA %pM aid %d enters power save mode\n", 15668c2ecf20Sopenharmony_ci sta->sta.addr, sta->sta.aid); 15678c2ecf20Sopenharmony_ci 15688c2ecf20Sopenharmony_ci ieee80211_clear_fast_xmit(sta); 15698c2ecf20Sopenharmony_ci 15708c2ecf20Sopenharmony_ci if (!sta->sta.txq[0]) 15718c2ecf20Sopenharmony_ci return; 15728c2ecf20Sopenharmony_ci 15738c2ecf20Sopenharmony_ci for (tid = 0; tid < IEEE80211_NUM_TIDS; tid++) { 15748c2ecf20Sopenharmony_ci struct ieee80211_txq *txq = sta->sta.txq[tid]; 15758c2ecf20Sopenharmony_ci struct txq_info *txqi = to_txq_info(txq); 15768c2ecf20Sopenharmony_ci 15778c2ecf20Sopenharmony_ci spin_lock(&local->active_txq_lock[txq->ac]); 15788c2ecf20Sopenharmony_ci if (!list_empty(&txqi->schedule_order)) 15798c2ecf20Sopenharmony_ci list_del_init(&txqi->schedule_order); 15808c2ecf20Sopenharmony_ci spin_unlock(&local->active_txq_lock[txq->ac]); 15818c2ecf20Sopenharmony_ci 15828c2ecf20Sopenharmony_ci if (txq_has_queue(txq)) 15838c2ecf20Sopenharmony_ci set_bit(tid, &sta->txq_buffered_tids); 15848c2ecf20Sopenharmony_ci else 15858c2ecf20Sopenharmony_ci clear_bit(tid, &sta->txq_buffered_tids); 15868c2ecf20Sopenharmony_ci } 15878c2ecf20Sopenharmony_ci} 15888c2ecf20Sopenharmony_ci 15898c2ecf20Sopenharmony_cistatic void sta_ps_end(struct sta_info *sta) 15908c2ecf20Sopenharmony_ci{ 15918c2ecf20Sopenharmony_ci ps_dbg(sta->sdata, "STA %pM aid %d exits power save mode\n", 15928c2ecf20Sopenharmony_ci sta->sta.addr, sta->sta.aid); 15938c2ecf20Sopenharmony_ci 15948c2ecf20Sopenharmony_ci if (test_sta_flag(sta, WLAN_STA_PS_DRIVER)) { 15958c2ecf20Sopenharmony_ci /* 15968c2ecf20Sopenharmony_ci * Clear the flag only if the other one is still set 15978c2ecf20Sopenharmony_ci * so that the TX path won't start TX'ing new frames 15988c2ecf20Sopenharmony_ci * directly ... In the case that the driver flag isn't 15998c2ecf20Sopenharmony_ci * set ieee80211_sta_ps_deliver_wakeup() will clear it. 16008c2ecf20Sopenharmony_ci */ 16018c2ecf20Sopenharmony_ci clear_sta_flag(sta, WLAN_STA_PS_STA); 16028c2ecf20Sopenharmony_ci ps_dbg(sta->sdata, "STA %pM aid %d driver-ps-blocked\n", 16038c2ecf20Sopenharmony_ci sta->sta.addr, sta->sta.aid); 16048c2ecf20Sopenharmony_ci return; 16058c2ecf20Sopenharmony_ci } 16068c2ecf20Sopenharmony_ci 16078c2ecf20Sopenharmony_ci set_sta_flag(sta, WLAN_STA_PS_DELIVER); 16088c2ecf20Sopenharmony_ci clear_sta_flag(sta, WLAN_STA_PS_STA); 16098c2ecf20Sopenharmony_ci ieee80211_sta_ps_deliver_wakeup(sta); 16108c2ecf20Sopenharmony_ci} 16118c2ecf20Sopenharmony_ci 16128c2ecf20Sopenharmony_ciint ieee80211_sta_ps_transition(struct ieee80211_sta *pubsta, bool start) 16138c2ecf20Sopenharmony_ci{ 16148c2ecf20Sopenharmony_ci struct sta_info *sta = container_of(pubsta, struct sta_info, sta); 16158c2ecf20Sopenharmony_ci bool in_ps; 16168c2ecf20Sopenharmony_ci 16178c2ecf20Sopenharmony_ci WARN_ON(!ieee80211_hw_check(&sta->local->hw, AP_LINK_PS)); 16188c2ecf20Sopenharmony_ci 16198c2ecf20Sopenharmony_ci /* Don't let the same PS state be set twice */ 16208c2ecf20Sopenharmony_ci in_ps = test_sta_flag(sta, WLAN_STA_PS_STA); 16218c2ecf20Sopenharmony_ci if ((start && in_ps) || (!start && !in_ps)) 16228c2ecf20Sopenharmony_ci return -EINVAL; 16238c2ecf20Sopenharmony_ci 16248c2ecf20Sopenharmony_ci if (start) 16258c2ecf20Sopenharmony_ci sta_ps_start(sta); 16268c2ecf20Sopenharmony_ci else 16278c2ecf20Sopenharmony_ci sta_ps_end(sta); 16288c2ecf20Sopenharmony_ci 16298c2ecf20Sopenharmony_ci return 0; 16308c2ecf20Sopenharmony_ci} 16318c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ieee80211_sta_ps_transition); 16328c2ecf20Sopenharmony_ci 16338c2ecf20Sopenharmony_civoid ieee80211_sta_pspoll(struct ieee80211_sta *pubsta) 16348c2ecf20Sopenharmony_ci{ 16358c2ecf20Sopenharmony_ci struct sta_info *sta = container_of(pubsta, struct sta_info, sta); 16368c2ecf20Sopenharmony_ci 16378c2ecf20Sopenharmony_ci if (test_sta_flag(sta, WLAN_STA_SP)) 16388c2ecf20Sopenharmony_ci return; 16398c2ecf20Sopenharmony_ci 16408c2ecf20Sopenharmony_ci if (!test_sta_flag(sta, WLAN_STA_PS_DRIVER)) 16418c2ecf20Sopenharmony_ci ieee80211_sta_ps_deliver_poll_response(sta); 16428c2ecf20Sopenharmony_ci else 16438c2ecf20Sopenharmony_ci set_sta_flag(sta, WLAN_STA_PSPOLL); 16448c2ecf20Sopenharmony_ci} 16458c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ieee80211_sta_pspoll); 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_civoid ieee80211_sta_uapsd_trigger(struct ieee80211_sta *pubsta, u8 tid) 16488c2ecf20Sopenharmony_ci{ 16498c2ecf20Sopenharmony_ci struct sta_info *sta = container_of(pubsta, struct sta_info, sta); 16508c2ecf20Sopenharmony_ci int ac = ieee80211_ac_from_tid(tid); 16518c2ecf20Sopenharmony_ci 16528c2ecf20Sopenharmony_ci /* 16538c2ecf20Sopenharmony_ci * If this AC is not trigger-enabled do nothing unless the 16548c2ecf20Sopenharmony_ci * driver is calling us after it already checked. 16558c2ecf20Sopenharmony_ci * 16568c2ecf20Sopenharmony_ci * NB: This could/should check a separate bitmap of trigger- 16578c2ecf20Sopenharmony_ci * enabled queues, but for now we only implement uAPSD w/o 16588c2ecf20Sopenharmony_ci * TSPEC changes to the ACs, so they're always the same. 16598c2ecf20Sopenharmony_ci */ 16608c2ecf20Sopenharmony_ci if (!(sta->sta.uapsd_queues & ieee80211_ac_to_qos_mask[ac]) && 16618c2ecf20Sopenharmony_ci tid != IEEE80211_NUM_TIDS) 16628c2ecf20Sopenharmony_ci return; 16638c2ecf20Sopenharmony_ci 16648c2ecf20Sopenharmony_ci /* if we are in a service period, do nothing */ 16658c2ecf20Sopenharmony_ci if (test_sta_flag(sta, WLAN_STA_SP)) 16668c2ecf20Sopenharmony_ci return; 16678c2ecf20Sopenharmony_ci 16688c2ecf20Sopenharmony_ci if (!test_sta_flag(sta, WLAN_STA_PS_DRIVER)) 16698c2ecf20Sopenharmony_ci ieee80211_sta_ps_deliver_uapsd(sta); 16708c2ecf20Sopenharmony_ci else 16718c2ecf20Sopenharmony_ci set_sta_flag(sta, WLAN_STA_UAPSD); 16728c2ecf20Sopenharmony_ci} 16738c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ieee80211_sta_uapsd_trigger); 16748c2ecf20Sopenharmony_ci 16758c2ecf20Sopenharmony_cistatic ieee80211_rx_result debug_noinline 16768c2ecf20Sopenharmony_ciieee80211_rx_h_uapsd_and_pspoll(struct ieee80211_rx_data *rx) 16778c2ecf20Sopenharmony_ci{ 16788c2ecf20Sopenharmony_ci struct ieee80211_sub_if_data *sdata = rx->sdata; 16798c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr = (void *)rx->skb->data; 16808c2ecf20Sopenharmony_ci struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); 16818c2ecf20Sopenharmony_ci 16828c2ecf20Sopenharmony_ci if (!rx->sta) 16838c2ecf20Sopenharmony_ci return RX_CONTINUE; 16848c2ecf20Sopenharmony_ci 16858c2ecf20Sopenharmony_ci if (sdata->vif.type != NL80211_IFTYPE_AP && 16868c2ecf20Sopenharmony_ci sdata->vif.type != NL80211_IFTYPE_AP_VLAN) 16878c2ecf20Sopenharmony_ci return RX_CONTINUE; 16888c2ecf20Sopenharmony_ci 16898c2ecf20Sopenharmony_ci /* 16908c2ecf20Sopenharmony_ci * The device handles station powersave, so don't do anything about 16918c2ecf20Sopenharmony_ci * uAPSD and PS-Poll frames (the latter shouldn't even come up from 16928c2ecf20Sopenharmony_ci * it to mac80211 since they're handled.) 16938c2ecf20Sopenharmony_ci */ 16948c2ecf20Sopenharmony_ci if (ieee80211_hw_check(&sdata->local->hw, AP_LINK_PS)) 16958c2ecf20Sopenharmony_ci return RX_CONTINUE; 16968c2ecf20Sopenharmony_ci 16978c2ecf20Sopenharmony_ci /* 16988c2ecf20Sopenharmony_ci * Don't do anything if the station isn't already asleep. In 16998c2ecf20Sopenharmony_ci * the uAPSD case, the station will probably be marked asleep, 17008c2ecf20Sopenharmony_ci * in the PS-Poll case the station must be confused ... 17018c2ecf20Sopenharmony_ci */ 17028c2ecf20Sopenharmony_ci if (!test_sta_flag(rx->sta, WLAN_STA_PS_STA)) 17038c2ecf20Sopenharmony_ci return RX_CONTINUE; 17048c2ecf20Sopenharmony_ci 17058c2ecf20Sopenharmony_ci if (unlikely(ieee80211_is_pspoll(hdr->frame_control))) { 17068c2ecf20Sopenharmony_ci ieee80211_sta_pspoll(&rx->sta->sta); 17078c2ecf20Sopenharmony_ci 17088c2ecf20Sopenharmony_ci /* Free PS Poll skb here instead of returning RX_DROP that would 17098c2ecf20Sopenharmony_ci * count as an dropped frame. */ 17108c2ecf20Sopenharmony_ci dev_kfree_skb(rx->skb); 17118c2ecf20Sopenharmony_ci 17128c2ecf20Sopenharmony_ci return RX_QUEUED; 17138c2ecf20Sopenharmony_ci } else if (!ieee80211_has_morefrags(hdr->frame_control) && 17148c2ecf20Sopenharmony_ci !(status->rx_flags & IEEE80211_RX_DEFERRED_RELEASE) && 17158c2ecf20Sopenharmony_ci ieee80211_has_pm(hdr->frame_control) && 17168c2ecf20Sopenharmony_ci (ieee80211_is_data_qos(hdr->frame_control) || 17178c2ecf20Sopenharmony_ci ieee80211_is_qos_nullfunc(hdr->frame_control))) { 17188c2ecf20Sopenharmony_ci u8 tid = ieee80211_get_tid(hdr); 17198c2ecf20Sopenharmony_ci 17208c2ecf20Sopenharmony_ci ieee80211_sta_uapsd_trigger(&rx->sta->sta, tid); 17218c2ecf20Sopenharmony_ci } 17228c2ecf20Sopenharmony_ci 17238c2ecf20Sopenharmony_ci return RX_CONTINUE; 17248c2ecf20Sopenharmony_ci} 17258c2ecf20Sopenharmony_ci 17268c2ecf20Sopenharmony_cistatic ieee80211_rx_result debug_noinline 17278c2ecf20Sopenharmony_ciieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) 17288c2ecf20Sopenharmony_ci{ 17298c2ecf20Sopenharmony_ci struct sta_info *sta = rx->sta; 17308c2ecf20Sopenharmony_ci struct sk_buff *skb = rx->skb; 17318c2ecf20Sopenharmony_ci struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); 17328c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; 17338c2ecf20Sopenharmony_ci int i; 17348c2ecf20Sopenharmony_ci 17358c2ecf20Sopenharmony_ci if (!sta) 17368c2ecf20Sopenharmony_ci return RX_CONTINUE; 17378c2ecf20Sopenharmony_ci 17388c2ecf20Sopenharmony_ci /* 17398c2ecf20Sopenharmony_ci * Update last_rx only for IBSS packets which are for the current 17408c2ecf20Sopenharmony_ci * BSSID and for station already AUTHORIZED to avoid keeping the 17418c2ecf20Sopenharmony_ci * current IBSS network alive in cases where other STAs start 17428c2ecf20Sopenharmony_ci * using different BSSID. This will also give the station another 17438c2ecf20Sopenharmony_ci * chance to restart the authentication/authorization in case 17448c2ecf20Sopenharmony_ci * something went wrong the first time. 17458c2ecf20Sopenharmony_ci */ 17468c2ecf20Sopenharmony_ci if (rx->sdata->vif.type == NL80211_IFTYPE_ADHOC) { 17478c2ecf20Sopenharmony_ci u8 *bssid = ieee80211_get_bssid(hdr, rx->skb->len, 17488c2ecf20Sopenharmony_ci NL80211_IFTYPE_ADHOC); 17498c2ecf20Sopenharmony_ci if (ether_addr_equal(bssid, rx->sdata->u.ibss.bssid) && 17508c2ecf20Sopenharmony_ci test_sta_flag(sta, WLAN_STA_AUTHORIZED)) { 17518c2ecf20Sopenharmony_ci sta->rx_stats.last_rx = jiffies; 17528c2ecf20Sopenharmony_ci if (ieee80211_is_data(hdr->frame_control) && 17538c2ecf20Sopenharmony_ci !is_multicast_ether_addr(hdr->addr1)) 17548c2ecf20Sopenharmony_ci sta->rx_stats.last_rate = 17558c2ecf20Sopenharmony_ci sta_stats_encode_rate(status); 17568c2ecf20Sopenharmony_ci } 17578c2ecf20Sopenharmony_ci } else if (rx->sdata->vif.type == NL80211_IFTYPE_OCB) { 17588c2ecf20Sopenharmony_ci sta->rx_stats.last_rx = jiffies; 17598c2ecf20Sopenharmony_ci } else if (!ieee80211_is_s1g_beacon(hdr->frame_control) && 17608c2ecf20Sopenharmony_ci !is_multicast_ether_addr(hdr->addr1)) { 17618c2ecf20Sopenharmony_ci /* 17628c2ecf20Sopenharmony_ci * Mesh beacons will update last_rx when if they are found to 17638c2ecf20Sopenharmony_ci * match the current local configuration when processed. 17648c2ecf20Sopenharmony_ci */ 17658c2ecf20Sopenharmony_ci sta->rx_stats.last_rx = jiffies; 17668c2ecf20Sopenharmony_ci if (ieee80211_is_data(hdr->frame_control)) 17678c2ecf20Sopenharmony_ci sta->rx_stats.last_rate = sta_stats_encode_rate(status); 17688c2ecf20Sopenharmony_ci } 17698c2ecf20Sopenharmony_ci 17708c2ecf20Sopenharmony_ci sta->rx_stats.fragments++; 17718c2ecf20Sopenharmony_ci 17728c2ecf20Sopenharmony_ci u64_stats_update_begin(&rx->sta->rx_stats.syncp); 17738c2ecf20Sopenharmony_ci sta->rx_stats.bytes += rx->skb->len; 17748c2ecf20Sopenharmony_ci u64_stats_update_end(&rx->sta->rx_stats.syncp); 17758c2ecf20Sopenharmony_ci 17768c2ecf20Sopenharmony_ci if (!(status->flag & RX_FLAG_NO_SIGNAL_VAL)) { 17778c2ecf20Sopenharmony_ci sta->rx_stats.last_signal = status->signal; 17788c2ecf20Sopenharmony_ci ewma_signal_add(&sta->rx_stats_avg.signal, -status->signal); 17798c2ecf20Sopenharmony_ci } 17808c2ecf20Sopenharmony_ci 17818c2ecf20Sopenharmony_ci if (status->chains) { 17828c2ecf20Sopenharmony_ci sta->rx_stats.chains = status->chains; 17838c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(status->chain_signal); i++) { 17848c2ecf20Sopenharmony_ci int signal = status->chain_signal[i]; 17858c2ecf20Sopenharmony_ci 17868c2ecf20Sopenharmony_ci if (!(status->chains & BIT(i))) 17878c2ecf20Sopenharmony_ci continue; 17888c2ecf20Sopenharmony_ci 17898c2ecf20Sopenharmony_ci sta->rx_stats.chain_signal_last[i] = signal; 17908c2ecf20Sopenharmony_ci ewma_signal_add(&sta->rx_stats_avg.chain_signal[i], 17918c2ecf20Sopenharmony_ci -signal); 17928c2ecf20Sopenharmony_ci } 17938c2ecf20Sopenharmony_ci } 17948c2ecf20Sopenharmony_ci 17958c2ecf20Sopenharmony_ci if (ieee80211_is_s1g_beacon(hdr->frame_control)) 17968c2ecf20Sopenharmony_ci return RX_CONTINUE; 17978c2ecf20Sopenharmony_ci 17988c2ecf20Sopenharmony_ci /* 17998c2ecf20Sopenharmony_ci * Change STA power saving mode only at the end of a frame 18008c2ecf20Sopenharmony_ci * exchange sequence, and only for a data or management 18018c2ecf20Sopenharmony_ci * frame as specified in IEEE 802.11-2016 11.2.3.2 18028c2ecf20Sopenharmony_ci */ 18038c2ecf20Sopenharmony_ci if (!ieee80211_hw_check(&sta->local->hw, AP_LINK_PS) && 18048c2ecf20Sopenharmony_ci !ieee80211_has_morefrags(hdr->frame_control) && 18058c2ecf20Sopenharmony_ci !is_multicast_ether_addr(hdr->addr1) && 18068c2ecf20Sopenharmony_ci (ieee80211_is_mgmt(hdr->frame_control) || 18078c2ecf20Sopenharmony_ci ieee80211_is_data(hdr->frame_control)) && 18088c2ecf20Sopenharmony_ci !(status->rx_flags & IEEE80211_RX_DEFERRED_RELEASE) && 18098c2ecf20Sopenharmony_ci (rx->sdata->vif.type == NL80211_IFTYPE_AP || 18108c2ecf20Sopenharmony_ci rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)) { 18118c2ecf20Sopenharmony_ci if (test_sta_flag(sta, WLAN_STA_PS_STA)) { 18128c2ecf20Sopenharmony_ci if (!ieee80211_has_pm(hdr->frame_control)) 18138c2ecf20Sopenharmony_ci sta_ps_end(sta); 18148c2ecf20Sopenharmony_ci } else { 18158c2ecf20Sopenharmony_ci if (ieee80211_has_pm(hdr->frame_control)) 18168c2ecf20Sopenharmony_ci sta_ps_start(sta); 18178c2ecf20Sopenharmony_ci } 18188c2ecf20Sopenharmony_ci } 18198c2ecf20Sopenharmony_ci 18208c2ecf20Sopenharmony_ci /* mesh power save support */ 18218c2ecf20Sopenharmony_ci if (ieee80211_vif_is_mesh(&rx->sdata->vif)) 18228c2ecf20Sopenharmony_ci ieee80211_mps_rx_h_sta_process(sta, hdr); 18238c2ecf20Sopenharmony_ci 18248c2ecf20Sopenharmony_ci /* 18258c2ecf20Sopenharmony_ci * Drop (qos-)data::nullfunc frames silently, since they 18268c2ecf20Sopenharmony_ci * are used only to control station power saving mode. 18278c2ecf20Sopenharmony_ci */ 18288c2ecf20Sopenharmony_ci if (ieee80211_is_any_nullfunc(hdr->frame_control)) { 18298c2ecf20Sopenharmony_ci I802_DEBUG_INC(rx->local->rx_handlers_drop_nullfunc); 18308c2ecf20Sopenharmony_ci 18318c2ecf20Sopenharmony_ci /* 18328c2ecf20Sopenharmony_ci * If we receive a 4-addr nullfunc frame from a STA 18338c2ecf20Sopenharmony_ci * that was not moved to a 4-addr STA vlan yet send 18348c2ecf20Sopenharmony_ci * the event to userspace and for older hostapd drop 18358c2ecf20Sopenharmony_ci * the frame to the monitor interface. 18368c2ecf20Sopenharmony_ci */ 18378c2ecf20Sopenharmony_ci if (ieee80211_has_a4(hdr->frame_control) && 18388c2ecf20Sopenharmony_ci (rx->sdata->vif.type == NL80211_IFTYPE_AP || 18398c2ecf20Sopenharmony_ci (rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN && 18408c2ecf20Sopenharmony_ci !rx->sdata->u.vlan.sta))) { 18418c2ecf20Sopenharmony_ci if (!test_and_set_sta_flag(sta, WLAN_STA_4ADDR_EVENT)) 18428c2ecf20Sopenharmony_ci cfg80211_rx_unexpected_4addr_frame( 18438c2ecf20Sopenharmony_ci rx->sdata->dev, sta->sta.addr, 18448c2ecf20Sopenharmony_ci GFP_ATOMIC); 18458c2ecf20Sopenharmony_ci return RX_DROP_MONITOR; 18468c2ecf20Sopenharmony_ci } 18478c2ecf20Sopenharmony_ci /* 18488c2ecf20Sopenharmony_ci * Update counter and free packet here to avoid 18498c2ecf20Sopenharmony_ci * counting this as a dropped packed. 18508c2ecf20Sopenharmony_ci */ 18518c2ecf20Sopenharmony_ci sta->rx_stats.packets++; 18528c2ecf20Sopenharmony_ci dev_kfree_skb(rx->skb); 18538c2ecf20Sopenharmony_ci return RX_QUEUED; 18548c2ecf20Sopenharmony_ci } 18558c2ecf20Sopenharmony_ci 18568c2ecf20Sopenharmony_ci return RX_CONTINUE; 18578c2ecf20Sopenharmony_ci} /* ieee80211_rx_h_sta_process */ 18588c2ecf20Sopenharmony_ci 18598c2ecf20Sopenharmony_cistatic struct ieee80211_key * 18608c2ecf20Sopenharmony_ciieee80211_rx_get_bigtk(struct ieee80211_rx_data *rx, int idx) 18618c2ecf20Sopenharmony_ci{ 18628c2ecf20Sopenharmony_ci struct ieee80211_key *key = NULL; 18638c2ecf20Sopenharmony_ci struct ieee80211_sub_if_data *sdata = rx->sdata; 18648c2ecf20Sopenharmony_ci int idx2; 18658c2ecf20Sopenharmony_ci 18668c2ecf20Sopenharmony_ci /* Make sure key gets set if either BIGTK key index is set so that 18678c2ecf20Sopenharmony_ci * ieee80211_drop_unencrypted_mgmt() can properly drop both unprotected 18688c2ecf20Sopenharmony_ci * Beacon frames and Beacon frames that claim to use another BIGTK key 18698c2ecf20Sopenharmony_ci * index (i.e., a key that we do not have). 18708c2ecf20Sopenharmony_ci */ 18718c2ecf20Sopenharmony_ci 18728c2ecf20Sopenharmony_ci if (idx < 0) { 18738c2ecf20Sopenharmony_ci idx = NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS; 18748c2ecf20Sopenharmony_ci idx2 = idx + 1; 18758c2ecf20Sopenharmony_ci } else { 18768c2ecf20Sopenharmony_ci if (idx == NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS) 18778c2ecf20Sopenharmony_ci idx2 = idx + 1; 18788c2ecf20Sopenharmony_ci else 18798c2ecf20Sopenharmony_ci idx2 = idx - 1; 18808c2ecf20Sopenharmony_ci } 18818c2ecf20Sopenharmony_ci 18828c2ecf20Sopenharmony_ci if (rx->sta) 18838c2ecf20Sopenharmony_ci key = rcu_dereference(rx->sta->gtk[idx]); 18848c2ecf20Sopenharmony_ci if (!key) 18858c2ecf20Sopenharmony_ci key = rcu_dereference(sdata->keys[idx]); 18868c2ecf20Sopenharmony_ci if (!key && rx->sta) 18878c2ecf20Sopenharmony_ci key = rcu_dereference(rx->sta->gtk[idx2]); 18888c2ecf20Sopenharmony_ci if (!key) 18898c2ecf20Sopenharmony_ci key = rcu_dereference(sdata->keys[idx2]); 18908c2ecf20Sopenharmony_ci 18918c2ecf20Sopenharmony_ci return key; 18928c2ecf20Sopenharmony_ci} 18938c2ecf20Sopenharmony_ci 18948c2ecf20Sopenharmony_cistatic ieee80211_rx_result debug_noinline 18958c2ecf20Sopenharmony_ciieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) 18968c2ecf20Sopenharmony_ci{ 18978c2ecf20Sopenharmony_ci struct sk_buff *skb = rx->skb; 18988c2ecf20Sopenharmony_ci struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); 18998c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; 19008c2ecf20Sopenharmony_ci int keyidx; 19018c2ecf20Sopenharmony_ci ieee80211_rx_result result = RX_DROP_UNUSABLE; 19028c2ecf20Sopenharmony_ci struct ieee80211_key *sta_ptk = NULL; 19038c2ecf20Sopenharmony_ci struct ieee80211_key *ptk_idx = NULL; 19048c2ecf20Sopenharmony_ci int mmie_keyidx = -1; 19058c2ecf20Sopenharmony_ci __le16 fc; 19068c2ecf20Sopenharmony_ci const struct ieee80211_cipher_scheme *cs = NULL; 19078c2ecf20Sopenharmony_ci 19088c2ecf20Sopenharmony_ci if (ieee80211_is_ext(hdr->frame_control)) 19098c2ecf20Sopenharmony_ci return RX_CONTINUE; 19108c2ecf20Sopenharmony_ci 19118c2ecf20Sopenharmony_ci /* 19128c2ecf20Sopenharmony_ci * Key selection 101 19138c2ecf20Sopenharmony_ci * 19148c2ecf20Sopenharmony_ci * There are five types of keys: 19158c2ecf20Sopenharmony_ci * - GTK (group keys) 19168c2ecf20Sopenharmony_ci * - IGTK (group keys for management frames) 19178c2ecf20Sopenharmony_ci * - BIGTK (group keys for Beacon frames) 19188c2ecf20Sopenharmony_ci * - PTK (pairwise keys) 19198c2ecf20Sopenharmony_ci * - STK (station-to-station pairwise keys) 19208c2ecf20Sopenharmony_ci * 19218c2ecf20Sopenharmony_ci * When selecting a key, we have to distinguish between multicast 19228c2ecf20Sopenharmony_ci * (including broadcast) and unicast frames, the latter can only 19238c2ecf20Sopenharmony_ci * use PTKs and STKs while the former always use GTKs, IGTKs, and 19248c2ecf20Sopenharmony_ci * BIGTKs. Unless, of course, actual WEP keys ("pre-RSNA") are used, 19258c2ecf20Sopenharmony_ci * then unicast frames can also use key indices like GTKs. Hence, if we 19268c2ecf20Sopenharmony_ci * don't have a PTK/STK we check the key index for a WEP key. 19278c2ecf20Sopenharmony_ci * 19288c2ecf20Sopenharmony_ci * Note that in a regular BSS, multicast frames are sent by the 19298c2ecf20Sopenharmony_ci * AP only, associated stations unicast the frame to the AP first 19308c2ecf20Sopenharmony_ci * which then multicasts it on their behalf. 19318c2ecf20Sopenharmony_ci * 19328c2ecf20Sopenharmony_ci * There is also a slight problem in IBSS mode: GTKs are negotiated 19338c2ecf20Sopenharmony_ci * with each station, that is something we don't currently handle. 19348c2ecf20Sopenharmony_ci * The spec seems to expect that one negotiates the same key with 19358c2ecf20Sopenharmony_ci * every station but there's no such requirement; VLANs could be 19368c2ecf20Sopenharmony_ci * possible. 19378c2ecf20Sopenharmony_ci */ 19388c2ecf20Sopenharmony_ci 19398c2ecf20Sopenharmony_ci /* start without a key */ 19408c2ecf20Sopenharmony_ci rx->key = NULL; 19418c2ecf20Sopenharmony_ci fc = hdr->frame_control; 19428c2ecf20Sopenharmony_ci 19438c2ecf20Sopenharmony_ci if (rx->sta) { 19448c2ecf20Sopenharmony_ci int keyid = rx->sta->ptk_idx; 19458c2ecf20Sopenharmony_ci sta_ptk = rcu_dereference(rx->sta->ptk[keyid]); 19468c2ecf20Sopenharmony_ci 19478c2ecf20Sopenharmony_ci if (ieee80211_has_protected(fc) && 19488c2ecf20Sopenharmony_ci !(status->flag & RX_FLAG_IV_STRIPPED)) { 19498c2ecf20Sopenharmony_ci cs = rx->sta->cipher_scheme; 19508c2ecf20Sopenharmony_ci keyid = ieee80211_get_keyid(rx->skb, cs); 19518c2ecf20Sopenharmony_ci 19528c2ecf20Sopenharmony_ci if (unlikely(keyid < 0)) 19538c2ecf20Sopenharmony_ci return RX_DROP_UNUSABLE; 19548c2ecf20Sopenharmony_ci 19558c2ecf20Sopenharmony_ci ptk_idx = rcu_dereference(rx->sta->ptk[keyid]); 19568c2ecf20Sopenharmony_ci } 19578c2ecf20Sopenharmony_ci } 19588c2ecf20Sopenharmony_ci 19598c2ecf20Sopenharmony_ci if (!ieee80211_has_protected(fc)) 19608c2ecf20Sopenharmony_ci mmie_keyidx = ieee80211_get_mmie_keyidx(rx->skb); 19618c2ecf20Sopenharmony_ci 19628c2ecf20Sopenharmony_ci if (!is_multicast_ether_addr(hdr->addr1) && sta_ptk) { 19638c2ecf20Sopenharmony_ci rx->key = ptk_idx ? ptk_idx : sta_ptk; 19648c2ecf20Sopenharmony_ci if ((status->flag & RX_FLAG_DECRYPTED) && 19658c2ecf20Sopenharmony_ci (status->flag & RX_FLAG_IV_STRIPPED)) 19668c2ecf20Sopenharmony_ci return RX_CONTINUE; 19678c2ecf20Sopenharmony_ci /* Skip decryption if the frame is not protected. */ 19688c2ecf20Sopenharmony_ci if (!ieee80211_has_protected(fc)) 19698c2ecf20Sopenharmony_ci return RX_CONTINUE; 19708c2ecf20Sopenharmony_ci } else if (mmie_keyidx >= 0 && ieee80211_is_beacon(fc)) { 19718c2ecf20Sopenharmony_ci /* Broadcast/multicast robust management frame / BIP */ 19728c2ecf20Sopenharmony_ci if ((status->flag & RX_FLAG_DECRYPTED) && 19738c2ecf20Sopenharmony_ci (status->flag & RX_FLAG_IV_STRIPPED)) 19748c2ecf20Sopenharmony_ci return RX_CONTINUE; 19758c2ecf20Sopenharmony_ci 19768c2ecf20Sopenharmony_ci if (mmie_keyidx < NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS || 19778c2ecf20Sopenharmony_ci mmie_keyidx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS + 19788c2ecf20Sopenharmony_ci NUM_DEFAULT_BEACON_KEYS) { 19798c2ecf20Sopenharmony_ci if (rx->sdata->dev) 19808c2ecf20Sopenharmony_ci cfg80211_rx_unprot_mlme_mgmt(rx->sdata->dev, 19818c2ecf20Sopenharmony_ci skb->data, 19828c2ecf20Sopenharmony_ci skb->len); 19838c2ecf20Sopenharmony_ci return RX_DROP_MONITOR; /* unexpected BIP keyidx */ 19848c2ecf20Sopenharmony_ci } 19858c2ecf20Sopenharmony_ci 19868c2ecf20Sopenharmony_ci rx->key = ieee80211_rx_get_bigtk(rx, mmie_keyidx); 19878c2ecf20Sopenharmony_ci if (!rx->key) 19888c2ecf20Sopenharmony_ci return RX_CONTINUE; /* Beacon protection not in use */ 19898c2ecf20Sopenharmony_ci } else if (mmie_keyidx >= 0) { 19908c2ecf20Sopenharmony_ci /* Broadcast/multicast robust management frame / BIP */ 19918c2ecf20Sopenharmony_ci if ((status->flag & RX_FLAG_DECRYPTED) && 19928c2ecf20Sopenharmony_ci (status->flag & RX_FLAG_IV_STRIPPED)) 19938c2ecf20Sopenharmony_ci return RX_CONTINUE; 19948c2ecf20Sopenharmony_ci 19958c2ecf20Sopenharmony_ci if (mmie_keyidx < NUM_DEFAULT_KEYS || 19968c2ecf20Sopenharmony_ci mmie_keyidx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS) 19978c2ecf20Sopenharmony_ci return RX_DROP_MONITOR; /* unexpected BIP keyidx */ 19988c2ecf20Sopenharmony_ci if (rx->sta) { 19998c2ecf20Sopenharmony_ci if (ieee80211_is_group_privacy_action(skb) && 20008c2ecf20Sopenharmony_ci test_sta_flag(rx->sta, WLAN_STA_MFP)) 20018c2ecf20Sopenharmony_ci return RX_DROP_MONITOR; 20028c2ecf20Sopenharmony_ci 20038c2ecf20Sopenharmony_ci rx->key = rcu_dereference(rx->sta->gtk[mmie_keyidx]); 20048c2ecf20Sopenharmony_ci } 20058c2ecf20Sopenharmony_ci if (!rx->key) 20068c2ecf20Sopenharmony_ci rx->key = rcu_dereference(rx->sdata->keys[mmie_keyidx]); 20078c2ecf20Sopenharmony_ci } else if (!ieee80211_has_protected(fc)) { 20088c2ecf20Sopenharmony_ci /* 20098c2ecf20Sopenharmony_ci * The frame was not protected, so skip decryption. However, we 20108c2ecf20Sopenharmony_ci * need to set rx->key if there is a key that could have been 20118c2ecf20Sopenharmony_ci * used so that the frame may be dropped if encryption would 20128c2ecf20Sopenharmony_ci * have been expected. 20138c2ecf20Sopenharmony_ci */ 20148c2ecf20Sopenharmony_ci struct ieee80211_key *key = NULL; 20158c2ecf20Sopenharmony_ci struct ieee80211_sub_if_data *sdata = rx->sdata; 20168c2ecf20Sopenharmony_ci int i; 20178c2ecf20Sopenharmony_ci 20188c2ecf20Sopenharmony_ci if (ieee80211_is_beacon(fc)) { 20198c2ecf20Sopenharmony_ci key = ieee80211_rx_get_bigtk(rx, -1); 20208c2ecf20Sopenharmony_ci } else if (ieee80211_is_mgmt(fc) && 20218c2ecf20Sopenharmony_ci is_multicast_ether_addr(hdr->addr1)) { 20228c2ecf20Sopenharmony_ci key = rcu_dereference(rx->sdata->default_mgmt_key); 20238c2ecf20Sopenharmony_ci } else { 20248c2ecf20Sopenharmony_ci if (rx->sta) { 20258c2ecf20Sopenharmony_ci for (i = 0; i < NUM_DEFAULT_KEYS; i++) { 20268c2ecf20Sopenharmony_ci key = rcu_dereference(rx->sta->gtk[i]); 20278c2ecf20Sopenharmony_ci if (key) 20288c2ecf20Sopenharmony_ci break; 20298c2ecf20Sopenharmony_ci } 20308c2ecf20Sopenharmony_ci } 20318c2ecf20Sopenharmony_ci if (!key) { 20328c2ecf20Sopenharmony_ci for (i = 0; i < NUM_DEFAULT_KEYS; i++) { 20338c2ecf20Sopenharmony_ci key = rcu_dereference(sdata->keys[i]); 20348c2ecf20Sopenharmony_ci if (key) 20358c2ecf20Sopenharmony_ci break; 20368c2ecf20Sopenharmony_ci } 20378c2ecf20Sopenharmony_ci } 20388c2ecf20Sopenharmony_ci } 20398c2ecf20Sopenharmony_ci if (key) 20408c2ecf20Sopenharmony_ci rx->key = key; 20418c2ecf20Sopenharmony_ci return RX_CONTINUE; 20428c2ecf20Sopenharmony_ci } else { 20438c2ecf20Sopenharmony_ci /* 20448c2ecf20Sopenharmony_ci * The device doesn't give us the IV so we won't be 20458c2ecf20Sopenharmony_ci * able to look up the key. That's ok though, we 20468c2ecf20Sopenharmony_ci * don't need to decrypt the frame, we just won't 20478c2ecf20Sopenharmony_ci * be able to keep statistics accurate. 20488c2ecf20Sopenharmony_ci * Except for key threshold notifications, should 20498c2ecf20Sopenharmony_ci * we somehow allow the driver to tell us which key 20508c2ecf20Sopenharmony_ci * the hardware used if this flag is set? 20518c2ecf20Sopenharmony_ci */ 20528c2ecf20Sopenharmony_ci if ((status->flag & RX_FLAG_DECRYPTED) && 20538c2ecf20Sopenharmony_ci (status->flag & RX_FLAG_IV_STRIPPED)) 20548c2ecf20Sopenharmony_ci return RX_CONTINUE; 20558c2ecf20Sopenharmony_ci 20568c2ecf20Sopenharmony_ci keyidx = ieee80211_get_keyid(rx->skb, cs); 20578c2ecf20Sopenharmony_ci 20588c2ecf20Sopenharmony_ci if (unlikely(keyidx < 0)) 20598c2ecf20Sopenharmony_ci return RX_DROP_UNUSABLE; 20608c2ecf20Sopenharmony_ci 20618c2ecf20Sopenharmony_ci /* check per-station GTK first, if multicast packet */ 20628c2ecf20Sopenharmony_ci if (is_multicast_ether_addr(hdr->addr1) && rx->sta) 20638c2ecf20Sopenharmony_ci rx->key = rcu_dereference(rx->sta->gtk[keyidx]); 20648c2ecf20Sopenharmony_ci 20658c2ecf20Sopenharmony_ci /* if not found, try default key */ 20668c2ecf20Sopenharmony_ci if (!rx->key) { 20678c2ecf20Sopenharmony_ci rx->key = rcu_dereference(rx->sdata->keys[keyidx]); 20688c2ecf20Sopenharmony_ci 20698c2ecf20Sopenharmony_ci /* 20708c2ecf20Sopenharmony_ci * RSNA-protected unicast frames should always be 20718c2ecf20Sopenharmony_ci * sent with pairwise or station-to-station keys, 20728c2ecf20Sopenharmony_ci * but for WEP we allow using a key index as well. 20738c2ecf20Sopenharmony_ci */ 20748c2ecf20Sopenharmony_ci if (rx->key && 20758c2ecf20Sopenharmony_ci rx->key->conf.cipher != WLAN_CIPHER_SUITE_WEP40 && 20768c2ecf20Sopenharmony_ci rx->key->conf.cipher != WLAN_CIPHER_SUITE_WEP104 && 20778c2ecf20Sopenharmony_ci !is_multicast_ether_addr(hdr->addr1)) 20788c2ecf20Sopenharmony_ci rx->key = NULL; 20798c2ecf20Sopenharmony_ci } 20808c2ecf20Sopenharmony_ci } 20818c2ecf20Sopenharmony_ci 20828c2ecf20Sopenharmony_ci if (rx->key) { 20838c2ecf20Sopenharmony_ci if (unlikely(rx->key->flags & KEY_FLAG_TAINTED)) 20848c2ecf20Sopenharmony_ci return RX_DROP_MONITOR; 20858c2ecf20Sopenharmony_ci 20868c2ecf20Sopenharmony_ci /* TODO: add threshold stuff again */ 20878c2ecf20Sopenharmony_ci } else { 20888c2ecf20Sopenharmony_ci return RX_DROP_MONITOR; 20898c2ecf20Sopenharmony_ci } 20908c2ecf20Sopenharmony_ci 20918c2ecf20Sopenharmony_ci switch (rx->key->conf.cipher) { 20928c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_WEP40: 20938c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_WEP104: 20948c2ecf20Sopenharmony_ci result = ieee80211_crypto_wep_decrypt(rx); 20958c2ecf20Sopenharmony_ci break; 20968c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_TKIP: 20978c2ecf20Sopenharmony_ci result = ieee80211_crypto_tkip_decrypt(rx); 20988c2ecf20Sopenharmony_ci break; 20998c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_CCMP: 21008c2ecf20Sopenharmony_ci result = ieee80211_crypto_ccmp_decrypt( 21018c2ecf20Sopenharmony_ci rx, IEEE80211_CCMP_MIC_LEN); 21028c2ecf20Sopenharmony_ci break; 21038c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_CCMP_256: 21048c2ecf20Sopenharmony_ci result = ieee80211_crypto_ccmp_decrypt( 21058c2ecf20Sopenharmony_ci rx, IEEE80211_CCMP_256_MIC_LEN); 21068c2ecf20Sopenharmony_ci break; 21078c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_AES_CMAC: 21088c2ecf20Sopenharmony_ci result = ieee80211_crypto_aes_cmac_decrypt(rx); 21098c2ecf20Sopenharmony_ci break; 21108c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_BIP_CMAC_256: 21118c2ecf20Sopenharmony_ci result = ieee80211_crypto_aes_cmac_256_decrypt(rx); 21128c2ecf20Sopenharmony_ci break; 21138c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_BIP_GMAC_128: 21148c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_BIP_GMAC_256: 21158c2ecf20Sopenharmony_ci result = ieee80211_crypto_aes_gmac_decrypt(rx); 21168c2ecf20Sopenharmony_ci break; 21178c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_GCMP: 21188c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_GCMP_256: 21198c2ecf20Sopenharmony_ci result = ieee80211_crypto_gcmp_decrypt(rx); 21208c2ecf20Sopenharmony_ci break; 21218c2ecf20Sopenharmony_ci default: 21228c2ecf20Sopenharmony_ci result = ieee80211_crypto_hw_decrypt(rx); 21238c2ecf20Sopenharmony_ci } 21248c2ecf20Sopenharmony_ci 21258c2ecf20Sopenharmony_ci /* the hdr variable is invalid after the decrypt handlers */ 21268c2ecf20Sopenharmony_ci 21278c2ecf20Sopenharmony_ci /* either the frame has been decrypted or will be dropped */ 21288c2ecf20Sopenharmony_ci status->flag |= RX_FLAG_DECRYPTED; 21298c2ecf20Sopenharmony_ci 21308c2ecf20Sopenharmony_ci if (unlikely(ieee80211_is_beacon(fc) && result == RX_DROP_UNUSABLE && 21318c2ecf20Sopenharmony_ci rx->sdata->dev)) 21328c2ecf20Sopenharmony_ci cfg80211_rx_unprot_mlme_mgmt(rx->sdata->dev, 21338c2ecf20Sopenharmony_ci skb->data, skb->len); 21348c2ecf20Sopenharmony_ci 21358c2ecf20Sopenharmony_ci return result; 21368c2ecf20Sopenharmony_ci} 21378c2ecf20Sopenharmony_ci 21388c2ecf20Sopenharmony_civoid ieee80211_init_frag_cache(struct ieee80211_fragment_cache *cache) 21398c2ecf20Sopenharmony_ci{ 21408c2ecf20Sopenharmony_ci int i; 21418c2ecf20Sopenharmony_ci 21428c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(cache->entries); i++) 21438c2ecf20Sopenharmony_ci skb_queue_head_init(&cache->entries[i].skb_list); 21448c2ecf20Sopenharmony_ci} 21458c2ecf20Sopenharmony_ci 21468c2ecf20Sopenharmony_civoid ieee80211_destroy_frag_cache(struct ieee80211_fragment_cache *cache) 21478c2ecf20Sopenharmony_ci{ 21488c2ecf20Sopenharmony_ci int i; 21498c2ecf20Sopenharmony_ci 21508c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(cache->entries); i++) 21518c2ecf20Sopenharmony_ci __skb_queue_purge(&cache->entries[i].skb_list); 21528c2ecf20Sopenharmony_ci} 21538c2ecf20Sopenharmony_ci 21548c2ecf20Sopenharmony_cistatic inline struct ieee80211_fragment_entry * 21558c2ecf20Sopenharmony_ciieee80211_reassemble_add(struct ieee80211_fragment_cache *cache, 21568c2ecf20Sopenharmony_ci unsigned int frag, unsigned int seq, int rx_queue, 21578c2ecf20Sopenharmony_ci struct sk_buff **skb) 21588c2ecf20Sopenharmony_ci{ 21598c2ecf20Sopenharmony_ci struct ieee80211_fragment_entry *entry; 21608c2ecf20Sopenharmony_ci 21618c2ecf20Sopenharmony_ci entry = &cache->entries[cache->next++]; 21628c2ecf20Sopenharmony_ci if (cache->next >= IEEE80211_FRAGMENT_MAX) 21638c2ecf20Sopenharmony_ci cache->next = 0; 21648c2ecf20Sopenharmony_ci 21658c2ecf20Sopenharmony_ci __skb_queue_purge(&entry->skb_list); 21668c2ecf20Sopenharmony_ci 21678c2ecf20Sopenharmony_ci __skb_queue_tail(&entry->skb_list, *skb); /* no need for locking */ 21688c2ecf20Sopenharmony_ci *skb = NULL; 21698c2ecf20Sopenharmony_ci entry->first_frag_time = jiffies; 21708c2ecf20Sopenharmony_ci entry->seq = seq; 21718c2ecf20Sopenharmony_ci entry->rx_queue = rx_queue; 21728c2ecf20Sopenharmony_ci entry->last_frag = frag; 21738c2ecf20Sopenharmony_ci entry->check_sequential_pn = false; 21748c2ecf20Sopenharmony_ci entry->extra_len = 0; 21758c2ecf20Sopenharmony_ci 21768c2ecf20Sopenharmony_ci return entry; 21778c2ecf20Sopenharmony_ci} 21788c2ecf20Sopenharmony_ci 21798c2ecf20Sopenharmony_cistatic inline struct ieee80211_fragment_entry * 21808c2ecf20Sopenharmony_ciieee80211_reassemble_find(struct ieee80211_fragment_cache *cache, 21818c2ecf20Sopenharmony_ci unsigned int frag, unsigned int seq, 21828c2ecf20Sopenharmony_ci int rx_queue, struct ieee80211_hdr *hdr) 21838c2ecf20Sopenharmony_ci{ 21848c2ecf20Sopenharmony_ci struct ieee80211_fragment_entry *entry; 21858c2ecf20Sopenharmony_ci int i, idx; 21868c2ecf20Sopenharmony_ci 21878c2ecf20Sopenharmony_ci idx = cache->next; 21888c2ecf20Sopenharmony_ci for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++) { 21898c2ecf20Sopenharmony_ci struct ieee80211_hdr *f_hdr; 21908c2ecf20Sopenharmony_ci struct sk_buff *f_skb; 21918c2ecf20Sopenharmony_ci 21928c2ecf20Sopenharmony_ci idx--; 21938c2ecf20Sopenharmony_ci if (idx < 0) 21948c2ecf20Sopenharmony_ci idx = IEEE80211_FRAGMENT_MAX - 1; 21958c2ecf20Sopenharmony_ci 21968c2ecf20Sopenharmony_ci entry = &cache->entries[idx]; 21978c2ecf20Sopenharmony_ci if (skb_queue_empty(&entry->skb_list) || entry->seq != seq || 21988c2ecf20Sopenharmony_ci entry->rx_queue != rx_queue || 21998c2ecf20Sopenharmony_ci entry->last_frag + 1 != frag) 22008c2ecf20Sopenharmony_ci continue; 22018c2ecf20Sopenharmony_ci 22028c2ecf20Sopenharmony_ci f_skb = __skb_peek(&entry->skb_list); 22038c2ecf20Sopenharmony_ci f_hdr = (struct ieee80211_hdr *) f_skb->data; 22048c2ecf20Sopenharmony_ci 22058c2ecf20Sopenharmony_ci /* 22068c2ecf20Sopenharmony_ci * Check ftype and addresses are equal, else check next fragment 22078c2ecf20Sopenharmony_ci */ 22088c2ecf20Sopenharmony_ci if (((hdr->frame_control ^ f_hdr->frame_control) & 22098c2ecf20Sopenharmony_ci cpu_to_le16(IEEE80211_FCTL_FTYPE)) || 22108c2ecf20Sopenharmony_ci !ether_addr_equal(hdr->addr1, f_hdr->addr1) || 22118c2ecf20Sopenharmony_ci !ether_addr_equal(hdr->addr2, f_hdr->addr2)) 22128c2ecf20Sopenharmony_ci continue; 22138c2ecf20Sopenharmony_ci 22148c2ecf20Sopenharmony_ci if (time_after(jiffies, entry->first_frag_time + 2 * HZ)) { 22158c2ecf20Sopenharmony_ci __skb_queue_purge(&entry->skb_list); 22168c2ecf20Sopenharmony_ci continue; 22178c2ecf20Sopenharmony_ci } 22188c2ecf20Sopenharmony_ci return entry; 22198c2ecf20Sopenharmony_ci } 22208c2ecf20Sopenharmony_ci 22218c2ecf20Sopenharmony_ci return NULL; 22228c2ecf20Sopenharmony_ci} 22238c2ecf20Sopenharmony_ci 22248c2ecf20Sopenharmony_cistatic bool requires_sequential_pn(struct ieee80211_rx_data *rx, __le16 fc) 22258c2ecf20Sopenharmony_ci{ 22268c2ecf20Sopenharmony_ci return rx->key && 22278c2ecf20Sopenharmony_ci (rx->key->conf.cipher == WLAN_CIPHER_SUITE_CCMP || 22288c2ecf20Sopenharmony_ci rx->key->conf.cipher == WLAN_CIPHER_SUITE_CCMP_256 || 22298c2ecf20Sopenharmony_ci rx->key->conf.cipher == WLAN_CIPHER_SUITE_GCMP || 22308c2ecf20Sopenharmony_ci rx->key->conf.cipher == WLAN_CIPHER_SUITE_GCMP_256) && 22318c2ecf20Sopenharmony_ci ieee80211_has_protected(fc); 22328c2ecf20Sopenharmony_ci} 22338c2ecf20Sopenharmony_ci 22348c2ecf20Sopenharmony_cistatic ieee80211_rx_result debug_noinline 22358c2ecf20Sopenharmony_ciieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) 22368c2ecf20Sopenharmony_ci{ 22378c2ecf20Sopenharmony_ci struct ieee80211_fragment_cache *cache = &rx->sdata->frags; 22388c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr; 22398c2ecf20Sopenharmony_ci u16 sc; 22408c2ecf20Sopenharmony_ci __le16 fc; 22418c2ecf20Sopenharmony_ci unsigned int frag, seq; 22428c2ecf20Sopenharmony_ci struct ieee80211_fragment_entry *entry; 22438c2ecf20Sopenharmony_ci struct sk_buff *skb; 22448c2ecf20Sopenharmony_ci struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); 22458c2ecf20Sopenharmony_ci 22468c2ecf20Sopenharmony_ci hdr = (struct ieee80211_hdr *)rx->skb->data; 22478c2ecf20Sopenharmony_ci fc = hdr->frame_control; 22488c2ecf20Sopenharmony_ci 22498c2ecf20Sopenharmony_ci if (ieee80211_is_ctl(fc) || ieee80211_is_ext(fc)) 22508c2ecf20Sopenharmony_ci return RX_CONTINUE; 22518c2ecf20Sopenharmony_ci 22528c2ecf20Sopenharmony_ci sc = le16_to_cpu(hdr->seq_ctrl); 22538c2ecf20Sopenharmony_ci frag = sc & IEEE80211_SCTL_FRAG; 22548c2ecf20Sopenharmony_ci 22558c2ecf20Sopenharmony_ci if (rx->sta) 22568c2ecf20Sopenharmony_ci cache = &rx->sta->frags; 22578c2ecf20Sopenharmony_ci 22588c2ecf20Sopenharmony_ci if (likely(!ieee80211_has_morefrags(fc) && frag == 0)) 22598c2ecf20Sopenharmony_ci goto out; 22608c2ecf20Sopenharmony_ci 22618c2ecf20Sopenharmony_ci if (is_multicast_ether_addr(hdr->addr1)) 22628c2ecf20Sopenharmony_ci return RX_DROP_MONITOR; 22638c2ecf20Sopenharmony_ci 22648c2ecf20Sopenharmony_ci I802_DEBUG_INC(rx->local->rx_handlers_fragments); 22658c2ecf20Sopenharmony_ci 22668c2ecf20Sopenharmony_ci if (skb_linearize(rx->skb)) 22678c2ecf20Sopenharmony_ci return RX_DROP_UNUSABLE; 22688c2ecf20Sopenharmony_ci 22698c2ecf20Sopenharmony_ci /* 22708c2ecf20Sopenharmony_ci * skb_linearize() might change the skb->data and 22718c2ecf20Sopenharmony_ci * previously cached variables (in this case, hdr) need to 22728c2ecf20Sopenharmony_ci * be refreshed with the new data. 22738c2ecf20Sopenharmony_ci */ 22748c2ecf20Sopenharmony_ci hdr = (struct ieee80211_hdr *)rx->skb->data; 22758c2ecf20Sopenharmony_ci seq = (sc & IEEE80211_SCTL_SEQ) >> 4; 22768c2ecf20Sopenharmony_ci 22778c2ecf20Sopenharmony_ci if (frag == 0) { 22788c2ecf20Sopenharmony_ci /* This is the first fragment of a new frame. */ 22798c2ecf20Sopenharmony_ci entry = ieee80211_reassemble_add(cache, frag, seq, 22808c2ecf20Sopenharmony_ci rx->seqno_idx, &(rx->skb)); 22818c2ecf20Sopenharmony_ci if (requires_sequential_pn(rx, fc)) { 22828c2ecf20Sopenharmony_ci int queue = rx->security_idx; 22838c2ecf20Sopenharmony_ci 22848c2ecf20Sopenharmony_ci /* Store CCMP/GCMP PN so that we can verify that the 22858c2ecf20Sopenharmony_ci * next fragment has a sequential PN value. 22868c2ecf20Sopenharmony_ci */ 22878c2ecf20Sopenharmony_ci entry->check_sequential_pn = true; 22888c2ecf20Sopenharmony_ci entry->is_protected = true; 22898c2ecf20Sopenharmony_ci entry->key_color = rx->key->color; 22908c2ecf20Sopenharmony_ci memcpy(entry->last_pn, 22918c2ecf20Sopenharmony_ci rx->key->u.ccmp.rx_pn[queue], 22928c2ecf20Sopenharmony_ci IEEE80211_CCMP_PN_LEN); 22938c2ecf20Sopenharmony_ci BUILD_BUG_ON(offsetof(struct ieee80211_key, 22948c2ecf20Sopenharmony_ci u.ccmp.rx_pn) != 22958c2ecf20Sopenharmony_ci offsetof(struct ieee80211_key, 22968c2ecf20Sopenharmony_ci u.gcmp.rx_pn)); 22978c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(rx->key->u.ccmp.rx_pn[queue]) != 22988c2ecf20Sopenharmony_ci sizeof(rx->key->u.gcmp.rx_pn[queue])); 22998c2ecf20Sopenharmony_ci BUILD_BUG_ON(IEEE80211_CCMP_PN_LEN != 23008c2ecf20Sopenharmony_ci IEEE80211_GCMP_PN_LEN); 23018c2ecf20Sopenharmony_ci } else if (rx->key && 23028c2ecf20Sopenharmony_ci (ieee80211_has_protected(fc) || 23038c2ecf20Sopenharmony_ci (status->flag & RX_FLAG_DECRYPTED))) { 23048c2ecf20Sopenharmony_ci entry->is_protected = true; 23058c2ecf20Sopenharmony_ci entry->key_color = rx->key->color; 23068c2ecf20Sopenharmony_ci } 23078c2ecf20Sopenharmony_ci return RX_QUEUED; 23088c2ecf20Sopenharmony_ci } 23098c2ecf20Sopenharmony_ci 23108c2ecf20Sopenharmony_ci /* This is a fragment for a frame that should already be pending in 23118c2ecf20Sopenharmony_ci * fragment cache. Add this fragment to the end of the pending entry. 23128c2ecf20Sopenharmony_ci */ 23138c2ecf20Sopenharmony_ci entry = ieee80211_reassemble_find(cache, frag, seq, 23148c2ecf20Sopenharmony_ci rx->seqno_idx, hdr); 23158c2ecf20Sopenharmony_ci if (!entry) { 23168c2ecf20Sopenharmony_ci I802_DEBUG_INC(rx->local->rx_handlers_drop_defrag); 23178c2ecf20Sopenharmony_ci return RX_DROP_MONITOR; 23188c2ecf20Sopenharmony_ci } 23198c2ecf20Sopenharmony_ci 23208c2ecf20Sopenharmony_ci /* "The receiver shall discard MSDUs and MMPDUs whose constituent 23218c2ecf20Sopenharmony_ci * MPDU PN values are not incrementing in steps of 1." 23228c2ecf20Sopenharmony_ci * see IEEE P802.11-REVmc/D5.0, 12.5.3.4.4, item d (for CCMP) 23238c2ecf20Sopenharmony_ci * and IEEE P802.11-REVmc/D5.0, 12.5.5.4.4, item d (for GCMP) 23248c2ecf20Sopenharmony_ci */ 23258c2ecf20Sopenharmony_ci if (entry->check_sequential_pn) { 23268c2ecf20Sopenharmony_ci int i; 23278c2ecf20Sopenharmony_ci u8 pn[IEEE80211_CCMP_PN_LEN], *rpn; 23288c2ecf20Sopenharmony_ci 23298c2ecf20Sopenharmony_ci if (!requires_sequential_pn(rx, fc)) 23308c2ecf20Sopenharmony_ci return RX_DROP_UNUSABLE; 23318c2ecf20Sopenharmony_ci 23328c2ecf20Sopenharmony_ci /* Prevent mixed key and fragment cache attacks */ 23338c2ecf20Sopenharmony_ci if (entry->key_color != rx->key->color) 23348c2ecf20Sopenharmony_ci return RX_DROP_UNUSABLE; 23358c2ecf20Sopenharmony_ci 23368c2ecf20Sopenharmony_ci memcpy(pn, entry->last_pn, IEEE80211_CCMP_PN_LEN); 23378c2ecf20Sopenharmony_ci for (i = IEEE80211_CCMP_PN_LEN - 1; i >= 0; i--) { 23388c2ecf20Sopenharmony_ci pn[i]++; 23398c2ecf20Sopenharmony_ci if (pn[i]) 23408c2ecf20Sopenharmony_ci break; 23418c2ecf20Sopenharmony_ci } 23428c2ecf20Sopenharmony_ci 23438c2ecf20Sopenharmony_ci rpn = rx->ccm_gcm.pn; 23448c2ecf20Sopenharmony_ci if (memcmp(pn, rpn, IEEE80211_CCMP_PN_LEN)) 23458c2ecf20Sopenharmony_ci return RX_DROP_UNUSABLE; 23468c2ecf20Sopenharmony_ci memcpy(entry->last_pn, pn, IEEE80211_CCMP_PN_LEN); 23478c2ecf20Sopenharmony_ci } else if (entry->is_protected && 23488c2ecf20Sopenharmony_ci (!rx->key || 23498c2ecf20Sopenharmony_ci (!ieee80211_has_protected(fc) && 23508c2ecf20Sopenharmony_ci !(status->flag & RX_FLAG_DECRYPTED)) || 23518c2ecf20Sopenharmony_ci rx->key->color != entry->key_color)) { 23528c2ecf20Sopenharmony_ci /* Drop this as a mixed key or fragment cache attack, even 23538c2ecf20Sopenharmony_ci * if for TKIP Michael MIC should protect us, and WEP is a 23548c2ecf20Sopenharmony_ci * lost cause anyway. 23558c2ecf20Sopenharmony_ci */ 23568c2ecf20Sopenharmony_ci return RX_DROP_UNUSABLE; 23578c2ecf20Sopenharmony_ci } else if (entry->is_protected && rx->key && 23588c2ecf20Sopenharmony_ci entry->key_color != rx->key->color && 23598c2ecf20Sopenharmony_ci (status->flag & RX_FLAG_DECRYPTED)) { 23608c2ecf20Sopenharmony_ci return RX_DROP_UNUSABLE; 23618c2ecf20Sopenharmony_ci } 23628c2ecf20Sopenharmony_ci 23638c2ecf20Sopenharmony_ci skb_pull(rx->skb, ieee80211_hdrlen(fc)); 23648c2ecf20Sopenharmony_ci __skb_queue_tail(&entry->skb_list, rx->skb); 23658c2ecf20Sopenharmony_ci entry->last_frag = frag; 23668c2ecf20Sopenharmony_ci entry->extra_len += rx->skb->len; 23678c2ecf20Sopenharmony_ci if (ieee80211_has_morefrags(fc)) { 23688c2ecf20Sopenharmony_ci rx->skb = NULL; 23698c2ecf20Sopenharmony_ci return RX_QUEUED; 23708c2ecf20Sopenharmony_ci } 23718c2ecf20Sopenharmony_ci 23728c2ecf20Sopenharmony_ci rx->skb = __skb_dequeue(&entry->skb_list); 23738c2ecf20Sopenharmony_ci if (skb_tailroom(rx->skb) < entry->extra_len) { 23748c2ecf20Sopenharmony_ci I802_DEBUG_INC(rx->local->rx_expand_skb_head_defrag); 23758c2ecf20Sopenharmony_ci if (unlikely(pskb_expand_head(rx->skb, 0, entry->extra_len, 23768c2ecf20Sopenharmony_ci GFP_ATOMIC))) { 23778c2ecf20Sopenharmony_ci I802_DEBUG_INC(rx->local->rx_handlers_drop_defrag); 23788c2ecf20Sopenharmony_ci __skb_queue_purge(&entry->skb_list); 23798c2ecf20Sopenharmony_ci return RX_DROP_UNUSABLE; 23808c2ecf20Sopenharmony_ci } 23818c2ecf20Sopenharmony_ci } 23828c2ecf20Sopenharmony_ci while ((skb = __skb_dequeue(&entry->skb_list))) { 23838c2ecf20Sopenharmony_ci skb_put_data(rx->skb, skb->data, skb->len); 23848c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 23858c2ecf20Sopenharmony_ci } 23868c2ecf20Sopenharmony_ci 23878c2ecf20Sopenharmony_ci out: 23888c2ecf20Sopenharmony_ci ieee80211_led_rx(rx->local); 23898c2ecf20Sopenharmony_ci if (rx->sta) 23908c2ecf20Sopenharmony_ci rx->sta->rx_stats.packets++; 23918c2ecf20Sopenharmony_ci return RX_CONTINUE; 23928c2ecf20Sopenharmony_ci} 23938c2ecf20Sopenharmony_ci 23948c2ecf20Sopenharmony_cistatic int ieee80211_802_1x_port_control(struct ieee80211_rx_data *rx) 23958c2ecf20Sopenharmony_ci{ 23968c2ecf20Sopenharmony_ci if (unlikely(!rx->sta || !test_sta_flag(rx->sta, WLAN_STA_AUTHORIZED))) 23978c2ecf20Sopenharmony_ci return -EACCES; 23988c2ecf20Sopenharmony_ci 23998c2ecf20Sopenharmony_ci return 0; 24008c2ecf20Sopenharmony_ci} 24018c2ecf20Sopenharmony_ci 24028c2ecf20Sopenharmony_cistatic int ieee80211_drop_unencrypted(struct ieee80211_rx_data *rx, __le16 fc) 24038c2ecf20Sopenharmony_ci{ 24048c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr = (void *)rx->skb->data; 24058c2ecf20Sopenharmony_ci struct sk_buff *skb = rx->skb; 24068c2ecf20Sopenharmony_ci struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); 24078c2ecf20Sopenharmony_ci 24088c2ecf20Sopenharmony_ci /* 24098c2ecf20Sopenharmony_ci * Pass through unencrypted frames if the hardware has 24108c2ecf20Sopenharmony_ci * decrypted them already. 24118c2ecf20Sopenharmony_ci */ 24128c2ecf20Sopenharmony_ci if (status->flag & RX_FLAG_DECRYPTED) 24138c2ecf20Sopenharmony_ci return 0; 24148c2ecf20Sopenharmony_ci 24158c2ecf20Sopenharmony_ci /* check mesh EAPOL frames first */ 24168c2ecf20Sopenharmony_ci if (unlikely(rx->sta && ieee80211_vif_is_mesh(&rx->sdata->vif) && 24178c2ecf20Sopenharmony_ci ieee80211_is_data(fc))) { 24188c2ecf20Sopenharmony_ci struct ieee80211s_hdr *mesh_hdr; 24198c2ecf20Sopenharmony_ci u16 hdr_len = ieee80211_hdrlen(fc); 24208c2ecf20Sopenharmony_ci u16 ethertype_offset; 24218c2ecf20Sopenharmony_ci __be16 ethertype; 24228c2ecf20Sopenharmony_ci 24238c2ecf20Sopenharmony_ci if (!ether_addr_equal(hdr->addr1, rx->sdata->vif.addr)) 24248c2ecf20Sopenharmony_ci goto drop_check; 24258c2ecf20Sopenharmony_ci 24268c2ecf20Sopenharmony_ci /* make sure fixed part of mesh header is there, also checks skb len */ 24278c2ecf20Sopenharmony_ci if (!pskb_may_pull(rx->skb, hdr_len + 6)) 24288c2ecf20Sopenharmony_ci goto drop_check; 24298c2ecf20Sopenharmony_ci 24308c2ecf20Sopenharmony_ci mesh_hdr = (struct ieee80211s_hdr *)(skb->data + hdr_len); 24318c2ecf20Sopenharmony_ci ethertype_offset = hdr_len + ieee80211_get_mesh_hdrlen(mesh_hdr) + 24328c2ecf20Sopenharmony_ci sizeof(rfc1042_header); 24338c2ecf20Sopenharmony_ci 24348c2ecf20Sopenharmony_ci if (skb_copy_bits(rx->skb, ethertype_offset, ðertype, 2) == 0 && 24358c2ecf20Sopenharmony_ci ethertype == rx->sdata->control_port_protocol) 24368c2ecf20Sopenharmony_ci return 0; 24378c2ecf20Sopenharmony_ci } 24388c2ecf20Sopenharmony_ci 24398c2ecf20Sopenharmony_cidrop_check: 24408c2ecf20Sopenharmony_ci /* Drop unencrypted frames if key is set. */ 24418c2ecf20Sopenharmony_ci if (unlikely(!ieee80211_has_protected(fc) && 24428c2ecf20Sopenharmony_ci !ieee80211_is_any_nullfunc(fc) && 24438c2ecf20Sopenharmony_ci ieee80211_is_data(fc) && rx->key)) 24448c2ecf20Sopenharmony_ci return -EACCES; 24458c2ecf20Sopenharmony_ci 24468c2ecf20Sopenharmony_ci return 0; 24478c2ecf20Sopenharmony_ci} 24488c2ecf20Sopenharmony_ci 24498c2ecf20Sopenharmony_cistatic int ieee80211_drop_unencrypted_mgmt(struct ieee80211_rx_data *rx) 24508c2ecf20Sopenharmony_ci{ 24518c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; 24528c2ecf20Sopenharmony_ci struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); 24538c2ecf20Sopenharmony_ci __le16 fc = hdr->frame_control; 24548c2ecf20Sopenharmony_ci 24558c2ecf20Sopenharmony_ci /* 24568c2ecf20Sopenharmony_ci * Pass through unencrypted frames if the hardware has 24578c2ecf20Sopenharmony_ci * decrypted them already. 24588c2ecf20Sopenharmony_ci */ 24598c2ecf20Sopenharmony_ci if (status->flag & RX_FLAG_DECRYPTED) 24608c2ecf20Sopenharmony_ci return 0; 24618c2ecf20Sopenharmony_ci 24628c2ecf20Sopenharmony_ci if (rx->sta && test_sta_flag(rx->sta, WLAN_STA_MFP)) { 24638c2ecf20Sopenharmony_ci if (unlikely(!ieee80211_has_protected(fc) && 24648c2ecf20Sopenharmony_ci ieee80211_is_unicast_robust_mgmt_frame(rx->skb) && 24658c2ecf20Sopenharmony_ci rx->key)) { 24668c2ecf20Sopenharmony_ci if (ieee80211_is_deauth(fc) || 24678c2ecf20Sopenharmony_ci ieee80211_is_disassoc(fc)) 24688c2ecf20Sopenharmony_ci cfg80211_rx_unprot_mlme_mgmt(rx->sdata->dev, 24698c2ecf20Sopenharmony_ci rx->skb->data, 24708c2ecf20Sopenharmony_ci rx->skb->len); 24718c2ecf20Sopenharmony_ci return -EACCES; 24728c2ecf20Sopenharmony_ci } 24738c2ecf20Sopenharmony_ci /* BIP does not use Protected field, so need to check MMIE */ 24748c2ecf20Sopenharmony_ci if (unlikely(ieee80211_is_multicast_robust_mgmt_frame(rx->skb) && 24758c2ecf20Sopenharmony_ci ieee80211_get_mmie_keyidx(rx->skb) < 0)) { 24768c2ecf20Sopenharmony_ci if (ieee80211_is_deauth(fc) || 24778c2ecf20Sopenharmony_ci ieee80211_is_disassoc(fc)) 24788c2ecf20Sopenharmony_ci cfg80211_rx_unprot_mlme_mgmt(rx->sdata->dev, 24798c2ecf20Sopenharmony_ci rx->skb->data, 24808c2ecf20Sopenharmony_ci rx->skb->len); 24818c2ecf20Sopenharmony_ci return -EACCES; 24828c2ecf20Sopenharmony_ci } 24838c2ecf20Sopenharmony_ci if (unlikely(ieee80211_is_beacon(fc) && rx->key && 24848c2ecf20Sopenharmony_ci ieee80211_get_mmie_keyidx(rx->skb) < 0)) { 24858c2ecf20Sopenharmony_ci cfg80211_rx_unprot_mlme_mgmt(rx->sdata->dev, 24868c2ecf20Sopenharmony_ci rx->skb->data, 24878c2ecf20Sopenharmony_ci rx->skb->len); 24888c2ecf20Sopenharmony_ci return -EACCES; 24898c2ecf20Sopenharmony_ci } 24908c2ecf20Sopenharmony_ci /* 24918c2ecf20Sopenharmony_ci * When using MFP, Action frames are not allowed prior to 24928c2ecf20Sopenharmony_ci * having configured keys. 24938c2ecf20Sopenharmony_ci */ 24948c2ecf20Sopenharmony_ci if (unlikely(ieee80211_is_action(fc) && !rx->key && 24958c2ecf20Sopenharmony_ci ieee80211_is_robust_mgmt_frame(rx->skb))) 24968c2ecf20Sopenharmony_ci return -EACCES; 24978c2ecf20Sopenharmony_ci } 24988c2ecf20Sopenharmony_ci 24998c2ecf20Sopenharmony_ci return 0; 25008c2ecf20Sopenharmony_ci} 25018c2ecf20Sopenharmony_ci 25028c2ecf20Sopenharmony_cistatic int 25038c2ecf20Sopenharmony_ci__ieee80211_data_to_8023(struct ieee80211_rx_data *rx, bool *port_control) 25048c2ecf20Sopenharmony_ci{ 25058c2ecf20Sopenharmony_ci struct ieee80211_sub_if_data *sdata = rx->sdata; 25068c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; 25078c2ecf20Sopenharmony_ci bool check_port_control = false; 25088c2ecf20Sopenharmony_ci struct ethhdr *ehdr; 25098c2ecf20Sopenharmony_ci int ret; 25108c2ecf20Sopenharmony_ci 25118c2ecf20Sopenharmony_ci *port_control = false; 25128c2ecf20Sopenharmony_ci if (ieee80211_has_a4(hdr->frame_control) && 25138c2ecf20Sopenharmony_ci sdata->vif.type == NL80211_IFTYPE_AP_VLAN && !sdata->u.vlan.sta) 25148c2ecf20Sopenharmony_ci return -1; 25158c2ecf20Sopenharmony_ci 25168c2ecf20Sopenharmony_ci if (sdata->vif.type == NL80211_IFTYPE_STATION && 25178c2ecf20Sopenharmony_ci !!sdata->u.mgd.use_4addr != !!ieee80211_has_a4(hdr->frame_control)) { 25188c2ecf20Sopenharmony_ci 25198c2ecf20Sopenharmony_ci if (!sdata->u.mgd.use_4addr) 25208c2ecf20Sopenharmony_ci return -1; 25218c2ecf20Sopenharmony_ci else if (!ether_addr_equal(hdr->addr1, sdata->vif.addr)) 25228c2ecf20Sopenharmony_ci check_port_control = true; 25238c2ecf20Sopenharmony_ci } 25248c2ecf20Sopenharmony_ci 25258c2ecf20Sopenharmony_ci if (is_multicast_ether_addr(hdr->addr1) && 25268c2ecf20Sopenharmony_ci sdata->vif.type == NL80211_IFTYPE_AP_VLAN && sdata->u.vlan.sta) 25278c2ecf20Sopenharmony_ci return -1; 25288c2ecf20Sopenharmony_ci 25298c2ecf20Sopenharmony_ci ret = ieee80211_data_to_8023(rx->skb, sdata->vif.addr, sdata->vif.type); 25308c2ecf20Sopenharmony_ci if (ret < 0) 25318c2ecf20Sopenharmony_ci return ret; 25328c2ecf20Sopenharmony_ci 25338c2ecf20Sopenharmony_ci ehdr = (struct ethhdr *) rx->skb->data; 25348c2ecf20Sopenharmony_ci if (ehdr->h_proto == rx->sdata->control_port_protocol) 25358c2ecf20Sopenharmony_ci *port_control = true; 25368c2ecf20Sopenharmony_ci else if (check_port_control) 25378c2ecf20Sopenharmony_ci return -1; 25388c2ecf20Sopenharmony_ci 25398c2ecf20Sopenharmony_ci return 0; 25408c2ecf20Sopenharmony_ci} 25418c2ecf20Sopenharmony_ci 25428c2ecf20Sopenharmony_ci/* 25438c2ecf20Sopenharmony_ci * requires that rx->skb is a frame with ethernet header 25448c2ecf20Sopenharmony_ci */ 25458c2ecf20Sopenharmony_cistatic bool ieee80211_frame_allowed(struct ieee80211_rx_data *rx, __le16 fc) 25468c2ecf20Sopenharmony_ci{ 25478c2ecf20Sopenharmony_ci static const u8 pae_group_addr[ETH_ALEN] __aligned(2) 25488c2ecf20Sopenharmony_ci = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x03 }; 25498c2ecf20Sopenharmony_ci struct ethhdr *ehdr = (struct ethhdr *) rx->skb->data; 25508c2ecf20Sopenharmony_ci 25518c2ecf20Sopenharmony_ci /* 25528c2ecf20Sopenharmony_ci * Allow EAPOL frames to us/the PAE group address regardless of 25538c2ecf20Sopenharmony_ci * whether the frame was encrypted or not, and always disallow 25548c2ecf20Sopenharmony_ci * all other destination addresses for them. 25558c2ecf20Sopenharmony_ci */ 25568c2ecf20Sopenharmony_ci if (unlikely(ehdr->h_proto == rx->sdata->control_port_protocol)) 25578c2ecf20Sopenharmony_ci return ether_addr_equal(ehdr->h_dest, rx->sdata->vif.addr) || 25588c2ecf20Sopenharmony_ci ether_addr_equal(ehdr->h_dest, pae_group_addr); 25598c2ecf20Sopenharmony_ci 25608c2ecf20Sopenharmony_ci if (ieee80211_802_1x_port_control(rx) || 25618c2ecf20Sopenharmony_ci ieee80211_drop_unencrypted(rx, fc)) 25628c2ecf20Sopenharmony_ci return false; 25638c2ecf20Sopenharmony_ci 25648c2ecf20Sopenharmony_ci return true; 25658c2ecf20Sopenharmony_ci} 25668c2ecf20Sopenharmony_ci 25678c2ecf20Sopenharmony_cistatic void ieee80211_deliver_skb_to_local_stack(struct sk_buff *skb, 25688c2ecf20Sopenharmony_ci struct ieee80211_rx_data *rx) 25698c2ecf20Sopenharmony_ci{ 25708c2ecf20Sopenharmony_ci struct ieee80211_sub_if_data *sdata = rx->sdata; 25718c2ecf20Sopenharmony_ci struct net_device *dev = sdata->dev; 25728c2ecf20Sopenharmony_ci 25738c2ecf20Sopenharmony_ci if (unlikely((skb->protocol == sdata->control_port_protocol || 25748c2ecf20Sopenharmony_ci (skb->protocol == cpu_to_be16(ETH_P_PREAUTH) && 25758c2ecf20Sopenharmony_ci !sdata->control_port_no_preauth)) && 25768c2ecf20Sopenharmony_ci sdata->control_port_over_nl80211)) { 25778c2ecf20Sopenharmony_ci struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); 25788c2ecf20Sopenharmony_ci bool noencrypt = !(status->flag & RX_FLAG_DECRYPTED); 25798c2ecf20Sopenharmony_ci 25808c2ecf20Sopenharmony_ci cfg80211_rx_control_port(dev, skb, noencrypt); 25818c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 25828c2ecf20Sopenharmony_ci } else { 25838c2ecf20Sopenharmony_ci struct ethhdr *ehdr = (void *)skb_mac_header(skb); 25848c2ecf20Sopenharmony_ci 25858c2ecf20Sopenharmony_ci memset(skb->cb, 0, sizeof(skb->cb)); 25868c2ecf20Sopenharmony_ci 25878c2ecf20Sopenharmony_ci /* 25888c2ecf20Sopenharmony_ci * 802.1X over 802.11 requires that the authenticator address 25898c2ecf20Sopenharmony_ci * be used for EAPOL frames. However, 802.1X allows the use of 25908c2ecf20Sopenharmony_ci * the PAE group address instead. If the interface is part of 25918c2ecf20Sopenharmony_ci * a bridge and we pass the frame with the PAE group address, 25928c2ecf20Sopenharmony_ci * then the bridge will forward it to the network (even if the 25938c2ecf20Sopenharmony_ci * client was not associated yet), which isn't supposed to 25948c2ecf20Sopenharmony_ci * happen. 25958c2ecf20Sopenharmony_ci * To avoid that, rewrite the destination address to our own 25968c2ecf20Sopenharmony_ci * address, so that the authenticator (e.g. hostapd) will see 25978c2ecf20Sopenharmony_ci * the frame, but bridge won't forward it anywhere else. Note 25988c2ecf20Sopenharmony_ci * that due to earlier filtering, the only other address can 25998c2ecf20Sopenharmony_ci * be the PAE group address. 26008c2ecf20Sopenharmony_ci */ 26018c2ecf20Sopenharmony_ci if (unlikely(skb->protocol == sdata->control_port_protocol && 26028c2ecf20Sopenharmony_ci !ether_addr_equal(ehdr->h_dest, sdata->vif.addr))) 26038c2ecf20Sopenharmony_ci ether_addr_copy(ehdr->h_dest, sdata->vif.addr); 26048c2ecf20Sopenharmony_ci 26058c2ecf20Sopenharmony_ci /* deliver to local stack */ 26068c2ecf20Sopenharmony_ci if (rx->list) 26078c2ecf20Sopenharmony_ci list_add_tail(&skb->list, rx->list); 26088c2ecf20Sopenharmony_ci else 26098c2ecf20Sopenharmony_ci netif_receive_skb(skb); 26108c2ecf20Sopenharmony_ci } 26118c2ecf20Sopenharmony_ci} 26128c2ecf20Sopenharmony_ci 26138c2ecf20Sopenharmony_ci/* 26148c2ecf20Sopenharmony_ci * requires that rx->skb is a frame with ethernet header 26158c2ecf20Sopenharmony_ci */ 26168c2ecf20Sopenharmony_cistatic void 26178c2ecf20Sopenharmony_ciieee80211_deliver_skb(struct ieee80211_rx_data *rx) 26188c2ecf20Sopenharmony_ci{ 26198c2ecf20Sopenharmony_ci struct ieee80211_sub_if_data *sdata = rx->sdata; 26208c2ecf20Sopenharmony_ci struct net_device *dev = sdata->dev; 26218c2ecf20Sopenharmony_ci struct sk_buff *skb, *xmit_skb; 26228c2ecf20Sopenharmony_ci struct ethhdr *ehdr = (struct ethhdr *) rx->skb->data; 26238c2ecf20Sopenharmony_ci struct sta_info *dsta; 26248c2ecf20Sopenharmony_ci 26258c2ecf20Sopenharmony_ci skb = rx->skb; 26268c2ecf20Sopenharmony_ci xmit_skb = NULL; 26278c2ecf20Sopenharmony_ci 26288c2ecf20Sopenharmony_ci ieee80211_rx_stats(dev, skb->len); 26298c2ecf20Sopenharmony_ci 26308c2ecf20Sopenharmony_ci if (rx->sta) { 26318c2ecf20Sopenharmony_ci /* The seqno index has the same property as needed 26328c2ecf20Sopenharmony_ci * for the rx_msdu field, i.e. it is IEEE80211_NUM_TIDS 26338c2ecf20Sopenharmony_ci * for non-QoS-data frames. Here we know it's a data 26348c2ecf20Sopenharmony_ci * frame, so count MSDUs. 26358c2ecf20Sopenharmony_ci */ 26368c2ecf20Sopenharmony_ci u64_stats_update_begin(&rx->sta->rx_stats.syncp); 26378c2ecf20Sopenharmony_ci rx->sta->rx_stats.msdu[rx->seqno_idx]++; 26388c2ecf20Sopenharmony_ci u64_stats_update_end(&rx->sta->rx_stats.syncp); 26398c2ecf20Sopenharmony_ci } 26408c2ecf20Sopenharmony_ci 26418c2ecf20Sopenharmony_ci if ((sdata->vif.type == NL80211_IFTYPE_AP || 26428c2ecf20Sopenharmony_ci sdata->vif.type == NL80211_IFTYPE_AP_VLAN) && 26438c2ecf20Sopenharmony_ci !(sdata->flags & IEEE80211_SDATA_DONT_BRIDGE_PACKETS) && 26448c2ecf20Sopenharmony_ci ehdr->h_proto != rx->sdata->control_port_protocol && 26458c2ecf20Sopenharmony_ci (sdata->vif.type != NL80211_IFTYPE_AP_VLAN || !sdata->u.vlan.sta)) { 26468c2ecf20Sopenharmony_ci if (is_multicast_ether_addr(ehdr->h_dest) && 26478c2ecf20Sopenharmony_ci ieee80211_vif_get_num_mcast_if(sdata) != 0) { 26488c2ecf20Sopenharmony_ci /* 26498c2ecf20Sopenharmony_ci * send multicast frames both to higher layers in 26508c2ecf20Sopenharmony_ci * local net stack and back to the wireless medium 26518c2ecf20Sopenharmony_ci */ 26528c2ecf20Sopenharmony_ci xmit_skb = skb_copy(skb, GFP_ATOMIC); 26538c2ecf20Sopenharmony_ci if (!xmit_skb) 26548c2ecf20Sopenharmony_ci net_info_ratelimited("%s: failed to clone multicast frame\n", 26558c2ecf20Sopenharmony_ci dev->name); 26568c2ecf20Sopenharmony_ci } else if (!is_multicast_ether_addr(ehdr->h_dest) && 26578c2ecf20Sopenharmony_ci !ether_addr_equal(ehdr->h_dest, ehdr->h_source)) { 26588c2ecf20Sopenharmony_ci dsta = sta_info_get(sdata, ehdr->h_dest); 26598c2ecf20Sopenharmony_ci if (dsta) { 26608c2ecf20Sopenharmony_ci /* 26618c2ecf20Sopenharmony_ci * The destination station is associated to 26628c2ecf20Sopenharmony_ci * this AP (in this VLAN), so send the frame 26638c2ecf20Sopenharmony_ci * directly to it and do not pass it to local 26648c2ecf20Sopenharmony_ci * net stack. 26658c2ecf20Sopenharmony_ci */ 26668c2ecf20Sopenharmony_ci xmit_skb = skb; 26678c2ecf20Sopenharmony_ci skb = NULL; 26688c2ecf20Sopenharmony_ci } 26698c2ecf20Sopenharmony_ci } 26708c2ecf20Sopenharmony_ci } 26718c2ecf20Sopenharmony_ci 26728c2ecf20Sopenharmony_ci#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 26738c2ecf20Sopenharmony_ci if (skb) { 26748c2ecf20Sopenharmony_ci /* 'align' will only take the values 0 or 2 here since all 26758c2ecf20Sopenharmony_ci * frames are required to be aligned to 2-byte boundaries 26768c2ecf20Sopenharmony_ci * when being passed to mac80211; the code here works just 26778c2ecf20Sopenharmony_ci * as well if that isn't true, but mac80211 assumes it can 26788c2ecf20Sopenharmony_ci * access fields as 2-byte aligned (e.g. for ether_addr_equal) 26798c2ecf20Sopenharmony_ci */ 26808c2ecf20Sopenharmony_ci int align; 26818c2ecf20Sopenharmony_ci 26828c2ecf20Sopenharmony_ci align = (unsigned long)(skb->data + sizeof(struct ethhdr)) & 3; 26838c2ecf20Sopenharmony_ci if (align) { 26848c2ecf20Sopenharmony_ci if (WARN_ON(skb_headroom(skb) < 3)) { 26858c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 26868c2ecf20Sopenharmony_ci skb = NULL; 26878c2ecf20Sopenharmony_ci } else { 26888c2ecf20Sopenharmony_ci u8 *data = skb->data; 26898c2ecf20Sopenharmony_ci size_t len = skb_headlen(skb); 26908c2ecf20Sopenharmony_ci skb->data -= align; 26918c2ecf20Sopenharmony_ci memmove(skb->data, data, len); 26928c2ecf20Sopenharmony_ci skb_set_tail_pointer(skb, len); 26938c2ecf20Sopenharmony_ci } 26948c2ecf20Sopenharmony_ci } 26958c2ecf20Sopenharmony_ci } 26968c2ecf20Sopenharmony_ci#endif 26978c2ecf20Sopenharmony_ci 26988c2ecf20Sopenharmony_ci if (skb) { 26998c2ecf20Sopenharmony_ci skb->protocol = eth_type_trans(skb, dev); 27008c2ecf20Sopenharmony_ci ieee80211_deliver_skb_to_local_stack(skb, rx); 27018c2ecf20Sopenharmony_ci } 27028c2ecf20Sopenharmony_ci 27038c2ecf20Sopenharmony_ci if (xmit_skb) { 27048c2ecf20Sopenharmony_ci /* 27058c2ecf20Sopenharmony_ci * Send to wireless media and increase priority by 256 to 27068c2ecf20Sopenharmony_ci * keep the received priority instead of reclassifying 27078c2ecf20Sopenharmony_ci * the frame (see cfg80211_classify8021d). 27088c2ecf20Sopenharmony_ci */ 27098c2ecf20Sopenharmony_ci xmit_skb->priority += 256; 27108c2ecf20Sopenharmony_ci xmit_skb->protocol = htons(ETH_P_802_3); 27118c2ecf20Sopenharmony_ci skb_reset_network_header(xmit_skb); 27128c2ecf20Sopenharmony_ci skb_reset_mac_header(xmit_skb); 27138c2ecf20Sopenharmony_ci dev_queue_xmit(xmit_skb); 27148c2ecf20Sopenharmony_ci } 27158c2ecf20Sopenharmony_ci} 27168c2ecf20Sopenharmony_ci 27178c2ecf20Sopenharmony_cistatic ieee80211_rx_result debug_noinline 27188c2ecf20Sopenharmony_ci__ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx, u8 data_offset) 27198c2ecf20Sopenharmony_ci{ 27208c2ecf20Sopenharmony_ci struct net_device *dev = rx->sdata->dev; 27218c2ecf20Sopenharmony_ci struct sk_buff *skb = rx->skb; 27228c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; 27238c2ecf20Sopenharmony_ci __le16 fc = hdr->frame_control; 27248c2ecf20Sopenharmony_ci struct sk_buff_head frame_list; 27258c2ecf20Sopenharmony_ci struct ethhdr ethhdr; 27268c2ecf20Sopenharmony_ci const u8 *check_da = ethhdr.h_dest, *check_sa = ethhdr.h_source; 27278c2ecf20Sopenharmony_ci 27288c2ecf20Sopenharmony_ci if (unlikely(ieee80211_has_a4(hdr->frame_control))) { 27298c2ecf20Sopenharmony_ci check_da = NULL; 27308c2ecf20Sopenharmony_ci check_sa = NULL; 27318c2ecf20Sopenharmony_ci } else switch (rx->sdata->vif.type) { 27328c2ecf20Sopenharmony_ci case NL80211_IFTYPE_AP: 27338c2ecf20Sopenharmony_ci case NL80211_IFTYPE_AP_VLAN: 27348c2ecf20Sopenharmony_ci check_da = NULL; 27358c2ecf20Sopenharmony_ci break; 27368c2ecf20Sopenharmony_ci case NL80211_IFTYPE_STATION: 27378c2ecf20Sopenharmony_ci if (!rx->sta || 27388c2ecf20Sopenharmony_ci !test_sta_flag(rx->sta, WLAN_STA_TDLS_PEER)) 27398c2ecf20Sopenharmony_ci check_sa = NULL; 27408c2ecf20Sopenharmony_ci break; 27418c2ecf20Sopenharmony_ci case NL80211_IFTYPE_MESH_POINT: 27428c2ecf20Sopenharmony_ci check_sa = NULL; 27438c2ecf20Sopenharmony_ci break; 27448c2ecf20Sopenharmony_ci default: 27458c2ecf20Sopenharmony_ci break; 27468c2ecf20Sopenharmony_ci } 27478c2ecf20Sopenharmony_ci 27488c2ecf20Sopenharmony_ci skb->dev = dev; 27498c2ecf20Sopenharmony_ci __skb_queue_head_init(&frame_list); 27508c2ecf20Sopenharmony_ci 27518c2ecf20Sopenharmony_ci if (ieee80211_data_to_8023_exthdr(skb, ðhdr, 27528c2ecf20Sopenharmony_ci rx->sdata->vif.addr, 27538c2ecf20Sopenharmony_ci rx->sdata->vif.type, 27548c2ecf20Sopenharmony_ci data_offset, true)) 27558c2ecf20Sopenharmony_ci return RX_DROP_UNUSABLE; 27568c2ecf20Sopenharmony_ci 27578c2ecf20Sopenharmony_ci ieee80211_amsdu_to_8023s(skb, &frame_list, dev->dev_addr, 27588c2ecf20Sopenharmony_ci rx->sdata->vif.type, 27598c2ecf20Sopenharmony_ci rx->local->hw.extra_tx_headroom, 27608c2ecf20Sopenharmony_ci check_da, check_sa); 27618c2ecf20Sopenharmony_ci 27628c2ecf20Sopenharmony_ci while (!skb_queue_empty(&frame_list)) { 27638c2ecf20Sopenharmony_ci rx->skb = __skb_dequeue(&frame_list); 27648c2ecf20Sopenharmony_ci 27658c2ecf20Sopenharmony_ci if (!ieee80211_frame_allowed(rx, fc)) { 27668c2ecf20Sopenharmony_ci dev_kfree_skb(rx->skb); 27678c2ecf20Sopenharmony_ci continue; 27688c2ecf20Sopenharmony_ci } 27698c2ecf20Sopenharmony_ci 27708c2ecf20Sopenharmony_ci ieee80211_deliver_skb(rx); 27718c2ecf20Sopenharmony_ci } 27728c2ecf20Sopenharmony_ci 27738c2ecf20Sopenharmony_ci return RX_QUEUED; 27748c2ecf20Sopenharmony_ci} 27758c2ecf20Sopenharmony_ci 27768c2ecf20Sopenharmony_cistatic ieee80211_rx_result debug_noinline 27778c2ecf20Sopenharmony_ciieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx) 27788c2ecf20Sopenharmony_ci{ 27798c2ecf20Sopenharmony_ci struct sk_buff *skb = rx->skb; 27808c2ecf20Sopenharmony_ci struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); 27818c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; 27828c2ecf20Sopenharmony_ci __le16 fc = hdr->frame_control; 27838c2ecf20Sopenharmony_ci 27848c2ecf20Sopenharmony_ci if (!(status->rx_flags & IEEE80211_RX_AMSDU)) 27858c2ecf20Sopenharmony_ci return RX_CONTINUE; 27868c2ecf20Sopenharmony_ci 27878c2ecf20Sopenharmony_ci if (unlikely(!ieee80211_is_data(fc))) 27888c2ecf20Sopenharmony_ci return RX_CONTINUE; 27898c2ecf20Sopenharmony_ci 27908c2ecf20Sopenharmony_ci if (unlikely(!ieee80211_is_data_present(fc))) 27918c2ecf20Sopenharmony_ci return RX_DROP_MONITOR; 27928c2ecf20Sopenharmony_ci 27938c2ecf20Sopenharmony_ci if (unlikely(ieee80211_has_a4(hdr->frame_control))) { 27948c2ecf20Sopenharmony_ci switch (rx->sdata->vif.type) { 27958c2ecf20Sopenharmony_ci case NL80211_IFTYPE_AP_VLAN: 27968c2ecf20Sopenharmony_ci if (!rx->sdata->u.vlan.sta) 27978c2ecf20Sopenharmony_ci return RX_DROP_UNUSABLE; 27988c2ecf20Sopenharmony_ci break; 27998c2ecf20Sopenharmony_ci case NL80211_IFTYPE_STATION: 28008c2ecf20Sopenharmony_ci if (!rx->sdata->u.mgd.use_4addr) 28018c2ecf20Sopenharmony_ci return RX_DROP_UNUSABLE; 28028c2ecf20Sopenharmony_ci break; 28038c2ecf20Sopenharmony_ci default: 28048c2ecf20Sopenharmony_ci return RX_DROP_UNUSABLE; 28058c2ecf20Sopenharmony_ci } 28068c2ecf20Sopenharmony_ci } 28078c2ecf20Sopenharmony_ci 28088c2ecf20Sopenharmony_ci if (is_multicast_ether_addr(hdr->addr1)) 28098c2ecf20Sopenharmony_ci return RX_DROP_UNUSABLE; 28108c2ecf20Sopenharmony_ci 28118c2ecf20Sopenharmony_ci if (rx->key) { 28128c2ecf20Sopenharmony_ci /* 28138c2ecf20Sopenharmony_ci * We should not receive A-MSDUs on pre-HT connections, 28148c2ecf20Sopenharmony_ci * and HT connections cannot use old ciphers. Thus drop 28158c2ecf20Sopenharmony_ci * them, as in those cases we couldn't even have SPP 28168c2ecf20Sopenharmony_ci * A-MSDUs or such. 28178c2ecf20Sopenharmony_ci */ 28188c2ecf20Sopenharmony_ci switch (rx->key->conf.cipher) { 28198c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_WEP40: 28208c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_WEP104: 28218c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_TKIP: 28228c2ecf20Sopenharmony_ci return RX_DROP_UNUSABLE; 28238c2ecf20Sopenharmony_ci default: 28248c2ecf20Sopenharmony_ci break; 28258c2ecf20Sopenharmony_ci } 28268c2ecf20Sopenharmony_ci } 28278c2ecf20Sopenharmony_ci 28288c2ecf20Sopenharmony_ci return __ieee80211_rx_h_amsdu(rx, 0); 28298c2ecf20Sopenharmony_ci} 28308c2ecf20Sopenharmony_ci 28318c2ecf20Sopenharmony_ci#ifdef CONFIG_MAC80211_MESH 28328c2ecf20Sopenharmony_cistatic ieee80211_rx_result 28338c2ecf20Sopenharmony_ciieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) 28348c2ecf20Sopenharmony_ci{ 28358c2ecf20Sopenharmony_ci struct ieee80211_hdr *fwd_hdr, *hdr; 28368c2ecf20Sopenharmony_ci struct ieee80211_tx_info *info; 28378c2ecf20Sopenharmony_ci struct ieee80211s_hdr *mesh_hdr; 28388c2ecf20Sopenharmony_ci struct sk_buff *skb = rx->skb, *fwd_skb; 28398c2ecf20Sopenharmony_ci struct ieee80211_local *local = rx->local; 28408c2ecf20Sopenharmony_ci struct ieee80211_sub_if_data *sdata = rx->sdata; 28418c2ecf20Sopenharmony_ci struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; 28428c2ecf20Sopenharmony_ci u16 ac, q, hdrlen; 28438c2ecf20Sopenharmony_ci int tailroom = 0; 28448c2ecf20Sopenharmony_ci 28458c2ecf20Sopenharmony_ci hdr = (struct ieee80211_hdr *) skb->data; 28468c2ecf20Sopenharmony_ci hdrlen = ieee80211_hdrlen(hdr->frame_control); 28478c2ecf20Sopenharmony_ci 28488c2ecf20Sopenharmony_ci /* make sure fixed part of mesh header is there, also checks skb len */ 28498c2ecf20Sopenharmony_ci if (!pskb_may_pull(rx->skb, hdrlen + 6)) 28508c2ecf20Sopenharmony_ci return RX_DROP_MONITOR; 28518c2ecf20Sopenharmony_ci 28528c2ecf20Sopenharmony_ci mesh_hdr = (struct ieee80211s_hdr *) (skb->data + hdrlen); 28538c2ecf20Sopenharmony_ci 28548c2ecf20Sopenharmony_ci /* make sure full mesh header is there, also checks skb len */ 28558c2ecf20Sopenharmony_ci if (!pskb_may_pull(rx->skb, 28568c2ecf20Sopenharmony_ci hdrlen + ieee80211_get_mesh_hdrlen(mesh_hdr))) 28578c2ecf20Sopenharmony_ci return RX_DROP_MONITOR; 28588c2ecf20Sopenharmony_ci 28598c2ecf20Sopenharmony_ci /* reload pointers */ 28608c2ecf20Sopenharmony_ci hdr = (struct ieee80211_hdr *) skb->data; 28618c2ecf20Sopenharmony_ci mesh_hdr = (struct ieee80211s_hdr *) (skb->data + hdrlen); 28628c2ecf20Sopenharmony_ci 28638c2ecf20Sopenharmony_ci if (ieee80211_drop_unencrypted(rx, hdr->frame_control)) 28648c2ecf20Sopenharmony_ci return RX_DROP_MONITOR; 28658c2ecf20Sopenharmony_ci 28668c2ecf20Sopenharmony_ci /* frame is in RMC, don't forward */ 28678c2ecf20Sopenharmony_ci if (ieee80211_is_data(hdr->frame_control) && 28688c2ecf20Sopenharmony_ci is_multicast_ether_addr(hdr->addr1) && 28698c2ecf20Sopenharmony_ci mesh_rmc_check(rx->sdata, hdr->addr3, mesh_hdr)) 28708c2ecf20Sopenharmony_ci return RX_DROP_MONITOR; 28718c2ecf20Sopenharmony_ci 28728c2ecf20Sopenharmony_ci if (!ieee80211_is_data(hdr->frame_control)) 28738c2ecf20Sopenharmony_ci return RX_CONTINUE; 28748c2ecf20Sopenharmony_ci 28758c2ecf20Sopenharmony_ci if (!mesh_hdr->ttl) 28768c2ecf20Sopenharmony_ci return RX_DROP_MONITOR; 28778c2ecf20Sopenharmony_ci 28788c2ecf20Sopenharmony_ci if (mesh_hdr->flags & MESH_FLAGS_AE) { 28798c2ecf20Sopenharmony_ci struct mesh_path *mppath; 28808c2ecf20Sopenharmony_ci char *proxied_addr; 28818c2ecf20Sopenharmony_ci char *mpp_addr; 28828c2ecf20Sopenharmony_ci 28838c2ecf20Sopenharmony_ci if (is_multicast_ether_addr(hdr->addr1)) { 28848c2ecf20Sopenharmony_ci mpp_addr = hdr->addr3; 28858c2ecf20Sopenharmony_ci proxied_addr = mesh_hdr->eaddr1; 28868c2ecf20Sopenharmony_ci } else if ((mesh_hdr->flags & MESH_FLAGS_AE) == 28878c2ecf20Sopenharmony_ci MESH_FLAGS_AE_A5_A6) { 28888c2ecf20Sopenharmony_ci /* has_a4 already checked in ieee80211_rx_mesh_check */ 28898c2ecf20Sopenharmony_ci mpp_addr = hdr->addr4; 28908c2ecf20Sopenharmony_ci proxied_addr = mesh_hdr->eaddr2; 28918c2ecf20Sopenharmony_ci } else { 28928c2ecf20Sopenharmony_ci return RX_DROP_MONITOR; 28938c2ecf20Sopenharmony_ci } 28948c2ecf20Sopenharmony_ci 28958c2ecf20Sopenharmony_ci rcu_read_lock(); 28968c2ecf20Sopenharmony_ci mppath = mpp_path_lookup(sdata, proxied_addr); 28978c2ecf20Sopenharmony_ci if (!mppath) { 28988c2ecf20Sopenharmony_ci mpp_path_add(sdata, proxied_addr, mpp_addr); 28998c2ecf20Sopenharmony_ci } else { 29008c2ecf20Sopenharmony_ci spin_lock_bh(&mppath->state_lock); 29018c2ecf20Sopenharmony_ci if (!ether_addr_equal(mppath->mpp, mpp_addr)) 29028c2ecf20Sopenharmony_ci memcpy(mppath->mpp, mpp_addr, ETH_ALEN); 29038c2ecf20Sopenharmony_ci mppath->exp_time = jiffies; 29048c2ecf20Sopenharmony_ci spin_unlock_bh(&mppath->state_lock); 29058c2ecf20Sopenharmony_ci } 29068c2ecf20Sopenharmony_ci rcu_read_unlock(); 29078c2ecf20Sopenharmony_ci } 29088c2ecf20Sopenharmony_ci 29098c2ecf20Sopenharmony_ci /* Frame has reached destination. Don't forward */ 29108c2ecf20Sopenharmony_ci if (!is_multicast_ether_addr(hdr->addr1) && 29118c2ecf20Sopenharmony_ci ether_addr_equal(sdata->vif.addr, hdr->addr3)) 29128c2ecf20Sopenharmony_ci return RX_CONTINUE; 29138c2ecf20Sopenharmony_ci 29148c2ecf20Sopenharmony_ci ac = ieee802_1d_to_ac[skb->priority]; 29158c2ecf20Sopenharmony_ci q = sdata->vif.hw_queue[ac]; 29168c2ecf20Sopenharmony_ci if (ieee80211_queue_stopped(&local->hw, q)) { 29178c2ecf20Sopenharmony_ci IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_congestion); 29188c2ecf20Sopenharmony_ci return RX_DROP_MONITOR; 29198c2ecf20Sopenharmony_ci } 29208c2ecf20Sopenharmony_ci skb_set_queue_mapping(skb, ac); 29218c2ecf20Sopenharmony_ci 29228c2ecf20Sopenharmony_ci if (!--mesh_hdr->ttl) { 29238c2ecf20Sopenharmony_ci if (!is_multicast_ether_addr(hdr->addr1)) 29248c2ecf20Sopenharmony_ci IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, 29258c2ecf20Sopenharmony_ci dropped_frames_ttl); 29268c2ecf20Sopenharmony_ci goto out; 29278c2ecf20Sopenharmony_ci } 29288c2ecf20Sopenharmony_ci 29298c2ecf20Sopenharmony_ci if (!ifmsh->mshcfg.dot11MeshForwarding) 29308c2ecf20Sopenharmony_ci goto out; 29318c2ecf20Sopenharmony_ci 29328c2ecf20Sopenharmony_ci if (sdata->crypto_tx_tailroom_needed_cnt) 29338c2ecf20Sopenharmony_ci tailroom = IEEE80211_ENCRYPT_TAILROOM; 29348c2ecf20Sopenharmony_ci 29358c2ecf20Sopenharmony_ci fwd_skb = skb_copy_expand(skb, local->tx_headroom + 29368c2ecf20Sopenharmony_ci sdata->encrypt_headroom, 29378c2ecf20Sopenharmony_ci tailroom, GFP_ATOMIC); 29388c2ecf20Sopenharmony_ci if (!fwd_skb) 29398c2ecf20Sopenharmony_ci goto out; 29408c2ecf20Sopenharmony_ci 29418c2ecf20Sopenharmony_ci fwd_hdr = (struct ieee80211_hdr *) fwd_skb->data; 29428c2ecf20Sopenharmony_ci fwd_hdr->frame_control &= ~cpu_to_le16(IEEE80211_FCTL_RETRY); 29438c2ecf20Sopenharmony_ci info = IEEE80211_SKB_CB(fwd_skb); 29448c2ecf20Sopenharmony_ci memset(info, 0, sizeof(*info)); 29458c2ecf20Sopenharmony_ci info->control.flags |= IEEE80211_TX_INTCFL_NEED_TXPROCESSING; 29468c2ecf20Sopenharmony_ci info->control.vif = &rx->sdata->vif; 29478c2ecf20Sopenharmony_ci info->control.jiffies = jiffies; 29488c2ecf20Sopenharmony_ci if (is_multicast_ether_addr(fwd_hdr->addr1)) { 29498c2ecf20Sopenharmony_ci IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_mcast); 29508c2ecf20Sopenharmony_ci memcpy(fwd_hdr->addr2, sdata->vif.addr, ETH_ALEN); 29518c2ecf20Sopenharmony_ci /* update power mode indication when forwarding */ 29528c2ecf20Sopenharmony_ci ieee80211_mps_set_frame_flags(sdata, NULL, fwd_hdr); 29538c2ecf20Sopenharmony_ci } else if (!mesh_nexthop_lookup(sdata, fwd_skb)) { 29548c2ecf20Sopenharmony_ci /* mesh power mode flags updated in mesh_nexthop_lookup */ 29558c2ecf20Sopenharmony_ci IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_unicast); 29568c2ecf20Sopenharmony_ci } else { 29578c2ecf20Sopenharmony_ci /* unable to resolve next hop */ 29588c2ecf20Sopenharmony_ci mesh_path_error_tx(sdata, ifmsh->mshcfg.element_ttl, 29598c2ecf20Sopenharmony_ci fwd_hdr->addr3, 0, 29608c2ecf20Sopenharmony_ci WLAN_REASON_MESH_PATH_NOFORWARD, 29618c2ecf20Sopenharmony_ci fwd_hdr->addr2); 29628c2ecf20Sopenharmony_ci IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_no_route); 29638c2ecf20Sopenharmony_ci kfree_skb(fwd_skb); 29648c2ecf20Sopenharmony_ci return RX_DROP_MONITOR; 29658c2ecf20Sopenharmony_ci } 29668c2ecf20Sopenharmony_ci 29678c2ecf20Sopenharmony_ci IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_frames); 29688c2ecf20Sopenharmony_ci ieee80211_add_pending_skb(local, fwd_skb); 29698c2ecf20Sopenharmony_ci out: 29708c2ecf20Sopenharmony_ci if (is_multicast_ether_addr(hdr->addr1)) 29718c2ecf20Sopenharmony_ci return RX_CONTINUE; 29728c2ecf20Sopenharmony_ci return RX_DROP_MONITOR; 29738c2ecf20Sopenharmony_ci} 29748c2ecf20Sopenharmony_ci#endif 29758c2ecf20Sopenharmony_ci 29768c2ecf20Sopenharmony_cistatic ieee80211_rx_result debug_noinline 29778c2ecf20Sopenharmony_ciieee80211_rx_h_data(struct ieee80211_rx_data *rx) 29788c2ecf20Sopenharmony_ci{ 29798c2ecf20Sopenharmony_ci struct ieee80211_sub_if_data *sdata = rx->sdata; 29808c2ecf20Sopenharmony_ci struct ieee80211_local *local = rx->local; 29818c2ecf20Sopenharmony_ci struct net_device *dev = sdata->dev; 29828c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; 29838c2ecf20Sopenharmony_ci __le16 fc = hdr->frame_control; 29848c2ecf20Sopenharmony_ci bool port_control; 29858c2ecf20Sopenharmony_ci int err; 29868c2ecf20Sopenharmony_ci 29878c2ecf20Sopenharmony_ci if (unlikely(!ieee80211_is_data(hdr->frame_control))) 29888c2ecf20Sopenharmony_ci return RX_CONTINUE; 29898c2ecf20Sopenharmony_ci 29908c2ecf20Sopenharmony_ci if (unlikely(!ieee80211_is_data_present(hdr->frame_control))) 29918c2ecf20Sopenharmony_ci return RX_DROP_MONITOR; 29928c2ecf20Sopenharmony_ci 29938c2ecf20Sopenharmony_ci /* 29948c2ecf20Sopenharmony_ci * Send unexpected-4addr-frame event to hostapd. For older versions, 29958c2ecf20Sopenharmony_ci * also drop the frame to cooked monitor interfaces. 29968c2ecf20Sopenharmony_ci */ 29978c2ecf20Sopenharmony_ci if (ieee80211_has_a4(hdr->frame_control) && 29988c2ecf20Sopenharmony_ci sdata->vif.type == NL80211_IFTYPE_AP) { 29998c2ecf20Sopenharmony_ci if (rx->sta && 30008c2ecf20Sopenharmony_ci !test_and_set_sta_flag(rx->sta, WLAN_STA_4ADDR_EVENT)) 30018c2ecf20Sopenharmony_ci cfg80211_rx_unexpected_4addr_frame( 30028c2ecf20Sopenharmony_ci rx->sdata->dev, rx->sta->sta.addr, GFP_ATOMIC); 30038c2ecf20Sopenharmony_ci return RX_DROP_MONITOR; 30048c2ecf20Sopenharmony_ci } 30058c2ecf20Sopenharmony_ci 30068c2ecf20Sopenharmony_ci err = __ieee80211_data_to_8023(rx, &port_control); 30078c2ecf20Sopenharmony_ci if (unlikely(err)) 30088c2ecf20Sopenharmony_ci return RX_DROP_UNUSABLE; 30098c2ecf20Sopenharmony_ci 30108c2ecf20Sopenharmony_ci if (!ieee80211_frame_allowed(rx, fc)) 30118c2ecf20Sopenharmony_ci return RX_DROP_MONITOR; 30128c2ecf20Sopenharmony_ci 30138c2ecf20Sopenharmony_ci /* directly handle TDLS channel switch requests/responses */ 30148c2ecf20Sopenharmony_ci if (unlikely(((struct ethhdr *)rx->skb->data)->h_proto == 30158c2ecf20Sopenharmony_ci cpu_to_be16(ETH_P_TDLS))) { 30168c2ecf20Sopenharmony_ci struct ieee80211_tdls_data *tf = (void *)rx->skb->data; 30178c2ecf20Sopenharmony_ci 30188c2ecf20Sopenharmony_ci if (pskb_may_pull(rx->skb, 30198c2ecf20Sopenharmony_ci offsetof(struct ieee80211_tdls_data, u)) && 30208c2ecf20Sopenharmony_ci tf->payload_type == WLAN_TDLS_SNAP_RFTYPE && 30218c2ecf20Sopenharmony_ci tf->category == WLAN_CATEGORY_TDLS && 30228c2ecf20Sopenharmony_ci (tf->action_code == WLAN_TDLS_CHANNEL_SWITCH_REQUEST || 30238c2ecf20Sopenharmony_ci tf->action_code == WLAN_TDLS_CHANNEL_SWITCH_RESPONSE)) { 30248c2ecf20Sopenharmony_ci skb_queue_tail(&local->skb_queue_tdls_chsw, rx->skb); 30258c2ecf20Sopenharmony_ci schedule_work(&local->tdls_chsw_work); 30268c2ecf20Sopenharmony_ci if (rx->sta) 30278c2ecf20Sopenharmony_ci rx->sta->rx_stats.packets++; 30288c2ecf20Sopenharmony_ci 30298c2ecf20Sopenharmony_ci return RX_QUEUED; 30308c2ecf20Sopenharmony_ci } 30318c2ecf20Sopenharmony_ci } 30328c2ecf20Sopenharmony_ci 30338c2ecf20Sopenharmony_ci if (rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN && 30348c2ecf20Sopenharmony_ci unlikely(port_control) && sdata->bss) { 30358c2ecf20Sopenharmony_ci sdata = container_of(sdata->bss, struct ieee80211_sub_if_data, 30368c2ecf20Sopenharmony_ci u.ap); 30378c2ecf20Sopenharmony_ci dev = sdata->dev; 30388c2ecf20Sopenharmony_ci rx->sdata = sdata; 30398c2ecf20Sopenharmony_ci } 30408c2ecf20Sopenharmony_ci 30418c2ecf20Sopenharmony_ci rx->skb->dev = dev; 30428c2ecf20Sopenharmony_ci 30438c2ecf20Sopenharmony_ci if (!ieee80211_hw_check(&local->hw, SUPPORTS_DYNAMIC_PS) && 30448c2ecf20Sopenharmony_ci local->ps_sdata && local->hw.conf.dynamic_ps_timeout > 0 && 30458c2ecf20Sopenharmony_ci !is_multicast_ether_addr( 30468c2ecf20Sopenharmony_ci ((struct ethhdr *)rx->skb->data)->h_dest) && 30478c2ecf20Sopenharmony_ci (!local->scanning && 30488c2ecf20Sopenharmony_ci !test_bit(SDATA_STATE_OFFCHANNEL, &sdata->state))) 30498c2ecf20Sopenharmony_ci mod_timer(&local->dynamic_ps_timer, jiffies + 30508c2ecf20Sopenharmony_ci msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout)); 30518c2ecf20Sopenharmony_ci 30528c2ecf20Sopenharmony_ci ieee80211_deliver_skb(rx); 30538c2ecf20Sopenharmony_ci 30548c2ecf20Sopenharmony_ci return RX_QUEUED; 30558c2ecf20Sopenharmony_ci} 30568c2ecf20Sopenharmony_ci 30578c2ecf20Sopenharmony_cistatic ieee80211_rx_result debug_noinline 30588c2ecf20Sopenharmony_ciieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx, struct sk_buff_head *frames) 30598c2ecf20Sopenharmony_ci{ 30608c2ecf20Sopenharmony_ci struct sk_buff *skb = rx->skb; 30618c2ecf20Sopenharmony_ci struct ieee80211_bar *bar = (struct ieee80211_bar *)skb->data; 30628c2ecf20Sopenharmony_ci struct tid_ampdu_rx *tid_agg_rx; 30638c2ecf20Sopenharmony_ci u16 start_seq_num; 30648c2ecf20Sopenharmony_ci u16 tid; 30658c2ecf20Sopenharmony_ci 30668c2ecf20Sopenharmony_ci if (likely(!ieee80211_is_ctl(bar->frame_control))) 30678c2ecf20Sopenharmony_ci return RX_CONTINUE; 30688c2ecf20Sopenharmony_ci 30698c2ecf20Sopenharmony_ci if (ieee80211_is_back_req(bar->frame_control)) { 30708c2ecf20Sopenharmony_ci struct { 30718c2ecf20Sopenharmony_ci __le16 control, start_seq_num; 30728c2ecf20Sopenharmony_ci } __packed bar_data; 30738c2ecf20Sopenharmony_ci struct ieee80211_event event = { 30748c2ecf20Sopenharmony_ci .type = BAR_RX_EVENT, 30758c2ecf20Sopenharmony_ci }; 30768c2ecf20Sopenharmony_ci 30778c2ecf20Sopenharmony_ci if (!rx->sta) 30788c2ecf20Sopenharmony_ci return RX_DROP_MONITOR; 30798c2ecf20Sopenharmony_ci 30808c2ecf20Sopenharmony_ci if (skb_copy_bits(skb, offsetof(struct ieee80211_bar, control), 30818c2ecf20Sopenharmony_ci &bar_data, sizeof(bar_data))) 30828c2ecf20Sopenharmony_ci return RX_DROP_MONITOR; 30838c2ecf20Sopenharmony_ci 30848c2ecf20Sopenharmony_ci tid = le16_to_cpu(bar_data.control) >> 12; 30858c2ecf20Sopenharmony_ci 30868c2ecf20Sopenharmony_ci if (!test_bit(tid, rx->sta->ampdu_mlme.agg_session_valid) && 30878c2ecf20Sopenharmony_ci !test_and_set_bit(tid, rx->sta->ampdu_mlme.unexpected_agg)) 30888c2ecf20Sopenharmony_ci ieee80211_send_delba(rx->sdata, rx->sta->sta.addr, tid, 30898c2ecf20Sopenharmony_ci WLAN_BACK_RECIPIENT, 30908c2ecf20Sopenharmony_ci WLAN_REASON_QSTA_REQUIRE_SETUP); 30918c2ecf20Sopenharmony_ci 30928c2ecf20Sopenharmony_ci tid_agg_rx = rcu_dereference(rx->sta->ampdu_mlme.tid_rx[tid]); 30938c2ecf20Sopenharmony_ci if (!tid_agg_rx) 30948c2ecf20Sopenharmony_ci return RX_DROP_MONITOR; 30958c2ecf20Sopenharmony_ci 30968c2ecf20Sopenharmony_ci start_seq_num = le16_to_cpu(bar_data.start_seq_num) >> 4; 30978c2ecf20Sopenharmony_ci event.u.ba.tid = tid; 30988c2ecf20Sopenharmony_ci event.u.ba.ssn = start_seq_num; 30998c2ecf20Sopenharmony_ci event.u.ba.sta = &rx->sta->sta; 31008c2ecf20Sopenharmony_ci 31018c2ecf20Sopenharmony_ci /* reset session timer */ 31028c2ecf20Sopenharmony_ci if (tid_agg_rx->timeout) 31038c2ecf20Sopenharmony_ci mod_timer(&tid_agg_rx->session_timer, 31048c2ecf20Sopenharmony_ci TU_TO_EXP_TIME(tid_agg_rx->timeout)); 31058c2ecf20Sopenharmony_ci 31068c2ecf20Sopenharmony_ci spin_lock(&tid_agg_rx->reorder_lock); 31078c2ecf20Sopenharmony_ci /* release stored frames up to start of BAR */ 31088c2ecf20Sopenharmony_ci ieee80211_release_reorder_frames(rx->sdata, tid_agg_rx, 31098c2ecf20Sopenharmony_ci start_seq_num, frames); 31108c2ecf20Sopenharmony_ci spin_unlock(&tid_agg_rx->reorder_lock); 31118c2ecf20Sopenharmony_ci 31128c2ecf20Sopenharmony_ci drv_event_callback(rx->local, rx->sdata, &event); 31138c2ecf20Sopenharmony_ci 31148c2ecf20Sopenharmony_ci kfree_skb(skb); 31158c2ecf20Sopenharmony_ci return RX_QUEUED; 31168c2ecf20Sopenharmony_ci } 31178c2ecf20Sopenharmony_ci 31188c2ecf20Sopenharmony_ci /* 31198c2ecf20Sopenharmony_ci * After this point, we only want management frames, 31208c2ecf20Sopenharmony_ci * so we can drop all remaining control frames to 31218c2ecf20Sopenharmony_ci * cooked monitor interfaces. 31228c2ecf20Sopenharmony_ci */ 31238c2ecf20Sopenharmony_ci return RX_DROP_MONITOR; 31248c2ecf20Sopenharmony_ci} 31258c2ecf20Sopenharmony_ci 31268c2ecf20Sopenharmony_cistatic void ieee80211_process_sa_query_req(struct ieee80211_sub_if_data *sdata, 31278c2ecf20Sopenharmony_ci struct ieee80211_mgmt *mgmt, 31288c2ecf20Sopenharmony_ci size_t len) 31298c2ecf20Sopenharmony_ci{ 31308c2ecf20Sopenharmony_ci struct ieee80211_local *local = sdata->local; 31318c2ecf20Sopenharmony_ci struct sk_buff *skb; 31328c2ecf20Sopenharmony_ci struct ieee80211_mgmt *resp; 31338c2ecf20Sopenharmony_ci 31348c2ecf20Sopenharmony_ci if (!ether_addr_equal(mgmt->da, sdata->vif.addr)) { 31358c2ecf20Sopenharmony_ci /* Not to own unicast address */ 31368c2ecf20Sopenharmony_ci return; 31378c2ecf20Sopenharmony_ci } 31388c2ecf20Sopenharmony_ci 31398c2ecf20Sopenharmony_ci if (!ether_addr_equal(mgmt->sa, sdata->u.mgd.bssid) || 31408c2ecf20Sopenharmony_ci !ether_addr_equal(mgmt->bssid, sdata->u.mgd.bssid)) { 31418c2ecf20Sopenharmony_ci /* Not from the current AP or not associated yet. */ 31428c2ecf20Sopenharmony_ci return; 31438c2ecf20Sopenharmony_ci } 31448c2ecf20Sopenharmony_ci 31458c2ecf20Sopenharmony_ci if (len < 24 + 1 + sizeof(resp->u.action.u.sa_query)) { 31468c2ecf20Sopenharmony_ci /* Too short SA Query request frame */ 31478c2ecf20Sopenharmony_ci return; 31488c2ecf20Sopenharmony_ci } 31498c2ecf20Sopenharmony_ci 31508c2ecf20Sopenharmony_ci skb = dev_alloc_skb(sizeof(*resp) + local->hw.extra_tx_headroom); 31518c2ecf20Sopenharmony_ci if (skb == NULL) 31528c2ecf20Sopenharmony_ci return; 31538c2ecf20Sopenharmony_ci 31548c2ecf20Sopenharmony_ci skb_reserve(skb, local->hw.extra_tx_headroom); 31558c2ecf20Sopenharmony_ci resp = skb_put_zero(skb, 24); 31568c2ecf20Sopenharmony_ci memcpy(resp->da, mgmt->sa, ETH_ALEN); 31578c2ecf20Sopenharmony_ci memcpy(resp->sa, sdata->vif.addr, ETH_ALEN); 31588c2ecf20Sopenharmony_ci memcpy(resp->bssid, sdata->u.mgd.bssid, ETH_ALEN); 31598c2ecf20Sopenharmony_ci resp->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | 31608c2ecf20Sopenharmony_ci IEEE80211_STYPE_ACTION); 31618c2ecf20Sopenharmony_ci skb_put(skb, 1 + sizeof(resp->u.action.u.sa_query)); 31628c2ecf20Sopenharmony_ci resp->u.action.category = WLAN_CATEGORY_SA_QUERY; 31638c2ecf20Sopenharmony_ci resp->u.action.u.sa_query.action = WLAN_ACTION_SA_QUERY_RESPONSE; 31648c2ecf20Sopenharmony_ci memcpy(resp->u.action.u.sa_query.trans_id, 31658c2ecf20Sopenharmony_ci mgmt->u.action.u.sa_query.trans_id, 31668c2ecf20Sopenharmony_ci WLAN_SA_QUERY_TR_ID_LEN); 31678c2ecf20Sopenharmony_ci 31688c2ecf20Sopenharmony_ci ieee80211_tx_skb(sdata, skb); 31698c2ecf20Sopenharmony_ci} 31708c2ecf20Sopenharmony_ci 31718c2ecf20Sopenharmony_cistatic ieee80211_rx_result debug_noinline 31728c2ecf20Sopenharmony_ciieee80211_rx_h_mgmt_check(struct ieee80211_rx_data *rx) 31738c2ecf20Sopenharmony_ci{ 31748c2ecf20Sopenharmony_ci struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data; 31758c2ecf20Sopenharmony_ci struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); 31768c2ecf20Sopenharmony_ci 31778c2ecf20Sopenharmony_ci if (ieee80211_is_s1g_beacon(mgmt->frame_control)) 31788c2ecf20Sopenharmony_ci return RX_CONTINUE; 31798c2ecf20Sopenharmony_ci 31808c2ecf20Sopenharmony_ci /* 31818c2ecf20Sopenharmony_ci * From here on, look only at management frames. 31828c2ecf20Sopenharmony_ci * Data and control frames are already handled, 31838c2ecf20Sopenharmony_ci * and unknown (reserved) frames are useless. 31848c2ecf20Sopenharmony_ci */ 31858c2ecf20Sopenharmony_ci if (rx->skb->len < 24) 31868c2ecf20Sopenharmony_ci return RX_DROP_MONITOR; 31878c2ecf20Sopenharmony_ci 31888c2ecf20Sopenharmony_ci if (!ieee80211_is_mgmt(mgmt->frame_control)) 31898c2ecf20Sopenharmony_ci return RX_DROP_MONITOR; 31908c2ecf20Sopenharmony_ci 31918c2ecf20Sopenharmony_ci if (rx->sdata->vif.type == NL80211_IFTYPE_AP && 31928c2ecf20Sopenharmony_ci ieee80211_is_beacon(mgmt->frame_control) && 31938c2ecf20Sopenharmony_ci !(rx->flags & IEEE80211_RX_BEACON_REPORTED)) { 31948c2ecf20Sopenharmony_ci int sig = 0; 31958c2ecf20Sopenharmony_ci 31968c2ecf20Sopenharmony_ci if (ieee80211_hw_check(&rx->local->hw, SIGNAL_DBM) && 31978c2ecf20Sopenharmony_ci !(status->flag & RX_FLAG_NO_SIGNAL_VAL)) 31988c2ecf20Sopenharmony_ci sig = status->signal; 31998c2ecf20Sopenharmony_ci 32008c2ecf20Sopenharmony_ci cfg80211_report_obss_beacon_khz(rx->local->hw.wiphy, 32018c2ecf20Sopenharmony_ci rx->skb->data, rx->skb->len, 32028c2ecf20Sopenharmony_ci ieee80211_rx_status_to_khz(status), 32038c2ecf20Sopenharmony_ci sig); 32048c2ecf20Sopenharmony_ci rx->flags |= IEEE80211_RX_BEACON_REPORTED; 32058c2ecf20Sopenharmony_ci } 32068c2ecf20Sopenharmony_ci 32078c2ecf20Sopenharmony_ci if (ieee80211_drop_unencrypted_mgmt(rx)) 32088c2ecf20Sopenharmony_ci return RX_DROP_UNUSABLE; 32098c2ecf20Sopenharmony_ci 32108c2ecf20Sopenharmony_ci return RX_CONTINUE; 32118c2ecf20Sopenharmony_ci} 32128c2ecf20Sopenharmony_ci 32138c2ecf20Sopenharmony_cistatic ieee80211_rx_result debug_noinline 32148c2ecf20Sopenharmony_ciieee80211_rx_h_action(struct ieee80211_rx_data *rx) 32158c2ecf20Sopenharmony_ci{ 32168c2ecf20Sopenharmony_ci struct ieee80211_local *local = rx->local; 32178c2ecf20Sopenharmony_ci struct ieee80211_sub_if_data *sdata = rx->sdata; 32188c2ecf20Sopenharmony_ci struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data; 32198c2ecf20Sopenharmony_ci struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); 32208c2ecf20Sopenharmony_ci int len = rx->skb->len; 32218c2ecf20Sopenharmony_ci 32228c2ecf20Sopenharmony_ci if (!ieee80211_is_action(mgmt->frame_control)) 32238c2ecf20Sopenharmony_ci return RX_CONTINUE; 32248c2ecf20Sopenharmony_ci 32258c2ecf20Sopenharmony_ci /* drop too small frames */ 32268c2ecf20Sopenharmony_ci if (len < IEEE80211_MIN_ACTION_SIZE) 32278c2ecf20Sopenharmony_ci return RX_DROP_UNUSABLE; 32288c2ecf20Sopenharmony_ci 32298c2ecf20Sopenharmony_ci if (!rx->sta && mgmt->u.action.category != WLAN_CATEGORY_PUBLIC && 32308c2ecf20Sopenharmony_ci mgmt->u.action.category != WLAN_CATEGORY_SELF_PROTECTED && 32318c2ecf20Sopenharmony_ci mgmt->u.action.category != WLAN_CATEGORY_SPECTRUM_MGMT) 32328c2ecf20Sopenharmony_ci return RX_DROP_UNUSABLE; 32338c2ecf20Sopenharmony_ci 32348c2ecf20Sopenharmony_ci switch (mgmt->u.action.category) { 32358c2ecf20Sopenharmony_ci case WLAN_CATEGORY_HT: 32368c2ecf20Sopenharmony_ci /* reject HT action frames from stations not supporting HT */ 32378c2ecf20Sopenharmony_ci if (!rx->sta->sta.ht_cap.ht_supported) 32388c2ecf20Sopenharmony_ci goto invalid; 32398c2ecf20Sopenharmony_ci 32408c2ecf20Sopenharmony_ci if (sdata->vif.type != NL80211_IFTYPE_STATION && 32418c2ecf20Sopenharmony_ci sdata->vif.type != NL80211_IFTYPE_MESH_POINT && 32428c2ecf20Sopenharmony_ci sdata->vif.type != NL80211_IFTYPE_AP_VLAN && 32438c2ecf20Sopenharmony_ci sdata->vif.type != NL80211_IFTYPE_AP && 32448c2ecf20Sopenharmony_ci sdata->vif.type != NL80211_IFTYPE_ADHOC) 32458c2ecf20Sopenharmony_ci break; 32468c2ecf20Sopenharmony_ci 32478c2ecf20Sopenharmony_ci /* verify action & smps_control/chanwidth are present */ 32488c2ecf20Sopenharmony_ci if (len < IEEE80211_MIN_ACTION_SIZE + 2) 32498c2ecf20Sopenharmony_ci goto invalid; 32508c2ecf20Sopenharmony_ci 32518c2ecf20Sopenharmony_ci switch (mgmt->u.action.u.ht_smps.action) { 32528c2ecf20Sopenharmony_ci case WLAN_HT_ACTION_SMPS: { 32538c2ecf20Sopenharmony_ci struct ieee80211_supported_band *sband; 32548c2ecf20Sopenharmony_ci enum ieee80211_smps_mode smps_mode; 32558c2ecf20Sopenharmony_ci struct sta_opmode_info sta_opmode = {}; 32568c2ecf20Sopenharmony_ci 32578c2ecf20Sopenharmony_ci if (sdata->vif.type != NL80211_IFTYPE_AP && 32588c2ecf20Sopenharmony_ci sdata->vif.type != NL80211_IFTYPE_AP_VLAN) 32598c2ecf20Sopenharmony_ci goto handled; 32608c2ecf20Sopenharmony_ci 32618c2ecf20Sopenharmony_ci /* convert to HT capability */ 32628c2ecf20Sopenharmony_ci switch (mgmt->u.action.u.ht_smps.smps_control) { 32638c2ecf20Sopenharmony_ci case WLAN_HT_SMPS_CONTROL_DISABLED: 32648c2ecf20Sopenharmony_ci smps_mode = IEEE80211_SMPS_OFF; 32658c2ecf20Sopenharmony_ci break; 32668c2ecf20Sopenharmony_ci case WLAN_HT_SMPS_CONTROL_STATIC: 32678c2ecf20Sopenharmony_ci smps_mode = IEEE80211_SMPS_STATIC; 32688c2ecf20Sopenharmony_ci break; 32698c2ecf20Sopenharmony_ci case WLAN_HT_SMPS_CONTROL_DYNAMIC: 32708c2ecf20Sopenharmony_ci smps_mode = IEEE80211_SMPS_DYNAMIC; 32718c2ecf20Sopenharmony_ci break; 32728c2ecf20Sopenharmony_ci default: 32738c2ecf20Sopenharmony_ci goto invalid; 32748c2ecf20Sopenharmony_ci } 32758c2ecf20Sopenharmony_ci 32768c2ecf20Sopenharmony_ci /* if no change do nothing */ 32778c2ecf20Sopenharmony_ci if (rx->sta->sta.smps_mode == smps_mode) 32788c2ecf20Sopenharmony_ci goto handled; 32798c2ecf20Sopenharmony_ci rx->sta->sta.smps_mode = smps_mode; 32808c2ecf20Sopenharmony_ci sta_opmode.smps_mode = 32818c2ecf20Sopenharmony_ci ieee80211_smps_mode_to_smps_mode(smps_mode); 32828c2ecf20Sopenharmony_ci sta_opmode.changed = STA_OPMODE_SMPS_MODE_CHANGED; 32838c2ecf20Sopenharmony_ci 32848c2ecf20Sopenharmony_ci sband = rx->local->hw.wiphy->bands[status->band]; 32858c2ecf20Sopenharmony_ci 32868c2ecf20Sopenharmony_ci rate_control_rate_update(local, sband, rx->sta, 32878c2ecf20Sopenharmony_ci IEEE80211_RC_SMPS_CHANGED); 32888c2ecf20Sopenharmony_ci cfg80211_sta_opmode_change_notify(sdata->dev, 32898c2ecf20Sopenharmony_ci rx->sta->addr, 32908c2ecf20Sopenharmony_ci &sta_opmode, 32918c2ecf20Sopenharmony_ci GFP_ATOMIC); 32928c2ecf20Sopenharmony_ci goto handled; 32938c2ecf20Sopenharmony_ci } 32948c2ecf20Sopenharmony_ci case WLAN_HT_ACTION_NOTIFY_CHANWIDTH: { 32958c2ecf20Sopenharmony_ci struct ieee80211_supported_band *sband; 32968c2ecf20Sopenharmony_ci u8 chanwidth = mgmt->u.action.u.ht_notify_cw.chanwidth; 32978c2ecf20Sopenharmony_ci enum ieee80211_sta_rx_bandwidth max_bw, new_bw; 32988c2ecf20Sopenharmony_ci struct sta_opmode_info sta_opmode = {}; 32998c2ecf20Sopenharmony_ci 33008c2ecf20Sopenharmony_ci /* If it doesn't support 40 MHz it can't change ... */ 33018c2ecf20Sopenharmony_ci if (!(rx->sta->sta.ht_cap.cap & 33028c2ecf20Sopenharmony_ci IEEE80211_HT_CAP_SUP_WIDTH_20_40)) 33038c2ecf20Sopenharmony_ci goto handled; 33048c2ecf20Sopenharmony_ci 33058c2ecf20Sopenharmony_ci if (chanwidth == IEEE80211_HT_CHANWIDTH_20MHZ) 33068c2ecf20Sopenharmony_ci max_bw = IEEE80211_STA_RX_BW_20; 33078c2ecf20Sopenharmony_ci else 33088c2ecf20Sopenharmony_ci max_bw = ieee80211_sta_cap_rx_bw(rx->sta); 33098c2ecf20Sopenharmony_ci 33108c2ecf20Sopenharmony_ci /* set cur_max_bandwidth and recalc sta bw */ 33118c2ecf20Sopenharmony_ci rx->sta->cur_max_bandwidth = max_bw; 33128c2ecf20Sopenharmony_ci new_bw = ieee80211_sta_cur_vht_bw(rx->sta); 33138c2ecf20Sopenharmony_ci 33148c2ecf20Sopenharmony_ci if (rx->sta->sta.bandwidth == new_bw) 33158c2ecf20Sopenharmony_ci goto handled; 33168c2ecf20Sopenharmony_ci 33178c2ecf20Sopenharmony_ci rx->sta->sta.bandwidth = new_bw; 33188c2ecf20Sopenharmony_ci sband = rx->local->hw.wiphy->bands[status->band]; 33198c2ecf20Sopenharmony_ci sta_opmode.bw = 33208c2ecf20Sopenharmony_ci ieee80211_sta_rx_bw_to_chan_width(rx->sta); 33218c2ecf20Sopenharmony_ci sta_opmode.changed = STA_OPMODE_MAX_BW_CHANGED; 33228c2ecf20Sopenharmony_ci 33238c2ecf20Sopenharmony_ci rate_control_rate_update(local, sband, rx->sta, 33248c2ecf20Sopenharmony_ci IEEE80211_RC_BW_CHANGED); 33258c2ecf20Sopenharmony_ci cfg80211_sta_opmode_change_notify(sdata->dev, 33268c2ecf20Sopenharmony_ci rx->sta->addr, 33278c2ecf20Sopenharmony_ci &sta_opmode, 33288c2ecf20Sopenharmony_ci GFP_ATOMIC); 33298c2ecf20Sopenharmony_ci goto handled; 33308c2ecf20Sopenharmony_ci } 33318c2ecf20Sopenharmony_ci default: 33328c2ecf20Sopenharmony_ci goto invalid; 33338c2ecf20Sopenharmony_ci } 33348c2ecf20Sopenharmony_ci 33358c2ecf20Sopenharmony_ci break; 33368c2ecf20Sopenharmony_ci case WLAN_CATEGORY_PUBLIC: 33378c2ecf20Sopenharmony_ci if (len < IEEE80211_MIN_ACTION_SIZE + 1) 33388c2ecf20Sopenharmony_ci goto invalid; 33398c2ecf20Sopenharmony_ci if (sdata->vif.type != NL80211_IFTYPE_STATION) 33408c2ecf20Sopenharmony_ci break; 33418c2ecf20Sopenharmony_ci if (!rx->sta) 33428c2ecf20Sopenharmony_ci break; 33438c2ecf20Sopenharmony_ci if (!ether_addr_equal(mgmt->bssid, sdata->u.mgd.bssid)) 33448c2ecf20Sopenharmony_ci break; 33458c2ecf20Sopenharmony_ci if (mgmt->u.action.u.ext_chan_switch.action_code != 33468c2ecf20Sopenharmony_ci WLAN_PUB_ACTION_EXT_CHANSW_ANN) 33478c2ecf20Sopenharmony_ci break; 33488c2ecf20Sopenharmony_ci if (len < offsetof(struct ieee80211_mgmt, 33498c2ecf20Sopenharmony_ci u.action.u.ext_chan_switch.variable)) 33508c2ecf20Sopenharmony_ci goto invalid; 33518c2ecf20Sopenharmony_ci goto queue; 33528c2ecf20Sopenharmony_ci case WLAN_CATEGORY_VHT: 33538c2ecf20Sopenharmony_ci if (sdata->vif.type != NL80211_IFTYPE_STATION && 33548c2ecf20Sopenharmony_ci sdata->vif.type != NL80211_IFTYPE_MESH_POINT && 33558c2ecf20Sopenharmony_ci sdata->vif.type != NL80211_IFTYPE_AP_VLAN && 33568c2ecf20Sopenharmony_ci sdata->vif.type != NL80211_IFTYPE_AP && 33578c2ecf20Sopenharmony_ci sdata->vif.type != NL80211_IFTYPE_ADHOC) 33588c2ecf20Sopenharmony_ci break; 33598c2ecf20Sopenharmony_ci 33608c2ecf20Sopenharmony_ci /* verify action code is present */ 33618c2ecf20Sopenharmony_ci if (len < IEEE80211_MIN_ACTION_SIZE + 1) 33628c2ecf20Sopenharmony_ci goto invalid; 33638c2ecf20Sopenharmony_ci 33648c2ecf20Sopenharmony_ci switch (mgmt->u.action.u.vht_opmode_notif.action_code) { 33658c2ecf20Sopenharmony_ci case WLAN_VHT_ACTION_OPMODE_NOTIF: { 33668c2ecf20Sopenharmony_ci /* verify opmode is present */ 33678c2ecf20Sopenharmony_ci if (len < IEEE80211_MIN_ACTION_SIZE + 2) 33688c2ecf20Sopenharmony_ci goto invalid; 33698c2ecf20Sopenharmony_ci goto queue; 33708c2ecf20Sopenharmony_ci } 33718c2ecf20Sopenharmony_ci case WLAN_VHT_ACTION_GROUPID_MGMT: { 33728c2ecf20Sopenharmony_ci if (len < IEEE80211_MIN_ACTION_SIZE + 25) 33738c2ecf20Sopenharmony_ci goto invalid; 33748c2ecf20Sopenharmony_ci goto queue; 33758c2ecf20Sopenharmony_ci } 33768c2ecf20Sopenharmony_ci default: 33778c2ecf20Sopenharmony_ci break; 33788c2ecf20Sopenharmony_ci } 33798c2ecf20Sopenharmony_ci break; 33808c2ecf20Sopenharmony_ci case WLAN_CATEGORY_BACK: 33818c2ecf20Sopenharmony_ci if (sdata->vif.type != NL80211_IFTYPE_STATION && 33828c2ecf20Sopenharmony_ci sdata->vif.type != NL80211_IFTYPE_MESH_POINT && 33838c2ecf20Sopenharmony_ci sdata->vif.type != NL80211_IFTYPE_AP_VLAN && 33848c2ecf20Sopenharmony_ci sdata->vif.type != NL80211_IFTYPE_AP && 33858c2ecf20Sopenharmony_ci sdata->vif.type != NL80211_IFTYPE_ADHOC) 33868c2ecf20Sopenharmony_ci break; 33878c2ecf20Sopenharmony_ci 33888c2ecf20Sopenharmony_ci /* verify action_code is present */ 33898c2ecf20Sopenharmony_ci if (len < IEEE80211_MIN_ACTION_SIZE + 1) 33908c2ecf20Sopenharmony_ci break; 33918c2ecf20Sopenharmony_ci 33928c2ecf20Sopenharmony_ci switch (mgmt->u.action.u.addba_req.action_code) { 33938c2ecf20Sopenharmony_ci case WLAN_ACTION_ADDBA_REQ: 33948c2ecf20Sopenharmony_ci if (len < (IEEE80211_MIN_ACTION_SIZE + 33958c2ecf20Sopenharmony_ci sizeof(mgmt->u.action.u.addba_req))) 33968c2ecf20Sopenharmony_ci goto invalid; 33978c2ecf20Sopenharmony_ci break; 33988c2ecf20Sopenharmony_ci case WLAN_ACTION_ADDBA_RESP: 33998c2ecf20Sopenharmony_ci if (len < (IEEE80211_MIN_ACTION_SIZE + 34008c2ecf20Sopenharmony_ci sizeof(mgmt->u.action.u.addba_resp))) 34018c2ecf20Sopenharmony_ci goto invalid; 34028c2ecf20Sopenharmony_ci break; 34038c2ecf20Sopenharmony_ci case WLAN_ACTION_DELBA: 34048c2ecf20Sopenharmony_ci if (len < (IEEE80211_MIN_ACTION_SIZE + 34058c2ecf20Sopenharmony_ci sizeof(mgmt->u.action.u.delba))) 34068c2ecf20Sopenharmony_ci goto invalid; 34078c2ecf20Sopenharmony_ci break; 34088c2ecf20Sopenharmony_ci default: 34098c2ecf20Sopenharmony_ci goto invalid; 34108c2ecf20Sopenharmony_ci } 34118c2ecf20Sopenharmony_ci 34128c2ecf20Sopenharmony_ci goto queue; 34138c2ecf20Sopenharmony_ci case WLAN_CATEGORY_SPECTRUM_MGMT: 34148c2ecf20Sopenharmony_ci /* verify action_code is present */ 34158c2ecf20Sopenharmony_ci if (len < IEEE80211_MIN_ACTION_SIZE + 1) 34168c2ecf20Sopenharmony_ci break; 34178c2ecf20Sopenharmony_ci 34188c2ecf20Sopenharmony_ci switch (mgmt->u.action.u.measurement.action_code) { 34198c2ecf20Sopenharmony_ci case WLAN_ACTION_SPCT_MSR_REQ: 34208c2ecf20Sopenharmony_ci if (status->band != NL80211_BAND_5GHZ) 34218c2ecf20Sopenharmony_ci break; 34228c2ecf20Sopenharmony_ci 34238c2ecf20Sopenharmony_ci if (len < (IEEE80211_MIN_ACTION_SIZE + 34248c2ecf20Sopenharmony_ci sizeof(mgmt->u.action.u.measurement))) 34258c2ecf20Sopenharmony_ci break; 34268c2ecf20Sopenharmony_ci 34278c2ecf20Sopenharmony_ci if (sdata->vif.type != NL80211_IFTYPE_STATION) 34288c2ecf20Sopenharmony_ci break; 34298c2ecf20Sopenharmony_ci 34308c2ecf20Sopenharmony_ci ieee80211_process_measurement_req(sdata, mgmt, len); 34318c2ecf20Sopenharmony_ci goto handled; 34328c2ecf20Sopenharmony_ci case WLAN_ACTION_SPCT_CHL_SWITCH: { 34338c2ecf20Sopenharmony_ci u8 *bssid; 34348c2ecf20Sopenharmony_ci if (len < (IEEE80211_MIN_ACTION_SIZE + 34358c2ecf20Sopenharmony_ci sizeof(mgmt->u.action.u.chan_switch))) 34368c2ecf20Sopenharmony_ci break; 34378c2ecf20Sopenharmony_ci 34388c2ecf20Sopenharmony_ci if (sdata->vif.type != NL80211_IFTYPE_STATION && 34398c2ecf20Sopenharmony_ci sdata->vif.type != NL80211_IFTYPE_ADHOC && 34408c2ecf20Sopenharmony_ci sdata->vif.type != NL80211_IFTYPE_MESH_POINT) 34418c2ecf20Sopenharmony_ci break; 34428c2ecf20Sopenharmony_ci 34438c2ecf20Sopenharmony_ci if (sdata->vif.type == NL80211_IFTYPE_STATION) 34448c2ecf20Sopenharmony_ci bssid = sdata->u.mgd.bssid; 34458c2ecf20Sopenharmony_ci else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) 34468c2ecf20Sopenharmony_ci bssid = sdata->u.ibss.bssid; 34478c2ecf20Sopenharmony_ci else if (sdata->vif.type == NL80211_IFTYPE_MESH_POINT) 34488c2ecf20Sopenharmony_ci bssid = mgmt->sa; 34498c2ecf20Sopenharmony_ci else 34508c2ecf20Sopenharmony_ci break; 34518c2ecf20Sopenharmony_ci 34528c2ecf20Sopenharmony_ci if (!ether_addr_equal(mgmt->bssid, bssid)) 34538c2ecf20Sopenharmony_ci break; 34548c2ecf20Sopenharmony_ci 34558c2ecf20Sopenharmony_ci goto queue; 34568c2ecf20Sopenharmony_ci } 34578c2ecf20Sopenharmony_ci } 34588c2ecf20Sopenharmony_ci break; 34598c2ecf20Sopenharmony_ci case WLAN_CATEGORY_SELF_PROTECTED: 34608c2ecf20Sopenharmony_ci if (len < (IEEE80211_MIN_ACTION_SIZE + 34618c2ecf20Sopenharmony_ci sizeof(mgmt->u.action.u.self_prot.action_code))) 34628c2ecf20Sopenharmony_ci break; 34638c2ecf20Sopenharmony_ci 34648c2ecf20Sopenharmony_ci switch (mgmt->u.action.u.self_prot.action_code) { 34658c2ecf20Sopenharmony_ci case WLAN_SP_MESH_PEERING_OPEN: 34668c2ecf20Sopenharmony_ci case WLAN_SP_MESH_PEERING_CLOSE: 34678c2ecf20Sopenharmony_ci case WLAN_SP_MESH_PEERING_CONFIRM: 34688c2ecf20Sopenharmony_ci if (!ieee80211_vif_is_mesh(&sdata->vif)) 34698c2ecf20Sopenharmony_ci goto invalid; 34708c2ecf20Sopenharmony_ci if (sdata->u.mesh.user_mpm) 34718c2ecf20Sopenharmony_ci /* userspace handles this frame */ 34728c2ecf20Sopenharmony_ci break; 34738c2ecf20Sopenharmony_ci goto queue; 34748c2ecf20Sopenharmony_ci case WLAN_SP_MGK_INFORM: 34758c2ecf20Sopenharmony_ci case WLAN_SP_MGK_ACK: 34768c2ecf20Sopenharmony_ci if (!ieee80211_vif_is_mesh(&sdata->vif)) 34778c2ecf20Sopenharmony_ci goto invalid; 34788c2ecf20Sopenharmony_ci break; 34798c2ecf20Sopenharmony_ci } 34808c2ecf20Sopenharmony_ci break; 34818c2ecf20Sopenharmony_ci case WLAN_CATEGORY_MESH_ACTION: 34828c2ecf20Sopenharmony_ci if (len < (IEEE80211_MIN_ACTION_SIZE + 34838c2ecf20Sopenharmony_ci sizeof(mgmt->u.action.u.mesh_action.action_code))) 34848c2ecf20Sopenharmony_ci break; 34858c2ecf20Sopenharmony_ci 34868c2ecf20Sopenharmony_ci if (!ieee80211_vif_is_mesh(&sdata->vif)) 34878c2ecf20Sopenharmony_ci break; 34888c2ecf20Sopenharmony_ci if (mesh_action_is_path_sel(mgmt) && 34898c2ecf20Sopenharmony_ci !mesh_path_sel_is_hwmp(sdata)) 34908c2ecf20Sopenharmony_ci break; 34918c2ecf20Sopenharmony_ci goto queue; 34928c2ecf20Sopenharmony_ci } 34938c2ecf20Sopenharmony_ci 34948c2ecf20Sopenharmony_ci return RX_CONTINUE; 34958c2ecf20Sopenharmony_ci 34968c2ecf20Sopenharmony_ci invalid: 34978c2ecf20Sopenharmony_ci status->rx_flags |= IEEE80211_RX_MALFORMED_ACTION_FRM; 34988c2ecf20Sopenharmony_ci /* will return in the next handlers */ 34998c2ecf20Sopenharmony_ci return RX_CONTINUE; 35008c2ecf20Sopenharmony_ci 35018c2ecf20Sopenharmony_ci handled: 35028c2ecf20Sopenharmony_ci if (rx->sta) 35038c2ecf20Sopenharmony_ci rx->sta->rx_stats.packets++; 35048c2ecf20Sopenharmony_ci dev_kfree_skb(rx->skb); 35058c2ecf20Sopenharmony_ci return RX_QUEUED; 35068c2ecf20Sopenharmony_ci 35078c2ecf20Sopenharmony_ci queue: 35088c2ecf20Sopenharmony_ci skb_queue_tail(&sdata->skb_queue, rx->skb); 35098c2ecf20Sopenharmony_ci ieee80211_queue_work(&local->hw, &sdata->work); 35108c2ecf20Sopenharmony_ci if (rx->sta) 35118c2ecf20Sopenharmony_ci rx->sta->rx_stats.packets++; 35128c2ecf20Sopenharmony_ci return RX_QUEUED; 35138c2ecf20Sopenharmony_ci} 35148c2ecf20Sopenharmony_ci 35158c2ecf20Sopenharmony_cistatic ieee80211_rx_result debug_noinline 35168c2ecf20Sopenharmony_ciieee80211_rx_h_userspace_mgmt(struct ieee80211_rx_data *rx) 35178c2ecf20Sopenharmony_ci{ 35188c2ecf20Sopenharmony_ci struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); 35198c2ecf20Sopenharmony_ci int sig = 0; 35208c2ecf20Sopenharmony_ci 35218c2ecf20Sopenharmony_ci /* skip known-bad action frames and return them in the next handler */ 35228c2ecf20Sopenharmony_ci if (status->rx_flags & IEEE80211_RX_MALFORMED_ACTION_FRM) 35238c2ecf20Sopenharmony_ci return RX_CONTINUE; 35248c2ecf20Sopenharmony_ci 35258c2ecf20Sopenharmony_ci /* 35268c2ecf20Sopenharmony_ci * Getting here means the kernel doesn't know how to handle 35278c2ecf20Sopenharmony_ci * it, but maybe userspace does ... include returned frames 35288c2ecf20Sopenharmony_ci * so userspace can register for those to know whether ones 35298c2ecf20Sopenharmony_ci * it transmitted were processed or returned. 35308c2ecf20Sopenharmony_ci */ 35318c2ecf20Sopenharmony_ci 35328c2ecf20Sopenharmony_ci if (ieee80211_hw_check(&rx->local->hw, SIGNAL_DBM) && 35338c2ecf20Sopenharmony_ci !(status->flag & RX_FLAG_NO_SIGNAL_VAL)) 35348c2ecf20Sopenharmony_ci sig = status->signal; 35358c2ecf20Sopenharmony_ci 35368c2ecf20Sopenharmony_ci if (cfg80211_rx_mgmt_khz(&rx->sdata->wdev, 35378c2ecf20Sopenharmony_ci ieee80211_rx_status_to_khz(status), sig, 35388c2ecf20Sopenharmony_ci rx->skb->data, rx->skb->len, 0)) { 35398c2ecf20Sopenharmony_ci if (rx->sta) 35408c2ecf20Sopenharmony_ci rx->sta->rx_stats.packets++; 35418c2ecf20Sopenharmony_ci dev_kfree_skb(rx->skb); 35428c2ecf20Sopenharmony_ci return RX_QUEUED; 35438c2ecf20Sopenharmony_ci } 35448c2ecf20Sopenharmony_ci 35458c2ecf20Sopenharmony_ci return RX_CONTINUE; 35468c2ecf20Sopenharmony_ci} 35478c2ecf20Sopenharmony_ci 35488c2ecf20Sopenharmony_cistatic ieee80211_rx_result debug_noinline 35498c2ecf20Sopenharmony_ciieee80211_rx_h_action_post_userspace(struct ieee80211_rx_data *rx) 35508c2ecf20Sopenharmony_ci{ 35518c2ecf20Sopenharmony_ci struct ieee80211_sub_if_data *sdata = rx->sdata; 35528c2ecf20Sopenharmony_ci struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data; 35538c2ecf20Sopenharmony_ci int len = rx->skb->len; 35548c2ecf20Sopenharmony_ci 35558c2ecf20Sopenharmony_ci if (!ieee80211_is_action(mgmt->frame_control)) 35568c2ecf20Sopenharmony_ci return RX_CONTINUE; 35578c2ecf20Sopenharmony_ci 35588c2ecf20Sopenharmony_ci switch (mgmt->u.action.category) { 35598c2ecf20Sopenharmony_ci case WLAN_CATEGORY_SA_QUERY: 35608c2ecf20Sopenharmony_ci if (len < (IEEE80211_MIN_ACTION_SIZE + 35618c2ecf20Sopenharmony_ci sizeof(mgmt->u.action.u.sa_query))) 35628c2ecf20Sopenharmony_ci break; 35638c2ecf20Sopenharmony_ci 35648c2ecf20Sopenharmony_ci switch (mgmt->u.action.u.sa_query.action) { 35658c2ecf20Sopenharmony_ci case WLAN_ACTION_SA_QUERY_REQUEST: 35668c2ecf20Sopenharmony_ci if (sdata->vif.type != NL80211_IFTYPE_STATION) 35678c2ecf20Sopenharmony_ci break; 35688c2ecf20Sopenharmony_ci ieee80211_process_sa_query_req(sdata, mgmt, len); 35698c2ecf20Sopenharmony_ci goto handled; 35708c2ecf20Sopenharmony_ci } 35718c2ecf20Sopenharmony_ci break; 35728c2ecf20Sopenharmony_ci } 35738c2ecf20Sopenharmony_ci 35748c2ecf20Sopenharmony_ci return RX_CONTINUE; 35758c2ecf20Sopenharmony_ci 35768c2ecf20Sopenharmony_ci handled: 35778c2ecf20Sopenharmony_ci if (rx->sta) 35788c2ecf20Sopenharmony_ci rx->sta->rx_stats.packets++; 35798c2ecf20Sopenharmony_ci dev_kfree_skb(rx->skb); 35808c2ecf20Sopenharmony_ci return RX_QUEUED; 35818c2ecf20Sopenharmony_ci} 35828c2ecf20Sopenharmony_ci 35838c2ecf20Sopenharmony_cistatic ieee80211_rx_result debug_noinline 35848c2ecf20Sopenharmony_ciieee80211_rx_h_action_return(struct ieee80211_rx_data *rx) 35858c2ecf20Sopenharmony_ci{ 35868c2ecf20Sopenharmony_ci struct ieee80211_local *local = rx->local; 35878c2ecf20Sopenharmony_ci struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data; 35888c2ecf20Sopenharmony_ci struct sk_buff *nskb; 35898c2ecf20Sopenharmony_ci struct ieee80211_sub_if_data *sdata = rx->sdata; 35908c2ecf20Sopenharmony_ci struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); 35918c2ecf20Sopenharmony_ci 35928c2ecf20Sopenharmony_ci if (!ieee80211_is_action(mgmt->frame_control)) 35938c2ecf20Sopenharmony_ci return RX_CONTINUE; 35948c2ecf20Sopenharmony_ci 35958c2ecf20Sopenharmony_ci /* 35968c2ecf20Sopenharmony_ci * For AP mode, hostapd is responsible for handling any action 35978c2ecf20Sopenharmony_ci * frames that we didn't handle, including returning unknown 35988c2ecf20Sopenharmony_ci * ones. For all other modes we will return them to the sender, 35998c2ecf20Sopenharmony_ci * setting the 0x80 bit in the action category, as required by 36008c2ecf20Sopenharmony_ci * 802.11-2012 9.24.4. 36018c2ecf20Sopenharmony_ci * Newer versions of hostapd shall also use the management frame 36028c2ecf20Sopenharmony_ci * registration mechanisms, but older ones still use cooked 36038c2ecf20Sopenharmony_ci * monitor interfaces so push all frames there. 36048c2ecf20Sopenharmony_ci */ 36058c2ecf20Sopenharmony_ci if (!(status->rx_flags & IEEE80211_RX_MALFORMED_ACTION_FRM) && 36068c2ecf20Sopenharmony_ci (sdata->vif.type == NL80211_IFTYPE_AP || 36078c2ecf20Sopenharmony_ci sdata->vif.type == NL80211_IFTYPE_AP_VLAN)) 36088c2ecf20Sopenharmony_ci return RX_DROP_MONITOR; 36098c2ecf20Sopenharmony_ci 36108c2ecf20Sopenharmony_ci if (is_multicast_ether_addr(mgmt->da)) 36118c2ecf20Sopenharmony_ci return RX_DROP_MONITOR; 36128c2ecf20Sopenharmony_ci 36138c2ecf20Sopenharmony_ci /* do not return rejected action frames */ 36148c2ecf20Sopenharmony_ci if (mgmt->u.action.category & 0x80) 36158c2ecf20Sopenharmony_ci return RX_DROP_UNUSABLE; 36168c2ecf20Sopenharmony_ci 36178c2ecf20Sopenharmony_ci nskb = skb_copy_expand(rx->skb, local->hw.extra_tx_headroom, 0, 36188c2ecf20Sopenharmony_ci GFP_ATOMIC); 36198c2ecf20Sopenharmony_ci if (nskb) { 36208c2ecf20Sopenharmony_ci struct ieee80211_mgmt *nmgmt = (void *)nskb->data; 36218c2ecf20Sopenharmony_ci 36228c2ecf20Sopenharmony_ci nmgmt->u.action.category |= 0x80; 36238c2ecf20Sopenharmony_ci memcpy(nmgmt->da, nmgmt->sa, ETH_ALEN); 36248c2ecf20Sopenharmony_ci memcpy(nmgmt->sa, rx->sdata->vif.addr, ETH_ALEN); 36258c2ecf20Sopenharmony_ci 36268c2ecf20Sopenharmony_ci memset(nskb->cb, 0, sizeof(nskb->cb)); 36278c2ecf20Sopenharmony_ci 36288c2ecf20Sopenharmony_ci if (rx->sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE) { 36298c2ecf20Sopenharmony_ci struct ieee80211_tx_info *info = IEEE80211_SKB_CB(nskb); 36308c2ecf20Sopenharmony_ci 36318c2ecf20Sopenharmony_ci info->flags = IEEE80211_TX_CTL_TX_OFFCHAN | 36328c2ecf20Sopenharmony_ci IEEE80211_TX_INTFL_OFFCHAN_TX_OK | 36338c2ecf20Sopenharmony_ci IEEE80211_TX_CTL_NO_CCK_RATE; 36348c2ecf20Sopenharmony_ci if (ieee80211_hw_check(&local->hw, QUEUE_CONTROL)) 36358c2ecf20Sopenharmony_ci info->hw_queue = 36368c2ecf20Sopenharmony_ci local->hw.offchannel_tx_hw_queue; 36378c2ecf20Sopenharmony_ci } 36388c2ecf20Sopenharmony_ci 36398c2ecf20Sopenharmony_ci __ieee80211_tx_skb_tid_band(rx->sdata, nskb, 7, 36408c2ecf20Sopenharmony_ci status->band); 36418c2ecf20Sopenharmony_ci } 36428c2ecf20Sopenharmony_ci dev_kfree_skb(rx->skb); 36438c2ecf20Sopenharmony_ci return RX_QUEUED; 36448c2ecf20Sopenharmony_ci} 36458c2ecf20Sopenharmony_ci 36468c2ecf20Sopenharmony_cistatic ieee80211_rx_result debug_noinline 36478c2ecf20Sopenharmony_ciieee80211_rx_h_ext(struct ieee80211_rx_data *rx) 36488c2ecf20Sopenharmony_ci{ 36498c2ecf20Sopenharmony_ci struct ieee80211_sub_if_data *sdata = rx->sdata; 36508c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr = (void *)rx->skb->data; 36518c2ecf20Sopenharmony_ci 36528c2ecf20Sopenharmony_ci if (!ieee80211_is_ext(hdr->frame_control)) 36538c2ecf20Sopenharmony_ci return RX_CONTINUE; 36548c2ecf20Sopenharmony_ci 36558c2ecf20Sopenharmony_ci if (sdata->vif.type != NL80211_IFTYPE_STATION) 36568c2ecf20Sopenharmony_ci return RX_DROP_MONITOR; 36578c2ecf20Sopenharmony_ci 36588c2ecf20Sopenharmony_ci /* for now only beacons are ext, so queue them */ 36598c2ecf20Sopenharmony_ci skb_queue_tail(&sdata->skb_queue, rx->skb); 36608c2ecf20Sopenharmony_ci ieee80211_queue_work(&rx->local->hw, &sdata->work); 36618c2ecf20Sopenharmony_ci if (rx->sta) 36628c2ecf20Sopenharmony_ci rx->sta->rx_stats.packets++; 36638c2ecf20Sopenharmony_ci 36648c2ecf20Sopenharmony_ci return RX_QUEUED; 36658c2ecf20Sopenharmony_ci} 36668c2ecf20Sopenharmony_ci 36678c2ecf20Sopenharmony_cistatic ieee80211_rx_result debug_noinline 36688c2ecf20Sopenharmony_ciieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx) 36698c2ecf20Sopenharmony_ci{ 36708c2ecf20Sopenharmony_ci struct ieee80211_sub_if_data *sdata = rx->sdata; 36718c2ecf20Sopenharmony_ci struct ieee80211_mgmt *mgmt = (void *)rx->skb->data; 36728c2ecf20Sopenharmony_ci __le16 stype; 36738c2ecf20Sopenharmony_ci 36748c2ecf20Sopenharmony_ci stype = mgmt->frame_control & cpu_to_le16(IEEE80211_FCTL_STYPE); 36758c2ecf20Sopenharmony_ci 36768c2ecf20Sopenharmony_ci if (!ieee80211_vif_is_mesh(&sdata->vif) && 36778c2ecf20Sopenharmony_ci sdata->vif.type != NL80211_IFTYPE_ADHOC && 36788c2ecf20Sopenharmony_ci sdata->vif.type != NL80211_IFTYPE_OCB && 36798c2ecf20Sopenharmony_ci sdata->vif.type != NL80211_IFTYPE_STATION) 36808c2ecf20Sopenharmony_ci return RX_DROP_MONITOR; 36818c2ecf20Sopenharmony_ci 36828c2ecf20Sopenharmony_ci switch (stype) { 36838c2ecf20Sopenharmony_ci case cpu_to_le16(IEEE80211_STYPE_AUTH): 36848c2ecf20Sopenharmony_ci case cpu_to_le16(IEEE80211_STYPE_BEACON): 36858c2ecf20Sopenharmony_ci case cpu_to_le16(IEEE80211_STYPE_PROBE_RESP): 36868c2ecf20Sopenharmony_ci /* process for all: mesh, mlme, ibss */ 36878c2ecf20Sopenharmony_ci break; 36888c2ecf20Sopenharmony_ci case cpu_to_le16(IEEE80211_STYPE_DEAUTH): 36898c2ecf20Sopenharmony_ci if (is_multicast_ether_addr(mgmt->da) && 36908c2ecf20Sopenharmony_ci !is_broadcast_ether_addr(mgmt->da)) 36918c2ecf20Sopenharmony_ci return RX_DROP_MONITOR; 36928c2ecf20Sopenharmony_ci 36938c2ecf20Sopenharmony_ci /* process only for station/IBSS */ 36948c2ecf20Sopenharmony_ci if (sdata->vif.type != NL80211_IFTYPE_STATION && 36958c2ecf20Sopenharmony_ci sdata->vif.type != NL80211_IFTYPE_ADHOC) 36968c2ecf20Sopenharmony_ci return RX_DROP_MONITOR; 36978c2ecf20Sopenharmony_ci break; 36988c2ecf20Sopenharmony_ci case cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP): 36998c2ecf20Sopenharmony_ci case cpu_to_le16(IEEE80211_STYPE_REASSOC_RESP): 37008c2ecf20Sopenharmony_ci case cpu_to_le16(IEEE80211_STYPE_DISASSOC): 37018c2ecf20Sopenharmony_ci if (is_multicast_ether_addr(mgmt->da) && 37028c2ecf20Sopenharmony_ci !is_broadcast_ether_addr(mgmt->da)) 37038c2ecf20Sopenharmony_ci return RX_DROP_MONITOR; 37048c2ecf20Sopenharmony_ci 37058c2ecf20Sopenharmony_ci /* process only for station */ 37068c2ecf20Sopenharmony_ci if (sdata->vif.type != NL80211_IFTYPE_STATION) 37078c2ecf20Sopenharmony_ci return RX_DROP_MONITOR; 37088c2ecf20Sopenharmony_ci break; 37098c2ecf20Sopenharmony_ci case cpu_to_le16(IEEE80211_STYPE_PROBE_REQ): 37108c2ecf20Sopenharmony_ci /* process only for ibss and mesh */ 37118c2ecf20Sopenharmony_ci if (sdata->vif.type != NL80211_IFTYPE_ADHOC && 37128c2ecf20Sopenharmony_ci sdata->vif.type != NL80211_IFTYPE_MESH_POINT) 37138c2ecf20Sopenharmony_ci return RX_DROP_MONITOR; 37148c2ecf20Sopenharmony_ci break; 37158c2ecf20Sopenharmony_ci default: 37168c2ecf20Sopenharmony_ci return RX_DROP_MONITOR; 37178c2ecf20Sopenharmony_ci } 37188c2ecf20Sopenharmony_ci 37198c2ecf20Sopenharmony_ci /* queue up frame and kick off work to process it */ 37208c2ecf20Sopenharmony_ci skb_queue_tail(&sdata->skb_queue, rx->skb); 37218c2ecf20Sopenharmony_ci ieee80211_queue_work(&rx->local->hw, &sdata->work); 37228c2ecf20Sopenharmony_ci if (rx->sta) 37238c2ecf20Sopenharmony_ci rx->sta->rx_stats.packets++; 37248c2ecf20Sopenharmony_ci 37258c2ecf20Sopenharmony_ci return RX_QUEUED; 37268c2ecf20Sopenharmony_ci} 37278c2ecf20Sopenharmony_ci 37288c2ecf20Sopenharmony_cistatic void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx, 37298c2ecf20Sopenharmony_ci struct ieee80211_rate *rate) 37308c2ecf20Sopenharmony_ci{ 37318c2ecf20Sopenharmony_ci struct ieee80211_sub_if_data *sdata; 37328c2ecf20Sopenharmony_ci struct ieee80211_local *local = rx->local; 37338c2ecf20Sopenharmony_ci struct sk_buff *skb = rx->skb, *skb2; 37348c2ecf20Sopenharmony_ci struct net_device *prev_dev = NULL; 37358c2ecf20Sopenharmony_ci struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); 37368c2ecf20Sopenharmony_ci int needed_headroom; 37378c2ecf20Sopenharmony_ci 37388c2ecf20Sopenharmony_ci /* 37398c2ecf20Sopenharmony_ci * If cooked monitor has been processed already, then 37408c2ecf20Sopenharmony_ci * don't do it again. If not, set the flag. 37418c2ecf20Sopenharmony_ci */ 37428c2ecf20Sopenharmony_ci if (rx->flags & IEEE80211_RX_CMNTR) 37438c2ecf20Sopenharmony_ci goto out_free_skb; 37448c2ecf20Sopenharmony_ci rx->flags |= IEEE80211_RX_CMNTR; 37458c2ecf20Sopenharmony_ci 37468c2ecf20Sopenharmony_ci /* If there are no cooked monitor interfaces, just free the SKB */ 37478c2ecf20Sopenharmony_ci if (!local->cooked_mntrs) 37488c2ecf20Sopenharmony_ci goto out_free_skb; 37498c2ecf20Sopenharmony_ci 37508c2ecf20Sopenharmony_ci /* vendor data is long removed here */ 37518c2ecf20Sopenharmony_ci status->flag &= ~RX_FLAG_RADIOTAP_VENDOR_DATA; 37528c2ecf20Sopenharmony_ci /* room for the radiotap header based on driver features */ 37538c2ecf20Sopenharmony_ci needed_headroom = ieee80211_rx_radiotap_hdrlen(local, status, skb); 37548c2ecf20Sopenharmony_ci 37558c2ecf20Sopenharmony_ci if (skb_headroom(skb) < needed_headroom && 37568c2ecf20Sopenharmony_ci pskb_expand_head(skb, needed_headroom, 0, GFP_ATOMIC)) 37578c2ecf20Sopenharmony_ci goto out_free_skb; 37588c2ecf20Sopenharmony_ci 37598c2ecf20Sopenharmony_ci /* prepend radiotap information */ 37608c2ecf20Sopenharmony_ci ieee80211_add_rx_radiotap_header(local, skb, rate, needed_headroom, 37618c2ecf20Sopenharmony_ci false); 37628c2ecf20Sopenharmony_ci 37638c2ecf20Sopenharmony_ci skb_reset_mac_header(skb); 37648c2ecf20Sopenharmony_ci skb->ip_summed = CHECKSUM_UNNECESSARY; 37658c2ecf20Sopenharmony_ci skb->pkt_type = PACKET_OTHERHOST; 37668c2ecf20Sopenharmony_ci skb->protocol = htons(ETH_P_802_2); 37678c2ecf20Sopenharmony_ci 37688c2ecf20Sopenharmony_ci list_for_each_entry_rcu(sdata, &local->interfaces, list) { 37698c2ecf20Sopenharmony_ci if (!ieee80211_sdata_running(sdata)) 37708c2ecf20Sopenharmony_ci continue; 37718c2ecf20Sopenharmony_ci 37728c2ecf20Sopenharmony_ci if (sdata->vif.type != NL80211_IFTYPE_MONITOR || 37738c2ecf20Sopenharmony_ci !(sdata->u.mntr.flags & MONITOR_FLAG_COOK_FRAMES)) 37748c2ecf20Sopenharmony_ci continue; 37758c2ecf20Sopenharmony_ci 37768c2ecf20Sopenharmony_ci if (prev_dev) { 37778c2ecf20Sopenharmony_ci skb2 = skb_clone(skb, GFP_ATOMIC); 37788c2ecf20Sopenharmony_ci if (skb2) { 37798c2ecf20Sopenharmony_ci skb2->dev = prev_dev; 37808c2ecf20Sopenharmony_ci netif_receive_skb(skb2); 37818c2ecf20Sopenharmony_ci } 37828c2ecf20Sopenharmony_ci } 37838c2ecf20Sopenharmony_ci 37848c2ecf20Sopenharmony_ci prev_dev = sdata->dev; 37858c2ecf20Sopenharmony_ci ieee80211_rx_stats(sdata->dev, skb->len); 37868c2ecf20Sopenharmony_ci } 37878c2ecf20Sopenharmony_ci 37888c2ecf20Sopenharmony_ci if (prev_dev) { 37898c2ecf20Sopenharmony_ci skb->dev = prev_dev; 37908c2ecf20Sopenharmony_ci netif_receive_skb(skb); 37918c2ecf20Sopenharmony_ci return; 37928c2ecf20Sopenharmony_ci } 37938c2ecf20Sopenharmony_ci 37948c2ecf20Sopenharmony_ci out_free_skb: 37958c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 37968c2ecf20Sopenharmony_ci} 37978c2ecf20Sopenharmony_ci 37988c2ecf20Sopenharmony_cistatic void ieee80211_rx_handlers_result(struct ieee80211_rx_data *rx, 37998c2ecf20Sopenharmony_ci ieee80211_rx_result res) 38008c2ecf20Sopenharmony_ci{ 38018c2ecf20Sopenharmony_ci switch (res) { 38028c2ecf20Sopenharmony_ci case RX_DROP_MONITOR: 38038c2ecf20Sopenharmony_ci I802_DEBUG_INC(rx->sdata->local->rx_handlers_drop); 38048c2ecf20Sopenharmony_ci if (rx->sta) 38058c2ecf20Sopenharmony_ci rx->sta->rx_stats.dropped++; 38068c2ecf20Sopenharmony_ci fallthrough; 38078c2ecf20Sopenharmony_ci case RX_CONTINUE: { 38088c2ecf20Sopenharmony_ci struct ieee80211_rate *rate = NULL; 38098c2ecf20Sopenharmony_ci struct ieee80211_supported_band *sband; 38108c2ecf20Sopenharmony_ci struct ieee80211_rx_status *status; 38118c2ecf20Sopenharmony_ci 38128c2ecf20Sopenharmony_ci status = IEEE80211_SKB_RXCB((rx->skb)); 38138c2ecf20Sopenharmony_ci 38148c2ecf20Sopenharmony_ci sband = rx->local->hw.wiphy->bands[status->band]; 38158c2ecf20Sopenharmony_ci if (status->encoding == RX_ENC_LEGACY) 38168c2ecf20Sopenharmony_ci rate = &sband->bitrates[status->rate_idx]; 38178c2ecf20Sopenharmony_ci 38188c2ecf20Sopenharmony_ci ieee80211_rx_cooked_monitor(rx, rate); 38198c2ecf20Sopenharmony_ci break; 38208c2ecf20Sopenharmony_ci } 38218c2ecf20Sopenharmony_ci case RX_DROP_UNUSABLE: 38228c2ecf20Sopenharmony_ci I802_DEBUG_INC(rx->sdata->local->rx_handlers_drop); 38238c2ecf20Sopenharmony_ci if (rx->sta) 38248c2ecf20Sopenharmony_ci rx->sta->rx_stats.dropped++; 38258c2ecf20Sopenharmony_ci dev_kfree_skb(rx->skb); 38268c2ecf20Sopenharmony_ci break; 38278c2ecf20Sopenharmony_ci case RX_QUEUED: 38288c2ecf20Sopenharmony_ci I802_DEBUG_INC(rx->sdata->local->rx_handlers_queued); 38298c2ecf20Sopenharmony_ci break; 38308c2ecf20Sopenharmony_ci } 38318c2ecf20Sopenharmony_ci} 38328c2ecf20Sopenharmony_ci 38338c2ecf20Sopenharmony_cistatic void ieee80211_rx_handlers(struct ieee80211_rx_data *rx, 38348c2ecf20Sopenharmony_ci struct sk_buff_head *frames) 38358c2ecf20Sopenharmony_ci{ 38368c2ecf20Sopenharmony_ci ieee80211_rx_result res = RX_DROP_MONITOR; 38378c2ecf20Sopenharmony_ci struct sk_buff *skb; 38388c2ecf20Sopenharmony_ci 38398c2ecf20Sopenharmony_ci#define CALL_RXH(rxh) \ 38408c2ecf20Sopenharmony_ci do { \ 38418c2ecf20Sopenharmony_ci res = rxh(rx); \ 38428c2ecf20Sopenharmony_ci if (res != RX_CONTINUE) \ 38438c2ecf20Sopenharmony_ci goto rxh_next; \ 38448c2ecf20Sopenharmony_ci } while (0) 38458c2ecf20Sopenharmony_ci 38468c2ecf20Sopenharmony_ci /* Lock here to avoid hitting all of the data used in the RX 38478c2ecf20Sopenharmony_ci * path (e.g. key data, station data, ...) concurrently when 38488c2ecf20Sopenharmony_ci * a frame is released from the reorder buffer due to timeout 38498c2ecf20Sopenharmony_ci * from the timer, potentially concurrently with RX from the 38508c2ecf20Sopenharmony_ci * driver. 38518c2ecf20Sopenharmony_ci */ 38528c2ecf20Sopenharmony_ci spin_lock_bh(&rx->local->rx_path_lock); 38538c2ecf20Sopenharmony_ci 38548c2ecf20Sopenharmony_ci while ((skb = __skb_dequeue(frames))) { 38558c2ecf20Sopenharmony_ci /* 38568c2ecf20Sopenharmony_ci * all the other fields are valid across frames 38578c2ecf20Sopenharmony_ci * that belong to an aMPDU since they are on the 38588c2ecf20Sopenharmony_ci * same TID from the same station 38598c2ecf20Sopenharmony_ci */ 38608c2ecf20Sopenharmony_ci rx->skb = skb; 38618c2ecf20Sopenharmony_ci 38628c2ecf20Sopenharmony_ci CALL_RXH(ieee80211_rx_h_check_more_data); 38638c2ecf20Sopenharmony_ci CALL_RXH(ieee80211_rx_h_uapsd_and_pspoll); 38648c2ecf20Sopenharmony_ci CALL_RXH(ieee80211_rx_h_sta_process); 38658c2ecf20Sopenharmony_ci CALL_RXH(ieee80211_rx_h_decrypt); 38668c2ecf20Sopenharmony_ci CALL_RXH(ieee80211_rx_h_defragment); 38678c2ecf20Sopenharmony_ci CALL_RXH(ieee80211_rx_h_michael_mic_verify); 38688c2ecf20Sopenharmony_ci /* must be after MMIC verify so header is counted in MPDU mic */ 38698c2ecf20Sopenharmony_ci#ifdef CONFIG_MAC80211_MESH 38708c2ecf20Sopenharmony_ci if (ieee80211_vif_is_mesh(&rx->sdata->vif)) 38718c2ecf20Sopenharmony_ci CALL_RXH(ieee80211_rx_h_mesh_fwding); 38728c2ecf20Sopenharmony_ci#endif 38738c2ecf20Sopenharmony_ci CALL_RXH(ieee80211_rx_h_amsdu); 38748c2ecf20Sopenharmony_ci CALL_RXH(ieee80211_rx_h_data); 38758c2ecf20Sopenharmony_ci 38768c2ecf20Sopenharmony_ci /* special treatment -- needs the queue */ 38778c2ecf20Sopenharmony_ci res = ieee80211_rx_h_ctrl(rx, frames); 38788c2ecf20Sopenharmony_ci if (res != RX_CONTINUE) 38798c2ecf20Sopenharmony_ci goto rxh_next; 38808c2ecf20Sopenharmony_ci 38818c2ecf20Sopenharmony_ci CALL_RXH(ieee80211_rx_h_mgmt_check); 38828c2ecf20Sopenharmony_ci CALL_RXH(ieee80211_rx_h_action); 38838c2ecf20Sopenharmony_ci CALL_RXH(ieee80211_rx_h_userspace_mgmt); 38848c2ecf20Sopenharmony_ci CALL_RXH(ieee80211_rx_h_action_post_userspace); 38858c2ecf20Sopenharmony_ci CALL_RXH(ieee80211_rx_h_action_return); 38868c2ecf20Sopenharmony_ci CALL_RXH(ieee80211_rx_h_ext); 38878c2ecf20Sopenharmony_ci CALL_RXH(ieee80211_rx_h_mgmt); 38888c2ecf20Sopenharmony_ci 38898c2ecf20Sopenharmony_ci rxh_next: 38908c2ecf20Sopenharmony_ci ieee80211_rx_handlers_result(rx, res); 38918c2ecf20Sopenharmony_ci 38928c2ecf20Sopenharmony_ci#undef CALL_RXH 38938c2ecf20Sopenharmony_ci } 38948c2ecf20Sopenharmony_ci 38958c2ecf20Sopenharmony_ci spin_unlock_bh(&rx->local->rx_path_lock); 38968c2ecf20Sopenharmony_ci} 38978c2ecf20Sopenharmony_ci 38988c2ecf20Sopenharmony_cistatic void ieee80211_invoke_rx_handlers(struct ieee80211_rx_data *rx) 38998c2ecf20Sopenharmony_ci{ 39008c2ecf20Sopenharmony_ci struct sk_buff_head reorder_release; 39018c2ecf20Sopenharmony_ci ieee80211_rx_result res = RX_DROP_MONITOR; 39028c2ecf20Sopenharmony_ci 39038c2ecf20Sopenharmony_ci __skb_queue_head_init(&reorder_release); 39048c2ecf20Sopenharmony_ci 39058c2ecf20Sopenharmony_ci#define CALL_RXH(rxh) \ 39068c2ecf20Sopenharmony_ci do { \ 39078c2ecf20Sopenharmony_ci res = rxh(rx); \ 39088c2ecf20Sopenharmony_ci if (res != RX_CONTINUE) \ 39098c2ecf20Sopenharmony_ci goto rxh_next; \ 39108c2ecf20Sopenharmony_ci } while (0) 39118c2ecf20Sopenharmony_ci 39128c2ecf20Sopenharmony_ci CALL_RXH(ieee80211_rx_h_check_dup); 39138c2ecf20Sopenharmony_ci CALL_RXH(ieee80211_rx_h_check); 39148c2ecf20Sopenharmony_ci 39158c2ecf20Sopenharmony_ci ieee80211_rx_reorder_ampdu(rx, &reorder_release); 39168c2ecf20Sopenharmony_ci 39178c2ecf20Sopenharmony_ci ieee80211_rx_handlers(rx, &reorder_release); 39188c2ecf20Sopenharmony_ci return; 39198c2ecf20Sopenharmony_ci 39208c2ecf20Sopenharmony_ci rxh_next: 39218c2ecf20Sopenharmony_ci ieee80211_rx_handlers_result(rx, res); 39228c2ecf20Sopenharmony_ci 39238c2ecf20Sopenharmony_ci#undef CALL_RXH 39248c2ecf20Sopenharmony_ci} 39258c2ecf20Sopenharmony_ci 39268c2ecf20Sopenharmony_ci/* 39278c2ecf20Sopenharmony_ci * This function makes calls into the RX path, therefore 39288c2ecf20Sopenharmony_ci * it has to be invoked under RCU read lock. 39298c2ecf20Sopenharmony_ci */ 39308c2ecf20Sopenharmony_civoid ieee80211_release_reorder_timeout(struct sta_info *sta, int tid) 39318c2ecf20Sopenharmony_ci{ 39328c2ecf20Sopenharmony_ci struct sk_buff_head frames; 39338c2ecf20Sopenharmony_ci struct ieee80211_rx_data rx = { 39348c2ecf20Sopenharmony_ci .sta = sta, 39358c2ecf20Sopenharmony_ci .sdata = sta->sdata, 39368c2ecf20Sopenharmony_ci .local = sta->local, 39378c2ecf20Sopenharmony_ci /* This is OK -- must be QoS data frame */ 39388c2ecf20Sopenharmony_ci .security_idx = tid, 39398c2ecf20Sopenharmony_ci .seqno_idx = tid, 39408c2ecf20Sopenharmony_ci }; 39418c2ecf20Sopenharmony_ci struct tid_ampdu_rx *tid_agg_rx; 39428c2ecf20Sopenharmony_ci 39438c2ecf20Sopenharmony_ci tid_agg_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[tid]); 39448c2ecf20Sopenharmony_ci if (!tid_agg_rx) 39458c2ecf20Sopenharmony_ci return; 39468c2ecf20Sopenharmony_ci 39478c2ecf20Sopenharmony_ci __skb_queue_head_init(&frames); 39488c2ecf20Sopenharmony_ci 39498c2ecf20Sopenharmony_ci spin_lock(&tid_agg_rx->reorder_lock); 39508c2ecf20Sopenharmony_ci ieee80211_sta_reorder_release(sta->sdata, tid_agg_rx, &frames); 39518c2ecf20Sopenharmony_ci spin_unlock(&tid_agg_rx->reorder_lock); 39528c2ecf20Sopenharmony_ci 39538c2ecf20Sopenharmony_ci if (!skb_queue_empty(&frames)) { 39548c2ecf20Sopenharmony_ci struct ieee80211_event event = { 39558c2ecf20Sopenharmony_ci .type = BA_FRAME_TIMEOUT, 39568c2ecf20Sopenharmony_ci .u.ba.tid = tid, 39578c2ecf20Sopenharmony_ci .u.ba.sta = &sta->sta, 39588c2ecf20Sopenharmony_ci }; 39598c2ecf20Sopenharmony_ci drv_event_callback(rx.local, rx.sdata, &event); 39608c2ecf20Sopenharmony_ci } 39618c2ecf20Sopenharmony_ci 39628c2ecf20Sopenharmony_ci ieee80211_rx_handlers(&rx, &frames); 39638c2ecf20Sopenharmony_ci} 39648c2ecf20Sopenharmony_ci 39658c2ecf20Sopenharmony_civoid ieee80211_mark_rx_ba_filtered_frames(struct ieee80211_sta *pubsta, u8 tid, 39668c2ecf20Sopenharmony_ci u16 ssn, u64 filtered, 39678c2ecf20Sopenharmony_ci u16 received_mpdus) 39688c2ecf20Sopenharmony_ci{ 39698c2ecf20Sopenharmony_ci struct sta_info *sta; 39708c2ecf20Sopenharmony_ci struct tid_ampdu_rx *tid_agg_rx; 39718c2ecf20Sopenharmony_ci struct sk_buff_head frames; 39728c2ecf20Sopenharmony_ci struct ieee80211_rx_data rx = { 39738c2ecf20Sopenharmony_ci /* This is OK -- must be QoS data frame */ 39748c2ecf20Sopenharmony_ci .security_idx = tid, 39758c2ecf20Sopenharmony_ci .seqno_idx = tid, 39768c2ecf20Sopenharmony_ci }; 39778c2ecf20Sopenharmony_ci int i, diff; 39788c2ecf20Sopenharmony_ci 39798c2ecf20Sopenharmony_ci if (WARN_ON(!pubsta || tid >= IEEE80211_NUM_TIDS)) 39808c2ecf20Sopenharmony_ci return; 39818c2ecf20Sopenharmony_ci 39828c2ecf20Sopenharmony_ci __skb_queue_head_init(&frames); 39838c2ecf20Sopenharmony_ci 39848c2ecf20Sopenharmony_ci sta = container_of(pubsta, struct sta_info, sta); 39858c2ecf20Sopenharmony_ci 39868c2ecf20Sopenharmony_ci rx.sta = sta; 39878c2ecf20Sopenharmony_ci rx.sdata = sta->sdata; 39888c2ecf20Sopenharmony_ci rx.local = sta->local; 39898c2ecf20Sopenharmony_ci 39908c2ecf20Sopenharmony_ci rcu_read_lock(); 39918c2ecf20Sopenharmony_ci tid_agg_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[tid]); 39928c2ecf20Sopenharmony_ci if (!tid_agg_rx) 39938c2ecf20Sopenharmony_ci goto out; 39948c2ecf20Sopenharmony_ci 39958c2ecf20Sopenharmony_ci spin_lock_bh(&tid_agg_rx->reorder_lock); 39968c2ecf20Sopenharmony_ci 39978c2ecf20Sopenharmony_ci if (received_mpdus >= IEEE80211_SN_MODULO >> 1) { 39988c2ecf20Sopenharmony_ci int release; 39998c2ecf20Sopenharmony_ci 40008c2ecf20Sopenharmony_ci /* release all frames in the reorder buffer */ 40018c2ecf20Sopenharmony_ci release = (tid_agg_rx->head_seq_num + tid_agg_rx->buf_size) % 40028c2ecf20Sopenharmony_ci IEEE80211_SN_MODULO; 40038c2ecf20Sopenharmony_ci ieee80211_release_reorder_frames(sta->sdata, tid_agg_rx, 40048c2ecf20Sopenharmony_ci release, &frames); 40058c2ecf20Sopenharmony_ci /* update ssn to match received ssn */ 40068c2ecf20Sopenharmony_ci tid_agg_rx->head_seq_num = ssn; 40078c2ecf20Sopenharmony_ci } else { 40088c2ecf20Sopenharmony_ci ieee80211_release_reorder_frames(sta->sdata, tid_agg_rx, ssn, 40098c2ecf20Sopenharmony_ci &frames); 40108c2ecf20Sopenharmony_ci } 40118c2ecf20Sopenharmony_ci 40128c2ecf20Sopenharmony_ci /* handle the case that received ssn is behind the mac ssn. 40138c2ecf20Sopenharmony_ci * it can be tid_agg_rx->buf_size behind and still be valid */ 40148c2ecf20Sopenharmony_ci diff = (tid_agg_rx->head_seq_num - ssn) & IEEE80211_SN_MASK; 40158c2ecf20Sopenharmony_ci if (diff >= tid_agg_rx->buf_size) { 40168c2ecf20Sopenharmony_ci tid_agg_rx->reorder_buf_filtered = 0; 40178c2ecf20Sopenharmony_ci goto release; 40188c2ecf20Sopenharmony_ci } 40198c2ecf20Sopenharmony_ci filtered = filtered >> diff; 40208c2ecf20Sopenharmony_ci ssn += diff; 40218c2ecf20Sopenharmony_ci 40228c2ecf20Sopenharmony_ci /* update bitmap */ 40238c2ecf20Sopenharmony_ci for (i = 0; i < tid_agg_rx->buf_size; i++) { 40248c2ecf20Sopenharmony_ci int index = (ssn + i) % tid_agg_rx->buf_size; 40258c2ecf20Sopenharmony_ci 40268c2ecf20Sopenharmony_ci tid_agg_rx->reorder_buf_filtered &= ~BIT_ULL(index); 40278c2ecf20Sopenharmony_ci if (filtered & BIT_ULL(i)) 40288c2ecf20Sopenharmony_ci tid_agg_rx->reorder_buf_filtered |= BIT_ULL(index); 40298c2ecf20Sopenharmony_ci } 40308c2ecf20Sopenharmony_ci 40318c2ecf20Sopenharmony_ci /* now process also frames that the filter marking released */ 40328c2ecf20Sopenharmony_ci ieee80211_sta_reorder_release(sta->sdata, tid_agg_rx, &frames); 40338c2ecf20Sopenharmony_ci 40348c2ecf20Sopenharmony_cirelease: 40358c2ecf20Sopenharmony_ci spin_unlock_bh(&tid_agg_rx->reorder_lock); 40368c2ecf20Sopenharmony_ci 40378c2ecf20Sopenharmony_ci ieee80211_rx_handlers(&rx, &frames); 40388c2ecf20Sopenharmony_ci 40398c2ecf20Sopenharmony_ci out: 40408c2ecf20Sopenharmony_ci rcu_read_unlock(); 40418c2ecf20Sopenharmony_ci} 40428c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ieee80211_mark_rx_ba_filtered_frames); 40438c2ecf20Sopenharmony_ci 40448c2ecf20Sopenharmony_ci/* main receive path */ 40458c2ecf20Sopenharmony_ci 40468c2ecf20Sopenharmony_cistatic bool ieee80211_accept_frame(struct ieee80211_rx_data *rx) 40478c2ecf20Sopenharmony_ci{ 40488c2ecf20Sopenharmony_ci struct ieee80211_sub_if_data *sdata = rx->sdata; 40498c2ecf20Sopenharmony_ci struct sk_buff *skb = rx->skb; 40508c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr = (void *)skb->data; 40518c2ecf20Sopenharmony_ci struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); 40528c2ecf20Sopenharmony_ci u8 *bssid = ieee80211_get_bssid(hdr, skb->len, sdata->vif.type); 40538c2ecf20Sopenharmony_ci bool multicast = is_multicast_ether_addr(hdr->addr1) || 40548c2ecf20Sopenharmony_ci ieee80211_is_s1g_beacon(hdr->frame_control); 40558c2ecf20Sopenharmony_ci 40568c2ecf20Sopenharmony_ci switch (sdata->vif.type) { 40578c2ecf20Sopenharmony_ci case NL80211_IFTYPE_STATION: 40588c2ecf20Sopenharmony_ci if (!bssid && !sdata->u.mgd.use_4addr) 40598c2ecf20Sopenharmony_ci return false; 40608c2ecf20Sopenharmony_ci if (ieee80211_is_robust_mgmt_frame(skb) && !rx->sta) 40618c2ecf20Sopenharmony_ci return false; 40628c2ecf20Sopenharmony_ci if (multicast) 40638c2ecf20Sopenharmony_ci return true; 40648c2ecf20Sopenharmony_ci return ether_addr_equal(sdata->vif.addr, hdr->addr1); 40658c2ecf20Sopenharmony_ci case NL80211_IFTYPE_ADHOC: 40668c2ecf20Sopenharmony_ci if (!bssid) 40678c2ecf20Sopenharmony_ci return false; 40688c2ecf20Sopenharmony_ci if (ether_addr_equal(sdata->vif.addr, hdr->addr2) || 40698c2ecf20Sopenharmony_ci ether_addr_equal(sdata->u.ibss.bssid, hdr->addr2) || 40708c2ecf20Sopenharmony_ci !is_valid_ether_addr(hdr->addr2)) 40718c2ecf20Sopenharmony_ci return false; 40728c2ecf20Sopenharmony_ci if (ieee80211_is_beacon(hdr->frame_control)) 40738c2ecf20Sopenharmony_ci return true; 40748c2ecf20Sopenharmony_ci if (!ieee80211_bssid_match(bssid, sdata->u.ibss.bssid)) 40758c2ecf20Sopenharmony_ci return false; 40768c2ecf20Sopenharmony_ci if (!multicast && 40778c2ecf20Sopenharmony_ci !ether_addr_equal(sdata->vif.addr, hdr->addr1)) 40788c2ecf20Sopenharmony_ci return false; 40798c2ecf20Sopenharmony_ci if (!rx->sta) { 40808c2ecf20Sopenharmony_ci int rate_idx; 40818c2ecf20Sopenharmony_ci if (status->encoding != RX_ENC_LEGACY) 40828c2ecf20Sopenharmony_ci rate_idx = 0; /* TODO: HT/VHT rates */ 40838c2ecf20Sopenharmony_ci else 40848c2ecf20Sopenharmony_ci rate_idx = status->rate_idx; 40858c2ecf20Sopenharmony_ci ieee80211_ibss_rx_no_sta(sdata, bssid, hdr->addr2, 40868c2ecf20Sopenharmony_ci BIT(rate_idx)); 40878c2ecf20Sopenharmony_ci } 40888c2ecf20Sopenharmony_ci return true; 40898c2ecf20Sopenharmony_ci case NL80211_IFTYPE_OCB: 40908c2ecf20Sopenharmony_ci if (!bssid) 40918c2ecf20Sopenharmony_ci return false; 40928c2ecf20Sopenharmony_ci if (!ieee80211_is_data_present(hdr->frame_control)) 40938c2ecf20Sopenharmony_ci return false; 40948c2ecf20Sopenharmony_ci if (!is_broadcast_ether_addr(bssid)) 40958c2ecf20Sopenharmony_ci return false; 40968c2ecf20Sopenharmony_ci if (!multicast && 40978c2ecf20Sopenharmony_ci !ether_addr_equal(sdata->dev->dev_addr, hdr->addr1)) 40988c2ecf20Sopenharmony_ci return false; 40998c2ecf20Sopenharmony_ci if (!rx->sta) { 41008c2ecf20Sopenharmony_ci int rate_idx; 41018c2ecf20Sopenharmony_ci if (status->encoding != RX_ENC_LEGACY) 41028c2ecf20Sopenharmony_ci rate_idx = 0; /* TODO: HT rates */ 41038c2ecf20Sopenharmony_ci else 41048c2ecf20Sopenharmony_ci rate_idx = status->rate_idx; 41058c2ecf20Sopenharmony_ci ieee80211_ocb_rx_no_sta(sdata, bssid, hdr->addr2, 41068c2ecf20Sopenharmony_ci BIT(rate_idx)); 41078c2ecf20Sopenharmony_ci } 41088c2ecf20Sopenharmony_ci return true; 41098c2ecf20Sopenharmony_ci case NL80211_IFTYPE_MESH_POINT: 41108c2ecf20Sopenharmony_ci if (ether_addr_equal(sdata->vif.addr, hdr->addr2)) 41118c2ecf20Sopenharmony_ci return false; 41128c2ecf20Sopenharmony_ci if (multicast) 41138c2ecf20Sopenharmony_ci return true; 41148c2ecf20Sopenharmony_ci return ether_addr_equal(sdata->vif.addr, hdr->addr1); 41158c2ecf20Sopenharmony_ci case NL80211_IFTYPE_AP_VLAN: 41168c2ecf20Sopenharmony_ci case NL80211_IFTYPE_AP: 41178c2ecf20Sopenharmony_ci if (!bssid) 41188c2ecf20Sopenharmony_ci return ether_addr_equal(sdata->vif.addr, hdr->addr1); 41198c2ecf20Sopenharmony_ci 41208c2ecf20Sopenharmony_ci if (!ieee80211_bssid_match(bssid, sdata->vif.addr)) { 41218c2ecf20Sopenharmony_ci /* 41228c2ecf20Sopenharmony_ci * Accept public action frames even when the 41238c2ecf20Sopenharmony_ci * BSSID doesn't match, this is used for P2P 41248c2ecf20Sopenharmony_ci * and location updates. Note that mac80211 41258c2ecf20Sopenharmony_ci * itself never looks at these frames. 41268c2ecf20Sopenharmony_ci */ 41278c2ecf20Sopenharmony_ci if (!multicast && 41288c2ecf20Sopenharmony_ci !ether_addr_equal(sdata->vif.addr, hdr->addr1)) 41298c2ecf20Sopenharmony_ci return false; 41308c2ecf20Sopenharmony_ci if (ieee80211_is_public_action(hdr, skb->len)) 41318c2ecf20Sopenharmony_ci return true; 41328c2ecf20Sopenharmony_ci return ieee80211_is_beacon(hdr->frame_control); 41338c2ecf20Sopenharmony_ci } 41348c2ecf20Sopenharmony_ci 41358c2ecf20Sopenharmony_ci if (!ieee80211_has_tods(hdr->frame_control)) { 41368c2ecf20Sopenharmony_ci /* ignore data frames to TDLS-peers */ 41378c2ecf20Sopenharmony_ci if (ieee80211_is_data(hdr->frame_control)) 41388c2ecf20Sopenharmony_ci return false; 41398c2ecf20Sopenharmony_ci /* ignore action frames to TDLS-peers */ 41408c2ecf20Sopenharmony_ci if (ieee80211_is_action(hdr->frame_control) && 41418c2ecf20Sopenharmony_ci !is_broadcast_ether_addr(bssid) && 41428c2ecf20Sopenharmony_ci !ether_addr_equal(bssid, hdr->addr1)) 41438c2ecf20Sopenharmony_ci return false; 41448c2ecf20Sopenharmony_ci } 41458c2ecf20Sopenharmony_ci 41468c2ecf20Sopenharmony_ci /* 41478c2ecf20Sopenharmony_ci * 802.11-2016 Table 9-26 says that for data frames, A1 must be 41488c2ecf20Sopenharmony_ci * the BSSID - we've checked that already but may have accepted 41498c2ecf20Sopenharmony_ci * the wildcard (ff:ff:ff:ff:ff:ff). 41508c2ecf20Sopenharmony_ci * 41518c2ecf20Sopenharmony_ci * It also says: 41528c2ecf20Sopenharmony_ci * The BSSID of the Data frame is determined as follows: 41538c2ecf20Sopenharmony_ci * a) If the STA is contained within an AP or is associated 41548c2ecf20Sopenharmony_ci * with an AP, the BSSID is the address currently in use 41558c2ecf20Sopenharmony_ci * by the STA contained in the AP. 41568c2ecf20Sopenharmony_ci * 41578c2ecf20Sopenharmony_ci * So we should not accept data frames with an address that's 41588c2ecf20Sopenharmony_ci * multicast. 41598c2ecf20Sopenharmony_ci * 41608c2ecf20Sopenharmony_ci * Accepting it also opens a security problem because stations 41618c2ecf20Sopenharmony_ci * could encrypt it with the GTK and inject traffic that way. 41628c2ecf20Sopenharmony_ci */ 41638c2ecf20Sopenharmony_ci if (ieee80211_is_data(hdr->frame_control) && multicast) 41648c2ecf20Sopenharmony_ci return false; 41658c2ecf20Sopenharmony_ci 41668c2ecf20Sopenharmony_ci return true; 41678c2ecf20Sopenharmony_ci case NL80211_IFTYPE_WDS: 41688c2ecf20Sopenharmony_ci if (bssid || !ieee80211_is_data(hdr->frame_control)) 41698c2ecf20Sopenharmony_ci return false; 41708c2ecf20Sopenharmony_ci return ether_addr_equal(sdata->u.wds.remote_addr, hdr->addr2); 41718c2ecf20Sopenharmony_ci case NL80211_IFTYPE_P2P_DEVICE: 41728c2ecf20Sopenharmony_ci return ieee80211_is_public_action(hdr, skb->len) || 41738c2ecf20Sopenharmony_ci ieee80211_is_probe_req(hdr->frame_control) || 41748c2ecf20Sopenharmony_ci ieee80211_is_probe_resp(hdr->frame_control) || 41758c2ecf20Sopenharmony_ci ieee80211_is_beacon(hdr->frame_control); 41768c2ecf20Sopenharmony_ci case NL80211_IFTYPE_NAN: 41778c2ecf20Sopenharmony_ci /* Currently no frames on NAN interface are allowed */ 41788c2ecf20Sopenharmony_ci return false; 41798c2ecf20Sopenharmony_ci default: 41808c2ecf20Sopenharmony_ci break; 41818c2ecf20Sopenharmony_ci } 41828c2ecf20Sopenharmony_ci 41838c2ecf20Sopenharmony_ci WARN_ON_ONCE(1); 41848c2ecf20Sopenharmony_ci return false; 41858c2ecf20Sopenharmony_ci} 41868c2ecf20Sopenharmony_ci 41878c2ecf20Sopenharmony_civoid ieee80211_check_fast_rx(struct sta_info *sta) 41888c2ecf20Sopenharmony_ci{ 41898c2ecf20Sopenharmony_ci struct ieee80211_sub_if_data *sdata = sta->sdata; 41908c2ecf20Sopenharmony_ci struct ieee80211_local *local = sdata->local; 41918c2ecf20Sopenharmony_ci struct ieee80211_key *key; 41928c2ecf20Sopenharmony_ci struct ieee80211_fast_rx fastrx = { 41938c2ecf20Sopenharmony_ci .dev = sdata->dev, 41948c2ecf20Sopenharmony_ci .vif_type = sdata->vif.type, 41958c2ecf20Sopenharmony_ci .control_port_protocol = sdata->control_port_protocol, 41968c2ecf20Sopenharmony_ci }, *old, *new = NULL; 41978c2ecf20Sopenharmony_ci bool assign = false; 41988c2ecf20Sopenharmony_ci 41998c2ecf20Sopenharmony_ci /* use sparse to check that we don't return without updating */ 42008c2ecf20Sopenharmony_ci __acquire(check_fast_rx); 42018c2ecf20Sopenharmony_ci 42028c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(fastrx.rfc1042_hdr) != sizeof(rfc1042_header)); 42038c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(fastrx.rfc1042_hdr) != ETH_ALEN); 42048c2ecf20Sopenharmony_ci ether_addr_copy(fastrx.rfc1042_hdr, rfc1042_header); 42058c2ecf20Sopenharmony_ci ether_addr_copy(fastrx.vif_addr, sdata->vif.addr); 42068c2ecf20Sopenharmony_ci 42078c2ecf20Sopenharmony_ci fastrx.uses_rss = ieee80211_hw_check(&local->hw, USES_RSS); 42088c2ecf20Sopenharmony_ci 42098c2ecf20Sopenharmony_ci /* fast-rx doesn't do reordering */ 42108c2ecf20Sopenharmony_ci if (ieee80211_hw_check(&local->hw, AMPDU_AGGREGATION) && 42118c2ecf20Sopenharmony_ci !ieee80211_hw_check(&local->hw, SUPPORTS_REORDERING_BUFFER)) 42128c2ecf20Sopenharmony_ci goto clear; 42138c2ecf20Sopenharmony_ci 42148c2ecf20Sopenharmony_ci switch (sdata->vif.type) { 42158c2ecf20Sopenharmony_ci case NL80211_IFTYPE_STATION: 42168c2ecf20Sopenharmony_ci if (sta->sta.tdls) { 42178c2ecf20Sopenharmony_ci fastrx.da_offs = offsetof(struct ieee80211_hdr, addr1); 42188c2ecf20Sopenharmony_ci fastrx.sa_offs = offsetof(struct ieee80211_hdr, addr2); 42198c2ecf20Sopenharmony_ci fastrx.expected_ds_bits = 0; 42208c2ecf20Sopenharmony_ci } else { 42218c2ecf20Sopenharmony_ci fastrx.da_offs = offsetof(struct ieee80211_hdr, addr1); 42228c2ecf20Sopenharmony_ci fastrx.sa_offs = offsetof(struct ieee80211_hdr, addr3); 42238c2ecf20Sopenharmony_ci fastrx.expected_ds_bits = 42248c2ecf20Sopenharmony_ci cpu_to_le16(IEEE80211_FCTL_FROMDS); 42258c2ecf20Sopenharmony_ci } 42268c2ecf20Sopenharmony_ci 42278c2ecf20Sopenharmony_ci if (sdata->u.mgd.use_4addr && !sta->sta.tdls) { 42288c2ecf20Sopenharmony_ci fastrx.expected_ds_bits |= 42298c2ecf20Sopenharmony_ci cpu_to_le16(IEEE80211_FCTL_TODS); 42308c2ecf20Sopenharmony_ci fastrx.da_offs = offsetof(struct ieee80211_hdr, addr3); 42318c2ecf20Sopenharmony_ci fastrx.sa_offs = offsetof(struct ieee80211_hdr, addr4); 42328c2ecf20Sopenharmony_ci } 42338c2ecf20Sopenharmony_ci 42348c2ecf20Sopenharmony_ci if (!sdata->u.mgd.powersave) 42358c2ecf20Sopenharmony_ci break; 42368c2ecf20Sopenharmony_ci 42378c2ecf20Sopenharmony_ci /* software powersave is a huge mess, avoid all of it */ 42388c2ecf20Sopenharmony_ci if (ieee80211_hw_check(&local->hw, PS_NULLFUNC_STACK)) 42398c2ecf20Sopenharmony_ci goto clear; 42408c2ecf20Sopenharmony_ci if (ieee80211_hw_check(&local->hw, SUPPORTS_PS) && 42418c2ecf20Sopenharmony_ci !ieee80211_hw_check(&local->hw, SUPPORTS_DYNAMIC_PS)) 42428c2ecf20Sopenharmony_ci goto clear; 42438c2ecf20Sopenharmony_ci break; 42448c2ecf20Sopenharmony_ci case NL80211_IFTYPE_AP_VLAN: 42458c2ecf20Sopenharmony_ci case NL80211_IFTYPE_AP: 42468c2ecf20Sopenharmony_ci /* parallel-rx requires this, at least with calls to 42478c2ecf20Sopenharmony_ci * ieee80211_sta_ps_transition() 42488c2ecf20Sopenharmony_ci */ 42498c2ecf20Sopenharmony_ci if (!ieee80211_hw_check(&local->hw, AP_LINK_PS)) 42508c2ecf20Sopenharmony_ci goto clear; 42518c2ecf20Sopenharmony_ci fastrx.da_offs = offsetof(struct ieee80211_hdr, addr3); 42528c2ecf20Sopenharmony_ci fastrx.sa_offs = offsetof(struct ieee80211_hdr, addr2); 42538c2ecf20Sopenharmony_ci fastrx.expected_ds_bits = cpu_to_le16(IEEE80211_FCTL_TODS); 42548c2ecf20Sopenharmony_ci 42558c2ecf20Sopenharmony_ci fastrx.internal_forward = 42568c2ecf20Sopenharmony_ci !(sdata->flags & IEEE80211_SDATA_DONT_BRIDGE_PACKETS) && 42578c2ecf20Sopenharmony_ci (sdata->vif.type != NL80211_IFTYPE_AP_VLAN || 42588c2ecf20Sopenharmony_ci !sdata->u.vlan.sta); 42598c2ecf20Sopenharmony_ci 42608c2ecf20Sopenharmony_ci if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN && 42618c2ecf20Sopenharmony_ci sdata->u.vlan.sta) { 42628c2ecf20Sopenharmony_ci fastrx.expected_ds_bits |= 42638c2ecf20Sopenharmony_ci cpu_to_le16(IEEE80211_FCTL_FROMDS); 42648c2ecf20Sopenharmony_ci fastrx.sa_offs = offsetof(struct ieee80211_hdr, addr4); 42658c2ecf20Sopenharmony_ci fastrx.internal_forward = 0; 42668c2ecf20Sopenharmony_ci } 42678c2ecf20Sopenharmony_ci 42688c2ecf20Sopenharmony_ci break; 42698c2ecf20Sopenharmony_ci default: 42708c2ecf20Sopenharmony_ci goto clear; 42718c2ecf20Sopenharmony_ci } 42728c2ecf20Sopenharmony_ci 42738c2ecf20Sopenharmony_ci if (!test_sta_flag(sta, WLAN_STA_AUTHORIZED)) 42748c2ecf20Sopenharmony_ci goto clear; 42758c2ecf20Sopenharmony_ci 42768c2ecf20Sopenharmony_ci rcu_read_lock(); 42778c2ecf20Sopenharmony_ci key = rcu_dereference(sta->ptk[sta->ptk_idx]); 42788c2ecf20Sopenharmony_ci if (!key) 42798c2ecf20Sopenharmony_ci key = rcu_dereference(sdata->default_unicast_key); 42808c2ecf20Sopenharmony_ci if (key) { 42818c2ecf20Sopenharmony_ci switch (key->conf.cipher) { 42828c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_TKIP: 42838c2ecf20Sopenharmony_ci /* we don't want to deal with MMIC in fast-rx */ 42848c2ecf20Sopenharmony_ci goto clear_rcu; 42858c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_CCMP: 42868c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_CCMP_256: 42878c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_GCMP: 42888c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_GCMP_256: 42898c2ecf20Sopenharmony_ci break; 42908c2ecf20Sopenharmony_ci default: 42918c2ecf20Sopenharmony_ci /* We also don't want to deal with 42928c2ecf20Sopenharmony_ci * WEP or cipher scheme. 42938c2ecf20Sopenharmony_ci */ 42948c2ecf20Sopenharmony_ci goto clear_rcu; 42958c2ecf20Sopenharmony_ci } 42968c2ecf20Sopenharmony_ci 42978c2ecf20Sopenharmony_ci fastrx.key = true; 42988c2ecf20Sopenharmony_ci fastrx.icv_len = key->conf.icv_len; 42998c2ecf20Sopenharmony_ci } 43008c2ecf20Sopenharmony_ci 43018c2ecf20Sopenharmony_ci assign = true; 43028c2ecf20Sopenharmony_ci clear_rcu: 43038c2ecf20Sopenharmony_ci rcu_read_unlock(); 43048c2ecf20Sopenharmony_ci clear: 43058c2ecf20Sopenharmony_ci __release(check_fast_rx); 43068c2ecf20Sopenharmony_ci 43078c2ecf20Sopenharmony_ci if (assign) 43088c2ecf20Sopenharmony_ci new = kmemdup(&fastrx, sizeof(fastrx), GFP_KERNEL); 43098c2ecf20Sopenharmony_ci 43108c2ecf20Sopenharmony_ci spin_lock_bh(&sta->lock); 43118c2ecf20Sopenharmony_ci old = rcu_dereference_protected(sta->fast_rx, true); 43128c2ecf20Sopenharmony_ci rcu_assign_pointer(sta->fast_rx, new); 43138c2ecf20Sopenharmony_ci spin_unlock_bh(&sta->lock); 43148c2ecf20Sopenharmony_ci 43158c2ecf20Sopenharmony_ci if (old) 43168c2ecf20Sopenharmony_ci kfree_rcu(old, rcu_head); 43178c2ecf20Sopenharmony_ci} 43188c2ecf20Sopenharmony_ci 43198c2ecf20Sopenharmony_civoid ieee80211_clear_fast_rx(struct sta_info *sta) 43208c2ecf20Sopenharmony_ci{ 43218c2ecf20Sopenharmony_ci struct ieee80211_fast_rx *old; 43228c2ecf20Sopenharmony_ci 43238c2ecf20Sopenharmony_ci spin_lock_bh(&sta->lock); 43248c2ecf20Sopenharmony_ci old = rcu_dereference_protected(sta->fast_rx, true); 43258c2ecf20Sopenharmony_ci RCU_INIT_POINTER(sta->fast_rx, NULL); 43268c2ecf20Sopenharmony_ci spin_unlock_bh(&sta->lock); 43278c2ecf20Sopenharmony_ci 43288c2ecf20Sopenharmony_ci if (old) 43298c2ecf20Sopenharmony_ci kfree_rcu(old, rcu_head); 43308c2ecf20Sopenharmony_ci} 43318c2ecf20Sopenharmony_ci 43328c2ecf20Sopenharmony_civoid __ieee80211_check_fast_rx_iface(struct ieee80211_sub_if_data *sdata) 43338c2ecf20Sopenharmony_ci{ 43348c2ecf20Sopenharmony_ci struct ieee80211_local *local = sdata->local; 43358c2ecf20Sopenharmony_ci struct sta_info *sta; 43368c2ecf20Sopenharmony_ci 43378c2ecf20Sopenharmony_ci lockdep_assert_held(&local->sta_mtx); 43388c2ecf20Sopenharmony_ci 43398c2ecf20Sopenharmony_ci list_for_each_entry(sta, &local->sta_list, list) { 43408c2ecf20Sopenharmony_ci if (sdata != sta->sdata && 43418c2ecf20Sopenharmony_ci (!sta->sdata->bss || sta->sdata->bss != sdata->bss)) 43428c2ecf20Sopenharmony_ci continue; 43438c2ecf20Sopenharmony_ci ieee80211_check_fast_rx(sta); 43448c2ecf20Sopenharmony_ci } 43458c2ecf20Sopenharmony_ci} 43468c2ecf20Sopenharmony_ci 43478c2ecf20Sopenharmony_civoid ieee80211_check_fast_rx_iface(struct ieee80211_sub_if_data *sdata) 43488c2ecf20Sopenharmony_ci{ 43498c2ecf20Sopenharmony_ci struct ieee80211_local *local = sdata->local; 43508c2ecf20Sopenharmony_ci 43518c2ecf20Sopenharmony_ci mutex_lock(&local->sta_mtx); 43528c2ecf20Sopenharmony_ci __ieee80211_check_fast_rx_iface(sdata); 43538c2ecf20Sopenharmony_ci mutex_unlock(&local->sta_mtx); 43548c2ecf20Sopenharmony_ci} 43558c2ecf20Sopenharmony_ci 43568c2ecf20Sopenharmony_cistatic bool ieee80211_invoke_fast_rx(struct ieee80211_rx_data *rx, 43578c2ecf20Sopenharmony_ci struct ieee80211_fast_rx *fast_rx) 43588c2ecf20Sopenharmony_ci{ 43598c2ecf20Sopenharmony_ci struct sk_buff *skb = rx->skb; 43608c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr = (void *)skb->data; 43618c2ecf20Sopenharmony_ci struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); 43628c2ecf20Sopenharmony_ci struct sta_info *sta = rx->sta; 43638c2ecf20Sopenharmony_ci int orig_len = skb->len; 43648c2ecf20Sopenharmony_ci int hdrlen = ieee80211_hdrlen(hdr->frame_control); 43658c2ecf20Sopenharmony_ci int snap_offs = hdrlen; 43668c2ecf20Sopenharmony_ci struct { 43678c2ecf20Sopenharmony_ci u8 snap[sizeof(rfc1042_header)]; 43688c2ecf20Sopenharmony_ci __be16 proto; 43698c2ecf20Sopenharmony_ci } *payload __aligned(2); 43708c2ecf20Sopenharmony_ci struct { 43718c2ecf20Sopenharmony_ci u8 da[ETH_ALEN]; 43728c2ecf20Sopenharmony_ci u8 sa[ETH_ALEN]; 43738c2ecf20Sopenharmony_ci } addrs __aligned(2); 43748c2ecf20Sopenharmony_ci struct ieee80211_sta_rx_stats *stats = &sta->rx_stats; 43758c2ecf20Sopenharmony_ci 43768c2ecf20Sopenharmony_ci if (fast_rx->uses_rss) 43778c2ecf20Sopenharmony_ci stats = this_cpu_ptr(sta->pcpu_rx_stats); 43788c2ecf20Sopenharmony_ci 43798c2ecf20Sopenharmony_ci /* for parallel-rx, we need to have DUP_VALIDATED, otherwise we write 43808c2ecf20Sopenharmony_ci * to a common data structure; drivers can implement that per queue 43818c2ecf20Sopenharmony_ci * but we don't have that information in mac80211 43828c2ecf20Sopenharmony_ci */ 43838c2ecf20Sopenharmony_ci if (!(status->flag & RX_FLAG_DUP_VALIDATED)) 43848c2ecf20Sopenharmony_ci return false; 43858c2ecf20Sopenharmony_ci 43868c2ecf20Sopenharmony_ci#define FAST_RX_CRYPT_FLAGS (RX_FLAG_PN_VALIDATED | RX_FLAG_DECRYPTED) 43878c2ecf20Sopenharmony_ci 43888c2ecf20Sopenharmony_ci /* If using encryption, we also need to have: 43898c2ecf20Sopenharmony_ci * - PN_VALIDATED: similar, but the implementation is tricky 43908c2ecf20Sopenharmony_ci * - DECRYPTED: necessary for PN_VALIDATED 43918c2ecf20Sopenharmony_ci */ 43928c2ecf20Sopenharmony_ci if (fast_rx->key && 43938c2ecf20Sopenharmony_ci (status->flag & FAST_RX_CRYPT_FLAGS) != FAST_RX_CRYPT_FLAGS) 43948c2ecf20Sopenharmony_ci return false; 43958c2ecf20Sopenharmony_ci 43968c2ecf20Sopenharmony_ci if (unlikely(!ieee80211_is_data_present(hdr->frame_control))) 43978c2ecf20Sopenharmony_ci return false; 43988c2ecf20Sopenharmony_ci 43998c2ecf20Sopenharmony_ci if (unlikely(ieee80211_is_frag(hdr))) 44008c2ecf20Sopenharmony_ci return false; 44018c2ecf20Sopenharmony_ci 44028c2ecf20Sopenharmony_ci /* Since our interface address cannot be multicast, this 44038c2ecf20Sopenharmony_ci * implicitly also rejects multicast frames without the 44048c2ecf20Sopenharmony_ci * explicit check. 44058c2ecf20Sopenharmony_ci * 44068c2ecf20Sopenharmony_ci * We shouldn't get any *data* frames not addressed to us 44078c2ecf20Sopenharmony_ci * (AP mode will accept multicast *management* frames), but 44088c2ecf20Sopenharmony_ci * punting here will make it go through the full checks in 44098c2ecf20Sopenharmony_ci * ieee80211_accept_frame(). 44108c2ecf20Sopenharmony_ci */ 44118c2ecf20Sopenharmony_ci if (!ether_addr_equal(fast_rx->vif_addr, hdr->addr1)) 44128c2ecf20Sopenharmony_ci return false; 44138c2ecf20Sopenharmony_ci 44148c2ecf20Sopenharmony_ci if ((hdr->frame_control & cpu_to_le16(IEEE80211_FCTL_FROMDS | 44158c2ecf20Sopenharmony_ci IEEE80211_FCTL_TODS)) != 44168c2ecf20Sopenharmony_ci fast_rx->expected_ds_bits) 44178c2ecf20Sopenharmony_ci return false; 44188c2ecf20Sopenharmony_ci 44198c2ecf20Sopenharmony_ci /* assign the key to drop unencrypted frames (later) 44208c2ecf20Sopenharmony_ci * and strip the IV/MIC if necessary 44218c2ecf20Sopenharmony_ci */ 44228c2ecf20Sopenharmony_ci if (fast_rx->key && !(status->flag & RX_FLAG_IV_STRIPPED)) { 44238c2ecf20Sopenharmony_ci /* GCMP header length is the same */ 44248c2ecf20Sopenharmony_ci snap_offs += IEEE80211_CCMP_HDR_LEN; 44258c2ecf20Sopenharmony_ci } 44268c2ecf20Sopenharmony_ci 44278c2ecf20Sopenharmony_ci if (!(status->rx_flags & IEEE80211_RX_AMSDU)) { 44288c2ecf20Sopenharmony_ci if (!pskb_may_pull(skb, snap_offs + sizeof(*payload))) 44298c2ecf20Sopenharmony_ci goto drop; 44308c2ecf20Sopenharmony_ci 44318c2ecf20Sopenharmony_ci payload = (void *)(skb->data + snap_offs); 44328c2ecf20Sopenharmony_ci 44338c2ecf20Sopenharmony_ci if (!ether_addr_equal(payload->snap, fast_rx->rfc1042_hdr)) 44348c2ecf20Sopenharmony_ci return false; 44358c2ecf20Sopenharmony_ci 44368c2ecf20Sopenharmony_ci /* Don't handle these here since they require special code. 44378c2ecf20Sopenharmony_ci * Accept AARP and IPX even though they should come with a 44388c2ecf20Sopenharmony_ci * bridge-tunnel header - but if we get them this way then 44398c2ecf20Sopenharmony_ci * there's little point in discarding them. 44408c2ecf20Sopenharmony_ci */ 44418c2ecf20Sopenharmony_ci if (unlikely(payload->proto == cpu_to_be16(ETH_P_TDLS) || 44428c2ecf20Sopenharmony_ci payload->proto == fast_rx->control_port_protocol)) 44438c2ecf20Sopenharmony_ci return false; 44448c2ecf20Sopenharmony_ci } 44458c2ecf20Sopenharmony_ci 44468c2ecf20Sopenharmony_ci /* after this point, don't punt to the slowpath! */ 44478c2ecf20Sopenharmony_ci 44488c2ecf20Sopenharmony_ci if (rx->key && !(status->flag & RX_FLAG_MIC_STRIPPED) && 44498c2ecf20Sopenharmony_ci pskb_trim(skb, skb->len - fast_rx->icv_len)) 44508c2ecf20Sopenharmony_ci goto drop; 44518c2ecf20Sopenharmony_ci 44528c2ecf20Sopenharmony_ci /* statistics part of ieee80211_rx_h_sta_process() */ 44538c2ecf20Sopenharmony_ci if (!(status->flag & RX_FLAG_NO_SIGNAL_VAL)) { 44548c2ecf20Sopenharmony_ci stats->last_signal = status->signal; 44558c2ecf20Sopenharmony_ci if (!fast_rx->uses_rss) 44568c2ecf20Sopenharmony_ci ewma_signal_add(&sta->rx_stats_avg.signal, 44578c2ecf20Sopenharmony_ci -status->signal); 44588c2ecf20Sopenharmony_ci } 44598c2ecf20Sopenharmony_ci 44608c2ecf20Sopenharmony_ci if (status->chains) { 44618c2ecf20Sopenharmony_ci int i; 44628c2ecf20Sopenharmony_ci 44638c2ecf20Sopenharmony_ci stats->chains = status->chains; 44648c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(status->chain_signal); i++) { 44658c2ecf20Sopenharmony_ci int signal = status->chain_signal[i]; 44668c2ecf20Sopenharmony_ci 44678c2ecf20Sopenharmony_ci if (!(status->chains & BIT(i))) 44688c2ecf20Sopenharmony_ci continue; 44698c2ecf20Sopenharmony_ci 44708c2ecf20Sopenharmony_ci stats->chain_signal_last[i] = signal; 44718c2ecf20Sopenharmony_ci if (!fast_rx->uses_rss) 44728c2ecf20Sopenharmony_ci ewma_signal_add(&sta->rx_stats_avg.chain_signal[i], 44738c2ecf20Sopenharmony_ci -signal); 44748c2ecf20Sopenharmony_ci } 44758c2ecf20Sopenharmony_ci } 44768c2ecf20Sopenharmony_ci /* end of statistics */ 44778c2ecf20Sopenharmony_ci 44788c2ecf20Sopenharmony_ci if (rx->key && !ieee80211_has_protected(hdr->frame_control)) 44798c2ecf20Sopenharmony_ci goto drop; 44808c2ecf20Sopenharmony_ci 44818c2ecf20Sopenharmony_ci if (status->rx_flags & IEEE80211_RX_AMSDU) { 44828c2ecf20Sopenharmony_ci if (__ieee80211_rx_h_amsdu(rx, snap_offs - hdrlen) != 44838c2ecf20Sopenharmony_ci RX_QUEUED) 44848c2ecf20Sopenharmony_ci goto drop; 44858c2ecf20Sopenharmony_ci 44868c2ecf20Sopenharmony_ci return true; 44878c2ecf20Sopenharmony_ci } 44888c2ecf20Sopenharmony_ci 44898c2ecf20Sopenharmony_ci stats->last_rx = jiffies; 44908c2ecf20Sopenharmony_ci stats->last_rate = sta_stats_encode_rate(status); 44918c2ecf20Sopenharmony_ci 44928c2ecf20Sopenharmony_ci stats->fragments++; 44938c2ecf20Sopenharmony_ci stats->packets++; 44948c2ecf20Sopenharmony_ci 44958c2ecf20Sopenharmony_ci /* do the header conversion - first grab the addresses */ 44968c2ecf20Sopenharmony_ci ether_addr_copy(addrs.da, skb->data + fast_rx->da_offs); 44978c2ecf20Sopenharmony_ci ether_addr_copy(addrs.sa, skb->data + fast_rx->sa_offs); 44988c2ecf20Sopenharmony_ci /* remove the SNAP but leave the ethertype */ 44998c2ecf20Sopenharmony_ci skb_pull(skb, snap_offs + sizeof(rfc1042_header)); 45008c2ecf20Sopenharmony_ci /* push the addresses in front */ 45018c2ecf20Sopenharmony_ci memcpy(skb_push(skb, sizeof(addrs)), &addrs, sizeof(addrs)); 45028c2ecf20Sopenharmony_ci 45038c2ecf20Sopenharmony_ci skb->dev = fast_rx->dev; 45048c2ecf20Sopenharmony_ci 45058c2ecf20Sopenharmony_ci ieee80211_rx_stats(fast_rx->dev, skb->len); 45068c2ecf20Sopenharmony_ci 45078c2ecf20Sopenharmony_ci /* The seqno index has the same property as needed 45088c2ecf20Sopenharmony_ci * for the rx_msdu field, i.e. it is IEEE80211_NUM_TIDS 45098c2ecf20Sopenharmony_ci * for non-QoS-data frames. Here we know it's a data 45108c2ecf20Sopenharmony_ci * frame, so count MSDUs. 45118c2ecf20Sopenharmony_ci */ 45128c2ecf20Sopenharmony_ci u64_stats_update_begin(&stats->syncp); 45138c2ecf20Sopenharmony_ci stats->msdu[rx->seqno_idx]++; 45148c2ecf20Sopenharmony_ci stats->bytes += orig_len; 45158c2ecf20Sopenharmony_ci u64_stats_update_end(&stats->syncp); 45168c2ecf20Sopenharmony_ci 45178c2ecf20Sopenharmony_ci if (fast_rx->internal_forward) { 45188c2ecf20Sopenharmony_ci struct sk_buff *xmit_skb = NULL; 45198c2ecf20Sopenharmony_ci if (is_multicast_ether_addr(addrs.da)) { 45208c2ecf20Sopenharmony_ci xmit_skb = skb_copy(skb, GFP_ATOMIC); 45218c2ecf20Sopenharmony_ci } else if (!ether_addr_equal(addrs.da, addrs.sa) && 45228c2ecf20Sopenharmony_ci sta_info_get(rx->sdata, addrs.da)) { 45238c2ecf20Sopenharmony_ci xmit_skb = skb; 45248c2ecf20Sopenharmony_ci skb = NULL; 45258c2ecf20Sopenharmony_ci } 45268c2ecf20Sopenharmony_ci 45278c2ecf20Sopenharmony_ci if (xmit_skb) { 45288c2ecf20Sopenharmony_ci /* 45298c2ecf20Sopenharmony_ci * Send to wireless media and increase priority by 256 45308c2ecf20Sopenharmony_ci * to keep the received priority instead of 45318c2ecf20Sopenharmony_ci * reclassifying the frame (see cfg80211_classify8021d). 45328c2ecf20Sopenharmony_ci */ 45338c2ecf20Sopenharmony_ci xmit_skb->priority += 256; 45348c2ecf20Sopenharmony_ci xmit_skb->protocol = htons(ETH_P_802_3); 45358c2ecf20Sopenharmony_ci skb_reset_network_header(xmit_skb); 45368c2ecf20Sopenharmony_ci skb_reset_mac_header(xmit_skb); 45378c2ecf20Sopenharmony_ci dev_queue_xmit(xmit_skb); 45388c2ecf20Sopenharmony_ci } 45398c2ecf20Sopenharmony_ci 45408c2ecf20Sopenharmony_ci if (!skb) 45418c2ecf20Sopenharmony_ci return true; 45428c2ecf20Sopenharmony_ci } 45438c2ecf20Sopenharmony_ci 45448c2ecf20Sopenharmony_ci /* deliver to local stack */ 45458c2ecf20Sopenharmony_ci skb->protocol = eth_type_trans(skb, fast_rx->dev); 45468c2ecf20Sopenharmony_ci memset(skb->cb, 0, sizeof(skb->cb)); 45478c2ecf20Sopenharmony_ci if (rx->list) 45488c2ecf20Sopenharmony_ci list_add_tail(&skb->list, rx->list); 45498c2ecf20Sopenharmony_ci else 45508c2ecf20Sopenharmony_ci netif_receive_skb(skb); 45518c2ecf20Sopenharmony_ci 45528c2ecf20Sopenharmony_ci return true; 45538c2ecf20Sopenharmony_ci drop: 45548c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 45558c2ecf20Sopenharmony_ci stats->dropped++; 45568c2ecf20Sopenharmony_ci return true; 45578c2ecf20Sopenharmony_ci} 45588c2ecf20Sopenharmony_ci 45598c2ecf20Sopenharmony_ci/* 45608c2ecf20Sopenharmony_ci * This function returns whether or not the SKB 45618c2ecf20Sopenharmony_ci * was destined for RX processing or not, which, 45628c2ecf20Sopenharmony_ci * if consume is true, is equivalent to whether 45638c2ecf20Sopenharmony_ci * or not the skb was consumed. 45648c2ecf20Sopenharmony_ci */ 45658c2ecf20Sopenharmony_cistatic bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx, 45668c2ecf20Sopenharmony_ci struct sk_buff *skb, bool consume) 45678c2ecf20Sopenharmony_ci{ 45688c2ecf20Sopenharmony_ci struct ieee80211_local *local = rx->local; 45698c2ecf20Sopenharmony_ci struct ieee80211_sub_if_data *sdata = rx->sdata; 45708c2ecf20Sopenharmony_ci 45718c2ecf20Sopenharmony_ci rx->skb = skb; 45728c2ecf20Sopenharmony_ci 45738c2ecf20Sopenharmony_ci /* See if we can do fast-rx; if we have to copy we already lost, 45748c2ecf20Sopenharmony_ci * so punt in that case. We should never have to deliver a data 45758c2ecf20Sopenharmony_ci * frame to multiple interfaces anyway. 45768c2ecf20Sopenharmony_ci * 45778c2ecf20Sopenharmony_ci * We skip the ieee80211_accept_frame() call and do the necessary 45788c2ecf20Sopenharmony_ci * checking inside ieee80211_invoke_fast_rx(). 45798c2ecf20Sopenharmony_ci */ 45808c2ecf20Sopenharmony_ci if (consume && rx->sta) { 45818c2ecf20Sopenharmony_ci struct ieee80211_fast_rx *fast_rx; 45828c2ecf20Sopenharmony_ci 45838c2ecf20Sopenharmony_ci fast_rx = rcu_dereference(rx->sta->fast_rx); 45848c2ecf20Sopenharmony_ci if (fast_rx && ieee80211_invoke_fast_rx(rx, fast_rx)) 45858c2ecf20Sopenharmony_ci return true; 45868c2ecf20Sopenharmony_ci } 45878c2ecf20Sopenharmony_ci 45888c2ecf20Sopenharmony_ci if (!ieee80211_accept_frame(rx)) 45898c2ecf20Sopenharmony_ci return false; 45908c2ecf20Sopenharmony_ci 45918c2ecf20Sopenharmony_ci if (!consume) { 45928c2ecf20Sopenharmony_ci skb = skb_copy(skb, GFP_ATOMIC); 45938c2ecf20Sopenharmony_ci if (!skb) { 45948c2ecf20Sopenharmony_ci if (net_ratelimit()) 45958c2ecf20Sopenharmony_ci wiphy_debug(local->hw.wiphy, 45968c2ecf20Sopenharmony_ci "failed to copy skb for %s\n", 45978c2ecf20Sopenharmony_ci sdata->name); 45988c2ecf20Sopenharmony_ci return true; 45998c2ecf20Sopenharmony_ci } 46008c2ecf20Sopenharmony_ci 46018c2ecf20Sopenharmony_ci rx->skb = skb; 46028c2ecf20Sopenharmony_ci } 46038c2ecf20Sopenharmony_ci 46048c2ecf20Sopenharmony_ci ieee80211_invoke_rx_handlers(rx); 46058c2ecf20Sopenharmony_ci return true; 46068c2ecf20Sopenharmony_ci} 46078c2ecf20Sopenharmony_ci 46088c2ecf20Sopenharmony_ci/* 46098c2ecf20Sopenharmony_ci * This is the actual Rx frames handler. as it belongs to Rx path it must 46108c2ecf20Sopenharmony_ci * be called with rcu_read_lock protection. 46118c2ecf20Sopenharmony_ci */ 46128c2ecf20Sopenharmony_cistatic void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, 46138c2ecf20Sopenharmony_ci struct ieee80211_sta *pubsta, 46148c2ecf20Sopenharmony_ci struct sk_buff *skb, 46158c2ecf20Sopenharmony_ci struct list_head *list) 46168c2ecf20Sopenharmony_ci{ 46178c2ecf20Sopenharmony_ci struct ieee80211_local *local = hw_to_local(hw); 46188c2ecf20Sopenharmony_ci struct ieee80211_sub_if_data *sdata; 46198c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr; 46208c2ecf20Sopenharmony_ci __le16 fc; 46218c2ecf20Sopenharmony_ci struct ieee80211_rx_data rx; 46228c2ecf20Sopenharmony_ci struct ieee80211_sub_if_data *prev; 46238c2ecf20Sopenharmony_ci struct rhlist_head *tmp; 46248c2ecf20Sopenharmony_ci int err = 0; 46258c2ecf20Sopenharmony_ci 46268c2ecf20Sopenharmony_ci fc = ((struct ieee80211_hdr *)skb->data)->frame_control; 46278c2ecf20Sopenharmony_ci memset(&rx, 0, sizeof(rx)); 46288c2ecf20Sopenharmony_ci rx.skb = skb; 46298c2ecf20Sopenharmony_ci rx.local = local; 46308c2ecf20Sopenharmony_ci rx.list = list; 46318c2ecf20Sopenharmony_ci 46328c2ecf20Sopenharmony_ci if (ieee80211_is_data(fc) || ieee80211_is_mgmt(fc)) 46338c2ecf20Sopenharmony_ci I802_DEBUG_INC(local->dot11ReceivedFragmentCount); 46348c2ecf20Sopenharmony_ci 46358c2ecf20Sopenharmony_ci if (ieee80211_is_mgmt(fc)) { 46368c2ecf20Sopenharmony_ci /* drop frame if too short for header */ 46378c2ecf20Sopenharmony_ci if (skb->len < ieee80211_hdrlen(fc)) 46388c2ecf20Sopenharmony_ci err = -ENOBUFS; 46398c2ecf20Sopenharmony_ci else 46408c2ecf20Sopenharmony_ci err = skb_linearize(skb); 46418c2ecf20Sopenharmony_ci } else { 46428c2ecf20Sopenharmony_ci err = !pskb_may_pull(skb, ieee80211_hdrlen(fc)); 46438c2ecf20Sopenharmony_ci } 46448c2ecf20Sopenharmony_ci 46458c2ecf20Sopenharmony_ci if (err) { 46468c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 46478c2ecf20Sopenharmony_ci return; 46488c2ecf20Sopenharmony_ci } 46498c2ecf20Sopenharmony_ci 46508c2ecf20Sopenharmony_ci hdr = (struct ieee80211_hdr *)skb->data; 46518c2ecf20Sopenharmony_ci ieee80211_parse_qos(&rx); 46528c2ecf20Sopenharmony_ci ieee80211_verify_alignment(&rx); 46538c2ecf20Sopenharmony_ci 46548c2ecf20Sopenharmony_ci if (unlikely(ieee80211_is_probe_resp(hdr->frame_control) || 46558c2ecf20Sopenharmony_ci ieee80211_is_beacon(hdr->frame_control) || 46568c2ecf20Sopenharmony_ci ieee80211_is_s1g_beacon(hdr->frame_control))) 46578c2ecf20Sopenharmony_ci ieee80211_scan_rx(local, skb); 46588c2ecf20Sopenharmony_ci 46598c2ecf20Sopenharmony_ci if (ieee80211_is_data(fc)) { 46608c2ecf20Sopenharmony_ci struct sta_info *sta, *prev_sta; 46618c2ecf20Sopenharmony_ci 46628c2ecf20Sopenharmony_ci if (pubsta) { 46638c2ecf20Sopenharmony_ci rx.sta = container_of(pubsta, struct sta_info, sta); 46648c2ecf20Sopenharmony_ci rx.sdata = rx.sta->sdata; 46658c2ecf20Sopenharmony_ci if (ieee80211_prepare_and_rx_handle(&rx, skb, true)) 46668c2ecf20Sopenharmony_ci return; 46678c2ecf20Sopenharmony_ci goto out; 46688c2ecf20Sopenharmony_ci } 46698c2ecf20Sopenharmony_ci 46708c2ecf20Sopenharmony_ci prev_sta = NULL; 46718c2ecf20Sopenharmony_ci 46728c2ecf20Sopenharmony_ci for_each_sta_info(local, hdr->addr2, sta, tmp) { 46738c2ecf20Sopenharmony_ci if (!prev_sta) { 46748c2ecf20Sopenharmony_ci prev_sta = sta; 46758c2ecf20Sopenharmony_ci continue; 46768c2ecf20Sopenharmony_ci } 46778c2ecf20Sopenharmony_ci 46788c2ecf20Sopenharmony_ci rx.sta = prev_sta; 46798c2ecf20Sopenharmony_ci rx.sdata = prev_sta->sdata; 46808c2ecf20Sopenharmony_ci ieee80211_prepare_and_rx_handle(&rx, skb, false); 46818c2ecf20Sopenharmony_ci 46828c2ecf20Sopenharmony_ci prev_sta = sta; 46838c2ecf20Sopenharmony_ci } 46848c2ecf20Sopenharmony_ci 46858c2ecf20Sopenharmony_ci if (prev_sta) { 46868c2ecf20Sopenharmony_ci rx.sta = prev_sta; 46878c2ecf20Sopenharmony_ci rx.sdata = prev_sta->sdata; 46888c2ecf20Sopenharmony_ci 46898c2ecf20Sopenharmony_ci if (ieee80211_prepare_and_rx_handle(&rx, skb, true)) 46908c2ecf20Sopenharmony_ci return; 46918c2ecf20Sopenharmony_ci goto out; 46928c2ecf20Sopenharmony_ci } 46938c2ecf20Sopenharmony_ci } 46948c2ecf20Sopenharmony_ci 46958c2ecf20Sopenharmony_ci prev = NULL; 46968c2ecf20Sopenharmony_ci 46978c2ecf20Sopenharmony_ci list_for_each_entry_rcu(sdata, &local->interfaces, list) { 46988c2ecf20Sopenharmony_ci if (!ieee80211_sdata_running(sdata)) 46998c2ecf20Sopenharmony_ci continue; 47008c2ecf20Sopenharmony_ci 47018c2ecf20Sopenharmony_ci if (sdata->vif.type == NL80211_IFTYPE_MONITOR || 47028c2ecf20Sopenharmony_ci sdata->vif.type == NL80211_IFTYPE_AP_VLAN) 47038c2ecf20Sopenharmony_ci continue; 47048c2ecf20Sopenharmony_ci 47058c2ecf20Sopenharmony_ci /* 47068c2ecf20Sopenharmony_ci * frame is destined for this interface, but if it's 47078c2ecf20Sopenharmony_ci * not also for the previous one we handle that after 47088c2ecf20Sopenharmony_ci * the loop to avoid copying the SKB once too much 47098c2ecf20Sopenharmony_ci */ 47108c2ecf20Sopenharmony_ci 47118c2ecf20Sopenharmony_ci if (!prev) { 47128c2ecf20Sopenharmony_ci prev = sdata; 47138c2ecf20Sopenharmony_ci continue; 47148c2ecf20Sopenharmony_ci } 47158c2ecf20Sopenharmony_ci 47168c2ecf20Sopenharmony_ci rx.sta = sta_info_get_bss(prev, hdr->addr2); 47178c2ecf20Sopenharmony_ci rx.sdata = prev; 47188c2ecf20Sopenharmony_ci ieee80211_prepare_and_rx_handle(&rx, skb, false); 47198c2ecf20Sopenharmony_ci 47208c2ecf20Sopenharmony_ci prev = sdata; 47218c2ecf20Sopenharmony_ci } 47228c2ecf20Sopenharmony_ci 47238c2ecf20Sopenharmony_ci if (prev) { 47248c2ecf20Sopenharmony_ci rx.sta = sta_info_get_bss(prev, hdr->addr2); 47258c2ecf20Sopenharmony_ci rx.sdata = prev; 47268c2ecf20Sopenharmony_ci 47278c2ecf20Sopenharmony_ci if (ieee80211_prepare_and_rx_handle(&rx, skb, true)) 47288c2ecf20Sopenharmony_ci return; 47298c2ecf20Sopenharmony_ci } 47308c2ecf20Sopenharmony_ci 47318c2ecf20Sopenharmony_ci out: 47328c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 47338c2ecf20Sopenharmony_ci} 47348c2ecf20Sopenharmony_ci 47358c2ecf20Sopenharmony_ci/* 47368c2ecf20Sopenharmony_ci * This is the receive path handler. It is called by a low level driver when an 47378c2ecf20Sopenharmony_ci * 802.11 MPDU is received from the hardware. 47388c2ecf20Sopenharmony_ci */ 47398c2ecf20Sopenharmony_civoid ieee80211_rx_list(struct ieee80211_hw *hw, struct ieee80211_sta *pubsta, 47408c2ecf20Sopenharmony_ci struct sk_buff *skb, struct list_head *list) 47418c2ecf20Sopenharmony_ci{ 47428c2ecf20Sopenharmony_ci struct ieee80211_local *local = hw_to_local(hw); 47438c2ecf20Sopenharmony_ci struct ieee80211_rate *rate = NULL; 47448c2ecf20Sopenharmony_ci struct ieee80211_supported_band *sband; 47458c2ecf20Sopenharmony_ci struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); 47468c2ecf20Sopenharmony_ci 47478c2ecf20Sopenharmony_ci WARN_ON_ONCE(softirq_count() == 0); 47488c2ecf20Sopenharmony_ci 47498c2ecf20Sopenharmony_ci if (WARN_ON(status->band >= NUM_NL80211_BANDS)) 47508c2ecf20Sopenharmony_ci goto drop; 47518c2ecf20Sopenharmony_ci 47528c2ecf20Sopenharmony_ci sband = local->hw.wiphy->bands[status->band]; 47538c2ecf20Sopenharmony_ci if (WARN_ON(!sband)) 47548c2ecf20Sopenharmony_ci goto drop; 47558c2ecf20Sopenharmony_ci 47568c2ecf20Sopenharmony_ci /* 47578c2ecf20Sopenharmony_ci * If we're suspending, it is possible although not too likely 47588c2ecf20Sopenharmony_ci * that we'd be receiving frames after having already partially 47598c2ecf20Sopenharmony_ci * quiesced the stack. We can't process such frames then since 47608c2ecf20Sopenharmony_ci * that might, for example, cause stations to be added or other 47618c2ecf20Sopenharmony_ci * driver callbacks be invoked. 47628c2ecf20Sopenharmony_ci */ 47638c2ecf20Sopenharmony_ci if (unlikely(local->quiescing || local->suspended)) 47648c2ecf20Sopenharmony_ci goto drop; 47658c2ecf20Sopenharmony_ci 47668c2ecf20Sopenharmony_ci /* We might be during a HW reconfig, prevent Rx for the same reason */ 47678c2ecf20Sopenharmony_ci if (unlikely(local->in_reconfig)) 47688c2ecf20Sopenharmony_ci goto drop; 47698c2ecf20Sopenharmony_ci 47708c2ecf20Sopenharmony_ci /* 47718c2ecf20Sopenharmony_ci * The same happens when we're not even started, 47728c2ecf20Sopenharmony_ci * but that's worth a warning. 47738c2ecf20Sopenharmony_ci */ 47748c2ecf20Sopenharmony_ci if (WARN_ON(!local->started)) 47758c2ecf20Sopenharmony_ci goto drop; 47768c2ecf20Sopenharmony_ci 47778c2ecf20Sopenharmony_ci if (likely(!(status->flag & RX_FLAG_FAILED_PLCP_CRC))) { 47788c2ecf20Sopenharmony_ci /* 47798c2ecf20Sopenharmony_ci * Validate the rate, unless a PLCP error means that 47808c2ecf20Sopenharmony_ci * we probably can't have a valid rate here anyway. 47818c2ecf20Sopenharmony_ci */ 47828c2ecf20Sopenharmony_ci 47838c2ecf20Sopenharmony_ci switch (status->encoding) { 47848c2ecf20Sopenharmony_ci case RX_ENC_HT: 47858c2ecf20Sopenharmony_ci /* 47868c2ecf20Sopenharmony_ci * rate_idx is MCS index, which can be [0-76] 47878c2ecf20Sopenharmony_ci * as documented on: 47888c2ecf20Sopenharmony_ci * 47898c2ecf20Sopenharmony_ci * https://wireless.wiki.kernel.org/en/developers/Documentation/ieee80211/802.11n 47908c2ecf20Sopenharmony_ci * 47918c2ecf20Sopenharmony_ci * Anything else would be some sort of driver or 47928c2ecf20Sopenharmony_ci * hardware error. The driver should catch hardware 47938c2ecf20Sopenharmony_ci * errors. 47948c2ecf20Sopenharmony_ci */ 47958c2ecf20Sopenharmony_ci if (WARN(status->rate_idx > 76, 47968c2ecf20Sopenharmony_ci "Rate marked as an HT rate but passed " 47978c2ecf20Sopenharmony_ci "status->rate_idx is not " 47988c2ecf20Sopenharmony_ci "an MCS index [0-76]: %d (0x%02x)\n", 47998c2ecf20Sopenharmony_ci status->rate_idx, 48008c2ecf20Sopenharmony_ci status->rate_idx)) 48018c2ecf20Sopenharmony_ci goto drop; 48028c2ecf20Sopenharmony_ci break; 48038c2ecf20Sopenharmony_ci case RX_ENC_VHT: 48048c2ecf20Sopenharmony_ci if (WARN_ONCE(status->rate_idx > 11 || 48058c2ecf20Sopenharmony_ci !status->nss || 48068c2ecf20Sopenharmony_ci status->nss > 8, 48078c2ecf20Sopenharmony_ci "Rate marked as a VHT rate but data is invalid: MCS: %d, NSS: %d\n", 48088c2ecf20Sopenharmony_ci status->rate_idx, status->nss)) 48098c2ecf20Sopenharmony_ci goto drop; 48108c2ecf20Sopenharmony_ci break; 48118c2ecf20Sopenharmony_ci case RX_ENC_HE: 48128c2ecf20Sopenharmony_ci if (WARN_ONCE(status->rate_idx > 11 || 48138c2ecf20Sopenharmony_ci !status->nss || 48148c2ecf20Sopenharmony_ci status->nss > 8, 48158c2ecf20Sopenharmony_ci "Rate marked as an HE rate but data is invalid: MCS: %d, NSS: %d\n", 48168c2ecf20Sopenharmony_ci status->rate_idx, status->nss)) 48178c2ecf20Sopenharmony_ci goto drop; 48188c2ecf20Sopenharmony_ci break; 48198c2ecf20Sopenharmony_ci default: 48208c2ecf20Sopenharmony_ci WARN_ON_ONCE(1); 48218c2ecf20Sopenharmony_ci fallthrough; 48228c2ecf20Sopenharmony_ci case RX_ENC_LEGACY: 48238c2ecf20Sopenharmony_ci if (WARN_ON(status->rate_idx >= sband->n_bitrates)) 48248c2ecf20Sopenharmony_ci goto drop; 48258c2ecf20Sopenharmony_ci rate = &sband->bitrates[status->rate_idx]; 48268c2ecf20Sopenharmony_ci } 48278c2ecf20Sopenharmony_ci } 48288c2ecf20Sopenharmony_ci 48298c2ecf20Sopenharmony_ci status->rx_flags = 0; 48308c2ecf20Sopenharmony_ci 48318c2ecf20Sopenharmony_ci /* 48328c2ecf20Sopenharmony_ci * Frames with failed FCS/PLCP checksum are not returned, 48338c2ecf20Sopenharmony_ci * all other frames are returned without radiotap header 48348c2ecf20Sopenharmony_ci * if it was previously present. 48358c2ecf20Sopenharmony_ci * Also, frames with less than 16 bytes are dropped. 48368c2ecf20Sopenharmony_ci */ 48378c2ecf20Sopenharmony_ci skb = ieee80211_rx_monitor(local, skb, rate); 48388c2ecf20Sopenharmony_ci if (!skb) 48398c2ecf20Sopenharmony_ci return; 48408c2ecf20Sopenharmony_ci 48418c2ecf20Sopenharmony_ci ieee80211_tpt_led_trig_rx(local, 48428c2ecf20Sopenharmony_ci ((struct ieee80211_hdr *)skb->data)->frame_control, 48438c2ecf20Sopenharmony_ci skb->len); 48448c2ecf20Sopenharmony_ci 48458c2ecf20Sopenharmony_ci __ieee80211_rx_handle_packet(hw, pubsta, skb, list); 48468c2ecf20Sopenharmony_ci 48478c2ecf20Sopenharmony_ci return; 48488c2ecf20Sopenharmony_ci drop: 48498c2ecf20Sopenharmony_ci kfree_skb(skb); 48508c2ecf20Sopenharmony_ci} 48518c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ieee80211_rx_list); 48528c2ecf20Sopenharmony_ci 48538c2ecf20Sopenharmony_civoid ieee80211_rx_napi(struct ieee80211_hw *hw, struct ieee80211_sta *pubsta, 48548c2ecf20Sopenharmony_ci struct sk_buff *skb, struct napi_struct *napi) 48558c2ecf20Sopenharmony_ci{ 48568c2ecf20Sopenharmony_ci struct sk_buff *tmp; 48578c2ecf20Sopenharmony_ci LIST_HEAD(list); 48588c2ecf20Sopenharmony_ci 48598c2ecf20Sopenharmony_ci 48608c2ecf20Sopenharmony_ci /* 48618c2ecf20Sopenharmony_ci * key references and virtual interfaces are protected using RCU 48628c2ecf20Sopenharmony_ci * and this requires that we are in a read-side RCU section during 48638c2ecf20Sopenharmony_ci * receive processing 48648c2ecf20Sopenharmony_ci */ 48658c2ecf20Sopenharmony_ci rcu_read_lock(); 48668c2ecf20Sopenharmony_ci ieee80211_rx_list(hw, pubsta, skb, &list); 48678c2ecf20Sopenharmony_ci rcu_read_unlock(); 48688c2ecf20Sopenharmony_ci 48698c2ecf20Sopenharmony_ci if (!napi) { 48708c2ecf20Sopenharmony_ci netif_receive_skb_list(&list); 48718c2ecf20Sopenharmony_ci return; 48728c2ecf20Sopenharmony_ci } 48738c2ecf20Sopenharmony_ci 48748c2ecf20Sopenharmony_ci list_for_each_entry_safe(skb, tmp, &list, list) { 48758c2ecf20Sopenharmony_ci skb_list_del_init(skb); 48768c2ecf20Sopenharmony_ci napi_gro_receive(napi, skb); 48778c2ecf20Sopenharmony_ci } 48788c2ecf20Sopenharmony_ci} 48798c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ieee80211_rx_napi); 48808c2ecf20Sopenharmony_ci 48818c2ecf20Sopenharmony_ci/* This is a version of the rx handler that can be called from hard irq 48828c2ecf20Sopenharmony_ci * context. Post the skb on the queue and schedule the tasklet */ 48838c2ecf20Sopenharmony_civoid ieee80211_rx_irqsafe(struct ieee80211_hw *hw, struct sk_buff *skb) 48848c2ecf20Sopenharmony_ci{ 48858c2ecf20Sopenharmony_ci struct ieee80211_local *local = hw_to_local(hw); 48868c2ecf20Sopenharmony_ci 48878c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(struct ieee80211_rx_status) > sizeof(skb->cb)); 48888c2ecf20Sopenharmony_ci 48898c2ecf20Sopenharmony_ci skb->pkt_type = IEEE80211_RX_MSG; 48908c2ecf20Sopenharmony_ci skb_queue_tail(&local->skb_queue, skb); 48918c2ecf20Sopenharmony_ci tasklet_schedule(&local->tasklet); 48928c2ecf20Sopenharmony_ci} 48938c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ieee80211_rx_irqsafe); 4894