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, ¶m_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 = ¶ms->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