11n.c (27175B)
1/* 2 * NXP Wireless LAN device driver: 802.11n 3 * 4 * Copyright 2011-2020 NXP 5 * 6 * This software file (the "File") is distributed by NXP 7 * under the terms of the GNU General Public License Version 2, June 1991 8 * (the "License"). You may use, redistribute and/or modify this File in 9 * accordance with the terms and conditions of the License, a copy of which 10 * is available by writing to the Free Software Foundation, Inc., 11 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the 12 * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. 13 * 14 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 16 * ARE EXPRESSLY DISCLAIMED. The License provides additional details about 17 * this warranty disclaimer. 18 */ 19 20#include "decl.h" 21#include "ioctl.h" 22#include "util.h" 23#include "fw.h" 24#include "main.h" 25#include "wmm.h" 26#include "11n.h" 27 28/* 29 * Fills HT capability information field, AMPDU Parameters field, HT extended 30 * capability field, and supported MCS set fields. 31 * 32 * HT capability information field, AMPDU Parameters field, supported MCS set 33 * fields are retrieved from cfg80211 stack 34 * 35 * RD responder bit to set to clear in the extended capability header. 36 */ 37int mwifiex_fill_cap_info(struct mwifiex_private *priv, u8 radio_type, 38 struct ieee80211_ht_cap *ht_cap) 39{ 40 uint16_t ht_ext_cap = le16_to_cpu(ht_cap->extended_ht_cap_info); 41 struct ieee80211_supported_band *sband = 42 priv->wdev.wiphy->bands[radio_type]; 43 44 if (WARN_ON_ONCE(!sband)) { 45 mwifiex_dbg(priv->adapter, ERROR, "Invalid radio type!\n"); 46 return -EINVAL; 47 } 48 49 ht_cap->ampdu_params_info = 50 (sband->ht_cap.ampdu_factor & 51 IEEE80211_HT_AMPDU_PARM_FACTOR) | 52 ((sband->ht_cap.ampdu_density << 53 IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT) & 54 IEEE80211_HT_AMPDU_PARM_DENSITY); 55 56 memcpy((u8 *)&ht_cap->mcs, &sband->ht_cap.mcs, 57 sizeof(sband->ht_cap.mcs)); 58 59 if (priv->bss_mode == NL80211_IFTYPE_STATION || 60 (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 && 61 (priv->adapter->sec_chan_offset != 62 IEEE80211_HT_PARAM_CHA_SEC_NONE))) 63 /* Set MCS32 for infra mode or ad-hoc mode with 40MHz support */ 64 SETHT_MCS32(ht_cap->mcs.rx_mask); 65 66 /* Clear RD responder bit */ 67 ht_ext_cap &= ~IEEE80211_HT_EXT_CAP_RD_RESPONDER; 68 69 ht_cap->cap_info = cpu_to_le16(sband->ht_cap.cap); 70 ht_cap->extended_ht_cap_info = cpu_to_le16(ht_ext_cap); 71 72 if (ISSUPP_BEAMFORMING(priv->adapter->hw_dot_11n_dev_cap)) 73 ht_cap->tx_BF_cap_info = cpu_to_le32(MWIFIEX_DEF_11N_TX_BF_CAP); 74 75 return 0; 76} 77 78/* 79 * This function returns the pointer to an entry in BA Stream 80 * table which matches the requested BA status. 81 */ 82static struct mwifiex_tx_ba_stream_tbl * 83mwifiex_get_ba_status(struct mwifiex_private *priv, 84 enum mwifiex_ba_status ba_status) 85{ 86 struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl; 87 88 spin_lock_bh(&priv->tx_ba_stream_tbl_lock); 89 list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) { 90 if (tx_ba_tsr_tbl->ba_status == ba_status) { 91 spin_unlock_bh(&priv->tx_ba_stream_tbl_lock); 92 return tx_ba_tsr_tbl; 93 } 94 } 95 spin_unlock_bh(&priv->tx_ba_stream_tbl_lock); 96 return NULL; 97} 98 99/* 100 * This function handles the command response of delete a block 101 * ack request. 102 * 103 * The function checks the response success status and takes action 104 * accordingly (send an add BA request in case of success, or recreate 105 * the deleted stream in case of failure, if the add BA was also 106 * initiated by us). 107 */ 108int mwifiex_ret_11n_delba(struct mwifiex_private *priv, 109 struct host_cmd_ds_command *resp) 110{ 111 int tid; 112 struct mwifiex_tx_ba_stream_tbl *tx_ba_tbl; 113 struct host_cmd_ds_11n_delba *del_ba = &resp->params.del_ba; 114 uint16_t del_ba_param_set = le16_to_cpu(del_ba->del_ba_param_set); 115 116 tid = del_ba_param_set >> DELBA_TID_POS; 117 if (del_ba->del_result == BA_RESULT_SUCCESS) { 118 mwifiex_del_ba_tbl(priv, tid, del_ba->peer_mac_addr, 119 TYPE_DELBA_SENT, 120 INITIATOR_BIT(del_ba_param_set)); 121 122 tx_ba_tbl = mwifiex_get_ba_status(priv, BA_SETUP_INPROGRESS); 123 if (tx_ba_tbl) 124 mwifiex_send_addba(priv, tx_ba_tbl->tid, 125 tx_ba_tbl->ra); 126 } else { /* 127 * In case of failure, recreate the deleted stream in case 128 * we initiated the DELBA 129 */ 130 if (!INITIATOR_BIT(del_ba_param_set)) 131 return 0; 132 133 mwifiex_create_ba_tbl(priv, del_ba->peer_mac_addr, tid, 134 BA_SETUP_INPROGRESS); 135 136 tx_ba_tbl = mwifiex_get_ba_status(priv, BA_SETUP_INPROGRESS); 137 138 if (tx_ba_tbl) 139 mwifiex_del_ba_tbl(priv, tx_ba_tbl->tid, tx_ba_tbl->ra, 140 TYPE_DELBA_SENT, true); 141 } 142 143 return 0; 144} 145 146/* 147 * This function handles the command response of add a block 148 * ack request. 149 * 150 * Handling includes changing the header fields to CPU formats, checking 151 * the response success status and taking actions accordingly (delete the 152 * BA stream table in case of failure). 153 */ 154int mwifiex_ret_11n_addba_req(struct mwifiex_private *priv, 155 struct host_cmd_ds_command *resp) 156{ 157 int tid, tid_down; 158 struct host_cmd_ds_11n_addba_rsp *add_ba_rsp = &resp->params.add_ba_rsp; 159 struct mwifiex_tx_ba_stream_tbl *tx_ba_tbl; 160 struct mwifiex_ra_list_tbl *ra_list; 161 u16 block_ack_param_set = le16_to_cpu(add_ba_rsp->block_ack_param_set); 162 163 add_ba_rsp->ssn = cpu_to_le16((le16_to_cpu(add_ba_rsp->ssn)) 164 & SSN_MASK); 165 166 tid = (block_ack_param_set & IEEE80211_ADDBA_PARAM_TID_MASK) 167 >> BLOCKACKPARAM_TID_POS; 168 169 tid_down = mwifiex_wmm_downgrade_tid(priv, tid); 170 ra_list = mwifiex_wmm_get_ralist_node(priv, tid_down, add_ba_rsp-> 171 peer_mac_addr); 172 if (le16_to_cpu(add_ba_rsp->status_code) != BA_RESULT_SUCCESS) { 173 if (ra_list) { 174 ra_list->ba_status = BA_SETUP_NONE; 175 ra_list->amsdu_in_ampdu = false; 176 } 177 mwifiex_del_ba_tbl(priv, tid, add_ba_rsp->peer_mac_addr, 178 TYPE_DELBA_SENT, true); 179 if (add_ba_rsp->add_rsp_result != BA_RESULT_TIMEOUT) 180 priv->aggr_prio_tbl[tid].ampdu_ap = 181 BA_STREAM_NOT_ALLOWED; 182 return 0; 183 } 184 185 tx_ba_tbl = mwifiex_get_ba_tbl(priv, tid, add_ba_rsp->peer_mac_addr); 186 if (tx_ba_tbl) { 187 mwifiex_dbg(priv->adapter, EVENT, "info: BA stream complete\n"); 188 tx_ba_tbl->ba_status = BA_SETUP_COMPLETE; 189 if ((block_ack_param_set & BLOCKACKPARAM_AMSDU_SUPP_MASK) && 190 priv->add_ba_param.tx_amsdu && 191 (priv->aggr_prio_tbl[tid].amsdu != BA_STREAM_NOT_ALLOWED)) 192 tx_ba_tbl->amsdu = true; 193 else 194 tx_ba_tbl->amsdu = false; 195 if (ra_list) { 196 ra_list->amsdu_in_ampdu = tx_ba_tbl->amsdu; 197 ra_list->ba_status = BA_SETUP_COMPLETE; 198 } 199 } else { 200 mwifiex_dbg(priv->adapter, ERROR, "BA stream not created\n"); 201 } 202 203 return 0; 204} 205 206/* 207 * This function prepares command of reconfigure Tx buffer. 208 * 209 * Preparation includes - 210 * - Setting command ID, action and proper size 211 * - Setting Tx buffer size (for SET only) 212 * - Ensuring correct endian-ness 213 */ 214int mwifiex_cmd_recfg_tx_buf(struct mwifiex_private *priv, 215 struct host_cmd_ds_command *cmd, int cmd_action, 216 u16 *buf_size) 217{ 218 struct host_cmd_ds_txbuf_cfg *tx_buf = &cmd->params.tx_buf; 219 u16 action = (u16) cmd_action; 220 221 cmd->command = cpu_to_le16(HostCmd_CMD_RECONFIGURE_TX_BUFF); 222 cmd->size = 223 cpu_to_le16(sizeof(struct host_cmd_ds_txbuf_cfg) + S_DS_GEN); 224 tx_buf->action = cpu_to_le16(action); 225 switch (action) { 226 case HostCmd_ACT_GEN_SET: 227 mwifiex_dbg(priv->adapter, CMD, 228 "cmd: set tx_buf=%d\n", *buf_size); 229 tx_buf->buff_size = cpu_to_le16(*buf_size); 230 break; 231 case HostCmd_ACT_GEN_GET: 232 default: 233 tx_buf->buff_size = 0; 234 break; 235 } 236 return 0; 237} 238 239/* 240 * This function prepares command of AMSDU aggregation control. 241 * 242 * Preparation includes - 243 * - Setting command ID, action and proper size 244 * - Setting AMSDU control parameters (for SET only) 245 * - Ensuring correct endian-ness 246 */ 247int mwifiex_cmd_amsdu_aggr_ctrl(struct host_cmd_ds_command *cmd, 248 int cmd_action, 249 struct mwifiex_ds_11n_amsdu_aggr_ctrl *aa_ctrl) 250{ 251 struct host_cmd_ds_amsdu_aggr_ctrl *amsdu_ctrl = 252 &cmd->params.amsdu_aggr_ctrl; 253 u16 action = (u16) cmd_action; 254 255 cmd->command = cpu_to_le16(HostCmd_CMD_AMSDU_AGGR_CTRL); 256 cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_amsdu_aggr_ctrl) 257 + S_DS_GEN); 258 amsdu_ctrl->action = cpu_to_le16(action); 259 switch (action) { 260 case HostCmd_ACT_GEN_SET: 261 amsdu_ctrl->enable = cpu_to_le16(aa_ctrl->enable); 262 amsdu_ctrl->curr_buf_size = 0; 263 break; 264 case HostCmd_ACT_GEN_GET: 265 default: 266 amsdu_ctrl->curr_buf_size = 0; 267 break; 268 } 269 return 0; 270} 271 272/* 273 * This function prepares 11n configuration command. 274 * 275 * Preparation includes - 276 * - Setting command ID, action and proper size 277 * - Setting HT Tx capability and HT Tx information fields 278 * - Ensuring correct endian-ness 279 */ 280int mwifiex_cmd_11n_cfg(struct mwifiex_private *priv, 281 struct host_cmd_ds_command *cmd, u16 cmd_action, 282 struct mwifiex_ds_11n_tx_cfg *txcfg) 283{ 284 struct host_cmd_ds_11n_cfg *htcfg = &cmd->params.htcfg; 285 286 cmd->command = cpu_to_le16(HostCmd_CMD_11N_CFG); 287 cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_11n_cfg) + S_DS_GEN); 288 htcfg->action = cpu_to_le16(cmd_action); 289 htcfg->ht_tx_cap = cpu_to_le16(txcfg->tx_htcap); 290 htcfg->ht_tx_info = cpu_to_le16(txcfg->tx_htinfo); 291 292 if (priv->adapter->is_hw_11ac_capable) 293 htcfg->misc_config = cpu_to_le16(txcfg->misc_config); 294 295 return 0; 296} 297 298/* 299 * This function appends an 11n TLV to a buffer. 300 * 301 * Buffer allocation is responsibility of the calling 302 * function. No size validation is made here. 303 * 304 * The function fills up the following sections, if applicable - 305 * - HT capability IE 306 * - HT information IE (with channel list) 307 * - 20/40 BSS Coexistence IE 308 * - HT Extended Capabilities IE 309 */ 310int 311mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv, 312 struct mwifiex_bssdescriptor *bss_desc, 313 u8 **buffer) 314{ 315 struct mwifiex_ie_types_htcap *ht_cap; 316 struct mwifiex_ie_types_htinfo *ht_info; 317 struct mwifiex_ie_types_chan_list_param_set *chan_list; 318 struct mwifiex_ie_types_2040bssco *bss_co_2040; 319 struct mwifiex_ie_types_extcap *ext_cap; 320 int ret_len = 0; 321 struct ieee80211_supported_band *sband; 322 struct ieee_types_header *hdr; 323 u8 radio_type; 324 325 if (!buffer || !*buffer) 326 return ret_len; 327 328 radio_type = mwifiex_band_to_radio_type((u8) bss_desc->bss_band); 329 sband = priv->wdev.wiphy->bands[radio_type]; 330 331 if (bss_desc->bcn_ht_cap) { 332 ht_cap = (struct mwifiex_ie_types_htcap *) *buffer; 333 memset(ht_cap, 0, sizeof(struct mwifiex_ie_types_htcap)); 334 ht_cap->header.type = cpu_to_le16(WLAN_EID_HT_CAPABILITY); 335 ht_cap->header.len = 336 cpu_to_le16(sizeof(struct ieee80211_ht_cap)); 337 memcpy((u8 *) ht_cap + sizeof(struct mwifiex_ie_types_header), 338 (u8 *)bss_desc->bcn_ht_cap, 339 le16_to_cpu(ht_cap->header.len)); 340 341 mwifiex_fill_cap_info(priv, radio_type, &ht_cap->ht_cap); 342 /* Update HT40 capability from current channel information */ 343 if (bss_desc->bcn_ht_oper) { 344 u8 ht_param = bss_desc->bcn_ht_oper->ht_param; 345 u8 radio = 346 mwifiex_band_to_radio_type(bss_desc->bss_band); 347 int freq = 348 ieee80211_channel_to_frequency(bss_desc->channel, 349 radio); 350 struct ieee80211_channel *chan = 351 ieee80211_get_channel(priv->adapter->wiphy, freq); 352 353 switch (ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { 354 case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: 355 if (chan->flags & IEEE80211_CHAN_NO_HT40PLUS) { 356 ht_cap->ht_cap.cap_info &= 357 cpu_to_le16 358 (~IEEE80211_HT_CAP_SUP_WIDTH_20_40); 359 ht_cap->ht_cap.cap_info &= 360 cpu_to_le16(~IEEE80211_HT_CAP_SGI_40); 361 } 362 break; 363 case IEEE80211_HT_PARAM_CHA_SEC_BELOW: 364 if (chan->flags & IEEE80211_CHAN_NO_HT40MINUS) { 365 ht_cap->ht_cap.cap_info &= 366 cpu_to_le16 367 (~IEEE80211_HT_CAP_SUP_WIDTH_20_40); 368 ht_cap->ht_cap.cap_info &= 369 cpu_to_le16(~IEEE80211_HT_CAP_SGI_40); 370 } 371 break; 372 } 373 } 374 375 *buffer += sizeof(struct mwifiex_ie_types_htcap); 376 ret_len += sizeof(struct mwifiex_ie_types_htcap); 377 } 378 379 if (bss_desc->bcn_ht_oper) { 380 if (priv->bss_mode == NL80211_IFTYPE_ADHOC) { 381 ht_info = (struct mwifiex_ie_types_htinfo *) *buffer; 382 memset(ht_info, 0, 383 sizeof(struct mwifiex_ie_types_htinfo)); 384 ht_info->header.type = 385 cpu_to_le16(WLAN_EID_HT_OPERATION); 386 ht_info->header.len = 387 cpu_to_le16( 388 sizeof(struct ieee80211_ht_operation)); 389 390 memcpy((u8 *) ht_info + 391 sizeof(struct mwifiex_ie_types_header), 392 (u8 *)bss_desc->bcn_ht_oper, 393 le16_to_cpu(ht_info->header.len)); 394 395 if (!(sband->ht_cap.cap & 396 IEEE80211_HT_CAP_SUP_WIDTH_20_40)) 397 ht_info->ht_oper.ht_param &= 398 ~(IEEE80211_HT_PARAM_CHAN_WIDTH_ANY | 399 IEEE80211_HT_PARAM_CHA_SEC_OFFSET); 400 401 *buffer += sizeof(struct mwifiex_ie_types_htinfo); 402 ret_len += sizeof(struct mwifiex_ie_types_htinfo); 403 } 404 405 chan_list = 406 (struct mwifiex_ie_types_chan_list_param_set *) *buffer; 407 memset(chan_list, 0, 408 sizeof(struct mwifiex_ie_types_chan_list_param_set)); 409 chan_list->header.type = cpu_to_le16(TLV_TYPE_CHANLIST); 410 chan_list->header.len = cpu_to_le16( 411 sizeof(struct mwifiex_ie_types_chan_list_param_set) - 412 sizeof(struct mwifiex_ie_types_header)); 413 chan_list->chan_scan_param[0].chan_number = 414 bss_desc->bcn_ht_oper->primary_chan; 415 chan_list->chan_scan_param[0].radio_type = 416 mwifiex_band_to_radio_type((u8) bss_desc->bss_band); 417 418 if (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 && 419 bss_desc->bcn_ht_oper->ht_param & 420 IEEE80211_HT_PARAM_CHAN_WIDTH_ANY) 421 SET_SECONDARYCHAN(chan_list->chan_scan_param[0]. 422 radio_type, 423 (bss_desc->bcn_ht_oper->ht_param & 424 IEEE80211_HT_PARAM_CHA_SEC_OFFSET)); 425 426 *buffer += sizeof(struct mwifiex_ie_types_chan_list_param_set); 427 ret_len += sizeof(struct mwifiex_ie_types_chan_list_param_set); 428 } 429 430 if (bss_desc->bcn_bss_co_2040) { 431 bss_co_2040 = (struct mwifiex_ie_types_2040bssco *) *buffer; 432 memset(bss_co_2040, 0, 433 sizeof(struct mwifiex_ie_types_2040bssco)); 434 bss_co_2040->header.type = cpu_to_le16(WLAN_EID_BSS_COEX_2040); 435 bss_co_2040->header.len = 436 cpu_to_le16(sizeof(bss_co_2040->bss_co_2040)); 437 438 memcpy((u8 *) bss_co_2040 + 439 sizeof(struct mwifiex_ie_types_header), 440 bss_desc->bcn_bss_co_2040 + 441 sizeof(struct ieee_types_header), 442 le16_to_cpu(bss_co_2040->header.len)); 443 444 *buffer += sizeof(struct mwifiex_ie_types_2040bssco); 445 ret_len += sizeof(struct mwifiex_ie_types_2040bssco); 446 } 447 448 if (bss_desc->bcn_ext_cap) { 449 hdr = (void *)bss_desc->bcn_ext_cap; 450 ext_cap = (struct mwifiex_ie_types_extcap *) *buffer; 451 memset(ext_cap, 0, sizeof(struct mwifiex_ie_types_extcap)); 452 ext_cap->header.type = cpu_to_le16(WLAN_EID_EXT_CAPABILITY); 453 ext_cap->header.len = cpu_to_le16(hdr->len); 454 455 memcpy((u8 *)ext_cap->ext_capab, 456 bss_desc->bcn_ext_cap + sizeof(struct ieee_types_header), 457 le16_to_cpu(ext_cap->header.len)); 458 459 if (hdr->len > 3 && 460 ext_cap->ext_capab[3] & WLAN_EXT_CAPA4_INTERWORKING_ENABLED) 461 priv->hs2_enabled = true; 462 else 463 priv->hs2_enabled = false; 464 465 *buffer += sizeof(struct mwifiex_ie_types_extcap) + hdr->len; 466 ret_len += sizeof(struct mwifiex_ie_types_extcap) + hdr->len; 467 } 468 469 return ret_len; 470} 471 472/* 473 * This function checks if the given pointer is valid entry of 474 * Tx BA Stream table. 475 */ 476static int mwifiex_is_tx_ba_stream_ptr_valid(struct mwifiex_private *priv, 477 struct mwifiex_tx_ba_stream_tbl *tx_tbl_ptr) 478{ 479 struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl; 480 481 list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) { 482 if (tx_ba_tsr_tbl == tx_tbl_ptr) 483 return true; 484 } 485 486 return false; 487} 488 489/* 490 * This function deletes the given entry in Tx BA Stream table. 491 * 492 * The function also performs a validity check on the supplied 493 * pointer before trying to delete. 494 */ 495void mwifiex_11n_delete_tx_ba_stream_tbl_entry(struct mwifiex_private *priv, 496 struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl) 497{ 498 if (!tx_ba_tsr_tbl && 499 mwifiex_is_tx_ba_stream_ptr_valid(priv, tx_ba_tsr_tbl)) 500 return; 501 502 mwifiex_dbg(priv->adapter, INFO, 503 "info: tx_ba_tsr_tbl %p\n", tx_ba_tsr_tbl); 504 505 list_del(&tx_ba_tsr_tbl->list); 506 507 kfree(tx_ba_tsr_tbl); 508} 509 510/* 511 * This function deletes all the entries in Tx BA Stream table. 512 */ 513void mwifiex_11n_delete_all_tx_ba_stream_tbl(struct mwifiex_private *priv) 514{ 515 int i; 516 struct mwifiex_tx_ba_stream_tbl *del_tbl_ptr, *tmp_node; 517 518 spin_lock_bh(&priv->tx_ba_stream_tbl_lock); 519 list_for_each_entry_safe(del_tbl_ptr, tmp_node, 520 &priv->tx_ba_stream_tbl_ptr, list) 521 mwifiex_11n_delete_tx_ba_stream_tbl_entry(priv, del_tbl_ptr); 522 spin_unlock_bh(&priv->tx_ba_stream_tbl_lock); 523 524 INIT_LIST_HEAD(&priv->tx_ba_stream_tbl_ptr); 525 526 for (i = 0; i < MAX_NUM_TID; ++i) 527 priv->aggr_prio_tbl[i].ampdu_ap = 528 priv->aggr_prio_tbl[i].ampdu_user; 529} 530 531/* 532 * This function returns the pointer to an entry in BA Stream 533 * table which matches the given RA/TID pair. 534 */ 535struct mwifiex_tx_ba_stream_tbl * 536mwifiex_get_ba_tbl(struct mwifiex_private *priv, int tid, u8 *ra) 537{ 538 struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl; 539 540 spin_lock_bh(&priv->tx_ba_stream_tbl_lock); 541 list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) { 542 if (ether_addr_equal_unaligned(tx_ba_tsr_tbl->ra, ra) && 543 tx_ba_tsr_tbl->tid == tid) { 544 spin_unlock_bh(&priv->tx_ba_stream_tbl_lock); 545 return tx_ba_tsr_tbl; 546 } 547 } 548 spin_unlock_bh(&priv->tx_ba_stream_tbl_lock); 549 return NULL; 550} 551 552/* 553 * This function creates an entry in Tx BA stream table for the 554 * given RA/TID pair. 555 */ 556void mwifiex_create_ba_tbl(struct mwifiex_private *priv, u8 *ra, int tid, 557 enum mwifiex_ba_status ba_status) 558{ 559 struct mwifiex_tx_ba_stream_tbl *new_node; 560 struct mwifiex_ra_list_tbl *ra_list; 561 int tid_down; 562 563 if (!mwifiex_get_ba_tbl(priv, tid, ra)) { 564 new_node = kzalloc(sizeof(struct mwifiex_tx_ba_stream_tbl), 565 GFP_ATOMIC); 566 if (!new_node) 567 return; 568 569 tid_down = mwifiex_wmm_downgrade_tid(priv, tid); 570 ra_list = mwifiex_wmm_get_ralist_node(priv, tid_down, ra); 571 if (ra_list) { 572 ra_list->ba_status = ba_status; 573 ra_list->amsdu_in_ampdu = false; 574 } 575 INIT_LIST_HEAD(&new_node->list); 576 577 new_node->tid = tid; 578 new_node->ba_status = ba_status; 579 memcpy(new_node->ra, ra, ETH_ALEN); 580 581 spin_lock_bh(&priv->tx_ba_stream_tbl_lock); 582 list_add_tail(&new_node->list, &priv->tx_ba_stream_tbl_ptr); 583 spin_unlock_bh(&priv->tx_ba_stream_tbl_lock); 584 } 585} 586 587/* 588 * This function sends an add BA request to the given TID/RA pair. 589 */ 590int mwifiex_send_addba(struct mwifiex_private *priv, int tid, u8 *peer_mac) 591{ 592 struct host_cmd_ds_11n_addba_req add_ba_req; 593 u32 tx_win_size = priv->add_ba_param.tx_win_size; 594 static u8 dialog_tok; 595 int ret; 596 u16 block_ack_param_set; 597 598 mwifiex_dbg(priv->adapter, CMD, "cmd: %s: tid %d\n", __func__, tid); 599 600 memset(&add_ba_req, 0, sizeof(add_ba_req)); 601 602 if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) && 603 ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info) && 604 priv->adapter->is_hw_11ac_capable && 605 memcmp(priv->cfg_bssid, peer_mac, ETH_ALEN)) { 606 struct mwifiex_sta_node *sta_ptr; 607 608 spin_lock_bh(&priv->sta_list_spinlock); 609 sta_ptr = mwifiex_get_sta_entry(priv, peer_mac); 610 if (!sta_ptr) { 611 spin_unlock_bh(&priv->sta_list_spinlock); 612 mwifiex_dbg(priv->adapter, ERROR, 613 "BA setup with unknown TDLS peer %pM!\n", 614 peer_mac); 615 return -1; 616 } 617 if (sta_ptr->is_11ac_enabled) 618 tx_win_size = MWIFIEX_11AC_STA_AMPDU_DEF_TXWINSIZE; 619 spin_unlock_bh(&priv->sta_list_spinlock); 620 } 621 622 block_ack_param_set = (u16)((tid << BLOCKACKPARAM_TID_POS) | 623 tx_win_size << BLOCKACKPARAM_WINSIZE_POS | 624 IMMEDIATE_BLOCK_ACK); 625 626 /* enable AMSDU inside AMPDU */ 627 if (priv->add_ba_param.tx_amsdu && 628 (priv->aggr_prio_tbl[tid].amsdu != BA_STREAM_NOT_ALLOWED)) 629 block_ack_param_set |= BLOCKACKPARAM_AMSDU_SUPP_MASK; 630 631 add_ba_req.block_ack_param_set = cpu_to_le16(block_ack_param_set); 632 add_ba_req.block_ack_tmo = cpu_to_le16((u16)priv->add_ba_param.timeout); 633 634 ++dialog_tok; 635 636 if (dialog_tok == 0) 637 dialog_tok = 1; 638 639 add_ba_req.dialog_token = dialog_tok; 640 memcpy(&add_ba_req.peer_mac_addr, peer_mac, ETH_ALEN); 641 642 /* We don't wait for the response of this command */ 643 ret = mwifiex_send_cmd(priv, HostCmd_CMD_11N_ADDBA_REQ, 644 0, 0, &add_ba_req, false); 645 646 return ret; 647} 648 649/* 650 * This function sends a delete BA request to the given TID/RA pair. 651 */ 652int mwifiex_send_delba(struct mwifiex_private *priv, int tid, u8 *peer_mac, 653 int initiator) 654{ 655 struct host_cmd_ds_11n_delba delba; 656 int ret; 657 uint16_t del_ba_param_set; 658 659 memset(&delba, 0, sizeof(delba)); 660 661 del_ba_param_set = tid << DELBA_TID_POS; 662 663 if (initiator) 664 del_ba_param_set |= IEEE80211_DELBA_PARAM_INITIATOR_MASK; 665 else 666 del_ba_param_set &= ~IEEE80211_DELBA_PARAM_INITIATOR_MASK; 667 668 delba.del_ba_param_set = cpu_to_le16(del_ba_param_set); 669 memcpy(&delba.peer_mac_addr, peer_mac, ETH_ALEN); 670 671 /* We don't wait for the response of this command */ 672 ret = mwifiex_send_cmd(priv, HostCmd_CMD_11N_DELBA, 673 HostCmd_ACT_GEN_SET, 0, &delba, false); 674 675 return ret; 676} 677 678/* 679 * This function sends delba to specific tid 680 */ 681void mwifiex_11n_delba(struct mwifiex_private *priv, int tid) 682{ 683 struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr; 684 685 spin_lock_bh(&priv->rx_reorder_tbl_lock); 686 list_for_each_entry(rx_reor_tbl_ptr, &priv->rx_reorder_tbl_ptr, list) { 687 if (rx_reor_tbl_ptr->tid == tid) { 688 dev_dbg(priv->adapter->dev, 689 "Send delba to tid=%d, %pM\n", 690 tid, rx_reor_tbl_ptr->ta); 691 mwifiex_send_delba(priv, tid, rx_reor_tbl_ptr->ta, 0); 692 goto exit; 693 } 694 } 695exit: 696 spin_unlock_bh(&priv->rx_reorder_tbl_lock); 697} 698 699/* 700 * This function handles the command response of a delete BA request. 701 */ 702void mwifiex_11n_delete_ba_stream(struct mwifiex_private *priv, u8 *del_ba) 703{ 704 struct host_cmd_ds_11n_delba *cmd_del_ba = 705 (struct host_cmd_ds_11n_delba *) del_ba; 706 uint16_t del_ba_param_set = le16_to_cpu(cmd_del_ba->del_ba_param_set); 707 int tid; 708 709 tid = del_ba_param_set >> DELBA_TID_POS; 710 711 mwifiex_del_ba_tbl(priv, tid, cmd_del_ba->peer_mac_addr, 712 TYPE_DELBA_RECEIVE, INITIATOR_BIT(del_ba_param_set)); 713} 714 715/* 716 * This function retrieves the Rx reordering table. 717 */ 718int mwifiex_get_rx_reorder_tbl(struct mwifiex_private *priv, 719 struct mwifiex_ds_rx_reorder_tbl *buf) 720{ 721 int i; 722 struct mwifiex_ds_rx_reorder_tbl *rx_reo_tbl = buf; 723 struct mwifiex_rx_reorder_tbl *rx_reorder_tbl_ptr; 724 int count = 0; 725 726 spin_lock_bh(&priv->rx_reorder_tbl_lock); 727 list_for_each_entry(rx_reorder_tbl_ptr, &priv->rx_reorder_tbl_ptr, 728 list) { 729 rx_reo_tbl->tid = (u16) rx_reorder_tbl_ptr->tid; 730 memcpy(rx_reo_tbl->ta, rx_reorder_tbl_ptr->ta, ETH_ALEN); 731 rx_reo_tbl->start_win = rx_reorder_tbl_ptr->start_win; 732 rx_reo_tbl->win_size = rx_reorder_tbl_ptr->win_size; 733 for (i = 0; i < rx_reorder_tbl_ptr->win_size; ++i) { 734 if (rx_reorder_tbl_ptr->rx_reorder_ptr[i]) 735 rx_reo_tbl->buffer[i] = true; 736 else 737 rx_reo_tbl->buffer[i] = false; 738 } 739 rx_reo_tbl++; 740 count++; 741 742 if (count >= MWIFIEX_MAX_RX_BASTREAM_SUPPORTED) 743 break; 744 } 745 spin_unlock_bh(&priv->rx_reorder_tbl_lock); 746 747 return count; 748} 749 750/* 751 * This function retrieves the Tx BA stream table. 752 */ 753int mwifiex_get_tx_ba_stream_tbl(struct mwifiex_private *priv, 754 struct mwifiex_ds_tx_ba_stream_tbl *buf) 755{ 756 struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl; 757 struct mwifiex_ds_tx_ba_stream_tbl *rx_reo_tbl = buf; 758 int count = 0; 759 760 spin_lock_bh(&priv->tx_ba_stream_tbl_lock); 761 list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) { 762 rx_reo_tbl->tid = (u16) tx_ba_tsr_tbl->tid; 763 mwifiex_dbg(priv->adapter, DATA, "data: %s tid=%d\n", 764 __func__, rx_reo_tbl->tid); 765 memcpy(rx_reo_tbl->ra, tx_ba_tsr_tbl->ra, ETH_ALEN); 766 rx_reo_tbl->amsdu = tx_ba_tsr_tbl->amsdu; 767 rx_reo_tbl++; 768 count++; 769 if (count >= MWIFIEX_MAX_TX_BASTREAM_SUPPORTED) 770 break; 771 } 772 spin_unlock_bh(&priv->tx_ba_stream_tbl_lock); 773 774 return count; 775} 776 777/* 778 * This function retrieves the entry for specific tx BA stream table by RA and 779 * deletes it. 780 */ 781void mwifiex_del_tx_ba_stream_tbl_by_ra(struct mwifiex_private *priv, u8 *ra) 782{ 783 struct mwifiex_tx_ba_stream_tbl *tbl, *tmp; 784 785 if (!ra) 786 return; 787 788 spin_lock_bh(&priv->tx_ba_stream_tbl_lock); 789 list_for_each_entry_safe(tbl, tmp, &priv->tx_ba_stream_tbl_ptr, list) 790 if (!memcmp(tbl->ra, ra, ETH_ALEN)) 791 mwifiex_11n_delete_tx_ba_stream_tbl_entry(priv, tbl); 792 spin_unlock_bh(&priv->tx_ba_stream_tbl_lock); 793 794 return; 795} 796 797/* This function initializes the BlockACK setup information for given 798 * mwifiex_private structure. 799 */ 800void mwifiex_set_ba_params(struct mwifiex_private *priv) 801{ 802 priv->add_ba_param.timeout = MWIFIEX_DEFAULT_BLOCK_ACK_TIMEOUT; 803 804 if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) { 805 priv->add_ba_param.tx_win_size = 806 MWIFIEX_UAP_AMPDU_DEF_TXWINSIZE; 807 priv->add_ba_param.rx_win_size = 808 MWIFIEX_UAP_AMPDU_DEF_RXWINSIZE; 809 } else { 810 priv->add_ba_param.tx_win_size = 811 MWIFIEX_STA_AMPDU_DEF_TXWINSIZE; 812 priv->add_ba_param.rx_win_size = 813 MWIFIEX_STA_AMPDU_DEF_RXWINSIZE; 814 } 815 816 priv->add_ba_param.tx_amsdu = true; 817 priv->add_ba_param.rx_amsdu = true; 818 819 return; 820} 821 822u8 mwifiex_get_sec_chan_offset(int chan) 823{ 824 u8 sec_offset; 825 826 switch (chan) { 827 case 36: 828 case 44: 829 case 52: 830 case 60: 831 case 100: 832 case 108: 833 case 116: 834 case 124: 835 case 132: 836 case 140: 837 case 149: 838 case 157: 839 sec_offset = IEEE80211_HT_PARAM_CHA_SEC_ABOVE; 840 break; 841 case 40: 842 case 48: 843 case 56: 844 case 64: 845 case 104: 846 case 112: 847 case 120: 848 case 128: 849 case 136: 850 case 144: 851 case 153: 852 case 161: 853 sec_offset = IEEE80211_HT_PARAM_CHA_SEC_BELOW; 854 break; 855 case 165: 856 default: 857 sec_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE; 858 break; 859 } 860 861 return sec_offset; 862} 863 864/* This function will send DELBA to entries in the priv's 865 * Tx BA stream table 866 */ 867static void 868mwifiex_send_delba_txbastream_tbl(struct mwifiex_private *priv, u8 tid) 869{ 870 struct mwifiex_adapter *adapter = priv->adapter; 871 struct mwifiex_tx_ba_stream_tbl *tx_ba_stream_tbl_ptr; 872 873 list_for_each_entry(tx_ba_stream_tbl_ptr, 874 &priv->tx_ba_stream_tbl_ptr, list) { 875 if (tx_ba_stream_tbl_ptr->ba_status == BA_SETUP_COMPLETE) { 876 if (tid == tx_ba_stream_tbl_ptr->tid) { 877 dev_dbg(adapter->dev, 878 "Tx:Send delba to tid=%d, %pM\n", tid, 879 tx_ba_stream_tbl_ptr->ra); 880 mwifiex_send_delba(priv, 881 tx_ba_stream_tbl_ptr->tid, 882 tx_ba_stream_tbl_ptr->ra, 1); 883 return; 884 } 885 } 886 } 887} 888 889/* This function updates all the tx_win_size 890 */ 891void mwifiex_update_ampdu_txwinsize(struct mwifiex_adapter *adapter) 892{ 893 u8 i; 894 u32 tx_win_size; 895 struct mwifiex_private *priv; 896 897 for (i = 0; i < adapter->priv_num; i++) { 898 if (!adapter->priv[i]) 899 continue; 900 priv = adapter->priv[i]; 901 tx_win_size = priv->add_ba_param.tx_win_size; 902 903 if (priv->bss_type == MWIFIEX_BSS_TYPE_STA) 904 priv->add_ba_param.tx_win_size = 905 MWIFIEX_STA_AMPDU_DEF_TXWINSIZE; 906 907 if (priv->bss_type == MWIFIEX_BSS_TYPE_P2P) 908 priv->add_ba_param.tx_win_size = 909 MWIFIEX_STA_AMPDU_DEF_TXWINSIZE; 910 911 if (priv->bss_type == MWIFIEX_BSS_TYPE_UAP) 912 priv->add_ba_param.tx_win_size = 913 MWIFIEX_UAP_AMPDU_DEF_TXWINSIZE; 914 915 if (adapter->coex_win_size) { 916 if (adapter->coex_tx_win_size) 917 priv->add_ba_param.tx_win_size = 918 adapter->coex_tx_win_size; 919 } 920 921 if (tx_win_size != priv->add_ba_param.tx_win_size) { 922 if (!priv->media_connected) 923 continue; 924 for (i = 0; i < MAX_NUM_TID; i++) 925 mwifiex_send_delba_txbastream_tbl(priv, i); 926 } 927 } 928}