xref: /linux/drivers/net/wireless/nxp/nxpwifi/uap_cmd.c (revision 91ec2035134982b98fab0609a9fd8480e8217dc1)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * NXP Wireless LAN device driver: AP specific command handling
4  *
5  * Copyright 2011-2024 NXP
6  */
7 
8 #include "main.h"
9 #include "cmdevt.h"
10 #include "11n.h"
11 #include "11ac.h"
12 #include "11ax.h"
13 
14 /* Parse BSS params and append WPA/WPA2 TLVs to the command buffer. */
15 static void
nxpwifi_uap_bss_wpa(u8 ** tlv_buf,void * cmd_buf,u16 * param_size)16 nxpwifi_uap_bss_wpa(u8 **tlv_buf, void *cmd_buf, u16 *param_size)
17 {
18 	struct host_cmd_tlv_pwk_cipher *pwk_cipher;
19 	struct host_cmd_tlv_gwk_cipher *gwk_cipher;
20 	struct host_cmd_tlv_passphrase *passphrase;
21 	struct host_cmd_tlv_akmp *tlv_akmp;
22 	struct nxpwifi_uap_bss_param *bss_cfg = cmd_buf;
23 	u16 cmd_size = *param_size;
24 	u8 *tlv = *tlv_buf;
25 
26 	tlv_akmp = (struct host_cmd_tlv_akmp *)tlv;
27 	tlv_akmp->header.type = cpu_to_le16(TLV_TYPE_UAP_AKMP);
28 	tlv_akmp->header.len = cpu_to_le16(sizeof(struct host_cmd_tlv_akmp) -
29 					sizeof(struct nxpwifi_ie_types_header));
30 	tlv_akmp->key_mgmt_operation = cpu_to_le16(bss_cfg->key_mgmt_operation);
31 	tlv_akmp->key_mgmt = cpu_to_le16(bss_cfg->key_mgmt);
32 	cmd_size += sizeof(struct host_cmd_tlv_akmp);
33 	tlv += sizeof(struct host_cmd_tlv_akmp);
34 
35 	if (bss_cfg->wpa_cfg.pairwise_cipher_wpa & VALID_CIPHER_BITMAP) {
36 		pwk_cipher = (struct host_cmd_tlv_pwk_cipher *)tlv;
37 		pwk_cipher->header.type = cpu_to_le16(TLV_TYPE_PWK_CIPHER);
38 		pwk_cipher->header.len =
39 			cpu_to_le16(sizeof(struct host_cmd_tlv_pwk_cipher) -
40 				    sizeof(struct nxpwifi_ie_types_header));
41 		pwk_cipher->proto = cpu_to_le16(PROTOCOL_WPA);
42 		pwk_cipher->cipher = bss_cfg->wpa_cfg.pairwise_cipher_wpa;
43 		cmd_size += sizeof(struct host_cmd_tlv_pwk_cipher);
44 		tlv += sizeof(struct host_cmd_tlv_pwk_cipher);
45 	}
46 
47 	if (bss_cfg->wpa_cfg.pairwise_cipher_wpa2 & VALID_CIPHER_BITMAP) {
48 		pwk_cipher = (struct host_cmd_tlv_pwk_cipher *)tlv;
49 		pwk_cipher->header.type = cpu_to_le16(TLV_TYPE_PWK_CIPHER);
50 		pwk_cipher->header.len =
51 			cpu_to_le16(sizeof(struct host_cmd_tlv_pwk_cipher) -
52 				    sizeof(struct nxpwifi_ie_types_header));
53 		pwk_cipher->proto = cpu_to_le16(PROTOCOL_WPA2);
54 		pwk_cipher->cipher = bss_cfg->wpa_cfg.pairwise_cipher_wpa2;
55 		cmd_size += sizeof(struct host_cmd_tlv_pwk_cipher);
56 		tlv += sizeof(struct host_cmd_tlv_pwk_cipher);
57 	}
58 
59 	if (bss_cfg->wpa_cfg.group_cipher & VALID_CIPHER_BITMAP) {
60 		gwk_cipher = (struct host_cmd_tlv_gwk_cipher *)tlv;
61 		gwk_cipher->header.type = cpu_to_le16(TLV_TYPE_GWK_CIPHER);
62 		gwk_cipher->header.len =
63 			cpu_to_le16(sizeof(struct host_cmd_tlv_gwk_cipher) -
64 				    sizeof(struct nxpwifi_ie_types_header));
65 		gwk_cipher->cipher = bss_cfg->wpa_cfg.group_cipher;
66 		cmd_size += sizeof(struct host_cmd_tlv_gwk_cipher);
67 		tlv += sizeof(struct host_cmd_tlv_gwk_cipher);
68 	}
69 
70 	if (bss_cfg->wpa_cfg.length) {
71 		passphrase = (struct host_cmd_tlv_passphrase *)tlv;
72 		passphrase->header.type =
73 				cpu_to_le16(TLV_TYPE_UAP_WPA_PASSPHRASE);
74 		passphrase->header.len = cpu_to_le16(bss_cfg->wpa_cfg.length);
75 		memcpy(passphrase->passphrase, bss_cfg->wpa_cfg.passphrase,
76 		       bss_cfg->wpa_cfg.length);
77 		cmd_size += sizeof(struct nxpwifi_ie_types_header) +
78 			    bss_cfg->wpa_cfg.length;
79 		tlv += sizeof(struct nxpwifi_ie_types_header) +
80 				bss_cfg->wpa_cfg.length;
81 	}
82 
83 	*param_size = cmd_size;
84 	*tlv_buf = tlv;
85 }
86 
87 /* Parse BSS params and append WEP TLVs to the command buffer. */
88 static void
nxpwifi_uap_bss_wep(u8 ** tlv_buf,void * cmd_buf,u16 * param_size)89 nxpwifi_uap_bss_wep(u8 **tlv_buf, void *cmd_buf, u16 *param_size)
90 {
91 	struct host_cmd_tlv_wep_key *wep_key;
92 	u16 cmd_size = *param_size;
93 	int i;
94 	u8 *tlv = *tlv_buf;
95 	struct nxpwifi_uap_bss_param *bss_cfg = cmd_buf;
96 
97 	for (i = 0; i < NUM_WEP_KEYS; i++) {
98 		if (bss_cfg->wep_cfg[i].length &&
99 		    (bss_cfg->wep_cfg[i].length == WLAN_KEY_LEN_WEP40 ||
100 		     bss_cfg->wep_cfg[i].length == WLAN_KEY_LEN_WEP104)) {
101 			wep_key = (struct host_cmd_tlv_wep_key *)tlv;
102 			wep_key->header.type =
103 				cpu_to_le16(TLV_TYPE_UAP_WEP_KEY);
104 			wep_key->header.len =
105 				cpu_to_le16(bss_cfg->wep_cfg[i].length + 2);
106 			wep_key->key_index = bss_cfg->wep_cfg[i].key_index;
107 			wep_key->is_default = bss_cfg->wep_cfg[i].is_default;
108 			memcpy(wep_key->key, bss_cfg->wep_cfg[i].key,
109 			       bss_cfg->wep_cfg[i].length);
110 			cmd_size += sizeof(struct nxpwifi_ie_types_header) + 2 +
111 				    bss_cfg->wep_cfg[i].length;
112 			tlv += sizeof(struct nxpwifi_ie_types_header) + 2 +
113 				    bss_cfg->wep_cfg[i].length;
114 		}
115 	}
116 
117 	*param_size = cmd_size;
118 	*tlv_buf = tlv;
119 }
120 
121 /* Parse BSS params and append TLVs to the command buffer. */
nxpwifi_uap_bss_param_prepare(struct nxpwifi_private * priv,u8 * tlv,void * cmd_buf,u16 * param_size)122 static int nxpwifi_uap_bss_param_prepare(struct nxpwifi_private *priv, u8 *tlv,
123 					 void *cmd_buf, u16 *param_size)
124 {
125 	struct host_cmd_tlv_mac_addr *mac_tlv;
126 	struct host_cmd_tlv_dtim_period *dtim_period;
127 	struct host_cmd_tlv_beacon_period *beacon_period;
128 	struct host_cmd_tlv_ssid *ssid;
129 	struct host_cmd_tlv_bcast_ssid *bcast_ssid;
130 	struct host_cmd_tlv_channel_band *chan_band;
131 	struct host_cmd_tlv_frag_threshold *frag_threshold;
132 	struct host_cmd_tlv_rts_threshold *rts_threshold;
133 	struct host_cmd_tlv_retry_limit *retry_limit;
134 	struct host_cmd_tlv_encrypt_protocol *encrypt_protocol;
135 	struct host_cmd_tlv_auth_type *auth_type;
136 	struct host_cmd_tlv_rates *tlv_rates;
137 	struct host_cmd_tlv_ageout_timer *ao_timer, *ps_ao_timer;
138 	struct host_cmd_tlv_power_constraint *pwr_ct;
139 	struct nxpwifi_ie_types_htcap *htcap;
140 	struct nxpwifi_uap_bss_param *bss_cfg = cmd_buf;
141 	int i;
142 	u16 cmd_size = *param_size;
143 
144 	mac_tlv = (struct host_cmd_tlv_mac_addr *)tlv;
145 	mac_tlv->header.type = cpu_to_le16(TLV_TYPE_UAP_MAC_ADDRESS);
146 	mac_tlv->header.len = cpu_to_le16(ETH_ALEN);
147 	memcpy(mac_tlv->mac_addr, bss_cfg->mac_addr, ETH_ALEN);
148 	cmd_size += sizeof(struct host_cmd_tlv_mac_addr);
149 	tlv += sizeof(struct host_cmd_tlv_mac_addr);
150 
151 	if (bss_cfg->ssid.ssid_len) {
152 		ssid = (struct host_cmd_tlv_ssid *)tlv;
153 		ssid->header.type = cpu_to_le16(TLV_TYPE_UAP_SSID);
154 		ssid->header.len = cpu_to_le16((u16)bss_cfg->ssid.ssid_len);
155 		memcpy(ssid->ssid, bss_cfg->ssid.ssid, bss_cfg->ssid.ssid_len);
156 		cmd_size += sizeof(struct nxpwifi_ie_types_header) +
157 			    bss_cfg->ssid.ssid_len;
158 		tlv += sizeof(struct nxpwifi_ie_types_header) +
159 				bss_cfg->ssid.ssid_len;
160 
161 		bcast_ssid = (struct host_cmd_tlv_bcast_ssid *)tlv;
162 		bcast_ssid->header.type = cpu_to_le16(TLV_TYPE_UAP_BCAST_SSID);
163 		bcast_ssid->header.len =
164 				cpu_to_le16(sizeof(bcast_ssid->bcast_ctl));
165 		bcast_ssid->bcast_ctl = bss_cfg->bcast_ssid_ctl;
166 		cmd_size += sizeof(struct host_cmd_tlv_bcast_ssid);
167 		tlv += sizeof(struct host_cmd_tlv_bcast_ssid);
168 	}
169 	if (bss_cfg->rates[0]) {
170 		tlv_rates = (struct host_cmd_tlv_rates *)tlv;
171 		tlv_rates->header.type = cpu_to_le16(TLV_TYPE_UAP_RATES);
172 
173 		for (i = 0; i < NXPWIFI_SUPPORTED_RATES && bss_cfg->rates[i];
174 		     i++)
175 			tlv_rates->rates[i] = bss_cfg->rates[i];
176 
177 		tlv_rates->header.len = cpu_to_le16(i);
178 		cmd_size += sizeof(struct host_cmd_tlv_rates) + i;
179 		tlv += sizeof(struct host_cmd_tlv_rates) + i;
180 	}
181 	if (bss_cfg->channel &&
182 	    (((bss_cfg->band_cfg & BIT(0)) == BAND_CONFIG_BG &&
183 	      bss_cfg->channel <= MAX_CHANNEL_BAND_BG) ||
184 	    ((bss_cfg->band_cfg & BIT(0)) == BAND_CONFIG_A &&
185 	     bss_cfg->channel <= MAX_CHANNEL_BAND_A))) {
186 		chan_band = (struct host_cmd_tlv_channel_band *)tlv;
187 		chan_band->header.type = cpu_to_le16(TLV_TYPE_CHANNELBANDLIST);
188 		chan_band->header.len =
189 			cpu_to_le16(sizeof(struct host_cmd_tlv_channel_band) -
190 				    sizeof(struct nxpwifi_ie_types_header));
191 		chan_band->band_config = bss_cfg->band_cfg;
192 		chan_band->channel = bss_cfg->channel;
193 		cmd_size += sizeof(struct host_cmd_tlv_channel_band);
194 		tlv += sizeof(struct host_cmd_tlv_channel_band);
195 	}
196 	if (bss_cfg->beacon_period >= NXPWIFI_BEACON_PERIOD_MIN &&
197 	    bss_cfg->beacon_period <= NXPWIFI_BEACON_PERIOD_MAX) {
198 		beacon_period = (struct host_cmd_tlv_beacon_period *)tlv;
199 		beacon_period->header.type =
200 					cpu_to_le16(TLV_TYPE_UAP_BEACON_PERIOD);
201 		beacon_period->header.len =
202 			cpu_to_le16(sizeof(struct host_cmd_tlv_beacon_period) -
203 				    sizeof(struct nxpwifi_ie_types_header));
204 		beacon_period->period = cpu_to_le16(bss_cfg->beacon_period);
205 		cmd_size += sizeof(struct host_cmd_tlv_beacon_period);
206 		tlv += sizeof(struct host_cmd_tlv_beacon_period);
207 	}
208 	if (bss_cfg->dtim_period >= NXPWIFI_MIN_DTIM_PERIOD &&
209 	    bss_cfg->dtim_period <= NXPWIFI_MAX_DTIM_PERIOD) {
210 		dtim_period = (struct host_cmd_tlv_dtim_period *)tlv;
211 		dtim_period->header.type =
212 			cpu_to_le16(TLV_TYPE_UAP_DTIM_PERIOD);
213 		dtim_period->header.len =
214 			cpu_to_le16(sizeof(struct host_cmd_tlv_dtim_period) -
215 				    sizeof(struct nxpwifi_ie_types_header));
216 		dtim_period->period = bss_cfg->dtim_period;
217 		cmd_size += sizeof(struct host_cmd_tlv_dtim_period);
218 		tlv += sizeof(struct host_cmd_tlv_dtim_period);
219 	}
220 	if (bss_cfg->rts_threshold <= NXPWIFI_RTS_THRESHOLD_MAX) {
221 		rts_threshold = (struct host_cmd_tlv_rts_threshold *)tlv;
222 		rts_threshold->header.type =
223 					cpu_to_le16(TLV_TYPE_UAP_RTS_THRESHOLD);
224 		rts_threshold->header.len =
225 			cpu_to_le16(sizeof(struct host_cmd_tlv_rts_threshold) -
226 				    sizeof(struct nxpwifi_ie_types_header));
227 		rts_threshold->rts_thr = cpu_to_le16(bss_cfg->rts_threshold);
228 		cmd_size += sizeof(struct host_cmd_tlv_frag_threshold);
229 		tlv += sizeof(struct host_cmd_tlv_frag_threshold);
230 	}
231 	if (bss_cfg->frag_threshold >= NXPWIFI_FRAG_THRESHOLD_MIN &&
232 	    bss_cfg->frag_threshold <= NXPWIFI_FRAG_THRESHOLD_MAX) {
233 		frag_threshold = (struct host_cmd_tlv_frag_threshold *)tlv;
234 		frag_threshold->header.type =
235 				cpu_to_le16(TLV_TYPE_UAP_FRAG_THRESHOLD);
236 		frag_threshold->header.len =
237 			cpu_to_le16(sizeof(struct host_cmd_tlv_frag_threshold) -
238 				    sizeof(struct nxpwifi_ie_types_header));
239 		frag_threshold->frag_thr = cpu_to_le16(bss_cfg->frag_threshold);
240 		cmd_size += sizeof(struct host_cmd_tlv_frag_threshold);
241 		tlv += sizeof(struct host_cmd_tlv_frag_threshold);
242 	}
243 	if (bss_cfg->retry_limit <= NXPWIFI_RETRY_LIMIT_MAX) {
244 		retry_limit = (struct host_cmd_tlv_retry_limit *)tlv;
245 		retry_limit->header.type =
246 			cpu_to_le16(TLV_TYPE_UAP_RETRY_LIMIT);
247 		retry_limit->header.len =
248 			cpu_to_le16(sizeof(struct host_cmd_tlv_retry_limit) -
249 				    sizeof(struct nxpwifi_ie_types_header));
250 		retry_limit->limit = (u8)bss_cfg->retry_limit;
251 		cmd_size += sizeof(struct host_cmd_tlv_retry_limit);
252 		tlv += sizeof(struct host_cmd_tlv_retry_limit);
253 	}
254 	if ((bss_cfg->protocol & PROTOCOL_WPA) ||
255 	    (bss_cfg->protocol & PROTOCOL_WPA2) ||
256 	    (bss_cfg->protocol & PROTOCOL_EAP))
257 		nxpwifi_uap_bss_wpa(&tlv, cmd_buf, &cmd_size);
258 	else
259 		nxpwifi_uap_bss_wep(&tlv, cmd_buf, &cmd_size);
260 
261 	if (bss_cfg->auth_mode <= WLAN_AUTH_SHARED_KEY ||
262 	    bss_cfg->auth_mode == NXPWIFI_AUTH_MODE_AUTO) {
263 		auth_type = (struct host_cmd_tlv_auth_type *)tlv;
264 		auth_type->header.type = cpu_to_le16(TLV_TYPE_AUTH_TYPE);
265 		auth_type->header.len =
266 			cpu_to_le16(sizeof(struct host_cmd_tlv_auth_type) -
267 			sizeof(struct nxpwifi_ie_types_header));
268 		auth_type->auth_type = (u8)bss_cfg->auth_mode;
269 		auth_type->pwe_derivation = 0;
270 		auth_type->transition_disable = 0;
271 		cmd_size += sizeof(struct host_cmd_tlv_auth_type);
272 		tlv += sizeof(struct host_cmd_tlv_auth_type);
273 	}
274 	if (bss_cfg->protocol) {
275 		encrypt_protocol = (struct host_cmd_tlv_encrypt_protocol *)tlv;
276 		encrypt_protocol->header.type =
277 			cpu_to_le16(TLV_TYPE_UAP_ENCRY_PROTOCOL);
278 		encrypt_protocol->header.len =
279 			cpu_to_le16(sizeof(struct host_cmd_tlv_encrypt_protocol)
280 			- sizeof(struct nxpwifi_ie_types_header));
281 		encrypt_protocol->proto = cpu_to_le16(bss_cfg->protocol);
282 		cmd_size += sizeof(struct host_cmd_tlv_encrypt_protocol);
283 		tlv += sizeof(struct host_cmd_tlv_encrypt_protocol);
284 	}
285 
286 	if (bss_cfg->ht_cap.cap_info) {
287 		htcap = (struct nxpwifi_ie_types_htcap *)tlv;
288 		htcap->header.type = cpu_to_le16(WLAN_EID_HT_CAPABILITY);
289 		htcap->header.len =
290 				cpu_to_le16(sizeof(struct ieee80211_ht_cap));
291 		htcap->ht_cap.cap_info = bss_cfg->ht_cap.cap_info;
292 		htcap->ht_cap.ampdu_params_info =
293 					     bss_cfg->ht_cap.ampdu_params_info;
294 		memcpy(&htcap->ht_cap.mcs, &bss_cfg->ht_cap.mcs,
295 		       sizeof(struct ieee80211_mcs_info));
296 		htcap->ht_cap.extended_ht_cap_info =
297 					bss_cfg->ht_cap.extended_ht_cap_info;
298 		htcap->ht_cap.tx_BF_cap_info = bss_cfg->ht_cap.tx_BF_cap_info;
299 		htcap->ht_cap.antenna_selection_info =
300 					bss_cfg->ht_cap.antenna_selection_info;
301 		cmd_size += sizeof(struct nxpwifi_ie_types_htcap);
302 		tlv += sizeof(struct nxpwifi_ie_types_htcap);
303 	}
304 
305 	if (priv->wmm_enabled) {
306 		struct nxpwifi_ie_types_wmmcap *wmm_cap;
307 		struct nxpwifi_types_wmm_info *fw_wmm;
308 		const struct ieee80211_wmm_param_ie *ie;
309 
310 		wmm_cap = (struct nxpwifi_ie_types_wmmcap *)tlv;
311 		fw_wmm = &wmm_cap->wmm_info;
312 		ie = &bss_cfg->wmm_element;
313 
314 		wmm_cap->header.type = cpu_to_le16(WLAN_EID_VENDOR_SPECIFIC);
315 		wmm_cap->header.len =
316 		    cpu_to_le16(sizeof(struct nxpwifi_types_wmm_info));
317 
318 		/* Map 802.11 WMM IE fields to FW WMM TLV payload */
319 		fw_wmm->oui[0] = ie->oui[0];
320 		fw_wmm->oui[1] = ie->oui[1];
321 		fw_wmm->oui[2] = ie->oui[2];
322 		fw_wmm->oui[3] = ie->oui_type;
323 
324 		fw_wmm->subtype = ie->oui_subtype;
325 		fw_wmm->version = ie->version;
326 		fw_wmm->qos_info = ie->qos_info;
327 		fw_wmm->reserved = ie->reserved;
328 
329 		memcpy(fw_wmm->ac, ie->ac, sizeof(fw_wmm->ac));
330 
331 		cmd_size += sizeof(*wmm_cap);
332 		tlv += sizeof(*wmm_cap);
333 	}
334 
335 	if (bss_cfg->sta_ao_timer) {
336 		ao_timer = (struct host_cmd_tlv_ageout_timer *)tlv;
337 		ao_timer->header.type = cpu_to_le16(TLV_TYPE_UAP_AO_TIMER);
338 		ao_timer->header.len = cpu_to_le16(sizeof(*ao_timer) -
339 					sizeof(struct nxpwifi_ie_types_header));
340 		ao_timer->sta_ao_timer = cpu_to_le32(bss_cfg->sta_ao_timer);
341 		cmd_size += sizeof(*ao_timer);
342 		tlv += sizeof(*ao_timer);
343 	}
344 
345 	if (bss_cfg->power_constraint) {
346 		pwr_ct = (void *)tlv;
347 		pwr_ct->header.type = cpu_to_le16(TLV_TYPE_PWR_CONSTRAINT);
348 		pwr_ct->header.len = cpu_to_le16(sizeof(u8));
349 		pwr_ct->constraint = bss_cfg->power_constraint;
350 		cmd_size += sizeof(*pwr_ct);
351 		tlv += sizeof(*pwr_ct);
352 	}
353 
354 	if (bss_cfg->ps_sta_ao_timer) {
355 		ps_ao_timer = (struct host_cmd_tlv_ageout_timer *)tlv;
356 		ps_ao_timer->header.type =
357 				cpu_to_le16(TLV_TYPE_UAP_PS_AO_TIMER);
358 		ps_ao_timer->header.len = cpu_to_le16(sizeof(*ps_ao_timer) -
359 				sizeof(struct nxpwifi_ie_types_header));
360 		ps_ao_timer->sta_ao_timer =
361 					cpu_to_le32(bss_cfg->ps_sta_ao_timer);
362 		cmd_size += sizeof(*ps_ao_timer);
363 		tlv += sizeof(*ps_ao_timer);
364 	}
365 
366 	*param_size = cmd_size;
367 
368 	return 0;
369 }
370 
371 /* Parse custom IEs and write them to the command buffer. */
nxpwifi_uap_custom_ie_prepare(u8 * tlv,void * cmd_buf,u16 * ie_size)372 static int nxpwifi_uap_custom_ie_prepare(u8 *tlv, void *cmd_buf, u16 *ie_size)
373 {
374 	struct nxpwifi_ie_list *ap_ie = cmd_buf;
375 	struct nxpwifi_ie_types_header *tlv_ie = (void *)tlv;
376 
377 	if (!ap_ie || !ap_ie->len)
378 		return -EINVAL;
379 
380 	*ie_size += le16_to_cpu(ap_ie->len) +
381 		    sizeof(struct nxpwifi_ie_types_header);
382 
383 	tlv_ie->type = cpu_to_le16(TLV_TYPE_MGMT_IE);
384 	tlv_ie->len = ap_ie->len;
385 	tlv += sizeof(struct nxpwifi_ie_types_header);
386 
387 	memcpy(tlv, ap_ie->ie_list, le16_to_cpu(ap_ie->len));
388 
389 	return 0;
390 }
391 
392 static int
nxpwifi_cmd_uap_sys_config(struct nxpwifi_private * priv,struct host_cmd_ds_command * cmd,u16 cmd_no,void * data_buf,u16 cmd_action,u32 cmd_type)393 nxpwifi_cmd_uap_sys_config(struct nxpwifi_private *priv,
394 			   struct host_cmd_ds_command *cmd,
395 			   u16 cmd_no, void *data_buf,
396 			   u16 cmd_action, u32 cmd_type)
397 {
398 	u8 *tlv;
399 	u16 cmd_size, param_size, ie_size;
400 	struct host_cmd_ds_sys_config *sys_cfg;
401 	int ret = 0;
402 
403 	cmd->command = cpu_to_le16(HOST_CMD_UAP_SYS_CONFIG);
404 	cmd_size = (u16)(sizeof(struct host_cmd_ds_sys_config) + S_DS_GEN);
405 	sys_cfg = &cmd->params.uap_sys_config;
406 	sys_cfg->action = cpu_to_le16(cmd_action);
407 	tlv = sys_cfg->tlv;
408 
409 	switch (cmd_type) {
410 	case UAP_BSS_PARAMS_I:
411 		param_size = cmd_size;
412 		ret = nxpwifi_uap_bss_param_prepare(priv, tlv, data_buf, &param_size);
413 		if (ret)
414 			return ret;
415 		cmd->size = cpu_to_le16(param_size);
416 		break;
417 	case UAP_CUSTOM_IE_I:
418 		ie_size = cmd_size;
419 		ret = nxpwifi_uap_custom_ie_prepare(tlv, data_buf, &ie_size);
420 		if (ret)
421 			return ret;
422 		cmd->size = cpu_to_le16(ie_size);
423 		break;
424 	default:
425 		return -EINVAL;
426 	}
427 
428 	return ret;
429 }
430 
431 static int
nxpwifi_cmd_uap_bss_start(struct nxpwifi_private * priv,struct host_cmd_ds_command * cmd,u16 cmd_no,void * data_buf,u16 cmd_action,u32 cmd_type)432 nxpwifi_cmd_uap_bss_start(struct nxpwifi_private *priv,
433 			  struct host_cmd_ds_command *cmd,
434 			  u16 cmd_no, void *data_buf,
435 			  u16 cmd_action, u32 cmd_type)
436 {
437 	struct nxpwifi_ie_types_host_mlme *tlv;
438 	int size;
439 
440 	cmd->command = cpu_to_le16(HOST_CMD_UAP_BSS_START);
441 	size = S_DS_GEN;
442 
443 	tlv = (struct nxpwifi_ie_types_host_mlme *)((u8 *)cmd + size);
444 	tlv->header.type = cpu_to_le16(TLV_TYPE_HOST_MLME);
445 	tlv->header.len = cpu_to_le16(sizeof(tlv->host_mlme));
446 	tlv->host_mlme = 1;
447 	size += sizeof(struct nxpwifi_ie_types_host_mlme);
448 
449 	cmd->size = cpu_to_le16(size);
450 
451 	return 0;
452 }
453 
454 static int
nxpwifi_ret_uap_bss_start(struct nxpwifi_private * priv,struct host_cmd_ds_command * resp,u16 cmdresp_no,void * data_buf)455 nxpwifi_ret_uap_bss_start(struct nxpwifi_private *priv,
456 			  struct host_cmd_ds_command *resp,
457 			  u16 cmdresp_no,
458 			  void *data_buf)
459 {
460 	struct nxpwifi_adapter *adapter = priv->adapter;
461 
462 	adapter->tx_lock_flag = false;
463 	adapter->pps_uapsd_mode = false;
464 	adapter->delay_null_pkt = false;
465 	priv->bss_started = 1;
466 
467 	return 0;
468 }
469 
470 static int
nxpwifi_ret_uap_bss_stop(struct nxpwifi_private * priv,struct host_cmd_ds_command * resp,u16 cmdresp_no,void * data_buf)471 nxpwifi_ret_uap_bss_stop(struct nxpwifi_private *priv,
472 			 struct host_cmd_ds_command *resp,
473 			 u16 cmdresp_no,
474 			 void *data_buf)
475 {
476 	priv->bss_started = 0;
477 
478 	return 0;
479 }
480 
nxpwifi_ret_apcmd_sta_list(struct nxpwifi_private * priv,struct host_cmd_ds_command * resp,u16 cmdresp_no,void * data_buf)481 static int nxpwifi_ret_apcmd_sta_list(struct nxpwifi_private *priv,
482 				      struct host_cmd_ds_command *resp,
483 				      u16 cmdresp_no, void *data_buf)
484 {
485 	struct host_cmd_ds_sta_list *sta_list = &resp->params.sta_list;
486 	struct nxpwifi_ie_types_sta_info *sta_info;
487 	struct nxpwifi_sta_node *sta_node;
488 	u16 sta_count;
489 	u32 resp_size;
490 	u32 base;
491 	u32 required_size;
492 	int i;
493 
494 	resp_size = le16_to_cpu(resp->size);
495 	sta_count = le16_to_cpu(sta_list->sta_count);
496 
497 	/* End of fixed fields before sta_list.tlv[] */
498 	base = offsetofend(struct host_cmd_ds_command, params.sta_list.sta_count);
499 
500 	/* At least fixed fields must be present */
501 	if (resp_size < base)
502 		return -EINVAL;
503 
504 	required_size = base + sta_count * sizeof(*sta_info);
505 
506 	/* Verify firmware did not claim more entries than the buffer holds */
507 	if (resp_size < required_size)
508 		return -EINVAL;
509 
510 	sta_info = (void *)sta_list->tlv;
511 
512 	rcu_read_lock();
513 	for (i = 0; i < sta_count; i++) {
514 		sta_node = nxpwifi_get_sta_entry(priv, sta_info->mac);
515 		if (unlikely(!sta_node)) {
516 			sta_info++;
517 			continue;
518 		}
519 
520 		sta_node->stats.rssi = sta_info->rssi;
521 		sta_info++;
522 	}
523 	rcu_read_unlock();
524 
525 	return 0;
526 }
527 
528 /* Build AP deauth command for the given MAC address. */
nxpwifi_cmd_uap_sta_deauth(struct nxpwifi_private * priv,struct host_cmd_ds_command * cmd,u16 cmd_no,void * data_buf,u16 cmd_action,u32 cmd_type)529 static int nxpwifi_cmd_uap_sta_deauth(struct nxpwifi_private *priv,
530 				      struct host_cmd_ds_command *cmd,
531 				      u16 cmd_no, void *data_buf,
532 				      u16 cmd_action, u32 cmd_type)
533 {
534 	struct host_cmd_ds_sta_deauth *sta_deauth = &cmd->params.sta_deauth;
535 	u8 *mac = (u8 *)data_buf;
536 
537 	cmd->command = cpu_to_le16(HOST_CMD_UAP_STA_DEAUTH);
538 	memcpy(sta_deauth->mac, mac, ETH_ALEN);
539 	sta_deauth->reason = cpu_to_le16(WLAN_REASON_DEAUTH_LEAVING);
540 
541 	cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_sta_deauth) +
542 				S_DS_GEN);
543 	return 0;
544 }
545 
546 static int
nxpwifi_cmd_uap_chan_report_request(struct nxpwifi_private * priv,struct host_cmd_ds_command * cmd,u16 cmd_no,void * data_buf,u16 cmd_action,u32 cmd_type)547 nxpwifi_cmd_uap_chan_report_request(struct nxpwifi_private *priv,
548 				    struct host_cmd_ds_command *cmd,
549 				    u16 cmd_no, void *data_buf,
550 				    u16 cmd_action, u32 cmd_type)
551 {
552 	return nxpwifi_cmd_issue_chan_report_request(priv, cmd, data_buf);
553 }
554 
555 /* Build AP add-station command. */
556 static int
nxpwifi_cmd_uap_add_new_station(struct nxpwifi_private * priv,struct host_cmd_ds_command * cmd,u16 cmd_no,void * data_buf,u16 cmd_action,u32 cmd_type)557 nxpwifi_cmd_uap_add_new_station(struct nxpwifi_private *priv,
558 				struct host_cmd_ds_command *cmd,
559 				u16 cmd_no, void *data_buf,
560 				u16 cmd_action, u32 cmd_type)
561 {
562 	struct host_cmd_ds_add_station *new_sta = &cmd->params.sta_info;
563 	struct nxpwifi_sta_info *add_sta = (struct nxpwifi_sta_info *)data_buf;
564 	struct station_parameters *params = add_sta->params;
565 	struct nxpwifi_sta_node *sta_ptr;
566 	u16 cmd_size;
567 	u8 *pos, *cmd_end;
568 	u16 tlv_len;
569 	struct nxpwifi_ie_types_sta_flag *sta_flag;
570 	int i;
571 
572 	cmd->command = cpu_to_le16(HOST_CMD_ADD_NEW_STATION);
573 	new_sta->action = cpu_to_le16(cmd_action);
574 	cmd_size = sizeof(struct host_cmd_ds_add_station) + S_DS_GEN;
575 
576 	if (cmd_action == HOST_ACT_ADD_STA)
577 		sta_ptr = nxpwifi_add_sta_entry(priv, add_sta->peer_mac);
578 	else
579 		sta_ptr = nxpwifi_get_sta_entry_rcu(priv, add_sta->peer_mac);
580 
581 	if (!sta_ptr)
582 		return -EINVAL;
583 
584 	memcpy(new_sta->peer_mac, add_sta->peer_mac, ETH_ALEN);
585 
586 	if (cmd_action == HOST_ACT_REMOVE_STA) {
587 		cmd->size = cpu_to_le16(cmd_size);
588 		return 0;
589 	}
590 
591 	new_sta->aid = cpu_to_le16(params->aid);
592 	new_sta->listen_interval = cpu_to_le32(params->listen_interval);
593 	new_sta->cap_info = cpu_to_le16(params->capability);
594 
595 	pos = new_sta->tlv;
596 	cmd_end = (u8 *)cmd;
597 	cmd_end += (NXPWIFI_SIZE_OF_CMD_BUFFER - 1);
598 
599 	if (params->sta_flags_set & NL80211_STA_FLAG_WME)
600 		sta_ptr->is_wmm_enabled = 1;
601 	sta_flag = (struct nxpwifi_ie_types_sta_flag *)pos;
602 	sta_flag->header.type = cpu_to_le16(TLV_TYPE_UAP_STA_FLAGS);
603 	sta_flag->header.len = cpu_to_le16(sizeof(__le32));
604 	sta_flag->sta_flags = cpu_to_le32(params->sta_flags_set);
605 	pos += sizeof(struct nxpwifi_ie_types_sta_flag);
606 	cmd_size += sizeof(struct nxpwifi_ie_types_sta_flag);
607 
608 	if (params->ext_capab_len) {
609 		u8 *data = (u8 *)params->ext_capab;
610 		u16 len = params->ext_capab_len;
611 
612 		tlv_len = nxpwifi_append_data_tlv(WLAN_EID_EXT_CAPABILITY,
613 						  data, len, pos, cmd_end);
614 		if (!tlv_len)
615 			return -EINVAL;
616 		pos += tlv_len;
617 		cmd_size += tlv_len;
618 	}
619 
620 	if (params->link_sta_params.supported_rates_len) {
621 		u8 *data = (u8 *)params->link_sta_params.supported_rates;
622 		u16 len = params->link_sta_params.supported_rates_len;
623 
624 		tlv_len = nxpwifi_append_data_tlv(WLAN_EID_SUPP_RATES,
625 						  data, len, pos, cmd_end);
626 		if (!tlv_len)
627 			return -EINVAL;
628 		pos += tlv_len;
629 		cmd_size += tlv_len;
630 	}
631 
632 	if (params->uapsd_queues || params->max_sp) {
633 		u8 qos_capability = params->uapsd_queues | (params->max_sp << 5);
634 		u8 *data = &qos_capability;
635 		u16 len = sizeof(u8);
636 
637 		tlv_len = nxpwifi_append_data_tlv(WLAN_EID_QOS_CAPA,
638 						  data, len, pos, cmd_end);
639 		if (!tlv_len)
640 			return -EINVAL;
641 		pos += tlv_len;
642 		cmd_size += tlv_len;
643 		sta_ptr->is_wmm_enabled = 1;
644 	}
645 
646 	if (params->link_sta_params.ht_capa) {
647 		u8 *data = (u8 *)params->link_sta_params.ht_capa;
648 		u16 len = sizeof(struct ieee80211_ht_cap);
649 
650 		tlv_len = nxpwifi_append_data_tlv(WLAN_EID_HT_CAPABILITY,
651 						  data, len, pos, cmd_end);
652 		if (!tlv_len)
653 			return -EINVAL;
654 		pos += tlv_len;
655 		cmd_size += tlv_len;
656 		sta_ptr->is_11n_enabled = 1;
657 		sta_ptr->max_amsdu =
658 			le16_to_cpu(params->link_sta_params.ht_capa->cap_info) &
659 			IEEE80211_HT_CAP_MAX_AMSDU ?
660 			NXPWIFI_TX_DATA_BUF_SIZE_8K :
661 			NXPWIFI_TX_DATA_BUF_SIZE_4K;
662 	}
663 
664 	if (params->link_sta_params.vht_capa) {
665 		u8 *data = (u8 *)params->link_sta_params.vht_capa;
666 		u16 len = sizeof(struct ieee80211_vht_cap);
667 
668 		tlv_len = nxpwifi_append_data_tlv(WLAN_EID_VHT_CAPABILITY,
669 						  data, len, pos, cmd_end);
670 		if (!tlv_len)
671 			return -EINVAL;
672 		pos += tlv_len;
673 		cmd_size += tlv_len;
674 		sta_ptr->is_11ac_enabled = 1;
675 	}
676 
677 	if (params->link_sta_params.opmode_notif_used) {
678 		u8 *data = &params->link_sta_params.opmode_notif;
679 		u16 len = sizeof(u8);
680 
681 		tlv_len = nxpwifi_append_data_tlv(WLAN_EID_OPMODE_NOTIF,
682 						  data, len, pos, cmd_end);
683 		if (!tlv_len)
684 			return -EINVAL;
685 		pos += tlv_len;
686 		cmd_size += tlv_len;
687 	}
688 
689 	if (params->link_sta_params.he_capa_len) {
690 		u8 *data = (u8 *)params->link_sta_params.he_capa;
691 		u16 len = params->link_sta_params.he_capa_len;
692 
693 		tlv_len = nxpwifi_append_data_tlv(WLAN_EID_EXT_HE_CAPABILITY,
694 						  data, len, pos, cmd_end);
695 		if (!tlv_len)
696 			return -EINVAL;
697 		pos += tlv_len;
698 		cmd_size += tlv_len;
699 		sta_ptr->is_11ax_enabled = 1;
700 	}
701 
702 	for (i = 0; i < MAX_NUM_TID; i++) {
703 		if (sta_ptr->is_11n_enabled || sta_ptr->is_11ax_enabled)
704 			sta_ptr->ampdu_sta[i] =
705 				      priv->aggr_prio_tbl[i].ampdu_user;
706 		else
707 			sta_ptr->ampdu_sta[i] = BA_STREAM_NOT_ALLOWED;
708 	}
709 
710 	memset(sta_ptr->rx_seq, 0xff, sizeof(sta_ptr->rx_seq));
711 
712 	cmd->size = cpu_to_le16(cmd_size);
713 
714 	return 0;
715 }
716 
717 static const struct nxpwifi_cmd_entry cmd_table_uap[] = {
718 	{.cmd_no = HOST_CMD_APCMD_SYS_RESET,
719 	.prepare_cmd = nxpwifi_cmd_fill_head_only,
720 	.cmd_resp = NULL},
721 	{.cmd_no = HOST_CMD_UAP_SYS_CONFIG,
722 	.prepare_cmd = nxpwifi_cmd_uap_sys_config,
723 	.cmd_resp = NULL},
724 	{.cmd_no = HOST_CMD_UAP_BSS_START,
725 	.prepare_cmd = nxpwifi_cmd_uap_bss_start,
726 	.cmd_resp = nxpwifi_ret_uap_bss_start},
727 	{.cmd_no = HOST_CMD_UAP_BSS_STOP,
728 	.prepare_cmd = nxpwifi_cmd_fill_head_only,
729 	.cmd_resp = nxpwifi_ret_uap_bss_stop},
730 	{.cmd_no = HOST_CMD_APCMD_STA_LIST,
731 	.prepare_cmd = nxpwifi_cmd_fill_head_only,
732 	.cmd_resp = nxpwifi_ret_apcmd_sta_list},
733 	{.cmd_no = HOST_CMD_UAP_STA_DEAUTH,
734 	.prepare_cmd = nxpwifi_cmd_uap_sta_deauth,
735 	.cmd_resp = NULL},
736 	{.cmd_no = HOST_CMD_CHAN_REPORT_REQUEST,
737 	.prepare_cmd = nxpwifi_cmd_uap_chan_report_request,
738 	.cmd_resp = NULL},
739 	{.cmd_no = HOST_CMD_ADD_NEW_STATION,
740 	.prepare_cmd = nxpwifi_cmd_uap_add_new_station,
741 	.cmd_resp = NULL},
742 };
743 
744 /* Prepare AP commands and dispatch to per-cmd builders before sending to firmware. */
nxpwifi_uap_prepare_cmd(struct nxpwifi_private * priv,struct cmd_ctrl_node * cmd_node,u16 cmd_action,u32 type)745 int nxpwifi_uap_prepare_cmd(struct nxpwifi_private *priv,
746 			    struct cmd_ctrl_node *cmd_node,
747 			    u16 cmd_action, u32 type)
748 {
749 	struct nxpwifi_adapter *adapter = priv->adapter;
750 	u16 cmd_no = cmd_node->cmd_no;
751 	struct host_cmd_ds_command *cmd =
752 		(struct host_cmd_ds_command *)cmd_node->skb->data;
753 	void *data_buf = cmd_node->data_buf;
754 	int i, ret = -EINVAL;
755 
756 	for (i = 0; i < ARRAY_SIZE(cmd_table_uap); i++) {
757 		if (cmd_no == cmd_table_uap[i].cmd_no) {
758 			if (cmd_table_uap[i].prepare_cmd)
759 				ret = cmd_table_uap[i].prepare_cmd(priv, cmd,
760 								   cmd_no,
761 								   data_buf,
762 								   cmd_action,
763 								   type);
764 			cmd_node->cmd_resp = cmd_table_uap[i].cmd_resp;
765 			break;
766 		}
767 	}
768 
769 	if (i == ARRAY_SIZE(cmd_table_uap))
770 		nxpwifi_dbg(adapter, ERROR,
771 			    "%s: unknown command: %#x\n",
772 			    __func__, cmd_no);
773 	else
774 		nxpwifi_dbg(adapter, CMD,
775 			    "%s: command: %#x\n",
776 			    __func__, cmd_no);
777 
778 	return ret;
779 }
780 
781 /* Translate cfg80211_ap_settings security into bss_config for firmware. */
nxpwifi_set_secure_params(struct nxpwifi_private * priv,struct nxpwifi_uap_bss_param * bss_config,struct cfg80211_ap_settings * params)782 int nxpwifi_set_secure_params(struct nxpwifi_private *priv,
783 			      struct nxpwifi_uap_bss_param *bss_config,
784 			      struct cfg80211_ap_settings *params)
785 {
786 	int i;
787 	struct nxpwifi_wep_key wep_key;
788 
789 	if (!params->privacy) {
790 		bss_config->protocol = PROTOCOL_NO_SECURITY;
791 		bss_config->key_mgmt = KEY_MGMT_NONE;
792 		bss_config->wpa_cfg.length = 0;
793 		priv->sec_info.wep_enabled = 0;
794 		priv->sec_info.wpa_enabled = 0;
795 		priv->sec_info.wpa2_enabled = 0;
796 
797 		return 0;
798 	}
799 
800 	switch (params->auth_type) {
801 	case NL80211_AUTHTYPE_OPEN_SYSTEM:
802 		bss_config->auth_mode = WLAN_AUTH_OPEN;
803 		break;
804 	case NL80211_AUTHTYPE_SHARED_KEY:
805 		bss_config->auth_mode = WLAN_AUTH_SHARED_KEY;
806 		break;
807 	case NL80211_AUTHTYPE_NETWORK_EAP:
808 		bss_config->auth_mode = WLAN_AUTH_LEAP;
809 		break;
810 	default:
811 		bss_config->auth_mode = NXPWIFI_AUTH_MODE_AUTO;
812 		break;
813 	}
814 
815 	bss_config->key_mgmt_operation |= KEY_MGMT_ON_HOST;
816 
817 	bss_config->protocol = 0;
818 	if (params->crypto.wpa_versions & NL80211_WPA_VERSION_1)
819 		bss_config->protocol |= PROTOCOL_WPA;
820 	if (params->crypto.wpa_versions & NL80211_WPA_VERSION_2)
821 		bss_config->protocol |= PROTOCOL_WPA2;
822 
823 	bss_config->key_mgmt = 0;
824 	for (i = 0; i < params->crypto.n_akm_suites; i++) {
825 		switch (params->crypto.akm_suites[i]) {
826 		case WLAN_AKM_SUITE_8021X:
827 			bss_config->key_mgmt |= KEY_MGMT_EAP;
828 			break;
829 		case WLAN_AKM_SUITE_PSK:
830 			bss_config->key_mgmt |= KEY_MGMT_PSK;
831 			break;
832 		case WLAN_AKM_SUITE_PSK_SHA256:
833 			bss_config->key_mgmt |= KEY_MGMT_PSK_SHA256;
834 			break;
835 		case WLAN_AKM_SUITE_OWE:
836 			bss_config->key_mgmt |= KEY_MGMT_OWE;
837 			break;
838 		case WLAN_AKM_SUITE_SAE:
839 			bss_config->key_mgmt |= KEY_MGMT_SAE;
840 			break;
841 		default:
842 			break;
843 		}
844 	}
845 
846 	for (i = 0; i < params->crypto.n_ciphers_pairwise; i++) {
847 		switch (params->crypto.ciphers_pairwise[i]) {
848 		case WLAN_CIPHER_SUITE_WEP40:
849 		case WLAN_CIPHER_SUITE_WEP104:
850 			break;
851 		case WLAN_CIPHER_SUITE_TKIP:
852 			if (params->crypto.wpa_versions & NL80211_WPA_VERSION_1)
853 				bss_config->wpa_cfg.pairwise_cipher_wpa |=
854 								CIPHER_TKIP;
855 			if (params->crypto.wpa_versions & NL80211_WPA_VERSION_2)
856 				bss_config->wpa_cfg.pairwise_cipher_wpa2 |=
857 								CIPHER_TKIP;
858 			break;
859 		case WLAN_CIPHER_SUITE_CCMP:
860 			if (params->crypto.wpa_versions & NL80211_WPA_VERSION_1)
861 				bss_config->wpa_cfg.pairwise_cipher_wpa |=
862 								CIPHER_AES_CCMP;
863 			if (params->crypto.wpa_versions & NL80211_WPA_VERSION_2)
864 				bss_config->wpa_cfg.pairwise_cipher_wpa2 |=
865 								CIPHER_AES_CCMP;
866 			break;
867 		default:
868 			break;
869 		}
870 	}
871 
872 	switch (params->crypto.cipher_group) {
873 	case WLAN_CIPHER_SUITE_WEP40:
874 	case WLAN_CIPHER_SUITE_WEP104:
875 		if (priv->sec_info.wep_enabled) {
876 			bss_config->protocol = PROTOCOL_STATIC_WEP;
877 			bss_config->key_mgmt = KEY_MGMT_NONE;
878 			bss_config->wpa_cfg.length = 0;
879 
880 			for (i = 0; i < NUM_WEP_KEYS; i++) {
881 				wep_key = priv->wep_key[i];
882 				bss_config->wep_cfg[i].key_index = i;
883 
884 				if (priv->wep_key_curr_index == i)
885 					bss_config->wep_cfg[i].is_default = 1;
886 				else
887 					bss_config->wep_cfg[i].is_default = 0;
888 
889 				bss_config->wep_cfg[i].length =
890 							     wep_key.key_length;
891 				memcpy(&bss_config->wep_cfg[i].key,
892 				       &wep_key.key_material,
893 				       wep_key.key_length);
894 			}
895 		}
896 		break;
897 	case WLAN_CIPHER_SUITE_TKIP:
898 		bss_config->wpa_cfg.group_cipher = CIPHER_TKIP;
899 		break;
900 	case WLAN_CIPHER_SUITE_CCMP:
901 		bss_config->wpa_cfg.group_cipher = CIPHER_AES_CCMP;
902 		break;
903 	default:
904 		break;
905 	}
906 
907 	return 0;
908 }
909 
910 /* Update 11n HT params from beacon and fill bss_config. */
911 void
nxpwifi_set_ht_params(struct nxpwifi_private * priv,struct nxpwifi_uap_bss_param * bss_cfg,struct cfg80211_ap_settings * params)912 nxpwifi_set_ht_params(struct nxpwifi_private *priv,
913 		      struct nxpwifi_uap_bss_param *bss_cfg,
914 		      struct cfg80211_ap_settings *params)
915 {
916 	const u8 *ht_ie;
917 
918 	if (!ISSUPP_11NENABLED(priv->adapter->fw_cap_info))
919 		return;
920 
921 	ht_ie = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, params->beacon.tail,
922 				 params->beacon.tail_len);
923 	if (ht_ie) {
924 		memcpy(&bss_cfg->ht_cap, ht_ie + 2,
925 		       sizeof(struct ieee80211_ht_cap));
926 		if (ISSUPP_BEAMFORMING(priv->adapter->hw_dot_11n_dev_cap))
927 			bss_cfg->ht_cap.tx_BF_cap_info =
928 				cpu_to_le32(NXPWIFI_DEF_11N_TX_BF_CAP);
929 		priv->ap_11n_enabled = 1;
930 	} else {
931 		memset(&bss_cfg->ht_cap, 0, sizeof(struct ieee80211_ht_cap));
932 		bss_cfg->ht_cap.cap_info = cpu_to_le16(NXPWIFI_DEF_HT_CAP);
933 		bss_cfg->ht_cap.ampdu_params_info = NXPWIFI_DEF_AMPDU;
934 	}
935 }
936 
937 /* Update 11ac VHT params from beacon and fill bss_config. */
nxpwifi_set_vht_params(struct nxpwifi_private * priv,struct nxpwifi_uap_bss_param * bss_cfg,struct cfg80211_ap_settings * params)938 void nxpwifi_set_vht_params(struct nxpwifi_private *priv,
939 			    struct nxpwifi_uap_bss_param *bss_cfg,
940 			    struct cfg80211_ap_settings *params)
941 {
942 	const u8 *vht_ie;
943 
944 	vht_ie = cfg80211_find_ie(WLAN_EID_VHT_CAPABILITY, params->beacon.tail,
945 				  params->beacon.tail_len);
946 	if (vht_ie) {
947 		memcpy(&bss_cfg->vht_cap, vht_ie + 2,
948 		       sizeof(struct ieee80211_vht_cap));
949 		priv->ap_11ac_enabled = 1;
950 	} else {
951 		priv->ap_11ac_enabled = 0;
952 	}
953 }
954 
955 /* Extract TPC request from beacon and set power_constraint. */
nxpwifi_set_tpc_params(struct nxpwifi_private * priv,struct nxpwifi_uap_bss_param * bss_cfg,struct cfg80211_ap_settings * params)956 void nxpwifi_set_tpc_params(struct nxpwifi_private *priv,
957 			    struct nxpwifi_uap_bss_param *bss_cfg,
958 			    struct cfg80211_ap_settings *params)
959 {
960 	const u8 *tpc_ie;
961 
962 	tpc_ie = cfg80211_find_ie(WLAN_EID_TPC_REQUEST, params->beacon.tail,
963 				  params->beacon.tail_len);
964 	if (tpc_ie)
965 		bss_cfg->power_constraint = *(tpc_ie + 2);
966 	else
967 		bss_cfg->power_constraint = 0;
968 }
969 
970 /* Enable VHT only when VHT IE is present; otherwise disable VHT. */
nxpwifi_set_vht_width(struct nxpwifi_private * priv,enum nl80211_chan_width width,bool ap_11ac_enable)971 void nxpwifi_set_vht_width(struct nxpwifi_private *priv,
972 			   enum nl80211_chan_width width,
973 			   bool ap_11ac_enable)
974 {
975 	struct nxpwifi_adapter *adapter = priv->adapter;
976 	struct nxpwifi_11ac_vht_cfg vht_cfg;
977 
978 	vht_cfg.band_config = VHT_CFG_5GHZ;
979 	vht_cfg.cap_info = adapter->hw_dot_11ac_dev_cap;
980 
981 	if (!ap_11ac_enable) {
982 		vht_cfg.mcs_tx_set = DISABLE_VHT_MCS_SET;
983 		vht_cfg.mcs_rx_set = DISABLE_VHT_MCS_SET;
984 	} else {
985 		vht_cfg.mcs_tx_set = DEFAULT_VHT_MCS_SET;
986 		vht_cfg.mcs_rx_set = DEFAULT_VHT_MCS_SET;
987 	}
988 
989 	vht_cfg.misc_config  = VHT_CAP_UAP_ONLY;
990 
991 	if (ap_11ac_enable && width >= NL80211_CHAN_WIDTH_80)
992 		vht_cfg.misc_config |= VHT_BW_80_160_80P80;
993 
994 	nxpwifi_send_cmd(priv, HOST_CMD_11AC_CFG,
995 			 HOST_ACT_GEN_SET, 0, &vht_cfg, true);
996 }
997 
nxpwifi_check_11ax_capability(struct nxpwifi_private * priv,struct nxpwifi_uap_bss_param * bss_cfg,struct cfg80211_ap_settings * params)998 bool nxpwifi_check_11ax_capability(struct nxpwifi_private *priv,
999 				   struct nxpwifi_uap_bss_param *bss_cfg,
1000 				   struct cfg80211_ap_settings *params)
1001 {
1002 	struct nxpwifi_adapter *adapter = priv->adapter;
1003 	u8 band = bss_cfg->band_cfg & BAND_CFG_CHAN_BAND_MASK;
1004 
1005 	if (band == BAND_2GHZ &&
1006 	    !(adapter->fw_bands & BAND_GAX))
1007 		return false;
1008 
1009 	if (band == BAND_5GHZ &&
1010 	    !(adapter->fw_bands & BAND_AAX))
1011 		return false;
1012 
1013 	if (params->he_cap)
1014 		return true;
1015 	else
1016 		return false;
1017 }
1018 
nxpwifi_set_11ax_status(struct nxpwifi_private * priv,struct nxpwifi_uap_bss_param * bss_cfg,struct cfg80211_ap_settings * params)1019 int nxpwifi_set_11ax_status(struct nxpwifi_private *priv,
1020 			    struct nxpwifi_uap_bss_param *bss_cfg,
1021 			    struct cfg80211_ap_settings *params)
1022 {
1023 	struct nxpwifi_11ax_he_cfg ax_cfg;
1024 	u8 band = bss_cfg->band_cfg & BAND_CFG_CHAN_BAND_MASK;
1025 	const struct element *he_cap;
1026 	int ret;
1027 
1028 	if (band == BAND_2GHZ)
1029 		ax_cfg.band = BIT(0);
1030 	else if (band == BAND_5GHZ)
1031 		ax_cfg.band = BIT(1);
1032 	else
1033 		return -EINVAL;
1034 
1035 	ret = nxpwifi_send_cmd(priv, HOST_CMD_11AX_CFG,
1036 			       HOST_ACT_GEN_GET, 0, &ax_cfg, true);
1037 	if (ret)
1038 		return ret;
1039 
1040 	he_cap = cfg80211_find_ext_elem(WLAN_EID_EXT_HE_CAPABILITY,
1041 					params->beacon.tail,
1042 					params->beacon.tail_len);
1043 
1044 	if (he_cap) {
1045 		ax_cfg.he_cap_cfg.id = he_cap->id;
1046 		ax_cfg.he_cap_cfg.len = he_cap->datalen;
1047 		if (params->twt_responder == 0) {
1048 			struct nxpwifi_11ax_he_cap_cfg *he_cap_cfg =
1049 			(struct nxpwifi_11ax_he_cap_cfg *)he_cap;
1050 
1051 			he_cap_cfg->cap_elem.mac_cap_info[0] &=
1052 				~HE_MAC_CAP_TWT_RESP_SUPPORT;
1053 		}
1054 		memcpy(ax_cfg.data + 4,
1055 		       he_cap->data,
1056 		       he_cap->datalen);
1057 	} else {
1058 		/* disable */
1059 		if (ax_cfg.he_cap_cfg.len &&
1060 		    ax_cfg.he_cap_cfg.ext_id == WLAN_EID_EXT_HE_CAPABILITY) {
1061 			memset(ax_cfg.he_cap_cfg.he_txrx_mcs_support, 0xff,
1062 			       sizeof(ax_cfg.he_cap_cfg.he_txrx_mcs_support));
1063 		}
1064 	}
1065 
1066 	return nxpwifi_send_cmd(priv, HOST_CMD_11AX_CFG,
1067 				HOST_ACT_GEN_SET, 0, &ax_cfg, true);
1068 }
1069 
1070 /* Copy supported rates from beacon into bss_config. */
1071 void
nxpwifi_set_uap_rates(struct nxpwifi_uap_bss_param * bss_cfg,struct cfg80211_ap_settings * params)1072 nxpwifi_set_uap_rates(struct nxpwifi_uap_bss_param *bss_cfg,
1073 		      struct cfg80211_ap_settings *params)
1074 {
1075 	struct element *rate_ie;
1076 	int var_offset = offsetof(struct ieee80211_mgmt, u.beacon.variable);
1077 	const u8 *var_pos = params->beacon.head + var_offset;
1078 	int len = params->beacon.head_len - var_offset;
1079 	u8 rate_len = 0;
1080 
1081 	rate_ie = (void *)cfg80211_find_ie(WLAN_EID_SUPP_RATES, var_pos, len);
1082 	if (rate_ie) {
1083 		if (rate_ie->datalen > NXPWIFI_SUPPORTED_RATES)
1084 			return;
1085 		memcpy(bss_cfg->rates, rate_ie + 1, rate_ie->datalen);
1086 		rate_len = rate_ie->datalen;
1087 	}
1088 
1089 	rate_ie = (void *)cfg80211_find_ie(WLAN_EID_EXT_SUPP_RATES,
1090 					   params->beacon.tail,
1091 					   params->beacon.tail_len);
1092 	if (rate_ie) {
1093 		if (rate_ie->datalen > NXPWIFI_SUPPORTED_RATES - rate_len)
1094 			return;
1095 		memcpy(bss_cfg->rates + rate_len,
1096 		       rate_ie + 1, rate_ie->datalen);
1097 	}
1098 }
1099 
1100 /*
1101  * Initialize bss_config fields to sentinel values.
1102  * Fields left with sentinel values are treated as unset and will not be
1103  * included in the corresponding firmware command.
1104  */
nxpwifi_set_sys_config_invalid_data(struct nxpwifi_uap_bss_param * config)1105 void nxpwifi_set_sys_config_invalid_data(struct nxpwifi_uap_bss_param *config)
1106 {
1107 	config->radio_ctl = __NXPWIFI_RADIO_CTL_MAX;
1108 	config->dtim_period = NXPWIFI_INVALID_DTIM_PERIOD;
1109 	config->beacon_period = NXPWIFI_INVALID_BEACON_PERIOD;
1110 	config->auth_mode = NXPWIFI_AUTH_MODE_AUTO;
1111 	config->rts_threshold = NXPWIFI_INVALID_RTS;
1112 	config->frag_threshold = NXPWIFI_INVALID_FRAG;
1113 	config->retry_limit = NXPWIFI_INVALID_RETRY_LIMI;
1114 }
1115 
1116 /* Parse WMM params from cfg80211_ap_settings and update bss_config. */
1117 void
nxpwifi_set_wmm_params(struct nxpwifi_private * priv,struct nxpwifi_uap_bss_param * bss_cfg,struct cfg80211_ap_settings * params)1118 nxpwifi_set_wmm_params(struct nxpwifi_private *priv,
1119 		       struct nxpwifi_uap_bss_param *bss_cfg,
1120 		       struct cfg80211_ap_settings *params)
1121 {
1122 	const u8 *vendor_ie;
1123 	const struct ieee80211_wmm_param_ie *wmm;
1124 	u8 ie_len;
1125 
1126 	vendor_ie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT,
1127 					    WLAN_OUI_TYPE_MICROSOFT_WMM,
1128 					    params->beacon.tail,
1129 					    params->beacon.tail_len);
1130 	if (!vendor_ie)
1131 		goto no_wmm;
1132 
1133 	ie_len = vendor_ie[1];
1134 
1135 	if (ie_len < sizeof(struct ieee80211_wmm_param_ie) - 2)
1136 		goto no_wmm;
1137 
1138 	wmm = (const struct ieee80211_wmm_param_ie *)vendor_ie;
1139 
1140 	if (memcmp(wmm->oui, "\x00\x50\xf2", 3))
1141 		goto no_wmm;
1142 
1143 	if (wmm->oui_type != WLAN_OUI_TYPE_MICROSOFT_WMM)
1144 		goto no_wmm;
1145 
1146 	if (wmm->oui_subtype != 1)
1147 		goto no_wmm;
1148 
1149 	/* Only WMM version 1 is supported */
1150 	if (wmm->version != 1)
1151 		goto no_wmm;
1152 
1153 	memcpy(&bss_cfg->wmm_element, wmm,
1154 	       sizeof(struct ieee80211_wmm_param_ie));
1155 
1156 	priv->wmm_enabled = true;
1157 	return;
1158 
1159 no_wmm:
1160 	memset(&bss_cfg->wmm_element, 0, sizeof(bss_cfg->wmm_element));
1161 	priv->wmm_enabled = false;
1162 }
1163 
1164 /* Enable 11d when country IE is present. */
nxpwifi_config_uap_11d(struct nxpwifi_private * priv,struct cfg80211_beacon_data * beacon_data)1165 void nxpwifi_config_uap_11d(struct nxpwifi_private *priv,
1166 			    struct cfg80211_beacon_data *beacon_data)
1167 {
1168 	enum state_11d_t state_11d;
1169 	const u8 *country_ie;
1170 
1171 	country_ie = cfg80211_find_ie(WLAN_EID_COUNTRY, beacon_data->tail,
1172 				      beacon_data->tail_len);
1173 	if (country_ie) {
1174 		/* Send cmd to FW to enable 11D function */
1175 		state_11d = ENABLE_11D;
1176 		if (nxpwifi_send_cmd(priv, HOST_CMD_802_11_SNMP_MIB,
1177 				     HOST_ACT_GEN_SET, DOT11D_I,
1178 				     &state_11d, true)) {
1179 			nxpwifi_dbg(priv->adapter, ERROR,
1180 				    "11D: failed to enable 11D\n");
1181 		}
1182 	}
1183 }
1184 
nxpwifi_uap_set_channel(struct nxpwifi_private * priv,struct nxpwifi_uap_bss_param * bss_cfg,struct cfg80211_chan_def chandef)1185 void nxpwifi_uap_set_channel(struct nxpwifi_private *priv,
1186 			     struct nxpwifi_uap_bss_param *bss_cfg,
1187 			     struct cfg80211_chan_def chandef)
1188 {
1189 	u8 config_bands = 0, old_bands = priv->config_bands;
1190 
1191 	priv->bss_chandef = chandef;
1192 
1193 	bss_cfg->channel =
1194 		ieee80211_frequency_to_channel(chandef.chan->center_freq);
1195 
1196 	nxpwifi_convert_chan_to_band_cfg(priv, &bss_cfg->band_cfg, &chandef);
1197 
1198 	/* Set appropriate bands */
1199 	if (chandef.chan->band == NL80211_BAND_2GHZ) {
1200 		config_bands = BAND_B | BAND_G;
1201 		if (chandef.width > NL80211_CHAN_WIDTH_20_NOHT)
1202 			config_bands |= BAND_GN | BAND_GAX;
1203 	} else {
1204 		config_bands = BAND_A;
1205 		if (chandef.width > NL80211_CHAN_WIDTH_20_NOHT)
1206 			config_bands |= BAND_AN;
1207 		if (chandef.width > NL80211_CHAN_WIDTH_40)
1208 			config_bands |= BAND_AAC | BAND_AAX;
1209 	}
1210 
1211 	priv->config_bands = config_bands;
1212 
1213 	if (old_bands != config_bands) {
1214 		if (nxpwifi_band_to_radio_type(priv->config_bands) ==
1215 		    HOST_SCAN_RADIO_TYPE_BG)
1216 			nxpwifi_send_domain_info_cmd_fw(priv->adapter->wiphy,
1217 							NL80211_BAND_2GHZ);
1218 		else
1219 			nxpwifi_send_domain_info_cmd_fw(priv->adapter->wiphy,
1220 							NL80211_BAND_5GHZ);
1221 	}
1222 }
1223 
nxpwifi_config_start_uap(struct nxpwifi_private * priv,struct nxpwifi_uap_bss_param * bss_cfg)1224 int nxpwifi_config_start_uap(struct nxpwifi_private *priv,
1225 			     struct nxpwifi_uap_bss_param *bss_cfg)
1226 {
1227 	int ret;
1228 
1229 	ret = nxpwifi_send_cmd(priv, HOST_CMD_UAP_SYS_CONFIG,
1230 			       HOST_ACT_GEN_SET,
1231 			       UAP_BSS_PARAMS_I, bss_cfg, true);
1232 	if (ret) {
1233 		nxpwifi_dbg(priv->adapter, ERROR,
1234 			    "Failed to set AP configuration\n");
1235 		return ret;
1236 	}
1237 
1238 	ret = nxpwifi_send_cmd(priv, HOST_CMD_UAP_BSS_START,
1239 			       HOST_ACT_GEN_SET, 0, NULL, true);
1240 	if (ret) {
1241 		nxpwifi_dbg(priv->adapter, ERROR,
1242 			    "Failed to start the BSS\n");
1243 		return ret;
1244 	}
1245 
1246 	if (priv->sec_info.wep_enabled)
1247 		priv->curr_pkt_filter |= HOST_ACT_MAC_WEP_ENABLE;
1248 	else
1249 		priv->curr_pkt_filter &= ~HOST_ACT_MAC_WEP_ENABLE;
1250 
1251 	ret = nxpwifi_send_cmd(priv, HOST_CMD_MAC_CONTROL,
1252 			       HOST_ACT_GEN_SET, 0,
1253 			       &priv->curr_pkt_filter, true);
1254 
1255 	return ret;
1256 }
1257