18c2ecf20Sopenharmony_ci/****************************************************************************** 28c2ecf20Sopenharmony_ci * 38c2ecf20Sopenharmony_ci * This file is provided under a dual BSD/GPLv2 license. When using or 48c2ecf20Sopenharmony_ci * redistributing this file, you may do so under either license. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * GPL LICENSE SUMMARY 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. 98c2ecf20Sopenharmony_ci * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH 108c2ecf20Sopenharmony_ci * Copyright(c) 2015 - 2017 Intel Deutschland GmbH 118c2ecf20Sopenharmony_ci * Copyright(c) 2018 - 2020 Intel Corporation 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 148c2ecf20Sopenharmony_ci * it under the terms of version 2 of the GNU General Public License as 158c2ecf20Sopenharmony_ci * published by the Free Software Foundation. 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * This program is distributed in the hope that it will be useful, but 188c2ecf20Sopenharmony_ci * WITHOUT ANY WARRANTY; without even the implied warranty of 198c2ecf20Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 208c2ecf20Sopenharmony_ci * General Public License for more details. 218c2ecf20Sopenharmony_ci * 228c2ecf20Sopenharmony_ci * The full GNU General Public License is included in this distribution 238c2ecf20Sopenharmony_ci * in the file called COPYING. 248c2ecf20Sopenharmony_ci * 258c2ecf20Sopenharmony_ci * Contact Information: 268c2ecf20Sopenharmony_ci * Intel Linux Wireless <linuxwifi@intel.com> 278c2ecf20Sopenharmony_ci * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 288c2ecf20Sopenharmony_ci * 298c2ecf20Sopenharmony_ci * BSD LICENSE 308c2ecf20Sopenharmony_ci * 318c2ecf20Sopenharmony_ci * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. 328c2ecf20Sopenharmony_ci * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH 338c2ecf20Sopenharmony_ci * Copyright(c) 2015 - 2017 Intel Deutschland GmbH 348c2ecf20Sopenharmony_ci * Copyright(c) 2018 - 2020 Intel Corporation 358c2ecf20Sopenharmony_ci * All rights reserved. 368c2ecf20Sopenharmony_ci * 378c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 388c2ecf20Sopenharmony_ci * modification, are permitted provided that the following conditions 398c2ecf20Sopenharmony_ci * are met: 408c2ecf20Sopenharmony_ci * 418c2ecf20Sopenharmony_ci * * Redistributions of source code must retain the above copyright 428c2ecf20Sopenharmony_ci * notice, this list of conditions and the following disclaimer. 438c2ecf20Sopenharmony_ci * * Redistributions in binary form must reproduce the above copyright 448c2ecf20Sopenharmony_ci * notice, this list of conditions and the following disclaimer in 458c2ecf20Sopenharmony_ci * the documentation and/or other materials provided with the 468c2ecf20Sopenharmony_ci * distribution. 478c2ecf20Sopenharmony_ci * * Neither the name Intel Corporation nor the names of its 488c2ecf20Sopenharmony_ci * contributors may be used to endorse or promote products derived 498c2ecf20Sopenharmony_ci * from this software without specific prior written permission. 508c2ecf20Sopenharmony_ci * 518c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 528c2ecf20Sopenharmony_ci * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 538c2ecf20Sopenharmony_ci * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 548c2ecf20Sopenharmony_ci * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 558c2ecf20Sopenharmony_ci * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 568c2ecf20Sopenharmony_ci * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 578c2ecf20Sopenharmony_ci * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 588c2ecf20Sopenharmony_ci * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 598c2ecf20Sopenharmony_ci * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 608c2ecf20Sopenharmony_ci * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 618c2ecf20Sopenharmony_ci * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 628c2ecf20Sopenharmony_ci *****************************************************************************/ 638c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 648c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 658c2ecf20Sopenharmony_ci#include "iwl-trans.h" 668c2ecf20Sopenharmony_ci#include "mvm.h" 678c2ecf20Sopenharmony_ci#include "fw-api.h" 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_cistatic void *iwl_mvm_skb_get_hdr(struct sk_buff *skb) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); 728c2ecf20Sopenharmony_ci u8 *data = skb->data; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci /* Alignment concerns */ 758c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(struct ieee80211_radiotap_he) % 4); 768c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(struct ieee80211_radiotap_he_mu) % 4); 778c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(struct ieee80211_radiotap_lsig) % 4); 788c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(struct ieee80211_vendor_radiotap) % 4); 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci if (rx_status->flag & RX_FLAG_RADIOTAP_HE) 818c2ecf20Sopenharmony_ci data += sizeof(struct ieee80211_radiotap_he); 828c2ecf20Sopenharmony_ci if (rx_status->flag & RX_FLAG_RADIOTAP_HE_MU) 838c2ecf20Sopenharmony_ci data += sizeof(struct ieee80211_radiotap_he_mu); 848c2ecf20Sopenharmony_ci if (rx_status->flag & RX_FLAG_RADIOTAP_LSIG) 858c2ecf20Sopenharmony_ci data += sizeof(struct ieee80211_radiotap_lsig); 868c2ecf20Sopenharmony_ci if (rx_status->flag & RX_FLAG_RADIOTAP_VENDOR_DATA) { 878c2ecf20Sopenharmony_ci struct ieee80211_vendor_radiotap *radiotap = (void *)data; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci data += sizeof(*radiotap) + radiotap->len + radiotap->pad; 908c2ecf20Sopenharmony_ci } 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci return data; 938c2ecf20Sopenharmony_ci} 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_cistatic inline int iwl_mvm_check_pn(struct iwl_mvm *mvm, struct sk_buff *skb, 968c2ecf20Sopenharmony_ci int queue, struct ieee80211_sta *sta) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci struct iwl_mvm_sta *mvmsta; 998c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr = iwl_mvm_skb_get_hdr(skb); 1008c2ecf20Sopenharmony_ci struct ieee80211_rx_status *stats = IEEE80211_SKB_RXCB(skb); 1018c2ecf20Sopenharmony_ci struct iwl_mvm_key_pn *ptk_pn; 1028c2ecf20Sopenharmony_ci int res; 1038c2ecf20Sopenharmony_ci u8 tid, keyidx; 1048c2ecf20Sopenharmony_ci u8 pn[IEEE80211_CCMP_PN_LEN]; 1058c2ecf20Sopenharmony_ci u8 *extiv; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci /* do PN checking */ 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci /* multicast and non-data only arrives on default queue */ 1108c2ecf20Sopenharmony_ci if (!ieee80211_is_data(hdr->frame_control) || 1118c2ecf20Sopenharmony_ci is_multicast_ether_addr(hdr->addr1)) 1128c2ecf20Sopenharmony_ci return 0; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci /* do not check PN for open AP */ 1158c2ecf20Sopenharmony_ci if (!(stats->flag & RX_FLAG_DECRYPTED)) 1168c2ecf20Sopenharmony_ci return 0; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci /* 1198c2ecf20Sopenharmony_ci * avoid checking for default queue - we don't want to replicate 1208c2ecf20Sopenharmony_ci * all the logic that's necessary for checking the PN on fragmented 1218c2ecf20Sopenharmony_ci * frames, leave that to mac80211 1228c2ecf20Sopenharmony_ci */ 1238c2ecf20Sopenharmony_ci if (queue == 0) 1248c2ecf20Sopenharmony_ci return 0; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci /* if we are here - this for sure is either CCMP or GCMP */ 1278c2ecf20Sopenharmony_ci if (IS_ERR_OR_NULL(sta)) { 1288c2ecf20Sopenharmony_ci IWL_ERR(mvm, 1298c2ecf20Sopenharmony_ci "expected hw-decrypted unicast frame for station\n"); 1308c2ecf20Sopenharmony_ci return -1; 1318c2ecf20Sopenharmony_ci } 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci mvmsta = iwl_mvm_sta_from_mac80211(sta); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci extiv = (u8 *)hdr + ieee80211_hdrlen(hdr->frame_control); 1368c2ecf20Sopenharmony_ci keyidx = extiv[3] >> 6; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci ptk_pn = rcu_dereference(mvmsta->ptk_pn[keyidx]); 1398c2ecf20Sopenharmony_ci if (!ptk_pn) 1408c2ecf20Sopenharmony_ci return -1; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci if (ieee80211_is_data_qos(hdr->frame_control)) 1438c2ecf20Sopenharmony_ci tid = ieee80211_get_tid(hdr); 1448c2ecf20Sopenharmony_ci else 1458c2ecf20Sopenharmony_ci tid = 0; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci /* we don't use HCCA/802.11 QoS TSPECs, so drop such frames */ 1488c2ecf20Sopenharmony_ci if (tid >= IWL_MAX_TID_COUNT) 1498c2ecf20Sopenharmony_ci return -1; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci /* load pn */ 1528c2ecf20Sopenharmony_ci pn[0] = extiv[7]; 1538c2ecf20Sopenharmony_ci pn[1] = extiv[6]; 1548c2ecf20Sopenharmony_ci pn[2] = extiv[5]; 1558c2ecf20Sopenharmony_ci pn[3] = extiv[4]; 1568c2ecf20Sopenharmony_ci pn[4] = extiv[1]; 1578c2ecf20Sopenharmony_ci pn[5] = extiv[0]; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci res = memcmp(pn, ptk_pn->q[queue].pn[tid], IEEE80211_CCMP_PN_LEN); 1608c2ecf20Sopenharmony_ci if (res < 0) 1618c2ecf20Sopenharmony_ci return -1; 1628c2ecf20Sopenharmony_ci if (!res && !(stats->flag & RX_FLAG_ALLOW_SAME_PN)) 1638c2ecf20Sopenharmony_ci return -1; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci memcpy(ptk_pn->q[queue].pn[tid], pn, IEEE80211_CCMP_PN_LEN); 1668c2ecf20Sopenharmony_ci stats->flag |= RX_FLAG_PN_VALIDATED; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci return 0; 1698c2ecf20Sopenharmony_ci} 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci/* iwl_mvm_create_skb Adds the rxb to a new skb */ 1728c2ecf20Sopenharmony_cistatic int iwl_mvm_create_skb(struct iwl_mvm *mvm, struct sk_buff *skb, 1738c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr, u16 len, u8 crypt_len, 1748c2ecf20Sopenharmony_ci struct iwl_rx_cmd_buffer *rxb) 1758c2ecf20Sopenharmony_ci{ 1768c2ecf20Sopenharmony_ci struct iwl_rx_packet *pkt = rxb_addr(rxb); 1778c2ecf20Sopenharmony_ci struct iwl_rx_mpdu_desc *desc = (void *)pkt->data; 1788c2ecf20Sopenharmony_ci unsigned int headlen, fraglen, pad_len = 0; 1798c2ecf20Sopenharmony_ci unsigned int hdrlen = ieee80211_hdrlen(hdr->frame_control); 1808c2ecf20Sopenharmony_ci u8 mic_crc_len = u8_get_bits(desc->mac_flags1, 1818c2ecf20Sopenharmony_ci IWL_RX_MPDU_MFLG1_MIC_CRC_LEN_MASK) << 1; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci if (desc->mac_flags2 & IWL_RX_MPDU_MFLG2_PAD) { 1848c2ecf20Sopenharmony_ci len -= 2; 1858c2ecf20Sopenharmony_ci pad_len = 2; 1868c2ecf20Sopenharmony_ci } 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci /* 1898c2ecf20Sopenharmony_ci * For non monitor interface strip the bytes the RADA might not have 1908c2ecf20Sopenharmony_ci * removed. As monitor interface cannot exist with other interfaces 1918c2ecf20Sopenharmony_ci * this removal is safe. 1928c2ecf20Sopenharmony_ci */ 1938c2ecf20Sopenharmony_ci if (mic_crc_len && !ieee80211_hw_check(mvm->hw, RX_INCLUDES_FCS)) { 1948c2ecf20Sopenharmony_ci u32 pkt_flags = le32_to_cpu(pkt->len_n_flags); 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci /* 1978c2ecf20Sopenharmony_ci * If RADA was not enabled then decryption was not performed so 1988c2ecf20Sopenharmony_ci * the MIC cannot be removed. 1998c2ecf20Sopenharmony_ci */ 2008c2ecf20Sopenharmony_ci if (!(pkt_flags & FH_RSCSR_RADA_EN)) { 2018c2ecf20Sopenharmony_ci if (WARN_ON(crypt_len > mic_crc_len)) 2028c2ecf20Sopenharmony_ci return -EINVAL; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci mic_crc_len -= crypt_len; 2058c2ecf20Sopenharmony_ci } 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci if (WARN_ON(mic_crc_len > len)) 2088c2ecf20Sopenharmony_ci return -EINVAL; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci len -= mic_crc_len; 2118c2ecf20Sopenharmony_ci } 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci /* If frame is small enough to fit in skb->head, pull it completely. 2148c2ecf20Sopenharmony_ci * If not, only pull ieee80211_hdr (including crypto if present, and 2158c2ecf20Sopenharmony_ci * an additional 8 bytes for SNAP/ethertype, see below) so that 2168c2ecf20Sopenharmony_ci * splice() or TCP coalesce are more efficient. 2178c2ecf20Sopenharmony_ci * 2188c2ecf20Sopenharmony_ci * Since, in addition, ieee80211_data_to_8023() always pull in at 2198c2ecf20Sopenharmony_ci * least 8 bytes (possibly more for mesh) we can do the same here 2208c2ecf20Sopenharmony_ci * to save the cost of doing it later. That still doesn't pull in 2218c2ecf20Sopenharmony_ci * the actual IP header since the typical case has a SNAP header. 2228c2ecf20Sopenharmony_ci * If the latter changes (there are efforts in the standards group 2238c2ecf20Sopenharmony_ci * to do so) we should revisit this and ieee80211_data_to_8023(). 2248c2ecf20Sopenharmony_ci */ 2258c2ecf20Sopenharmony_ci headlen = (len <= skb_tailroom(skb)) ? len : 2268c2ecf20Sopenharmony_ci hdrlen + crypt_len + 8; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci /* The firmware may align the packet to DWORD. 2298c2ecf20Sopenharmony_ci * The padding is inserted after the IV. 2308c2ecf20Sopenharmony_ci * After copying the header + IV skip the padding if 2318c2ecf20Sopenharmony_ci * present before copying packet data. 2328c2ecf20Sopenharmony_ci */ 2338c2ecf20Sopenharmony_ci hdrlen += crypt_len; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci if (WARN_ONCE(headlen < hdrlen, 2368c2ecf20Sopenharmony_ci "invalid packet lengths (hdrlen=%d, len=%d, crypt_len=%d)\n", 2378c2ecf20Sopenharmony_ci hdrlen, len, crypt_len)) { 2388c2ecf20Sopenharmony_ci /* 2398c2ecf20Sopenharmony_ci * We warn and trace because we want to be able to see 2408c2ecf20Sopenharmony_ci * it in trace-cmd as well. 2418c2ecf20Sopenharmony_ci */ 2428c2ecf20Sopenharmony_ci IWL_DEBUG_RX(mvm, 2438c2ecf20Sopenharmony_ci "invalid packet lengths (hdrlen=%d, len=%d, crypt_len=%d)\n", 2448c2ecf20Sopenharmony_ci hdrlen, len, crypt_len); 2458c2ecf20Sopenharmony_ci return -EINVAL; 2468c2ecf20Sopenharmony_ci } 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci skb_put_data(skb, hdr, hdrlen); 2498c2ecf20Sopenharmony_ci skb_put_data(skb, (u8 *)hdr + hdrlen + pad_len, headlen - hdrlen); 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci /* 2528c2ecf20Sopenharmony_ci * If we did CHECKSUM_COMPLETE, the hardware only does it right for 2538c2ecf20Sopenharmony_ci * certain cases and starts the checksum after the SNAP. Check if 2548c2ecf20Sopenharmony_ci * this is the case - it's easier to just bail out to CHECKSUM_NONE 2558c2ecf20Sopenharmony_ci * in the cases the hardware didn't handle, since it's rare to see 2568c2ecf20Sopenharmony_ci * such packets, even though the hardware did calculate the checksum 2578c2ecf20Sopenharmony_ci * in this case, just starting after the MAC header instead. 2588c2ecf20Sopenharmony_ci */ 2598c2ecf20Sopenharmony_ci if (skb->ip_summed == CHECKSUM_COMPLETE) { 2608c2ecf20Sopenharmony_ci struct { 2618c2ecf20Sopenharmony_ci u8 hdr[6]; 2628c2ecf20Sopenharmony_ci __be16 type; 2638c2ecf20Sopenharmony_ci } __packed *shdr = (void *)((u8 *)hdr + hdrlen + pad_len); 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci if (unlikely(headlen - hdrlen < sizeof(*shdr) || 2668c2ecf20Sopenharmony_ci !ether_addr_equal(shdr->hdr, rfc1042_header) || 2678c2ecf20Sopenharmony_ci (shdr->type != htons(ETH_P_IP) && 2688c2ecf20Sopenharmony_ci shdr->type != htons(ETH_P_ARP) && 2698c2ecf20Sopenharmony_ci shdr->type != htons(ETH_P_IPV6) && 2708c2ecf20Sopenharmony_ci shdr->type != htons(ETH_P_8021Q) && 2718c2ecf20Sopenharmony_ci shdr->type != htons(ETH_P_PAE) && 2728c2ecf20Sopenharmony_ci shdr->type != htons(ETH_P_TDLS)))) 2738c2ecf20Sopenharmony_ci skb->ip_summed = CHECKSUM_NONE; 2748c2ecf20Sopenharmony_ci } 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci fraglen = len - headlen; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci if (fraglen) { 2798c2ecf20Sopenharmony_ci int offset = (void *)hdr + headlen + pad_len - 2808c2ecf20Sopenharmony_ci rxb_addr(rxb) + rxb_offset(rxb); 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci skb_add_rx_frag(skb, 0, rxb_steal_page(rxb), offset, 2838c2ecf20Sopenharmony_ci fraglen, rxb->truesize); 2848c2ecf20Sopenharmony_ci } 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci return 0; 2878c2ecf20Sopenharmony_ci} 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_cistatic void iwl_mvm_add_rtap_sniffer_config(struct iwl_mvm *mvm, 2908c2ecf20Sopenharmony_ci struct sk_buff *skb) 2918c2ecf20Sopenharmony_ci{ 2928c2ecf20Sopenharmony_ci struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); 2938c2ecf20Sopenharmony_ci struct ieee80211_vendor_radiotap *radiotap; 2948c2ecf20Sopenharmony_ci const int size = sizeof(*radiotap) + sizeof(__le16); 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci if (!mvm->cur_aid) 2978c2ecf20Sopenharmony_ci return; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci /* ensure alignment */ 3008c2ecf20Sopenharmony_ci BUILD_BUG_ON((size + 2) % 4); 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci radiotap = skb_put(skb, size + 2); 3038c2ecf20Sopenharmony_ci radiotap->align = 1; 3048c2ecf20Sopenharmony_ci /* Intel OUI */ 3058c2ecf20Sopenharmony_ci radiotap->oui[0] = 0xf6; 3068c2ecf20Sopenharmony_ci radiotap->oui[1] = 0x54; 3078c2ecf20Sopenharmony_ci radiotap->oui[2] = 0x25; 3088c2ecf20Sopenharmony_ci /* radiotap sniffer config sub-namespace */ 3098c2ecf20Sopenharmony_ci radiotap->subns = 1; 3108c2ecf20Sopenharmony_ci radiotap->present = 0x1; 3118c2ecf20Sopenharmony_ci radiotap->len = size - sizeof(*radiotap); 3128c2ecf20Sopenharmony_ci radiotap->pad = 2; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci /* fill the data now */ 3158c2ecf20Sopenharmony_ci memcpy(radiotap->data, &mvm->cur_aid, sizeof(mvm->cur_aid)); 3168c2ecf20Sopenharmony_ci /* and clear the padding */ 3178c2ecf20Sopenharmony_ci memset(radiotap->data + sizeof(__le16), 0, radiotap->pad); 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci rx_status->flag |= RX_FLAG_RADIOTAP_VENDOR_DATA; 3208c2ecf20Sopenharmony_ci} 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci/* iwl_mvm_pass_packet_to_mac80211 - passes the packet for mac80211 */ 3238c2ecf20Sopenharmony_cistatic void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm, 3248c2ecf20Sopenharmony_ci struct napi_struct *napi, 3258c2ecf20Sopenharmony_ci struct sk_buff *skb, int queue, 3268c2ecf20Sopenharmony_ci struct ieee80211_sta *sta, 3278c2ecf20Sopenharmony_ci bool csi) 3288c2ecf20Sopenharmony_ci{ 3298c2ecf20Sopenharmony_ci if (iwl_mvm_check_pn(mvm, skb, queue, sta)) 3308c2ecf20Sopenharmony_ci kfree_skb(skb); 3318c2ecf20Sopenharmony_ci else 3328c2ecf20Sopenharmony_ci ieee80211_rx_napi(mvm->hw, sta, skb, napi); 3338c2ecf20Sopenharmony_ci} 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_cistatic void iwl_mvm_get_signal_strength(struct iwl_mvm *mvm, 3368c2ecf20Sopenharmony_ci struct ieee80211_rx_status *rx_status, 3378c2ecf20Sopenharmony_ci u32 rate_n_flags, int energy_a, 3388c2ecf20Sopenharmony_ci int energy_b) 3398c2ecf20Sopenharmony_ci{ 3408c2ecf20Sopenharmony_ci int max_energy; 3418c2ecf20Sopenharmony_ci u32 rate_flags = rate_n_flags; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci energy_a = energy_a ? -energy_a : S8_MIN; 3448c2ecf20Sopenharmony_ci energy_b = energy_b ? -energy_b : S8_MIN; 3458c2ecf20Sopenharmony_ci max_energy = max(energy_a, energy_b); 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci IWL_DEBUG_STATS(mvm, "energy In A %d B %d, and max %d\n", 3488c2ecf20Sopenharmony_ci energy_a, energy_b, max_energy); 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci rx_status->signal = max_energy; 3518c2ecf20Sopenharmony_ci rx_status->chains = 3528c2ecf20Sopenharmony_ci (rate_flags & RATE_MCS_ANT_AB_MSK) >> RATE_MCS_ANT_POS; 3538c2ecf20Sopenharmony_ci rx_status->chain_signal[0] = energy_a; 3548c2ecf20Sopenharmony_ci rx_status->chain_signal[1] = energy_b; 3558c2ecf20Sopenharmony_ci rx_status->chain_signal[2] = S8_MIN; 3568c2ecf20Sopenharmony_ci} 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_cistatic int iwl_mvm_rx_crypto(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr, 3598c2ecf20Sopenharmony_ci struct ieee80211_rx_status *stats, u16 phy_info, 3608c2ecf20Sopenharmony_ci struct iwl_rx_mpdu_desc *desc, 3618c2ecf20Sopenharmony_ci u32 pkt_flags, int queue, u8 *crypt_len) 3628c2ecf20Sopenharmony_ci{ 3638c2ecf20Sopenharmony_ci u32 status = le32_to_cpu(desc->status); 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci /* 3668c2ecf20Sopenharmony_ci * Drop UNKNOWN frames in aggregation, unless in monitor mode 3678c2ecf20Sopenharmony_ci * (where we don't have the keys). 3688c2ecf20Sopenharmony_ci * We limit this to aggregation because in TKIP this is a valid 3698c2ecf20Sopenharmony_ci * scenario, since we may not have the (correct) TTAK (phase 1 3708c2ecf20Sopenharmony_ci * key) in the firmware. 3718c2ecf20Sopenharmony_ci */ 3728c2ecf20Sopenharmony_ci if (phy_info & IWL_RX_MPDU_PHY_AMPDU && 3738c2ecf20Sopenharmony_ci (status & IWL_RX_MPDU_STATUS_SEC_MASK) == 3748c2ecf20Sopenharmony_ci IWL_RX_MPDU_STATUS_SEC_UNKNOWN && !mvm->monitor_on) 3758c2ecf20Sopenharmony_ci return -1; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci if (!ieee80211_has_protected(hdr->frame_control) || 3788c2ecf20Sopenharmony_ci (status & IWL_RX_MPDU_STATUS_SEC_MASK) == 3798c2ecf20Sopenharmony_ci IWL_RX_MPDU_STATUS_SEC_NONE) 3808c2ecf20Sopenharmony_ci return 0; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci /* TODO: handle packets encrypted with unknown alg */ 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci switch (status & IWL_RX_MPDU_STATUS_SEC_MASK) { 3858c2ecf20Sopenharmony_ci case IWL_RX_MPDU_STATUS_SEC_CCM: 3868c2ecf20Sopenharmony_ci case IWL_RX_MPDU_STATUS_SEC_GCM: 3878c2ecf20Sopenharmony_ci BUILD_BUG_ON(IEEE80211_CCMP_PN_LEN != IEEE80211_GCMP_PN_LEN); 3888c2ecf20Sopenharmony_ci /* alg is CCM: check MIC only */ 3898c2ecf20Sopenharmony_ci if (!(status & IWL_RX_MPDU_STATUS_MIC_OK)) 3908c2ecf20Sopenharmony_ci return -1; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci stats->flag |= RX_FLAG_DECRYPTED; 3938c2ecf20Sopenharmony_ci if (pkt_flags & FH_RSCSR_RADA_EN) 3948c2ecf20Sopenharmony_ci stats->flag |= RX_FLAG_MIC_STRIPPED; 3958c2ecf20Sopenharmony_ci *crypt_len = IEEE80211_CCMP_HDR_LEN; 3968c2ecf20Sopenharmony_ci return 0; 3978c2ecf20Sopenharmony_ci case IWL_RX_MPDU_STATUS_SEC_TKIP: 3988c2ecf20Sopenharmony_ci /* Don't drop the frame and decrypt it in SW */ 3998c2ecf20Sopenharmony_ci if (!fw_has_api(&mvm->fw->ucode_capa, 4008c2ecf20Sopenharmony_ci IWL_UCODE_TLV_API_DEPRECATE_TTAK) && 4018c2ecf20Sopenharmony_ci !(status & IWL_RX_MPDU_RES_STATUS_TTAK_OK)) 4028c2ecf20Sopenharmony_ci return 0; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci if (mvm->trans->trans_cfg->gen2 && 4058c2ecf20Sopenharmony_ci !(status & RX_MPDU_RES_STATUS_MIC_OK)) 4068c2ecf20Sopenharmony_ci stats->flag |= RX_FLAG_MMIC_ERROR; 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci *crypt_len = IEEE80211_TKIP_IV_LEN; 4098c2ecf20Sopenharmony_ci /* fall through */ 4108c2ecf20Sopenharmony_ci case IWL_RX_MPDU_STATUS_SEC_WEP: 4118c2ecf20Sopenharmony_ci if (!(status & IWL_RX_MPDU_STATUS_ICV_OK)) 4128c2ecf20Sopenharmony_ci return -1; 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci stats->flag |= RX_FLAG_DECRYPTED; 4158c2ecf20Sopenharmony_ci if ((status & IWL_RX_MPDU_STATUS_SEC_MASK) == 4168c2ecf20Sopenharmony_ci IWL_RX_MPDU_STATUS_SEC_WEP) 4178c2ecf20Sopenharmony_ci *crypt_len = IEEE80211_WEP_IV_LEN; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci if (pkt_flags & FH_RSCSR_RADA_EN) { 4208c2ecf20Sopenharmony_ci stats->flag |= RX_FLAG_ICV_STRIPPED; 4218c2ecf20Sopenharmony_ci if (mvm->trans->trans_cfg->gen2) 4228c2ecf20Sopenharmony_ci stats->flag |= RX_FLAG_MMIC_STRIPPED; 4238c2ecf20Sopenharmony_ci } 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci return 0; 4268c2ecf20Sopenharmony_ci case IWL_RX_MPDU_STATUS_SEC_EXT_ENC: 4278c2ecf20Sopenharmony_ci if (!(status & IWL_RX_MPDU_STATUS_MIC_OK)) 4288c2ecf20Sopenharmony_ci return -1; 4298c2ecf20Sopenharmony_ci stats->flag |= RX_FLAG_DECRYPTED; 4308c2ecf20Sopenharmony_ci return 0; 4318c2ecf20Sopenharmony_ci default: 4328c2ecf20Sopenharmony_ci /* 4338c2ecf20Sopenharmony_ci * Sometimes we can get frames that were not decrypted 4348c2ecf20Sopenharmony_ci * because the firmware didn't have the keys yet. This can 4358c2ecf20Sopenharmony_ci * happen after connection where we can get multicast frames 4368c2ecf20Sopenharmony_ci * before the GTK is installed. 4378c2ecf20Sopenharmony_ci * Silently drop those frames. 4388c2ecf20Sopenharmony_ci * Also drop un-decrypted frames in monitor mode. 4398c2ecf20Sopenharmony_ci */ 4408c2ecf20Sopenharmony_ci if (!is_multicast_ether_addr(hdr->addr1) && 4418c2ecf20Sopenharmony_ci !mvm->monitor_on && net_ratelimit()) 4428c2ecf20Sopenharmony_ci IWL_ERR(mvm, "Unhandled alg: 0x%x\n", status); 4438c2ecf20Sopenharmony_ci } 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci return 0; 4468c2ecf20Sopenharmony_ci} 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_cistatic void iwl_mvm_rx_csum(struct iwl_mvm *mvm, 4498c2ecf20Sopenharmony_ci struct ieee80211_sta *sta, 4508c2ecf20Sopenharmony_ci struct sk_buff *skb, 4518c2ecf20Sopenharmony_ci struct iwl_rx_packet *pkt) 4528c2ecf20Sopenharmony_ci{ 4538c2ecf20Sopenharmony_ci struct iwl_rx_mpdu_desc *desc = (void *)pkt->data; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci if (mvm->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) { 4568c2ecf20Sopenharmony_ci if (pkt->len_n_flags & cpu_to_le32(FH_RSCSR_RPA_EN)) { 4578c2ecf20Sopenharmony_ci u16 hwsum = be16_to_cpu(desc->v3.raw_xsum); 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci skb->ip_summed = CHECKSUM_COMPLETE; 4608c2ecf20Sopenharmony_ci skb->csum = csum_unfold(~(__force __sum16)hwsum); 4618c2ecf20Sopenharmony_ci } 4628c2ecf20Sopenharmony_ci } else { 4638c2ecf20Sopenharmony_ci struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); 4648c2ecf20Sopenharmony_ci struct iwl_mvm_vif *mvmvif; 4658c2ecf20Sopenharmony_ci u16 flags = le16_to_cpu(desc->l3l4_flags); 4668c2ecf20Sopenharmony_ci u8 l3_prot = (u8)((flags & IWL_RX_L3L4_L3_PROTO_MASK) >> 4678c2ecf20Sopenharmony_ci IWL_RX_L3_PROTO_POS); 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci mvmvif = iwl_mvm_vif_from_mac80211(mvmsta->vif); 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci if (mvmvif->features & NETIF_F_RXCSUM && 4728c2ecf20Sopenharmony_ci flags & IWL_RX_L3L4_TCP_UDP_CSUM_OK && 4738c2ecf20Sopenharmony_ci (flags & IWL_RX_L3L4_IP_HDR_CSUM_OK || 4748c2ecf20Sopenharmony_ci l3_prot == IWL_RX_L3_TYPE_IPV6 || 4758c2ecf20Sopenharmony_ci l3_prot == IWL_RX_L3_TYPE_IPV6_FRAG)) 4768c2ecf20Sopenharmony_ci skb->ip_summed = CHECKSUM_UNNECESSARY; 4778c2ecf20Sopenharmony_ci } 4788c2ecf20Sopenharmony_ci} 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci/* 4818c2ecf20Sopenharmony_ci * returns true if a packet is a duplicate and should be dropped. 4828c2ecf20Sopenharmony_ci * Updates AMSDU PN tracking info 4838c2ecf20Sopenharmony_ci */ 4848c2ecf20Sopenharmony_cistatic bool iwl_mvm_is_dup(struct ieee80211_sta *sta, int queue, 4858c2ecf20Sopenharmony_ci struct ieee80211_rx_status *rx_status, 4868c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr, 4878c2ecf20Sopenharmony_ci struct iwl_rx_mpdu_desc *desc) 4888c2ecf20Sopenharmony_ci{ 4898c2ecf20Sopenharmony_ci struct iwl_mvm_sta *mvm_sta; 4908c2ecf20Sopenharmony_ci struct iwl_mvm_rxq_dup_data *dup_data; 4918c2ecf20Sopenharmony_ci u8 tid, sub_frame_idx; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci if (WARN_ON(IS_ERR_OR_NULL(sta))) 4948c2ecf20Sopenharmony_ci return false; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci mvm_sta = iwl_mvm_sta_from_mac80211(sta); 4978c2ecf20Sopenharmony_ci dup_data = &mvm_sta->dup_data[queue]; 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci /* 5008c2ecf20Sopenharmony_ci * Drop duplicate 802.11 retransmissions 5018c2ecf20Sopenharmony_ci * (IEEE 802.11-2012: 9.3.2.10 "Duplicate detection and recovery") 5028c2ecf20Sopenharmony_ci */ 5038c2ecf20Sopenharmony_ci if (ieee80211_is_ctl(hdr->frame_control) || 5048c2ecf20Sopenharmony_ci ieee80211_is_qos_nullfunc(hdr->frame_control) || 5058c2ecf20Sopenharmony_ci is_multicast_ether_addr(hdr->addr1)) { 5068c2ecf20Sopenharmony_ci rx_status->flag |= RX_FLAG_DUP_VALIDATED; 5078c2ecf20Sopenharmony_ci return false; 5088c2ecf20Sopenharmony_ci } 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci if (ieee80211_is_data_qos(hdr->frame_control)) 5118c2ecf20Sopenharmony_ci /* frame has qos control */ 5128c2ecf20Sopenharmony_ci tid = ieee80211_get_tid(hdr); 5138c2ecf20Sopenharmony_ci else 5148c2ecf20Sopenharmony_ci tid = IWL_MAX_TID_COUNT; 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci /* If this wasn't a part of an A-MSDU the sub-frame index will be 0 */ 5178c2ecf20Sopenharmony_ci sub_frame_idx = desc->amsdu_info & 5188c2ecf20Sopenharmony_ci IWL_RX_MPDU_AMSDU_SUBFRAME_IDX_MASK; 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci if (unlikely(ieee80211_has_retry(hdr->frame_control) && 5218c2ecf20Sopenharmony_ci dup_data->last_seq[tid] == hdr->seq_ctrl && 5228c2ecf20Sopenharmony_ci dup_data->last_sub_frame[tid] >= sub_frame_idx)) 5238c2ecf20Sopenharmony_ci return true; 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci /* Allow same PN as the first subframe for following sub frames */ 5268c2ecf20Sopenharmony_ci if (dup_data->last_seq[tid] == hdr->seq_ctrl && 5278c2ecf20Sopenharmony_ci sub_frame_idx > dup_data->last_sub_frame[tid] && 5288c2ecf20Sopenharmony_ci desc->mac_flags2 & IWL_RX_MPDU_MFLG2_AMSDU) 5298c2ecf20Sopenharmony_ci rx_status->flag |= RX_FLAG_ALLOW_SAME_PN; 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci dup_data->last_seq[tid] = hdr->seq_ctrl; 5328c2ecf20Sopenharmony_ci dup_data->last_sub_frame[tid] = sub_frame_idx; 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci rx_status->flag |= RX_FLAG_DUP_VALIDATED; 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci return false; 5378c2ecf20Sopenharmony_ci} 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ciint iwl_mvm_notify_rx_queue(struct iwl_mvm *mvm, u32 rxq_mask, 5408c2ecf20Sopenharmony_ci const u8 *data, u32 count, bool async) 5418c2ecf20Sopenharmony_ci{ 5428c2ecf20Sopenharmony_ci u8 buf[sizeof(struct iwl_rxq_sync_cmd) + 5438c2ecf20Sopenharmony_ci sizeof(struct iwl_mvm_rss_sync_notif)]; 5448c2ecf20Sopenharmony_ci struct iwl_rxq_sync_cmd *cmd = (void *)buf; 5458c2ecf20Sopenharmony_ci u32 data_size = sizeof(*cmd) + count; 5468c2ecf20Sopenharmony_ci int ret; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci /* 5498c2ecf20Sopenharmony_ci * size must be a multiple of DWORD 5508c2ecf20Sopenharmony_ci * Ensure we don't overflow buf 5518c2ecf20Sopenharmony_ci */ 5528c2ecf20Sopenharmony_ci if (WARN_ON(count & 3 || 5538c2ecf20Sopenharmony_ci count > sizeof(struct iwl_mvm_rss_sync_notif))) 5548c2ecf20Sopenharmony_ci return -EINVAL; 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci cmd->rxq_mask = cpu_to_le32(rxq_mask); 5578c2ecf20Sopenharmony_ci cmd->count = cpu_to_le32(count); 5588c2ecf20Sopenharmony_ci cmd->flags = 0; 5598c2ecf20Sopenharmony_ci memcpy(cmd->payload, data, count); 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci ret = iwl_mvm_send_cmd_pdu(mvm, 5628c2ecf20Sopenharmony_ci WIDE_ID(DATA_PATH_GROUP, 5638c2ecf20Sopenharmony_ci TRIGGER_RX_QUEUES_NOTIF_CMD), 5648c2ecf20Sopenharmony_ci async ? CMD_ASYNC : 0, data_size, cmd); 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci return ret; 5678c2ecf20Sopenharmony_ci} 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci/* 5708c2ecf20Sopenharmony_ci * Returns true if sn2 - buffer_size < sn1 < sn2. 5718c2ecf20Sopenharmony_ci * To be used only in order to compare reorder buffer head with NSSN. 5728c2ecf20Sopenharmony_ci * We fully trust NSSN unless it is behind us due to reorder timeout. 5738c2ecf20Sopenharmony_ci * Reorder timeout can only bring us up to buffer_size SNs ahead of NSSN. 5748c2ecf20Sopenharmony_ci */ 5758c2ecf20Sopenharmony_cistatic bool iwl_mvm_is_sn_less(u16 sn1, u16 sn2, u16 buffer_size) 5768c2ecf20Sopenharmony_ci{ 5778c2ecf20Sopenharmony_ci return ieee80211_sn_less(sn1, sn2) && 5788c2ecf20Sopenharmony_ci !ieee80211_sn_less(sn1, sn2 - buffer_size); 5798c2ecf20Sopenharmony_ci} 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_cistatic void iwl_mvm_sync_nssn(struct iwl_mvm *mvm, u8 baid, u16 nssn) 5828c2ecf20Sopenharmony_ci{ 5838c2ecf20Sopenharmony_ci if (IWL_MVM_USE_NSSN_SYNC) { 5848c2ecf20Sopenharmony_ci struct iwl_mvm_rss_sync_notif notif = { 5858c2ecf20Sopenharmony_ci .metadata.type = IWL_MVM_RXQ_NSSN_SYNC, 5868c2ecf20Sopenharmony_ci .metadata.sync = 0, 5878c2ecf20Sopenharmony_ci .nssn_sync.baid = baid, 5888c2ecf20Sopenharmony_ci .nssn_sync.nssn = nssn, 5898c2ecf20Sopenharmony_ci }; 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci iwl_mvm_sync_rx_queues_internal(mvm, (void *)¬if, 5928c2ecf20Sopenharmony_ci sizeof(notif)); 5938c2ecf20Sopenharmony_ci } 5948c2ecf20Sopenharmony_ci} 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci#define RX_REORDER_BUF_TIMEOUT_MQ (HZ / 10) 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_cienum iwl_mvm_release_flags { 5998c2ecf20Sopenharmony_ci IWL_MVM_RELEASE_SEND_RSS_SYNC = BIT(0), 6008c2ecf20Sopenharmony_ci IWL_MVM_RELEASE_FROM_RSS_SYNC = BIT(1), 6018c2ecf20Sopenharmony_ci}; 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_cistatic void iwl_mvm_release_frames(struct iwl_mvm *mvm, 6048c2ecf20Sopenharmony_ci struct ieee80211_sta *sta, 6058c2ecf20Sopenharmony_ci struct napi_struct *napi, 6068c2ecf20Sopenharmony_ci struct iwl_mvm_baid_data *baid_data, 6078c2ecf20Sopenharmony_ci struct iwl_mvm_reorder_buffer *reorder_buf, 6088c2ecf20Sopenharmony_ci u16 nssn, u32 flags) 6098c2ecf20Sopenharmony_ci{ 6108c2ecf20Sopenharmony_ci struct iwl_mvm_reorder_buf_entry *entries = 6118c2ecf20Sopenharmony_ci &baid_data->entries[reorder_buf->queue * 6128c2ecf20Sopenharmony_ci baid_data->entries_per_queue]; 6138c2ecf20Sopenharmony_ci u16 ssn = reorder_buf->head_sn; 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci lockdep_assert_held(&reorder_buf->lock); 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci /* 6188c2ecf20Sopenharmony_ci * We keep the NSSN not too far behind, if we are sync'ing it and it 6198c2ecf20Sopenharmony_ci * is more than 2048 ahead of us, it must be behind us. Discard it. 6208c2ecf20Sopenharmony_ci * This can happen if the queue that hit the 0 / 2048 seqno was lagging 6218c2ecf20Sopenharmony_ci * behind and this queue already processed packets. The next if 6228c2ecf20Sopenharmony_ci * would have caught cases where this queue would have processed less 6238c2ecf20Sopenharmony_ci * than 64 packets, but it may have processed more than 64 packets. 6248c2ecf20Sopenharmony_ci */ 6258c2ecf20Sopenharmony_ci if ((flags & IWL_MVM_RELEASE_FROM_RSS_SYNC) && 6268c2ecf20Sopenharmony_ci ieee80211_sn_less(nssn, ssn)) 6278c2ecf20Sopenharmony_ci goto set_timer; 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci /* ignore nssn smaller than head sn - this can happen due to timeout */ 6308c2ecf20Sopenharmony_ci if (iwl_mvm_is_sn_less(nssn, ssn, reorder_buf->buf_size)) 6318c2ecf20Sopenharmony_ci goto set_timer; 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci while (iwl_mvm_is_sn_less(ssn, nssn, reorder_buf->buf_size)) { 6348c2ecf20Sopenharmony_ci int index = ssn % reorder_buf->buf_size; 6358c2ecf20Sopenharmony_ci struct sk_buff_head *skb_list = &entries[index].e.frames; 6368c2ecf20Sopenharmony_ci struct sk_buff *skb; 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci ssn = ieee80211_sn_inc(ssn); 6398c2ecf20Sopenharmony_ci if ((flags & IWL_MVM_RELEASE_SEND_RSS_SYNC) && 6408c2ecf20Sopenharmony_ci (ssn == 2048 || ssn == 0)) 6418c2ecf20Sopenharmony_ci iwl_mvm_sync_nssn(mvm, baid_data->baid, ssn); 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci /* 6448c2ecf20Sopenharmony_ci * Empty the list. Will have more than one frame for A-MSDU. 6458c2ecf20Sopenharmony_ci * Empty list is valid as well since nssn indicates frames were 6468c2ecf20Sopenharmony_ci * received. 6478c2ecf20Sopenharmony_ci */ 6488c2ecf20Sopenharmony_ci while ((skb = __skb_dequeue(skb_list))) { 6498c2ecf20Sopenharmony_ci iwl_mvm_pass_packet_to_mac80211(mvm, napi, skb, 6508c2ecf20Sopenharmony_ci reorder_buf->queue, 6518c2ecf20Sopenharmony_ci sta, false); 6528c2ecf20Sopenharmony_ci reorder_buf->num_stored--; 6538c2ecf20Sopenharmony_ci } 6548c2ecf20Sopenharmony_ci } 6558c2ecf20Sopenharmony_ci reorder_buf->head_sn = nssn; 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ciset_timer: 6588c2ecf20Sopenharmony_ci if (reorder_buf->num_stored && !reorder_buf->removed) { 6598c2ecf20Sopenharmony_ci u16 index = reorder_buf->head_sn % reorder_buf->buf_size; 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci while (skb_queue_empty(&entries[index].e.frames)) 6628c2ecf20Sopenharmony_ci index = (index + 1) % reorder_buf->buf_size; 6638c2ecf20Sopenharmony_ci /* modify timer to match next frame's expiration time */ 6648c2ecf20Sopenharmony_ci mod_timer(&reorder_buf->reorder_timer, 6658c2ecf20Sopenharmony_ci entries[index].e.reorder_time + 1 + 6668c2ecf20Sopenharmony_ci RX_REORDER_BUF_TIMEOUT_MQ); 6678c2ecf20Sopenharmony_ci } else { 6688c2ecf20Sopenharmony_ci del_timer(&reorder_buf->reorder_timer); 6698c2ecf20Sopenharmony_ci } 6708c2ecf20Sopenharmony_ci} 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_civoid iwl_mvm_reorder_timer_expired(struct timer_list *t) 6738c2ecf20Sopenharmony_ci{ 6748c2ecf20Sopenharmony_ci struct iwl_mvm_reorder_buffer *buf = from_timer(buf, t, reorder_timer); 6758c2ecf20Sopenharmony_ci struct iwl_mvm_baid_data *baid_data = 6768c2ecf20Sopenharmony_ci iwl_mvm_baid_data_from_reorder_buf(buf); 6778c2ecf20Sopenharmony_ci struct iwl_mvm_reorder_buf_entry *entries = 6788c2ecf20Sopenharmony_ci &baid_data->entries[buf->queue * baid_data->entries_per_queue]; 6798c2ecf20Sopenharmony_ci int i; 6808c2ecf20Sopenharmony_ci u16 sn = 0, index = 0; 6818c2ecf20Sopenharmony_ci bool expired = false; 6828c2ecf20Sopenharmony_ci bool cont = false; 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci spin_lock(&buf->lock); 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci if (!buf->num_stored || buf->removed) { 6878c2ecf20Sopenharmony_ci spin_unlock(&buf->lock); 6888c2ecf20Sopenharmony_ci return; 6898c2ecf20Sopenharmony_ci } 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci for (i = 0; i < buf->buf_size ; i++) { 6928c2ecf20Sopenharmony_ci index = (buf->head_sn + i) % buf->buf_size; 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci if (skb_queue_empty(&entries[index].e.frames)) { 6958c2ecf20Sopenharmony_ci /* 6968c2ecf20Sopenharmony_ci * If there is a hole and the next frame didn't expire 6978c2ecf20Sopenharmony_ci * we want to break and not advance SN 6988c2ecf20Sopenharmony_ci */ 6998c2ecf20Sopenharmony_ci cont = false; 7008c2ecf20Sopenharmony_ci continue; 7018c2ecf20Sopenharmony_ci } 7028c2ecf20Sopenharmony_ci if (!cont && 7038c2ecf20Sopenharmony_ci !time_after(jiffies, entries[index].e.reorder_time + 7048c2ecf20Sopenharmony_ci RX_REORDER_BUF_TIMEOUT_MQ)) 7058c2ecf20Sopenharmony_ci break; 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci expired = true; 7088c2ecf20Sopenharmony_ci /* continue until next hole after this expired frames */ 7098c2ecf20Sopenharmony_ci cont = true; 7108c2ecf20Sopenharmony_ci sn = ieee80211_sn_add(buf->head_sn, i + 1); 7118c2ecf20Sopenharmony_ci } 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci if (expired) { 7148c2ecf20Sopenharmony_ci struct ieee80211_sta *sta; 7158c2ecf20Sopenharmony_ci struct iwl_mvm_sta *mvmsta; 7168c2ecf20Sopenharmony_ci u8 sta_id = baid_data->sta_id; 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci rcu_read_lock(); 7198c2ecf20Sopenharmony_ci sta = rcu_dereference(buf->mvm->fw_id_to_mac_id[sta_id]); 7208c2ecf20Sopenharmony_ci mvmsta = iwl_mvm_sta_from_mac80211(sta); 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci /* SN is set to the last expired frame + 1 */ 7238c2ecf20Sopenharmony_ci IWL_DEBUG_HT(buf->mvm, 7248c2ecf20Sopenharmony_ci "Releasing expired frames for sta %u, sn %d\n", 7258c2ecf20Sopenharmony_ci sta_id, sn); 7268c2ecf20Sopenharmony_ci iwl_mvm_event_frame_timeout_callback(buf->mvm, mvmsta->vif, 7278c2ecf20Sopenharmony_ci sta, baid_data->tid); 7288c2ecf20Sopenharmony_ci iwl_mvm_release_frames(buf->mvm, sta, NULL, baid_data, 7298c2ecf20Sopenharmony_ci buf, sn, IWL_MVM_RELEASE_SEND_RSS_SYNC); 7308c2ecf20Sopenharmony_ci rcu_read_unlock(); 7318c2ecf20Sopenharmony_ci } else { 7328c2ecf20Sopenharmony_ci /* 7338c2ecf20Sopenharmony_ci * If no frame expired and there are stored frames, index is now 7348c2ecf20Sopenharmony_ci * pointing to the first unexpired frame - modify timer 7358c2ecf20Sopenharmony_ci * accordingly to this frame. 7368c2ecf20Sopenharmony_ci */ 7378c2ecf20Sopenharmony_ci mod_timer(&buf->reorder_timer, 7388c2ecf20Sopenharmony_ci entries[index].e.reorder_time + 7398c2ecf20Sopenharmony_ci 1 + RX_REORDER_BUF_TIMEOUT_MQ); 7408c2ecf20Sopenharmony_ci } 7418c2ecf20Sopenharmony_ci spin_unlock(&buf->lock); 7428c2ecf20Sopenharmony_ci} 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_cistatic void iwl_mvm_del_ba(struct iwl_mvm *mvm, int queue, 7458c2ecf20Sopenharmony_ci struct iwl_mvm_delba_data *data) 7468c2ecf20Sopenharmony_ci{ 7478c2ecf20Sopenharmony_ci struct iwl_mvm_baid_data *ba_data; 7488c2ecf20Sopenharmony_ci struct ieee80211_sta *sta; 7498c2ecf20Sopenharmony_ci struct iwl_mvm_reorder_buffer *reorder_buf; 7508c2ecf20Sopenharmony_ci u8 baid = data->baid; 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci if (WARN_ONCE(baid >= IWL_MAX_BAID, "invalid BAID: %x\n", baid)) 7538c2ecf20Sopenharmony_ci return; 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci rcu_read_lock(); 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci ba_data = rcu_dereference(mvm->baid_map[baid]); 7588c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(!ba_data)) 7598c2ecf20Sopenharmony_ci goto out; 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci sta = rcu_dereference(mvm->fw_id_to_mac_id[ba_data->sta_id]); 7628c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(IS_ERR_OR_NULL(sta))) 7638c2ecf20Sopenharmony_ci goto out; 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci reorder_buf = &ba_data->reorder_buf[queue]; 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci /* release all frames that are in the reorder buffer to the stack */ 7688c2ecf20Sopenharmony_ci spin_lock_bh(&reorder_buf->lock); 7698c2ecf20Sopenharmony_ci iwl_mvm_release_frames(mvm, sta, NULL, ba_data, reorder_buf, 7708c2ecf20Sopenharmony_ci ieee80211_sn_add(reorder_buf->head_sn, 7718c2ecf20Sopenharmony_ci reorder_buf->buf_size), 7728c2ecf20Sopenharmony_ci 0); 7738c2ecf20Sopenharmony_ci spin_unlock_bh(&reorder_buf->lock); 7748c2ecf20Sopenharmony_ci del_timer_sync(&reorder_buf->reorder_timer); 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ciout: 7778c2ecf20Sopenharmony_ci rcu_read_unlock(); 7788c2ecf20Sopenharmony_ci} 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_cistatic void iwl_mvm_release_frames_from_notif(struct iwl_mvm *mvm, 7818c2ecf20Sopenharmony_ci struct napi_struct *napi, 7828c2ecf20Sopenharmony_ci u8 baid, u16 nssn, int queue, 7838c2ecf20Sopenharmony_ci u32 flags) 7848c2ecf20Sopenharmony_ci{ 7858c2ecf20Sopenharmony_ci struct ieee80211_sta *sta; 7868c2ecf20Sopenharmony_ci struct iwl_mvm_reorder_buffer *reorder_buf; 7878c2ecf20Sopenharmony_ci struct iwl_mvm_baid_data *ba_data; 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci IWL_DEBUG_HT(mvm, "Frame release notification for BAID %u, NSSN %d\n", 7908c2ecf20Sopenharmony_ci baid, nssn); 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(baid == IWL_RX_REORDER_DATA_INVALID_BAID || 7938c2ecf20Sopenharmony_ci baid >= ARRAY_SIZE(mvm->baid_map))) 7948c2ecf20Sopenharmony_ci return; 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci rcu_read_lock(); 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci ba_data = rcu_dereference(mvm->baid_map[baid]); 7998c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(!ba_data)) 8008c2ecf20Sopenharmony_ci goto out; 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci sta = rcu_dereference(mvm->fw_id_to_mac_id[ba_data->sta_id]); 8038c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(IS_ERR_OR_NULL(sta))) 8048c2ecf20Sopenharmony_ci goto out; 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci reorder_buf = &ba_data->reorder_buf[queue]; 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci spin_lock_bh(&reorder_buf->lock); 8098c2ecf20Sopenharmony_ci iwl_mvm_release_frames(mvm, sta, napi, ba_data, 8108c2ecf20Sopenharmony_ci reorder_buf, nssn, flags); 8118c2ecf20Sopenharmony_ci spin_unlock_bh(&reorder_buf->lock); 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_ciout: 8148c2ecf20Sopenharmony_ci rcu_read_unlock(); 8158c2ecf20Sopenharmony_ci} 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_cistatic void iwl_mvm_nssn_sync(struct iwl_mvm *mvm, 8188c2ecf20Sopenharmony_ci struct napi_struct *napi, int queue, 8198c2ecf20Sopenharmony_ci const struct iwl_mvm_nssn_sync_data *data) 8208c2ecf20Sopenharmony_ci{ 8218c2ecf20Sopenharmony_ci iwl_mvm_release_frames_from_notif(mvm, napi, data->baid, 8228c2ecf20Sopenharmony_ci data->nssn, queue, 8238c2ecf20Sopenharmony_ci IWL_MVM_RELEASE_FROM_RSS_SYNC); 8248c2ecf20Sopenharmony_ci} 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_civoid iwl_mvm_rx_queue_notif(struct iwl_mvm *mvm, struct napi_struct *napi, 8278c2ecf20Sopenharmony_ci struct iwl_rx_cmd_buffer *rxb, int queue) 8288c2ecf20Sopenharmony_ci{ 8298c2ecf20Sopenharmony_ci struct iwl_rx_packet *pkt = rxb_addr(rxb); 8308c2ecf20Sopenharmony_ci struct iwl_rxq_sync_notification *notif; 8318c2ecf20Sopenharmony_ci struct iwl_mvm_internal_rxq_notif *internal_notif; 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci notif = (void *)pkt->data; 8348c2ecf20Sopenharmony_ci internal_notif = (void *)notif->payload; 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci if (internal_notif->sync && 8378c2ecf20Sopenharmony_ci mvm->queue_sync_cookie != internal_notif->cookie) { 8388c2ecf20Sopenharmony_ci WARN_ONCE(1, "Received expired RX queue sync message\n"); 8398c2ecf20Sopenharmony_ci return; 8408c2ecf20Sopenharmony_ci } 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci switch (internal_notif->type) { 8438c2ecf20Sopenharmony_ci case IWL_MVM_RXQ_EMPTY: 8448c2ecf20Sopenharmony_ci break; 8458c2ecf20Sopenharmony_ci case IWL_MVM_RXQ_NOTIF_DEL_BA: 8468c2ecf20Sopenharmony_ci iwl_mvm_del_ba(mvm, queue, (void *)internal_notif->data); 8478c2ecf20Sopenharmony_ci break; 8488c2ecf20Sopenharmony_ci case IWL_MVM_RXQ_NSSN_SYNC: 8498c2ecf20Sopenharmony_ci iwl_mvm_nssn_sync(mvm, napi, queue, 8508c2ecf20Sopenharmony_ci (void *)internal_notif->data); 8518c2ecf20Sopenharmony_ci break; 8528c2ecf20Sopenharmony_ci default: 8538c2ecf20Sopenharmony_ci WARN_ONCE(1, "Invalid identifier %d", internal_notif->type); 8548c2ecf20Sopenharmony_ci } 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci if (internal_notif->sync && 8578c2ecf20Sopenharmony_ci !atomic_dec_return(&mvm->queue_sync_counter)) 8588c2ecf20Sopenharmony_ci wake_up(&mvm->rx_sync_waitq); 8598c2ecf20Sopenharmony_ci} 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_cistatic void iwl_mvm_oldsn_workaround(struct iwl_mvm *mvm, 8628c2ecf20Sopenharmony_ci struct ieee80211_sta *sta, int tid, 8638c2ecf20Sopenharmony_ci struct iwl_mvm_reorder_buffer *buffer, 8648c2ecf20Sopenharmony_ci u32 reorder, u32 gp2, int queue) 8658c2ecf20Sopenharmony_ci{ 8668c2ecf20Sopenharmony_ci struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci if (gp2 != buffer->consec_oldsn_ampdu_gp2) { 8698c2ecf20Sopenharmony_ci /* we have a new (A-)MPDU ... */ 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci /* 8728c2ecf20Sopenharmony_ci * reset counter to 0 if we didn't have any oldsn in 8738c2ecf20Sopenharmony_ci * the last A-MPDU (as detected by GP2 being identical) 8748c2ecf20Sopenharmony_ci */ 8758c2ecf20Sopenharmony_ci if (!buffer->consec_oldsn_prev_drop) 8768c2ecf20Sopenharmony_ci buffer->consec_oldsn_drops = 0; 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci /* either way, update our tracking state */ 8798c2ecf20Sopenharmony_ci buffer->consec_oldsn_ampdu_gp2 = gp2; 8808c2ecf20Sopenharmony_ci } else if (buffer->consec_oldsn_prev_drop) { 8818c2ecf20Sopenharmony_ci /* 8828c2ecf20Sopenharmony_ci * tracking state didn't change, and we had an old SN 8838c2ecf20Sopenharmony_ci * indication before - do nothing in this case, we 8848c2ecf20Sopenharmony_ci * already noted this one down and are waiting for the 8858c2ecf20Sopenharmony_ci * next A-MPDU (by GP2) 8868c2ecf20Sopenharmony_ci */ 8878c2ecf20Sopenharmony_ci return; 8888c2ecf20Sopenharmony_ci } 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci /* return unless this MPDU has old SN */ 8918c2ecf20Sopenharmony_ci if (!(reorder & IWL_RX_MPDU_REORDER_BA_OLD_SN)) 8928c2ecf20Sopenharmony_ci return; 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci /* update state */ 8958c2ecf20Sopenharmony_ci buffer->consec_oldsn_prev_drop = 1; 8968c2ecf20Sopenharmony_ci buffer->consec_oldsn_drops++; 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci /* if limit is reached, send del BA and reset state */ 8998c2ecf20Sopenharmony_ci if (buffer->consec_oldsn_drops == IWL_MVM_AMPDU_CONSEC_DROPS_DELBA) { 9008c2ecf20Sopenharmony_ci IWL_WARN(mvm, 9018c2ecf20Sopenharmony_ci "reached %d old SN frames from %pM on queue %d, stopping BA session on TID %d\n", 9028c2ecf20Sopenharmony_ci IWL_MVM_AMPDU_CONSEC_DROPS_DELBA, 9038c2ecf20Sopenharmony_ci sta->addr, queue, tid); 9048c2ecf20Sopenharmony_ci ieee80211_stop_rx_ba_session(mvmsta->vif, BIT(tid), sta->addr); 9058c2ecf20Sopenharmony_ci buffer->consec_oldsn_prev_drop = 0; 9068c2ecf20Sopenharmony_ci buffer->consec_oldsn_drops = 0; 9078c2ecf20Sopenharmony_ci } 9088c2ecf20Sopenharmony_ci} 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci/* 9118c2ecf20Sopenharmony_ci * Returns true if the MPDU was buffered\dropped, false if it should be passed 9128c2ecf20Sopenharmony_ci * to upper layer. 9138c2ecf20Sopenharmony_ci */ 9148c2ecf20Sopenharmony_cistatic bool iwl_mvm_reorder(struct iwl_mvm *mvm, 9158c2ecf20Sopenharmony_ci struct napi_struct *napi, 9168c2ecf20Sopenharmony_ci int queue, 9178c2ecf20Sopenharmony_ci struct ieee80211_sta *sta, 9188c2ecf20Sopenharmony_ci struct sk_buff *skb, 9198c2ecf20Sopenharmony_ci struct iwl_rx_mpdu_desc *desc) 9208c2ecf20Sopenharmony_ci{ 9218c2ecf20Sopenharmony_ci struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); 9228c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr = iwl_mvm_skb_get_hdr(skb); 9238c2ecf20Sopenharmony_ci struct iwl_mvm_sta *mvm_sta; 9248c2ecf20Sopenharmony_ci struct iwl_mvm_baid_data *baid_data; 9258c2ecf20Sopenharmony_ci struct iwl_mvm_reorder_buffer *buffer; 9268c2ecf20Sopenharmony_ci struct sk_buff *tail; 9278c2ecf20Sopenharmony_ci u32 reorder = le32_to_cpu(desc->reorder_data); 9288c2ecf20Sopenharmony_ci bool amsdu = desc->mac_flags2 & IWL_RX_MPDU_MFLG2_AMSDU; 9298c2ecf20Sopenharmony_ci bool last_subframe = 9308c2ecf20Sopenharmony_ci desc->amsdu_info & IWL_RX_MPDU_AMSDU_LAST_SUBFRAME; 9318c2ecf20Sopenharmony_ci u8 tid = ieee80211_get_tid(hdr); 9328c2ecf20Sopenharmony_ci u8 sub_frame_idx = desc->amsdu_info & 9338c2ecf20Sopenharmony_ci IWL_RX_MPDU_AMSDU_SUBFRAME_IDX_MASK; 9348c2ecf20Sopenharmony_ci struct iwl_mvm_reorder_buf_entry *entries; 9358c2ecf20Sopenharmony_ci int index; 9368c2ecf20Sopenharmony_ci u16 nssn, sn; 9378c2ecf20Sopenharmony_ci u8 baid; 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci baid = (reorder & IWL_RX_MPDU_REORDER_BAID_MASK) >> 9408c2ecf20Sopenharmony_ci IWL_RX_MPDU_REORDER_BAID_SHIFT; 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci /* 9438c2ecf20Sopenharmony_ci * This also covers the case of receiving a Block Ack Request 9448c2ecf20Sopenharmony_ci * outside a BA session; we'll pass it to mac80211 and that 9458c2ecf20Sopenharmony_ci * then sends a delBA action frame. 9468c2ecf20Sopenharmony_ci * This also covers pure monitor mode, in which case we won't 9478c2ecf20Sopenharmony_ci * have any BA sessions. 9488c2ecf20Sopenharmony_ci */ 9498c2ecf20Sopenharmony_ci if (baid == IWL_RX_REORDER_DATA_INVALID_BAID) 9508c2ecf20Sopenharmony_ci return false; 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci /* no sta yet */ 9538c2ecf20Sopenharmony_ci if (WARN_ONCE(IS_ERR_OR_NULL(sta), 9548c2ecf20Sopenharmony_ci "Got valid BAID without a valid station assigned\n")) 9558c2ecf20Sopenharmony_ci return false; 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci mvm_sta = iwl_mvm_sta_from_mac80211(sta); 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ci /* not a data packet or a bar */ 9608c2ecf20Sopenharmony_ci if (!ieee80211_is_back_req(hdr->frame_control) && 9618c2ecf20Sopenharmony_ci (!ieee80211_is_data_qos(hdr->frame_control) || 9628c2ecf20Sopenharmony_ci is_multicast_ether_addr(hdr->addr1))) 9638c2ecf20Sopenharmony_ci return false; 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci if (unlikely(!ieee80211_is_data_present(hdr->frame_control))) 9668c2ecf20Sopenharmony_ci return false; 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci baid_data = rcu_dereference(mvm->baid_map[baid]); 9698c2ecf20Sopenharmony_ci if (!baid_data) { 9708c2ecf20Sopenharmony_ci IWL_DEBUG_RX(mvm, 9718c2ecf20Sopenharmony_ci "Got valid BAID but no baid allocated, bypass the re-ordering buffer. Baid %d reorder 0x%x\n", 9728c2ecf20Sopenharmony_ci baid, reorder); 9738c2ecf20Sopenharmony_ci return false; 9748c2ecf20Sopenharmony_ci } 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci if (WARN(tid != baid_data->tid || mvm_sta->sta_id != baid_data->sta_id, 9778c2ecf20Sopenharmony_ci "baid 0x%x is mapped to sta:%d tid:%d, but was received for sta:%d tid:%d\n", 9788c2ecf20Sopenharmony_ci baid, baid_data->sta_id, baid_data->tid, mvm_sta->sta_id, 9798c2ecf20Sopenharmony_ci tid)) 9808c2ecf20Sopenharmony_ci return false; 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci nssn = reorder & IWL_RX_MPDU_REORDER_NSSN_MASK; 9838c2ecf20Sopenharmony_ci sn = (reorder & IWL_RX_MPDU_REORDER_SN_MASK) >> 9848c2ecf20Sopenharmony_ci IWL_RX_MPDU_REORDER_SN_SHIFT; 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci buffer = &baid_data->reorder_buf[queue]; 9878c2ecf20Sopenharmony_ci entries = &baid_data->entries[queue * baid_data->entries_per_queue]; 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci spin_lock_bh(&buffer->lock); 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci if (!buffer->valid) { 9928c2ecf20Sopenharmony_ci if (reorder & IWL_RX_MPDU_REORDER_BA_OLD_SN) { 9938c2ecf20Sopenharmony_ci spin_unlock_bh(&buffer->lock); 9948c2ecf20Sopenharmony_ci return false; 9958c2ecf20Sopenharmony_ci } 9968c2ecf20Sopenharmony_ci buffer->valid = true; 9978c2ecf20Sopenharmony_ci } 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci if (ieee80211_is_back_req(hdr->frame_control)) { 10008c2ecf20Sopenharmony_ci iwl_mvm_release_frames(mvm, sta, napi, baid_data, 10018c2ecf20Sopenharmony_ci buffer, nssn, 0); 10028c2ecf20Sopenharmony_ci goto drop; 10038c2ecf20Sopenharmony_ci } 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci /* 10068c2ecf20Sopenharmony_ci * If there was a significant jump in the nssn - adjust. 10078c2ecf20Sopenharmony_ci * If the SN is smaller than the NSSN it might need to first go into 10088c2ecf20Sopenharmony_ci * the reorder buffer, in which case we just release up to it and the 10098c2ecf20Sopenharmony_ci * rest of the function will take care of storing it and releasing up to 10108c2ecf20Sopenharmony_ci * the nssn. 10118c2ecf20Sopenharmony_ci * This should not happen. This queue has been lagging and it should 10128c2ecf20Sopenharmony_ci * have been updated by a IWL_MVM_RXQ_NSSN_SYNC notification. Be nice 10138c2ecf20Sopenharmony_ci * and update the other queues. 10148c2ecf20Sopenharmony_ci */ 10158c2ecf20Sopenharmony_ci if (!iwl_mvm_is_sn_less(nssn, buffer->head_sn + buffer->buf_size, 10168c2ecf20Sopenharmony_ci buffer->buf_size) || 10178c2ecf20Sopenharmony_ci !ieee80211_sn_less(sn, buffer->head_sn + buffer->buf_size)) { 10188c2ecf20Sopenharmony_ci u16 min_sn = ieee80211_sn_less(sn, nssn) ? sn : nssn; 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_ci iwl_mvm_release_frames(mvm, sta, napi, baid_data, buffer, 10218c2ecf20Sopenharmony_ci min_sn, IWL_MVM_RELEASE_SEND_RSS_SYNC); 10228c2ecf20Sopenharmony_ci } 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci iwl_mvm_oldsn_workaround(mvm, sta, tid, buffer, reorder, 10258c2ecf20Sopenharmony_ci rx_status->device_timestamp, queue); 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci /* drop any oudated packets */ 10288c2ecf20Sopenharmony_ci if (ieee80211_sn_less(sn, buffer->head_sn)) 10298c2ecf20Sopenharmony_ci goto drop; 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci /* release immediately if allowed by nssn and no stored frames */ 10328c2ecf20Sopenharmony_ci if (!buffer->num_stored && ieee80211_sn_less(sn, nssn)) { 10338c2ecf20Sopenharmony_ci if (iwl_mvm_is_sn_less(buffer->head_sn, nssn, 10348c2ecf20Sopenharmony_ci buffer->buf_size) && 10358c2ecf20Sopenharmony_ci (!amsdu || last_subframe)) { 10368c2ecf20Sopenharmony_ci /* 10378c2ecf20Sopenharmony_ci * If we crossed the 2048 or 0 SN, notify all the 10388c2ecf20Sopenharmony_ci * queues. This is done in order to avoid having a 10398c2ecf20Sopenharmony_ci * head_sn that lags behind for too long. When that 10408c2ecf20Sopenharmony_ci * happens, we can get to a situation where the head_sn 10418c2ecf20Sopenharmony_ci * is within the interval [nssn - buf_size : nssn] 10428c2ecf20Sopenharmony_ci * which will make us think that the nssn is a packet 10438c2ecf20Sopenharmony_ci * that we already freed because of the reordering 10448c2ecf20Sopenharmony_ci * buffer and we will ignore it. So maintain the 10458c2ecf20Sopenharmony_ci * head_sn somewhat updated across all the queues: 10468c2ecf20Sopenharmony_ci * when it crosses 0 and 2048. 10478c2ecf20Sopenharmony_ci */ 10488c2ecf20Sopenharmony_ci if (sn == 2048 || sn == 0) 10498c2ecf20Sopenharmony_ci iwl_mvm_sync_nssn(mvm, baid, sn); 10508c2ecf20Sopenharmony_ci buffer->head_sn = nssn; 10518c2ecf20Sopenharmony_ci } 10528c2ecf20Sopenharmony_ci /* No need to update AMSDU last SN - we are moving the head */ 10538c2ecf20Sopenharmony_ci spin_unlock_bh(&buffer->lock); 10548c2ecf20Sopenharmony_ci return false; 10558c2ecf20Sopenharmony_ci } 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_ci /* 10588c2ecf20Sopenharmony_ci * release immediately if there are no stored frames, and the sn is 10598c2ecf20Sopenharmony_ci * equal to the head. 10608c2ecf20Sopenharmony_ci * This can happen due to reorder timer, where NSSN is behind head_sn. 10618c2ecf20Sopenharmony_ci * When we released everything, and we got the next frame in the 10628c2ecf20Sopenharmony_ci * sequence, according to the NSSN we can't release immediately, 10638c2ecf20Sopenharmony_ci * while technically there is no hole and we can move forward. 10648c2ecf20Sopenharmony_ci */ 10658c2ecf20Sopenharmony_ci if (!buffer->num_stored && sn == buffer->head_sn) { 10668c2ecf20Sopenharmony_ci if (!amsdu || last_subframe) { 10678c2ecf20Sopenharmony_ci if (sn == 2048 || sn == 0) 10688c2ecf20Sopenharmony_ci iwl_mvm_sync_nssn(mvm, baid, sn); 10698c2ecf20Sopenharmony_ci buffer->head_sn = ieee80211_sn_inc(buffer->head_sn); 10708c2ecf20Sopenharmony_ci } 10718c2ecf20Sopenharmony_ci /* No need to update AMSDU last SN - we are moving the head */ 10728c2ecf20Sopenharmony_ci spin_unlock_bh(&buffer->lock); 10738c2ecf20Sopenharmony_ci return false; 10748c2ecf20Sopenharmony_ci } 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_ci index = sn % buffer->buf_size; 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci /* 10798c2ecf20Sopenharmony_ci * Check if we already stored this frame 10808c2ecf20Sopenharmony_ci * As AMSDU is either received or not as whole, logic is simple: 10818c2ecf20Sopenharmony_ci * If we have frames in that position in the buffer and the last frame 10828c2ecf20Sopenharmony_ci * originated from AMSDU had a different SN then it is a retransmission. 10838c2ecf20Sopenharmony_ci * If it is the same SN then if the subframe index is incrementing it 10848c2ecf20Sopenharmony_ci * is the same AMSDU - otherwise it is a retransmission. 10858c2ecf20Sopenharmony_ci */ 10868c2ecf20Sopenharmony_ci tail = skb_peek_tail(&entries[index].e.frames); 10878c2ecf20Sopenharmony_ci if (tail && !amsdu) 10888c2ecf20Sopenharmony_ci goto drop; 10898c2ecf20Sopenharmony_ci else if (tail && (sn != buffer->last_amsdu || 10908c2ecf20Sopenharmony_ci buffer->last_sub_index >= sub_frame_idx)) 10918c2ecf20Sopenharmony_ci goto drop; 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_ci /* put in reorder buffer */ 10948c2ecf20Sopenharmony_ci __skb_queue_tail(&entries[index].e.frames, skb); 10958c2ecf20Sopenharmony_ci buffer->num_stored++; 10968c2ecf20Sopenharmony_ci entries[index].e.reorder_time = jiffies; 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci if (amsdu) { 10998c2ecf20Sopenharmony_ci buffer->last_amsdu = sn; 11008c2ecf20Sopenharmony_ci buffer->last_sub_index = sub_frame_idx; 11018c2ecf20Sopenharmony_ci } 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_ci /* 11048c2ecf20Sopenharmony_ci * We cannot trust NSSN for AMSDU sub-frames that are not the last. 11058c2ecf20Sopenharmony_ci * The reason is that NSSN advances on the first sub-frame, and may 11068c2ecf20Sopenharmony_ci * cause the reorder buffer to advance before all the sub-frames arrive. 11078c2ecf20Sopenharmony_ci * Example: reorder buffer contains SN 0 & 2, and we receive AMSDU with 11088c2ecf20Sopenharmony_ci * SN 1. NSSN for first sub frame will be 3 with the result of driver 11098c2ecf20Sopenharmony_ci * releasing SN 0,1, 2. When sub-frame 1 arrives - reorder buffer is 11108c2ecf20Sopenharmony_ci * already ahead and it will be dropped. 11118c2ecf20Sopenharmony_ci * If the last sub-frame is not on this queue - we will get frame 11128c2ecf20Sopenharmony_ci * release notification with up to date NSSN. 11138c2ecf20Sopenharmony_ci */ 11148c2ecf20Sopenharmony_ci if (!amsdu || last_subframe) 11158c2ecf20Sopenharmony_ci iwl_mvm_release_frames(mvm, sta, napi, baid_data, 11168c2ecf20Sopenharmony_ci buffer, nssn, 11178c2ecf20Sopenharmony_ci IWL_MVM_RELEASE_SEND_RSS_SYNC); 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci spin_unlock_bh(&buffer->lock); 11208c2ecf20Sopenharmony_ci return true; 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_cidrop: 11238c2ecf20Sopenharmony_ci kfree_skb(skb); 11248c2ecf20Sopenharmony_ci spin_unlock_bh(&buffer->lock); 11258c2ecf20Sopenharmony_ci return true; 11268c2ecf20Sopenharmony_ci} 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_cistatic void iwl_mvm_agg_rx_received(struct iwl_mvm *mvm, 11298c2ecf20Sopenharmony_ci u32 reorder_data, u8 baid) 11308c2ecf20Sopenharmony_ci{ 11318c2ecf20Sopenharmony_ci unsigned long now = jiffies; 11328c2ecf20Sopenharmony_ci unsigned long timeout; 11338c2ecf20Sopenharmony_ci struct iwl_mvm_baid_data *data; 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ci rcu_read_lock(); 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_ci data = rcu_dereference(mvm->baid_map[baid]); 11388c2ecf20Sopenharmony_ci if (!data) { 11398c2ecf20Sopenharmony_ci IWL_DEBUG_RX(mvm, 11408c2ecf20Sopenharmony_ci "Got valid BAID but no baid allocated, bypass the re-ordering buffer. Baid %d reorder 0x%x\n", 11418c2ecf20Sopenharmony_ci baid, reorder_data); 11428c2ecf20Sopenharmony_ci goto out; 11438c2ecf20Sopenharmony_ci } 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci if (!data->timeout) 11468c2ecf20Sopenharmony_ci goto out; 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_ci timeout = data->timeout; 11498c2ecf20Sopenharmony_ci /* 11508c2ecf20Sopenharmony_ci * Do not update last rx all the time to avoid cache bouncing 11518c2ecf20Sopenharmony_ci * between the rx queues. 11528c2ecf20Sopenharmony_ci * Update it every timeout. Worst case is the session will 11538c2ecf20Sopenharmony_ci * expire after ~ 2 * timeout, which doesn't matter that much. 11548c2ecf20Sopenharmony_ci */ 11558c2ecf20Sopenharmony_ci if (time_before(data->last_rx + TU_TO_JIFFIES(timeout), now)) 11568c2ecf20Sopenharmony_ci /* Update is atomic */ 11578c2ecf20Sopenharmony_ci data->last_rx = now; 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_ciout: 11608c2ecf20Sopenharmony_ci rcu_read_unlock(); 11618c2ecf20Sopenharmony_ci} 11628c2ecf20Sopenharmony_ci 11638c2ecf20Sopenharmony_cistatic void iwl_mvm_flip_address(u8 *addr) 11648c2ecf20Sopenharmony_ci{ 11658c2ecf20Sopenharmony_ci int i; 11668c2ecf20Sopenharmony_ci u8 mac_addr[ETH_ALEN]; 11678c2ecf20Sopenharmony_ci 11688c2ecf20Sopenharmony_ci for (i = 0; i < ETH_ALEN; i++) 11698c2ecf20Sopenharmony_ci mac_addr[i] = addr[ETH_ALEN - i - 1]; 11708c2ecf20Sopenharmony_ci ether_addr_copy(addr, mac_addr); 11718c2ecf20Sopenharmony_ci} 11728c2ecf20Sopenharmony_ci 11738c2ecf20Sopenharmony_cistruct iwl_mvm_rx_phy_data { 11748c2ecf20Sopenharmony_ci enum iwl_rx_phy_info_type info_type; 11758c2ecf20Sopenharmony_ci __le32 d0, d1, d2, d3; 11768c2ecf20Sopenharmony_ci __le16 d4; 11778c2ecf20Sopenharmony_ci}; 11788c2ecf20Sopenharmony_ci 11798c2ecf20Sopenharmony_cistatic void iwl_mvm_decode_he_mu_ext(struct iwl_mvm *mvm, 11808c2ecf20Sopenharmony_ci struct iwl_mvm_rx_phy_data *phy_data, 11818c2ecf20Sopenharmony_ci u32 rate_n_flags, 11828c2ecf20Sopenharmony_ci struct ieee80211_radiotap_he_mu *he_mu) 11838c2ecf20Sopenharmony_ci{ 11848c2ecf20Sopenharmony_ci u32 phy_data2 = le32_to_cpu(phy_data->d2); 11858c2ecf20Sopenharmony_ci u32 phy_data3 = le32_to_cpu(phy_data->d3); 11868c2ecf20Sopenharmony_ci u16 phy_data4 = le16_to_cpu(phy_data->d4); 11878c2ecf20Sopenharmony_ci 11888c2ecf20Sopenharmony_ci if (FIELD_GET(IWL_RX_PHY_DATA4_HE_MU_EXT_CH1_CRC_OK, phy_data4)) { 11898c2ecf20Sopenharmony_ci he_mu->flags1 |= 11908c2ecf20Sopenharmony_ci cpu_to_le16(IEEE80211_RADIOTAP_HE_MU_FLAGS1_CH1_RU_KNOWN | 11918c2ecf20Sopenharmony_ci IEEE80211_RADIOTAP_HE_MU_FLAGS1_CH1_CTR_26T_RU_KNOWN); 11928c2ecf20Sopenharmony_ci 11938c2ecf20Sopenharmony_ci he_mu->flags1 |= 11948c2ecf20Sopenharmony_ci le16_encode_bits(FIELD_GET(IWL_RX_PHY_DATA4_HE_MU_EXT_CH1_CTR_RU, 11958c2ecf20Sopenharmony_ci phy_data4), 11968c2ecf20Sopenharmony_ci IEEE80211_RADIOTAP_HE_MU_FLAGS1_CH1_CTR_26T_RU); 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_ci he_mu->ru_ch1[0] = FIELD_GET(IWL_RX_PHY_DATA2_HE_MU_EXT_CH1_RU0, 11998c2ecf20Sopenharmony_ci phy_data2); 12008c2ecf20Sopenharmony_ci he_mu->ru_ch1[1] = FIELD_GET(IWL_RX_PHY_DATA3_HE_MU_EXT_CH1_RU1, 12018c2ecf20Sopenharmony_ci phy_data3); 12028c2ecf20Sopenharmony_ci he_mu->ru_ch1[2] = FIELD_GET(IWL_RX_PHY_DATA2_HE_MU_EXT_CH1_RU2, 12038c2ecf20Sopenharmony_ci phy_data2); 12048c2ecf20Sopenharmony_ci he_mu->ru_ch1[3] = FIELD_GET(IWL_RX_PHY_DATA3_HE_MU_EXT_CH1_RU3, 12058c2ecf20Sopenharmony_ci phy_data3); 12068c2ecf20Sopenharmony_ci } 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_ci if (FIELD_GET(IWL_RX_PHY_DATA4_HE_MU_EXT_CH2_CRC_OK, phy_data4) && 12098c2ecf20Sopenharmony_ci (rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK) != RATE_MCS_CHAN_WIDTH_20) { 12108c2ecf20Sopenharmony_ci he_mu->flags1 |= 12118c2ecf20Sopenharmony_ci cpu_to_le16(IEEE80211_RADIOTAP_HE_MU_FLAGS1_CH2_RU_KNOWN | 12128c2ecf20Sopenharmony_ci IEEE80211_RADIOTAP_HE_MU_FLAGS1_CH2_CTR_26T_RU_KNOWN); 12138c2ecf20Sopenharmony_ci 12148c2ecf20Sopenharmony_ci he_mu->flags2 |= 12158c2ecf20Sopenharmony_ci le16_encode_bits(FIELD_GET(IWL_RX_PHY_DATA4_HE_MU_EXT_CH2_CTR_RU, 12168c2ecf20Sopenharmony_ci phy_data4), 12178c2ecf20Sopenharmony_ci IEEE80211_RADIOTAP_HE_MU_FLAGS2_CH2_CTR_26T_RU); 12188c2ecf20Sopenharmony_ci 12198c2ecf20Sopenharmony_ci he_mu->ru_ch2[0] = FIELD_GET(IWL_RX_PHY_DATA2_HE_MU_EXT_CH2_RU0, 12208c2ecf20Sopenharmony_ci phy_data2); 12218c2ecf20Sopenharmony_ci he_mu->ru_ch2[1] = FIELD_GET(IWL_RX_PHY_DATA3_HE_MU_EXT_CH2_RU1, 12228c2ecf20Sopenharmony_ci phy_data3); 12238c2ecf20Sopenharmony_ci he_mu->ru_ch2[2] = FIELD_GET(IWL_RX_PHY_DATA2_HE_MU_EXT_CH2_RU2, 12248c2ecf20Sopenharmony_ci phy_data2); 12258c2ecf20Sopenharmony_ci he_mu->ru_ch2[3] = FIELD_GET(IWL_RX_PHY_DATA3_HE_MU_EXT_CH2_RU3, 12268c2ecf20Sopenharmony_ci phy_data3); 12278c2ecf20Sopenharmony_ci } 12288c2ecf20Sopenharmony_ci} 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_cistatic void 12318c2ecf20Sopenharmony_ciiwl_mvm_decode_he_phy_ru_alloc(struct iwl_mvm_rx_phy_data *phy_data, 12328c2ecf20Sopenharmony_ci u32 rate_n_flags, 12338c2ecf20Sopenharmony_ci struct ieee80211_radiotap_he *he, 12348c2ecf20Sopenharmony_ci struct ieee80211_radiotap_he_mu *he_mu, 12358c2ecf20Sopenharmony_ci struct ieee80211_rx_status *rx_status) 12368c2ecf20Sopenharmony_ci{ 12378c2ecf20Sopenharmony_ci /* 12388c2ecf20Sopenharmony_ci * Unfortunately, we have to leave the mac80211 data 12398c2ecf20Sopenharmony_ci * incorrect for the case that we receive an HE-MU 12408c2ecf20Sopenharmony_ci * transmission and *don't* have the HE phy data (due 12418c2ecf20Sopenharmony_ci * to the bits being used for TSF). This shouldn't 12428c2ecf20Sopenharmony_ci * happen though as management frames where we need 12438c2ecf20Sopenharmony_ci * the TSF/timers are not be transmitted in HE-MU. 12448c2ecf20Sopenharmony_ci */ 12458c2ecf20Sopenharmony_ci u8 ru = le32_get_bits(phy_data->d1, IWL_RX_PHY_DATA1_HE_RU_ALLOC_MASK); 12468c2ecf20Sopenharmony_ci u32 he_type = rate_n_flags & RATE_MCS_HE_TYPE_MSK; 12478c2ecf20Sopenharmony_ci u8 offs = 0; 12488c2ecf20Sopenharmony_ci 12498c2ecf20Sopenharmony_ci rx_status->bw = RATE_INFO_BW_HE_RU; 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_ci he->data1 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_BW_RU_ALLOC_KNOWN); 12528c2ecf20Sopenharmony_ci 12538c2ecf20Sopenharmony_ci switch (ru) { 12548c2ecf20Sopenharmony_ci case 0 ... 36: 12558c2ecf20Sopenharmony_ci rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_26; 12568c2ecf20Sopenharmony_ci offs = ru; 12578c2ecf20Sopenharmony_ci break; 12588c2ecf20Sopenharmony_ci case 37 ... 52: 12598c2ecf20Sopenharmony_ci rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_52; 12608c2ecf20Sopenharmony_ci offs = ru - 37; 12618c2ecf20Sopenharmony_ci break; 12628c2ecf20Sopenharmony_ci case 53 ... 60: 12638c2ecf20Sopenharmony_ci rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_106; 12648c2ecf20Sopenharmony_ci offs = ru - 53; 12658c2ecf20Sopenharmony_ci break; 12668c2ecf20Sopenharmony_ci case 61 ... 64: 12678c2ecf20Sopenharmony_ci rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_242; 12688c2ecf20Sopenharmony_ci offs = ru - 61; 12698c2ecf20Sopenharmony_ci break; 12708c2ecf20Sopenharmony_ci case 65 ... 66: 12718c2ecf20Sopenharmony_ci rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_484; 12728c2ecf20Sopenharmony_ci offs = ru - 65; 12738c2ecf20Sopenharmony_ci break; 12748c2ecf20Sopenharmony_ci case 67: 12758c2ecf20Sopenharmony_ci rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_996; 12768c2ecf20Sopenharmony_ci break; 12778c2ecf20Sopenharmony_ci case 68: 12788c2ecf20Sopenharmony_ci rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_2x996; 12798c2ecf20Sopenharmony_ci break; 12808c2ecf20Sopenharmony_ci } 12818c2ecf20Sopenharmony_ci he->data2 |= le16_encode_bits(offs, 12828c2ecf20Sopenharmony_ci IEEE80211_RADIOTAP_HE_DATA2_RU_OFFSET); 12838c2ecf20Sopenharmony_ci he->data2 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_PRISEC_80_KNOWN | 12848c2ecf20Sopenharmony_ci IEEE80211_RADIOTAP_HE_DATA2_RU_OFFSET_KNOWN); 12858c2ecf20Sopenharmony_ci if (phy_data->d1 & cpu_to_le32(IWL_RX_PHY_DATA1_HE_RU_ALLOC_SEC80)) 12868c2ecf20Sopenharmony_ci he->data2 |= 12878c2ecf20Sopenharmony_ci cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_PRISEC_80_SEC); 12888c2ecf20Sopenharmony_ci 12898c2ecf20Sopenharmony_ci#define CHECK_BW(bw) \ 12908c2ecf20Sopenharmony_ci BUILD_BUG_ON(IEEE80211_RADIOTAP_HE_MU_FLAGS2_BW_FROM_SIG_A_BW_ ## bw ## MHZ != \ 12918c2ecf20Sopenharmony_ci RATE_MCS_CHAN_WIDTH_##bw >> RATE_MCS_CHAN_WIDTH_POS); \ 12928c2ecf20Sopenharmony_ci BUILD_BUG_ON(IEEE80211_RADIOTAP_HE_DATA6_TB_PPDU_BW_ ## bw ## MHZ != \ 12938c2ecf20Sopenharmony_ci RATE_MCS_CHAN_WIDTH_##bw >> RATE_MCS_CHAN_WIDTH_POS) 12948c2ecf20Sopenharmony_ci CHECK_BW(20); 12958c2ecf20Sopenharmony_ci CHECK_BW(40); 12968c2ecf20Sopenharmony_ci CHECK_BW(80); 12978c2ecf20Sopenharmony_ci CHECK_BW(160); 12988c2ecf20Sopenharmony_ci 12998c2ecf20Sopenharmony_ci if (he_mu) 13008c2ecf20Sopenharmony_ci he_mu->flags2 |= 13018c2ecf20Sopenharmony_ci le16_encode_bits(FIELD_GET(RATE_MCS_CHAN_WIDTH_MSK, 13028c2ecf20Sopenharmony_ci rate_n_flags), 13038c2ecf20Sopenharmony_ci IEEE80211_RADIOTAP_HE_MU_FLAGS2_BW_FROM_SIG_A_BW); 13048c2ecf20Sopenharmony_ci else if (he_type == RATE_MCS_HE_TYPE_TRIG) 13058c2ecf20Sopenharmony_ci he->data6 |= 13068c2ecf20Sopenharmony_ci cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA6_TB_PPDU_BW_KNOWN) | 13078c2ecf20Sopenharmony_ci le16_encode_bits(FIELD_GET(RATE_MCS_CHAN_WIDTH_MSK, 13088c2ecf20Sopenharmony_ci rate_n_flags), 13098c2ecf20Sopenharmony_ci IEEE80211_RADIOTAP_HE_DATA6_TB_PPDU_BW); 13108c2ecf20Sopenharmony_ci} 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_cistatic void iwl_mvm_decode_he_phy_data(struct iwl_mvm *mvm, 13138c2ecf20Sopenharmony_ci struct iwl_mvm_rx_phy_data *phy_data, 13148c2ecf20Sopenharmony_ci struct ieee80211_radiotap_he *he, 13158c2ecf20Sopenharmony_ci struct ieee80211_radiotap_he_mu *he_mu, 13168c2ecf20Sopenharmony_ci struct ieee80211_rx_status *rx_status, 13178c2ecf20Sopenharmony_ci u32 rate_n_flags, int queue) 13188c2ecf20Sopenharmony_ci{ 13198c2ecf20Sopenharmony_ci switch (phy_data->info_type) { 13208c2ecf20Sopenharmony_ci case IWL_RX_PHY_INFO_TYPE_NONE: 13218c2ecf20Sopenharmony_ci case IWL_RX_PHY_INFO_TYPE_CCK: 13228c2ecf20Sopenharmony_ci case IWL_RX_PHY_INFO_TYPE_OFDM_LGCY: 13238c2ecf20Sopenharmony_ci case IWL_RX_PHY_INFO_TYPE_HT: 13248c2ecf20Sopenharmony_ci case IWL_RX_PHY_INFO_TYPE_VHT_SU: 13258c2ecf20Sopenharmony_ci case IWL_RX_PHY_INFO_TYPE_VHT_MU: 13268c2ecf20Sopenharmony_ci return; 13278c2ecf20Sopenharmony_ci case IWL_RX_PHY_INFO_TYPE_HE_TB_EXT: 13288c2ecf20Sopenharmony_ci he->data1 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_SPTL_REUSE_KNOWN | 13298c2ecf20Sopenharmony_ci IEEE80211_RADIOTAP_HE_DATA1_SPTL_REUSE2_KNOWN | 13308c2ecf20Sopenharmony_ci IEEE80211_RADIOTAP_HE_DATA1_SPTL_REUSE3_KNOWN | 13318c2ecf20Sopenharmony_ci IEEE80211_RADIOTAP_HE_DATA1_SPTL_REUSE4_KNOWN); 13328c2ecf20Sopenharmony_ci he->data4 |= le16_encode_bits(le32_get_bits(phy_data->d2, 13338c2ecf20Sopenharmony_ci IWL_RX_PHY_DATA2_HE_TB_EXT_SPTL_REUSE1), 13348c2ecf20Sopenharmony_ci IEEE80211_RADIOTAP_HE_DATA4_TB_SPTL_REUSE1); 13358c2ecf20Sopenharmony_ci he->data4 |= le16_encode_bits(le32_get_bits(phy_data->d2, 13368c2ecf20Sopenharmony_ci IWL_RX_PHY_DATA2_HE_TB_EXT_SPTL_REUSE2), 13378c2ecf20Sopenharmony_ci IEEE80211_RADIOTAP_HE_DATA4_TB_SPTL_REUSE2); 13388c2ecf20Sopenharmony_ci he->data4 |= le16_encode_bits(le32_get_bits(phy_data->d2, 13398c2ecf20Sopenharmony_ci IWL_RX_PHY_DATA2_HE_TB_EXT_SPTL_REUSE3), 13408c2ecf20Sopenharmony_ci IEEE80211_RADIOTAP_HE_DATA4_TB_SPTL_REUSE3); 13418c2ecf20Sopenharmony_ci he->data4 |= le16_encode_bits(le32_get_bits(phy_data->d2, 13428c2ecf20Sopenharmony_ci IWL_RX_PHY_DATA2_HE_TB_EXT_SPTL_REUSE4), 13438c2ecf20Sopenharmony_ci IEEE80211_RADIOTAP_HE_DATA4_TB_SPTL_REUSE4); 13448c2ecf20Sopenharmony_ci /* fall through */ 13458c2ecf20Sopenharmony_ci case IWL_RX_PHY_INFO_TYPE_HE_SU: 13468c2ecf20Sopenharmony_ci case IWL_RX_PHY_INFO_TYPE_HE_MU: 13478c2ecf20Sopenharmony_ci case IWL_RX_PHY_INFO_TYPE_HE_MU_EXT: 13488c2ecf20Sopenharmony_ci case IWL_RX_PHY_INFO_TYPE_HE_TB: 13498c2ecf20Sopenharmony_ci /* HE common */ 13508c2ecf20Sopenharmony_ci he->data1 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_LDPC_XSYMSEG_KNOWN | 13518c2ecf20Sopenharmony_ci IEEE80211_RADIOTAP_HE_DATA1_DOPPLER_KNOWN | 13528c2ecf20Sopenharmony_ci IEEE80211_RADIOTAP_HE_DATA1_BSS_COLOR_KNOWN); 13538c2ecf20Sopenharmony_ci he->data2 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_PRE_FEC_PAD_KNOWN | 13548c2ecf20Sopenharmony_ci IEEE80211_RADIOTAP_HE_DATA2_PE_DISAMBIG_KNOWN | 13558c2ecf20Sopenharmony_ci IEEE80211_RADIOTAP_HE_DATA2_TXOP_KNOWN | 13568c2ecf20Sopenharmony_ci IEEE80211_RADIOTAP_HE_DATA2_NUM_LTF_SYMS_KNOWN); 13578c2ecf20Sopenharmony_ci he->data3 |= le16_encode_bits(le32_get_bits(phy_data->d0, 13588c2ecf20Sopenharmony_ci IWL_RX_PHY_DATA0_HE_BSS_COLOR_MASK), 13598c2ecf20Sopenharmony_ci IEEE80211_RADIOTAP_HE_DATA3_BSS_COLOR); 13608c2ecf20Sopenharmony_ci if (phy_data->info_type != IWL_RX_PHY_INFO_TYPE_HE_TB && 13618c2ecf20Sopenharmony_ci phy_data->info_type != IWL_RX_PHY_INFO_TYPE_HE_TB_EXT) { 13628c2ecf20Sopenharmony_ci he->data1 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_UL_DL_KNOWN); 13638c2ecf20Sopenharmony_ci he->data3 |= le16_encode_bits(le32_get_bits(phy_data->d0, 13648c2ecf20Sopenharmony_ci IWL_RX_PHY_DATA0_HE_UPLINK), 13658c2ecf20Sopenharmony_ci IEEE80211_RADIOTAP_HE_DATA3_UL_DL); 13668c2ecf20Sopenharmony_ci } 13678c2ecf20Sopenharmony_ci he->data3 |= le16_encode_bits(le32_get_bits(phy_data->d0, 13688c2ecf20Sopenharmony_ci IWL_RX_PHY_DATA0_HE_LDPC_EXT_SYM), 13698c2ecf20Sopenharmony_ci IEEE80211_RADIOTAP_HE_DATA3_LDPC_XSYMSEG); 13708c2ecf20Sopenharmony_ci he->data5 |= le16_encode_bits(le32_get_bits(phy_data->d0, 13718c2ecf20Sopenharmony_ci IWL_RX_PHY_DATA0_HE_PRE_FEC_PAD_MASK), 13728c2ecf20Sopenharmony_ci IEEE80211_RADIOTAP_HE_DATA5_PRE_FEC_PAD); 13738c2ecf20Sopenharmony_ci he->data5 |= le16_encode_bits(le32_get_bits(phy_data->d0, 13748c2ecf20Sopenharmony_ci IWL_RX_PHY_DATA0_HE_PE_DISAMBIG), 13758c2ecf20Sopenharmony_ci IEEE80211_RADIOTAP_HE_DATA5_PE_DISAMBIG); 13768c2ecf20Sopenharmony_ci he->data5 |= le16_encode_bits(le32_get_bits(phy_data->d1, 13778c2ecf20Sopenharmony_ci IWL_RX_PHY_DATA1_HE_LTF_NUM_MASK), 13788c2ecf20Sopenharmony_ci IEEE80211_RADIOTAP_HE_DATA5_NUM_LTF_SYMS); 13798c2ecf20Sopenharmony_ci he->data6 |= le16_encode_bits(le32_get_bits(phy_data->d0, 13808c2ecf20Sopenharmony_ci IWL_RX_PHY_DATA0_HE_TXOP_DUR_MASK), 13818c2ecf20Sopenharmony_ci IEEE80211_RADIOTAP_HE_DATA6_TXOP); 13828c2ecf20Sopenharmony_ci he->data6 |= le16_encode_bits(le32_get_bits(phy_data->d0, 13838c2ecf20Sopenharmony_ci IWL_RX_PHY_DATA0_HE_DOPPLER), 13848c2ecf20Sopenharmony_ci IEEE80211_RADIOTAP_HE_DATA6_DOPPLER); 13858c2ecf20Sopenharmony_ci break; 13868c2ecf20Sopenharmony_ci } 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_ci switch (phy_data->info_type) { 13898c2ecf20Sopenharmony_ci case IWL_RX_PHY_INFO_TYPE_HE_MU_EXT: 13908c2ecf20Sopenharmony_ci case IWL_RX_PHY_INFO_TYPE_HE_MU: 13918c2ecf20Sopenharmony_ci case IWL_RX_PHY_INFO_TYPE_HE_SU: 13928c2ecf20Sopenharmony_ci he->data1 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_SPTL_REUSE_KNOWN); 13938c2ecf20Sopenharmony_ci he->data4 |= le16_encode_bits(le32_get_bits(phy_data->d0, 13948c2ecf20Sopenharmony_ci IWL_RX_PHY_DATA0_HE_SPATIAL_REUSE_MASK), 13958c2ecf20Sopenharmony_ci IEEE80211_RADIOTAP_HE_DATA4_SU_MU_SPTL_REUSE); 13968c2ecf20Sopenharmony_ci break; 13978c2ecf20Sopenharmony_ci default: 13988c2ecf20Sopenharmony_ci /* nothing here */ 13998c2ecf20Sopenharmony_ci break; 14008c2ecf20Sopenharmony_ci } 14018c2ecf20Sopenharmony_ci 14028c2ecf20Sopenharmony_ci switch (phy_data->info_type) { 14038c2ecf20Sopenharmony_ci case IWL_RX_PHY_INFO_TYPE_HE_MU_EXT: 14048c2ecf20Sopenharmony_ci he_mu->flags1 |= 14058c2ecf20Sopenharmony_ci le16_encode_bits(le16_get_bits(phy_data->d4, 14068c2ecf20Sopenharmony_ci IWL_RX_PHY_DATA4_HE_MU_EXT_SIGB_DCM), 14078c2ecf20Sopenharmony_ci IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_DCM); 14088c2ecf20Sopenharmony_ci he_mu->flags1 |= 14098c2ecf20Sopenharmony_ci le16_encode_bits(le16_get_bits(phy_data->d4, 14108c2ecf20Sopenharmony_ci IWL_RX_PHY_DATA4_HE_MU_EXT_SIGB_MCS_MASK), 14118c2ecf20Sopenharmony_ci IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_MCS); 14128c2ecf20Sopenharmony_ci he_mu->flags2 |= 14138c2ecf20Sopenharmony_ci le16_encode_bits(le16_get_bits(phy_data->d4, 14148c2ecf20Sopenharmony_ci IWL_RX_PHY_DATA4_HE_MU_EXT_PREAMBLE_PUNC_TYPE_MASK), 14158c2ecf20Sopenharmony_ci IEEE80211_RADIOTAP_HE_MU_FLAGS2_PUNC_FROM_SIG_A_BW); 14168c2ecf20Sopenharmony_ci iwl_mvm_decode_he_mu_ext(mvm, phy_data, rate_n_flags, he_mu); 14178c2ecf20Sopenharmony_ci /* fall through */ 14188c2ecf20Sopenharmony_ci case IWL_RX_PHY_INFO_TYPE_HE_MU: 14198c2ecf20Sopenharmony_ci he_mu->flags2 |= 14208c2ecf20Sopenharmony_ci le16_encode_bits(le32_get_bits(phy_data->d1, 14218c2ecf20Sopenharmony_ci IWL_RX_PHY_DATA1_HE_MU_SIBG_SYM_OR_USER_NUM_MASK), 14228c2ecf20Sopenharmony_ci IEEE80211_RADIOTAP_HE_MU_FLAGS2_SIG_B_SYMS_USERS); 14238c2ecf20Sopenharmony_ci he_mu->flags2 |= 14248c2ecf20Sopenharmony_ci le16_encode_bits(le32_get_bits(phy_data->d1, 14258c2ecf20Sopenharmony_ci IWL_RX_PHY_DATA1_HE_MU_SIGB_COMPRESSION), 14268c2ecf20Sopenharmony_ci IEEE80211_RADIOTAP_HE_MU_FLAGS2_SIG_B_COMP); 14278c2ecf20Sopenharmony_ci /* fall through */ 14288c2ecf20Sopenharmony_ci case IWL_RX_PHY_INFO_TYPE_HE_TB: 14298c2ecf20Sopenharmony_ci case IWL_RX_PHY_INFO_TYPE_HE_TB_EXT: 14308c2ecf20Sopenharmony_ci iwl_mvm_decode_he_phy_ru_alloc(phy_data, rate_n_flags, 14318c2ecf20Sopenharmony_ci he, he_mu, rx_status); 14328c2ecf20Sopenharmony_ci break; 14338c2ecf20Sopenharmony_ci case IWL_RX_PHY_INFO_TYPE_HE_SU: 14348c2ecf20Sopenharmony_ci he->data1 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_BEAM_CHANGE_KNOWN); 14358c2ecf20Sopenharmony_ci he->data3 |= le16_encode_bits(le32_get_bits(phy_data->d0, 14368c2ecf20Sopenharmony_ci IWL_RX_PHY_DATA0_HE_BEAM_CHNG), 14378c2ecf20Sopenharmony_ci IEEE80211_RADIOTAP_HE_DATA3_BEAM_CHANGE); 14388c2ecf20Sopenharmony_ci break; 14398c2ecf20Sopenharmony_ci default: 14408c2ecf20Sopenharmony_ci /* nothing */ 14418c2ecf20Sopenharmony_ci break; 14428c2ecf20Sopenharmony_ci } 14438c2ecf20Sopenharmony_ci} 14448c2ecf20Sopenharmony_ci 14458c2ecf20Sopenharmony_cistatic void iwl_mvm_rx_he(struct iwl_mvm *mvm, struct sk_buff *skb, 14468c2ecf20Sopenharmony_ci struct iwl_mvm_rx_phy_data *phy_data, 14478c2ecf20Sopenharmony_ci u32 rate_n_flags, u16 phy_info, int queue) 14488c2ecf20Sopenharmony_ci{ 14498c2ecf20Sopenharmony_ci struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); 14508c2ecf20Sopenharmony_ci struct ieee80211_radiotap_he *he = NULL; 14518c2ecf20Sopenharmony_ci struct ieee80211_radiotap_he_mu *he_mu = NULL; 14528c2ecf20Sopenharmony_ci u32 he_type = rate_n_flags & RATE_MCS_HE_TYPE_MSK; 14538c2ecf20Sopenharmony_ci u8 stbc, ltf; 14548c2ecf20Sopenharmony_ci static const struct ieee80211_radiotap_he known = { 14558c2ecf20Sopenharmony_ci .data1 = cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_DATA_MCS_KNOWN | 14568c2ecf20Sopenharmony_ci IEEE80211_RADIOTAP_HE_DATA1_DATA_DCM_KNOWN | 14578c2ecf20Sopenharmony_ci IEEE80211_RADIOTAP_HE_DATA1_STBC_KNOWN | 14588c2ecf20Sopenharmony_ci IEEE80211_RADIOTAP_HE_DATA1_CODING_KNOWN), 14598c2ecf20Sopenharmony_ci .data2 = cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_GI_KNOWN | 14608c2ecf20Sopenharmony_ci IEEE80211_RADIOTAP_HE_DATA2_TXBF_KNOWN), 14618c2ecf20Sopenharmony_ci }; 14628c2ecf20Sopenharmony_ci static const struct ieee80211_radiotap_he_mu mu_known = { 14638c2ecf20Sopenharmony_ci .flags1 = cpu_to_le16(IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_MCS_KNOWN | 14648c2ecf20Sopenharmony_ci IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_DCM_KNOWN | 14658c2ecf20Sopenharmony_ci IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_SYMS_USERS_KNOWN | 14668c2ecf20Sopenharmony_ci IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_COMP_KNOWN), 14678c2ecf20Sopenharmony_ci .flags2 = cpu_to_le16(IEEE80211_RADIOTAP_HE_MU_FLAGS2_PUNC_FROM_SIG_A_BW_KNOWN | 14688c2ecf20Sopenharmony_ci IEEE80211_RADIOTAP_HE_MU_FLAGS2_BW_FROM_SIG_A_BW_KNOWN), 14698c2ecf20Sopenharmony_ci }; 14708c2ecf20Sopenharmony_ci 14718c2ecf20Sopenharmony_ci he = skb_put_data(skb, &known, sizeof(known)); 14728c2ecf20Sopenharmony_ci rx_status->flag |= RX_FLAG_RADIOTAP_HE; 14738c2ecf20Sopenharmony_ci 14748c2ecf20Sopenharmony_ci if (phy_data->info_type == IWL_RX_PHY_INFO_TYPE_HE_MU || 14758c2ecf20Sopenharmony_ci phy_data->info_type == IWL_RX_PHY_INFO_TYPE_HE_MU_EXT) { 14768c2ecf20Sopenharmony_ci he_mu = skb_put_data(skb, &mu_known, sizeof(mu_known)); 14778c2ecf20Sopenharmony_ci rx_status->flag |= RX_FLAG_RADIOTAP_HE_MU; 14788c2ecf20Sopenharmony_ci } 14798c2ecf20Sopenharmony_ci 14808c2ecf20Sopenharmony_ci /* report the AMPDU-EOF bit on single frames */ 14818c2ecf20Sopenharmony_ci if (!queue && !(phy_info & IWL_RX_MPDU_PHY_AMPDU)) { 14828c2ecf20Sopenharmony_ci rx_status->flag |= RX_FLAG_AMPDU_DETAILS; 14838c2ecf20Sopenharmony_ci rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT_KNOWN; 14848c2ecf20Sopenharmony_ci if (phy_data->d0 & cpu_to_le32(IWL_RX_PHY_DATA0_HE_DELIM_EOF)) 14858c2ecf20Sopenharmony_ci rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT; 14868c2ecf20Sopenharmony_ci } 14878c2ecf20Sopenharmony_ci 14888c2ecf20Sopenharmony_ci if (phy_info & IWL_RX_MPDU_PHY_TSF_OVERLOAD) 14898c2ecf20Sopenharmony_ci iwl_mvm_decode_he_phy_data(mvm, phy_data, he, he_mu, rx_status, 14908c2ecf20Sopenharmony_ci rate_n_flags, queue); 14918c2ecf20Sopenharmony_ci 14928c2ecf20Sopenharmony_ci /* update aggregation data for monitor sake on default queue */ 14938c2ecf20Sopenharmony_ci if (!queue && (phy_info & IWL_RX_MPDU_PHY_TSF_OVERLOAD) && 14948c2ecf20Sopenharmony_ci (phy_info & IWL_RX_MPDU_PHY_AMPDU)) { 14958c2ecf20Sopenharmony_ci bool toggle_bit = phy_info & IWL_RX_MPDU_PHY_AMPDU_TOGGLE; 14968c2ecf20Sopenharmony_ci 14978c2ecf20Sopenharmony_ci /* toggle is switched whenever new aggregation starts */ 14988c2ecf20Sopenharmony_ci if (toggle_bit != mvm->ampdu_toggle) { 14998c2ecf20Sopenharmony_ci rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT_KNOWN; 15008c2ecf20Sopenharmony_ci if (phy_data->d0 & cpu_to_le32(IWL_RX_PHY_DATA0_HE_DELIM_EOF)) 15018c2ecf20Sopenharmony_ci rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT; 15028c2ecf20Sopenharmony_ci } 15038c2ecf20Sopenharmony_ci } 15048c2ecf20Sopenharmony_ci 15058c2ecf20Sopenharmony_ci if (he_type == RATE_MCS_HE_TYPE_EXT_SU && 15068c2ecf20Sopenharmony_ci rate_n_flags & RATE_MCS_HE_106T_MSK) { 15078c2ecf20Sopenharmony_ci rx_status->bw = RATE_INFO_BW_HE_RU; 15088c2ecf20Sopenharmony_ci rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_106; 15098c2ecf20Sopenharmony_ci } 15108c2ecf20Sopenharmony_ci 15118c2ecf20Sopenharmony_ci /* actually data is filled in mac80211 */ 15128c2ecf20Sopenharmony_ci if (he_type == RATE_MCS_HE_TYPE_SU || 15138c2ecf20Sopenharmony_ci he_type == RATE_MCS_HE_TYPE_EXT_SU) 15148c2ecf20Sopenharmony_ci he->data1 |= 15158c2ecf20Sopenharmony_ci cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_BW_RU_ALLOC_KNOWN); 15168c2ecf20Sopenharmony_ci 15178c2ecf20Sopenharmony_ci stbc = (rate_n_flags & RATE_MCS_STBC_MSK) >> RATE_MCS_STBC_POS; 15188c2ecf20Sopenharmony_ci rx_status->nss = 15198c2ecf20Sopenharmony_ci ((rate_n_flags & RATE_VHT_MCS_NSS_MSK) >> 15208c2ecf20Sopenharmony_ci RATE_VHT_MCS_NSS_POS) + 1; 15218c2ecf20Sopenharmony_ci rx_status->rate_idx = rate_n_flags & RATE_VHT_MCS_RATE_CODE_MSK; 15228c2ecf20Sopenharmony_ci rx_status->encoding = RX_ENC_HE; 15238c2ecf20Sopenharmony_ci rx_status->enc_flags |= stbc << RX_ENC_FLAG_STBC_SHIFT; 15248c2ecf20Sopenharmony_ci if (rate_n_flags & RATE_MCS_BF_MSK) 15258c2ecf20Sopenharmony_ci rx_status->enc_flags |= RX_ENC_FLAG_BF; 15268c2ecf20Sopenharmony_ci 15278c2ecf20Sopenharmony_ci rx_status->he_dcm = 15288c2ecf20Sopenharmony_ci !!(rate_n_flags & RATE_HE_DUAL_CARRIER_MODE_MSK); 15298c2ecf20Sopenharmony_ci 15308c2ecf20Sopenharmony_ci#define CHECK_TYPE(F) \ 15318c2ecf20Sopenharmony_ci BUILD_BUG_ON(IEEE80211_RADIOTAP_HE_DATA1_FORMAT_ ## F != \ 15328c2ecf20Sopenharmony_ci (RATE_MCS_HE_TYPE_ ## F >> RATE_MCS_HE_TYPE_POS)) 15338c2ecf20Sopenharmony_ci 15348c2ecf20Sopenharmony_ci CHECK_TYPE(SU); 15358c2ecf20Sopenharmony_ci CHECK_TYPE(EXT_SU); 15368c2ecf20Sopenharmony_ci CHECK_TYPE(MU); 15378c2ecf20Sopenharmony_ci CHECK_TYPE(TRIG); 15388c2ecf20Sopenharmony_ci 15398c2ecf20Sopenharmony_ci he->data1 |= cpu_to_le16(he_type >> RATE_MCS_HE_TYPE_POS); 15408c2ecf20Sopenharmony_ci 15418c2ecf20Sopenharmony_ci if (rate_n_flags & RATE_MCS_BF_MSK) 15428c2ecf20Sopenharmony_ci he->data5 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA5_TXBF); 15438c2ecf20Sopenharmony_ci 15448c2ecf20Sopenharmony_ci switch ((rate_n_flags & RATE_MCS_HE_GI_LTF_MSK) >> 15458c2ecf20Sopenharmony_ci RATE_MCS_HE_GI_LTF_POS) { 15468c2ecf20Sopenharmony_ci case 0: 15478c2ecf20Sopenharmony_ci if (he_type == RATE_MCS_HE_TYPE_TRIG) 15488c2ecf20Sopenharmony_ci rx_status->he_gi = NL80211_RATE_INFO_HE_GI_1_6; 15498c2ecf20Sopenharmony_ci else 15508c2ecf20Sopenharmony_ci rx_status->he_gi = NL80211_RATE_INFO_HE_GI_0_8; 15518c2ecf20Sopenharmony_ci if (he_type == RATE_MCS_HE_TYPE_MU) 15528c2ecf20Sopenharmony_ci ltf = IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_4X; 15538c2ecf20Sopenharmony_ci else 15548c2ecf20Sopenharmony_ci ltf = IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_1X; 15558c2ecf20Sopenharmony_ci break; 15568c2ecf20Sopenharmony_ci case 1: 15578c2ecf20Sopenharmony_ci if (he_type == RATE_MCS_HE_TYPE_TRIG) 15588c2ecf20Sopenharmony_ci rx_status->he_gi = NL80211_RATE_INFO_HE_GI_1_6; 15598c2ecf20Sopenharmony_ci else 15608c2ecf20Sopenharmony_ci rx_status->he_gi = NL80211_RATE_INFO_HE_GI_0_8; 15618c2ecf20Sopenharmony_ci ltf = IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_2X; 15628c2ecf20Sopenharmony_ci break; 15638c2ecf20Sopenharmony_ci case 2: 15648c2ecf20Sopenharmony_ci if (he_type == RATE_MCS_HE_TYPE_TRIG) { 15658c2ecf20Sopenharmony_ci rx_status->he_gi = NL80211_RATE_INFO_HE_GI_3_2; 15668c2ecf20Sopenharmony_ci ltf = IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_4X; 15678c2ecf20Sopenharmony_ci } else { 15688c2ecf20Sopenharmony_ci rx_status->he_gi = NL80211_RATE_INFO_HE_GI_1_6; 15698c2ecf20Sopenharmony_ci ltf = IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_2X; 15708c2ecf20Sopenharmony_ci } 15718c2ecf20Sopenharmony_ci break; 15728c2ecf20Sopenharmony_ci case 3: 15738c2ecf20Sopenharmony_ci if ((he_type == RATE_MCS_HE_TYPE_SU || 15748c2ecf20Sopenharmony_ci he_type == RATE_MCS_HE_TYPE_EXT_SU) && 15758c2ecf20Sopenharmony_ci rate_n_flags & RATE_MCS_SGI_MSK) 15768c2ecf20Sopenharmony_ci rx_status->he_gi = NL80211_RATE_INFO_HE_GI_0_8; 15778c2ecf20Sopenharmony_ci else 15788c2ecf20Sopenharmony_ci rx_status->he_gi = NL80211_RATE_INFO_HE_GI_3_2; 15798c2ecf20Sopenharmony_ci ltf = IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_4X; 15808c2ecf20Sopenharmony_ci break; 15818c2ecf20Sopenharmony_ci } 15828c2ecf20Sopenharmony_ci 15838c2ecf20Sopenharmony_ci he->data5 |= le16_encode_bits(ltf, 15848c2ecf20Sopenharmony_ci IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE); 15858c2ecf20Sopenharmony_ci} 15868c2ecf20Sopenharmony_ci 15878c2ecf20Sopenharmony_cistatic void iwl_mvm_decode_lsig(struct sk_buff *skb, 15888c2ecf20Sopenharmony_ci struct iwl_mvm_rx_phy_data *phy_data) 15898c2ecf20Sopenharmony_ci{ 15908c2ecf20Sopenharmony_ci struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); 15918c2ecf20Sopenharmony_ci struct ieee80211_radiotap_lsig *lsig; 15928c2ecf20Sopenharmony_ci 15938c2ecf20Sopenharmony_ci switch (phy_data->info_type) { 15948c2ecf20Sopenharmony_ci case IWL_RX_PHY_INFO_TYPE_HT: 15958c2ecf20Sopenharmony_ci case IWL_RX_PHY_INFO_TYPE_VHT_SU: 15968c2ecf20Sopenharmony_ci case IWL_RX_PHY_INFO_TYPE_VHT_MU: 15978c2ecf20Sopenharmony_ci case IWL_RX_PHY_INFO_TYPE_HE_TB_EXT: 15988c2ecf20Sopenharmony_ci case IWL_RX_PHY_INFO_TYPE_HE_SU: 15998c2ecf20Sopenharmony_ci case IWL_RX_PHY_INFO_TYPE_HE_MU: 16008c2ecf20Sopenharmony_ci case IWL_RX_PHY_INFO_TYPE_HE_MU_EXT: 16018c2ecf20Sopenharmony_ci case IWL_RX_PHY_INFO_TYPE_HE_TB: 16028c2ecf20Sopenharmony_ci lsig = skb_put(skb, sizeof(*lsig)); 16038c2ecf20Sopenharmony_ci lsig->data1 = cpu_to_le16(IEEE80211_RADIOTAP_LSIG_DATA1_LENGTH_KNOWN); 16048c2ecf20Sopenharmony_ci lsig->data2 = le16_encode_bits(le32_get_bits(phy_data->d1, 16058c2ecf20Sopenharmony_ci IWL_RX_PHY_DATA1_LSIG_LEN_MASK), 16068c2ecf20Sopenharmony_ci IEEE80211_RADIOTAP_LSIG_DATA2_LENGTH); 16078c2ecf20Sopenharmony_ci rx_status->flag |= RX_FLAG_RADIOTAP_LSIG; 16088c2ecf20Sopenharmony_ci break; 16098c2ecf20Sopenharmony_ci default: 16108c2ecf20Sopenharmony_ci break; 16118c2ecf20Sopenharmony_ci } 16128c2ecf20Sopenharmony_ci} 16138c2ecf20Sopenharmony_ci 16148c2ecf20Sopenharmony_cistatic inline u8 iwl_mvm_nl80211_band_from_rx_msdu(u8 phy_band) 16158c2ecf20Sopenharmony_ci{ 16168c2ecf20Sopenharmony_ci switch (phy_band) { 16178c2ecf20Sopenharmony_ci case PHY_BAND_24: 16188c2ecf20Sopenharmony_ci return NL80211_BAND_2GHZ; 16198c2ecf20Sopenharmony_ci case PHY_BAND_5: 16208c2ecf20Sopenharmony_ci return NL80211_BAND_5GHZ; 16218c2ecf20Sopenharmony_ci default: 16228c2ecf20Sopenharmony_ci WARN_ONCE(1, "Unsupported phy band (%u)\n", phy_band); 16238c2ecf20Sopenharmony_ci return NL80211_BAND_5GHZ; 16248c2ecf20Sopenharmony_ci } 16258c2ecf20Sopenharmony_ci} 16268c2ecf20Sopenharmony_ci 16278c2ecf20Sopenharmony_civoid iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, 16288c2ecf20Sopenharmony_ci struct iwl_rx_cmd_buffer *rxb, int queue) 16298c2ecf20Sopenharmony_ci{ 16308c2ecf20Sopenharmony_ci struct ieee80211_rx_status *rx_status; 16318c2ecf20Sopenharmony_ci struct iwl_rx_packet *pkt = rxb_addr(rxb); 16328c2ecf20Sopenharmony_ci struct iwl_rx_mpdu_desc *desc = (void *)pkt->data; 16338c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr; 16348c2ecf20Sopenharmony_ci u32 len = le16_to_cpu(desc->mpdu_len); 16358c2ecf20Sopenharmony_ci u32 rate_n_flags, gp2_on_air_rise; 16368c2ecf20Sopenharmony_ci u16 phy_info = le16_to_cpu(desc->phy_info); 16378c2ecf20Sopenharmony_ci struct ieee80211_sta *sta = NULL; 16388c2ecf20Sopenharmony_ci struct sk_buff *skb; 16398c2ecf20Sopenharmony_ci u8 crypt_len = 0, channel, energy_a, energy_b; 16408c2ecf20Sopenharmony_ci size_t desc_size; 16418c2ecf20Sopenharmony_ci struct iwl_mvm_rx_phy_data phy_data = { 16428c2ecf20Sopenharmony_ci .d4 = desc->phy_data4, 16438c2ecf20Sopenharmony_ci .info_type = IWL_RX_PHY_INFO_TYPE_NONE, 16448c2ecf20Sopenharmony_ci }; 16458c2ecf20Sopenharmony_ci bool csi = false; 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_ci if (unlikely(test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))) 16488c2ecf20Sopenharmony_ci return; 16498c2ecf20Sopenharmony_ci 16508c2ecf20Sopenharmony_ci if (mvm->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) { 16518c2ecf20Sopenharmony_ci rate_n_flags = le32_to_cpu(desc->v3.rate_n_flags); 16528c2ecf20Sopenharmony_ci channel = desc->v3.channel; 16538c2ecf20Sopenharmony_ci gp2_on_air_rise = le32_to_cpu(desc->v3.gp2_on_air_rise); 16548c2ecf20Sopenharmony_ci energy_a = desc->v3.energy_a; 16558c2ecf20Sopenharmony_ci energy_b = desc->v3.energy_b; 16568c2ecf20Sopenharmony_ci desc_size = sizeof(*desc); 16578c2ecf20Sopenharmony_ci 16588c2ecf20Sopenharmony_ci phy_data.d0 = desc->v3.phy_data0; 16598c2ecf20Sopenharmony_ci phy_data.d1 = desc->v3.phy_data1; 16608c2ecf20Sopenharmony_ci phy_data.d2 = desc->v3.phy_data2; 16618c2ecf20Sopenharmony_ci phy_data.d3 = desc->v3.phy_data3; 16628c2ecf20Sopenharmony_ci } else { 16638c2ecf20Sopenharmony_ci rate_n_flags = le32_to_cpu(desc->v1.rate_n_flags); 16648c2ecf20Sopenharmony_ci channel = desc->v1.channel; 16658c2ecf20Sopenharmony_ci gp2_on_air_rise = le32_to_cpu(desc->v1.gp2_on_air_rise); 16668c2ecf20Sopenharmony_ci energy_a = desc->v1.energy_a; 16678c2ecf20Sopenharmony_ci energy_b = desc->v1.energy_b; 16688c2ecf20Sopenharmony_ci desc_size = IWL_RX_DESC_SIZE_V1; 16698c2ecf20Sopenharmony_ci 16708c2ecf20Sopenharmony_ci phy_data.d0 = desc->v1.phy_data0; 16718c2ecf20Sopenharmony_ci phy_data.d1 = desc->v1.phy_data1; 16728c2ecf20Sopenharmony_ci phy_data.d2 = desc->v1.phy_data2; 16738c2ecf20Sopenharmony_ci phy_data.d3 = desc->v1.phy_data3; 16748c2ecf20Sopenharmony_ci } 16758c2ecf20Sopenharmony_ci 16768c2ecf20Sopenharmony_ci if (phy_info & IWL_RX_MPDU_PHY_TSF_OVERLOAD) 16778c2ecf20Sopenharmony_ci phy_data.info_type = 16788c2ecf20Sopenharmony_ci le32_get_bits(phy_data.d1, 16798c2ecf20Sopenharmony_ci IWL_RX_PHY_DATA1_INFO_TYPE_MASK); 16808c2ecf20Sopenharmony_ci 16818c2ecf20Sopenharmony_ci hdr = (void *)(pkt->data + desc_size); 16828c2ecf20Sopenharmony_ci /* Dont use dev_alloc_skb(), we'll have enough headroom once 16838c2ecf20Sopenharmony_ci * ieee80211_hdr pulled. 16848c2ecf20Sopenharmony_ci */ 16858c2ecf20Sopenharmony_ci skb = alloc_skb(128, GFP_ATOMIC); 16868c2ecf20Sopenharmony_ci if (!skb) { 16878c2ecf20Sopenharmony_ci IWL_ERR(mvm, "alloc_skb failed\n"); 16888c2ecf20Sopenharmony_ci return; 16898c2ecf20Sopenharmony_ci } 16908c2ecf20Sopenharmony_ci 16918c2ecf20Sopenharmony_ci if (desc->mac_flags2 & IWL_RX_MPDU_MFLG2_PAD) { 16928c2ecf20Sopenharmony_ci /* 16938c2ecf20Sopenharmony_ci * If the device inserted padding it means that (it thought) 16948c2ecf20Sopenharmony_ci * the 802.11 header wasn't a multiple of 4 bytes long. In 16958c2ecf20Sopenharmony_ci * this case, reserve two bytes at the start of the SKB to 16968c2ecf20Sopenharmony_ci * align the payload properly in case we end up copying it. 16978c2ecf20Sopenharmony_ci */ 16988c2ecf20Sopenharmony_ci skb_reserve(skb, 2); 16998c2ecf20Sopenharmony_ci } 17008c2ecf20Sopenharmony_ci 17018c2ecf20Sopenharmony_ci rx_status = IEEE80211_SKB_RXCB(skb); 17028c2ecf20Sopenharmony_ci 17038c2ecf20Sopenharmony_ci /* This may be overridden by iwl_mvm_rx_he() to HE_RU */ 17048c2ecf20Sopenharmony_ci switch (rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK) { 17058c2ecf20Sopenharmony_ci case RATE_MCS_CHAN_WIDTH_20: 17068c2ecf20Sopenharmony_ci break; 17078c2ecf20Sopenharmony_ci case RATE_MCS_CHAN_WIDTH_40: 17088c2ecf20Sopenharmony_ci rx_status->bw = RATE_INFO_BW_40; 17098c2ecf20Sopenharmony_ci break; 17108c2ecf20Sopenharmony_ci case RATE_MCS_CHAN_WIDTH_80: 17118c2ecf20Sopenharmony_ci rx_status->bw = RATE_INFO_BW_80; 17128c2ecf20Sopenharmony_ci break; 17138c2ecf20Sopenharmony_ci case RATE_MCS_CHAN_WIDTH_160: 17148c2ecf20Sopenharmony_ci rx_status->bw = RATE_INFO_BW_160; 17158c2ecf20Sopenharmony_ci break; 17168c2ecf20Sopenharmony_ci } 17178c2ecf20Sopenharmony_ci 17188c2ecf20Sopenharmony_ci if (rate_n_flags & RATE_MCS_HE_MSK) 17198c2ecf20Sopenharmony_ci iwl_mvm_rx_he(mvm, skb, &phy_data, rate_n_flags, 17208c2ecf20Sopenharmony_ci phy_info, queue); 17218c2ecf20Sopenharmony_ci 17228c2ecf20Sopenharmony_ci iwl_mvm_decode_lsig(skb, &phy_data); 17238c2ecf20Sopenharmony_ci 17248c2ecf20Sopenharmony_ci rx_status = IEEE80211_SKB_RXCB(skb); 17258c2ecf20Sopenharmony_ci 17268c2ecf20Sopenharmony_ci if (iwl_mvm_rx_crypto(mvm, hdr, rx_status, phy_info, desc, 17278c2ecf20Sopenharmony_ci le32_to_cpu(pkt->len_n_flags), queue, 17288c2ecf20Sopenharmony_ci &crypt_len)) { 17298c2ecf20Sopenharmony_ci kfree_skb(skb); 17308c2ecf20Sopenharmony_ci return; 17318c2ecf20Sopenharmony_ci } 17328c2ecf20Sopenharmony_ci 17338c2ecf20Sopenharmony_ci /* 17348c2ecf20Sopenharmony_ci * Keep packets with CRC errors (and with overrun) for monitor mode 17358c2ecf20Sopenharmony_ci * (otherwise the firmware discards them) but mark them as bad. 17368c2ecf20Sopenharmony_ci */ 17378c2ecf20Sopenharmony_ci if (!(desc->status & cpu_to_le32(IWL_RX_MPDU_STATUS_CRC_OK)) || 17388c2ecf20Sopenharmony_ci !(desc->status & cpu_to_le32(IWL_RX_MPDU_STATUS_OVERRUN_OK))) { 17398c2ecf20Sopenharmony_ci IWL_DEBUG_RX(mvm, "Bad CRC or FIFO: 0x%08X.\n", 17408c2ecf20Sopenharmony_ci le32_to_cpu(desc->status)); 17418c2ecf20Sopenharmony_ci rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; 17428c2ecf20Sopenharmony_ci } 17438c2ecf20Sopenharmony_ci /* set the preamble flag if appropriate */ 17448c2ecf20Sopenharmony_ci if (rate_n_flags & RATE_MCS_CCK_MSK && 17458c2ecf20Sopenharmony_ci phy_info & IWL_RX_MPDU_PHY_SHORT_PREAMBLE) 17468c2ecf20Sopenharmony_ci rx_status->enc_flags |= RX_ENC_FLAG_SHORTPRE; 17478c2ecf20Sopenharmony_ci 17488c2ecf20Sopenharmony_ci if (likely(!(phy_info & IWL_RX_MPDU_PHY_TSF_OVERLOAD))) { 17498c2ecf20Sopenharmony_ci u64 tsf_on_air_rise; 17508c2ecf20Sopenharmony_ci 17518c2ecf20Sopenharmony_ci if (mvm->trans->trans_cfg->device_family >= 17528c2ecf20Sopenharmony_ci IWL_DEVICE_FAMILY_AX210) 17538c2ecf20Sopenharmony_ci tsf_on_air_rise = le64_to_cpu(desc->v3.tsf_on_air_rise); 17548c2ecf20Sopenharmony_ci else 17558c2ecf20Sopenharmony_ci tsf_on_air_rise = le64_to_cpu(desc->v1.tsf_on_air_rise); 17568c2ecf20Sopenharmony_ci 17578c2ecf20Sopenharmony_ci rx_status->mactime = tsf_on_air_rise; 17588c2ecf20Sopenharmony_ci /* TSF as indicated by the firmware is at INA time */ 17598c2ecf20Sopenharmony_ci rx_status->flag |= RX_FLAG_MACTIME_PLCP_START; 17608c2ecf20Sopenharmony_ci } 17618c2ecf20Sopenharmony_ci 17628c2ecf20Sopenharmony_ci rx_status->device_timestamp = gp2_on_air_rise; 17638c2ecf20Sopenharmony_ci if (iwl_mvm_is_band_in_rx_supported(mvm)) { 17648c2ecf20Sopenharmony_ci u8 band = BAND_IN_RX_STATUS(desc->mac_phy_idx); 17658c2ecf20Sopenharmony_ci 17668c2ecf20Sopenharmony_ci rx_status->band = iwl_mvm_nl80211_band_from_rx_msdu(band); 17678c2ecf20Sopenharmony_ci } else { 17688c2ecf20Sopenharmony_ci rx_status->band = channel > 14 ? NL80211_BAND_5GHZ : 17698c2ecf20Sopenharmony_ci NL80211_BAND_2GHZ; 17708c2ecf20Sopenharmony_ci } 17718c2ecf20Sopenharmony_ci rx_status->freq = ieee80211_channel_to_frequency(channel, 17728c2ecf20Sopenharmony_ci rx_status->band); 17738c2ecf20Sopenharmony_ci iwl_mvm_get_signal_strength(mvm, rx_status, rate_n_flags, energy_a, 17748c2ecf20Sopenharmony_ci energy_b); 17758c2ecf20Sopenharmony_ci 17768c2ecf20Sopenharmony_ci /* update aggregation data for monitor sake on default queue */ 17778c2ecf20Sopenharmony_ci if (!queue && (phy_info & IWL_RX_MPDU_PHY_AMPDU)) { 17788c2ecf20Sopenharmony_ci bool toggle_bit = phy_info & IWL_RX_MPDU_PHY_AMPDU_TOGGLE; 17798c2ecf20Sopenharmony_ci 17808c2ecf20Sopenharmony_ci rx_status->flag |= RX_FLAG_AMPDU_DETAILS; 17818c2ecf20Sopenharmony_ci /* 17828c2ecf20Sopenharmony_ci * Toggle is switched whenever new aggregation starts. Make 17838c2ecf20Sopenharmony_ci * sure ampdu_reference is never 0 so we can later use it to 17848c2ecf20Sopenharmony_ci * see if the frame was really part of an A-MPDU or not. 17858c2ecf20Sopenharmony_ci */ 17868c2ecf20Sopenharmony_ci if (toggle_bit != mvm->ampdu_toggle) { 17878c2ecf20Sopenharmony_ci mvm->ampdu_ref++; 17888c2ecf20Sopenharmony_ci if (mvm->ampdu_ref == 0) 17898c2ecf20Sopenharmony_ci mvm->ampdu_ref++; 17908c2ecf20Sopenharmony_ci mvm->ampdu_toggle = toggle_bit; 17918c2ecf20Sopenharmony_ci } 17928c2ecf20Sopenharmony_ci rx_status->ampdu_reference = mvm->ampdu_ref; 17938c2ecf20Sopenharmony_ci } 17948c2ecf20Sopenharmony_ci 17958c2ecf20Sopenharmony_ci if (unlikely(mvm->monitor_on)) 17968c2ecf20Sopenharmony_ci iwl_mvm_add_rtap_sniffer_config(mvm, skb); 17978c2ecf20Sopenharmony_ci 17988c2ecf20Sopenharmony_ci rcu_read_lock(); 17998c2ecf20Sopenharmony_ci 18008c2ecf20Sopenharmony_ci if (desc->status & cpu_to_le32(IWL_RX_MPDU_STATUS_SRC_STA_FOUND)) { 18018c2ecf20Sopenharmony_ci u8 id = le32_get_bits(desc->status, IWL_RX_MPDU_STATUS_STA_ID); 18028c2ecf20Sopenharmony_ci 18038c2ecf20Sopenharmony_ci if (!WARN_ON_ONCE(id >= mvm->fw->ucode_capa.num_stations)) { 18048c2ecf20Sopenharmony_ci sta = rcu_dereference(mvm->fw_id_to_mac_id[id]); 18058c2ecf20Sopenharmony_ci if (IS_ERR(sta)) 18068c2ecf20Sopenharmony_ci sta = NULL; 18078c2ecf20Sopenharmony_ci } 18088c2ecf20Sopenharmony_ci } else if (!is_multicast_ether_addr(hdr->addr2)) { 18098c2ecf20Sopenharmony_ci /* 18108c2ecf20Sopenharmony_ci * This is fine since we prevent two stations with the same 18118c2ecf20Sopenharmony_ci * address from being added. 18128c2ecf20Sopenharmony_ci */ 18138c2ecf20Sopenharmony_ci sta = ieee80211_find_sta_by_ifaddr(mvm->hw, hdr->addr2, NULL); 18148c2ecf20Sopenharmony_ci } 18158c2ecf20Sopenharmony_ci 18168c2ecf20Sopenharmony_ci if (sta) { 18178c2ecf20Sopenharmony_ci struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); 18188c2ecf20Sopenharmony_ci struct ieee80211_vif *tx_blocked_vif = 18198c2ecf20Sopenharmony_ci rcu_dereference(mvm->csa_tx_blocked_vif); 18208c2ecf20Sopenharmony_ci u8 baid = (u8)((le32_to_cpu(desc->reorder_data) & 18218c2ecf20Sopenharmony_ci IWL_RX_MPDU_REORDER_BAID_MASK) >> 18228c2ecf20Sopenharmony_ci IWL_RX_MPDU_REORDER_BAID_SHIFT); 18238c2ecf20Sopenharmony_ci struct iwl_fw_dbg_trigger_tlv *trig; 18248c2ecf20Sopenharmony_ci struct ieee80211_vif *vif = mvmsta->vif; 18258c2ecf20Sopenharmony_ci 18268c2ecf20Sopenharmony_ci if (!mvm->tcm.paused && len >= sizeof(*hdr) && 18278c2ecf20Sopenharmony_ci !is_multicast_ether_addr(hdr->addr1) && 18288c2ecf20Sopenharmony_ci ieee80211_is_data(hdr->frame_control) && 18298c2ecf20Sopenharmony_ci time_after(jiffies, mvm->tcm.ts + MVM_TCM_PERIOD)) 18308c2ecf20Sopenharmony_ci schedule_delayed_work(&mvm->tcm.work, 0); 18318c2ecf20Sopenharmony_ci 18328c2ecf20Sopenharmony_ci /* 18338c2ecf20Sopenharmony_ci * We have tx blocked stations (with CS bit). If we heard 18348c2ecf20Sopenharmony_ci * frames from a blocked station on a new channel we can 18358c2ecf20Sopenharmony_ci * TX to it again. 18368c2ecf20Sopenharmony_ci */ 18378c2ecf20Sopenharmony_ci if (unlikely(tx_blocked_vif) && tx_blocked_vif == vif) { 18388c2ecf20Sopenharmony_ci struct iwl_mvm_vif *mvmvif = 18398c2ecf20Sopenharmony_ci iwl_mvm_vif_from_mac80211(tx_blocked_vif); 18408c2ecf20Sopenharmony_ci 18418c2ecf20Sopenharmony_ci if (mvmvif->csa_target_freq == rx_status->freq) 18428c2ecf20Sopenharmony_ci iwl_mvm_sta_modify_disable_tx_ap(mvm, sta, 18438c2ecf20Sopenharmony_ci false); 18448c2ecf20Sopenharmony_ci } 18458c2ecf20Sopenharmony_ci 18468c2ecf20Sopenharmony_ci rs_update_last_rssi(mvm, mvmsta, rx_status); 18478c2ecf20Sopenharmony_ci 18488c2ecf20Sopenharmony_ci trig = iwl_fw_dbg_trigger_on(&mvm->fwrt, 18498c2ecf20Sopenharmony_ci ieee80211_vif_to_wdev(vif), 18508c2ecf20Sopenharmony_ci FW_DBG_TRIGGER_RSSI); 18518c2ecf20Sopenharmony_ci 18528c2ecf20Sopenharmony_ci if (trig && ieee80211_is_beacon(hdr->frame_control)) { 18538c2ecf20Sopenharmony_ci struct iwl_fw_dbg_trigger_low_rssi *rssi_trig; 18548c2ecf20Sopenharmony_ci s32 rssi; 18558c2ecf20Sopenharmony_ci 18568c2ecf20Sopenharmony_ci rssi_trig = (void *)trig->data; 18578c2ecf20Sopenharmony_ci rssi = le32_to_cpu(rssi_trig->rssi); 18588c2ecf20Sopenharmony_ci 18598c2ecf20Sopenharmony_ci if (rx_status->signal < rssi) 18608c2ecf20Sopenharmony_ci iwl_fw_dbg_collect_trig(&mvm->fwrt, trig, 18618c2ecf20Sopenharmony_ci NULL); 18628c2ecf20Sopenharmony_ci } 18638c2ecf20Sopenharmony_ci 18648c2ecf20Sopenharmony_ci if (ieee80211_is_data(hdr->frame_control)) 18658c2ecf20Sopenharmony_ci iwl_mvm_rx_csum(mvm, sta, skb, pkt); 18668c2ecf20Sopenharmony_ci 18678c2ecf20Sopenharmony_ci if (iwl_mvm_is_dup(sta, queue, rx_status, hdr, desc)) { 18688c2ecf20Sopenharmony_ci kfree_skb(skb); 18698c2ecf20Sopenharmony_ci goto out; 18708c2ecf20Sopenharmony_ci } 18718c2ecf20Sopenharmony_ci 18728c2ecf20Sopenharmony_ci /* 18738c2ecf20Sopenharmony_ci * Our hardware de-aggregates AMSDUs but copies the mac header 18748c2ecf20Sopenharmony_ci * as it to the de-aggregated MPDUs. We need to turn off the 18758c2ecf20Sopenharmony_ci * AMSDU bit in the QoS control ourselves. 18768c2ecf20Sopenharmony_ci * In addition, HW reverses addr3 and addr4 - reverse it back. 18778c2ecf20Sopenharmony_ci */ 18788c2ecf20Sopenharmony_ci if ((desc->mac_flags2 & IWL_RX_MPDU_MFLG2_AMSDU) && 18798c2ecf20Sopenharmony_ci !WARN_ON(!ieee80211_is_data_qos(hdr->frame_control))) { 18808c2ecf20Sopenharmony_ci u8 *qc = ieee80211_get_qos_ctl(hdr); 18818c2ecf20Sopenharmony_ci 18828c2ecf20Sopenharmony_ci *qc &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT; 18838c2ecf20Sopenharmony_ci 18848c2ecf20Sopenharmony_ci if (mvm->trans->trans_cfg->device_family == 18858c2ecf20Sopenharmony_ci IWL_DEVICE_FAMILY_9000) { 18868c2ecf20Sopenharmony_ci iwl_mvm_flip_address(hdr->addr3); 18878c2ecf20Sopenharmony_ci 18888c2ecf20Sopenharmony_ci if (ieee80211_has_a4(hdr->frame_control)) 18898c2ecf20Sopenharmony_ci iwl_mvm_flip_address(hdr->addr4); 18908c2ecf20Sopenharmony_ci } 18918c2ecf20Sopenharmony_ci } 18928c2ecf20Sopenharmony_ci if (baid != IWL_RX_REORDER_DATA_INVALID_BAID) { 18938c2ecf20Sopenharmony_ci u32 reorder_data = le32_to_cpu(desc->reorder_data); 18948c2ecf20Sopenharmony_ci 18958c2ecf20Sopenharmony_ci iwl_mvm_agg_rx_received(mvm, reorder_data, baid); 18968c2ecf20Sopenharmony_ci } 18978c2ecf20Sopenharmony_ci } 18988c2ecf20Sopenharmony_ci 18998c2ecf20Sopenharmony_ci if (!(rate_n_flags & RATE_MCS_CCK_MSK) && 19008c2ecf20Sopenharmony_ci rate_n_flags & RATE_MCS_SGI_MSK) 19018c2ecf20Sopenharmony_ci rx_status->enc_flags |= RX_ENC_FLAG_SHORT_GI; 19028c2ecf20Sopenharmony_ci if (rate_n_flags & RATE_HT_MCS_GF_MSK) 19038c2ecf20Sopenharmony_ci rx_status->enc_flags |= RX_ENC_FLAG_HT_GF; 19048c2ecf20Sopenharmony_ci if (rate_n_flags & RATE_MCS_LDPC_MSK) 19058c2ecf20Sopenharmony_ci rx_status->enc_flags |= RX_ENC_FLAG_LDPC; 19068c2ecf20Sopenharmony_ci if (rate_n_flags & RATE_MCS_HT_MSK) { 19078c2ecf20Sopenharmony_ci u8 stbc = (rate_n_flags & RATE_MCS_STBC_MSK) >> 19088c2ecf20Sopenharmony_ci RATE_MCS_STBC_POS; 19098c2ecf20Sopenharmony_ci rx_status->encoding = RX_ENC_HT; 19108c2ecf20Sopenharmony_ci rx_status->rate_idx = rate_n_flags & RATE_HT_MCS_INDEX_MSK; 19118c2ecf20Sopenharmony_ci rx_status->enc_flags |= stbc << RX_ENC_FLAG_STBC_SHIFT; 19128c2ecf20Sopenharmony_ci } else if (rate_n_flags & RATE_MCS_VHT_MSK) { 19138c2ecf20Sopenharmony_ci u8 stbc = (rate_n_flags & RATE_MCS_STBC_MSK) >> 19148c2ecf20Sopenharmony_ci RATE_MCS_STBC_POS; 19158c2ecf20Sopenharmony_ci rx_status->nss = 19168c2ecf20Sopenharmony_ci ((rate_n_flags & RATE_VHT_MCS_NSS_MSK) >> 19178c2ecf20Sopenharmony_ci RATE_VHT_MCS_NSS_POS) + 1; 19188c2ecf20Sopenharmony_ci rx_status->rate_idx = rate_n_flags & RATE_VHT_MCS_RATE_CODE_MSK; 19198c2ecf20Sopenharmony_ci rx_status->encoding = RX_ENC_VHT; 19208c2ecf20Sopenharmony_ci rx_status->enc_flags |= stbc << RX_ENC_FLAG_STBC_SHIFT; 19218c2ecf20Sopenharmony_ci if (rate_n_flags & RATE_MCS_BF_MSK) 19228c2ecf20Sopenharmony_ci rx_status->enc_flags |= RX_ENC_FLAG_BF; 19238c2ecf20Sopenharmony_ci } else if (!(rate_n_flags & RATE_MCS_HE_MSK)) { 19248c2ecf20Sopenharmony_ci int rate = iwl_mvm_legacy_rate_to_mac80211_idx(rate_n_flags, 19258c2ecf20Sopenharmony_ci rx_status->band); 19268c2ecf20Sopenharmony_ci 19278c2ecf20Sopenharmony_ci if (WARN(rate < 0 || rate > 0xFF, 19288c2ecf20Sopenharmony_ci "Invalid rate flags 0x%x, band %d,\n", 19298c2ecf20Sopenharmony_ci rate_n_flags, rx_status->band)) { 19308c2ecf20Sopenharmony_ci kfree_skb(skb); 19318c2ecf20Sopenharmony_ci goto out; 19328c2ecf20Sopenharmony_ci } 19338c2ecf20Sopenharmony_ci rx_status->rate_idx = rate; 19348c2ecf20Sopenharmony_ci } 19358c2ecf20Sopenharmony_ci 19368c2ecf20Sopenharmony_ci /* management stuff on default queue */ 19378c2ecf20Sopenharmony_ci if (!queue) { 19388c2ecf20Sopenharmony_ci if (unlikely((ieee80211_is_beacon(hdr->frame_control) || 19398c2ecf20Sopenharmony_ci ieee80211_is_probe_resp(hdr->frame_control)) && 19408c2ecf20Sopenharmony_ci mvm->sched_scan_pass_all == 19418c2ecf20Sopenharmony_ci SCHED_SCAN_PASS_ALL_ENABLED)) 19428c2ecf20Sopenharmony_ci mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_FOUND; 19438c2ecf20Sopenharmony_ci 19448c2ecf20Sopenharmony_ci if (unlikely(ieee80211_is_beacon(hdr->frame_control) || 19458c2ecf20Sopenharmony_ci ieee80211_is_probe_resp(hdr->frame_control))) 19468c2ecf20Sopenharmony_ci rx_status->boottime_ns = ktime_get_boottime_ns(); 19478c2ecf20Sopenharmony_ci } 19488c2ecf20Sopenharmony_ci 19498c2ecf20Sopenharmony_ci if (iwl_mvm_create_skb(mvm, skb, hdr, len, crypt_len, rxb)) { 19508c2ecf20Sopenharmony_ci kfree_skb(skb); 19518c2ecf20Sopenharmony_ci goto out; 19528c2ecf20Sopenharmony_ci } 19538c2ecf20Sopenharmony_ci 19548c2ecf20Sopenharmony_ci if (!iwl_mvm_reorder(mvm, napi, queue, sta, skb, desc)) 19558c2ecf20Sopenharmony_ci iwl_mvm_pass_packet_to_mac80211(mvm, napi, skb, queue, 19568c2ecf20Sopenharmony_ci sta, csi); 19578c2ecf20Sopenharmony_ciout: 19588c2ecf20Sopenharmony_ci rcu_read_unlock(); 19598c2ecf20Sopenharmony_ci} 19608c2ecf20Sopenharmony_ci 19618c2ecf20Sopenharmony_civoid iwl_mvm_rx_monitor_no_data(struct iwl_mvm *mvm, struct napi_struct *napi, 19628c2ecf20Sopenharmony_ci struct iwl_rx_cmd_buffer *rxb, int queue) 19638c2ecf20Sopenharmony_ci{ 19648c2ecf20Sopenharmony_ci struct ieee80211_rx_status *rx_status; 19658c2ecf20Sopenharmony_ci struct iwl_rx_packet *pkt = rxb_addr(rxb); 19668c2ecf20Sopenharmony_ci struct iwl_rx_no_data *desc = (void *)pkt->data; 19678c2ecf20Sopenharmony_ci u32 rate_n_flags = le32_to_cpu(desc->rate); 19688c2ecf20Sopenharmony_ci u32 gp2_on_air_rise = le32_to_cpu(desc->on_air_rise_time); 19698c2ecf20Sopenharmony_ci u32 rssi = le32_to_cpu(desc->rssi); 19708c2ecf20Sopenharmony_ci u32 info_type = le32_to_cpu(desc->info) & RX_NO_DATA_INFO_TYPE_MSK; 19718c2ecf20Sopenharmony_ci u16 phy_info = IWL_RX_MPDU_PHY_TSF_OVERLOAD; 19728c2ecf20Sopenharmony_ci struct ieee80211_sta *sta = NULL; 19738c2ecf20Sopenharmony_ci struct sk_buff *skb; 19748c2ecf20Sopenharmony_ci u8 channel, energy_a, energy_b; 19758c2ecf20Sopenharmony_ci struct iwl_mvm_rx_phy_data phy_data = { 19768c2ecf20Sopenharmony_ci .d0 = desc->phy_info[0], 19778c2ecf20Sopenharmony_ci .info_type = IWL_RX_PHY_INFO_TYPE_NONE, 19788c2ecf20Sopenharmony_ci }; 19798c2ecf20Sopenharmony_ci 19808c2ecf20Sopenharmony_ci if (unlikely(test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))) 19818c2ecf20Sopenharmony_ci return; 19828c2ecf20Sopenharmony_ci 19838c2ecf20Sopenharmony_ci energy_a = (rssi & RX_NO_DATA_CHAIN_A_MSK) >> RX_NO_DATA_CHAIN_A_POS; 19848c2ecf20Sopenharmony_ci energy_b = (rssi & RX_NO_DATA_CHAIN_B_MSK) >> RX_NO_DATA_CHAIN_B_POS; 19858c2ecf20Sopenharmony_ci channel = (rssi & RX_NO_DATA_CHANNEL_MSK) >> RX_NO_DATA_CHANNEL_POS; 19868c2ecf20Sopenharmony_ci 19878c2ecf20Sopenharmony_ci phy_data.info_type = 19888c2ecf20Sopenharmony_ci le32_get_bits(desc->phy_info[1], 19898c2ecf20Sopenharmony_ci IWL_RX_PHY_DATA1_INFO_TYPE_MASK); 19908c2ecf20Sopenharmony_ci 19918c2ecf20Sopenharmony_ci /* Dont use dev_alloc_skb(), we'll have enough headroom once 19928c2ecf20Sopenharmony_ci * ieee80211_hdr pulled. 19938c2ecf20Sopenharmony_ci */ 19948c2ecf20Sopenharmony_ci skb = alloc_skb(128, GFP_ATOMIC); 19958c2ecf20Sopenharmony_ci if (!skb) { 19968c2ecf20Sopenharmony_ci IWL_ERR(mvm, "alloc_skb failed\n"); 19978c2ecf20Sopenharmony_ci return; 19988c2ecf20Sopenharmony_ci } 19998c2ecf20Sopenharmony_ci 20008c2ecf20Sopenharmony_ci rx_status = IEEE80211_SKB_RXCB(skb); 20018c2ecf20Sopenharmony_ci 20028c2ecf20Sopenharmony_ci /* 0-length PSDU */ 20038c2ecf20Sopenharmony_ci rx_status->flag |= RX_FLAG_NO_PSDU; 20048c2ecf20Sopenharmony_ci 20058c2ecf20Sopenharmony_ci switch (info_type) { 20068c2ecf20Sopenharmony_ci case RX_NO_DATA_INFO_TYPE_NDP: 20078c2ecf20Sopenharmony_ci rx_status->zero_length_psdu_type = 20088c2ecf20Sopenharmony_ci IEEE80211_RADIOTAP_ZERO_LEN_PSDU_SOUNDING; 20098c2ecf20Sopenharmony_ci break; 20108c2ecf20Sopenharmony_ci case RX_NO_DATA_INFO_TYPE_MU_UNMATCHED: 20118c2ecf20Sopenharmony_ci case RX_NO_DATA_INFO_TYPE_HE_TB_UNMATCHED: 20128c2ecf20Sopenharmony_ci rx_status->zero_length_psdu_type = 20138c2ecf20Sopenharmony_ci IEEE80211_RADIOTAP_ZERO_LEN_PSDU_NOT_CAPTURED; 20148c2ecf20Sopenharmony_ci break; 20158c2ecf20Sopenharmony_ci default: 20168c2ecf20Sopenharmony_ci rx_status->zero_length_psdu_type = 20178c2ecf20Sopenharmony_ci IEEE80211_RADIOTAP_ZERO_LEN_PSDU_VENDOR; 20188c2ecf20Sopenharmony_ci break; 20198c2ecf20Sopenharmony_ci } 20208c2ecf20Sopenharmony_ci 20218c2ecf20Sopenharmony_ci /* This may be overridden by iwl_mvm_rx_he() to HE_RU */ 20228c2ecf20Sopenharmony_ci switch (rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK) { 20238c2ecf20Sopenharmony_ci case RATE_MCS_CHAN_WIDTH_20: 20248c2ecf20Sopenharmony_ci break; 20258c2ecf20Sopenharmony_ci case RATE_MCS_CHAN_WIDTH_40: 20268c2ecf20Sopenharmony_ci rx_status->bw = RATE_INFO_BW_40; 20278c2ecf20Sopenharmony_ci break; 20288c2ecf20Sopenharmony_ci case RATE_MCS_CHAN_WIDTH_80: 20298c2ecf20Sopenharmony_ci rx_status->bw = RATE_INFO_BW_80; 20308c2ecf20Sopenharmony_ci break; 20318c2ecf20Sopenharmony_ci case RATE_MCS_CHAN_WIDTH_160: 20328c2ecf20Sopenharmony_ci rx_status->bw = RATE_INFO_BW_160; 20338c2ecf20Sopenharmony_ci break; 20348c2ecf20Sopenharmony_ci } 20358c2ecf20Sopenharmony_ci 20368c2ecf20Sopenharmony_ci if (rate_n_flags & RATE_MCS_HE_MSK) 20378c2ecf20Sopenharmony_ci iwl_mvm_rx_he(mvm, skb, &phy_data, rate_n_flags, 20388c2ecf20Sopenharmony_ci phy_info, queue); 20398c2ecf20Sopenharmony_ci 20408c2ecf20Sopenharmony_ci iwl_mvm_decode_lsig(skb, &phy_data); 20418c2ecf20Sopenharmony_ci 20428c2ecf20Sopenharmony_ci rx_status->device_timestamp = gp2_on_air_rise; 20438c2ecf20Sopenharmony_ci rx_status->band = channel > 14 ? NL80211_BAND_5GHZ : 20448c2ecf20Sopenharmony_ci NL80211_BAND_2GHZ; 20458c2ecf20Sopenharmony_ci rx_status->freq = ieee80211_channel_to_frequency(channel, 20468c2ecf20Sopenharmony_ci rx_status->band); 20478c2ecf20Sopenharmony_ci iwl_mvm_get_signal_strength(mvm, rx_status, rate_n_flags, energy_a, 20488c2ecf20Sopenharmony_ci energy_b); 20498c2ecf20Sopenharmony_ci 20508c2ecf20Sopenharmony_ci rcu_read_lock(); 20518c2ecf20Sopenharmony_ci 20528c2ecf20Sopenharmony_ci if (!(rate_n_flags & RATE_MCS_CCK_MSK) && 20538c2ecf20Sopenharmony_ci rate_n_flags & RATE_MCS_SGI_MSK) 20548c2ecf20Sopenharmony_ci rx_status->enc_flags |= RX_ENC_FLAG_SHORT_GI; 20558c2ecf20Sopenharmony_ci if (rate_n_flags & RATE_HT_MCS_GF_MSK) 20568c2ecf20Sopenharmony_ci rx_status->enc_flags |= RX_ENC_FLAG_HT_GF; 20578c2ecf20Sopenharmony_ci if (rate_n_flags & RATE_MCS_LDPC_MSK) 20588c2ecf20Sopenharmony_ci rx_status->enc_flags |= RX_ENC_FLAG_LDPC; 20598c2ecf20Sopenharmony_ci if (rate_n_flags & RATE_MCS_HT_MSK) { 20608c2ecf20Sopenharmony_ci u8 stbc = (rate_n_flags & RATE_MCS_STBC_MSK) >> 20618c2ecf20Sopenharmony_ci RATE_MCS_STBC_POS; 20628c2ecf20Sopenharmony_ci rx_status->encoding = RX_ENC_HT; 20638c2ecf20Sopenharmony_ci rx_status->rate_idx = rate_n_flags & RATE_HT_MCS_INDEX_MSK; 20648c2ecf20Sopenharmony_ci rx_status->enc_flags |= stbc << RX_ENC_FLAG_STBC_SHIFT; 20658c2ecf20Sopenharmony_ci } else if (rate_n_flags & RATE_MCS_VHT_MSK) { 20668c2ecf20Sopenharmony_ci u8 stbc = (rate_n_flags & RATE_MCS_STBC_MSK) >> 20678c2ecf20Sopenharmony_ci RATE_MCS_STBC_POS; 20688c2ecf20Sopenharmony_ci rx_status->rate_idx = rate_n_flags & RATE_VHT_MCS_RATE_CODE_MSK; 20698c2ecf20Sopenharmony_ci rx_status->encoding = RX_ENC_VHT; 20708c2ecf20Sopenharmony_ci rx_status->enc_flags |= stbc << RX_ENC_FLAG_STBC_SHIFT; 20718c2ecf20Sopenharmony_ci if (rate_n_flags & RATE_MCS_BF_MSK) 20728c2ecf20Sopenharmony_ci rx_status->enc_flags |= RX_ENC_FLAG_BF; 20738c2ecf20Sopenharmony_ci /* 20748c2ecf20Sopenharmony_ci * take the nss from the rx_vec since the rate_n_flags has 20758c2ecf20Sopenharmony_ci * only 2 bits for the nss which gives a max of 4 ss but 20768c2ecf20Sopenharmony_ci * there may be up to 8 spatial streams 20778c2ecf20Sopenharmony_ci */ 20788c2ecf20Sopenharmony_ci rx_status->nss = 20798c2ecf20Sopenharmony_ci le32_get_bits(desc->rx_vec[0], 20808c2ecf20Sopenharmony_ci RX_NO_DATA_RX_VEC0_VHT_NSTS_MSK) + 1; 20818c2ecf20Sopenharmony_ci } else if (rate_n_flags & RATE_MCS_HE_MSK) { 20828c2ecf20Sopenharmony_ci rx_status->nss = 20838c2ecf20Sopenharmony_ci le32_get_bits(desc->rx_vec[0], 20848c2ecf20Sopenharmony_ci RX_NO_DATA_RX_VEC0_HE_NSTS_MSK) + 1; 20858c2ecf20Sopenharmony_ci } else { 20868c2ecf20Sopenharmony_ci int rate = iwl_mvm_legacy_rate_to_mac80211_idx(rate_n_flags, 20878c2ecf20Sopenharmony_ci rx_status->band); 20888c2ecf20Sopenharmony_ci 20898c2ecf20Sopenharmony_ci if (WARN(rate < 0 || rate > 0xFF, 20908c2ecf20Sopenharmony_ci "Invalid rate flags 0x%x, band %d,\n", 20918c2ecf20Sopenharmony_ci rate_n_flags, rx_status->band)) { 20928c2ecf20Sopenharmony_ci kfree_skb(skb); 20938c2ecf20Sopenharmony_ci goto out; 20948c2ecf20Sopenharmony_ci } 20958c2ecf20Sopenharmony_ci rx_status->rate_idx = rate; 20968c2ecf20Sopenharmony_ci } 20978c2ecf20Sopenharmony_ci 20988c2ecf20Sopenharmony_ci ieee80211_rx_napi(mvm->hw, sta, skb, napi); 20998c2ecf20Sopenharmony_ciout: 21008c2ecf20Sopenharmony_ci rcu_read_unlock(); 21018c2ecf20Sopenharmony_ci} 21028c2ecf20Sopenharmony_ci 21038c2ecf20Sopenharmony_civoid iwl_mvm_rx_frame_release(struct iwl_mvm *mvm, struct napi_struct *napi, 21048c2ecf20Sopenharmony_ci struct iwl_rx_cmd_buffer *rxb, int queue) 21058c2ecf20Sopenharmony_ci{ 21068c2ecf20Sopenharmony_ci struct iwl_rx_packet *pkt = rxb_addr(rxb); 21078c2ecf20Sopenharmony_ci struct iwl_frame_release *release = (void *)pkt->data; 21088c2ecf20Sopenharmony_ci 21098c2ecf20Sopenharmony_ci iwl_mvm_release_frames_from_notif(mvm, napi, release->baid, 21108c2ecf20Sopenharmony_ci le16_to_cpu(release->nssn), 21118c2ecf20Sopenharmony_ci queue, 0); 21128c2ecf20Sopenharmony_ci} 21138c2ecf20Sopenharmony_ci 21148c2ecf20Sopenharmony_civoid iwl_mvm_rx_bar_frame_release(struct iwl_mvm *mvm, struct napi_struct *napi, 21158c2ecf20Sopenharmony_ci struct iwl_rx_cmd_buffer *rxb, int queue) 21168c2ecf20Sopenharmony_ci{ 21178c2ecf20Sopenharmony_ci struct iwl_rx_packet *pkt = rxb_addr(rxb); 21188c2ecf20Sopenharmony_ci struct iwl_bar_frame_release *release = (void *)pkt->data; 21198c2ecf20Sopenharmony_ci unsigned int baid = le32_get_bits(release->ba_info, 21208c2ecf20Sopenharmony_ci IWL_BAR_FRAME_RELEASE_BAID_MASK); 21218c2ecf20Sopenharmony_ci unsigned int nssn = le32_get_bits(release->ba_info, 21228c2ecf20Sopenharmony_ci IWL_BAR_FRAME_RELEASE_NSSN_MASK); 21238c2ecf20Sopenharmony_ci unsigned int sta_id = le32_get_bits(release->sta_tid, 21248c2ecf20Sopenharmony_ci IWL_BAR_FRAME_RELEASE_STA_MASK); 21258c2ecf20Sopenharmony_ci unsigned int tid = le32_get_bits(release->sta_tid, 21268c2ecf20Sopenharmony_ci IWL_BAR_FRAME_RELEASE_TID_MASK); 21278c2ecf20Sopenharmony_ci struct iwl_mvm_baid_data *baid_data; 21288c2ecf20Sopenharmony_ci 21298c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(baid == IWL_RX_REORDER_DATA_INVALID_BAID || 21308c2ecf20Sopenharmony_ci baid >= ARRAY_SIZE(mvm->baid_map))) 21318c2ecf20Sopenharmony_ci return; 21328c2ecf20Sopenharmony_ci 21338c2ecf20Sopenharmony_ci rcu_read_lock(); 21348c2ecf20Sopenharmony_ci baid_data = rcu_dereference(mvm->baid_map[baid]); 21358c2ecf20Sopenharmony_ci if (!baid_data) { 21368c2ecf20Sopenharmony_ci IWL_DEBUG_RX(mvm, 21378c2ecf20Sopenharmony_ci "Got valid BAID %d but not allocated, invalid BAR release!\n", 21388c2ecf20Sopenharmony_ci baid); 21398c2ecf20Sopenharmony_ci goto out; 21408c2ecf20Sopenharmony_ci } 21418c2ecf20Sopenharmony_ci 21428c2ecf20Sopenharmony_ci if (WARN(tid != baid_data->tid || sta_id != baid_data->sta_id, 21438c2ecf20Sopenharmony_ci "baid 0x%x is mapped to sta:%d tid:%d, but BAR release received for sta:%d tid:%d\n", 21448c2ecf20Sopenharmony_ci baid, baid_data->sta_id, baid_data->tid, sta_id, 21458c2ecf20Sopenharmony_ci tid)) 21468c2ecf20Sopenharmony_ci goto out; 21478c2ecf20Sopenharmony_ci 21488c2ecf20Sopenharmony_ci iwl_mvm_release_frames_from_notif(mvm, napi, baid, nssn, queue, 0); 21498c2ecf20Sopenharmony_ciout: 21508c2ecf20Sopenharmony_ci rcu_read_unlock(); 21518c2ecf20Sopenharmony_ci} 2152