1/*
2 * NXP Wireless LAN device driver: station command handling
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#include "11ac.h"
28
29static bool drcs;
30module_param(drcs, bool, 0644);
31MODULE_PARM_DESC(drcs, "multi-channel operation:1, single-channel operation:0");
32
33static bool disable_auto_ds;
34module_param(disable_auto_ds, bool, 0);
35MODULE_PARM_DESC(disable_auto_ds,
36		 "deepsleep enabled=0(default), deepsleep disabled=1");
37/*
38 * This function prepares command to set/get RSSI information.
39 *
40 * Preparation includes -
41 *      - Setting command ID, action and proper size
42 *      - Setting data/beacon average factors
43 *      - Resetting SNR/NF/RSSI values in private structure
44 *      - Ensuring correct endian-ness
45 */
46static int
47mwifiex_cmd_802_11_rssi_info(struct mwifiex_private *priv,
48			     struct host_cmd_ds_command *cmd, u16 cmd_action)
49{
50	cmd->command = cpu_to_le16(HostCmd_CMD_RSSI_INFO);
51	cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_rssi_info) +
52				S_DS_GEN);
53	cmd->params.rssi_info.action = cpu_to_le16(cmd_action);
54	cmd->params.rssi_info.ndata = cpu_to_le16(priv->data_avg_factor);
55	cmd->params.rssi_info.nbcn = cpu_to_le16(priv->bcn_avg_factor);
56
57	/* Reset SNR/NF/RSSI values in private structure */
58	priv->data_rssi_last = 0;
59	priv->data_nf_last = 0;
60	priv->data_rssi_avg = 0;
61	priv->data_nf_avg = 0;
62	priv->bcn_rssi_last = 0;
63	priv->bcn_nf_last = 0;
64	priv->bcn_rssi_avg = 0;
65	priv->bcn_nf_avg = 0;
66
67	return 0;
68}
69
70/*
71 * This function prepares command to set MAC control.
72 *
73 * Preparation includes -
74 *      - Setting command ID, action and proper size
75 *      - Ensuring correct endian-ness
76 */
77static int mwifiex_cmd_mac_control(struct mwifiex_private *priv,
78				   struct host_cmd_ds_command *cmd,
79				   u16 cmd_action, u32 *action)
80{
81	struct host_cmd_ds_mac_control *mac_ctrl = &cmd->params.mac_ctrl;
82
83	if (cmd_action != HostCmd_ACT_GEN_SET) {
84		mwifiex_dbg(priv->adapter, ERROR,
85			    "mac_control: only support set cmd\n");
86		return -1;
87	}
88
89	cmd->command = cpu_to_le16(HostCmd_CMD_MAC_CONTROL);
90	cmd->size =
91		cpu_to_le16(sizeof(struct host_cmd_ds_mac_control) + S_DS_GEN);
92	mac_ctrl->action = cpu_to_le32(*action);
93
94	return 0;
95}
96
97/*
98 * This function prepares command to set/get SNMP MIB.
99 *
100 * Preparation includes -
101 *      - Setting command ID, action and proper size
102 *      - Setting SNMP MIB OID number and value
103 *        (as required)
104 *      - Ensuring correct endian-ness
105 *
106 * The following SNMP MIB OIDs are supported -
107 *      - FRAG_THRESH_I     : Fragmentation threshold
108 *      - RTS_THRESH_I      : RTS threshold
109 *      - SHORT_RETRY_LIM_I : Short retry limit
110 *      - DOT11D_I          : 11d support
111 */
112static int mwifiex_cmd_802_11_snmp_mib(struct mwifiex_private *priv,
113				       struct host_cmd_ds_command *cmd,
114				       u16 cmd_action, u32 cmd_oid,
115				       u16 *ul_temp)
116{
117	struct host_cmd_ds_802_11_snmp_mib *snmp_mib = &cmd->params.smib;
118
119	mwifiex_dbg(priv->adapter, CMD,
120		    "cmd: SNMP_CMD: cmd_oid = 0x%x\n", cmd_oid);
121	cmd->command = cpu_to_le16(HostCmd_CMD_802_11_SNMP_MIB);
122	cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_snmp_mib)
123				- 1 + S_DS_GEN);
124
125	snmp_mib->oid = cpu_to_le16((u16)cmd_oid);
126	if (cmd_action == HostCmd_ACT_GEN_GET) {
127		snmp_mib->query_type = cpu_to_le16(HostCmd_ACT_GEN_GET);
128		snmp_mib->buf_size = cpu_to_le16(MAX_SNMP_BUF_SIZE);
129		le16_unaligned_add_cpu(&cmd->size, MAX_SNMP_BUF_SIZE);
130	} else if (cmd_action == HostCmd_ACT_GEN_SET) {
131		snmp_mib->query_type = cpu_to_le16(HostCmd_ACT_GEN_SET);
132		snmp_mib->buf_size = cpu_to_le16(sizeof(u16));
133		put_unaligned_le16(*ul_temp, snmp_mib->value);
134		le16_unaligned_add_cpu(&cmd->size, sizeof(u16));
135	}
136
137	mwifiex_dbg(priv->adapter, CMD,
138		    "cmd: SNMP_CMD: Action=0x%x, OID=0x%x,\t"
139		    "OIDSize=0x%x, Value=0x%x\n",
140		    cmd_action, cmd_oid, le16_to_cpu(snmp_mib->buf_size),
141		    get_unaligned_le16(snmp_mib->value));
142	return 0;
143}
144
145/*
146 * This function prepares command to get log.
147 *
148 * Preparation includes -
149 *      - Setting command ID and proper size
150 *      - Ensuring correct endian-ness
151 */
152static int
153mwifiex_cmd_802_11_get_log(struct host_cmd_ds_command *cmd)
154{
155	cmd->command = cpu_to_le16(HostCmd_CMD_802_11_GET_LOG);
156	cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_get_log) +
157				S_DS_GEN);
158	return 0;
159}
160
161/*
162 * This function prepares command to set/get Tx data rate configuration.
163 *
164 * Preparation includes -
165 *      - Setting command ID, action and proper size
166 *      - Setting configuration index, rate scope and rate drop pattern
167 *        parameters (as required)
168 *      - Ensuring correct endian-ness
169 */
170static int mwifiex_cmd_tx_rate_cfg(struct mwifiex_private *priv,
171				   struct host_cmd_ds_command *cmd,
172				   u16 cmd_action, u16 *pbitmap_rates)
173{
174	struct host_cmd_ds_tx_rate_cfg *rate_cfg = &cmd->params.tx_rate_cfg;
175	struct mwifiex_rate_scope *rate_scope;
176	struct mwifiex_rate_drop_pattern *rate_drop;
177	u32 i;
178
179	cmd->command = cpu_to_le16(HostCmd_CMD_TX_RATE_CFG);
180
181	rate_cfg->action = cpu_to_le16(cmd_action);
182	rate_cfg->cfg_index = 0;
183
184	rate_scope = (struct mwifiex_rate_scope *) ((u8 *) rate_cfg +
185		      sizeof(struct host_cmd_ds_tx_rate_cfg));
186	rate_scope->type = cpu_to_le16(TLV_TYPE_RATE_SCOPE);
187	rate_scope->length = cpu_to_le16
188		(sizeof(*rate_scope) - sizeof(struct mwifiex_ie_types_header));
189	if (pbitmap_rates != NULL) {
190		rate_scope->hr_dsss_rate_bitmap = cpu_to_le16(pbitmap_rates[0]);
191		rate_scope->ofdm_rate_bitmap = cpu_to_le16(pbitmap_rates[1]);
192		for (i = 0; i < ARRAY_SIZE(rate_scope->ht_mcs_rate_bitmap); i++)
193			rate_scope->ht_mcs_rate_bitmap[i] =
194				cpu_to_le16(pbitmap_rates[2 + i]);
195		if (priv->adapter->fw_api_ver == MWIFIEX_FW_V15) {
196			for (i = 0;
197			     i < ARRAY_SIZE(rate_scope->vht_mcs_rate_bitmap);
198			     i++)
199				rate_scope->vht_mcs_rate_bitmap[i] =
200					cpu_to_le16(pbitmap_rates[10 + i]);
201		}
202	} else {
203		rate_scope->hr_dsss_rate_bitmap =
204			cpu_to_le16(priv->bitmap_rates[0]);
205		rate_scope->ofdm_rate_bitmap =
206			cpu_to_le16(priv->bitmap_rates[1]);
207		for (i = 0; i < ARRAY_SIZE(rate_scope->ht_mcs_rate_bitmap); i++)
208			rate_scope->ht_mcs_rate_bitmap[i] =
209				cpu_to_le16(priv->bitmap_rates[2 + i]);
210		if (priv->adapter->fw_api_ver == MWIFIEX_FW_V15) {
211			for (i = 0;
212			     i < ARRAY_SIZE(rate_scope->vht_mcs_rate_bitmap);
213			     i++)
214				rate_scope->vht_mcs_rate_bitmap[i] =
215					cpu_to_le16(priv->bitmap_rates[10 + i]);
216		}
217	}
218
219	rate_drop = (struct mwifiex_rate_drop_pattern *) ((u8 *) rate_scope +
220					     sizeof(struct mwifiex_rate_scope));
221	rate_drop->type = cpu_to_le16(TLV_TYPE_RATE_DROP_CONTROL);
222	rate_drop->length = cpu_to_le16(sizeof(rate_drop->rate_drop_mode));
223	rate_drop->rate_drop_mode = 0;
224
225	cmd->size =
226		cpu_to_le16(S_DS_GEN + sizeof(struct host_cmd_ds_tx_rate_cfg) +
227			    sizeof(struct mwifiex_rate_scope) +
228			    sizeof(struct mwifiex_rate_drop_pattern));
229
230	return 0;
231}
232
233/*
234 * This function prepares command to set/get Tx power configuration.
235 *
236 * Preparation includes -
237 *      - Setting command ID, action and proper size
238 *      - Setting Tx power mode, power group TLV
239 *        (as required)
240 *      - Ensuring correct endian-ness
241 */
242static int mwifiex_cmd_tx_power_cfg(struct host_cmd_ds_command *cmd,
243				    u16 cmd_action,
244				    struct host_cmd_ds_txpwr_cfg *txp)
245{
246	struct mwifiex_types_power_group *pg_tlv;
247	struct host_cmd_ds_txpwr_cfg *cmd_txp_cfg = &cmd->params.txp_cfg;
248
249	cmd->command = cpu_to_le16(HostCmd_CMD_TXPWR_CFG);
250	cmd->size =
251		cpu_to_le16(S_DS_GEN + sizeof(struct host_cmd_ds_txpwr_cfg));
252	switch (cmd_action) {
253	case HostCmd_ACT_GEN_SET:
254		if (txp->mode) {
255			pg_tlv = (struct mwifiex_types_power_group
256				  *) ((unsigned long) txp +
257				     sizeof(struct host_cmd_ds_txpwr_cfg));
258			memmove(cmd_txp_cfg, txp,
259				sizeof(struct host_cmd_ds_txpwr_cfg) +
260				sizeof(struct mwifiex_types_power_group) +
261				le16_to_cpu(pg_tlv->length));
262
263			pg_tlv = (struct mwifiex_types_power_group *) ((u8 *)
264				  cmd_txp_cfg +
265				  sizeof(struct host_cmd_ds_txpwr_cfg));
266			cmd->size = cpu_to_le16(le16_to_cpu(cmd->size) +
267				  sizeof(struct mwifiex_types_power_group) +
268				  le16_to_cpu(pg_tlv->length));
269		} else {
270			memmove(cmd_txp_cfg, txp, sizeof(*txp));
271		}
272		cmd_txp_cfg->action = cpu_to_le16(cmd_action);
273		break;
274	case HostCmd_ACT_GEN_GET:
275		cmd_txp_cfg->action = cpu_to_le16(cmd_action);
276		break;
277	}
278
279	return 0;
280}
281
282/*
283 * This function prepares command to get RF Tx power.
284 */
285static int mwifiex_cmd_rf_tx_power(struct mwifiex_private *priv,
286				   struct host_cmd_ds_command *cmd,
287				   u16 cmd_action, void *data_buf)
288{
289	struct host_cmd_ds_rf_tx_pwr *txp = &cmd->params.txp;
290
291	cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_rf_tx_pwr)
292				+ S_DS_GEN);
293	cmd->command = cpu_to_le16(HostCmd_CMD_RF_TX_PWR);
294	txp->action = cpu_to_le16(cmd_action);
295
296	return 0;
297}
298
299/*
300 * This function prepares command to set rf antenna.
301 */
302static int mwifiex_cmd_rf_antenna(struct mwifiex_private *priv,
303				  struct host_cmd_ds_command *cmd,
304				  u16 cmd_action,
305				  struct mwifiex_ds_ant_cfg *ant_cfg)
306{
307	struct host_cmd_ds_rf_ant_mimo *ant_mimo = &cmd->params.ant_mimo;
308	struct host_cmd_ds_rf_ant_siso *ant_siso = &cmd->params.ant_siso;
309
310	cmd->command = cpu_to_le16(HostCmd_CMD_RF_ANTENNA);
311
312	switch (cmd_action) {
313	case HostCmd_ACT_GEN_SET:
314		if (priv->adapter->hw_dev_mcs_support == HT_STREAM_2X2) {
315			cmd->size = cpu_to_le16(sizeof(struct
316						host_cmd_ds_rf_ant_mimo)
317						+ S_DS_GEN);
318			ant_mimo->action_tx = cpu_to_le16(HostCmd_ACT_SET_TX);
319			ant_mimo->tx_ant_mode = cpu_to_le16((u16)ant_cfg->
320							    tx_ant);
321			ant_mimo->action_rx = cpu_to_le16(HostCmd_ACT_SET_RX);
322			ant_mimo->rx_ant_mode = cpu_to_le16((u16)ant_cfg->
323							    rx_ant);
324		} else {
325			cmd->size = cpu_to_le16(sizeof(struct
326						host_cmd_ds_rf_ant_siso) +
327						S_DS_GEN);
328			ant_siso->action = cpu_to_le16(HostCmd_ACT_SET_BOTH);
329			ant_siso->ant_mode = cpu_to_le16((u16)ant_cfg->tx_ant);
330		}
331		break;
332	case HostCmd_ACT_GEN_GET:
333		if (priv->adapter->hw_dev_mcs_support == HT_STREAM_2X2) {
334			cmd->size = cpu_to_le16(sizeof(struct
335						host_cmd_ds_rf_ant_mimo) +
336						S_DS_GEN);
337			ant_mimo->action_tx = cpu_to_le16(HostCmd_ACT_GET_TX);
338			ant_mimo->action_rx = cpu_to_le16(HostCmd_ACT_GET_RX);
339		} else {
340			cmd->size = cpu_to_le16(sizeof(struct
341						host_cmd_ds_rf_ant_siso) +
342						S_DS_GEN);
343			ant_siso->action = cpu_to_le16(HostCmd_ACT_GET_BOTH);
344		}
345		break;
346	}
347	return 0;
348}
349
350/*
351 * This function prepares command to set Host Sleep configuration.
352 *
353 * Preparation includes -
354 *      - Setting command ID and proper size
355 *      - Setting Host Sleep action, conditions, ARP filters
356 *        (as required)
357 *      - Ensuring correct endian-ness
358 */
359static int
360mwifiex_cmd_802_11_hs_cfg(struct mwifiex_private *priv,
361			  struct host_cmd_ds_command *cmd,
362			  u16 cmd_action,
363			  struct mwifiex_hs_config_param *hscfg_param)
364{
365	struct mwifiex_adapter *adapter = priv->adapter;
366	struct host_cmd_ds_802_11_hs_cfg_enh *hs_cfg = &cmd->params.opt_hs_cfg;
367	u8 *tlv = (u8 *)hs_cfg + sizeof(struct host_cmd_ds_802_11_hs_cfg_enh);
368	struct mwifiex_ps_param_in_hs *psparam_tlv = NULL;
369	bool hs_activate = false;
370	u16 size;
371
372	if (!hscfg_param)
373		/* New Activate command */
374		hs_activate = true;
375	cmd->command = cpu_to_le16(HostCmd_CMD_802_11_HS_CFG_ENH);
376
377	if (!hs_activate &&
378	    (hscfg_param->conditions != cpu_to_le32(HS_CFG_CANCEL)) &&
379	    ((adapter->arp_filter_size > 0) &&
380	     (adapter->arp_filter_size <= ARP_FILTER_MAX_BUF_SIZE))) {
381		mwifiex_dbg(adapter, CMD,
382			    "cmd: Attach %d bytes ArpFilter to HSCfg cmd\n",
383			    adapter->arp_filter_size);
384		memcpy(((u8 *) hs_cfg) +
385		       sizeof(struct host_cmd_ds_802_11_hs_cfg_enh),
386		       adapter->arp_filter, adapter->arp_filter_size);
387		size = adapter->arp_filter_size +
388			sizeof(struct host_cmd_ds_802_11_hs_cfg_enh)
389			+ S_DS_GEN;
390		tlv = (u8 *)hs_cfg
391			+ sizeof(struct host_cmd_ds_802_11_hs_cfg_enh)
392			+ adapter->arp_filter_size;
393	} else {
394		size = S_DS_GEN + sizeof(struct host_cmd_ds_802_11_hs_cfg_enh);
395	}
396	if (hs_activate) {
397		hs_cfg->action = cpu_to_le16(HS_ACTIVATE);
398		hs_cfg->params.hs_activate.resp_ctrl = cpu_to_le16(RESP_NEEDED);
399	} else {
400		hs_cfg->action = cpu_to_le16(HS_CONFIGURE);
401		hs_cfg->params.hs_config.conditions = hscfg_param->conditions;
402		hs_cfg->params.hs_config.gpio = hscfg_param->gpio;
403		hs_cfg->params.hs_config.gap = hscfg_param->gap;
404
405		size += sizeof(struct mwifiex_ps_param_in_hs);
406		psparam_tlv = (struct mwifiex_ps_param_in_hs *)tlv;
407		psparam_tlv->header.type =
408			cpu_to_le16(TLV_TYPE_PS_PARAMS_IN_HS);
409		psparam_tlv->header.len =
410			cpu_to_le16(sizeof(struct mwifiex_ps_param_in_hs)
411				- sizeof(struct mwifiex_ie_types_header));
412		psparam_tlv->hs_wake_int = cpu_to_le32(HS_DEF_WAKE_INTERVAL);
413		psparam_tlv->hs_inact_timeout =
414			cpu_to_le32(HS_DEF_INACTIVITY_TIMEOUT);
415
416		mwifiex_dbg(adapter, CMD,
417			    "cmd: HS_CFG_CMD: condition:0x%x gpio:0x%x gap:0x%x\n",
418			    hs_cfg->params.hs_config.conditions,
419			    hs_cfg->params.hs_config.gpio,
420			    hs_cfg->params.hs_config.gap);
421	}
422	cmd->size = cpu_to_le16(size);
423
424	return 0;
425}
426
427/*
428 * This function prepares command to set/get MAC address.
429 *
430 * Preparation includes -
431 *      - Setting command ID, action and proper size
432 *      - Setting MAC address (for SET only)
433 *      - Ensuring correct endian-ness
434 */
435static int mwifiex_cmd_802_11_mac_address(struct mwifiex_private *priv,
436					  struct host_cmd_ds_command *cmd,
437					  u16 cmd_action)
438{
439	cmd->command = cpu_to_le16(HostCmd_CMD_802_11_MAC_ADDRESS);
440	cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_mac_address) +
441				S_DS_GEN);
442	cmd->result = 0;
443
444	cmd->params.mac_addr.action = cpu_to_le16(cmd_action);
445
446	if (cmd_action == HostCmd_ACT_GEN_SET)
447		memcpy(cmd->params.mac_addr.mac_addr, priv->curr_addr,
448		       ETH_ALEN);
449	return 0;
450}
451
452/*
453 * This function prepares command to set MAC multicast address.
454 *
455 * Preparation includes -
456 *      - Setting command ID, action and proper size
457 *      - Setting MAC multicast address
458 *      - Ensuring correct endian-ness
459 */
460static int
461mwifiex_cmd_mac_multicast_adr(struct host_cmd_ds_command *cmd,
462			      u16 cmd_action,
463			      struct mwifiex_multicast_list *mcast_list)
464{
465	struct host_cmd_ds_mac_multicast_adr *mcast_addr = &cmd->params.mc_addr;
466
467	cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_mac_multicast_adr) +
468				S_DS_GEN);
469	cmd->command = cpu_to_le16(HostCmd_CMD_MAC_MULTICAST_ADR);
470
471	mcast_addr->action = cpu_to_le16(cmd_action);
472	mcast_addr->num_of_adrs =
473		cpu_to_le16((u16) mcast_list->num_multicast_addr);
474	memcpy(mcast_addr->mac_list, mcast_list->mac_list,
475	       mcast_list->num_multicast_addr * ETH_ALEN);
476
477	return 0;
478}
479
480/*
481 * This function prepares command to deauthenticate.
482 *
483 * Preparation includes -
484 *      - Setting command ID and proper size
485 *      - Setting AP MAC address and reason code
486 *      - Ensuring correct endian-ness
487 */
488static int mwifiex_cmd_802_11_deauthenticate(struct mwifiex_private *priv,
489					     struct host_cmd_ds_command *cmd,
490					     u8 *mac)
491{
492	struct host_cmd_ds_802_11_deauthenticate *deauth = &cmd->params.deauth;
493
494	cmd->command = cpu_to_le16(HostCmd_CMD_802_11_DEAUTHENTICATE);
495	cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_deauthenticate)
496				+ S_DS_GEN);
497
498	/* Set AP MAC address */
499	memcpy(deauth->mac_addr, mac, ETH_ALEN);
500
501	mwifiex_dbg(priv->adapter, CMD, "cmd: Deauth: %pM\n", deauth->mac_addr);
502
503	deauth->reason_code = cpu_to_le16(WLAN_REASON_DEAUTH_LEAVING);
504
505	return 0;
506}
507
508/*
509 * This function prepares command to stop Ad-Hoc network.
510 *
511 * Preparation includes -
512 *      - Setting command ID and proper size
513 *      - Ensuring correct endian-ness
514 */
515static int mwifiex_cmd_802_11_ad_hoc_stop(struct host_cmd_ds_command *cmd)
516{
517	cmd->command = cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_STOP);
518	cmd->size = cpu_to_le16(S_DS_GEN);
519	return 0;
520}
521
522/*
523 * This function sets WEP key(s) to key parameter TLV(s).
524 *
525 * Multi-key parameter TLVs are supported, so we can send multiple
526 * WEP keys in a single buffer.
527 */
528static int
529mwifiex_set_keyparamset_wep(struct mwifiex_private *priv,
530			    struct mwifiex_ie_type_key_param_set *key_param_set,
531			    u16 *key_param_len)
532{
533	int cur_key_param_len;
534	u8 i;
535
536	/* Multi-key_param_set TLV is supported */
537	for (i = 0; i < NUM_WEP_KEYS; i++) {
538		if ((priv->wep_key[i].key_length == WLAN_KEY_LEN_WEP40) ||
539		    (priv->wep_key[i].key_length == WLAN_KEY_LEN_WEP104)) {
540			key_param_set->type =
541				cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
542/* Key_param_set WEP fixed length */
543#define KEYPARAMSET_WEP_FIXED_LEN 8
544			key_param_set->length = cpu_to_le16((u16)
545					(priv->wep_key[i].
546					 key_length +
547					 KEYPARAMSET_WEP_FIXED_LEN));
548			key_param_set->key_type_id =
549				cpu_to_le16(KEY_TYPE_ID_WEP);
550			key_param_set->key_info =
551				cpu_to_le16(KEY_ENABLED | KEY_UNICAST |
552					    KEY_MCAST);
553			key_param_set->key_len =
554				cpu_to_le16(priv->wep_key[i].key_length);
555			/* Set WEP key index */
556			key_param_set->key[0] = i;
557			/* Set default Tx key flag */
558			if (i ==
559			    (priv->
560			     wep_key_curr_index & HostCmd_WEP_KEY_INDEX_MASK))
561				key_param_set->key[1] = 1;
562			else
563				key_param_set->key[1] = 0;
564			memmove(&key_param_set->key[2],
565				priv->wep_key[i].key_material,
566				priv->wep_key[i].key_length);
567
568			cur_key_param_len = priv->wep_key[i].key_length +
569				KEYPARAMSET_WEP_FIXED_LEN +
570				sizeof(struct mwifiex_ie_types_header);
571			*key_param_len += (u16) cur_key_param_len;
572			key_param_set =
573				(struct mwifiex_ie_type_key_param_set *)
574						((u8 *)key_param_set +
575						 cur_key_param_len);
576		} else if (!priv->wep_key[i].key_length) {
577			continue;
578		} else {
579			mwifiex_dbg(priv->adapter, ERROR,
580				    "key%d Length = %d is incorrect\n",
581				    (i + 1), priv->wep_key[i].key_length);
582			return -1;
583		}
584	}
585
586	return 0;
587}
588
589/* This function populates key material v2 command
590 * to set network key for AES & CMAC AES.
591 */
592static int mwifiex_set_aes_key_v2(struct mwifiex_private *priv,
593				  struct host_cmd_ds_command *cmd,
594				  struct mwifiex_ds_encrypt_key *enc_key,
595				  struct host_cmd_ds_802_11_key_material_v2 *km)
596{
597	struct mwifiex_adapter *adapter = priv->adapter;
598	u16 size, len = KEY_PARAMS_FIXED_LEN;
599
600	if (enc_key->is_igtk_key) {
601		mwifiex_dbg(adapter, INFO,
602			    "%s: Set CMAC AES Key\n", __func__);
603		if (enc_key->is_rx_seq_valid)
604			memcpy(km->key_param_set.key_params.cmac_aes.ipn,
605			       enc_key->pn, enc_key->pn_len);
606		km->key_param_set.key_info &= cpu_to_le16(~KEY_MCAST);
607		km->key_param_set.key_info |= cpu_to_le16(KEY_IGTK);
608		km->key_param_set.key_type = KEY_TYPE_ID_AES_CMAC;
609		km->key_param_set.key_params.cmac_aes.key_len =
610					  cpu_to_le16(enc_key->key_len);
611		memcpy(km->key_param_set.key_params.cmac_aes.key,
612		       enc_key->key_material, enc_key->key_len);
613		len += sizeof(struct mwifiex_cmac_aes_param);
614	} else if (enc_key->is_igtk_def_key) {
615		mwifiex_dbg(adapter, INFO,
616			    "%s: Set CMAC default Key index\n", __func__);
617		km->key_param_set.key_type = KEY_TYPE_ID_AES_CMAC_DEF;
618		km->key_param_set.key_idx = enc_key->key_index & KEY_INDEX_MASK;
619	} else {
620		mwifiex_dbg(adapter, INFO,
621			    "%s: Set AES Key\n", __func__);
622		if (enc_key->is_rx_seq_valid)
623			memcpy(km->key_param_set.key_params.aes.pn,
624			       enc_key->pn, enc_key->pn_len);
625		km->key_param_set.key_type = KEY_TYPE_ID_AES;
626		km->key_param_set.key_params.aes.key_len =
627					  cpu_to_le16(enc_key->key_len);
628		memcpy(km->key_param_set.key_params.aes.key,
629		       enc_key->key_material, enc_key->key_len);
630		len += sizeof(struct mwifiex_aes_param);
631	}
632
633	km->key_param_set.len = cpu_to_le16(len);
634	size = len + sizeof(struct mwifiex_ie_types_header) +
635	       sizeof(km->action) + S_DS_GEN;
636	cmd->size = cpu_to_le16(size);
637
638	return 0;
639}
640
641/* This function prepares command to set/get/reset network key(s).
642 * This function prepares key material command for V2 format.
643 * Preparation includes -
644 *      - Setting command ID, action and proper size
645 *      - Setting WEP keys, WAPI keys or WPA keys along with required
646 *        encryption (TKIP, AES) (as required)
647 *      - Ensuring correct endian-ness
648 */
649static int
650mwifiex_cmd_802_11_key_material_v2(struct mwifiex_private *priv,
651				   struct host_cmd_ds_command *cmd,
652				   u16 cmd_action, u32 cmd_oid,
653				   struct mwifiex_ds_encrypt_key *enc_key)
654{
655	struct mwifiex_adapter *adapter = priv->adapter;
656	u8 *mac = enc_key->mac_addr;
657	u16 key_info, len = KEY_PARAMS_FIXED_LEN;
658	struct host_cmd_ds_802_11_key_material_v2 *km =
659						&cmd->params.key_material_v2;
660
661	cmd->command = cpu_to_le16(HostCmd_CMD_802_11_KEY_MATERIAL);
662	km->action = cpu_to_le16(cmd_action);
663
664	if (cmd_action == HostCmd_ACT_GEN_GET) {
665		mwifiex_dbg(adapter, INFO, "%s: Get key\n", __func__);
666		km->key_param_set.key_idx =
667					enc_key->key_index & KEY_INDEX_MASK;
668		km->key_param_set.type = cpu_to_le16(TLV_TYPE_KEY_PARAM_V2);
669		km->key_param_set.len = cpu_to_le16(KEY_PARAMS_FIXED_LEN);
670		memcpy(km->key_param_set.mac_addr, mac, ETH_ALEN);
671
672		if (enc_key->key_index & MWIFIEX_KEY_INDEX_UNICAST)
673			key_info = KEY_UNICAST;
674		else
675			key_info = KEY_MCAST;
676
677		if (enc_key->is_igtk_key)
678			key_info |= KEY_IGTK;
679
680		km->key_param_set.key_info = cpu_to_le16(key_info);
681
682		cmd->size = cpu_to_le16(sizeof(struct mwifiex_ie_types_header) +
683					S_DS_GEN + KEY_PARAMS_FIXED_LEN +
684					sizeof(km->action));
685		return 0;
686	}
687
688	memset(&km->key_param_set, 0,
689	       sizeof(struct mwifiex_ie_type_key_param_set_v2));
690
691	if (enc_key->key_disable) {
692		mwifiex_dbg(adapter, INFO, "%s: Remove key\n", __func__);
693		km->action = cpu_to_le16(HostCmd_ACT_GEN_REMOVE);
694		km->key_param_set.type = cpu_to_le16(TLV_TYPE_KEY_PARAM_V2);
695		km->key_param_set.len = cpu_to_le16(KEY_PARAMS_FIXED_LEN);
696		km->key_param_set.key_idx = enc_key->key_index & KEY_INDEX_MASK;
697		key_info = KEY_MCAST | KEY_UNICAST;
698		km->key_param_set.key_info = cpu_to_le16(key_info);
699		memcpy(km->key_param_set.mac_addr, mac, ETH_ALEN);
700		cmd->size = cpu_to_le16(sizeof(struct mwifiex_ie_types_header) +
701					S_DS_GEN + KEY_PARAMS_FIXED_LEN +
702					sizeof(km->action));
703		return 0;
704	}
705
706	km->action = cpu_to_le16(HostCmd_ACT_GEN_SET);
707	km->key_param_set.key_idx = enc_key->key_index & KEY_INDEX_MASK;
708	km->key_param_set.type = cpu_to_le16(TLV_TYPE_KEY_PARAM_V2);
709	key_info = KEY_ENABLED;
710	memcpy(km->key_param_set.mac_addr, mac, ETH_ALEN);
711
712	if (enc_key->key_len <= WLAN_KEY_LEN_WEP104) {
713		mwifiex_dbg(adapter, INFO, "%s: Set WEP Key\n", __func__);
714		len += sizeof(struct mwifiex_wep_param);
715		km->key_param_set.len = cpu_to_le16(len);
716		km->key_param_set.key_type = KEY_TYPE_ID_WEP;
717
718		if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) {
719				key_info |= KEY_MCAST | KEY_UNICAST;
720		} else {
721			if (enc_key->is_current_wep_key) {
722				key_info |= KEY_MCAST | KEY_UNICAST;
723				if (km->key_param_set.key_idx ==
724				    (priv->wep_key_curr_index & KEY_INDEX_MASK))
725					key_info |= KEY_DEFAULT;
726			} else {
727				if (is_broadcast_ether_addr(mac))
728					key_info |= KEY_MCAST;
729				else
730					key_info |= KEY_UNICAST | KEY_DEFAULT;
731			}
732		}
733		km->key_param_set.key_info = cpu_to_le16(key_info);
734
735		km->key_param_set.key_params.wep.key_len =
736						  cpu_to_le16(enc_key->key_len);
737		memcpy(km->key_param_set.key_params.wep.key,
738		       enc_key->key_material, enc_key->key_len);
739
740		cmd->size = cpu_to_le16(sizeof(struct mwifiex_ie_types_header) +
741					len + sizeof(km->action) + S_DS_GEN);
742		return 0;
743	}
744
745	if (is_broadcast_ether_addr(mac))
746		key_info |= KEY_MCAST | KEY_RX_KEY;
747	else
748		key_info |= KEY_UNICAST | KEY_TX_KEY | KEY_RX_KEY;
749
750	if (enc_key->is_wapi_key) {
751		mwifiex_dbg(adapter, INFO, "%s: Set WAPI Key\n", __func__);
752		km->key_param_set.key_type = KEY_TYPE_ID_WAPI;
753		memcpy(km->key_param_set.key_params.wapi.pn, enc_key->pn,
754		       PN_LEN);
755		km->key_param_set.key_params.wapi.key_len =
756						cpu_to_le16(enc_key->key_len);
757		memcpy(km->key_param_set.key_params.wapi.key,
758		       enc_key->key_material, enc_key->key_len);
759		if (is_broadcast_ether_addr(mac))
760			priv->sec_info.wapi_key_on = true;
761
762		if (!priv->sec_info.wapi_key_on)
763			key_info |= KEY_DEFAULT;
764		km->key_param_set.key_info = cpu_to_le16(key_info);
765
766		len += sizeof(struct mwifiex_wapi_param);
767		km->key_param_set.len = cpu_to_le16(len);
768		cmd->size = cpu_to_le16(sizeof(struct mwifiex_ie_types_header) +
769					len + sizeof(km->action) + S_DS_GEN);
770		return 0;
771	}
772
773	if (priv->bss_mode == NL80211_IFTYPE_ADHOC) {
774		key_info |= KEY_DEFAULT;
775		/* Enable unicast bit for WPA-NONE/ADHOC_AES */
776		if (!priv->sec_info.wpa2_enabled &&
777		    !is_broadcast_ether_addr(mac))
778			key_info |= KEY_UNICAST;
779	} else {
780		/* Enable default key for WPA/WPA2 */
781		if (!priv->wpa_is_gtk_set)
782			key_info |= KEY_DEFAULT;
783	}
784
785	km->key_param_set.key_info = cpu_to_le16(key_info);
786
787	if (enc_key->key_len == WLAN_KEY_LEN_CCMP)
788		return mwifiex_set_aes_key_v2(priv, cmd, enc_key, km);
789
790	if (enc_key->key_len == WLAN_KEY_LEN_TKIP) {
791		mwifiex_dbg(adapter, INFO,
792			    "%s: Set TKIP Key\n", __func__);
793		if (enc_key->is_rx_seq_valid)
794			memcpy(km->key_param_set.key_params.tkip.pn,
795			       enc_key->pn, enc_key->pn_len);
796		km->key_param_set.key_type = KEY_TYPE_ID_TKIP;
797		km->key_param_set.key_params.tkip.key_len =
798						cpu_to_le16(enc_key->key_len);
799		memcpy(km->key_param_set.key_params.tkip.key,
800		       enc_key->key_material, enc_key->key_len);
801
802		len += sizeof(struct mwifiex_tkip_param);
803		km->key_param_set.len = cpu_to_le16(len);
804		cmd->size = cpu_to_le16(sizeof(struct mwifiex_ie_types_header) +
805					len + sizeof(km->action) + S_DS_GEN);
806	}
807
808	return 0;
809}
810
811/*
812 * This function prepares command to set/get/reset network key(s).
813 * This function prepares key material command for V1 format.
814 *
815 * Preparation includes -
816 *      - Setting command ID, action and proper size
817 *      - Setting WEP keys, WAPI keys or WPA keys along with required
818 *        encryption (TKIP, AES) (as required)
819 *      - Ensuring correct endian-ness
820 */
821static int
822mwifiex_cmd_802_11_key_material_v1(struct mwifiex_private *priv,
823				   struct host_cmd_ds_command *cmd,
824				   u16 cmd_action, u32 cmd_oid,
825				   struct mwifiex_ds_encrypt_key *enc_key)
826{
827	struct host_cmd_ds_802_11_key_material *key_material =
828		&cmd->params.key_material;
829	struct host_cmd_tlv_mac_addr *tlv_mac;
830	u16 key_param_len = 0, cmd_size;
831	int ret = 0;
832
833	cmd->command = cpu_to_le16(HostCmd_CMD_802_11_KEY_MATERIAL);
834	key_material->action = cpu_to_le16(cmd_action);
835
836	if (cmd_action == HostCmd_ACT_GEN_GET) {
837		cmd->size =
838			cpu_to_le16(sizeof(key_material->action) + S_DS_GEN);
839		return ret;
840	}
841
842	if (!enc_key) {
843		memset(&key_material->key_param_set, 0,
844		       (NUM_WEP_KEYS *
845			sizeof(struct mwifiex_ie_type_key_param_set)));
846		ret = mwifiex_set_keyparamset_wep(priv,
847						  &key_material->key_param_set,
848						  &key_param_len);
849		cmd->size = cpu_to_le16(key_param_len +
850				    sizeof(key_material->action) + S_DS_GEN);
851		return ret;
852	} else
853		memset(&key_material->key_param_set, 0,
854		       sizeof(struct mwifiex_ie_type_key_param_set));
855	if (enc_key->is_wapi_key) {
856		struct mwifiex_ie_type_key_param_set *set;
857
858		mwifiex_dbg(priv->adapter, INFO, "info: Set WAPI Key\n");
859		set = &key_material->key_param_set;
860		set->key_type_id = cpu_to_le16(KEY_TYPE_ID_WAPI);
861		if (cmd_oid == KEY_INFO_ENABLED)
862			set->key_info = cpu_to_le16(KEY_ENABLED);
863		else
864			set->key_info = cpu_to_le16(!KEY_ENABLED);
865
866		set->key[0] = enc_key->key_index;
867		if (!priv->sec_info.wapi_key_on)
868			set->key[1] = 1;
869		else
870			/* set 0 when re-key */
871			set->key[1] = 0;
872
873		if (!is_broadcast_ether_addr(enc_key->mac_addr)) {
874			/* WAPI pairwise key: unicast */
875			set->key_info |= cpu_to_le16(KEY_UNICAST);
876		} else {	/* WAPI group key: multicast */
877			set->key_info |= cpu_to_le16(KEY_MCAST);
878			priv->sec_info.wapi_key_on = true;
879		}
880
881		set->type = cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
882		set->key_len = cpu_to_le16(WAPI_KEY_LEN);
883		memcpy(&set->key[2], enc_key->key_material, enc_key->key_len);
884		memcpy(&set->key[2 + enc_key->key_len], enc_key->pn, PN_LEN);
885		set->length = cpu_to_le16(WAPI_KEY_LEN + KEYPARAMSET_FIXED_LEN);
886
887		key_param_len = (WAPI_KEY_LEN + KEYPARAMSET_FIXED_LEN) +
888				 sizeof(struct mwifiex_ie_types_header);
889		cmd->size = cpu_to_le16(sizeof(key_material->action)
890					+ S_DS_GEN +  key_param_len);
891		return ret;
892	}
893	if (enc_key->key_len == WLAN_KEY_LEN_CCMP) {
894		if (enc_key->is_igtk_key) {
895			mwifiex_dbg(priv->adapter, CMD, "cmd: CMAC_AES\n");
896			key_material->key_param_set.key_type_id =
897					cpu_to_le16(KEY_TYPE_ID_AES_CMAC);
898			if (cmd_oid == KEY_INFO_ENABLED)
899				key_material->key_param_set.key_info =
900						cpu_to_le16(KEY_ENABLED);
901			else
902				key_material->key_param_set.key_info =
903						cpu_to_le16(!KEY_ENABLED);
904
905			key_material->key_param_set.key_info |=
906							cpu_to_le16(KEY_IGTK);
907		} else {
908			mwifiex_dbg(priv->adapter, CMD, "cmd: WPA_AES\n");
909			key_material->key_param_set.key_type_id =
910						cpu_to_le16(KEY_TYPE_ID_AES);
911			if (cmd_oid == KEY_INFO_ENABLED)
912				key_material->key_param_set.key_info =
913						cpu_to_le16(KEY_ENABLED);
914			else
915				key_material->key_param_set.key_info =
916						cpu_to_le16(!KEY_ENABLED);
917
918			if (enc_key->key_index & MWIFIEX_KEY_INDEX_UNICAST)
919				/* AES pairwise key: unicast */
920				key_material->key_param_set.key_info |=
921						cpu_to_le16(KEY_UNICAST);
922			else	/* AES group key: multicast */
923				key_material->key_param_set.key_info |=
924							cpu_to_le16(KEY_MCAST);
925		}
926	} else if (enc_key->key_len == WLAN_KEY_LEN_TKIP) {
927		mwifiex_dbg(priv->adapter, CMD, "cmd: WPA_TKIP\n");
928		key_material->key_param_set.key_type_id =
929						cpu_to_le16(KEY_TYPE_ID_TKIP);
930		key_material->key_param_set.key_info =
931						cpu_to_le16(KEY_ENABLED);
932
933		if (enc_key->key_index & MWIFIEX_KEY_INDEX_UNICAST)
934				/* TKIP pairwise key: unicast */
935			key_material->key_param_set.key_info |=
936						cpu_to_le16(KEY_UNICAST);
937		else		/* TKIP group key: multicast */
938			key_material->key_param_set.key_info |=
939							cpu_to_le16(KEY_MCAST);
940	}
941
942	if (key_material->key_param_set.key_type_id) {
943		key_material->key_param_set.type =
944					cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
945		key_material->key_param_set.key_len =
946					cpu_to_le16((u16) enc_key->key_len);
947		memcpy(key_material->key_param_set.key, enc_key->key_material,
948		       enc_key->key_len);
949		key_material->key_param_set.length =
950			cpu_to_le16((u16) enc_key->key_len +
951				    KEYPARAMSET_FIXED_LEN);
952
953		key_param_len = (u16)(enc_key->key_len + KEYPARAMSET_FIXED_LEN)
954				+ sizeof(struct mwifiex_ie_types_header);
955
956		if (le16_to_cpu(key_material->key_param_set.key_type_id) ==
957							KEY_TYPE_ID_AES_CMAC) {
958			struct mwifiex_cmac_param *param =
959					(void *)key_material->key_param_set.key;
960
961			memcpy(param->ipn, enc_key->pn, IGTK_PN_LEN);
962			memcpy(param->key, enc_key->key_material,
963			       WLAN_KEY_LEN_AES_CMAC);
964
965			key_param_len = sizeof(struct mwifiex_cmac_param);
966			key_material->key_param_set.key_len =
967						cpu_to_le16(key_param_len);
968			key_param_len += KEYPARAMSET_FIXED_LEN;
969			key_material->key_param_set.length =
970						cpu_to_le16(key_param_len);
971			key_param_len += sizeof(struct mwifiex_ie_types_header);
972		}
973
974		cmd->size = cpu_to_le16(sizeof(key_material->action) + S_DS_GEN
975					+ key_param_len);
976
977		if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) {
978			tlv_mac = (void *)((u8 *)&key_material->key_param_set +
979					   key_param_len);
980			tlv_mac->header.type =
981					cpu_to_le16(TLV_TYPE_STA_MAC_ADDR);
982			tlv_mac->header.len = cpu_to_le16(ETH_ALEN);
983			memcpy(tlv_mac->mac_addr, enc_key->mac_addr, ETH_ALEN);
984			cmd_size = key_param_len + S_DS_GEN +
985				   sizeof(key_material->action) +
986				   sizeof(struct host_cmd_tlv_mac_addr);
987		} else {
988			cmd_size = key_param_len + S_DS_GEN +
989				   sizeof(key_material->action);
990		}
991		cmd->size = cpu_to_le16(cmd_size);
992	}
993
994	return ret;
995}
996
997/* Wrapper function for setting network key depending upon FW KEY API version */
998static int
999mwifiex_cmd_802_11_key_material(struct mwifiex_private *priv,
1000				struct host_cmd_ds_command *cmd,
1001				u16 cmd_action, u32 cmd_oid,
1002				struct mwifiex_ds_encrypt_key *enc_key)
1003{
1004	if (priv->adapter->key_api_major_ver == KEY_API_VER_MAJOR_V2)
1005		return mwifiex_cmd_802_11_key_material_v2(priv, cmd,
1006							  cmd_action, cmd_oid,
1007							  enc_key);
1008
1009	else
1010		return mwifiex_cmd_802_11_key_material_v1(priv, cmd,
1011							  cmd_action, cmd_oid,
1012							  enc_key);
1013}
1014
1015/*
1016 * This function prepares command to set/get 11d domain information.
1017 *
1018 * Preparation includes -
1019 *      - Setting command ID, action and proper size
1020 *      - Setting domain information fields (for SET only)
1021 *      - Ensuring correct endian-ness
1022 */
1023static int mwifiex_cmd_802_11d_domain_info(struct mwifiex_private *priv,
1024					   struct host_cmd_ds_command *cmd,
1025					   u16 cmd_action)
1026{
1027	struct mwifiex_adapter *adapter = priv->adapter;
1028	struct host_cmd_ds_802_11d_domain_info *domain_info =
1029		&cmd->params.domain_info;
1030	struct mwifiex_ietypes_domain_param_set *domain =
1031		&domain_info->domain;
1032	u8 no_of_triplet = adapter->domain_reg.no_of_triplet;
1033
1034	mwifiex_dbg(adapter, INFO,
1035		    "info: 11D: no_of_triplet=0x%x\n", no_of_triplet);
1036
1037	cmd->command = cpu_to_le16(HostCmd_CMD_802_11D_DOMAIN_INFO);
1038	domain_info->action = cpu_to_le16(cmd_action);
1039	if (cmd_action == HostCmd_ACT_GEN_GET) {
1040		cmd->size = cpu_to_le16(sizeof(domain_info->action) + S_DS_GEN);
1041		return 0;
1042	}
1043
1044	/* Set domain info fields */
1045	domain->header.type = cpu_to_le16(WLAN_EID_COUNTRY);
1046	memcpy(domain->country_code, adapter->domain_reg.country_code,
1047	       sizeof(domain->country_code));
1048
1049	domain->header.len =
1050		cpu_to_le16((no_of_triplet *
1051			     sizeof(struct ieee80211_country_ie_triplet))
1052			    + sizeof(domain->country_code));
1053
1054	if (no_of_triplet) {
1055		memcpy(domain->triplet, adapter->domain_reg.triplet,
1056		       no_of_triplet * sizeof(struct
1057					      ieee80211_country_ie_triplet));
1058
1059		cmd->size = cpu_to_le16(sizeof(domain_info->action) +
1060					le16_to_cpu(domain->header.len) +
1061					sizeof(struct mwifiex_ie_types_header)
1062					+ S_DS_GEN);
1063	} else {
1064		cmd->size = cpu_to_le16(sizeof(domain_info->action) + S_DS_GEN);
1065	}
1066
1067	return 0;
1068}
1069
1070/*
1071 * This function prepares command to set/get IBSS coalescing status.
1072 *
1073 * Preparation includes -
1074 *      - Setting command ID, action and proper size
1075 *      - Setting status to enable or disable (for SET only)
1076 *      - Ensuring correct endian-ness
1077 */
1078static int mwifiex_cmd_ibss_coalescing_status(struct host_cmd_ds_command *cmd,
1079					      u16 cmd_action, u16 *enable)
1080{
1081	struct host_cmd_ds_802_11_ibss_status *ibss_coal =
1082		&(cmd->params.ibss_coalescing);
1083
1084	cmd->command = cpu_to_le16(HostCmd_CMD_802_11_IBSS_COALESCING_STATUS);
1085	cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_ibss_status) +
1086				S_DS_GEN);
1087	cmd->result = 0;
1088	ibss_coal->action = cpu_to_le16(cmd_action);
1089
1090	switch (cmd_action) {
1091	case HostCmd_ACT_GEN_SET:
1092		if (enable)
1093			ibss_coal->enable = cpu_to_le16(*enable);
1094		else
1095			ibss_coal->enable = 0;
1096		break;
1097
1098		/* In other case.. Nothing to do */
1099	case HostCmd_ACT_GEN_GET:
1100	default:
1101		break;
1102	}
1103
1104	return 0;
1105}
1106
1107/* This function prepares command buffer to get/set memory location value.
1108 */
1109static int
1110mwifiex_cmd_mem_access(struct host_cmd_ds_command *cmd, u16 cmd_action,
1111		       void *pdata_buf)
1112{
1113	struct mwifiex_ds_mem_rw *mem_rw = (void *)pdata_buf;
1114	struct host_cmd_ds_mem_access *mem_access = (void *)&cmd->params.mem;
1115
1116	cmd->command = cpu_to_le16(HostCmd_CMD_MEM_ACCESS);
1117	cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_mem_access) +
1118				S_DS_GEN);
1119
1120	mem_access->action = cpu_to_le16(cmd_action);
1121	mem_access->addr = cpu_to_le32(mem_rw->addr);
1122	mem_access->value = cpu_to_le32(mem_rw->value);
1123
1124	return 0;
1125}
1126
1127/*
1128 * This function prepares command to set/get register value.
1129 *
1130 * Preparation includes -
1131 *      - Setting command ID, action and proper size
1132 *      - Setting register offset (for both GET and SET) and
1133 *        register value (for SET only)
1134 *      - Ensuring correct endian-ness
1135 *
1136 * The following type of registers can be accessed with this function -
1137 *      - MAC register
1138 *      - BBP register
1139 *      - RF register
1140 *      - PMIC register
1141 *      - CAU register
1142 *      - EEPROM
1143 */
1144static int mwifiex_cmd_reg_access(struct host_cmd_ds_command *cmd,
1145				  u16 cmd_action, void *data_buf)
1146{
1147	struct mwifiex_ds_reg_rw *reg_rw = data_buf;
1148
1149	switch (le16_to_cpu(cmd->command)) {
1150	case HostCmd_CMD_MAC_REG_ACCESS:
1151	{
1152		struct host_cmd_ds_mac_reg_access *mac_reg;
1153
1154		cmd->size = cpu_to_le16(sizeof(*mac_reg) + S_DS_GEN);
1155		mac_reg = &cmd->params.mac_reg;
1156		mac_reg->action = cpu_to_le16(cmd_action);
1157		mac_reg->offset = cpu_to_le16((u16) reg_rw->offset);
1158		mac_reg->value = cpu_to_le32(reg_rw->value);
1159		break;
1160	}
1161	case HostCmd_CMD_BBP_REG_ACCESS:
1162	{
1163		struct host_cmd_ds_bbp_reg_access *bbp_reg;
1164
1165		cmd->size = cpu_to_le16(sizeof(*bbp_reg) + S_DS_GEN);
1166		bbp_reg = &cmd->params.bbp_reg;
1167		bbp_reg->action = cpu_to_le16(cmd_action);
1168		bbp_reg->offset = cpu_to_le16((u16) reg_rw->offset);
1169		bbp_reg->value = (u8) reg_rw->value;
1170		break;
1171	}
1172	case HostCmd_CMD_RF_REG_ACCESS:
1173	{
1174		struct host_cmd_ds_rf_reg_access *rf_reg;
1175
1176		cmd->size = cpu_to_le16(sizeof(*rf_reg) + S_DS_GEN);
1177		rf_reg = &cmd->params.rf_reg;
1178		rf_reg->action = cpu_to_le16(cmd_action);
1179		rf_reg->offset = cpu_to_le16((u16) reg_rw->offset);
1180		rf_reg->value = (u8) reg_rw->value;
1181		break;
1182	}
1183	case HostCmd_CMD_PMIC_REG_ACCESS:
1184	{
1185		struct host_cmd_ds_pmic_reg_access *pmic_reg;
1186
1187		cmd->size = cpu_to_le16(sizeof(*pmic_reg) + S_DS_GEN);
1188		pmic_reg = &cmd->params.pmic_reg;
1189		pmic_reg->action = cpu_to_le16(cmd_action);
1190		pmic_reg->offset = cpu_to_le16((u16) reg_rw->offset);
1191		pmic_reg->value = (u8) reg_rw->value;
1192		break;
1193	}
1194	case HostCmd_CMD_CAU_REG_ACCESS:
1195	{
1196		struct host_cmd_ds_rf_reg_access *cau_reg;
1197
1198		cmd->size = cpu_to_le16(sizeof(*cau_reg) + S_DS_GEN);
1199		cau_reg = &cmd->params.rf_reg;
1200		cau_reg->action = cpu_to_le16(cmd_action);
1201		cau_reg->offset = cpu_to_le16((u16) reg_rw->offset);
1202		cau_reg->value = (u8) reg_rw->value;
1203		break;
1204	}
1205	case HostCmd_CMD_802_11_EEPROM_ACCESS:
1206	{
1207		struct mwifiex_ds_read_eeprom *rd_eeprom = data_buf;
1208		struct host_cmd_ds_802_11_eeprom_access *cmd_eeprom =
1209			&cmd->params.eeprom;
1210
1211		cmd->size = cpu_to_le16(sizeof(*cmd_eeprom) + S_DS_GEN);
1212		cmd_eeprom->action = cpu_to_le16(cmd_action);
1213		cmd_eeprom->offset = cpu_to_le16(rd_eeprom->offset);
1214		cmd_eeprom->byte_count = cpu_to_le16(rd_eeprom->byte_count);
1215		cmd_eeprom->value = 0;
1216		break;
1217	}
1218	default:
1219		return -1;
1220	}
1221
1222	return 0;
1223}
1224
1225/*
1226 * This function prepares command to set PCI-Express
1227 * host buffer configuration
1228 *
1229 * Preparation includes -
1230 *      - Setting command ID, action and proper size
1231 *      - Setting host buffer configuration
1232 *      - Ensuring correct endian-ness
1233 */
1234static int
1235mwifiex_cmd_pcie_host_spec(struct mwifiex_private *priv,
1236			   struct host_cmd_ds_command *cmd, u16 action)
1237{
1238	struct host_cmd_ds_pcie_details *host_spec =
1239					&cmd->params.pcie_host_spec;
1240	struct pcie_service_card *card = priv->adapter->card;
1241
1242	cmd->command = cpu_to_le16(HostCmd_CMD_PCIE_DESC_DETAILS);
1243	cmd->size = cpu_to_le16(sizeof(struct
1244					host_cmd_ds_pcie_details) + S_DS_GEN);
1245	cmd->result = 0;
1246
1247	memset(host_spec, 0, sizeof(struct host_cmd_ds_pcie_details));
1248
1249	if (action != HostCmd_ACT_GEN_SET)
1250		return 0;
1251
1252	/* Send the ring base addresses and count to firmware */
1253	host_spec->txbd_addr_lo = cpu_to_le32((u32)(card->txbd_ring_pbase));
1254	host_spec->txbd_addr_hi =
1255			cpu_to_le32((u32)(((u64)card->txbd_ring_pbase) >> 32));
1256	host_spec->txbd_count = cpu_to_le32(MWIFIEX_MAX_TXRX_BD);
1257	host_spec->rxbd_addr_lo = cpu_to_le32((u32)(card->rxbd_ring_pbase));
1258	host_spec->rxbd_addr_hi =
1259			cpu_to_le32((u32)(((u64)card->rxbd_ring_pbase) >> 32));
1260	host_spec->rxbd_count = cpu_to_le32(MWIFIEX_MAX_TXRX_BD);
1261	host_spec->evtbd_addr_lo = cpu_to_le32((u32)(card->evtbd_ring_pbase));
1262	host_spec->evtbd_addr_hi =
1263			cpu_to_le32((u32)(((u64)card->evtbd_ring_pbase) >> 32));
1264	host_spec->evtbd_count = cpu_to_le32(MWIFIEX_MAX_EVT_BD);
1265	if (card->sleep_cookie_vbase) {
1266		host_spec->sleep_cookie_addr_lo =
1267				cpu_to_le32((u32)(card->sleep_cookie_pbase));
1268		host_spec->sleep_cookie_addr_hi = cpu_to_le32((u32)(((u64)
1269					(card->sleep_cookie_pbase)) >> 32));
1270		mwifiex_dbg(priv->adapter, INFO,
1271			    "sleep_cook_lo phy addr: 0x%x\n",
1272			    host_spec->sleep_cookie_addr_lo);
1273	}
1274
1275	return 0;
1276}
1277
1278/*
1279 * This function prepares command for event subscription, configuration
1280 * and query. Events can be subscribed or unsubscribed. Current subscribed
1281 * events can be queried. Also, current subscribed events are reported in
1282 * every FW response.
1283 */
1284static int
1285mwifiex_cmd_802_11_subsc_evt(struct mwifiex_private *priv,
1286			     struct host_cmd_ds_command *cmd,
1287			     struct mwifiex_ds_misc_subsc_evt *subsc_evt_cfg)
1288{
1289	struct host_cmd_ds_802_11_subsc_evt *subsc_evt = &cmd->params.subsc_evt;
1290	struct mwifiex_ie_types_rssi_threshold *rssi_tlv;
1291	u16 event_bitmap;
1292	u8 *pos;
1293
1294	cmd->command = cpu_to_le16(HostCmd_CMD_802_11_SUBSCRIBE_EVENT);
1295	cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_subsc_evt) +
1296				S_DS_GEN);
1297
1298	subsc_evt->action = cpu_to_le16(subsc_evt_cfg->action);
1299	mwifiex_dbg(priv->adapter, CMD,
1300		    "cmd: action: %d\n", subsc_evt_cfg->action);
1301
1302	/*For query requests, no configuration TLV structures are to be added.*/
1303	if (subsc_evt_cfg->action == HostCmd_ACT_GEN_GET)
1304		return 0;
1305
1306	subsc_evt->events = cpu_to_le16(subsc_evt_cfg->events);
1307
1308	event_bitmap = subsc_evt_cfg->events;
1309	mwifiex_dbg(priv->adapter, CMD, "cmd: event bitmap : %16x\n",
1310		    event_bitmap);
1311
1312	if (((subsc_evt_cfg->action == HostCmd_ACT_BITWISE_CLR) ||
1313	     (subsc_evt_cfg->action == HostCmd_ACT_BITWISE_SET)) &&
1314	    (event_bitmap == 0)) {
1315		mwifiex_dbg(priv->adapter, ERROR,
1316			    "Error: No event specified\t"
1317			    "for bitwise action type\n");
1318		return -EINVAL;
1319	}
1320
1321	/*
1322	 * Append TLV structures for each of the specified events for
1323	 * subscribing or re-configuring. This is not required for
1324	 * bitwise unsubscribing request.
1325	 */
1326	if (subsc_evt_cfg->action == HostCmd_ACT_BITWISE_CLR)
1327		return 0;
1328
1329	pos = ((u8 *)subsc_evt) +
1330			sizeof(struct host_cmd_ds_802_11_subsc_evt);
1331
1332	if (event_bitmap & BITMASK_BCN_RSSI_LOW) {
1333		rssi_tlv = (struct mwifiex_ie_types_rssi_threshold *) pos;
1334
1335		rssi_tlv->header.type = cpu_to_le16(TLV_TYPE_RSSI_LOW);
1336		rssi_tlv->header.len =
1337		    cpu_to_le16(sizeof(struct mwifiex_ie_types_rssi_threshold) -
1338				sizeof(struct mwifiex_ie_types_header));
1339		rssi_tlv->abs_value = subsc_evt_cfg->bcn_l_rssi_cfg.abs_value;
1340		rssi_tlv->evt_freq = subsc_evt_cfg->bcn_l_rssi_cfg.evt_freq;
1341
1342		mwifiex_dbg(priv->adapter, EVENT,
1343			    "Cfg Beacon Low Rssi event,\t"
1344			    "RSSI:-%d dBm, Freq:%d\n",
1345			    subsc_evt_cfg->bcn_l_rssi_cfg.abs_value,
1346			    subsc_evt_cfg->bcn_l_rssi_cfg.evt_freq);
1347
1348		pos += sizeof(struct mwifiex_ie_types_rssi_threshold);
1349		le16_unaligned_add_cpu(&cmd->size,
1350				       sizeof(
1351				       struct mwifiex_ie_types_rssi_threshold));
1352	}
1353
1354	if (event_bitmap & BITMASK_BCN_RSSI_HIGH) {
1355		rssi_tlv = (struct mwifiex_ie_types_rssi_threshold *) pos;
1356
1357		rssi_tlv->header.type = cpu_to_le16(TLV_TYPE_RSSI_HIGH);
1358		rssi_tlv->header.len =
1359		    cpu_to_le16(sizeof(struct mwifiex_ie_types_rssi_threshold) -
1360				sizeof(struct mwifiex_ie_types_header));
1361		rssi_tlv->abs_value = subsc_evt_cfg->bcn_h_rssi_cfg.abs_value;
1362		rssi_tlv->evt_freq = subsc_evt_cfg->bcn_h_rssi_cfg.evt_freq;
1363
1364		mwifiex_dbg(priv->adapter, EVENT,
1365			    "Cfg Beacon High Rssi event,\t"
1366			    "RSSI:-%d dBm, Freq:%d\n",
1367			    subsc_evt_cfg->bcn_h_rssi_cfg.abs_value,
1368			    subsc_evt_cfg->bcn_h_rssi_cfg.evt_freq);
1369
1370		pos += sizeof(struct mwifiex_ie_types_rssi_threshold);
1371		le16_unaligned_add_cpu(&cmd->size,
1372				       sizeof(
1373				       struct mwifiex_ie_types_rssi_threshold));
1374	}
1375
1376	return 0;
1377}
1378
1379static int
1380mwifiex_cmd_append_rpn_expression(struct mwifiex_private *priv,
1381				  struct mwifiex_mef_entry *mef_entry,
1382				  u8 **buffer)
1383{
1384	struct mwifiex_mef_filter *filter = mef_entry->filter;
1385	int i, byte_len;
1386	u8 *stack_ptr = *buffer;
1387
1388	for (i = 0; i < MWIFIEX_MEF_MAX_FILTERS; i++) {
1389		filter = &mef_entry->filter[i];
1390		if (!filter->filt_type)
1391			break;
1392		put_unaligned_le32((u32)filter->repeat, stack_ptr);
1393		stack_ptr += 4;
1394		*stack_ptr = TYPE_DNUM;
1395		stack_ptr += 1;
1396
1397		byte_len = filter->byte_seq[MWIFIEX_MEF_MAX_BYTESEQ];
1398		memcpy(stack_ptr, filter->byte_seq, byte_len);
1399		stack_ptr += byte_len;
1400		*stack_ptr = byte_len;
1401		stack_ptr += 1;
1402		*stack_ptr = TYPE_BYTESEQ;
1403		stack_ptr += 1;
1404		put_unaligned_le32((u32)filter->offset, stack_ptr);
1405		stack_ptr += 4;
1406		*stack_ptr = TYPE_DNUM;
1407		stack_ptr += 1;
1408
1409		*stack_ptr = filter->filt_type;
1410		stack_ptr += 1;
1411
1412		if (filter->filt_action) {
1413			*stack_ptr = filter->filt_action;
1414			stack_ptr += 1;
1415		}
1416
1417		if (stack_ptr - *buffer > STACK_NBYTES)
1418			return -1;
1419	}
1420
1421	*buffer = stack_ptr;
1422	return 0;
1423}
1424
1425static int
1426mwifiex_cmd_mef_cfg(struct mwifiex_private *priv,
1427		    struct host_cmd_ds_command *cmd,
1428		    struct mwifiex_ds_mef_cfg *mef)
1429{
1430	struct host_cmd_ds_mef_cfg *mef_cfg = &cmd->params.mef_cfg;
1431	struct mwifiex_fw_mef_entry *mef_entry = NULL;
1432	u8 *pos = (u8 *)mef_cfg;
1433	u16 i;
1434
1435	cmd->command = cpu_to_le16(HostCmd_CMD_MEF_CFG);
1436
1437	mef_cfg->criteria = cpu_to_le32(mef->criteria);
1438	mef_cfg->num_entries = cpu_to_le16(mef->num_entries);
1439	pos += sizeof(*mef_cfg);
1440
1441	for (i = 0; i < mef->num_entries; i++) {
1442		mef_entry = (struct mwifiex_fw_mef_entry *)pos;
1443		mef_entry->mode = mef->mef_entry[i].mode;
1444		mef_entry->action = mef->mef_entry[i].action;
1445		pos += sizeof(*mef_cfg->mef_entry);
1446
1447		if (mwifiex_cmd_append_rpn_expression(priv,
1448						      &mef->mef_entry[i], &pos))
1449			return -1;
1450
1451		mef_entry->exprsize =
1452			cpu_to_le16(pos - mef_entry->expr);
1453	}
1454	cmd->size = cpu_to_le16((u16) (pos - (u8 *)mef_cfg) + S_DS_GEN);
1455
1456	return 0;
1457}
1458
1459/* This function parse cal data from ASCII to hex */
1460static u32 mwifiex_parse_cal_cfg(u8 *src, size_t len, u8 *dst)
1461{
1462	u8 *s = src, *d = dst;
1463
1464	while (s - src < len) {
1465		if (*s && (isspace(*s) || *s == '\t')) {
1466			s++;
1467			continue;
1468		}
1469		if (isxdigit(*s)) {
1470			*d++ = simple_strtol(s, NULL, 16);
1471			s += 2;
1472		} else {
1473			s++;
1474		}
1475	}
1476
1477	return d - dst;
1478}
1479
1480int mwifiex_dnld_dt_cfgdata(struct mwifiex_private *priv,
1481			    struct device_node *node, const char *prefix)
1482{
1483#ifdef CONFIG_OF
1484	struct property *prop;
1485	size_t len = strlen(prefix);
1486	int ret;
1487
1488	/* look for all matching property names */
1489	for_each_property_of_node(node, prop) {
1490		if (len > strlen(prop->name) ||
1491		    strncmp(prop->name, prefix, len))
1492			continue;
1493
1494		/* property header is 6 bytes, data must fit in cmd buffer */
1495		if (prop->value && prop->length > 6 &&
1496		    prop->length <= MWIFIEX_SIZE_OF_CMD_BUFFER - S_DS_GEN) {
1497			ret = mwifiex_send_cmd(priv, HostCmd_CMD_CFG_DATA,
1498					       HostCmd_ACT_GEN_SET, 0,
1499					       prop, true);
1500			if (ret)
1501				return ret;
1502		}
1503	}
1504#endif
1505	return 0;
1506}
1507
1508/* This function prepares command of set_cfg_data. */
1509static int mwifiex_cmd_cfg_data(struct mwifiex_private *priv,
1510				struct host_cmd_ds_command *cmd, void *data_buf)
1511{
1512	struct mwifiex_adapter *adapter = priv->adapter;
1513	struct property *prop = data_buf;
1514	u32 len;
1515	u8 *data = (u8 *)cmd + S_DS_GEN;
1516	int ret;
1517
1518	if (prop) {
1519		len = prop->length;
1520		ret = of_property_read_u8_array(adapter->dt_node, prop->name,
1521						data, len);
1522		if (ret)
1523			return ret;
1524		mwifiex_dbg(adapter, INFO,
1525			    "download cfg_data from device tree: %s\n",
1526			    prop->name);
1527	} else if (adapter->cal_data->data && adapter->cal_data->size > 0) {
1528		len = mwifiex_parse_cal_cfg((u8 *)adapter->cal_data->data,
1529					    adapter->cal_data->size, data);
1530		mwifiex_dbg(adapter, INFO,
1531			    "download cfg_data from config file\n");
1532	} else {
1533		return -1;
1534	}
1535
1536	cmd->command = cpu_to_le16(HostCmd_CMD_CFG_DATA);
1537	cmd->size = cpu_to_le16(S_DS_GEN + len);
1538
1539	return 0;
1540}
1541
1542static int
1543mwifiex_cmd_set_mc_policy(struct mwifiex_private *priv,
1544			  struct host_cmd_ds_command *cmd,
1545			  u16 cmd_action, void *data_buf)
1546{
1547	struct host_cmd_ds_multi_chan_policy *mc_pol = &cmd->params.mc_policy;
1548	const u16 *drcs_info = data_buf;
1549
1550	mc_pol->action = cpu_to_le16(cmd_action);
1551	mc_pol->policy = cpu_to_le16(*drcs_info);
1552	cmd->command = cpu_to_le16(HostCmd_CMD_MC_POLICY);
1553	cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_multi_chan_policy) +
1554				S_DS_GEN);
1555	return 0;
1556}
1557
1558static int mwifiex_cmd_robust_coex(struct mwifiex_private *priv,
1559				   struct host_cmd_ds_command *cmd,
1560				   u16 cmd_action, bool *is_timeshare)
1561{
1562	struct host_cmd_ds_robust_coex *coex = &cmd->params.coex;
1563	struct mwifiex_ie_types_robust_coex *coex_tlv;
1564
1565	cmd->command = cpu_to_le16(HostCmd_CMD_ROBUST_COEX);
1566	cmd->size = cpu_to_le16(sizeof(*coex) + sizeof(*coex_tlv) + S_DS_GEN);
1567
1568	coex->action = cpu_to_le16(cmd_action);
1569	coex_tlv = (struct mwifiex_ie_types_robust_coex *)
1570				((u8 *)coex + sizeof(*coex));
1571	coex_tlv->header.type = cpu_to_le16(TLV_TYPE_ROBUST_COEX);
1572	coex_tlv->header.len = cpu_to_le16(sizeof(coex_tlv->mode));
1573
1574	if (coex->action == HostCmd_ACT_GEN_GET)
1575		return 0;
1576
1577	if (*is_timeshare)
1578		coex_tlv->mode = cpu_to_le32(MWIFIEX_COEX_MODE_TIMESHARE);
1579	else
1580		coex_tlv->mode = cpu_to_le32(MWIFIEX_COEX_MODE_SPATIAL);
1581
1582	return 0;
1583}
1584
1585static int mwifiex_cmd_gtk_rekey_offload(struct mwifiex_private *priv,
1586					 struct host_cmd_ds_command *cmd,
1587					 u16 cmd_action,
1588					 struct cfg80211_gtk_rekey_data *data)
1589{
1590	struct host_cmd_ds_gtk_rekey_params *rekey = &cmd->params.rekey;
1591	u64 rekey_ctr;
1592
1593	cmd->command = cpu_to_le16(HostCmd_CMD_GTK_REKEY_OFFLOAD_CFG);
1594	cmd->size = cpu_to_le16(sizeof(*rekey) + S_DS_GEN);
1595
1596	rekey->action = cpu_to_le16(cmd_action);
1597	if (cmd_action == HostCmd_ACT_GEN_SET) {
1598		memcpy(rekey->kek, data->kek, NL80211_KEK_LEN);
1599		memcpy(rekey->kck, data->kck, NL80211_KCK_LEN);
1600		rekey_ctr = be64_to_cpup((__be64 *)data->replay_ctr);
1601		rekey->replay_ctr_low = cpu_to_le32((u32)rekey_ctr);
1602		rekey->replay_ctr_high =
1603			cpu_to_le32((u32)((u64)rekey_ctr >> 32));
1604	}
1605
1606	return 0;
1607}
1608
1609static int mwifiex_cmd_chan_region_cfg(struct mwifiex_private *priv,
1610				       struct host_cmd_ds_command *cmd,
1611				       u16 cmd_action)
1612{
1613	struct host_cmd_ds_chan_region_cfg *reg = &cmd->params.reg_cfg;
1614
1615	cmd->command = cpu_to_le16(HostCmd_CMD_CHAN_REGION_CFG);
1616	cmd->size = cpu_to_le16(sizeof(*reg) + S_DS_GEN);
1617
1618	if (cmd_action == HostCmd_ACT_GEN_GET)
1619		reg->action = cpu_to_le16(cmd_action);
1620
1621	return 0;
1622}
1623
1624static int
1625mwifiex_cmd_coalesce_cfg(struct mwifiex_private *priv,
1626			 struct host_cmd_ds_command *cmd,
1627			 u16 cmd_action, void *data_buf)
1628{
1629	struct host_cmd_ds_coalesce_cfg *coalesce_cfg =
1630						&cmd->params.coalesce_cfg;
1631	struct mwifiex_ds_coalesce_cfg *cfg = data_buf;
1632	struct coalesce_filt_field_param *param;
1633	u16 cnt, idx, length;
1634	struct coalesce_receive_filt_rule *rule;
1635
1636	cmd->command = cpu_to_le16(HostCmd_CMD_COALESCE_CFG);
1637	cmd->size = cpu_to_le16(S_DS_GEN);
1638
1639	coalesce_cfg->action = cpu_to_le16(cmd_action);
1640	coalesce_cfg->num_of_rules = cpu_to_le16(cfg->num_of_rules);
1641	rule = coalesce_cfg->rule;
1642
1643	for (cnt = 0; cnt < cfg->num_of_rules; cnt++) {
1644		rule->header.type = cpu_to_le16(TLV_TYPE_COALESCE_RULE);
1645		rule->max_coalescing_delay =
1646			cpu_to_le16(cfg->rule[cnt].max_coalescing_delay);
1647		rule->pkt_type = cfg->rule[cnt].pkt_type;
1648		rule->num_of_fields = cfg->rule[cnt].num_of_fields;
1649
1650		length = 0;
1651
1652		param = rule->params;
1653		for (idx = 0; idx < cfg->rule[cnt].num_of_fields; idx++) {
1654			param->operation = cfg->rule[cnt].params[idx].operation;
1655			param->operand_len =
1656					cfg->rule[cnt].params[idx].operand_len;
1657			param->offset =
1658				cpu_to_le16(cfg->rule[cnt].params[idx].offset);
1659			memcpy(param->operand_byte_stream,
1660			       cfg->rule[cnt].params[idx].operand_byte_stream,
1661			       param->operand_len);
1662
1663			length += sizeof(struct coalesce_filt_field_param);
1664
1665			param++;
1666		}
1667
1668		/* Total rule length is sizeof max_coalescing_delay(u16),
1669		 * num_of_fields(u8), pkt_type(u8) and total length of the all
1670		 * params
1671		 */
1672		rule->header.len = cpu_to_le16(length + sizeof(u16) +
1673					       sizeof(u8) + sizeof(u8));
1674
1675		/* Add the rule length to the command size*/
1676		le16_unaligned_add_cpu(&cmd->size,
1677				       le16_to_cpu(rule->header.len) +
1678				       sizeof(struct mwifiex_ie_types_header));
1679
1680		rule = (void *)((u8 *)rule->params + length);
1681	}
1682
1683	/* Add sizeof action, num_of_rules to total command length */
1684	le16_unaligned_add_cpu(&cmd->size, sizeof(u16) + sizeof(u16));
1685
1686	return 0;
1687}
1688
1689static int
1690mwifiex_cmd_tdls_config(struct mwifiex_private *priv,
1691			struct host_cmd_ds_command *cmd,
1692			u16 cmd_action, void *data_buf)
1693{
1694	struct host_cmd_ds_tdls_config *tdls_config = &cmd->params.tdls_config;
1695	struct mwifiex_tdls_init_cs_params *config;
1696	struct mwifiex_tdls_config *init_config;
1697	u16 len;
1698
1699	cmd->command = cpu_to_le16(HostCmd_CMD_TDLS_CONFIG);
1700	cmd->size = cpu_to_le16(S_DS_GEN);
1701	tdls_config->tdls_action = cpu_to_le16(cmd_action);
1702	le16_unaligned_add_cpu(&cmd->size, sizeof(tdls_config->tdls_action));
1703
1704	switch (cmd_action) {
1705	case ACT_TDLS_CS_ENABLE_CONFIG:
1706		init_config = data_buf;
1707		len = sizeof(*init_config);
1708		memcpy(tdls_config->tdls_data, init_config, len);
1709		break;
1710	case ACT_TDLS_CS_INIT:
1711		config = data_buf;
1712		len = sizeof(*config);
1713		memcpy(tdls_config->tdls_data, config, len);
1714		break;
1715	case ACT_TDLS_CS_STOP:
1716		len = sizeof(struct mwifiex_tdls_stop_cs_params);
1717		memcpy(tdls_config->tdls_data, data_buf, len);
1718		break;
1719	case ACT_TDLS_CS_PARAMS:
1720		len = sizeof(struct mwifiex_tdls_config_cs_params);
1721		memcpy(tdls_config->tdls_data, data_buf, len);
1722		break;
1723	default:
1724		mwifiex_dbg(priv->adapter, ERROR,
1725			    "Unknown TDLS configuration\n");
1726		return -EOPNOTSUPP;
1727	}
1728
1729	le16_unaligned_add_cpu(&cmd->size, len);
1730	return 0;
1731}
1732
1733static int
1734mwifiex_cmd_tdls_oper(struct mwifiex_private *priv,
1735		      struct host_cmd_ds_command *cmd,
1736		      void *data_buf)
1737{
1738	struct host_cmd_ds_tdls_oper *tdls_oper = &cmd->params.tdls_oper;
1739	struct mwifiex_ds_tdls_oper *oper = data_buf;
1740	struct host_cmd_tlv_rates *tlv_rates;
1741	struct mwifiex_ie_types_htcap *ht_capab;
1742	struct mwifiex_ie_types_qos_info *wmm_qos_info;
1743	struct mwifiex_ie_types_extcap *extcap;
1744	struct mwifiex_ie_types_vhtcap *vht_capab;
1745	struct mwifiex_ie_types_aid *aid;
1746	struct mwifiex_ie_types_tdls_idle_timeout *timeout;
1747	u8 *pos;
1748	u16 config_len = 0;
1749	struct station_parameters *params = priv->sta_params;
1750
1751	cmd->command = cpu_to_le16(HostCmd_CMD_TDLS_OPER);
1752	cmd->size = cpu_to_le16(S_DS_GEN);
1753	le16_unaligned_add_cpu(&cmd->size,
1754			       sizeof(struct host_cmd_ds_tdls_oper));
1755
1756	tdls_oper->reason = 0;
1757	memcpy(tdls_oper->peer_mac, oper->peer_mac, ETH_ALEN);
1758
1759	pos = (u8 *)tdls_oper + sizeof(struct host_cmd_ds_tdls_oper);
1760
1761	switch (oper->tdls_action) {
1762	case MWIFIEX_TDLS_DISABLE_LINK:
1763		tdls_oper->tdls_action = cpu_to_le16(ACT_TDLS_DELETE);
1764		break;
1765	case MWIFIEX_TDLS_CREATE_LINK:
1766		tdls_oper->tdls_action = cpu_to_le16(ACT_TDLS_CREATE);
1767		break;
1768	case MWIFIEX_TDLS_CONFIG_LINK:
1769		tdls_oper->tdls_action = cpu_to_le16(ACT_TDLS_CONFIG);
1770
1771		if (!params) {
1772			mwifiex_dbg(priv->adapter, ERROR,
1773				    "TDLS config params not available for %pM\n",
1774				    oper->peer_mac);
1775			return -ENODATA;
1776		}
1777
1778		put_unaligned_le16(params->capability, pos);
1779		config_len += sizeof(params->capability);
1780
1781		wmm_qos_info = (void *)(pos + config_len);
1782		wmm_qos_info->header.type = cpu_to_le16(WLAN_EID_QOS_CAPA);
1783		wmm_qos_info->header.len =
1784				cpu_to_le16(sizeof(wmm_qos_info->qos_info));
1785		wmm_qos_info->qos_info = 0;
1786		config_len += sizeof(struct mwifiex_ie_types_qos_info);
1787
1788		if (params->ht_capa) {
1789			ht_capab = (struct mwifiex_ie_types_htcap *)(pos +
1790								    config_len);
1791			ht_capab->header.type =
1792					    cpu_to_le16(WLAN_EID_HT_CAPABILITY);
1793			ht_capab->header.len =
1794				   cpu_to_le16(sizeof(struct ieee80211_ht_cap));
1795			memcpy(&ht_capab->ht_cap, params->ht_capa,
1796			       sizeof(struct ieee80211_ht_cap));
1797			config_len += sizeof(struct mwifiex_ie_types_htcap);
1798		}
1799
1800		if (params->supported_rates && params->supported_rates_len) {
1801			tlv_rates = (struct host_cmd_tlv_rates *)(pos +
1802								  config_len);
1803			tlv_rates->header.type =
1804					       cpu_to_le16(WLAN_EID_SUPP_RATES);
1805			tlv_rates->header.len =
1806				       cpu_to_le16(params->supported_rates_len);
1807			memcpy(tlv_rates->rates, params->supported_rates,
1808			       params->supported_rates_len);
1809			config_len += sizeof(struct host_cmd_tlv_rates) +
1810				      params->supported_rates_len;
1811		}
1812
1813		if (params->ext_capab && params->ext_capab_len) {
1814			extcap = (struct mwifiex_ie_types_extcap *)(pos +
1815								    config_len);
1816			extcap->header.type =
1817					   cpu_to_le16(WLAN_EID_EXT_CAPABILITY);
1818			extcap->header.len = cpu_to_le16(params->ext_capab_len);
1819			memcpy(extcap->ext_capab, params->ext_capab,
1820			       params->ext_capab_len);
1821			config_len += sizeof(struct mwifiex_ie_types_extcap) +
1822				      params->ext_capab_len;
1823		}
1824		if (params->vht_capa) {
1825			vht_capab = (struct mwifiex_ie_types_vhtcap *)(pos +
1826								    config_len);
1827			vht_capab->header.type =
1828					   cpu_to_le16(WLAN_EID_VHT_CAPABILITY);
1829			vht_capab->header.len =
1830				  cpu_to_le16(sizeof(struct ieee80211_vht_cap));
1831			memcpy(&vht_capab->vht_cap, params->vht_capa,
1832			       sizeof(struct ieee80211_vht_cap));
1833			config_len += sizeof(struct mwifiex_ie_types_vhtcap);
1834		}
1835		if (params->aid) {
1836			aid = (struct mwifiex_ie_types_aid *)(pos + config_len);
1837			aid->header.type = cpu_to_le16(WLAN_EID_AID);
1838			aid->header.len = cpu_to_le16(sizeof(params->aid));
1839			aid->aid = cpu_to_le16(params->aid);
1840			config_len += sizeof(struct mwifiex_ie_types_aid);
1841		}
1842
1843		timeout = (void *)(pos + config_len);
1844		timeout->header.type = cpu_to_le16(TLV_TYPE_TDLS_IDLE_TIMEOUT);
1845		timeout->header.len = cpu_to_le16(sizeof(timeout->value));
1846		timeout->value = cpu_to_le16(MWIFIEX_TDLS_IDLE_TIMEOUT_IN_SEC);
1847		config_len += sizeof(struct mwifiex_ie_types_tdls_idle_timeout);
1848
1849		break;
1850	default:
1851		mwifiex_dbg(priv->adapter, ERROR, "Unknown TDLS operation\n");
1852		return -EOPNOTSUPP;
1853	}
1854
1855	le16_unaligned_add_cpu(&cmd->size, config_len);
1856
1857	return 0;
1858}
1859
1860/* This function prepares command of sdio rx aggr info. */
1861static int mwifiex_cmd_sdio_rx_aggr_cfg(struct host_cmd_ds_command *cmd,
1862					u16 cmd_action, void *data_buf)
1863{
1864	struct host_cmd_sdio_sp_rx_aggr_cfg *cfg =
1865					&cmd->params.sdio_rx_aggr_cfg;
1866
1867	cmd->command = cpu_to_le16(HostCmd_CMD_SDIO_SP_RX_AGGR_CFG);
1868	cmd->size =
1869		cpu_to_le16(sizeof(struct host_cmd_sdio_sp_rx_aggr_cfg) +
1870			    S_DS_GEN);
1871	cfg->action = cmd_action;
1872	if (cmd_action == HostCmd_ACT_GEN_SET)
1873		cfg->enable = *(u8 *)data_buf;
1874
1875	return 0;
1876}
1877
1878/* This function prepares command to get HS wakeup reason.
1879 *
1880 * Preparation includes -
1881 *      - Setting command ID, action and proper size
1882 *      - Ensuring correct endian-ness
1883 */
1884static int mwifiex_cmd_get_wakeup_reason(struct mwifiex_private *priv,
1885					 struct host_cmd_ds_command *cmd)
1886{
1887	cmd->command = cpu_to_le16(HostCmd_CMD_HS_WAKEUP_REASON);
1888	cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_wakeup_reason) +
1889				S_DS_GEN);
1890
1891	return 0;
1892}
1893
1894static int mwifiex_cmd_get_chan_info(struct host_cmd_ds_command *cmd,
1895				     u16 cmd_action)
1896{
1897	struct host_cmd_ds_sta_configure *sta_cfg_cmd = &cmd->params.sta_cfg;
1898	struct host_cmd_tlv_channel_band *tlv_band_channel =
1899	(struct host_cmd_tlv_channel_band *)sta_cfg_cmd->tlv_buffer;
1900
1901	cmd->command = cpu_to_le16(HostCmd_CMD_STA_CONFIGURE);
1902	cmd->size = cpu_to_le16(sizeof(*sta_cfg_cmd) +
1903				sizeof(*tlv_band_channel) + S_DS_GEN);
1904	sta_cfg_cmd->action = cpu_to_le16(cmd_action);
1905	memset(tlv_band_channel, 0, sizeof(*tlv_band_channel));
1906	tlv_band_channel->header.type = cpu_to_le16(TLV_TYPE_CHANNELBANDLIST);
1907	tlv_band_channel->header.len  = cpu_to_le16(sizeof(*tlv_band_channel) -
1908					sizeof(struct mwifiex_ie_types_header));
1909
1910	return 0;
1911}
1912
1913/* This function check if the command is supported by firmware */
1914static int mwifiex_is_cmd_supported(struct mwifiex_private *priv, u16 cmd_no)
1915{
1916	if (!ISSUPP_ADHOC_ENABLED(priv->adapter->fw_cap_info)) {
1917		switch (cmd_no) {
1918		case HostCmd_CMD_802_11_IBSS_COALESCING_STATUS:
1919		case HostCmd_CMD_802_11_AD_HOC_START:
1920		case HostCmd_CMD_802_11_AD_HOC_JOIN:
1921		case HostCmd_CMD_802_11_AD_HOC_STOP:
1922			return -EOPNOTSUPP;
1923		default:
1924			break;
1925		}
1926	}
1927
1928	return 0;
1929}
1930
1931/*
1932 * This function prepares the commands before sending them to the firmware.
1933 *
1934 * This is a generic function which calls specific command preparation
1935 * routines based upon the command number.
1936 */
1937int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no,
1938			    u16 cmd_action, u32 cmd_oid,
1939			    void *data_buf, void *cmd_buf)
1940{
1941	struct host_cmd_ds_command *cmd_ptr = cmd_buf;
1942	int ret = 0;
1943
1944	if (mwifiex_is_cmd_supported(priv, cmd_no)) {
1945		mwifiex_dbg(priv->adapter, ERROR,
1946			    "0x%x command not supported by firmware\n",
1947			    cmd_no);
1948		return -EOPNOTSUPP;
1949	}
1950
1951	/* Prepare command */
1952	switch (cmd_no) {
1953	case HostCmd_CMD_GET_HW_SPEC:
1954		ret = mwifiex_cmd_get_hw_spec(priv, cmd_ptr);
1955		break;
1956	case HostCmd_CMD_CFG_DATA:
1957		ret = mwifiex_cmd_cfg_data(priv, cmd_ptr, data_buf);
1958		break;
1959	case HostCmd_CMD_MAC_CONTROL:
1960		ret = mwifiex_cmd_mac_control(priv, cmd_ptr, cmd_action,
1961					      data_buf);
1962		break;
1963	case HostCmd_CMD_802_11_MAC_ADDRESS:
1964		ret = mwifiex_cmd_802_11_mac_address(priv, cmd_ptr,
1965						     cmd_action);
1966		break;
1967	case HostCmd_CMD_MAC_MULTICAST_ADR:
1968		ret = mwifiex_cmd_mac_multicast_adr(cmd_ptr, cmd_action,
1969						    data_buf);
1970		break;
1971	case HostCmd_CMD_TX_RATE_CFG:
1972		ret = mwifiex_cmd_tx_rate_cfg(priv, cmd_ptr, cmd_action,
1973					      data_buf);
1974		break;
1975	case HostCmd_CMD_TXPWR_CFG:
1976		ret = mwifiex_cmd_tx_power_cfg(cmd_ptr, cmd_action,
1977					       data_buf);
1978		break;
1979	case HostCmd_CMD_RF_TX_PWR:
1980		ret = mwifiex_cmd_rf_tx_power(priv, cmd_ptr, cmd_action,
1981					      data_buf);
1982		break;
1983	case HostCmd_CMD_RF_ANTENNA:
1984		ret = mwifiex_cmd_rf_antenna(priv, cmd_ptr, cmd_action,
1985					     data_buf);
1986		break;
1987	case HostCmd_CMD_802_11_PS_MODE_ENH:
1988		ret = mwifiex_cmd_enh_power_mode(priv, cmd_ptr, cmd_action,
1989						 (uint16_t)cmd_oid, data_buf);
1990		break;
1991	case HostCmd_CMD_802_11_HS_CFG_ENH:
1992		ret = mwifiex_cmd_802_11_hs_cfg(priv, cmd_ptr, cmd_action,
1993				(struct mwifiex_hs_config_param *) data_buf);
1994		break;
1995	case HostCmd_CMD_802_11_SCAN:
1996		ret = mwifiex_cmd_802_11_scan(cmd_ptr, data_buf);
1997		break;
1998	case HostCmd_CMD_802_11_BG_SCAN_CONFIG:
1999		ret = mwifiex_cmd_802_11_bg_scan_config(priv, cmd_ptr,
2000							data_buf);
2001		break;
2002	case HostCmd_CMD_802_11_BG_SCAN_QUERY:
2003		ret = mwifiex_cmd_802_11_bg_scan_query(cmd_ptr);
2004		break;
2005	case HostCmd_CMD_802_11_ASSOCIATE:
2006		ret = mwifiex_cmd_802_11_associate(priv, cmd_ptr, data_buf);
2007		break;
2008	case HostCmd_CMD_802_11_DEAUTHENTICATE:
2009		ret = mwifiex_cmd_802_11_deauthenticate(priv, cmd_ptr,
2010							data_buf);
2011		break;
2012	case HostCmd_CMD_802_11_AD_HOC_START:
2013		ret = mwifiex_cmd_802_11_ad_hoc_start(priv, cmd_ptr,
2014						      data_buf);
2015		break;
2016	case HostCmd_CMD_802_11_GET_LOG:
2017		ret = mwifiex_cmd_802_11_get_log(cmd_ptr);
2018		break;
2019	case HostCmd_CMD_802_11_AD_HOC_JOIN:
2020		ret = mwifiex_cmd_802_11_ad_hoc_join(priv, cmd_ptr,
2021						     data_buf);
2022		break;
2023	case HostCmd_CMD_802_11_AD_HOC_STOP:
2024		ret = mwifiex_cmd_802_11_ad_hoc_stop(cmd_ptr);
2025		break;
2026	case HostCmd_CMD_RSSI_INFO:
2027		ret = mwifiex_cmd_802_11_rssi_info(priv, cmd_ptr, cmd_action);
2028		break;
2029	case HostCmd_CMD_802_11_SNMP_MIB:
2030		ret = mwifiex_cmd_802_11_snmp_mib(priv, cmd_ptr, cmd_action,
2031						  cmd_oid, data_buf);
2032		break;
2033	case HostCmd_CMD_802_11_TX_RATE_QUERY:
2034		cmd_ptr->command =
2035			cpu_to_le16(HostCmd_CMD_802_11_TX_RATE_QUERY);
2036		cmd_ptr->size =
2037			cpu_to_le16(sizeof(struct host_cmd_ds_tx_rate_query) +
2038				    S_DS_GEN);
2039		priv->tx_rate = 0;
2040		ret = 0;
2041		break;
2042	case HostCmd_CMD_VERSION_EXT:
2043		cmd_ptr->command = cpu_to_le16(cmd_no);
2044		cmd_ptr->params.verext.version_str_sel =
2045			(u8)(get_unaligned((u32 *)data_buf));
2046		memcpy(&cmd_ptr->params, data_buf,
2047		       sizeof(struct host_cmd_ds_version_ext));
2048		cmd_ptr->size =
2049			cpu_to_le16(sizeof(struct host_cmd_ds_version_ext) +
2050				    S_DS_GEN);
2051		ret = 0;
2052		break;
2053	case HostCmd_CMD_MGMT_FRAME_REG:
2054		cmd_ptr->command = cpu_to_le16(cmd_no);
2055		cmd_ptr->params.reg_mask.action = cpu_to_le16(cmd_action);
2056		cmd_ptr->params.reg_mask.mask = cpu_to_le32(
2057						get_unaligned((u32 *)data_buf));
2058		cmd_ptr->size =
2059			cpu_to_le16(sizeof(struct host_cmd_ds_mgmt_frame_reg) +
2060				    S_DS_GEN);
2061		ret = 0;
2062		break;
2063	case HostCmd_CMD_REMAIN_ON_CHAN:
2064		cmd_ptr->command = cpu_to_le16(cmd_no);
2065		memcpy(&cmd_ptr->params, data_buf,
2066		       sizeof(struct host_cmd_ds_remain_on_chan));
2067		cmd_ptr->size =
2068		      cpu_to_le16(sizeof(struct host_cmd_ds_remain_on_chan) +
2069				  S_DS_GEN);
2070		break;
2071	case HostCmd_CMD_11AC_CFG:
2072		ret = mwifiex_cmd_11ac_cfg(priv, cmd_ptr, cmd_action, data_buf);
2073		break;
2074	case HostCmd_CMD_PACKET_AGGR_CTRL:
2075		cmd_ptr->command = cpu_to_le16(cmd_no);
2076		cmd_ptr->params.pkt_aggr_ctrl.action = cpu_to_le16(cmd_action);
2077		cmd_ptr->params.pkt_aggr_ctrl.enable =
2078						cpu_to_le16(*(u16 *)data_buf);
2079		cmd_ptr->size =
2080			cpu_to_le16(sizeof(struct host_cmd_ds_pkt_aggr_ctrl) +
2081				    S_DS_GEN);
2082		break;
2083	case HostCmd_CMD_P2P_MODE_CFG:
2084		cmd_ptr->command = cpu_to_le16(cmd_no);
2085		cmd_ptr->params.mode_cfg.action = cpu_to_le16(cmd_action);
2086		cmd_ptr->params.mode_cfg.mode = cpu_to_le16(
2087						get_unaligned((u16 *)data_buf));
2088		cmd_ptr->size =
2089			cpu_to_le16(sizeof(struct host_cmd_ds_p2p_mode_cfg) +
2090				    S_DS_GEN);
2091		break;
2092	case HostCmd_CMD_FUNC_INIT:
2093		if (priv->adapter->hw_status == MWIFIEX_HW_STATUS_RESET)
2094			priv->adapter->hw_status = MWIFIEX_HW_STATUS_READY;
2095		cmd_ptr->command = cpu_to_le16(cmd_no);
2096		cmd_ptr->size = cpu_to_le16(S_DS_GEN);
2097		break;
2098	case HostCmd_CMD_FUNC_SHUTDOWN:
2099		priv->adapter->hw_status = MWIFIEX_HW_STATUS_RESET;
2100		cmd_ptr->command = cpu_to_le16(cmd_no);
2101		cmd_ptr->size = cpu_to_le16(S_DS_GEN);
2102		break;
2103	case HostCmd_CMD_11N_ADDBA_REQ:
2104		ret = mwifiex_cmd_11n_addba_req(cmd_ptr, data_buf);
2105		break;
2106	case HostCmd_CMD_11N_DELBA:
2107		ret = mwifiex_cmd_11n_delba(cmd_ptr, data_buf);
2108		break;
2109	case HostCmd_CMD_11N_ADDBA_RSP:
2110		ret = mwifiex_cmd_11n_addba_rsp_gen(priv, cmd_ptr, data_buf);
2111		break;
2112	case HostCmd_CMD_802_11_KEY_MATERIAL:
2113		ret = mwifiex_cmd_802_11_key_material(priv, cmd_ptr,
2114						      cmd_action, cmd_oid,
2115						      data_buf);
2116		break;
2117	case HostCmd_CMD_802_11D_DOMAIN_INFO:
2118		ret = mwifiex_cmd_802_11d_domain_info(priv, cmd_ptr,
2119						      cmd_action);
2120		break;
2121	case HostCmd_CMD_RECONFIGURE_TX_BUFF:
2122		ret = mwifiex_cmd_recfg_tx_buf(priv, cmd_ptr, cmd_action,
2123					       data_buf);
2124		break;
2125	case HostCmd_CMD_AMSDU_AGGR_CTRL:
2126		ret = mwifiex_cmd_amsdu_aggr_ctrl(cmd_ptr, cmd_action,
2127						  data_buf);
2128		break;
2129	case HostCmd_CMD_11N_CFG:
2130		ret = mwifiex_cmd_11n_cfg(priv, cmd_ptr, cmd_action, data_buf);
2131		break;
2132	case HostCmd_CMD_WMM_GET_STATUS:
2133		mwifiex_dbg(priv->adapter, CMD,
2134			    "cmd: WMM: WMM_GET_STATUS cmd sent\n");
2135		cmd_ptr->command = cpu_to_le16(HostCmd_CMD_WMM_GET_STATUS);
2136		cmd_ptr->size =
2137			cpu_to_le16(sizeof(struct host_cmd_ds_wmm_get_status) +
2138				    S_DS_GEN);
2139		ret = 0;
2140		break;
2141	case HostCmd_CMD_802_11_IBSS_COALESCING_STATUS:
2142		ret = mwifiex_cmd_ibss_coalescing_status(cmd_ptr, cmd_action,
2143							 data_buf);
2144		break;
2145	case HostCmd_CMD_802_11_SCAN_EXT:
2146		ret = mwifiex_cmd_802_11_scan_ext(priv, cmd_ptr, data_buf);
2147		break;
2148	case HostCmd_CMD_MEM_ACCESS:
2149		ret = mwifiex_cmd_mem_access(cmd_ptr, cmd_action, data_buf);
2150		break;
2151	case HostCmd_CMD_MAC_REG_ACCESS:
2152	case HostCmd_CMD_BBP_REG_ACCESS:
2153	case HostCmd_CMD_RF_REG_ACCESS:
2154	case HostCmd_CMD_PMIC_REG_ACCESS:
2155	case HostCmd_CMD_CAU_REG_ACCESS:
2156	case HostCmd_CMD_802_11_EEPROM_ACCESS:
2157		ret = mwifiex_cmd_reg_access(cmd_ptr, cmd_action, data_buf);
2158		break;
2159	case HostCmd_CMD_SET_BSS_MODE:
2160		cmd_ptr->command = cpu_to_le16(cmd_no);
2161		if (priv->bss_mode == NL80211_IFTYPE_ADHOC)
2162			cmd_ptr->params.bss_mode.con_type =
2163				CONNECTION_TYPE_ADHOC;
2164		else if (priv->bss_mode == NL80211_IFTYPE_STATION ||
2165			 priv->bss_mode == NL80211_IFTYPE_P2P_CLIENT)
2166			cmd_ptr->params.bss_mode.con_type =
2167				CONNECTION_TYPE_INFRA;
2168		else if (priv->bss_mode == NL80211_IFTYPE_AP ||
2169			 priv->bss_mode == NL80211_IFTYPE_P2P_GO)
2170			cmd_ptr->params.bss_mode.con_type = CONNECTION_TYPE_AP;
2171		cmd_ptr->size = cpu_to_le16(sizeof(struct
2172				host_cmd_ds_set_bss_mode) + S_DS_GEN);
2173		ret = 0;
2174		break;
2175	case HostCmd_CMD_PCIE_DESC_DETAILS:
2176		ret = mwifiex_cmd_pcie_host_spec(priv, cmd_ptr, cmd_action);
2177		break;
2178	case HostCmd_CMD_802_11_SUBSCRIBE_EVENT:
2179		ret = mwifiex_cmd_802_11_subsc_evt(priv, cmd_ptr, data_buf);
2180		break;
2181	case HostCmd_CMD_MEF_CFG:
2182		ret = mwifiex_cmd_mef_cfg(priv, cmd_ptr, data_buf);
2183		break;
2184	case HostCmd_CMD_COALESCE_CFG:
2185		ret = mwifiex_cmd_coalesce_cfg(priv, cmd_ptr, cmd_action,
2186					       data_buf);
2187		break;
2188	case HostCmd_CMD_TDLS_OPER:
2189		ret = mwifiex_cmd_tdls_oper(priv, cmd_ptr, data_buf);
2190		break;
2191	case HostCmd_CMD_TDLS_CONFIG:
2192		ret = mwifiex_cmd_tdls_config(priv, cmd_ptr, cmd_action,
2193					      data_buf);
2194		break;
2195	case HostCmd_CMD_CHAN_REPORT_REQUEST:
2196		ret = mwifiex_cmd_issue_chan_report_request(priv, cmd_ptr,
2197							    data_buf);
2198		break;
2199	case HostCmd_CMD_SDIO_SP_RX_AGGR_CFG:
2200		ret = mwifiex_cmd_sdio_rx_aggr_cfg(cmd_ptr, cmd_action,
2201						   data_buf);
2202		break;
2203	case HostCmd_CMD_HS_WAKEUP_REASON:
2204		ret = mwifiex_cmd_get_wakeup_reason(priv, cmd_ptr);
2205		break;
2206	case HostCmd_CMD_MC_POLICY:
2207		ret = mwifiex_cmd_set_mc_policy(priv, cmd_ptr, cmd_action,
2208						data_buf);
2209		break;
2210	case HostCmd_CMD_ROBUST_COEX:
2211		ret = mwifiex_cmd_robust_coex(priv, cmd_ptr, cmd_action,
2212					      data_buf);
2213		break;
2214	case HostCmd_CMD_GTK_REKEY_OFFLOAD_CFG:
2215		ret = mwifiex_cmd_gtk_rekey_offload(priv, cmd_ptr, cmd_action,
2216						    data_buf);
2217		break;
2218	case HostCmd_CMD_CHAN_REGION_CFG:
2219		ret = mwifiex_cmd_chan_region_cfg(priv, cmd_ptr, cmd_action);
2220		break;
2221	case HostCmd_CMD_FW_DUMP_EVENT:
2222		cmd_ptr->command = cpu_to_le16(cmd_no);
2223		cmd_ptr->size = cpu_to_le16(S_DS_GEN);
2224		break;
2225	case HostCmd_CMD_STA_CONFIGURE:
2226		ret = mwifiex_cmd_get_chan_info(cmd_ptr, cmd_action);
2227		break;
2228	default:
2229		mwifiex_dbg(priv->adapter, ERROR,
2230			    "PREP_CMD: unknown cmd- %#x\n", cmd_no);
2231		ret = -1;
2232		break;
2233	}
2234	return ret;
2235}
2236
2237/*
2238 * This function issues commands to initialize firmware.
2239 *
2240 * This is called after firmware download to bring the card to
2241 * working state.
2242 * Function is also called during reinitialization of virtual
2243 * interfaces.
2244 *
2245 * The following commands are issued sequentially -
2246 *      - Set PCI-Express host buffer configuration (PCIE only)
2247 *      - Function init (for first interface only)
2248 *      - Read MAC address (for first interface only)
2249 *      - Reconfigure Tx buffer size (for first interface only)
2250 *      - Enable auto deep sleep (for first interface only)
2251 *      - Get Tx rate
2252 *      - Get Tx power
2253 *      - Set IBSS coalescing status
2254 *      - Set AMSDU aggregation control
2255 *      - Set 11d control
2256 *      - Set MAC control (this must be the last command to initialize firmware)
2257 */
2258int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta, bool init)
2259{
2260	struct mwifiex_adapter *adapter = priv->adapter;
2261	int ret;
2262	struct mwifiex_ds_11n_amsdu_aggr_ctrl amsdu_aggr_ctrl;
2263	struct mwifiex_ds_auto_ds auto_ds;
2264	enum state_11d_t state_11d;
2265	struct mwifiex_ds_11n_tx_cfg tx_cfg;
2266	u8 sdio_sp_rx_aggr_enable;
2267	u16 packet_aggr_enable;
2268	int data;
2269
2270	if (first_sta) {
2271		if (priv->adapter->iface_type == MWIFIEX_PCIE) {
2272			ret = mwifiex_send_cmd(priv,
2273					       HostCmd_CMD_PCIE_DESC_DETAILS,
2274					       HostCmd_ACT_GEN_SET, 0, NULL,
2275					       true);
2276			if (ret)
2277				return -1;
2278		}
2279
2280		ret = mwifiex_send_cmd(priv, HostCmd_CMD_FUNC_INIT,
2281				       HostCmd_ACT_GEN_SET, 0, NULL, true);
2282		if (ret)
2283			return -1;
2284
2285		/* Download calibration data to firmware.
2286		 * The cal-data can be read from device tree and/or
2287		 * a configuration file and downloaded to firmware.
2288		 */
2289		if (adapter->dt_node) {
2290			if (of_property_read_u32(adapter->dt_node,
2291						 "marvell,wakeup-pin",
2292						 &data) == 0) {
2293				pr_debug("Wakeup pin = 0x%x\n", data);
2294				adapter->hs_cfg.gpio = data;
2295			}
2296
2297			mwifiex_dnld_dt_cfgdata(priv, adapter->dt_node,
2298						"marvell,caldata");
2299		}
2300
2301		if (adapter->cal_data)
2302			mwifiex_send_cmd(priv, HostCmd_CMD_CFG_DATA,
2303					 HostCmd_ACT_GEN_SET, 0, NULL, true);
2304
2305		/* Read MAC address from HW */
2306		ret = mwifiex_send_cmd(priv, HostCmd_CMD_GET_HW_SPEC,
2307				       HostCmd_ACT_GEN_GET, 0, NULL, true);
2308		if (ret)
2309			return -1;
2310
2311		/** Set SDIO Single Port RX Aggr Info */
2312		if (priv->adapter->iface_type == MWIFIEX_SDIO &&
2313		    ISSUPP_SDIO_SPA_ENABLED(priv->adapter->fw_cap_info) &&
2314		    !priv->adapter->host_disable_sdio_rx_aggr) {
2315			sdio_sp_rx_aggr_enable = true;
2316			ret = mwifiex_send_cmd(priv,
2317					       HostCmd_CMD_SDIO_SP_RX_AGGR_CFG,
2318					       HostCmd_ACT_GEN_SET, 0,
2319					       &sdio_sp_rx_aggr_enable,
2320					       true);
2321			if (ret) {
2322				mwifiex_dbg(priv->adapter, ERROR,
2323					    "error while enabling SP aggregation..disable it");
2324				adapter->sdio_rx_aggr_enable = false;
2325			}
2326		}
2327
2328		/* Reconfigure tx buf size */
2329		ret = mwifiex_send_cmd(priv, HostCmd_CMD_RECONFIGURE_TX_BUFF,
2330				       HostCmd_ACT_GEN_SET, 0,
2331				       &priv->adapter->tx_buf_size, true);
2332		if (ret)
2333			return -1;
2334
2335		if (priv->bss_type != MWIFIEX_BSS_TYPE_UAP) {
2336			/* Enable IEEE PS by default */
2337			priv->adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_PSP;
2338			ret = mwifiex_send_cmd(priv,
2339					       HostCmd_CMD_802_11_PS_MODE_ENH,
2340					       EN_AUTO_PS, BITMAP_STA_PS, NULL,
2341					       true);
2342			if (ret)
2343				return -1;
2344		}
2345
2346		if (drcs) {
2347			adapter->drcs_enabled = true;
2348			if (ISSUPP_DRCS_ENABLED(adapter->fw_cap_info))
2349				ret = mwifiex_send_cmd(priv,
2350						       HostCmd_CMD_MC_POLICY,
2351						       HostCmd_ACT_GEN_SET, 0,
2352						       &adapter->drcs_enabled,
2353						       true);
2354			if (ret)
2355				return -1;
2356		}
2357
2358		mwifiex_send_cmd(priv, HostCmd_CMD_CHAN_REGION_CFG,
2359				 HostCmd_ACT_GEN_GET, 0, NULL, true);
2360	}
2361
2362	/* get tx rate */
2363	ret = mwifiex_send_cmd(priv, HostCmd_CMD_TX_RATE_CFG,
2364			       HostCmd_ACT_GEN_GET, 0, NULL, true);
2365	if (ret)
2366		return -1;
2367	priv->data_rate = 0;
2368
2369	/* get tx power */
2370	ret = mwifiex_send_cmd(priv, HostCmd_CMD_RF_TX_PWR,
2371			       HostCmd_ACT_GEN_GET, 0, NULL, true);
2372	if (ret)
2373		return -1;
2374
2375	memset(&amsdu_aggr_ctrl, 0, sizeof(amsdu_aggr_ctrl));
2376	amsdu_aggr_ctrl.enable = true;
2377	/* Send request to firmware */
2378	ret = mwifiex_send_cmd(priv, HostCmd_CMD_AMSDU_AGGR_CTRL,
2379			       HostCmd_ACT_GEN_SET, 0,
2380			       &amsdu_aggr_ctrl, true);
2381	if (ret)
2382		return -1;
2383	/* MAC Control must be the last command in init_fw */
2384	/* set MAC Control */
2385	ret = mwifiex_send_cmd(priv, HostCmd_CMD_MAC_CONTROL,
2386			       HostCmd_ACT_GEN_SET, 0,
2387			       &priv->curr_pkt_filter, true);
2388	if (ret)
2389		return -1;
2390
2391	if (!disable_auto_ds && first_sta &&
2392	    priv->bss_type != MWIFIEX_BSS_TYPE_UAP) {
2393		/* Enable auto deep sleep */
2394		auto_ds.auto_ds = DEEP_SLEEP_ON;
2395		auto_ds.idle_time = DEEP_SLEEP_IDLE_TIME;
2396		ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_PS_MODE_ENH,
2397				       EN_AUTO_PS, BITMAP_AUTO_DS,
2398				       &auto_ds, true);
2399		if (ret)
2400			return -1;
2401	}
2402
2403	if (priv->bss_type != MWIFIEX_BSS_TYPE_UAP) {
2404		/* Send cmd to FW to enable/disable 11D function */
2405		state_11d = ENABLE_11D;
2406		ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB,
2407				       HostCmd_ACT_GEN_SET, DOT11D_I,
2408				       &state_11d, true);
2409		if (ret)
2410			mwifiex_dbg(priv->adapter, ERROR,
2411				    "11D: failed to enable 11D\n");
2412	}
2413
2414	/* Pacekt aggregation handshake with firmware */
2415	if (aggr_ctrl) {
2416		packet_aggr_enable = true;
2417		mwifiex_send_cmd(priv, HostCmd_CMD_PACKET_AGGR_CTRL,
2418				 HostCmd_ACT_GEN_SET, 0,
2419				 &packet_aggr_enable, true);
2420	}
2421
2422	/* Send cmd to FW to configure 11n specific configuration
2423	 * (Short GI, Channel BW, Green field support etc.) for transmit
2424	 */
2425	tx_cfg.tx_htcap = MWIFIEX_FW_DEF_HTTXCFG;
2426	ret = mwifiex_send_cmd(priv, HostCmd_CMD_11N_CFG,
2427			       HostCmd_ACT_GEN_SET, 0, &tx_cfg, true);
2428
2429	if (init) {
2430		/* set last_init_cmd before sending the command */
2431		priv->adapter->last_init_cmd = HostCmd_CMD_11N_CFG;
2432		ret = -EINPROGRESS;
2433	}
2434
2435	return ret;
2436}
2437