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 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 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. */ 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. */ 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 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 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 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 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 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. */ 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 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 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. */ 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. */ 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 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. */ 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. */ 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. */ 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 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 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 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 */ 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 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. */ 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 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 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