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 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 */
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, j;
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 (j = 0; j < MAX_NUM_TID; j++)
925				mwifiex_send_delba_txbastream_tbl(priv, j);
926		}
927	}
928}
929