162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * NXP Wireless LAN device driver: AP specific command handling 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright 2011-2020 NXP 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include "main.h" 962306a36Sopenharmony_ci#include "11ac.h" 1062306a36Sopenharmony_ci#include "11n.h" 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci/* This function parses security related parameters from cfg80211_ap_settings 1362306a36Sopenharmony_ci * and sets into FW understandable bss_config structure. 1462306a36Sopenharmony_ci */ 1562306a36Sopenharmony_ciint mwifiex_set_secure_params(struct mwifiex_private *priv, 1662306a36Sopenharmony_ci struct mwifiex_uap_bss_param *bss_config, 1762306a36Sopenharmony_ci struct cfg80211_ap_settings *params) { 1862306a36Sopenharmony_ci int i; 1962306a36Sopenharmony_ci struct mwifiex_wep_key wep_key; 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci if (!params->privacy) { 2262306a36Sopenharmony_ci bss_config->protocol = PROTOCOL_NO_SECURITY; 2362306a36Sopenharmony_ci bss_config->key_mgmt = KEY_MGMT_NONE; 2462306a36Sopenharmony_ci bss_config->wpa_cfg.length = 0; 2562306a36Sopenharmony_ci priv->sec_info.wep_enabled = 0; 2662306a36Sopenharmony_ci priv->sec_info.wpa_enabled = 0; 2762306a36Sopenharmony_ci priv->sec_info.wpa2_enabled = 0; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci return 0; 3062306a36Sopenharmony_ci } 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci switch (params->auth_type) { 3362306a36Sopenharmony_ci case NL80211_AUTHTYPE_OPEN_SYSTEM: 3462306a36Sopenharmony_ci bss_config->auth_mode = WLAN_AUTH_OPEN; 3562306a36Sopenharmony_ci break; 3662306a36Sopenharmony_ci case NL80211_AUTHTYPE_SHARED_KEY: 3762306a36Sopenharmony_ci bss_config->auth_mode = WLAN_AUTH_SHARED_KEY; 3862306a36Sopenharmony_ci break; 3962306a36Sopenharmony_ci case NL80211_AUTHTYPE_NETWORK_EAP: 4062306a36Sopenharmony_ci bss_config->auth_mode = WLAN_AUTH_LEAP; 4162306a36Sopenharmony_ci break; 4262306a36Sopenharmony_ci default: 4362306a36Sopenharmony_ci bss_config->auth_mode = MWIFIEX_AUTH_MODE_AUTO; 4462306a36Sopenharmony_ci break; 4562306a36Sopenharmony_ci } 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci bss_config->key_mgmt_operation |= KEY_MGMT_ON_HOST; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci for (i = 0; i < params->crypto.n_akm_suites; i++) { 5062306a36Sopenharmony_ci switch (params->crypto.akm_suites[i]) { 5162306a36Sopenharmony_ci case WLAN_AKM_SUITE_8021X: 5262306a36Sopenharmony_ci if (params->crypto.wpa_versions & 5362306a36Sopenharmony_ci NL80211_WPA_VERSION_1) { 5462306a36Sopenharmony_ci bss_config->protocol = PROTOCOL_WPA; 5562306a36Sopenharmony_ci bss_config->key_mgmt = KEY_MGMT_EAP; 5662306a36Sopenharmony_ci } 5762306a36Sopenharmony_ci if (params->crypto.wpa_versions & 5862306a36Sopenharmony_ci NL80211_WPA_VERSION_2) { 5962306a36Sopenharmony_ci bss_config->protocol |= PROTOCOL_WPA2; 6062306a36Sopenharmony_ci bss_config->key_mgmt = KEY_MGMT_EAP; 6162306a36Sopenharmony_ci } 6262306a36Sopenharmony_ci break; 6362306a36Sopenharmony_ci case WLAN_AKM_SUITE_PSK: 6462306a36Sopenharmony_ci if (params->crypto.wpa_versions & 6562306a36Sopenharmony_ci NL80211_WPA_VERSION_1) { 6662306a36Sopenharmony_ci bss_config->protocol = PROTOCOL_WPA; 6762306a36Sopenharmony_ci bss_config->key_mgmt = KEY_MGMT_PSK; 6862306a36Sopenharmony_ci } 6962306a36Sopenharmony_ci if (params->crypto.wpa_versions & 7062306a36Sopenharmony_ci NL80211_WPA_VERSION_2) { 7162306a36Sopenharmony_ci bss_config->protocol |= PROTOCOL_WPA2; 7262306a36Sopenharmony_ci bss_config->key_mgmt = KEY_MGMT_PSK; 7362306a36Sopenharmony_ci } 7462306a36Sopenharmony_ci break; 7562306a36Sopenharmony_ci default: 7662306a36Sopenharmony_ci break; 7762306a36Sopenharmony_ci } 7862306a36Sopenharmony_ci } 7962306a36Sopenharmony_ci for (i = 0; i < params->crypto.n_ciphers_pairwise; i++) { 8062306a36Sopenharmony_ci switch (params->crypto.ciphers_pairwise[i]) { 8162306a36Sopenharmony_ci case WLAN_CIPHER_SUITE_WEP40: 8262306a36Sopenharmony_ci case WLAN_CIPHER_SUITE_WEP104: 8362306a36Sopenharmony_ci break; 8462306a36Sopenharmony_ci case WLAN_CIPHER_SUITE_TKIP: 8562306a36Sopenharmony_ci if (params->crypto.wpa_versions & NL80211_WPA_VERSION_1) 8662306a36Sopenharmony_ci bss_config->wpa_cfg.pairwise_cipher_wpa |= 8762306a36Sopenharmony_ci CIPHER_TKIP; 8862306a36Sopenharmony_ci if (params->crypto.wpa_versions & NL80211_WPA_VERSION_2) 8962306a36Sopenharmony_ci bss_config->wpa_cfg.pairwise_cipher_wpa2 |= 9062306a36Sopenharmony_ci CIPHER_TKIP; 9162306a36Sopenharmony_ci break; 9262306a36Sopenharmony_ci case WLAN_CIPHER_SUITE_CCMP: 9362306a36Sopenharmony_ci if (params->crypto.wpa_versions & NL80211_WPA_VERSION_1) 9462306a36Sopenharmony_ci bss_config->wpa_cfg.pairwise_cipher_wpa |= 9562306a36Sopenharmony_ci CIPHER_AES_CCMP; 9662306a36Sopenharmony_ci if (params->crypto.wpa_versions & NL80211_WPA_VERSION_2) 9762306a36Sopenharmony_ci bss_config->wpa_cfg.pairwise_cipher_wpa2 |= 9862306a36Sopenharmony_ci CIPHER_AES_CCMP; 9962306a36Sopenharmony_ci break; 10062306a36Sopenharmony_ci default: 10162306a36Sopenharmony_ci break; 10262306a36Sopenharmony_ci } 10362306a36Sopenharmony_ci } 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci switch (params->crypto.cipher_group) { 10662306a36Sopenharmony_ci case WLAN_CIPHER_SUITE_WEP40: 10762306a36Sopenharmony_ci case WLAN_CIPHER_SUITE_WEP104: 10862306a36Sopenharmony_ci if (priv->sec_info.wep_enabled) { 10962306a36Sopenharmony_ci bss_config->protocol = PROTOCOL_STATIC_WEP; 11062306a36Sopenharmony_ci bss_config->key_mgmt = KEY_MGMT_NONE; 11162306a36Sopenharmony_ci bss_config->wpa_cfg.length = 0; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci for (i = 0; i < NUM_WEP_KEYS; i++) { 11462306a36Sopenharmony_ci wep_key = priv->wep_key[i]; 11562306a36Sopenharmony_ci bss_config->wep_cfg[i].key_index = i; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci if (priv->wep_key_curr_index == i) 11862306a36Sopenharmony_ci bss_config->wep_cfg[i].is_default = 1; 11962306a36Sopenharmony_ci else 12062306a36Sopenharmony_ci bss_config->wep_cfg[i].is_default = 0; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci bss_config->wep_cfg[i].length = 12362306a36Sopenharmony_ci wep_key.key_length; 12462306a36Sopenharmony_ci memcpy(&bss_config->wep_cfg[i].key, 12562306a36Sopenharmony_ci &wep_key.key_material, 12662306a36Sopenharmony_ci wep_key.key_length); 12762306a36Sopenharmony_ci } 12862306a36Sopenharmony_ci } 12962306a36Sopenharmony_ci break; 13062306a36Sopenharmony_ci case WLAN_CIPHER_SUITE_TKIP: 13162306a36Sopenharmony_ci bss_config->wpa_cfg.group_cipher = CIPHER_TKIP; 13262306a36Sopenharmony_ci break; 13362306a36Sopenharmony_ci case WLAN_CIPHER_SUITE_CCMP: 13462306a36Sopenharmony_ci bss_config->wpa_cfg.group_cipher = CIPHER_AES_CCMP; 13562306a36Sopenharmony_ci break; 13662306a36Sopenharmony_ci default: 13762306a36Sopenharmony_ci break; 13862306a36Sopenharmony_ci } 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci return 0; 14162306a36Sopenharmony_ci} 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci/* This function updates 11n related parameters from IE and sets them into 14462306a36Sopenharmony_ci * bss_config structure. 14562306a36Sopenharmony_ci */ 14662306a36Sopenharmony_civoid 14762306a36Sopenharmony_cimwifiex_set_ht_params(struct mwifiex_private *priv, 14862306a36Sopenharmony_ci struct mwifiex_uap_bss_param *bss_cfg, 14962306a36Sopenharmony_ci struct cfg80211_ap_settings *params) 15062306a36Sopenharmony_ci{ 15162306a36Sopenharmony_ci const u8 *ht_ie; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci if (!ISSUPP_11NENABLED(priv->adapter->fw_cap_info)) 15462306a36Sopenharmony_ci return; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci ht_ie = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, params->beacon.tail, 15762306a36Sopenharmony_ci params->beacon.tail_len); 15862306a36Sopenharmony_ci if (ht_ie) { 15962306a36Sopenharmony_ci memcpy(&bss_cfg->ht_cap, ht_ie + 2, 16062306a36Sopenharmony_ci sizeof(struct ieee80211_ht_cap)); 16162306a36Sopenharmony_ci priv->ap_11n_enabled = 1; 16262306a36Sopenharmony_ci } else { 16362306a36Sopenharmony_ci memset(&bss_cfg->ht_cap, 0, sizeof(struct ieee80211_ht_cap)); 16462306a36Sopenharmony_ci bss_cfg->ht_cap.cap_info = cpu_to_le16(MWIFIEX_DEF_HT_CAP); 16562306a36Sopenharmony_ci bss_cfg->ht_cap.ampdu_params_info = MWIFIEX_DEF_AMPDU; 16662306a36Sopenharmony_ci } 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci return; 16962306a36Sopenharmony_ci} 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci/* This function updates 11ac related parameters from IE 17262306a36Sopenharmony_ci * and sets them into bss_config structure. 17362306a36Sopenharmony_ci */ 17462306a36Sopenharmony_civoid mwifiex_set_vht_params(struct mwifiex_private *priv, 17562306a36Sopenharmony_ci struct mwifiex_uap_bss_param *bss_cfg, 17662306a36Sopenharmony_ci struct cfg80211_ap_settings *params) 17762306a36Sopenharmony_ci{ 17862306a36Sopenharmony_ci const u8 *vht_ie; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci vht_ie = cfg80211_find_ie(WLAN_EID_VHT_CAPABILITY, params->beacon.tail, 18162306a36Sopenharmony_ci params->beacon.tail_len); 18262306a36Sopenharmony_ci if (vht_ie) { 18362306a36Sopenharmony_ci memcpy(&bss_cfg->vht_cap, vht_ie + 2, 18462306a36Sopenharmony_ci sizeof(struct ieee80211_vht_cap)); 18562306a36Sopenharmony_ci priv->ap_11ac_enabled = 1; 18662306a36Sopenharmony_ci } else { 18762306a36Sopenharmony_ci priv->ap_11ac_enabled = 0; 18862306a36Sopenharmony_ci } 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci return; 19162306a36Sopenharmony_ci} 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci/* This function updates 11ac related parameters from IE 19462306a36Sopenharmony_ci * and sets them into bss_config structure. 19562306a36Sopenharmony_ci */ 19662306a36Sopenharmony_civoid mwifiex_set_tpc_params(struct mwifiex_private *priv, 19762306a36Sopenharmony_ci struct mwifiex_uap_bss_param *bss_cfg, 19862306a36Sopenharmony_ci struct cfg80211_ap_settings *params) 19962306a36Sopenharmony_ci{ 20062306a36Sopenharmony_ci const u8 *tpc_ie; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci tpc_ie = cfg80211_find_ie(WLAN_EID_TPC_REQUEST, params->beacon.tail, 20362306a36Sopenharmony_ci params->beacon.tail_len); 20462306a36Sopenharmony_ci if (tpc_ie) 20562306a36Sopenharmony_ci bss_cfg->power_constraint = *(tpc_ie + 2); 20662306a36Sopenharmony_ci else 20762306a36Sopenharmony_ci bss_cfg->power_constraint = 0; 20862306a36Sopenharmony_ci} 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci/* Enable VHT only when cfg80211_ap_settings has VHT IE. 21162306a36Sopenharmony_ci * Otherwise disable VHT. 21262306a36Sopenharmony_ci */ 21362306a36Sopenharmony_civoid mwifiex_set_vht_width(struct mwifiex_private *priv, 21462306a36Sopenharmony_ci enum nl80211_chan_width width, 21562306a36Sopenharmony_ci bool ap_11ac_enable) 21662306a36Sopenharmony_ci{ 21762306a36Sopenharmony_ci struct mwifiex_adapter *adapter = priv->adapter; 21862306a36Sopenharmony_ci struct mwifiex_11ac_vht_cfg vht_cfg; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci vht_cfg.band_config = VHT_CFG_5GHZ; 22162306a36Sopenharmony_ci vht_cfg.cap_info = adapter->hw_dot_11ac_dev_cap; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci if (!ap_11ac_enable) { 22462306a36Sopenharmony_ci vht_cfg.mcs_tx_set = DISABLE_VHT_MCS_SET; 22562306a36Sopenharmony_ci vht_cfg.mcs_rx_set = DISABLE_VHT_MCS_SET; 22662306a36Sopenharmony_ci } else { 22762306a36Sopenharmony_ci vht_cfg.mcs_tx_set = DEFAULT_VHT_MCS_SET; 22862306a36Sopenharmony_ci vht_cfg.mcs_rx_set = DEFAULT_VHT_MCS_SET; 22962306a36Sopenharmony_ci } 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci vht_cfg.misc_config = VHT_CAP_UAP_ONLY; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci if (ap_11ac_enable && width >= NL80211_CHAN_WIDTH_80) 23462306a36Sopenharmony_ci vht_cfg.misc_config |= VHT_BW_80_160_80P80; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci mwifiex_send_cmd(priv, HostCmd_CMD_11AC_CFG, 23762306a36Sopenharmony_ci HostCmd_ACT_GEN_SET, 0, &vht_cfg, true); 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci return; 24062306a36Sopenharmony_ci} 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci/* This function finds supported rates IE from beacon parameter and sets 24362306a36Sopenharmony_ci * these rates into bss_config structure. 24462306a36Sopenharmony_ci */ 24562306a36Sopenharmony_civoid 24662306a36Sopenharmony_cimwifiex_set_uap_rates(struct mwifiex_uap_bss_param *bss_cfg, 24762306a36Sopenharmony_ci struct cfg80211_ap_settings *params) 24862306a36Sopenharmony_ci{ 24962306a36Sopenharmony_ci struct ieee_types_header *rate_ie; 25062306a36Sopenharmony_ci int var_offset = offsetof(struct ieee80211_mgmt, u.beacon.variable); 25162306a36Sopenharmony_ci const u8 *var_pos = params->beacon.head + var_offset; 25262306a36Sopenharmony_ci int len = params->beacon.head_len - var_offset; 25362306a36Sopenharmony_ci u8 rate_len = 0; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci rate_ie = (void *)cfg80211_find_ie(WLAN_EID_SUPP_RATES, var_pos, len); 25662306a36Sopenharmony_ci if (rate_ie) { 25762306a36Sopenharmony_ci if (rate_ie->len > MWIFIEX_SUPPORTED_RATES) 25862306a36Sopenharmony_ci return; 25962306a36Sopenharmony_ci memcpy(bss_cfg->rates, rate_ie + 1, rate_ie->len); 26062306a36Sopenharmony_ci rate_len = rate_ie->len; 26162306a36Sopenharmony_ci } 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci rate_ie = (void *)cfg80211_find_ie(WLAN_EID_EXT_SUPP_RATES, 26462306a36Sopenharmony_ci params->beacon.tail, 26562306a36Sopenharmony_ci params->beacon.tail_len); 26662306a36Sopenharmony_ci if (rate_ie) { 26762306a36Sopenharmony_ci if (rate_ie->len > MWIFIEX_SUPPORTED_RATES - rate_len) 26862306a36Sopenharmony_ci return; 26962306a36Sopenharmony_ci memcpy(bss_cfg->rates + rate_len, rate_ie + 1, rate_ie->len); 27062306a36Sopenharmony_ci } 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci return; 27362306a36Sopenharmony_ci} 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci/* This function initializes some of mwifiex_uap_bss_param variables. 27662306a36Sopenharmony_ci * This helps FW in ignoring invalid values. These values may or may not 27762306a36Sopenharmony_ci * be get updated to valid ones at later stage. 27862306a36Sopenharmony_ci */ 27962306a36Sopenharmony_civoid mwifiex_set_sys_config_invalid_data(struct mwifiex_uap_bss_param *config) 28062306a36Sopenharmony_ci{ 28162306a36Sopenharmony_ci config->bcast_ssid_ctl = 0x7F; 28262306a36Sopenharmony_ci config->radio_ctl = 0x7F; 28362306a36Sopenharmony_ci config->dtim_period = 0x7F; 28462306a36Sopenharmony_ci config->beacon_period = 0x7FFF; 28562306a36Sopenharmony_ci config->auth_mode = 0x7F; 28662306a36Sopenharmony_ci config->rts_threshold = 0x7FFF; 28762306a36Sopenharmony_ci config->frag_threshold = 0x7FFF; 28862306a36Sopenharmony_ci config->retry_limit = 0x7F; 28962306a36Sopenharmony_ci config->qos_info = 0xFF; 29062306a36Sopenharmony_ci} 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci/* This function parses BSS related parameters from structure 29362306a36Sopenharmony_ci * and prepares TLVs specific to WPA/WPA2 security. 29462306a36Sopenharmony_ci * These TLVs are appended to command buffer. 29562306a36Sopenharmony_ci */ 29662306a36Sopenharmony_cistatic void 29762306a36Sopenharmony_cimwifiex_uap_bss_wpa(u8 **tlv_buf, void *cmd_buf, u16 *param_size) 29862306a36Sopenharmony_ci{ 29962306a36Sopenharmony_ci struct host_cmd_tlv_pwk_cipher *pwk_cipher; 30062306a36Sopenharmony_ci struct host_cmd_tlv_gwk_cipher *gwk_cipher; 30162306a36Sopenharmony_ci struct host_cmd_tlv_passphrase *passphrase; 30262306a36Sopenharmony_ci struct host_cmd_tlv_akmp *tlv_akmp; 30362306a36Sopenharmony_ci struct mwifiex_uap_bss_param *bss_cfg = cmd_buf; 30462306a36Sopenharmony_ci u16 cmd_size = *param_size; 30562306a36Sopenharmony_ci u8 *tlv = *tlv_buf; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci tlv_akmp = (struct host_cmd_tlv_akmp *)tlv; 30862306a36Sopenharmony_ci tlv_akmp->header.type = cpu_to_le16(TLV_TYPE_UAP_AKMP); 30962306a36Sopenharmony_ci tlv_akmp->header.len = cpu_to_le16(sizeof(struct host_cmd_tlv_akmp) - 31062306a36Sopenharmony_ci sizeof(struct mwifiex_ie_types_header)); 31162306a36Sopenharmony_ci tlv_akmp->key_mgmt_operation = cpu_to_le16(bss_cfg->key_mgmt_operation); 31262306a36Sopenharmony_ci tlv_akmp->key_mgmt = cpu_to_le16(bss_cfg->key_mgmt); 31362306a36Sopenharmony_ci cmd_size += sizeof(struct host_cmd_tlv_akmp); 31462306a36Sopenharmony_ci tlv += sizeof(struct host_cmd_tlv_akmp); 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci if (bss_cfg->wpa_cfg.pairwise_cipher_wpa & VALID_CIPHER_BITMAP) { 31762306a36Sopenharmony_ci pwk_cipher = (struct host_cmd_tlv_pwk_cipher *)tlv; 31862306a36Sopenharmony_ci pwk_cipher->header.type = cpu_to_le16(TLV_TYPE_PWK_CIPHER); 31962306a36Sopenharmony_ci pwk_cipher->header.len = 32062306a36Sopenharmony_ci cpu_to_le16(sizeof(struct host_cmd_tlv_pwk_cipher) - 32162306a36Sopenharmony_ci sizeof(struct mwifiex_ie_types_header)); 32262306a36Sopenharmony_ci pwk_cipher->proto = cpu_to_le16(PROTOCOL_WPA); 32362306a36Sopenharmony_ci pwk_cipher->cipher = bss_cfg->wpa_cfg.pairwise_cipher_wpa; 32462306a36Sopenharmony_ci cmd_size += sizeof(struct host_cmd_tlv_pwk_cipher); 32562306a36Sopenharmony_ci tlv += sizeof(struct host_cmd_tlv_pwk_cipher); 32662306a36Sopenharmony_ci } 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci if (bss_cfg->wpa_cfg.pairwise_cipher_wpa2 & VALID_CIPHER_BITMAP) { 32962306a36Sopenharmony_ci pwk_cipher = (struct host_cmd_tlv_pwk_cipher *)tlv; 33062306a36Sopenharmony_ci pwk_cipher->header.type = cpu_to_le16(TLV_TYPE_PWK_CIPHER); 33162306a36Sopenharmony_ci pwk_cipher->header.len = 33262306a36Sopenharmony_ci cpu_to_le16(sizeof(struct host_cmd_tlv_pwk_cipher) - 33362306a36Sopenharmony_ci sizeof(struct mwifiex_ie_types_header)); 33462306a36Sopenharmony_ci pwk_cipher->proto = cpu_to_le16(PROTOCOL_WPA2); 33562306a36Sopenharmony_ci pwk_cipher->cipher = bss_cfg->wpa_cfg.pairwise_cipher_wpa2; 33662306a36Sopenharmony_ci cmd_size += sizeof(struct host_cmd_tlv_pwk_cipher); 33762306a36Sopenharmony_ci tlv += sizeof(struct host_cmd_tlv_pwk_cipher); 33862306a36Sopenharmony_ci } 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci if (bss_cfg->wpa_cfg.group_cipher & VALID_CIPHER_BITMAP) { 34162306a36Sopenharmony_ci gwk_cipher = (struct host_cmd_tlv_gwk_cipher *)tlv; 34262306a36Sopenharmony_ci gwk_cipher->header.type = cpu_to_le16(TLV_TYPE_GWK_CIPHER); 34362306a36Sopenharmony_ci gwk_cipher->header.len = 34462306a36Sopenharmony_ci cpu_to_le16(sizeof(struct host_cmd_tlv_gwk_cipher) - 34562306a36Sopenharmony_ci sizeof(struct mwifiex_ie_types_header)); 34662306a36Sopenharmony_ci gwk_cipher->cipher = bss_cfg->wpa_cfg.group_cipher; 34762306a36Sopenharmony_ci cmd_size += sizeof(struct host_cmd_tlv_gwk_cipher); 34862306a36Sopenharmony_ci tlv += sizeof(struct host_cmd_tlv_gwk_cipher); 34962306a36Sopenharmony_ci } 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci if (bss_cfg->wpa_cfg.length) { 35262306a36Sopenharmony_ci passphrase = (struct host_cmd_tlv_passphrase *)tlv; 35362306a36Sopenharmony_ci passphrase->header.type = 35462306a36Sopenharmony_ci cpu_to_le16(TLV_TYPE_UAP_WPA_PASSPHRASE); 35562306a36Sopenharmony_ci passphrase->header.len = cpu_to_le16(bss_cfg->wpa_cfg.length); 35662306a36Sopenharmony_ci memcpy(passphrase->passphrase, bss_cfg->wpa_cfg.passphrase, 35762306a36Sopenharmony_ci bss_cfg->wpa_cfg.length); 35862306a36Sopenharmony_ci cmd_size += sizeof(struct mwifiex_ie_types_header) + 35962306a36Sopenharmony_ci bss_cfg->wpa_cfg.length; 36062306a36Sopenharmony_ci tlv += sizeof(struct mwifiex_ie_types_header) + 36162306a36Sopenharmony_ci bss_cfg->wpa_cfg.length; 36262306a36Sopenharmony_ci } 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci *param_size = cmd_size; 36562306a36Sopenharmony_ci *tlv_buf = tlv; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci return; 36862306a36Sopenharmony_ci} 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci/* This function parses WMM related parameters from cfg80211_ap_settings 37162306a36Sopenharmony_ci * structure and updates bss_config structure. 37262306a36Sopenharmony_ci */ 37362306a36Sopenharmony_civoid 37462306a36Sopenharmony_cimwifiex_set_wmm_params(struct mwifiex_private *priv, 37562306a36Sopenharmony_ci struct mwifiex_uap_bss_param *bss_cfg, 37662306a36Sopenharmony_ci struct cfg80211_ap_settings *params) 37762306a36Sopenharmony_ci{ 37862306a36Sopenharmony_ci const u8 *vendor_ie; 37962306a36Sopenharmony_ci const u8 *wmm_ie; 38062306a36Sopenharmony_ci static const u8 wmm_oui[] = {0x00, 0x50, 0xf2, 0x02}; 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci vendor_ie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT, 38362306a36Sopenharmony_ci WLAN_OUI_TYPE_MICROSOFT_WMM, 38462306a36Sopenharmony_ci params->beacon.tail, 38562306a36Sopenharmony_ci params->beacon.tail_len); 38662306a36Sopenharmony_ci if (vendor_ie) { 38762306a36Sopenharmony_ci wmm_ie = vendor_ie; 38862306a36Sopenharmony_ci if (*(wmm_ie + 1) > sizeof(struct mwifiex_types_wmm_info)) 38962306a36Sopenharmony_ci return; 39062306a36Sopenharmony_ci memcpy(&bss_cfg->wmm_info, wmm_ie + 39162306a36Sopenharmony_ci sizeof(struct ieee_types_header), *(wmm_ie + 1)); 39262306a36Sopenharmony_ci priv->wmm_enabled = 1; 39362306a36Sopenharmony_ci } else { 39462306a36Sopenharmony_ci memset(&bss_cfg->wmm_info, 0, sizeof(bss_cfg->wmm_info)); 39562306a36Sopenharmony_ci memcpy(&bss_cfg->wmm_info.oui, wmm_oui, sizeof(wmm_oui)); 39662306a36Sopenharmony_ci bss_cfg->wmm_info.subtype = MWIFIEX_WMM_SUBTYPE; 39762306a36Sopenharmony_ci bss_cfg->wmm_info.version = MWIFIEX_WMM_VERSION; 39862306a36Sopenharmony_ci priv->wmm_enabled = 0; 39962306a36Sopenharmony_ci } 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci bss_cfg->qos_info = 0x00; 40262306a36Sopenharmony_ci return; 40362306a36Sopenharmony_ci} 40462306a36Sopenharmony_ci/* This function parses BSS related parameters from structure 40562306a36Sopenharmony_ci * and prepares TLVs specific to WEP encryption. 40662306a36Sopenharmony_ci * These TLVs are appended to command buffer. 40762306a36Sopenharmony_ci */ 40862306a36Sopenharmony_cistatic void 40962306a36Sopenharmony_cimwifiex_uap_bss_wep(u8 **tlv_buf, void *cmd_buf, u16 *param_size) 41062306a36Sopenharmony_ci{ 41162306a36Sopenharmony_ci struct host_cmd_tlv_wep_key *wep_key; 41262306a36Sopenharmony_ci u16 cmd_size = *param_size; 41362306a36Sopenharmony_ci int i; 41462306a36Sopenharmony_ci u8 *tlv = *tlv_buf; 41562306a36Sopenharmony_ci struct mwifiex_uap_bss_param *bss_cfg = cmd_buf; 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci for (i = 0; i < NUM_WEP_KEYS; i++) { 41862306a36Sopenharmony_ci if (bss_cfg->wep_cfg[i].length && 41962306a36Sopenharmony_ci (bss_cfg->wep_cfg[i].length == WLAN_KEY_LEN_WEP40 || 42062306a36Sopenharmony_ci bss_cfg->wep_cfg[i].length == WLAN_KEY_LEN_WEP104)) { 42162306a36Sopenharmony_ci wep_key = (struct host_cmd_tlv_wep_key *)tlv; 42262306a36Sopenharmony_ci wep_key->header.type = 42362306a36Sopenharmony_ci cpu_to_le16(TLV_TYPE_UAP_WEP_KEY); 42462306a36Sopenharmony_ci wep_key->header.len = 42562306a36Sopenharmony_ci cpu_to_le16(bss_cfg->wep_cfg[i].length + 2); 42662306a36Sopenharmony_ci wep_key->key_index = bss_cfg->wep_cfg[i].key_index; 42762306a36Sopenharmony_ci wep_key->is_default = bss_cfg->wep_cfg[i].is_default; 42862306a36Sopenharmony_ci memcpy(wep_key->key, bss_cfg->wep_cfg[i].key, 42962306a36Sopenharmony_ci bss_cfg->wep_cfg[i].length); 43062306a36Sopenharmony_ci cmd_size += sizeof(struct mwifiex_ie_types_header) + 2 + 43162306a36Sopenharmony_ci bss_cfg->wep_cfg[i].length; 43262306a36Sopenharmony_ci tlv += sizeof(struct mwifiex_ie_types_header) + 2 + 43362306a36Sopenharmony_ci bss_cfg->wep_cfg[i].length; 43462306a36Sopenharmony_ci } 43562306a36Sopenharmony_ci } 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci *param_size = cmd_size; 43862306a36Sopenharmony_ci *tlv_buf = tlv; 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci return; 44162306a36Sopenharmony_ci} 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci/* This function enable 11D if userspace set the country IE. 44462306a36Sopenharmony_ci */ 44562306a36Sopenharmony_civoid mwifiex_config_uap_11d(struct mwifiex_private *priv, 44662306a36Sopenharmony_ci struct cfg80211_beacon_data *beacon_data) 44762306a36Sopenharmony_ci{ 44862306a36Sopenharmony_ci enum state_11d_t state_11d; 44962306a36Sopenharmony_ci const u8 *country_ie; 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci country_ie = cfg80211_find_ie(WLAN_EID_COUNTRY, beacon_data->tail, 45262306a36Sopenharmony_ci beacon_data->tail_len); 45362306a36Sopenharmony_ci if (country_ie) { 45462306a36Sopenharmony_ci /* Send cmd to FW to enable 11D function */ 45562306a36Sopenharmony_ci state_11d = ENABLE_11D; 45662306a36Sopenharmony_ci if (mwifiex_send_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB, 45762306a36Sopenharmony_ci HostCmd_ACT_GEN_SET, DOT11D_I, 45862306a36Sopenharmony_ci &state_11d, true)) { 45962306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 46062306a36Sopenharmony_ci "11D: failed to enable 11D\n"); 46162306a36Sopenharmony_ci } 46262306a36Sopenharmony_ci } 46362306a36Sopenharmony_ci} 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci/* This function parses BSS related parameters from structure 46662306a36Sopenharmony_ci * and prepares TLVs. These TLVs are appended to command buffer. 46762306a36Sopenharmony_ci*/ 46862306a36Sopenharmony_cistatic int 46962306a36Sopenharmony_cimwifiex_uap_bss_param_prepare(u8 *tlv, void *cmd_buf, u16 *param_size) 47062306a36Sopenharmony_ci{ 47162306a36Sopenharmony_ci struct host_cmd_tlv_mac_addr *mac_tlv; 47262306a36Sopenharmony_ci struct host_cmd_tlv_dtim_period *dtim_period; 47362306a36Sopenharmony_ci struct host_cmd_tlv_beacon_period *beacon_period; 47462306a36Sopenharmony_ci struct host_cmd_tlv_ssid *ssid; 47562306a36Sopenharmony_ci struct host_cmd_tlv_bcast_ssid *bcast_ssid; 47662306a36Sopenharmony_ci struct host_cmd_tlv_channel_band *chan_band; 47762306a36Sopenharmony_ci struct host_cmd_tlv_frag_threshold *frag_threshold; 47862306a36Sopenharmony_ci struct host_cmd_tlv_rts_threshold *rts_threshold; 47962306a36Sopenharmony_ci struct host_cmd_tlv_retry_limit *retry_limit; 48062306a36Sopenharmony_ci struct host_cmd_tlv_encrypt_protocol *encrypt_protocol; 48162306a36Sopenharmony_ci struct host_cmd_tlv_auth_type *auth_type; 48262306a36Sopenharmony_ci struct host_cmd_tlv_rates *tlv_rates; 48362306a36Sopenharmony_ci struct host_cmd_tlv_ageout_timer *ao_timer, *ps_ao_timer; 48462306a36Sopenharmony_ci struct host_cmd_tlv_power_constraint *pwr_ct; 48562306a36Sopenharmony_ci struct mwifiex_ie_types_htcap *htcap; 48662306a36Sopenharmony_ci struct mwifiex_ie_types_wmmcap *wmm_cap; 48762306a36Sopenharmony_ci struct mwifiex_uap_bss_param *bss_cfg = cmd_buf; 48862306a36Sopenharmony_ci int i; 48962306a36Sopenharmony_ci u16 cmd_size = *param_size; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci mac_tlv = (struct host_cmd_tlv_mac_addr *)tlv; 49262306a36Sopenharmony_ci mac_tlv->header.type = cpu_to_le16(TLV_TYPE_UAP_MAC_ADDRESS); 49362306a36Sopenharmony_ci mac_tlv->header.len = cpu_to_le16(ETH_ALEN); 49462306a36Sopenharmony_ci memcpy(mac_tlv->mac_addr, bss_cfg->mac_addr, ETH_ALEN); 49562306a36Sopenharmony_ci cmd_size += sizeof(struct host_cmd_tlv_mac_addr); 49662306a36Sopenharmony_ci tlv += sizeof(struct host_cmd_tlv_mac_addr); 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci if (bss_cfg->ssid.ssid_len) { 49962306a36Sopenharmony_ci ssid = (struct host_cmd_tlv_ssid *)tlv; 50062306a36Sopenharmony_ci ssid->header.type = cpu_to_le16(TLV_TYPE_UAP_SSID); 50162306a36Sopenharmony_ci ssid->header.len = cpu_to_le16((u16)bss_cfg->ssid.ssid_len); 50262306a36Sopenharmony_ci memcpy(ssid->ssid, bss_cfg->ssid.ssid, bss_cfg->ssid.ssid_len); 50362306a36Sopenharmony_ci cmd_size += sizeof(struct mwifiex_ie_types_header) + 50462306a36Sopenharmony_ci bss_cfg->ssid.ssid_len; 50562306a36Sopenharmony_ci tlv += sizeof(struct mwifiex_ie_types_header) + 50662306a36Sopenharmony_ci bss_cfg->ssid.ssid_len; 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci bcast_ssid = (struct host_cmd_tlv_bcast_ssid *)tlv; 50962306a36Sopenharmony_ci bcast_ssid->header.type = cpu_to_le16(TLV_TYPE_UAP_BCAST_SSID); 51062306a36Sopenharmony_ci bcast_ssid->header.len = 51162306a36Sopenharmony_ci cpu_to_le16(sizeof(bcast_ssid->bcast_ctl)); 51262306a36Sopenharmony_ci bcast_ssid->bcast_ctl = bss_cfg->bcast_ssid_ctl; 51362306a36Sopenharmony_ci cmd_size += sizeof(struct host_cmd_tlv_bcast_ssid); 51462306a36Sopenharmony_ci tlv += sizeof(struct host_cmd_tlv_bcast_ssid); 51562306a36Sopenharmony_ci } 51662306a36Sopenharmony_ci if (bss_cfg->rates[0]) { 51762306a36Sopenharmony_ci tlv_rates = (struct host_cmd_tlv_rates *)tlv; 51862306a36Sopenharmony_ci tlv_rates->header.type = cpu_to_le16(TLV_TYPE_UAP_RATES); 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci for (i = 0; i < MWIFIEX_SUPPORTED_RATES && bss_cfg->rates[i]; 52162306a36Sopenharmony_ci i++) 52262306a36Sopenharmony_ci tlv_rates->rates[i] = bss_cfg->rates[i]; 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci tlv_rates->header.len = cpu_to_le16(i); 52562306a36Sopenharmony_ci cmd_size += sizeof(struct host_cmd_tlv_rates) + i; 52662306a36Sopenharmony_ci tlv += sizeof(struct host_cmd_tlv_rates) + i; 52762306a36Sopenharmony_ci } 52862306a36Sopenharmony_ci if (bss_cfg->channel && 52962306a36Sopenharmony_ci (((bss_cfg->band_cfg & BIT(0)) == BAND_CONFIG_BG && 53062306a36Sopenharmony_ci bss_cfg->channel <= MAX_CHANNEL_BAND_BG) || 53162306a36Sopenharmony_ci ((bss_cfg->band_cfg & BIT(0)) == BAND_CONFIG_A && 53262306a36Sopenharmony_ci bss_cfg->channel <= MAX_CHANNEL_BAND_A))) { 53362306a36Sopenharmony_ci chan_band = (struct host_cmd_tlv_channel_band *)tlv; 53462306a36Sopenharmony_ci chan_band->header.type = cpu_to_le16(TLV_TYPE_CHANNELBANDLIST); 53562306a36Sopenharmony_ci chan_band->header.len = 53662306a36Sopenharmony_ci cpu_to_le16(sizeof(struct host_cmd_tlv_channel_band) - 53762306a36Sopenharmony_ci sizeof(struct mwifiex_ie_types_header)); 53862306a36Sopenharmony_ci chan_band->band_config = bss_cfg->band_cfg; 53962306a36Sopenharmony_ci chan_band->channel = bss_cfg->channel; 54062306a36Sopenharmony_ci cmd_size += sizeof(struct host_cmd_tlv_channel_band); 54162306a36Sopenharmony_ci tlv += sizeof(struct host_cmd_tlv_channel_band); 54262306a36Sopenharmony_ci } 54362306a36Sopenharmony_ci if (bss_cfg->beacon_period >= MIN_BEACON_PERIOD && 54462306a36Sopenharmony_ci bss_cfg->beacon_period <= MAX_BEACON_PERIOD) { 54562306a36Sopenharmony_ci beacon_period = (struct host_cmd_tlv_beacon_period *)tlv; 54662306a36Sopenharmony_ci beacon_period->header.type = 54762306a36Sopenharmony_ci cpu_to_le16(TLV_TYPE_UAP_BEACON_PERIOD); 54862306a36Sopenharmony_ci beacon_period->header.len = 54962306a36Sopenharmony_ci cpu_to_le16(sizeof(struct host_cmd_tlv_beacon_period) - 55062306a36Sopenharmony_ci sizeof(struct mwifiex_ie_types_header)); 55162306a36Sopenharmony_ci beacon_period->period = cpu_to_le16(bss_cfg->beacon_period); 55262306a36Sopenharmony_ci cmd_size += sizeof(struct host_cmd_tlv_beacon_period); 55362306a36Sopenharmony_ci tlv += sizeof(struct host_cmd_tlv_beacon_period); 55462306a36Sopenharmony_ci } 55562306a36Sopenharmony_ci if (bss_cfg->dtim_period >= MIN_DTIM_PERIOD && 55662306a36Sopenharmony_ci bss_cfg->dtim_period <= MAX_DTIM_PERIOD) { 55762306a36Sopenharmony_ci dtim_period = (struct host_cmd_tlv_dtim_period *)tlv; 55862306a36Sopenharmony_ci dtim_period->header.type = 55962306a36Sopenharmony_ci cpu_to_le16(TLV_TYPE_UAP_DTIM_PERIOD); 56062306a36Sopenharmony_ci dtim_period->header.len = 56162306a36Sopenharmony_ci cpu_to_le16(sizeof(struct host_cmd_tlv_dtim_period) - 56262306a36Sopenharmony_ci sizeof(struct mwifiex_ie_types_header)); 56362306a36Sopenharmony_ci dtim_period->period = bss_cfg->dtim_period; 56462306a36Sopenharmony_ci cmd_size += sizeof(struct host_cmd_tlv_dtim_period); 56562306a36Sopenharmony_ci tlv += sizeof(struct host_cmd_tlv_dtim_period); 56662306a36Sopenharmony_ci } 56762306a36Sopenharmony_ci if (bss_cfg->rts_threshold <= MWIFIEX_RTS_MAX_VALUE) { 56862306a36Sopenharmony_ci rts_threshold = (struct host_cmd_tlv_rts_threshold *)tlv; 56962306a36Sopenharmony_ci rts_threshold->header.type = 57062306a36Sopenharmony_ci cpu_to_le16(TLV_TYPE_UAP_RTS_THRESHOLD); 57162306a36Sopenharmony_ci rts_threshold->header.len = 57262306a36Sopenharmony_ci cpu_to_le16(sizeof(struct host_cmd_tlv_rts_threshold) - 57362306a36Sopenharmony_ci sizeof(struct mwifiex_ie_types_header)); 57462306a36Sopenharmony_ci rts_threshold->rts_thr = cpu_to_le16(bss_cfg->rts_threshold); 57562306a36Sopenharmony_ci cmd_size += sizeof(struct host_cmd_tlv_frag_threshold); 57662306a36Sopenharmony_ci tlv += sizeof(struct host_cmd_tlv_frag_threshold); 57762306a36Sopenharmony_ci } 57862306a36Sopenharmony_ci if ((bss_cfg->frag_threshold >= MWIFIEX_FRAG_MIN_VALUE) && 57962306a36Sopenharmony_ci (bss_cfg->frag_threshold <= MWIFIEX_FRAG_MAX_VALUE)) { 58062306a36Sopenharmony_ci frag_threshold = (struct host_cmd_tlv_frag_threshold *)tlv; 58162306a36Sopenharmony_ci frag_threshold->header.type = 58262306a36Sopenharmony_ci cpu_to_le16(TLV_TYPE_UAP_FRAG_THRESHOLD); 58362306a36Sopenharmony_ci frag_threshold->header.len = 58462306a36Sopenharmony_ci cpu_to_le16(sizeof(struct host_cmd_tlv_frag_threshold) - 58562306a36Sopenharmony_ci sizeof(struct mwifiex_ie_types_header)); 58662306a36Sopenharmony_ci frag_threshold->frag_thr = cpu_to_le16(bss_cfg->frag_threshold); 58762306a36Sopenharmony_ci cmd_size += sizeof(struct host_cmd_tlv_frag_threshold); 58862306a36Sopenharmony_ci tlv += sizeof(struct host_cmd_tlv_frag_threshold); 58962306a36Sopenharmony_ci } 59062306a36Sopenharmony_ci if (bss_cfg->retry_limit <= MWIFIEX_RETRY_LIMIT) { 59162306a36Sopenharmony_ci retry_limit = (struct host_cmd_tlv_retry_limit *)tlv; 59262306a36Sopenharmony_ci retry_limit->header.type = 59362306a36Sopenharmony_ci cpu_to_le16(TLV_TYPE_UAP_RETRY_LIMIT); 59462306a36Sopenharmony_ci retry_limit->header.len = 59562306a36Sopenharmony_ci cpu_to_le16(sizeof(struct host_cmd_tlv_retry_limit) - 59662306a36Sopenharmony_ci sizeof(struct mwifiex_ie_types_header)); 59762306a36Sopenharmony_ci retry_limit->limit = (u8)bss_cfg->retry_limit; 59862306a36Sopenharmony_ci cmd_size += sizeof(struct host_cmd_tlv_retry_limit); 59962306a36Sopenharmony_ci tlv += sizeof(struct host_cmd_tlv_retry_limit); 60062306a36Sopenharmony_ci } 60162306a36Sopenharmony_ci if ((bss_cfg->protocol & PROTOCOL_WPA) || 60262306a36Sopenharmony_ci (bss_cfg->protocol & PROTOCOL_WPA2) || 60362306a36Sopenharmony_ci (bss_cfg->protocol & PROTOCOL_EAP)) 60462306a36Sopenharmony_ci mwifiex_uap_bss_wpa(&tlv, cmd_buf, &cmd_size); 60562306a36Sopenharmony_ci else 60662306a36Sopenharmony_ci mwifiex_uap_bss_wep(&tlv, cmd_buf, &cmd_size); 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci if ((bss_cfg->auth_mode <= WLAN_AUTH_SHARED_KEY) || 60962306a36Sopenharmony_ci (bss_cfg->auth_mode == MWIFIEX_AUTH_MODE_AUTO)) { 61062306a36Sopenharmony_ci auth_type = (struct host_cmd_tlv_auth_type *)tlv; 61162306a36Sopenharmony_ci auth_type->header.type = cpu_to_le16(TLV_TYPE_AUTH_TYPE); 61262306a36Sopenharmony_ci auth_type->header.len = 61362306a36Sopenharmony_ci cpu_to_le16(sizeof(struct host_cmd_tlv_auth_type) - 61462306a36Sopenharmony_ci sizeof(struct mwifiex_ie_types_header)); 61562306a36Sopenharmony_ci auth_type->auth_type = (u8)bss_cfg->auth_mode; 61662306a36Sopenharmony_ci cmd_size += sizeof(struct host_cmd_tlv_auth_type); 61762306a36Sopenharmony_ci tlv += sizeof(struct host_cmd_tlv_auth_type); 61862306a36Sopenharmony_ci } 61962306a36Sopenharmony_ci if (bss_cfg->protocol) { 62062306a36Sopenharmony_ci encrypt_protocol = (struct host_cmd_tlv_encrypt_protocol *)tlv; 62162306a36Sopenharmony_ci encrypt_protocol->header.type = 62262306a36Sopenharmony_ci cpu_to_le16(TLV_TYPE_UAP_ENCRY_PROTOCOL); 62362306a36Sopenharmony_ci encrypt_protocol->header.len = 62462306a36Sopenharmony_ci cpu_to_le16(sizeof(struct host_cmd_tlv_encrypt_protocol) 62562306a36Sopenharmony_ci - sizeof(struct mwifiex_ie_types_header)); 62662306a36Sopenharmony_ci encrypt_protocol->proto = cpu_to_le16(bss_cfg->protocol); 62762306a36Sopenharmony_ci cmd_size += sizeof(struct host_cmd_tlv_encrypt_protocol); 62862306a36Sopenharmony_ci tlv += sizeof(struct host_cmd_tlv_encrypt_protocol); 62962306a36Sopenharmony_ci } 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci if (bss_cfg->ht_cap.cap_info) { 63262306a36Sopenharmony_ci htcap = (struct mwifiex_ie_types_htcap *)tlv; 63362306a36Sopenharmony_ci htcap->header.type = cpu_to_le16(WLAN_EID_HT_CAPABILITY); 63462306a36Sopenharmony_ci htcap->header.len = 63562306a36Sopenharmony_ci cpu_to_le16(sizeof(struct ieee80211_ht_cap)); 63662306a36Sopenharmony_ci htcap->ht_cap.cap_info = bss_cfg->ht_cap.cap_info; 63762306a36Sopenharmony_ci htcap->ht_cap.ampdu_params_info = 63862306a36Sopenharmony_ci bss_cfg->ht_cap.ampdu_params_info; 63962306a36Sopenharmony_ci memcpy(&htcap->ht_cap.mcs, &bss_cfg->ht_cap.mcs, 64062306a36Sopenharmony_ci sizeof(struct ieee80211_mcs_info)); 64162306a36Sopenharmony_ci htcap->ht_cap.extended_ht_cap_info = 64262306a36Sopenharmony_ci bss_cfg->ht_cap.extended_ht_cap_info; 64362306a36Sopenharmony_ci htcap->ht_cap.tx_BF_cap_info = bss_cfg->ht_cap.tx_BF_cap_info; 64462306a36Sopenharmony_ci htcap->ht_cap.antenna_selection_info = 64562306a36Sopenharmony_ci bss_cfg->ht_cap.antenna_selection_info; 64662306a36Sopenharmony_ci cmd_size += sizeof(struct mwifiex_ie_types_htcap); 64762306a36Sopenharmony_ci tlv += sizeof(struct mwifiex_ie_types_htcap); 64862306a36Sopenharmony_ci } 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci if (bss_cfg->wmm_info.qos_info != 0xFF) { 65162306a36Sopenharmony_ci wmm_cap = (struct mwifiex_ie_types_wmmcap *)tlv; 65262306a36Sopenharmony_ci wmm_cap->header.type = cpu_to_le16(WLAN_EID_VENDOR_SPECIFIC); 65362306a36Sopenharmony_ci wmm_cap->header.len = cpu_to_le16(sizeof(wmm_cap->wmm_info)); 65462306a36Sopenharmony_ci memcpy(&wmm_cap->wmm_info, &bss_cfg->wmm_info, 65562306a36Sopenharmony_ci sizeof(wmm_cap->wmm_info)); 65662306a36Sopenharmony_ci cmd_size += sizeof(struct mwifiex_ie_types_wmmcap); 65762306a36Sopenharmony_ci tlv += sizeof(struct mwifiex_ie_types_wmmcap); 65862306a36Sopenharmony_ci } 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci if (bss_cfg->sta_ao_timer) { 66162306a36Sopenharmony_ci ao_timer = (struct host_cmd_tlv_ageout_timer *)tlv; 66262306a36Sopenharmony_ci ao_timer->header.type = cpu_to_le16(TLV_TYPE_UAP_AO_TIMER); 66362306a36Sopenharmony_ci ao_timer->header.len = cpu_to_le16(sizeof(*ao_timer) - 66462306a36Sopenharmony_ci sizeof(struct mwifiex_ie_types_header)); 66562306a36Sopenharmony_ci ao_timer->sta_ao_timer = cpu_to_le32(bss_cfg->sta_ao_timer); 66662306a36Sopenharmony_ci cmd_size += sizeof(*ao_timer); 66762306a36Sopenharmony_ci tlv += sizeof(*ao_timer); 66862306a36Sopenharmony_ci } 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci if (bss_cfg->power_constraint) { 67162306a36Sopenharmony_ci pwr_ct = (void *)tlv; 67262306a36Sopenharmony_ci pwr_ct->header.type = cpu_to_le16(TLV_TYPE_PWR_CONSTRAINT); 67362306a36Sopenharmony_ci pwr_ct->header.len = cpu_to_le16(sizeof(u8)); 67462306a36Sopenharmony_ci pwr_ct->constraint = bss_cfg->power_constraint; 67562306a36Sopenharmony_ci cmd_size += sizeof(*pwr_ct); 67662306a36Sopenharmony_ci tlv += sizeof(*pwr_ct); 67762306a36Sopenharmony_ci } 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci if (bss_cfg->ps_sta_ao_timer) { 68062306a36Sopenharmony_ci ps_ao_timer = (struct host_cmd_tlv_ageout_timer *)tlv; 68162306a36Sopenharmony_ci ps_ao_timer->header.type = 68262306a36Sopenharmony_ci cpu_to_le16(TLV_TYPE_UAP_PS_AO_TIMER); 68362306a36Sopenharmony_ci ps_ao_timer->header.len = cpu_to_le16(sizeof(*ps_ao_timer) - 68462306a36Sopenharmony_ci sizeof(struct mwifiex_ie_types_header)); 68562306a36Sopenharmony_ci ps_ao_timer->sta_ao_timer = 68662306a36Sopenharmony_ci cpu_to_le32(bss_cfg->ps_sta_ao_timer); 68762306a36Sopenharmony_ci cmd_size += sizeof(*ps_ao_timer); 68862306a36Sopenharmony_ci tlv += sizeof(*ps_ao_timer); 68962306a36Sopenharmony_ci } 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci *param_size = cmd_size; 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci return 0; 69462306a36Sopenharmony_ci} 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci/* This function parses custom IEs from IE list and prepares command buffer */ 69762306a36Sopenharmony_cistatic int mwifiex_uap_custom_ie_prepare(u8 *tlv, void *cmd_buf, u16 *ie_size) 69862306a36Sopenharmony_ci{ 69962306a36Sopenharmony_ci struct mwifiex_ie_list *ap_ie = cmd_buf; 70062306a36Sopenharmony_ci struct mwifiex_ie_types_header *tlv_ie = (void *)tlv; 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci if (!ap_ie || !ap_ie->len) 70362306a36Sopenharmony_ci return -1; 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci *ie_size += le16_to_cpu(ap_ie->len) + 70662306a36Sopenharmony_ci sizeof(struct mwifiex_ie_types_header); 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci tlv_ie->type = cpu_to_le16(TLV_TYPE_MGMT_IE); 70962306a36Sopenharmony_ci tlv_ie->len = ap_ie->len; 71062306a36Sopenharmony_ci tlv += sizeof(struct mwifiex_ie_types_header); 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci memcpy(tlv, ap_ie->ie_list, le16_to_cpu(ap_ie->len)); 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci return 0; 71562306a36Sopenharmony_ci} 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci/* Parse AP config structure and prepare TLV based command structure 71862306a36Sopenharmony_ci * to be sent to FW for uAP configuration 71962306a36Sopenharmony_ci */ 72062306a36Sopenharmony_cistatic int 72162306a36Sopenharmony_cimwifiex_cmd_uap_sys_config(struct host_cmd_ds_command *cmd, u16 cmd_action, 72262306a36Sopenharmony_ci u32 type, void *cmd_buf) 72362306a36Sopenharmony_ci{ 72462306a36Sopenharmony_ci u8 *tlv; 72562306a36Sopenharmony_ci u16 cmd_size, param_size, ie_size; 72662306a36Sopenharmony_ci struct host_cmd_ds_sys_config *sys_cfg; 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci cmd->command = cpu_to_le16(HostCmd_CMD_UAP_SYS_CONFIG); 72962306a36Sopenharmony_ci cmd_size = (u16)(sizeof(struct host_cmd_ds_sys_config) + S_DS_GEN); 73062306a36Sopenharmony_ci sys_cfg = (struct host_cmd_ds_sys_config *)&cmd->params.uap_sys_config; 73162306a36Sopenharmony_ci sys_cfg->action = cpu_to_le16(cmd_action); 73262306a36Sopenharmony_ci tlv = sys_cfg->tlv; 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci switch (type) { 73562306a36Sopenharmony_ci case UAP_BSS_PARAMS_I: 73662306a36Sopenharmony_ci param_size = cmd_size; 73762306a36Sopenharmony_ci if (mwifiex_uap_bss_param_prepare(tlv, cmd_buf, ¶m_size)) 73862306a36Sopenharmony_ci return -1; 73962306a36Sopenharmony_ci cmd->size = cpu_to_le16(param_size); 74062306a36Sopenharmony_ci break; 74162306a36Sopenharmony_ci case UAP_CUSTOM_IE_I: 74262306a36Sopenharmony_ci ie_size = cmd_size; 74362306a36Sopenharmony_ci if (mwifiex_uap_custom_ie_prepare(tlv, cmd_buf, &ie_size)) 74462306a36Sopenharmony_ci return -1; 74562306a36Sopenharmony_ci cmd->size = cpu_to_le16(ie_size); 74662306a36Sopenharmony_ci break; 74762306a36Sopenharmony_ci default: 74862306a36Sopenharmony_ci return -1; 74962306a36Sopenharmony_ci } 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci return 0; 75262306a36Sopenharmony_ci} 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci/* This function prepares AP specific deauth command with mac supplied in 75562306a36Sopenharmony_ci * function parameter. 75662306a36Sopenharmony_ci */ 75762306a36Sopenharmony_cistatic int mwifiex_cmd_uap_sta_deauth(struct mwifiex_private *priv, 75862306a36Sopenharmony_ci struct host_cmd_ds_command *cmd, u8 *mac) 75962306a36Sopenharmony_ci{ 76062306a36Sopenharmony_ci struct host_cmd_ds_sta_deauth *sta_deauth = &cmd->params.sta_deauth; 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci cmd->command = cpu_to_le16(HostCmd_CMD_UAP_STA_DEAUTH); 76362306a36Sopenharmony_ci memcpy(sta_deauth->mac, mac, ETH_ALEN); 76462306a36Sopenharmony_ci sta_deauth->reason = cpu_to_le16(WLAN_REASON_DEAUTH_LEAVING); 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_sta_deauth) + 76762306a36Sopenharmony_ci S_DS_GEN); 76862306a36Sopenharmony_ci return 0; 76962306a36Sopenharmony_ci} 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci/* This function prepares the AP specific commands before sending them 77262306a36Sopenharmony_ci * to the firmware. 77362306a36Sopenharmony_ci * This is a generic function which calls specific command preparation 77462306a36Sopenharmony_ci * routines based upon the command number. 77562306a36Sopenharmony_ci */ 77662306a36Sopenharmony_ciint mwifiex_uap_prepare_cmd(struct mwifiex_private *priv, u16 cmd_no, 77762306a36Sopenharmony_ci u16 cmd_action, u32 type, 77862306a36Sopenharmony_ci void *data_buf, void *cmd_buf) 77962306a36Sopenharmony_ci{ 78062306a36Sopenharmony_ci struct host_cmd_ds_command *cmd = cmd_buf; 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci switch (cmd_no) { 78362306a36Sopenharmony_ci case HostCmd_CMD_UAP_SYS_CONFIG: 78462306a36Sopenharmony_ci if (mwifiex_cmd_uap_sys_config(cmd, cmd_action, type, data_buf)) 78562306a36Sopenharmony_ci return -1; 78662306a36Sopenharmony_ci break; 78762306a36Sopenharmony_ci case HostCmd_CMD_UAP_BSS_START: 78862306a36Sopenharmony_ci case HostCmd_CMD_UAP_BSS_STOP: 78962306a36Sopenharmony_ci case HOST_CMD_APCMD_SYS_RESET: 79062306a36Sopenharmony_ci case HOST_CMD_APCMD_STA_LIST: 79162306a36Sopenharmony_ci cmd->command = cpu_to_le16(cmd_no); 79262306a36Sopenharmony_ci cmd->size = cpu_to_le16(S_DS_GEN); 79362306a36Sopenharmony_ci break; 79462306a36Sopenharmony_ci case HostCmd_CMD_UAP_STA_DEAUTH: 79562306a36Sopenharmony_ci if (mwifiex_cmd_uap_sta_deauth(priv, cmd, data_buf)) 79662306a36Sopenharmony_ci return -1; 79762306a36Sopenharmony_ci break; 79862306a36Sopenharmony_ci case HostCmd_CMD_CHAN_REPORT_REQUEST: 79962306a36Sopenharmony_ci if (mwifiex_cmd_issue_chan_report_request(priv, cmd_buf, 80062306a36Sopenharmony_ci data_buf)) 80162306a36Sopenharmony_ci return -1; 80262306a36Sopenharmony_ci break; 80362306a36Sopenharmony_ci default: 80462306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 80562306a36Sopenharmony_ci "PREP_CMD: unknown cmd %#x\n", cmd_no); 80662306a36Sopenharmony_ci return -1; 80762306a36Sopenharmony_ci } 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci return 0; 81062306a36Sopenharmony_ci} 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_civoid mwifiex_uap_set_channel(struct mwifiex_private *priv, 81362306a36Sopenharmony_ci struct mwifiex_uap_bss_param *bss_cfg, 81462306a36Sopenharmony_ci struct cfg80211_chan_def chandef) 81562306a36Sopenharmony_ci{ 81662306a36Sopenharmony_ci u8 config_bands = 0, old_bands = priv->adapter->config_bands; 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci priv->bss_chandef = chandef; 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci bss_cfg->channel = ieee80211_frequency_to_channel( 82162306a36Sopenharmony_ci chandef.chan->center_freq); 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci /* Set appropriate bands */ 82462306a36Sopenharmony_ci if (chandef.chan->band == NL80211_BAND_2GHZ) { 82562306a36Sopenharmony_ci bss_cfg->band_cfg = BAND_CONFIG_BG; 82662306a36Sopenharmony_ci config_bands = BAND_B | BAND_G; 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci if (chandef.width > NL80211_CHAN_WIDTH_20_NOHT) 82962306a36Sopenharmony_ci config_bands |= BAND_GN; 83062306a36Sopenharmony_ci } else { 83162306a36Sopenharmony_ci bss_cfg->band_cfg = BAND_CONFIG_A; 83262306a36Sopenharmony_ci config_bands = BAND_A; 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci if (chandef.width > NL80211_CHAN_WIDTH_20_NOHT) 83562306a36Sopenharmony_ci config_bands |= BAND_AN; 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci if (chandef.width > NL80211_CHAN_WIDTH_40) 83862306a36Sopenharmony_ci config_bands |= BAND_AAC; 83962306a36Sopenharmony_ci } 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci switch (chandef.width) { 84262306a36Sopenharmony_ci case NL80211_CHAN_WIDTH_5: 84362306a36Sopenharmony_ci case NL80211_CHAN_WIDTH_10: 84462306a36Sopenharmony_ci case NL80211_CHAN_WIDTH_20_NOHT: 84562306a36Sopenharmony_ci case NL80211_CHAN_WIDTH_20: 84662306a36Sopenharmony_ci break; 84762306a36Sopenharmony_ci case NL80211_CHAN_WIDTH_40: 84862306a36Sopenharmony_ci if (chandef.center_freq1 < chandef.chan->center_freq) 84962306a36Sopenharmony_ci bss_cfg->band_cfg |= MWIFIEX_SEC_CHAN_BELOW; 85062306a36Sopenharmony_ci else 85162306a36Sopenharmony_ci bss_cfg->band_cfg |= MWIFIEX_SEC_CHAN_ABOVE; 85262306a36Sopenharmony_ci break; 85362306a36Sopenharmony_ci case NL80211_CHAN_WIDTH_80: 85462306a36Sopenharmony_ci case NL80211_CHAN_WIDTH_80P80: 85562306a36Sopenharmony_ci case NL80211_CHAN_WIDTH_160: 85662306a36Sopenharmony_ci bss_cfg->band_cfg |= 85762306a36Sopenharmony_ci mwifiex_get_sec_chan_offset(bss_cfg->channel) << 4; 85862306a36Sopenharmony_ci break; 85962306a36Sopenharmony_ci default: 86062306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, 86162306a36Sopenharmony_ci WARN, "Unknown channel width: %d\n", 86262306a36Sopenharmony_ci chandef.width); 86362306a36Sopenharmony_ci break; 86462306a36Sopenharmony_ci } 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci priv->adapter->config_bands = config_bands; 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci if (old_bands != config_bands) { 86962306a36Sopenharmony_ci mwifiex_send_domain_info_cmd_fw(priv->adapter->wiphy); 87062306a36Sopenharmony_ci mwifiex_dnld_txpwr_table(priv); 87162306a36Sopenharmony_ci } 87262306a36Sopenharmony_ci} 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ciint mwifiex_config_start_uap(struct mwifiex_private *priv, 87562306a36Sopenharmony_ci struct mwifiex_uap_bss_param *bss_cfg) 87662306a36Sopenharmony_ci{ 87762306a36Sopenharmony_ci if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_SYS_CONFIG, 87862306a36Sopenharmony_ci HostCmd_ACT_GEN_SET, 87962306a36Sopenharmony_ci UAP_BSS_PARAMS_I, bss_cfg, true)) { 88062306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 88162306a36Sopenharmony_ci "Failed to set AP configuration\n"); 88262306a36Sopenharmony_ci return -1; 88362306a36Sopenharmony_ci } 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_START, 88662306a36Sopenharmony_ci HostCmd_ACT_GEN_SET, 0, NULL, true)) { 88762306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 88862306a36Sopenharmony_ci "Failed to start the BSS\n"); 88962306a36Sopenharmony_ci return -1; 89062306a36Sopenharmony_ci } 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci if (priv->sec_info.wep_enabled) 89362306a36Sopenharmony_ci priv->curr_pkt_filter |= HostCmd_ACT_MAC_WEP_ENABLE; 89462306a36Sopenharmony_ci else 89562306a36Sopenharmony_ci priv->curr_pkt_filter &= ~HostCmd_ACT_MAC_WEP_ENABLE; 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci if (mwifiex_send_cmd(priv, HostCmd_CMD_MAC_CONTROL, 89862306a36Sopenharmony_ci HostCmd_ACT_GEN_SET, 0, 89962306a36Sopenharmony_ci &priv->curr_pkt_filter, true)) 90062306a36Sopenharmony_ci return -1; 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci return 0; 90362306a36Sopenharmony_ci} 904