18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * NXP Wireless LAN device driver: 802.11n 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright 2011-2020 NXP 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * This software file (the "File") is distributed by NXP 78c2ecf20Sopenharmony_ci * under the terms of the GNU General Public License Version 2, June 1991 88c2ecf20Sopenharmony_ci * (the "License"). You may use, redistribute and/or modify this File in 98c2ecf20Sopenharmony_ci * accordance with the terms and conditions of the License, a copy of which 108c2ecf20Sopenharmony_ci * is available by writing to the Free Software Foundation, Inc., 118c2ecf20Sopenharmony_ci * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the 128c2ecf20Sopenharmony_ci * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 158c2ecf20Sopenharmony_ci * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 168c2ecf20Sopenharmony_ci * ARE EXPRESSLY DISCLAIMED. The License provides additional details about 178c2ecf20Sopenharmony_ci * this warranty disclaimer. 188c2ecf20Sopenharmony_ci */ 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include "decl.h" 218c2ecf20Sopenharmony_ci#include "ioctl.h" 228c2ecf20Sopenharmony_ci#include "util.h" 238c2ecf20Sopenharmony_ci#include "fw.h" 248c2ecf20Sopenharmony_ci#include "main.h" 258c2ecf20Sopenharmony_ci#include "wmm.h" 268c2ecf20Sopenharmony_ci#include "11n.h" 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci/* 298c2ecf20Sopenharmony_ci * Fills HT capability information field, AMPDU Parameters field, HT extended 308c2ecf20Sopenharmony_ci * capability field, and supported MCS set fields. 318c2ecf20Sopenharmony_ci * 328c2ecf20Sopenharmony_ci * HT capability information field, AMPDU Parameters field, supported MCS set 338c2ecf20Sopenharmony_ci * fields are retrieved from cfg80211 stack 348c2ecf20Sopenharmony_ci * 358c2ecf20Sopenharmony_ci * RD responder bit to set to clear in the extended capability header. 368c2ecf20Sopenharmony_ci */ 378c2ecf20Sopenharmony_ciint mwifiex_fill_cap_info(struct mwifiex_private *priv, u8 radio_type, 388c2ecf20Sopenharmony_ci struct ieee80211_ht_cap *ht_cap) 398c2ecf20Sopenharmony_ci{ 408c2ecf20Sopenharmony_ci uint16_t ht_ext_cap = le16_to_cpu(ht_cap->extended_ht_cap_info); 418c2ecf20Sopenharmony_ci struct ieee80211_supported_band *sband = 428c2ecf20Sopenharmony_ci priv->wdev.wiphy->bands[radio_type]; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(!sband)) { 458c2ecf20Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, "Invalid radio type!\n"); 468c2ecf20Sopenharmony_ci return -EINVAL; 478c2ecf20Sopenharmony_ci } 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci ht_cap->ampdu_params_info = 508c2ecf20Sopenharmony_ci (sband->ht_cap.ampdu_factor & 518c2ecf20Sopenharmony_ci IEEE80211_HT_AMPDU_PARM_FACTOR) | 528c2ecf20Sopenharmony_ci ((sband->ht_cap.ampdu_density << 538c2ecf20Sopenharmony_ci IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT) & 548c2ecf20Sopenharmony_ci IEEE80211_HT_AMPDU_PARM_DENSITY); 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci memcpy((u8 *)&ht_cap->mcs, &sband->ht_cap.mcs, 578c2ecf20Sopenharmony_ci sizeof(sband->ht_cap.mcs)); 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci if (priv->bss_mode == NL80211_IFTYPE_STATION || 608c2ecf20Sopenharmony_ci (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 && 618c2ecf20Sopenharmony_ci (priv->adapter->sec_chan_offset != 628c2ecf20Sopenharmony_ci IEEE80211_HT_PARAM_CHA_SEC_NONE))) 638c2ecf20Sopenharmony_ci /* Set MCS32 for infra mode or ad-hoc mode with 40MHz support */ 648c2ecf20Sopenharmony_ci SETHT_MCS32(ht_cap->mcs.rx_mask); 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci /* Clear RD responder bit */ 678c2ecf20Sopenharmony_ci ht_ext_cap &= ~IEEE80211_HT_EXT_CAP_RD_RESPONDER; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci ht_cap->cap_info = cpu_to_le16(sband->ht_cap.cap); 708c2ecf20Sopenharmony_ci ht_cap->extended_ht_cap_info = cpu_to_le16(ht_ext_cap); 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci if (ISSUPP_BEAMFORMING(priv->adapter->hw_dot_11n_dev_cap)) 738c2ecf20Sopenharmony_ci ht_cap->tx_BF_cap_info = cpu_to_le32(MWIFIEX_DEF_11N_TX_BF_CAP); 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci return 0; 768c2ecf20Sopenharmony_ci} 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci/* 798c2ecf20Sopenharmony_ci * This function returns the pointer to an entry in BA Stream 808c2ecf20Sopenharmony_ci * table which matches the requested BA status. 818c2ecf20Sopenharmony_ci */ 828c2ecf20Sopenharmony_cistatic struct mwifiex_tx_ba_stream_tbl * 838c2ecf20Sopenharmony_cimwifiex_get_ba_status(struct mwifiex_private *priv, 848c2ecf20Sopenharmony_ci enum mwifiex_ba_status ba_status) 858c2ecf20Sopenharmony_ci{ 868c2ecf20Sopenharmony_ci struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci spin_lock_bh(&priv->tx_ba_stream_tbl_lock); 898c2ecf20Sopenharmony_ci list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) { 908c2ecf20Sopenharmony_ci if (tx_ba_tsr_tbl->ba_status == ba_status) { 918c2ecf20Sopenharmony_ci spin_unlock_bh(&priv->tx_ba_stream_tbl_lock); 928c2ecf20Sopenharmony_ci return tx_ba_tsr_tbl; 938c2ecf20Sopenharmony_ci } 948c2ecf20Sopenharmony_ci } 958c2ecf20Sopenharmony_ci spin_unlock_bh(&priv->tx_ba_stream_tbl_lock); 968c2ecf20Sopenharmony_ci return NULL; 978c2ecf20Sopenharmony_ci} 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci/* 1008c2ecf20Sopenharmony_ci * This function handles the command response of delete a block 1018c2ecf20Sopenharmony_ci * ack request. 1028c2ecf20Sopenharmony_ci * 1038c2ecf20Sopenharmony_ci * The function checks the response success status and takes action 1048c2ecf20Sopenharmony_ci * accordingly (send an add BA request in case of success, or recreate 1058c2ecf20Sopenharmony_ci * the deleted stream in case of failure, if the add BA was also 1068c2ecf20Sopenharmony_ci * initiated by us). 1078c2ecf20Sopenharmony_ci */ 1088c2ecf20Sopenharmony_ciint mwifiex_ret_11n_delba(struct mwifiex_private *priv, 1098c2ecf20Sopenharmony_ci struct host_cmd_ds_command *resp) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci int tid; 1128c2ecf20Sopenharmony_ci struct mwifiex_tx_ba_stream_tbl *tx_ba_tbl; 1138c2ecf20Sopenharmony_ci struct host_cmd_ds_11n_delba *del_ba = &resp->params.del_ba; 1148c2ecf20Sopenharmony_ci uint16_t del_ba_param_set = le16_to_cpu(del_ba->del_ba_param_set); 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci tid = del_ba_param_set >> DELBA_TID_POS; 1178c2ecf20Sopenharmony_ci if (del_ba->del_result == BA_RESULT_SUCCESS) { 1188c2ecf20Sopenharmony_ci mwifiex_del_ba_tbl(priv, tid, del_ba->peer_mac_addr, 1198c2ecf20Sopenharmony_ci TYPE_DELBA_SENT, 1208c2ecf20Sopenharmony_ci INITIATOR_BIT(del_ba_param_set)); 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci tx_ba_tbl = mwifiex_get_ba_status(priv, BA_SETUP_INPROGRESS); 1238c2ecf20Sopenharmony_ci if (tx_ba_tbl) 1248c2ecf20Sopenharmony_ci mwifiex_send_addba(priv, tx_ba_tbl->tid, 1258c2ecf20Sopenharmony_ci tx_ba_tbl->ra); 1268c2ecf20Sopenharmony_ci } else { /* 1278c2ecf20Sopenharmony_ci * In case of failure, recreate the deleted stream in case 1288c2ecf20Sopenharmony_ci * we initiated the ADDBA 1298c2ecf20Sopenharmony_ci */ 1308c2ecf20Sopenharmony_ci if (!INITIATOR_BIT(del_ba_param_set)) 1318c2ecf20Sopenharmony_ci return 0; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci mwifiex_create_ba_tbl(priv, del_ba->peer_mac_addr, tid, 1348c2ecf20Sopenharmony_ci BA_SETUP_INPROGRESS); 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci tx_ba_tbl = mwifiex_get_ba_status(priv, BA_SETUP_INPROGRESS); 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci if (tx_ba_tbl) 1398c2ecf20Sopenharmony_ci mwifiex_del_ba_tbl(priv, tx_ba_tbl->tid, tx_ba_tbl->ra, 1408c2ecf20Sopenharmony_ci TYPE_DELBA_SENT, true); 1418c2ecf20Sopenharmony_ci } 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci return 0; 1448c2ecf20Sopenharmony_ci} 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci/* 1478c2ecf20Sopenharmony_ci * This function handles the command response of add a block 1488c2ecf20Sopenharmony_ci * ack request. 1498c2ecf20Sopenharmony_ci * 1508c2ecf20Sopenharmony_ci * Handling includes changing the header fields to CPU formats, checking 1518c2ecf20Sopenharmony_ci * the response success status and taking actions accordingly (delete the 1528c2ecf20Sopenharmony_ci * BA stream table in case of failure). 1538c2ecf20Sopenharmony_ci */ 1548c2ecf20Sopenharmony_ciint mwifiex_ret_11n_addba_req(struct mwifiex_private *priv, 1558c2ecf20Sopenharmony_ci struct host_cmd_ds_command *resp) 1568c2ecf20Sopenharmony_ci{ 1578c2ecf20Sopenharmony_ci int tid, tid_down; 1588c2ecf20Sopenharmony_ci struct host_cmd_ds_11n_addba_rsp *add_ba_rsp = &resp->params.add_ba_rsp; 1598c2ecf20Sopenharmony_ci struct mwifiex_tx_ba_stream_tbl *tx_ba_tbl; 1608c2ecf20Sopenharmony_ci struct mwifiex_ra_list_tbl *ra_list; 1618c2ecf20Sopenharmony_ci u16 block_ack_param_set = le16_to_cpu(add_ba_rsp->block_ack_param_set); 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci add_ba_rsp->ssn = cpu_to_le16((le16_to_cpu(add_ba_rsp->ssn)) 1648c2ecf20Sopenharmony_ci & SSN_MASK); 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci tid = (block_ack_param_set & IEEE80211_ADDBA_PARAM_TID_MASK) 1678c2ecf20Sopenharmony_ci >> BLOCKACKPARAM_TID_POS; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci tid_down = mwifiex_wmm_downgrade_tid(priv, tid); 1708c2ecf20Sopenharmony_ci ra_list = mwifiex_wmm_get_ralist_node(priv, tid_down, add_ba_rsp-> 1718c2ecf20Sopenharmony_ci peer_mac_addr); 1728c2ecf20Sopenharmony_ci if (le16_to_cpu(add_ba_rsp->status_code) != BA_RESULT_SUCCESS) { 1738c2ecf20Sopenharmony_ci if (ra_list) { 1748c2ecf20Sopenharmony_ci ra_list->ba_status = BA_SETUP_NONE; 1758c2ecf20Sopenharmony_ci ra_list->amsdu_in_ampdu = false; 1768c2ecf20Sopenharmony_ci } 1778c2ecf20Sopenharmony_ci mwifiex_del_ba_tbl(priv, tid, add_ba_rsp->peer_mac_addr, 1788c2ecf20Sopenharmony_ci TYPE_DELBA_SENT, true); 1798c2ecf20Sopenharmony_ci if (add_ba_rsp->add_rsp_result != BA_RESULT_TIMEOUT) 1808c2ecf20Sopenharmony_ci priv->aggr_prio_tbl[tid].ampdu_ap = 1818c2ecf20Sopenharmony_ci BA_STREAM_NOT_ALLOWED; 1828c2ecf20Sopenharmony_ci return 0; 1838c2ecf20Sopenharmony_ci } 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci tx_ba_tbl = mwifiex_get_ba_tbl(priv, tid, add_ba_rsp->peer_mac_addr); 1868c2ecf20Sopenharmony_ci if (tx_ba_tbl) { 1878c2ecf20Sopenharmony_ci mwifiex_dbg(priv->adapter, EVENT, "info: BA stream complete\n"); 1888c2ecf20Sopenharmony_ci tx_ba_tbl->ba_status = BA_SETUP_COMPLETE; 1898c2ecf20Sopenharmony_ci if ((block_ack_param_set & BLOCKACKPARAM_AMSDU_SUPP_MASK) && 1908c2ecf20Sopenharmony_ci priv->add_ba_param.tx_amsdu && 1918c2ecf20Sopenharmony_ci (priv->aggr_prio_tbl[tid].amsdu != BA_STREAM_NOT_ALLOWED)) 1928c2ecf20Sopenharmony_ci tx_ba_tbl->amsdu = true; 1938c2ecf20Sopenharmony_ci else 1948c2ecf20Sopenharmony_ci tx_ba_tbl->amsdu = false; 1958c2ecf20Sopenharmony_ci if (ra_list) { 1968c2ecf20Sopenharmony_ci ra_list->amsdu_in_ampdu = tx_ba_tbl->amsdu; 1978c2ecf20Sopenharmony_ci ra_list->ba_status = BA_SETUP_COMPLETE; 1988c2ecf20Sopenharmony_ci } 1998c2ecf20Sopenharmony_ci } else { 2008c2ecf20Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, "BA stream not created\n"); 2018c2ecf20Sopenharmony_ci } 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci return 0; 2048c2ecf20Sopenharmony_ci} 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci/* 2078c2ecf20Sopenharmony_ci * This function prepares command of reconfigure Tx buffer. 2088c2ecf20Sopenharmony_ci * 2098c2ecf20Sopenharmony_ci * Preparation includes - 2108c2ecf20Sopenharmony_ci * - Setting command ID, action and proper size 2118c2ecf20Sopenharmony_ci * - Setting Tx buffer size (for SET only) 2128c2ecf20Sopenharmony_ci * - Ensuring correct endian-ness 2138c2ecf20Sopenharmony_ci */ 2148c2ecf20Sopenharmony_ciint mwifiex_cmd_recfg_tx_buf(struct mwifiex_private *priv, 2158c2ecf20Sopenharmony_ci struct host_cmd_ds_command *cmd, int cmd_action, 2168c2ecf20Sopenharmony_ci u16 *buf_size) 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci struct host_cmd_ds_txbuf_cfg *tx_buf = &cmd->params.tx_buf; 2198c2ecf20Sopenharmony_ci u16 action = (u16) cmd_action; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci cmd->command = cpu_to_le16(HostCmd_CMD_RECONFIGURE_TX_BUFF); 2228c2ecf20Sopenharmony_ci cmd->size = 2238c2ecf20Sopenharmony_ci cpu_to_le16(sizeof(struct host_cmd_ds_txbuf_cfg) + S_DS_GEN); 2248c2ecf20Sopenharmony_ci tx_buf->action = cpu_to_le16(action); 2258c2ecf20Sopenharmony_ci switch (action) { 2268c2ecf20Sopenharmony_ci case HostCmd_ACT_GEN_SET: 2278c2ecf20Sopenharmony_ci mwifiex_dbg(priv->adapter, CMD, 2288c2ecf20Sopenharmony_ci "cmd: set tx_buf=%d\n", *buf_size); 2298c2ecf20Sopenharmony_ci tx_buf->buff_size = cpu_to_le16(*buf_size); 2308c2ecf20Sopenharmony_ci break; 2318c2ecf20Sopenharmony_ci case HostCmd_ACT_GEN_GET: 2328c2ecf20Sopenharmony_ci default: 2338c2ecf20Sopenharmony_ci tx_buf->buff_size = 0; 2348c2ecf20Sopenharmony_ci break; 2358c2ecf20Sopenharmony_ci } 2368c2ecf20Sopenharmony_ci return 0; 2378c2ecf20Sopenharmony_ci} 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci/* 2408c2ecf20Sopenharmony_ci * This function prepares command of AMSDU aggregation control. 2418c2ecf20Sopenharmony_ci * 2428c2ecf20Sopenharmony_ci * Preparation includes - 2438c2ecf20Sopenharmony_ci * - Setting command ID, action and proper size 2448c2ecf20Sopenharmony_ci * - Setting AMSDU control parameters (for SET only) 2458c2ecf20Sopenharmony_ci * - Ensuring correct endian-ness 2468c2ecf20Sopenharmony_ci */ 2478c2ecf20Sopenharmony_ciint mwifiex_cmd_amsdu_aggr_ctrl(struct host_cmd_ds_command *cmd, 2488c2ecf20Sopenharmony_ci int cmd_action, 2498c2ecf20Sopenharmony_ci struct mwifiex_ds_11n_amsdu_aggr_ctrl *aa_ctrl) 2508c2ecf20Sopenharmony_ci{ 2518c2ecf20Sopenharmony_ci struct host_cmd_ds_amsdu_aggr_ctrl *amsdu_ctrl = 2528c2ecf20Sopenharmony_ci &cmd->params.amsdu_aggr_ctrl; 2538c2ecf20Sopenharmony_ci u16 action = (u16) cmd_action; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci cmd->command = cpu_to_le16(HostCmd_CMD_AMSDU_AGGR_CTRL); 2568c2ecf20Sopenharmony_ci cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_amsdu_aggr_ctrl) 2578c2ecf20Sopenharmony_ci + S_DS_GEN); 2588c2ecf20Sopenharmony_ci amsdu_ctrl->action = cpu_to_le16(action); 2598c2ecf20Sopenharmony_ci switch (action) { 2608c2ecf20Sopenharmony_ci case HostCmd_ACT_GEN_SET: 2618c2ecf20Sopenharmony_ci amsdu_ctrl->enable = cpu_to_le16(aa_ctrl->enable); 2628c2ecf20Sopenharmony_ci amsdu_ctrl->curr_buf_size = 0; 2638c2ecf20Sopenharmony_ci break; 2648c2ecf20Sopenharmony_ci case HostCmd_ACT_GEN_GET: 2658c2ecf20Sopenharmony_ci default: 2668c2ecf20Sopenharmony_ci amsdu_ctrl->curr_buf_size = 0; 2678c2ecf20Sopenharmony_ci break; 2688c2ecf20Sopenharmony_ci } 2698c2ecf20Sopenharmony_ci return 0; 2708c2ecf20Sopenharmony_ci} 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci/* 2738c2ecf20Sopenharmony_ci * This function prepares 11n configuration command. 2748c2ecf20Sopenharmony_ci * 2758c2ecf20Sopenharmony_ci * Preparation includes - 2768c2ecf20Sopenharmony_ci * - Setting command ID, action and proper size 2778c2ecf20Sopenharmony_ci * - Setting HT Tx capability and HT Tx information fields 2788c2ecf20Sopenharmony_ci * - Ensuring correct endian-ness 2798c2ecf20Sopenharmony_ci */ 2808c2ecf20Sopenharmony_ciint mwifiex_cmd_11n_cfg(struct mwifiex_private *priv, 2818c2ecf20Sopenharmony_ci struct host_cmd_ds_command *cmd, u16 cmd_action, 2828c2ecf20Sopenharmony_ci struct mwifiex_ds_11n_tx_cfg *txcfg) 2838c2ecf20Sopenharmony_ci{ 2848c2ecf20Sopenharmony_ci struct host_cmd_ds_11n_cfg *htcfg = &cmd->params.htcfg; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci cmd->command = cpu_to_le16(HostCmd_CMD_11N_CFG); 2878c2ecf20Sopenharmony_ci cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_11n_cfg) + S_DS_GEN); 2888c2ecf20Sopenharmony_ci htcfg->action = cpu_to_le16(cmd_action); 2898c2ecf20Sopenharmony_ci htcfg->ht_tx_cap = cpu_to_le16(txcfg->tx_htcap); 2908c2ecf20Sopenharmony_ci htcfg->ht_tx_info = cpu_to_le16(txcfg->tx_htinfo); 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci if (priv->adapter->is_hw_11ac_capable) 2938c2ecf20Sopenharmony_ci htcfg->misc_config = cpu_to_le16(txcfg->misc_config); 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci return 0; 2968c2ecf20Sopenharmony_ci} 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci/* 2998c2ecf20Sopenharmony_ci * This function appends an 11n TLV to a buffer. 3008c2ecf20Sopenharmony_ci * 3018c2ecf20Sopenharmony_ci * Buffer allocation is responsibility of the calling 3028c2ecf20Sopenharmony_ci * function. No size validation is made here. 3038c2ecf20Sopenharmony_ci * 3048c2ecf20Sopenharmony_ci * The function fills up the following sections, if applicable - 3058c2ecf20Sopenharmony_ci * - HT capability IE 3068c2ecf20Sopenharmony_ci * - HT information IE (with channel list) 3078c2ecf20Sopenharmony_ci * - 20/40 BSS Coexistence IE 3088c2ecf20Sopenharmony_ci * - HT Extended Capabilities IE 3098c2ecf20Sopenharmony_ci */ 3108c2ecf20Sopenharmony_ciint 3118c2ecf20Sopenharmony_cimwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv, 3128c2ecf20Sopenharmony_ci struct mwifiex_bssdescriptor *bss_desc, 3138c2ecf20Sopenharmony_ci u8 **buffer) 3148c2ecf20Sopenharmony_ci{ 3158c2ecf20Sopenharmony_ci struct mwifiex_ie_types_htcap *ht_cap; 3168c2ecf20Sopenharmony_ci struct mwifiex_ie_types_htinfo *ht_info; 3178c2ecf20Sopenharmony_ci struct mwifiex_ie_types_chan_list_param_set *chan_list; 3188c2ecf20Sopenharmony_ci struct mwifiex_ie_types_2040bssco *bss_co_2040; 3198c2ecf20Sopenharmony_ci struct mwifiex_ie_types_extcap *ext_cap; 3208c2ecf20Sopenharmony_ci int ret_len = 0; 3218c2ecf20Sopenharmony_ci struct ieee80211_supported_band *sband; 3228c2ecf20Sopenharmony_ci struct ieee_types_header *hdr; 3238c2ecf20Sopenharmony_ci u8 radio_type; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci if (!buffer || !*buffer) 3268c2ecf20Sopenharmony_ci return ret_len; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci radio_type = mwifiex_band_to_radio_type((u8) bss_desc->bss_band); 3298c2ecf20Sopenharmony_ci sband = priv->wdev.wiphy->bands[radio_type]; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci if (bss_desc->bcn_ht_cap) { 3328c2ecf20Sopenharmony_ci ht_cap = (struct mwifiex_ie_types_htcap *) *buffer; 3338c2ecf20Sopenharmony_ci memset(ht_cap, 0, sizeof(struct mwifiex_ie_types_htcap)); 3348c2ecf20Sopenharmony_ci ht_cap->header.type = cpu_to_le16(WLAN_EID_HT_CAPABILITY); 3358c2ecf20Sopenharmony_ci ht_cap->header.len = 3368c2ecf20Sopenharmony_ci cpu_to_le16(sizeof(struct ieee80211_ht_cap)); 3378c2ecf20Sopenharmony_ci memcpy((u8 *) ht_cap + sizeof(struct mwifiex_ie_types_header), 3388c2ecf20Sopenharmony_ci (u8 *)bss_desc->bcn_ht_cap, 3398c2ecf20Sopenharmony_ci le16_to_cpu(ht_cap->header.len)); 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci mwifiex_fill_cap_info(priv, radio_type, &ht_cap->ht_cap); 3428c2ecf20Sopenharmony_ci /* Update HT40 capability from current channel information */ 3438c2ecf20Sopenharmony_ci if (bss_desc->bcn_ht_oper) { 3448c2ecf20Sopenharmony_ci u8 ht_param = bss_desc->bcn_ht_oper->ht_param; 3458c2ecf20Sopenharmony_ci u8 radio = 3468c2ecf20Sopenharmony_ci mwifiex_band_to_radio_type(bss_desc->bss_band); 3478c2ecf20Sopenharmony_ci int freq = 3488c2ecf20Sopenharmony_ci ieee80211_channel_to_frequency(bss_desc->channel, 3498c2ecf20Sopenharmony_ci radio); 3508c2ecf20Sopenharmony_ci struct ieee80211_channel *chan = 3518c2ecf20Sopenharmony_ci ieee80211_get_channel(priv->adapter->wiphy, freq); 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci switch (ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { 3548c2ecf20Sopenharmony_ci case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: 3558c2ecf20Sopenharmony_ci if (chan->flags & IEEE80211_CHAN_NO_HT40PLUS) { 3568c2ecf20Sopenharmony_ci ht_cap->ht_cap.cap_info &= 3578c2ecf20Sopenharmony_ci cpu_to_le16 3588c2ecf20Sopenharmony_ci (~IEEE80211_HT_CAP_SUP_WIDTH_20_40); 3598c2ecf20Sopenharmony_ci ht_cap->ht_cap.cap_info &= 3608c2ecf20Sopenharmony_ci cpu_to_le16(~IEEE80211_HT_CAP_SGI_40); 3618c2ecf20Sopenharmony_ci } 3628c2ecf20Sopenharmony_ci break; 3638c2ecf20Sopenharmony_ci case IEEE80211_HT_PARAM_CHA_SEC_BELOW: 3648c2ecf20Sopenharmony_ci if (chan->flags & IEEE80211_CHAN_NO_HT40MINUS) { 3658c2ecf20Sopenharmony_ci ht_cap->ht_cap.cap_info &= 3668c2ecf20Sopenharmony_ci cpu_to_le16 3678c2ecf20Sopenharmony_ci (~IEEE80211_HT_CAP_SUP_WIDTH_20_40); 3688c2ecf20Sopenharmony_ci ht_cap->ht_cap.cap_info &= 3698c2ecf20Sopenharmony_ci cpu_to_le16(~IEEE80211_HT_CAP_SGI_40); 3708c2ecf20Sopenharmony_ci } 3718c2ecf20Sopenharmony_ci break; 3728c2ecf20Sopenharmony_ci } 3738c2ecf20Sopenharmony_ci } 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci *buffer += sizeof(struct mwifiex_ie_types_htcap); 3768c2ecf20Sopenharmony_ci ret_len += sizeof(struct mwifiex_ie_types_htcap); 3778c2ecf20Sopenharmony_ci } 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci if (bss_desc->bcn_ht_oper) { 3808c2ecf20Sopenharmony_ci if (priv->bss_mode == NL80211_IFTYPE_ADHOC) { 3818c2ecf20Sopenharmony_ci ht_info = (struct mwifiex_ie_types_htinfo *) *buffer; 3828c2ecf20Sopenharmony_ci memset(ht_info, 0, 3838c2ecf20Sopenharmony_ci sizeof(struct mwifiex_ie_types_htinfo)); 3848c2ecf20Sopenharmony_ci ht_info->header.type = 3858c2ecf20Sopenharmony_ci cpu_to_le16(WLAN_EID_HT_OPERATION); 3868c2ecf20Sopenharmony_ci ht_info->header.len = 3878c2ecf20Sopenharmony_ci cpu_to_le16( 3888c2ecf20Sopenharmony_ci sizeof(struct ieee80211_ht_operation)); 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci memcpy((u8 *) ht_info + 3918c2ecf20Sopenharmony_ci sizeof(struct mwifiex_ie_types_header), 3928c2ecf20Sopenharmony_ci (u8 *)bss_desc->bcn_ht_oper, 3938c2ecf20Sopenharmony_ci le16_to_cpu(ht_info->header.len)); 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci if (!(sband->ht_cap.cap & 3968c2ecf20Sopenharmony_ci IEEE80211_HT_CAP_SUP_WIDTH_20_40)) 3978c2ecf20Sopenharmony_ci ht_info->ht_oper.ht_param &= 3988c2ecf20Sopenharmony_ci ~(IEEE80211_HT_PARAM_CHAN_WIDTH_ANY | 3998c2ecf20Sopenharmony_ci IEEE80211_HT_PARAM_CHA_SEC_OFFSET); 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci *buffer += sizeof(struct mwifiex_ie_types_htinfo); 4028c2ecf20Sopenharmony_ci ret_len += sizeof(struct mwifiex_ie_types_htinfo); 4038c2ecf20Sopenharmony_ci } 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci chan_list = 4068c2ecf20Sopenharmony_ci (struct mwifiex_ie_types_chan_list_param_set *) *buffer; 4078c2ecf20Sopenharmony_ci memset(chan_list, 0, 4088c2ecf20Sopenharmony_ci sizeof(struct mwifiex_ie_types_chan_list_param_set)); 4098c2ecf20Sopenharmony_ci chan_list->header.type = cpu_to_le16(TLV_TYPE_CHANLIST); 4108c2ecf20Sopenharmony_ci chan_list->header.len = cpu_to_le16( 4118c2ecf20Sopenharmony_ci sizeof(struct mwifiex_ie_types_chan_list_param_set) - 4128c2ecf20Sopenharmony_ci sizeof(struct mwifiex_ie_types_header)); 4138c2ecf20Sopenharmony_ci chan_list->chan_scan_param[0].chan_number = 4148c2ecf20Sopenharmony_ci bss_desc->bcn_ht_oper->primary_chan; 4158c2ecf20Sopenharmony_ci chan_list->chan_scan_param[0].radio_type = 4168c2ecf20Sopenharmony_ci mwifiex_band_to_radio_type((u8) bss_desc->bss_band); 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci if (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 && 4198c2ecf20Sopenharmony_ci bss_desc->bcn_ht_oper->ht_param & 4208c2ecf20Sopenharmony_ci IEEE80211_HT_PARAM_CHAN_WIDTH_ANY) 4218c2ecf20Sopenharmony_ci SET_SECONDARYCHAN(chan_list->chan_scan_param[0]. 4228c2ecf20Sopenharmony_ci radio_type, 4238c2ecf20Sopenharmony_ci (bss_desc->bcn_ht_oper->ht_param & 4248c2ecf20Sopenharmony_ci IEEE80211_HT_PARAM_CHA_SEC_OFFSET)); 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci *buffer += sizeof(struct mwifiex_ie_types_chan_list_param_set); 4278c2ecf20Sopenharmony_ci ret_len += sizeof(struct mwifiex_ie_types_chan_list_param_set); 4288c2ecf20Sopenharmony_ci } 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci if (bss_desc->bcn_bss_co_2040) { 4318c2ecf20Sopenharmony_ci bss_co_2040 = (struct mwifiex_ie_types_2040bssco *) *buffer; 4328c2ecf20Sopenharmony_ci memset(bss_co_2040, 0, 4338c2ecf20Sopenharmony_ci sizeof(struct mwifiex_ie_types_2040bssco)); 4348c2ecf20Sopenharmony_ci bss_co_2040->header.type = cpu_to_le16(WLAN_EID_BSS_COEX_2040); 4358c2ecf20Sopenharmony_ci bss_co_2040->header.len = 4368c2ecf20Sopenharmony_ci cpu_to_le16(sizeof(bss_co_2040->bss_co_2040)); 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci memcpy((u8 *) bss_co_2040 + 4398c2ecf20Sopenharmony_ci sizeof(struct mwifiex_ie_types_header), 4408c2ecf20Sopenharmony_ci bss_desc->bcn_bss_co_2040 + 4418c2ecf20Sopenharmony_ci sizeof(struct ieee_types_header), 4428c2ecf20Sopenharmony_ci le16_to_cpu(bss_co_2040->header.len)); 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci *buffer += sizeof(struct mwifiex_ie_types_2040bssco); 4458c2ecf20Sopenharmony_ci ret_len += sizeof(struct mwifiex_ie_types_2040bssco); 4468c2ecf20Sopenharmony_ci } 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci if (bss_desc->bcn_ext_cap) { 4498c2ecf20Sopenharmony_ci hdr = (void *)bss_desc->bcn_ext_cap; 4508c2ecf20Sopenharmony_ci ext_cap = (struct mwifiex_ie_types_extcap *) *buffer; 4518c2ecf20Sopenharmony_ci memset(ext_cap, 0, sizeof(struct mwifiex_ie_types_extcap)); 4528c2ecf20Sopenharmony_ci ext_cap->header.type = cpu_to_le16(WLAN_EID_EXT_CAPABILITY); 4538c2ecf20Sopenharmony_ci ext_cap->header.len = cpu_to_le16(hdr->len); 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci memcpy((u8 *)ext_cap->ext_capab, 4568c2ecf20Sopenharmony_ci bss_desc->bcn_ext_cap + sizeof(struct ieee_types_header), 4578c2ecf20Sopenharmony_ci le16_to_cpu(ext_cap->header.len)); 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci if (hdr->len > 3 && 4608c2ecf20Sopenharmony_ci ext_cap->ext_capab[3] & WLAN_EXT_CAPA4_INTERWORKING_ENABLED) 4618c2ecf20Sopenharmony_ci priv->hs2_enabled = true; 4628c2ecf20Sopenharmony_ci else 4638c2ecf20Sopenharmony_ci priv->hs2_enabled = false; 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci *buffer += sizeof(struct mwifiex_ie_types_extcap) + hdr->len; 4668c2ecf20Sopenharmony_ci ret_len += sizeof(struct mwifiex_ie_types_extcap) + hdr->len; 4678c2ecf20Sopenharmony_ci } 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci return ret_len; 4708c2ecf20Sopenharmony_ci} 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci/* 4738c2ecf20Sopenharmony_ci * This function checks if the given pointer is valid entry of 4748c2ecf20Sopenharmony_ci * Tx BA Stream table. 4758c2ecf20Sopenharmony_ci */ 4768c2ecf20Sopenharmony_cistatic int mwifiex_is_tx_ba_stream_ptr_valid(struct mwifiex_private *priv, 4778c2ecf20Sopenharmony_ci struct mwifiex_tx_ba_stream_tbl *tx_tbl_ptr) 4788c2ecf20Sopenharmony_ci{ 4798c2ecf20Sopenharmony_ci struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl; 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) { 4828c2ecf20Sopenharmony_ci if (tx_ba_tsr_tbl == tx_tbl_ptr) 4838c2ecf20Sopenharmony_ci return true; 4848c2ecf20Sopenharmony_ci } 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci return false; 4878c2ecf20Sopenharmony_ci} 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci/* 4908c2ecf20Sopenharmony_ci * This function deletes the given entry in Tx BA Stream table. 4918c2ecf20Sopenharmony_ci * 4928c2ecf20Sopenharmony_ci * The function also performs a validity check on the supplied 4938c2ecf20Sopenharmony_ci * pointer before trying to delete. 4948c2ecf20Sopenharmony_ci */ 4958c2ecf20Sopenharmony_civoid mwifiex_11n_delete_tx_ba_stream_tbl_entry(struct mwifiex_private *priv, 4968c2ecf20Sopenharmony_ci struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl) 4978c2ecf20Sopenharmony_ci{ 4988c2ecf20Sopenharmony_ci if (!tx_ba_tsr_tbl && 4998c2ecf20Sopenharmony_ci mwifiex_is_tx_ba_stream_ptr_valid(priv, tx_ba_tsr_tbl)) 5008c2ecf20Sopenharmony_ci return; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci mwifiex_dbg(priv->adapter, INFO, 5038c2ecf20Sopenharmony_ci "info: tx_ba_tsr_tbl %p\n", tx_ba_tsr_tbl); 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci list_del(&tx_ba_tsr_tbl->list); 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci kfree(tx_ba_tsr_tbl); 5088c2ecf20Sopenharmony_ci} 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci/* 5118c2ecf20Sopenharmony_ci * This function deletes all the entries in Tx BA Stream table. 5128c2ecf20Sopenharmony_ci */ 5138c2ecf20Sopenharmony_civoid mwifiex_11n_delete_all_tx_ba_stream_tbl(struct mwifiex_private *priv) 5148c2ecf20Sopenharmony_ci{ 5158c2ecf20Sopenharmony_ci int i; 5168c2ecf20Sopenharmony_ci struct mwifiex_tx_ba_stream_tbl *del_tbl_ptr, *tmp_node; 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci spin_lock_bh(&priv->tx_ba_stream_tbl_lock); 5198c2ecf20Sopenharmony_ci list_for_each_entry_safe(del_tbl_ptr, tmp_node, 5208c2ecf20Sopenharmony_ci &priv->tx_ba_stream_tbl_ptr, list) 5218c2ecf20Sopenharmony_ci mwifiex_11n_delete_tx_ba_stream_tbl_entry(priv, del_tbl_ptr); 5228c2ecf20Sopenharmony_ci spin_unlock_bh(&priv->tx_ba_stream_tbl_lock); 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&priv->tx_ba_stream_tbl_ptr); 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci for (i = 0; i < MAX_NUM_TID; ++i) 5278c2ecf20Sopenharmony_ci priv->aggr_prio_tbl[i].ampdu_ap = 5288c2ecf20Sopenharmony_ci priv->aggr_prio_tbl[i].ampdu_user; 5298c2ecf20Sopenharmony_ci} 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci/* 5328c2ecf20Sopenharmony_ci * This function returns the pointer to an entry in BA Stream 5338c2ecf20Sopenharmony_ci * table which matches the given RA/TID pair. 5348c2ecf20Sopenharmony_ci */ 5358c2ecf20Sopenharmony_cistruct mwifiex_tx_ba_stream_tbl * 5368c2ecf20Sopenharmony_cimwifiex_get_ba_tbl(struct mwifiex_private *priv, int tid, u8 *ra) 5378c2ecf20Sopenharmony_ci{ 5388c2ecf20Sopenharmony_ci struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl; 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci spin_lock_bh(&priv->tx_ba_stream_tbl_lock); 5418c2ecf20Sopenharmony_ci list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) { 5428c2ecf20Sopenharmony_ci if (ether_addr_equal_unaligned(tx_ba_tsr_tbl->ra, ra) && 5438c2ecf20Sopenharmony_ci tx_ba_tsr_tbl->tid == tid) { 5448c2ecf20Sopenharmony_ci spin_unlock_bh(&priv->tx_ba_stream_tbl_lock); 5458c2ecf20Sopenharmony_ci return tx_ba_tsr_tbl; 5468c2ecf20Sopenharmony_ci } 5478c2ecf20Sopenharmony_ci } 5488c2ecf20Sopenharmony_ci spin_unlock_bh(&priv->tx_ba_stream_tbl_lock); 5498c2ecf20Sopenharmony_ci return NULL; 5508c2ecf20Sopenharmony_ci} 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci/* 5538c2ecf20Sopenharmony_ci * This function creates an entry in Tx BA stream table for the 5548c2ecf20Sopenharmony_ci * given RA/TID pair. 5558c2ecf20Sopenharmony_ci */ 5568c2ecf20Sopenharmony_civoid mwifiex_create_ba_tbl(struct mwifiex_private *priv, u8 *ra, int tid, 5578c2ecf20Sopenharmony_ci enum mwifiex_ba_status ba_status) 5588c2ecf20Sopenharmony_ci{ 5598c2ecf20Sopenharmony_ci struct mwifiex_tx_ba_stream_tbl *new_node; 5608c2ecf20Sopenharmony_ci struct mwifiex_ra_list_tbl *ra_list; 5618c2ecf20Sopenharmony_ci int tid_down; 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci if (!mwifiex_get_ba_tbl(priv, tid, ra)) { 5648c2ecf20Sopenharmony_ci new_node = kzalloc(sizeof(struct mwifiex_tx_ba_stream_tbl), 5658c2ecf20Sopenharmony_ci GFP_ATOMIC); 5668c2ecf20Sopenharmony_ci if (!new_node) 5678c2ecf20Sopenharmony_ci return; 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci tid_down = mwifiex_wmm_downgrade_tid(priv, tid); 5708c2ecf20Sopenharmony_ci ra_list = mwifiex_wmm_get_ralist_node(priv, tid_down, ra); 5718c2ecf20Sopenharmony_ci if (ra_list) { 5728c2ecf20Sopenharmony_ci ra_list->ba_status = ba_status; 5738c2ecf20Sopenharmony_ci ra_list->amsdu_in_ampdu = false; 5748c2ecf20Sopenharmony_ci } 5758c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&new_node->list); 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci new_node->tid = tid; 5788c2ecf20Sopenharmony_ci new_node->ba_status = ba_status; 5798c2ecf20Sopenharmony_ci memcpy(new_node->ra, ra, ETH_ALEN); 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci spin_lock_bh(&priv->tx_ba_stream_tbl_lock); 5828c2ecf20Sopenharmony_ci list_add_tail(&new_node->list, &priv->tx_ba_stream_tbl_ptr); 5838c2ecf20Sopenharmony_ci spin_unlock_bh(&priv->tx_ba_stream_tbl_lock); 5848c2ecf20Sopenharmony_ci } 5858c2ecf20Sopenharmony_ci} 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci/* 5888c2ecf20Sopenharmony_ci * This function sends an add BA request to the given TID/RA pair. 5898c2ecf20Sopenharmony_ci */ 5908c2ecf20Sopenharmony_ciint mwifiex_send_addba(struct mwifiex_private *priv, int tid, u8 *peer_mac) 5918c2ecf20Sopenharmony_ci{ 5928c2ecf20Sopenharmony_ci struct host_cmd_ds_11n_addba_req add_ba_req; 5938c2ecf20Sopenharmony_ci u32 tx_win_size = priv->add_ba_param.tx_win_size; 5948c2ecf20Sopenharmony_ci static u8 dialog_tok; 5958c2ecf20Sopenharmony_ci int ret; 5968c2ecf20Sopenharmony_ci u16 block_ack_param_set; 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci mwifiex_dbg(priv->adapter, CMD, "cmd: %s: tid %d\n", __func__, tid); 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci memset(&add_ba_req, 0, sizeof(add_ba_req)); 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) && 6038c2ecf20Sopenharmony_ci ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info) && 6048c2ecf20Sopenharmony_ci priv->adapter->is_hw_11ac_capable && 6058c2ecf20Sopenharmony_ci memcmp(priv->cfg_bssid, peer_mac, ETH_ALEN)) { 6068c2ecf20Sopenharmony_ci struct mwifiex_sta_node *sta_ptr; 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci spin_lock_bh(&priv->sta_list_spinlock); 6098c2ecf20Sopenharmony_ci sta_ptr = mwifiex_get_sta_entry(priv, peer_mac); 6108c2ecf20Sopenharmony_ci if (!sta_ptr) { 6118c2ecf20Sopenharmony_ci spin_unlock_bh(&priv->sta_list_spinlock); 6128c2ecf20Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 6138c2ecf20Sopenharmony_ci "BA setup with unknown TDLS peer %pM!\n", 6148c2ecf20Sopenharmony_ci peer_mac); 6158c2ecf20Sopenharmony_ci return -1; 6168c2ecf20Sopenharmony_ci } 6178c2ecf20Sopenharmony_ci if (sta_ptr->is_11ac_enabled) 6188c2ecf20Sopenharmony_ci tx_win_size = MWIFIEX_11AC_STA_AMPDU_DEF_TXWINSIZE; 6198c2ecf20Sopenharmony_ci spin_unlock_bh(&priv->sta_list_spinlock); 6208c2ecf20Sopenharmony_ci } 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci block_ack_param_set = (u16)((tid << BLOCKACKPARAM_TID_POS) | 6238c2ecf20Sopenharmony_ci tx_win_size << BLOCKACKPARAM_WINSIZE_POS | 6248c2ecf20Sopenharmony_ci IMMEDIATE_BLOCK_ACK); 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci /* enable AMSDU inside AMPDU */ 6278c2ecf20Sopenharmony_ci if (priv->add_ba_param.tx_amsdu && 6288c2ecf20Sopenharmony_ci (priv->aggr_prio_tbl[tid].amsdu != BA_STREAM_NOT_ALLOWED)) 6298c2ecf20Sopenharmony_ci block_ack_param_set |= BLOCKACKPARAM_AMSDU_SUPP_MASK; 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci add_ba_req.block_ack_param_set = cpu_to_le16(block_ack_param_set); 6328c2ecf20Sopenharmony_ci add_ba_req.block_ack_tmo = cpu_to_le16((u16)priv->add_ba_param.timeout); 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci ++dialog_tok; 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci if (dialog_tok == 0) 6378c2ecf20Sopenharmony_ci dialog_tok = 1; 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci add_ba_req.dialog_token = dialog_tok; 6408c2ecf20Sopenharmony_ci memcpy(&add_ba_req.peer_mac_addr, peer_mac, ETH_ALEN); 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci /* We don't wait for the response of this command */ 6438c2ecf20Sopenharmony_ci ret = mwifiex_send_cmd(priv, HostCmd_CMD_11N_ADDBA_REQ, 6448c2ecf20Sopenharmony_ci 0, 0, &add_ba_req, false); 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci return ret; 6478c2ecf20Sopenharmony_ci} 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci/* 6508c2ecf20Sopenharmony_ci * This function sends a delete BA request to the given TID/RA pair. 6518c2ecf20Sopenharmony_ci */ 6528c2ecf20Sopenharmony_ciint mwifiex_send_delba(struct mwifiex_private *priv, int tid, u8 *peer_mac, 6538c2ecf20Sopenharmony_ci int initiator) 6548c2ecf20Sopenharmony_ci{ 6558c2ecf20Sopenharmony_ci struct host_cmd_ds_11n_delba delba; 6568c2ecf20Sopenharmony_ci int ret; 6578c2ecf20Sopenharmony_ci uint16_t del_ba_param_set; 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci memset(&delba, 0, sizeof(delba)); 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci del_ba_param_set = tid << DELBA_TID_POS; 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci if (initiator) 6648c2ecf20Sopenharmony_ci del_ba_param_set |= IEEE80211_DELBA_PARAM_INITIATOR_MASK; 6658c2ecf20Sopenharmony_ci else 6668c2ecf20Sopenharmony_ci del_ba_param_set &= ~IEEE80211_DELBA_PARAM_INITIATOR_MASK; 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci delba.del_ba_param_set = cpu_to_le16(del_ba_param_set); 6698c2ecf20Sopenharmony_ci memcpy(&delba.peer_mac_addr, peer_mac, ETH_ALEN); 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci /* We don't wait for the response of this command */ 6728c2ecf20Sopenharmony_ci ret = mwifiex_send_cmd(priv, HostCmd_CMD_11N_DELBA, 6738c2ecf20Sopenharmony_ci HostCmd_ACT_GEN_SET, 0, &delba, false); 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci return ret; 6768c2ecf20Sopenharmony_ci} 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci/* 6798c2ecf20Sopenharmony_ci * This function sends delba to specific tid 6808c2ecf20Sopenharmony_ci */ 6818c2ecf20Sopenharmony_civoid mwifiex_11n_delba(struct mwifiex_private *priv, int tid) 6828c2ecf20Sopenharmony_ci{ 6838c2ecf20Sopenharmony_ci struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr; 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci spin_lock_bh(&priv->rx_reorder_tbl_lock); 6868c2ecf20Sopenharmony_ci list_for_each_entry(rx_reor_tbl_ptr, &priv->rx_reorder_tbl_ptr, list) { 6878c2ecf20Sopenharmony_ci if (rx_reor_tbl_ptr->tid == tid) { 6888c2ecf20Sopenharmony_ci dev_dbg(priv->adapter->dev, 6898c2ecf20Sopenharmony_ci "Send delba to tid=%d, %pM\n", 6908c2ecf20Sopenharmony_ci tid, rx_reor_tbl_ptr->ta); 6918c2ecf20Sopenharmony_ci mwifiex_send_delba(priv, tid, rx_reor_tbl_ptr->ta, 0); 6928c2ecf20Sopenharmony_ci goto exit; 6938c2ecf20Sopenharmony_ci } 6948c2ecf20Sopenharmony_ci } 6958c2ecf20Sopenharmony_ciexit: 6968c2ecf20Sopenharmony_ci spin_unlock_bh(&priv->rx_reorder_tbl_lock); 6978c2ecf20Sopenharmony_ci} 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci/* 7008c2ecf20Sopenharmony_ci * This function handles the command response of a delete BA request. 7018c2ecf20Sopenharmony_ci */ 7028c2ecf20Sopenharmony_civoid mwifiex_11n_delete_ba_stream(struct mwifiex_private *priv, u8 *del_ba) 7038c2ecf20Sopenharmony_ci{ 7048c2ecf20Sopenharmony_ci struct host_cmd_ds_11n_delba *cmd_del_ba = 7058c2ecf20Sopenharmony_ci (struct host_cmd_ds_11n_delba *) del_ba; 7068c2ecf20Sopenharmony_ci uint16_t del_ba_param_set = le16_to_cpu(cmd_del_ba->del_ba_param_set); 7078c2ecf20Sopenharmony_ci int tid; 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci tid = del_ba_param_set >> DELBA_TID_POS; 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci mwifiex_del_ba_tbl(priv, tid, cmd_del_ba->peer_mac_addr, 7128c2ecf20Sopenharmony_ci TYPE_DELBA_RECEIVE, INITIATOR_BIT(del_ba_param_set)); 7138c2ecf20Sopenharmony_ci} 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci/* 7168c2ecf20Sopenharmony_ci * This function retrieves the Rx reordering table. 7178c2ecf20Sopenharmony_ci */ 7188c2ecf20Sopenharmony_ciint mwifiex_get_rx_reorder_tbl(struct mwifiex_private *priv, 7198c2ecf20Sopenharmony_ci struct mwifiex_ds_rx_reorder_tbl *buf) 7208c2ecf20Sopenharmony_ci{ 7218c2ecf20Sopenharmony_ci int i; 7228c2ecf20Sopenharmony_ci struct mwifiex_ds_rx_reorder_tbl *rx_reo_tbl = buf; 7238c2ecf20Sopenharmony_ci struct mwifiex_rx_reorder_tbl *rx_reorder_tbl_ptr; 7248c2ecf20Sopenharmony_ci int count = 0; 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci spin_lock_bh(&priv->rx_reorder_tbl_lock); 7278c2ecf20Sopenharmony_ci list_for_each_entry(rx_reorder_tbl_ptr, &priv->rx_reorder_tbl_ptr, 7288c2ecf20Sopenharmony_ci list) { 7298c2ecf20Sopenharmony_ci rx_reo_tbl->tid = (u16) rx_reorder_tbl_ptr->tid; 7308c2ecf20Sopenharmony_ci memcpy(rx_reo_tbl->ta, rx_reorder_tbl_ptr->ta, ETH_ALEN); 7318c2ecf20Sopenharmony_ci rx_reo_tbl->start_win = rx_reorder_tbl_ptr->start_win; 7328c2ecf20Sopenharmony_ci rx_reo_tbl->win_size = rx_reorder_tbl_ptr->win_size; 7338c2ecf20Sopenharmony_ci for (i = 0; i < rx_reorder_tbl_ptr->win_size; ++i) { 7348c2ecf20Sopenharmony_ci if (rx_reorder_tbl_ptr->rx_reorder_ptr[i]) 7358c2ecf20Sopenharmony_ci rx_reo_tbl->buffer[i] = true; 7368c2ecf20Sopenharmony_ci else 7378c2ecf20Sopenharmony_ci rx_reo_tbl->buffer[i] = false; 7388c2ecf20Sopenharmony_ci } 7398c2ecf20Sopenharmony_ci rx_reo_tbl++; 7408c2ecf20Sopenharmony_ci count++; 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci if (count >= MWIFIEX_MAX_RX_BASTREAM_SUPPORTED) 7438c2ecf20Sopenharmony_ci break; 7448c2ecf20Sopenharmony_ci } 7458c2ecf20Sopenharmony_ci spin_unlock_bh(&priv->rx_reorder_tbl_lock); 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci return count; 7488c2ecf20Sopenharmony_ci} 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci/* 7518c2ecf20Sopenharmony_ci * This function retrieves the Tx BA stream table. 7528c2ecf20Sopenharmony_ci */ 7538c2ecf20Sopenharmony_ciint mwifiex_get_tx_ba_stream_tbl(struct mwifiex_private *priv, 7548c2ecf20Sopenharmony_ci struct mwifiex_ds_tx_ba_stream_tbl *buf) 7558c2ecf20Sopenharmony_ci{ 7568c2ecf20Sopenharmony_ci struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl; 7578c2ecf20Sopenharmony_ci struct mwifiex_ds_tx_ba_stream_tbl *rx_reo_tbl = buf; 7588c2ecf20Sopenharmony_ci int count = 0; 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci spin_lock_bh(&priv->tx_ba_stream_tbl_lock); 7618c2ecf20Sopenharmony_ci list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) { 7628c2ecf20Sopenharmony_ci rx_reo_tbl->tid = (u16) tx_ba_tsr_tbl->tid; 7638c2ecf20Sopenharmony_ci mwifiex_dbg(priv->adapter, DATA, "data: %s tid=%d\n", 7648c2ecf20Sopenharmony_ci __func__, rx_reo_tbl->tid); 7658c2ecf20Sopenharmony_ci memcpy(rx_reo_tbl->ra, tx_ba_tsr_tbl->ra, ETH_ALEN); 7668c2ecf20Sopenharmony_ci rx_reo_tbl->amsdu = tx_ba_tsr_tbl->amsdu; 7678c2ecf20Sopenharmony_ci rx_reo_tbl++; 7688c2ecf20Sopenharmony_ci count++; 7698c2ecf20Sopenharmony_ci if (count >= MWIFIEX_MAX_TX_BASTREAM_SUPPORTED) 7708c2ecf20Sopenharmony_ci break; 7718c2ecf20Sopenharmony_ci } 7728c2ecf20Sopenharmony_ci spin_unlock_bh(&priv->tx_ba_stream_tbl_lock); 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci return count; 7758c2ecf20Sopenharmony_ci} 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci/* 7788c2ecf20Sopenharmony_ci * This function retrieves the entry for specific tx BA stream table by RA and 7798c2ecf20Sopenharmony_ci * deletes it. 7808c2ecf20Sopenharmony_ci */ 7818c2ecf20Sopenharmony_civoid mwifiex_del_tx_ba_stream_tbl_by_ra(struct mwifiex_private *priv, u8 *ra) 7828c2ecf20Sopenharmony_ci{ 7838c2ecf20Sopenharmony_ci struct mwifiex_tx_ba_stream_tbl *tbl, *tmp; 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci if (!ra) 7868c2ecf20Sopenharmony_ci return; 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci spin_lock_bh(&priv->tx_ba_stream_tbl_lock); 7898c2ecf20Sopenharmony_ci list_for_each_entry_safe(tbl, tmp, &priv->tx_ba_stream_tbl_ptr, list) 7908c2ecf20Sopenharmony_ci if (!memcmp(tbl->ra, ra, ETH_ALEN)) 7918c2ecf20Sopenharmony_ci mwifiex_11n_delete_tx_ba_stream_tbl_entry(priv, tbl); 7928c2ecf20Sopenharmony_ci spin_unlock_bh(&priv->tx_ba_stream_tbl_lock); 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci return; 7958c2ecf20Sopenharmony_ci} 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci/* This function initializes the BlockACK setup information for given 7988c2ecf20Sopenharmony_ci * mwifiex_private structure. 7998c2ecf20Sopenharmony_ci */ 8008c2ecf20Sopenharmony_civoid mwifiex_set_ba_params(struct mwifiex_private *priv) 8018c2ecf20Sopenharmony_ci{ 8028c2ecf20Sopenharmony_ci priv->add_ba_param.timeout = MWIFIEX_DEFAULT_BLOCK_ACK_TIMEOUT; 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) { 8058c2ecf20Sopenharmony_ci priv->add_ba_param.tx_win_size = 8068c2ecf20Sopenharmony_ci MWIFIEX_UAP_AMPDU_DEF_TXWINSIZE; 8078c2ecf20Sopenharmony_ci priv->add_ba_param.rx_win_size = 8088c2ecf20Sopenharmony_ci MWIFIEX_UAP_AMPDU_DEF_RXWINSIZE; 8098c2ecf20Sopenharmony_ci } else { 8108c2ecf20Sopenharmony_ci priv->add_ba_param.tx_win_size = 8118c2ecf20Sopenharmony_ci MWIFIEX_STA_AMPDU_DEF_TXWINSIZE; 8128c2ecf20Sopenharmony_ci priv->add_ba_param.rx_win_size = 8138c2ecf20Sopenharmony_ci MWIFIEX_STA_AMPDU_DEF_RXWINSIZE; 8148c2ecf20Sopenharmony_ci } 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci priv->add_ba_param.tx_amsdu = true; 8178c2ecf20Sopenharmony_ci priv->add_ba_param.rx_amsdu = true; 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci return; 8208c2ecf20Sopenharmony_ci} 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ciu8 mwifiex_get_sec_chan_offset(int chan) 8238c2ecf20Sopenharmony_ci{ 8248c2ecf20Sopenharmony_ci u8 sec_offset; 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci switch (chan) { 8278c2ecf20Sopenharmony_ci case 36: 8288c2ecf20Sopenharmony_ci case 44: 8298c2ecf20Sopenharmony_ci case 52: 8308c2ecf20Sopenharmony_ci case 60: 8318c2ecf20Sopenharmony_ci case 100: 8328c2ecf20Sopenharmony_ci case 108: 8338c2ecf20Sopenharmony_ci case 116: 8348c2ecf20Sopenharmony_ci case 124: 8358c2ecf20Sopenharmony_ci case 132: 8368c2ecf20Sopenharmony_ci case 140: 8378c2ecf20Sopenharmony_ci case 149: 8388c2ecf20Sopenharmony_ci case 157: 8398c2ecf20Sopenharmony_ci sec_offset = IEEE80211_HT_PARAM_CHA_SEC_ABOVE; 8408c2ecf20Sopenharmony_ci break; 8418c2ecf20Sopenharmony_ci case 40: 8428c2ecf20Sopenharmony_ci case 48: 8438c2ecf20Sopenharmony_ci case 56: 8448c2ecf20Sopenharmony_ci case 64: 8458c2ecf20Sopenharmony_ci case 104: 8468c2ecf20Sopenharmony_ci case 112: 8478c2ecf20Sopenharmony_ci case 120: 8488c2ecf20Sopenharmony_ci case 128: 8498c2ecf20Sopenharmony_ci case 136: 8508c2ecf20Sopenharmony_ci case 144: 8518c2ecf20Sopenharmony_ci case 153: 8528c2ecf20Sopenharmony_ci case 161: 8538c2ecf20Sopenharmony_ci sec_offset = IEEE80211_HT_PARAM_CHA_SEC_BELOW; 8548c2ecf20Sopenharmony_ci break; 8558c2ecf20Sopenharmony_ci case 165: 8568c2ecf20Sopenharmony_ci default: 8578c2ecf20Sopenharmony_ci sec_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE; 8588c2ecf20Sopenharmony_ci break; 8598c2ecf20Sopenharmony_ci } 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ci return sec_offset; 8628c2ecf20Sopenharmony_ci} 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci/* This function will send DELBA to entries in the priv's 8658c2ecf20Sopenharmony_ci * Tx BA stream table 8668c2ecf20Sopenharmony_ci */ 8678c2ecf20Sopenharmony_cistatic void 8688c2ecf20Sopenharmony_cimwifiex_send_delba_txbastream_tbl(struct mwifiex_private *priv, u8 tid) 8698c2ecf20Sopenharmony_ci{ 8708c2ecf20Sopenharmony_ci struct mwifiex_adapter *adapter = priv->adapter; 8718c2ecf20Sopenharmony_ci struct mwifiex_tx_ba_stream_tbl *tx_ba_stream_tbl_ptr; 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci list_for_each_entry(tx_ba_stream_tbl_ptr, 8748c2ecf20Sopenharmony_ci &priv->tx_ba_stream_tbl_ptr, list) { 8758c2ecf20Sopenharmony_ci if (tx_ba_stream_tbl_ptr->ba_status == BA_SETUP_COMPLETE) { 8768c2ecf20Sopenharmony_ci if (tid == tx_ba_stream_tbl_ptr->tid) { 8778c2ecf20Sopenharmony_ci dev_dbg(adapter->dev, 8788c2ecf20Sopenharmony_ci "Tx:Send delba to tid=%d, %pM\n", tid, 8798c2ecf20Sopenharmony_ci tx_ba_stream_tbl_ptr->ra); 8808c2ecf20Sopenharmony_ci mwifiex_send_delba(priv, 8818c2ecf20Sopenharmony_ci tx_ba_stream_tbl_ptr->tid, 8828c2ecf20Sopenharmony_ci tx_ba_stream_tbl_ptr->ra, 1); 8838c2ecf20Sopenharmony_ci return; 8848c2ecf20Sopenharmony_ci } 8858c2ecf20Sopenharmony_ci } 8868c2ecf20Sopenharmony_ci } 8878c2ecf20Sopenharmony_ci} 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci/* This function updates all the tx_win_size 8908c2ecf20Sopenharmony_ci */ 8918c2ecf20Sopenharmony_civoid mwifiex_update_ampdu_txwinsize(struct mwifiex_adapter *adapter) 8928c2ecf20Sopenharmony_ci{ 8938c2ecf20Sopenharmony_ci u8 i, j; 8948c2ecf20Sopenharmony_ci u32 tx_win_size; 8958c2ecf20Sopenharmony_ci struct mwifiex_private *priv; 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci for (i = 0; i < adapter->priv_num; i++) { 8988c2ecf20Sopenharmony_ci if (!adapter->priv[i]) 8998c2ecf20Sopenharmony_ci continue; 9008c2ecf20Sopenharmony_ci priv = adapter->priv[i]; 9018c2ecf20Sopenharmony_ci tx_win_size = priv->add_ba_param.tx_win_size; 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci if (priv->bss_type == MWIFIEX_BSS_TYPE_STA) 9048c2ecf20Sopenharmony_ci priv->add_ba_param.tx_win_size = 9058c2ecf20Sopenharmony_ci MWIFIEX_STA_AMPDU_DEF_TXWINSIZE; 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci if (priv->bss_type == MWIFIEX_BSS_TYPE_P2P) 9088c2ecf20Sopenharmony_ci priv->add_ba_param.tx_win_size = 9098c2ecf20Sopenharmony_ci MWIFIEX_STA_AMPDU_DEF_TXWINSIZE; 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci if (priv->bss_type == MWIFIEX_BSS_TYPE_UAP) 9128c2ecf20Sopenharmony_ci priv->add_ba_param.tx_win_size = 9138c2ecf20Sopenharmony_ci MWIFIEX_UAP_AMPDU_DEF_TXWINSIZE; 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci if (adapter->coex_win_size) { 9168c2ecf20Sopenharmony_ci if (adapter->coex_tx_win_size) 9178c2ecf20Sopenharmony_ci priv->add_ba_param.tx_win_size = 9188c2ecf20Sopenharmony_ci adapter->coex_tx_win_size; 9198c2ecf20Sopenharmony_ci } 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci if (tx_win_size != priv->add_ba_param.tx_win_size) { 9228c2ecf20Sopenharmony_ci if (!priv->media_connected) 9238c2ecf20Sopenharmony_ci continue; 9248c2ecf20Sopenharmony_ci for (j = 0; j < MAX_NUM_TID; j++) 9258c2ecf20Sopenharmony_ci mwifiex_send_delba_txbastream_tbl(priv, j); 9268c2ecf20Sopenharmony_ci } 9278c2ecf20Sopenharmony_ci } 9288c2ecf20Sopenharmony_ci} 929