1/*
2 * NXP Wireless LAN device driver: AP specific 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 "main.h"
21#include "11ac.h"
22#include "11n.h"
23
24/* This function parses security related parameters from cfg80211_ap_settings
25 * and sets into FW understandable bss_config structure.
26 */
27int mwifiex_set_secure_params(struct mwifiex_private *priv,
28			      struct mwifiex_uap_bss_param *bss_config,
29			      struct cfg80211_ap_settings *params) {
30	int i;
31	struct mwifiex_wep_key wep_key;
32
33	if (!params->privacy) {
34		bss_config->protocol = PROTOCOL_NO_SECURITY;
35		bss_config->key_mgmt = KEY_MGMT_NONE;
36		bss_config->wpa_cfg.length = 0;
37		priv->sec_info.wep_enabled = 0;
38		priv->sec_info.wpa_enabled = 0;
39		priv->sec_info.wpa2_enabled = 0;
40
41		return 0;
42	}
43
44	switch (params->auth_type) {
45	case NL80211_AUTHTYPE_OPEN_SYSTEM:
46		bss_config->auth_mode = WLAN_AUTH_OPEN;
47		break;
48	case NL80211_AUTHTYPE_SHARED_KEY:
49		bss_config->auth_mode = WLAN_AUTH_SHARED_KEY;
50		break;
51	case NL80211_AUTHTYPE_NETWORK_EAP:
52		bss_config->auth_mode = WLAN_AUTH_LEAP;
53		break;
54	default:
55		bss_config->auth_mode = MWIFIEX_AUTH_MODE_AUTO;
56		break;
57	}
58
59	bss_config->key_mgmt_operation |= KEY_MGMT_ON_HOST;
60
61	for (i = 0; i < params->crypto.n_akm_suites; i++) {
62		switch (params->crypto.akm_suites[i]) {
63		case WLAN_AKM_SUITE_8021X:
64			if (params->crypto.wpa_versions &
65			    NL80211_WPA_VERSION_1) {
66				bss_config->protocol = PROTOCOL_WPA;
67				bss_config->key_mgmt = KEY_MGMT_EAP;
68			}
69			if (params->crypto.wpa_versions &
70			    NL80211_WPA_VERSION_2) {
71				bss_config->protocol |= PROTOCOL_WPA2;
72				bss_config->key_mgmt = KEY_MGMT_EAP;
73			}
74			break;
75		case WLAN_AKM_SUITE_PSK:
76			if (params->crypto.wpa_versions &
77			    NL80211_WPA_VERSION_1) {
78				bss_config->protocol = PROTOCOL_WPA;
79				bss_config->key_mgmt = KEY_MGMT_PSK;
80			}
81			if (params->crypto.wpa_versions &
82			    NL80211_WPA_VERSION_2) {
83				bss_config->protocol |= PROTOCOL_WPA2;
84				bss_config->key_mgmt = KEY_MGMT_PSK;
85			}
86			break;
87		default:
88			break;
89		}
90	}
91	for (i = 0; i < params->crypto.n_ciphers_pairwise; i++) {
92		switch (params->crypto.ciphers_pairwise[i]) {
93		case WLAN_CIPHER_SUITE_WEP40:
94		case WLAN_CIPHER_SUITE_WEP104:
95			break;
96		case WLAN_CIPHER_SUITE_TKIP:
97			if (params->crypto.wpa_versions & NL80211_WPA_VERSION_1)
98				bss_config->wpa_cfg.pairwise_cipher_wpa |=
99								CIPHER_TKIP;
100			if (params->crypto.wpa_versions & NL80211_WPA_VERSION_2)
101				bss_config->wpa_cfg.pairwise_cipher_wpa2 |=
102								CIPHER_TKIP;
103			break;
104		case WLAN_CIPHER_SUITE_CCMP:
105			if (params->crypto.wpa_versions & NL80211_WPA_VERSION_1)
106				bss_config->wpa_cfg.pairwise_cipher_wpa |=
107								CIPHER_AES_CCMP;
108			if (params->crypto.wpa_versions & NL80211_WPA_VERSION_2)
109				bss_config->wpa_cfg.pairwise_cipher_wpa2 |=
110								CIPHER_AES_CCMP;
111		default:
112			break;
113		}
114	}
115
116	switch (params->crypto.cipher_group) {
117	case WLAN_CIPHER_SUITE_WEP40:
118	case WLAN_CIPHER_SUITE_WEP104:
119		if (priv->sec_info.wep_enabled) {
120			bss_config->protocol = PROTOCOL_STATIC_WEP;
121			bss_config->key_mgmt = KEY_MGMT_NONE;
122			bss_config->wpa_cfg.length = 0;
123
124			for (i = 0; i < NUM_WEP_KEYS; i++) {
125				wep_key = priv->wep_key[i];
126				bss_config->wep_cfg[i].key_index = i;
127
128				if (priv->wep_key_curr_index == i)
129					bss_config->wep_cfg[i].is_default = 1;
130				else
131					bss_config->wep_cfg[i].is_default = 0;
132
133				bss_config->wep_cfg[i].length =
134							     wep_key.key_length;
135				memcpy(&bss_config->wep_cfg[i].key,
136				       &wep_key.key_material,
137				       wep_key.key_length);
138			}
139		}
140		break;
141	case WLAN_CIPHER_SUITE_TKIP:
142		bss_config->wpa_cfg.group_cipher = CIPHER_TKIP;
143		break;
144	case WLAN_CIPHER_SUITE_CCMP:
145		bss_config->wpa_cfg.group_cipher = CIPHER_AES_CCMP;
146		break;
147	default:
148		break;
149	}
150
151	return 0;
152}
153
154/* This function updates 11n related parameters from IE and sets them into
155 * bss_config structure.
156 */
157void
158mwifiex_set_ht_params(struct mwifiex_private *priv,
159		      struct mwifiex_uap_bss_param *bss_cfg,
160		      struct cfg80211_ap_settings *params)
161{
162	const u8 *ht_ie;
163
164	if (!ISSUPP_11NENABLED(priv->adapter->fw_cap_info))
165		return;
166
167	ht_ie = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, params->beacon.tail,
168				 params->beacon.tail_len);
169	if (ht_ie) {
170		memcpy(&bss_cfg->ht_cap, ht_ie + 2,
171		       sizeof(struct ieee80211_ht_cap));
172		priv->ap_11n_enabled = 1;
173	} else {
174		memset(&bss_cfg->ht_cap, 0, sizeof(struct ieee80211_ht_cap));
175		bss_cfg->ht_cap.cap_info = cpu_to_le16(MWIFIEX_DEF_HT_CAP);
176		bss_cfg->ht_cap.ampdu_params_info = MWIFIEX_DEF_AMPDU;
177	}
178
179	return;
180}
181
182/* This function updates 11ac related parameters from IE
183 * and sets them into bss_config structure.
184 */
185void mwifiex_set_vht_params(struct mwifiex_private *priv,
186			    struct mwifiex_uap_bss_param *bss_cfg,
187			    struct cfg80211_ap_settings *params)
188{
189	const u8 *vht_ie;
190
191	vht_ie = cfg80211_find_ie(WLAN_EID_VHT_CAPABILITY, params->beacon.tail,
192				  params->beacon.tail_len);
193	if (vht_ie) {
194		memcpy(&bss_cfg->vht_cap, vht_ie + 2,
195		       sizeof(struct ieee80211_vht_cap));
196		priv->ap_11ac_enabled = 1;
197	} else {
198		priv->ap_11ac_enabled = 0;
199	}
200
201	return;
202}
203
204/* This function updates 11ac related parameters from IE
205 * and sets them into bss_config structure.
206 */
207void mwifiex_set_tpc_params(struct mwifiex_private *priv,
208			    struct mwifiex_uap_bss_param *bss_cfg,
209			    struct cfg80211_ap_settings *params)
210{
211	const u8 *tpc_ie;
212
213	tpc_ie = cfg80211_find_ie(WLAN_EID_TPC_REQUEST, params->beacon.tail,
214				  params->beacon.tail_len);
215	if (tpc_ie)
216		bss_cfg->power_constraint = *(tpc_ie + 2);
217	else
218		bss_cfg->power_constraint = 0;
219}
220
221/* Enable VHT only when cfg80211_ap_settings has VHT IE.
222 * Otherwise disable VHT.
223 */
224void mwifiex_set_vht_width(struct mwifiex_private *priv,
225			   enum nl80211_chan_width width,
226			   bool ap_11ac_enable)
227{
228	struct mwifiex_adapter *adapter = priv->adapter;
229	struct mwifiex_11ac_vht_cfg vht_cfg;
230
231	vht_cfg.band_config = VHT_CFG_5GHZ;
232	vht_cfg.cap_info = adapter->hw_dot_11ac_dev_cap;
233
234	if (!ap_11ac_enable) {
235		vht_cfg.mcs_tx_set = DISABLE_VHT_MCS_SET;
236		vht_cfg.mcs_rx_set = DISABLE_VHT_MCS_SET;
237	} else {
238		vht_cfg.mcs_tx_set = DEFAULT_VHT_MCS_SET;
239		vht_cfg.mcs_rx_set = DEFAULT_VHT_MCS_SET;
240	}
241
242	vht_cfg.misc_config  = VHT_CAP_UAP_ONLY;
243
244	if (ap_11ac_enable && width >= NL80211_CHAN_WIDTH_80)
245		vht_cfg.misc_config |= VHT_BW_80_160_80P80;
246
247	mwifiex_send_cmd(priv, HostCmd_CMD_11AC_CFG,
248			 HostCmd_ACT_GEN_SET, 0, &vht_cfg, true);
249
250	return;
251}
252
253/* This function finds supported rates IE from beacon parameter and sets
254 * these rates into bss_config structure.
255 */
256void
257mwifiex_set_uap_rates(struct mwifiex_uap_bss_param *bss_cfg,
258		      struct cfg80211_ap_settings *params)
259{
260	struct ieee_types_header *rate_ie;
261	int var_offset = offsetof(struct ieee80211_mgmt, u.beacon.variable);
262	const u8 *var_pos = params->beacon.head + var_offset;
263	int len = params->beacon.head_len - var_offset;
264	u8 rate_len = 0;
265
266	rate_ie = (void *)cfg80211_find_ie(WLAN_EID_SUPP_RATES, var_pos, len);
267	if (rate_ie) {
268		if (rate_ie->len > MWIFIEX_SUPPORTED_RATES)
269			return;
270		memcpy(bss_cfg->rates, rate_ie + 1, rate_ie->len);
271		rate_len = rate_ie->len;
272	}
273
274	rate_ie = (void *)cfg80211_find_ie(WLAN_EID_EXT_SUPP_RATES,
275					   params->beacon.tail,
276					   params->beacon.tail_len);
277	if (rate_ie) {
278		if (rate_ie->len > MWIFIEX_SUPPORTED_RATES - rate_len)
279			return;
280		memcpy(bss_cfg->rates + rate_len, rate_ie + 1, rate_ie->len);
281	}
282
283	return;
284}
285
286/* This function initializes some of mwifiex_uap_bss_param variables.
287 * This helps FW in ignoring invalid values. These values may or may not
288 * be get updated to valid ones at later stage.
289 */
290void mwifiex_set_sys_config_invalid_data(struct mwifiex_uap_bss_param *config)
291{
292	config->bcast_ssid_ctl = 0x7F;
293	config->radio_ctl = 0x7F;
294	config->dtim_period = 0x7F;
295	config->beacon_period = 0x7FFF;
296	config->auth_mode = 0x7F;
297	config->rts_threshold = 0x7FFF;
298	config->frag_threshold = 0x7FFF;
299	config->retry_limit = 0x7F;
300	config->qos_info = 0xFF;
301}
302
303/* This function parses BSS related parameters from structure
304 * and prepares TLVs specific to WPA/WPA2 security.
305 * These TLVs are appended to command buffer.
306 */
307static void
308mwifiex_uap_bss_wpa(u8 **tlv_buf, void *cmd_buf, u16 *param_size)
309{
310	struct host_cmd_tlv_pwk_cipher *pwk_cipher;
311	struct host_cmd_tlv_gwk_cipher *gwk_cipher;
312	struct host_cmd_tlv_passphrase *passphrase;
313	struct host_cmd_tlv_akmp *tlv_akmp;
314	struct mwifiex_uap_bss_param *bss_cfg = cmd_buf;
315	u16 cmd_size = *param_size;
316	u8 *tlv = *tlv_buf;
317
318	tlv_akmp = (struct host_cmd_tlv_akmp *)tlv;
319	tlv_akmp->header.type = cpu_to_le16(TLV_TYPE_UAP_AKMP);
320	tlv_akmp->header.len = cpu_to_le16(sizeof(struct host_cmd_tlv_akmp) -
321					sizeof(struct mwifiex_ie_types_header));
322	tlv_akmp->key_mgmt_operation = cpu_to_le16(bss_cfg->key_mgmt_operation);
323	tlv_akmp->key_mgmt = cpu_to_le16(bss_cfg->key_mgmt);
324	cmd_size += sizeof(struct host_cmd_tlv_akmp);
325	tlv += sizeof(struct host_cmd_tlv_akmp);
326
327	if (bss_cfg->wpa_cfg.pairwise_cipher_wpa & VALID_CIPHER_BITMAP) {
328		pwk_cipher = (struct host_cmd_tlv_pwk_cipher *)tlv;
329		pwk_cipher->header.type = cpu_to_le16(TLV_TYPE_PWK_CIPHER);
330		pwk_cipher->header.len =
331			cpu_to_le16(sizeof(struct host_cmd_tlv_pwk_cipher) -
332				    sizeof(struct mwifiex_ie_types_header));
333		pwk_cipher->proto = cpu_to_le16(PROTOCOL_WPA);
334		pwk_cipher->cipher = bss_cfg->wpa_cfg.pairwise_cipher_wpa;
335		cmd_size += sizeof(struct host_cmd_tlv_pwk_cipher);
336		tlv += sizeof(struct host_cmd_tlv_pwk_cipher);
337	}
338
339	if (bss_cfg->wpa_cfg.pairwise_cipher_wpa2 & VALID_CIPHER_BITMAP) {
340		pwk_cipher = (struct host_cmd_tlv_pwk_cipher *)tlv;
341		pwk_cipher->header.type = cpu_to_le16(TLV_TYPE_PWK_CIPHER);
342		pwk_cipher->header.len =
343			cpu_to_le16(sizeof(struct host_cmd_tlv_pwk_cipher) -
344				    sizeof(struct mwifiex_ie_types_header));
345		pwk_cipher->proto = cpu_to_le16(PROTOCOL_WPA2);
346		pwk_cipher->cipher = bss_cfg->wpa_cfg.pairwise_cipher_wpa2;
347		cmd_size += sizeof(struct host_cmd_tlv_pwk_cipher);
348		tlv += sizeof(struct host_cmd_tlv_pwk_cipher);
349	}
350
351	if (bss_cfg->wpa_cfg.group_cipher & VALID_CIPHER_BITMAP) {
352		gwk_cipher = (struct host_cmd_tlv_gwk_cipher *)tlv;
353		gwk_cipher->header.type = cpu_to_le16(TLV_TYPE_GWK_CIPHER);
354		gwk_cipher->header.len =
355			cpu_to_le16(sizeof(struct host_cmd_tlv_gwk_cipher) -
356				    sizeof(struct mwifiex_ie_types_header));
357		gwk_cipher->cipher = bss_cfg->wpa_cfg.group_cipher;
358		cmd_size += sizeof(struct host_cmd_tlv_gwk_cipher);
359		tlv += sizeof(struct host_cmd_tlv_gwk_cipher);
360	}
361
362	if (bss_cfg->wpa_cfg.length) {
363		passphrase = (struct host_cmd_tlv_passphrase *)tlv;
364		passphrase->header.type =
365				cpu_to_le16(TLV_TYPE_UAP_WPA_PASSPHRASE);
366		passphrase->header.len = cpu_to_le16(bss_cfg->wpa_cfg.length);
367		memcpy(passphrase->passphrase, bss_cfg->wpa_cfg.passphrase,
368		       bss_cfg->wpa_cfg.length);
369		cmd_size += sizeof(struct mwifiex_ie_types_header) +
370			    bss_cfg->wpa_cfg.length;
371		tlv += sizeof(struct mwifiex_ie_types_header) +
372				bss_cfg->wpa_cfg.length;
373	}
374
375	*param_size = cmd_size;
376	*tlv_buf = tlv;
377
378	return;
379}
380
381/* This function parses WMM related parameters from cfg80211_ap_settings
382 * structure and updates bss_config structure.
383 */
384void
385mwifiex_set_wmm_params(struct mwifiex_private *priv,
386		       struct mwifiex_uap_bss_param *bss_cfg,
387		       struct cfg80211_ap_settings *params)
388{
389	const u8 *vendor_ie;
390	const u8 *wmm_ie;
391	u8 wmm_oui[] = {0x00, 0x50, 0xf2, 0x02};
392
393	vendor_ie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT,
394					    WLAN_OUI_TYPE_MICROSOFT_WMM,
395					    params->beacon.tail,
396					    params->beacon.tail_len);
397	if (vendor_ie) {
398		wmm_ie = vendor_ie;
399		if (*(wmm_ie + 1) > sizeof(struct mwifiex_types_wmm_info))
400			return;
401		memcpy(&bss_cfg->wmm_info, wmm_ie +
402		       sizeof(struct ieee_types_header), *(wmm_ie + 1));
403		priv->wmm_enabled = 1;
404	} else {
405		memset(&bss_cfg->wmm_info, 0, sizeof(bss_cfg->wmm_info));
406		memcpy(&bss_cfg->wmm_info.oui, wmm_oui, sizeof(wmm_oui));
407		bss_cfg->wmm_info.subtype = MWIFIEX_WMM_SUBTYPE;
408		bss_cfg->wmm_info.version = MWIFIEX_WMM_VERSION;
409		priv->wmm_enabled = 0;
410	}
411
412	bss_cfg->qos_info = 0x00;
413	return;
414}
415/* This function parses BSS related parameters from structure
416 * and prepares TLVs specific to WEP encryption.
417 * These TLVs are appended to command buffer.
418 */
419static void
420mwifiex_uap_bss_wep(u8 **tlv_buf, void *cmd_buf, u16 *param_size)
421{
422	struct host_cmd_tlv_wep_key *wep_key;
423	u16 cmd_size = *param_size;
424	int i;
425	u8 *tlv = *tlv_buf;
426	struct mwifiex_uap_bss_param *bss_cfg = cmd_buf;
427
428	for (i = 0; i < NUM_WEP_KEYS; i++) {
429		if (bss_cfg->wep_cfg[i].length &&
430		    (bss_cfg->wep_cfg[i].length == WLAN_KEY_LEN_WEP40 ||
431		     bss_cfg->wep_cfg[i].length == WLAN_KEY_LEN_WEP104)) {
432			wep_key = (struct host_cmd_tlv_wep_key *)tlv;
433			wep_key->header.type =
434				cpu_to_le16(TLV_TYPE_UAP_WEP_KEY);
435			wep_key->header.len =
436				cpu_to_le16(bss_cfg->wep_cfg[i].length + 2);
437			wep_key->key_index = bss_cfg->wep_cfg[i].key_index;
438			wep_key->is_default = bss_cfg->wep_cfg[i].is_default;
439			memcpy(wep_key->key, bss_cfg->wep_cfg[i].key,
440			       bss_cfg->wep_cfg[i].length);
441			cmd_size += sizeof(struct mwifiex_ie_types_header) + 2 +
442				    bss_cfg->wep_cfg[i].length;
443			tlv += sizeof(struct mwifiex_ie_types_header) + 2 +
444				    bss_cfg->wep_cfg[i].length;
445		}
446	}
447
448	*param_size = cmd_size;
449	*tlv_buf = tlv;
450
451	return;
452}
453
454/* This function enable 11D if userspace set the country IE.
455 */
456void mwifiex_config_uap_11d(struct mwifiex_private *priv,
457			    struct cfg80211_beacon_data *beacon_data)
458{
459	enum state_11d_t state_11d;
460	const u8 *country_ie;
461
462	country_ie = cfg80211_find_ie(WLAN_EID_COUNTRY, beacon_data->tail,
463				      beacon_data->tail_len);
464	if (country_ie) {
465		/* Send cmd to FW to enable 11D function */
466		state_11d = ENABLE_11D;
467		if (mwifiex_send_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB,
468				     HostCmd_ACT_GEN_SET, DOT11D_I,
469				     &state_11d, true)) {
470			mwifiex_dbg(priv->adapter, ERROR,
471				    "11D: failed to enable 11D\n");
472		}
473	}
474}
475
476/* This function parses BSS related parameters from structure
477 * and prepares TLVs. These TLVs are appended to command buffer.
478*/
479static int
480mwifiex_uap_bss_param_prepare(u8 *tlv, void *cmd_buf, u16 *param_size)
481{
482	struct host_cmd_tlv_mac_addr *mac_tlv;
483	struct host_cmd_tlv_dtim_period *dtim_period;
484	struct host_cmd_tlv_beacon_period *beacon_period;
485	struct host_cmd_tlv_ssid *ssid;
486	struct host_cmd_tlv_bcast_ssid *bcast_ssid;
487	struct host_cmd_tlv_channel_band *chan_band;
488	struct host_cmd_tlv_frag_threshold *frag_threshold;
489	struct host_cmd_tlv_rts_threshold *rts_threshold;
490	struct host_cmd_tlv_retry_limit *retry_limit;
491	struct host_cmd_tlv_encrypt_protocol *encrypt_protocol;
492	struct host_cmd_tlv_auth_type *auth_type;
493	struct host_cmd_tlv_rates *tlv_rates;
494	struct host_cmd_tlv_ageout_timer *ao_timer, *ps_ao_timer;
495	struct host_cmd_tlv_power_constraint *pwr_ct;
496	struct mwifiex_ie_types_htcap *htcap;
497	struct mwifiex_ie_types_wmmcap *wmm_cap;
498	struct mwifiex_uap_bss_param *bss_cfg = cmd_buf;
499	int i;
500	u16 cmd_size = *param_size;
501
502	mac_tlv = (struct host_cmd_tlv_mac_addr *)tlv;
503	mac_tlv->header.type = cpu_to_le16(TLV_TYPE_UAP_MAC_ADDRESS);
504	mac_tlv->header.len = cpu_to_le16(ETH_ALEN);
505	memcpy(mac_tlv->mac_addr, bss_cfg->mac_addr, ETH_ALEN);
506	cmd_size += sizeof(struct host_cmd_tlv_mac_addr);
507	tlv += sizeof(struct host_cmd_tlv_mac_addr);
508
509	if (bss_cfg->ssid.ssid_len) {
510		ssid = (struct host_cmd_tlv_ssid *)tlv;
511		ssid->header.type = cpu_to_le16(TLV_TYPE_UAP_SSID);
512		ssid->header.len = cpu_to_le16((u16)bss_cfg->ssid.ssid_len);
513		memcpy(ssid->ssid, bss_cfg->ssid.ssid, bss_cfg->ssid.ssid_len);
514		cmd_size += sizeof(struct mwifiex_ie_types_header) +
515			    bss_cfg->ssid.ssid_len;
516		tlv += sizeof(struct mwifiex_ie_types_header) +
517				bss_cfg->ssid.ssid_len;
518
519		bcast_ssid = (struct host_cmd_tlv_bcast_ssid *)tlv;
520		bcast_ssid->header.type = cpu_to_le16(TLV_TYPE_UAP_BCAST_SSID);
521		bcast_ssid->header.len =
522				cpu_to_le16(sizeof(bcast_ssid->bcast_ctl));
523		bcast_ssid->bcast_ctl = bss_cfg->bcast_ssid_ctl;
524		cmd_size += sizeof(struct host_cmd_tlv_bcast_ssid);
525		tlv += sizeof(struct host_cmd_tlv_bcast_ssid);
526	}
527	if (bss_cfg->rates[0]) {
528		tlv_rates = (struct host_cmd_tlv_rates *)tlv;
529		tlv_rates->header.type = cpu_to_le16(TLV_TYPE_UAP_RATES);
530
531		for (i = 0; i < MWIFIEX_SUPPORTED_RATES && bss_cfg->rates[i];
532		     i++)
533			tlv_rates->rates[i] = bss_cfg->rates[i];
534
535		tlv_rates->header.len = cpu_to_le16(i);
536		cmd_size += sizeof(struct host_cmd_tlv_rates) + i;
537		tlv += sizeof(struct host_cmd_tlv_rates) + i;
538	}
539	if (bss_cfg->channel &&
540	    (((bss_cfg->band_cfg & BIT(0)) == BAND_CONFIG_BG &&
541	      bss_cfg->channel <= MAX_CHANNEL_BAND_BG) ||
542	    ((bss_cfg->band_cfg & BIT(0)) == BAND_CONFIG_A &&
543	     bss_cfg->channel <= MAX_CHANNEL_BAND_A))) {
544		chan_band = (struct host_cmd_tlv_channel_band *)tlv;
545		chan_band->header.type = cpu_to_le16(TLV_TYPE_CHANNELBANDLIST);
546		chan_band->header.len =
547			cpu_to_le16(sizeof(struct host_cmd_tlv_channel_band) -
548				    sizeof(struct mwifiex_ie_types_header));
549		chan_band->band_config = bss_cfg->band_cfg;
550		chan_band->channel = bss_cfg->channel;
551		cmd_size += sizeof(struct host_cmd_tlv_channel_band);
552		tlv += sizeof(struct host_cmd_tlv_channel_band);
553	}
554	if (bss_cfg->beacon_period >= MIN_BEACON_PERIOD &&
555	    bss_cfg->beacon_period <= MAX_BEACON_PERIOD) {
556		beacon_period = (struct host_cmd_tlv_beacon_period *)tlv;
557		beacon_period->header.type =
558					cpu_to_le16(TLV_TYPE_UAP_BEACON_PERIOD);
559		beacon_period->header.len =
560			cpu_to_le16(sizeof(struct host_cmd_tlv_beacon_period) -
561				    sizeof(struct mwifiex_ie_types_header));
562		beacon_period->period = cpu_to_le16(bss_cfg->beacon_period);
563		cmd_size += sizeof(struct host_cmd_tlv_beacon_period);
564		tlv += sizeof(struct host_cmd_tlv_beacon_period);
565	}
566	if (bss_cfg->dtim_period >= MIN_DTIM_PERIOD &&
567	    bss_cfg->dtim_period <= MAX_DTIM_PERIOD) {
568		dtim_period = (struct host_cmd_tlv_dtim_period *)tlv;
569		dtim_period->header.type =
570			cpu_to_le16(TLV_TYPE_UAP_DTIM_PERIOD);
571		dtim_period->header.len =
572			cpu_to_le16(sizeof(struct host_cmd_tlv_dtim_period) -
573				    sizeof(struct mwifiex_ie_types_header));
574		dtim_period->period = bss_cfg->dtim_period;
575		cmd_size += sizeof(struct host_cmd_tlv_dtim_period);
576		tlv += sizeof(struct host_cmd_tlv_dtim_period);
577	}
578	if (bss_cfg->rts_threshold <= MWIFIEX_RTS_MAX_VALUE) {
579		rts_threshold = (struct host_cmd_tlv_rts_threshold *)tlv;
580		rts_threshold->header.type =
581					cpu_to_le16(TLV_TYPE_UAP_RTS_THRESHOLD);
582		rts_threshold->header.len =
583			cpu_to_le16(sizeof(struct host_cmd_tlv_rts_threshold) -
584				    sizeof(struct mwifiex_ie_types_header));
585		rts_threshold->rts_thr = cpu_to_le16(bss_cfg->rts_threshold);
586		cmd_size += sizeof(struct host_cmd_tlv_frag_threshold);
587		tlv += sizeof(struct host_cmd_tlv_frag_threshold);
588	}
589	if ((bss_cfg->frag_threshold >= MWIFIEX_FRAG_MIN_VALUE) &&
590	    (bss_cfg->frag_threshold <= MWIFIEX_FRAG_MAX_VALUE)) {
591		frag_threshold = (struct host_cmd_tlv_frag_threshold *)tlv;
592		frag_threshold->header.type =
593				cpu_to_le16(TLV_TYPE_UAP_FRAG_THRESHOLD);
594		frag_threshold->header.len =
595			cpu_to_le16(sizeof(struct host_cmd_tlv_frag_threshold) -
596				    sizeof(struct mwifiex_ie_types_header));
597		frag_threshold->frag_thr = cpu_to_le16(bss_cfg->frag_threshold);
598		cmd_size += sizeof(struct host_cmd_tlv_frag_threshold);
599		tlv += sizeof(struct host_cmd_tlv_frag_threshold);
600	}
601	if (bss_cfg->retry_limit <= MWIFIEX_RETRY_LIMIT) {
602		retry_limit = (struct host_cmd_tlv_retry_limit *)tlv;
603		retry_limit->header.type =
604			cpu_to_le16(TLV_TYPE_UAP_RETRY_LIMIT);
605		retry_limit->header.len =
606			cpu_to_le16(sizeof(struct host_cmd_tlv_retry_limit) -
607				    sizeof(struct mwifiex_ie_types_header));
608		retry_limit->limit = (u8)bss_cfg->retry_limit;
609		cmd_size += sizeof(struct host_cmd_tlv_retry_limit);
610		tlv += sizeof(struct host_cmd_tlv_retry_limit);
611	}
612	if ((bss_cfg->protocol & PROTOCOL_WPA) ||
613	    (bss_cfg->protocol & PROTOCOL_WPA2) ||
614	    (bss_cfg->protocol & PROTOCOL_EAP))
615		mwifiex_uap_bss_wpa(&tlv, cmd_buf, &cmd_size);
616	else
617		mwifiex_uap_bss_wep(&tlv, cmd_buf, &cmd_size);
618
619	if ((bss_cfg->auth_mode <= WLAN_AUTH_SHARED_KEY) ||
620	    (bss_cfg->auth_mode == MWIFIEX_AUTH_MODE_AUTO)) {
621		auth_type = (struct host_cmd_tlv_auth_type *)tlv;
622		auth_type->header.type = cpu_to_le16(TLV_TYPE_AUTH_TYPE);
623		auth_type->header.len =
624			cpu_to_le16(sizeof(struct host_cmd_tlv_auth_type) -
625			sizeof(struct mwifiex_ie_types_header));
626		auth_type->auth_type = (u8)bss_cfg->auth_mode;
627		cmd_size += sizeof(struct host_cmd_tlv_auth_type);
628		tlv += sizeof(struct host_cmd_tlv_auth_type);
629	}
630	if (bss_cfg->protocol) {
631		encrypt_protocol = (struct host_cmd_tlv_encrypt_protocol *)tlv;
632		encrypt_protocol->header.type =
633			cpu_to_le16(TLV_TYPE_UAP_ENCRY_PROTOCOL);
634		encrypt_protocol->header.len =
635			cpu_to_le16(sizeof(struct host_cmd_tlv_encrypt_protocol)
636			- sizeof(struct mwifiex_ie_types_header));
637		encrypt_protocol->proto = cpu_to_le16(bss_cfg->protocol);
638		cmd_size += sizeof(struct host_cmd_tlv_encrypt_protocol);
639		tlv += sizeof(struct host_cmd_tlv_encrypt_protocol);
640	}
641
642	if (bss_cfg->ht_cap.cap_info) {
643		htcap = (struct mwifiex_ie_types_htcap *)tlv;
644		htcap->header.type = cpu_to_le16(WLAN_EID_HT_CAPABILITY);
645		htcap->header.len =
646				cpu_to_le16(sizeof(struct ieee80211_ht_cap));
647		htcap->ht_cap.cap_info = bss_cfg->ht_cap.cap_info;
648		htcap->ht_cap.ampdu_params_info =
649					     bss_cfg->ht_cap.ampdu_params_info;
650		memcpy(&htcap->ht_cap.mcs, &bss_cfg->ht_cap.mcs,
651		       sizeof(struct ieee80211_mcs_info));
652		htcap->ht_cap.extended_ht_cap_info =
653					bss_cfg->ht_cap.extended_ht_cap_info;
654		htcap->ht_cap.tx_BF_cap_info = bss_cfg->ht_cap.tx_BF_cap_info;
655		htcap->ht_cap.antenna_selection_info =
656					bss_cfg->ht_cap.antenna_selection_info;
657		cmd_size += sizeof(struct mwifiex_ie_types_htcap);
658		tlv += sizeof(struct mwifiex_ie_types_htcap);
659	}
660
661	if (bss_cfg->wmm_info.qos_info != 0xFF) {
662		wmm_cap = (struct mwifiex_ie_types_wmmcap *)tlv;
663		wmm_cap->header.type = cpu_to_le16(WLAN_EID_VENDOR_SPECIFIC);
664		wmm_cap->header.len = cpu_to_le16(sizeof(wmm_cap->wmm_info));
665		memcpy(&wmm_cap->wmm_info, &bss_cfg->wmm_info,
666		       sizeof(wmm_cap->wmm_info));
667		cmd_size += sizeof(struct mwifiex_ie_types_wmmcap);
668		tlv += sizeof(struct mwifiex_ie_types_wmmcap);
669	}
670
671	if (bss_cfg->sta_ao_timer) {
672		ao_timer = (struct host_cmd_tlv_ageout_timer *)tlv;
673		ao_timer->header.type = cpu_to_le16(TLV_TYPE_UAP_AO_TIMER);
674		ao_timer->header.len = cpu_to_le16(sizeof(*ao_timer) -
675					sizeof(struct mwifiex_ie_types_header));
676		ao_timer->sta_ao_timer = cpu_to_le32(bss_cfg->sta_ao_timer);
677		cmd_size += sizeof(*ao_timer);
678		tlv += sizeof(*ao_timer);
679	}
680
681	if (bss_cfg->power_constraint) {
682		pwr_ct = (void *)tlv;
683		pwr_ct->header.type = cpu_to_le16(TLV_TYPE_PWR_CONSTRAINT);
684		pwr_ct->header.len = cpu_to_le16(sizeof(u8));
685		pwr_ct->constraint = bss_cfg->power_constraint;
686		cmd_size += sizeof(*pwr_ct);
687		tlv += sizeof(*pwr_ct);
688	}
689
690	if (bss_cfg->ps_sta_ao_timer) {
691		ps_ao_timer = (struct host_cmd_tlv_ageout_timer *)tlv;
692		ps_ao_timer->header.type =
693				cpu_to_le16(TLV_TYPE_UAP_PS_AO_TIMER);
694		ps_ao_timer->header.len = cpu_to_le16(sizeof(*ps_ao_timer) -
695				sizeof(struct mwifiex_ie_types_header));
696		ps_ao_timer->sta_ao_timer =
697					cpu_to_le32(bss_cfg->ps_sta_ao_timer);
698		cmd_size += sizeof(*ps_ao_timer);
699		tlv += sizeof(*ps_ao_timer);
700	}
701
702	*param_size = cmd_size;
703
704	return 0;
705}
706
707/* This function parses custom IEs from IE list and prepares command buffer */
708static int mwifiex_uap_custom_ie_prepare(u8 *tlv, void *cmd_buf, u16 *ie_size)
709{
710	struct mwifiex_ie_list *ap_ie = cmd_buf;
711	struct mwifiex_ie_types_header *tlv_ie = (void *)tlv;
712
713	if (!ap_ie || !ap_ie->len)
714		return -1;
715
716	*ie_size += le16_to_cpu(ap_ie->len) +
717			sizeof(struct mwifiex_ie_types_header);
718
719	tlv_ie->type = cpu_to_le16(TLV_TYPE_MGMT_IE);
720	tlv_ie->len = ap_ie->len;
721	tlv += sizeof(struct mwifiex_ie_types_header);
722
723	memcpy(tlv, ap_ie->ie_list, le16_to_cpu(ap_ie->len));
724
725	return 0;
726}
727
728/* Parse AP config structure and prepare TLV based command structure
729 * to be sent to FW for uAP configuration
730 */
731static int
732mwifiex_cmd_uap_sys_config(struct host_cmd_ds_command *cmd, u16 cmd_action,
733			   u32 type, void *cmd_buf)
734{
735	u8 *tlv;
736	u16 cmd_size, param_size, ie_size;
737	struct host_cmd_ds_sys_config *sys_cfg;
738
739	cmd->command = cpu_to_le16(HostCmd_CMD_UAP_SYS_CONFIG);
740	cmd_size = (u16)(sizeof(struct host_cmd_ds_sys_config) + S_DS_GEN);
741	sys_cfg = (struct host_cmd_ds_sys_config *)&cmd->params.uap_sys_config;
742	sys_cfg->action = cpu_to_le16(cmd_action);
743	tlv = sys_cfg->tlv;
744
745	switch (type) {
746	case UAP_BSS_PARAMS_I:
747		param_size = cmd_size;
748		if (mwifiex_uap_bss_param_prepare(tlv, cmd_buf, &param_size))
749			return -1;
750		cmd->size = cpu_to_le16(param_size);
751		break;
752	case UAP_CUSTOM_IE_I:
753		ie_size = cmd_size;
754		if (mwifiex_uap_custom_ie_prepare(tlv, cmd_buf, &ie_size))
755			return -1;
756		cmd->size = cpu_to_le16(ie_size);
757		break;
758	default:
759		return -1;
760	}
761
762	return 0;
763}
764
765/* This function prepares AP specific deauth command with mac supplied in
766 * function parameter.
767 */
768static int mwifiex_cmd_uap_sta_deauth(struct mwifiex_private *priv,
769				      struct host_cmd_ds_command *cmd, u8 *mac)
770{
771	struct host_cmd_ds_sta_deauth *sta_deauth = &cmd->params.sta_deauth;
772
773	cmd->command = cpu_to_le16(HostCmd_CMD_UAP_STA_DEAUTH);
774	memcpy(sta_deauth->mac, mac, ETH_ALEN);
775	sta_deauth->reason = cpu_to_le16(WLAN_REASON_DEAUTH_LEAVING);
776
777	cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_sta_deauth) +
778				S_DS_GEN);
779	return 0;
780}
781
782/* This function prepares the AP specific commands before sending them
783 * to the firmware.
784 * This is a generic function which calls specific command preparation
785 * routines based upon the command number.
786 */
787int mwifiex_uap_prepare_cmd(struct mwifiex_private *priv, u16 cmd_no,
788			    u16 cmd_action, u32 type,
789			    void *data_buf, void *cmd_buf)
790{
791	struct host_cmd_ds_command *cmd = cmd_buf;
792
793	switch (cmd_no) {
794	case HostCmd_CMD_UAP_SYS_CONFIG:
795		if (mwifiex_cmd_uap_sys_config(cmd, cmd_action, type, data_buf))
796			return -1;
797		break;
798	case HostCmd_CMD_UAP_BSS_START:
799	case HostCmd_CMD_UAP_BSS_STOP:
800	case HOST_CMD_APCMD_SYS_RESET:
801	case HOST_CMD_APCMD_STA_LIST:
802		cmd->command = cpu_to_le16(cmd_no);
803		cmd->size = cpu_to_le16(S_DS_GEN);
804		break;
805	case HostCmd_CMD_UAP_STA_DEAUTH:
806		if (mwifiex_cmd_uap_sta_deauth(priv, cmd, data_buf))
807			return -1;
808		break;
809	case HostCmd_CMD_CHAN_REPORT_REQUEST:
810		if (mwifiex_cmd_issue_chan_report_request(priv, cmd_buf,
811							  data_buf))
812			return -1;
813		break;
814	default:
815		mwifiex_dbg(priv->adapter, ERROR,
816			    "PREP_CMD: unknown cmd %#x\n", cmd_no);
817		return -1;
818	}
819
820	return 0;
821}
822
823void mwifiex_uap_set_channel(struct mwifiex_private *priv,
824			     struct mwifiex_uap_bss_param *bss_cfg,
825			     struct cfg80211_chan_def chandef)
826{
827	u8 config_bands = 0, old_bands = priv->adapter->config_bands;
828
829	priv->bss_chandef = chandef;
830
831	bss_cfg->channel = ieee80211_frequency_to_channel(
832						     chandef.chan->center_freq);
833
834	/* Set appropriate bands */
835	if (chandef.chan->band == NL80211_BAND_2GHZ) {
836		bss_cfg->band_cfg = BAND_CONFIG_BG;
837		config_bands = BAND_B | BAND_G;
838
839		if (chandef.width > NL80211_CHAN_WIDTH_20_NOHT)
840			config_bands |= BAND_GN;
841	} else {
842		bss_cfg->band_cfg = BAND_CONFIG_A;
843		config_bands = BAND_A;
844
845		if (chandef.width > NL80211_CHAN_WIDTH_20_NOHT)
846			config_bands |= BAND_AN;
847
848		if (chandef.width > NL80211_CHAN_WIDTH_40)
849			config_bands |= BAND_AAC;
850	}
851
852	switch (chandef.width) {
853	case NL80211_CHAN_WIDTH_5:
854	case NL80211_CHAN_WIDTH_10:
855	case NL80211_CHAN_WIDTH_20_NOHT:
856	case NL80211_CHAN_WIDTH_20:
857		break;
858	case NL80211_CHAN_WIDTH_40:
859		if (chandef.center_freq1 < chandef.chan->center_freq)
860			bss_cfg->band_cfg |= MWIFIEX_SEC_CHAN_BELOW;
861		else
862			bss_cfg->band_cfg |= MWIFIEX_SEC_CHAN_ABOVE;
863		break;
864	case NL80211_CHAN_WIDTH_80:
865	case NL80211_CHAN_WIDTH_80P80:
866	case NL80211_CHAN_WIDTH_160:
867		bss_cfg->band_cfg |=
868		    mwifiex_get_sec_chan_offset(bss_cfg->channel) << 4;
869		break;
870	default:
871		mwifiex_dbg(priv->adapter,
872			    WARN, "Unknown channel width: %d\n",
873			    chandef.width);
874		break;
875	}
876
877	priv->adapter->config_bands = config_bands;
878
879	if (old_bands != config_bands) {
880		mwifiex_send_domain_info_cmd_fw(priv->adapter->wiphy);
881		mwifiex_dnld_txpwr_table(priv);
882	}
883}
884
885int mwifiex_config_start_uap(struct mwifiex_private *priv,
886			     struct mwifiex_uap_bss_param *bss_cfg)
887{
888	if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_SYS_CONFIG,
889			     HostCmd_ACT_GEN_SET,
890			     UAP_BSS_PARAMS_I, bss_cfg, true)) {
891		mwifiex_dbg(priv->adapter, ERROR,
892			    "Failed to set AP configuration\n");
893		return -1;
894	}
895
896	if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_START,
897			     HostCmd_ACT_GEN_SET, 0, NULL, true)) {
898		mwifiex_dbg(priv->adapter, ERROR,
899			    "Failed to start the BSS\n");
900		return -1;
901	}
902
903	if (priv->sec_info.wep_enabled)
904		priv->curr_pkt_filter |= HostCmd_ACT_MAC_WEP_ENABLE;
905	else
906		priv->curr_pkt_filter &= ~HostCmd_ACT_MAC_WEP_ENABLE;
907
908	if (mwifiex_send_cmd(priv, HostCmd_CMD_MAC_CONTROL,
909			     HostCmd_ACT_GEN_SET, 0,
910			     &priv->curr_pkt_filter, true))
911		return -1;
912
913	return 0;
914}
915