cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

uap_cmd.c (29366B)


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