1 /* 2 * Marvell Wireless LAN device driver: 802.11n 3 * 4 * Copyright (C) 2011-2014, Marvell International Ltd. 5 * 6 * This software file (the "File") is distributed by Marvell International 7 * Ltd. 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 */ 37 int 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 */ 82 static struct mwifiex_tx_ba_stream_tbl * 83 mwifiex_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 */ 108 int 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 ADDBA 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 */ 154 int 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 */ 214 int 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 */ 247 int 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 */ 280 int 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 */ 310 int 311 mwifiex_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 */ 476 static 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 */ 495 void 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 */ 513 void 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 */ 535 struct mwifiex_tx_ba_stream_tbl * 536 mwifiex_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 */ 556 void 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 */ 590 int 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 */ 652 int 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 delba.del_ba_param_set = cpu_to_le16(tid << DELBA_TID_POS); 661 662 del_ba_param_set = le16_to_cpu(delba.del_ba_param_set); 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 memcpy(&delba.peer_mac_addr, peer_mac, ETH_ALEN); 669 670 /* We don't wait for the response of this command */ 671 ret = mwifiex_send_cmd(priv, HostCmd_CMD_11N_DELBA, 672 HostCmd_ACT_GEN_SET, 0, &delba, false); 673 674 return ret; 675 } 676 677 /* 678 * This function sends delba to specific tid 679 */ 680 void mwifiex_11n_delba(struct mwifiex_private *priv, int tid) 681 { 682 struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr; 683 684 spin_lock_bh(&priv->rx_reorder_tbl_lock); 685 list_for_each_entry(rx_reor_tbl_ptr, &priv->rx_reorder_tbl_ptr, list) { 686 if (rx_reor_tbl_ptr->tid == tid) { 687 dev_dbg(priv->adapter->dev, 688 "Send delba to tid=%d, %pM\n", 689 tid, rx_reor_tbl_ptr->ta); 690 mwifiex_send_delba(priv, tid, rx_reor_tbl_ptr->ta, 0); 691 goto exit; 692 } 693 } 694 exit: 695 spin_unlock_bh(&priv->rx_reorder_tbl_lock); 696 } 697 698 /* 699 * This function handles the command response of a delete BA request. 700 */ 701 void mwifiex_11n_delete_ba_stream(struct mwifiex_private *priv, u8 *del_ba) 702 { 703 struct host_cmd_ds_11n_delba *cmd_del_ba = 704 (struct host_cmd_ds_11n_delba *) del_ba; 705 uint16_t del_ba_param_set = le16_to_cpu(cmd_del_ba->del_ba_param_set); 706 int tid; 707 708 tid = del_ba_param_set >> DELBA_TID_POS; 709 710 mwifiex_del_ba_tbl(priv, tid, cmd_del_ba->peer_mac_addr, 711 TYPE_DELBA_RECEIVE, INITIATOR_BIT(del_ba_param_set)); 712 } 713 714 /* 715 * This function retrieves the Rx reordering table. 716 */ 717 int mwifiex_get_rx_reorder_tbl(struct mwifiex_private *priv, 718 struct mwifiex_ds_rx_reorder_tbl *buf) 719 { 720 int i; 721 struct mwifiex_ds_rx_reorder_tbl *rx_reo_tbl = buf; 722 struct mwifiex_rx_reorder_tbl *rx_reorder_tbl_ptr; 723 int count = 0; 724 725 spin_lock_bh(&priv->rx_reorder_tbl_lock); 726 list_for_each_entry(rx_reorder_tbl_ptr, &priv->rx_reorder_tbl_ptr, 727 list) { 728 rx_reo_tbl->tid = (u16) rx_reorder_tbl_ptr->tid; 729 memcpy(rx_reo_tbl->ta, rx_reorder_tbl_ptr->ta, ETH_ALEN); 730 rx_reo_tbl->start_win = rx_reorder_tbl_ptr->start_win; 731 rx_reo_tbl->win_size = rx_reorder_tbl_ptr->win_size; 732 for (i = 0; i < rx_reorder_tbl_ptr->win_size; ++i) { 733 if (rx_reorder_tbl_ptr->rx_reorder_ptr[i]) 734 rx_reo_tbl->buffer[i] = true; 735 else 736 rx_reo_tbl->buffer[i] = false; 737 } 738 rx_reo_tbl++; 739 count++; 740 741 if (count >= MWIFIEX_MAX_RX_BASTREAM_SUPPORTED) 742 break; 743 } 744 spin_unlock_bh(&priv->rx_reorder_tbl_lock); 745 746 return count; 747 } 748 749 /* 750 * This function retrieves the Tx BA stream table. 751 */ 752 int mwifiex_get_tx_ba_stream_tbl(struct mwifiex_private *priv, 753 struct mwifiex_ds_tx_ba_stream_tbl *buf) 754 { 755 struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl; 756 struct mwifiex_ds_tx_ba_stream_tbl *rx_reo_tbl = buf; 757 int count = 0; 758 759 spin_lock_bh(&priv->tx_ba_stream_tbl_lock); 760 list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) { 761 rx_reo_tbl->tid = (u16) tx_ba_tsr_tbl->tid; 762 mwifiex_dbg(priv->adapter, DATA, "data: %s tid=%d\n", 763 __func__, rx_reo_tbl->tid); 764 memcpy(rx_reo_tbl->ra, tx_ba_tsr_tbl->ra, ETH_ALEN); 765 rx_reo_tbl->amsdu = tx_ba_tsr_tbl->amsdu; 766 rx_reo_tbl++; 767 count++; 768 if (count >= MWIFIEX_MAX_TX_BASTREAM_SUPPORTED) 769 break; 770 } 771 spin_unlock_bh(&priv->tx_ba_stream_tbl_lock); 772 773 return count; 774 } 775 776 /* 777 * This function retrieves the entry for specific tx BA stream table by RA and 778 * deletes it. 779 */ 780 void mwifiex_del_tx_ba_stream_tbl_by_ra(struct mwifiex_private *priv, u8 *ra) 781 { 782 struct mwifiex_tx_ba_stream_tbl *tbl, *tmp; 783 784 if (!ra) 785 return; 786 787 spin_lock_bh(&priv->tx_ba_stream_tbl_lock); 788 list_for_each_entry_safe(tbl, tmp, &priv->tx_ba_stream_tbl_ptr, list) 789 if (!memcmp(tbl->ra, ra, ETH_ALEN)) 790 mwifiex_11n_delete_tx_ba_stream_tbl_entry(priv, tbl); 791 spin_unlock_bh(&priv->tx_ba_stream_tbl_lock); 792 793 return; 794 } 795 796 /* This function initializes the BlockACK setup information for given 797 * mwifiex_private structure. 798 */ 799 void mwifiex_set_ba_params(struct mwifiex_private *priv) 800 { 801 priv->add_ba_param.timeout = MWIFIEX_DEFAULT_BLOCK_ACK_TIMEOUT; 802 803 if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) { 804 priv->add_ba_param.tx_win_size = 805 MWIFIEX_UAP_AMPDU_DEF_TXWINSIZE; 806 priv->add_ba_param.rx_win_size = 807 MWIFIEX_UAP_AMPDU_DEF_RXWINSIZE; 808 } else { 809 priv->add_ba_param.tx_win_size = 810 MWIFIEX_STA_AMPDU_DEF_TXWINSIZE; 811 priv->add_ba_param.rx_win_size = 812 MWIFIEX_STA_AMPDU_DEF_RXWINSIZE; 813 } 814 815 priv->add_ba_param.tx_amsdu = true; 816 priv->add_ba_param.rx_amsdu = true; 817 818 return; 819 } 820 821 u8 mwifiex_get_sec_chan_offset(int chan) 822 { 823 u8 sec_offset; 824 825 switch (chan) { 826 case 36: 827 case 44: 828 case 52: 829 case 60: 830 case 100: 831 case 108: 832 case 116: 833 case 124: 834 case 132: 835 case 140: 836 case 149: 837 case 157: 838 sec_offset = IEEE80211_HT_PARAM_CHA_SEC_ABOVE; 839 break; 840 case 40: 841 case 48: 842 case 56: 843 case 64: 844 case 104: 845 case 112: 846 case 120: 847 case 128: 848 case 136: 849 case 144: 850 case 153: 851 case 161: 852 sec_offset = IEEE80211_HT_PARAM_CHA_SEC_BELOW; 853 break; 854 case 165: 855 default: 856 sec_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE; 857 break; 858 } 859 860 return sec_offset; 861 } 862 863 /* This function will send DELBA to entries in the priv's 864 * Tx BA stream table 865 */ 866 static void 867 mwifiex_send_delba_txbastream_tbl(struct mwifiex_private *priv, u8 tid) 868 { 869 struct mwifiex_adapter *adapter = priv->adapter; 870 struct mwifiex_tx_ba_stream_tbl *tx_ba_stream_tbl_ptr; 871 872 list_for_each_entry(tx_ba_stream_tbl_ptr, 873 &priv->tx_ba_stream_tbl_ptr, list) { 874 if (tx_ba_stream_tbl_ptr->ba_status == BA_SETUP_COMPLETE) { 875 if (tid == tx_ba_stream_tbl_ptr->tid) { 876 dev_dbg(adapter->dev, 877 "Tx:Send delba to tid=%d, %pM\n", tid, 878 tx_ba_stream_tbl_ptr->ra); 879 mwifiex_send_delba(priv, 880 tx_ba_stream_tbl_ptr->tid, 881 tx_ba_stream_tbl_ptr->ra, 1); 882 return; 883 } 884 } 885 } 886 } 887 888 /* This function updates all the tx_win_size 889 */ 890 void mwifiex_update_ampdu_txwinsize(struct mwifiex_adapter *adapter) 891 { 892 u8 i; 893 u32 tx_win_size; 894 struct mwifiex_private *priv; 895 896 for (i = 0; i < adapter->priv_num; i++) { 897 if (!adapter->priv[i]) 898 continue; 899 priv = adapter->priv[i]; 900 tx_win_size = priv->add_ba_param.tx_win_size; 901 902 if (priv->bss_type == MWIFIEX_BSS_TYPE_STA) 903 priv->add_ba_param.tx_win_size = 904 MWIFIEX_STA_AMPDU_DEF_TXWINSIZE; 905 906 if (priv->bss_type == MWIFIEX_BSS_TYPE_P2P) 907 priv->add_ba_param.tx_win_size = 908 MWIFIEX_STA_AMPDU_DEF_TXWINSIZE; 909 910 if (priv->bss_type == MWIFIEX_BSS_TYPE_UAP) 911 priv->add_ba_param.tx_win_size = 912 MWIFIEX_UAP_AMPDU_DEF_TXWINSIZE; 913 914 if (adapter->coex_win_size) { 915 if (adapter->coex_tx_win_size) 916 priv->add_ba_param.tx_win_size = 917 adapter->coex_tx_win_size; 918 } 919 920 if (tx_win_size != priv->add_ba_param.tx_win_size) { 921 if (!priv->media_connected) 922 continue; 923 for (i = 0; i < MAX_NUM_TID; i++) 924 mwifiex_send_delba_txbastream_tbl(priv, i); 925 } 926 } 927 } 928