cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

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}