File Index
Files and directories
Sign in
FILE

uap_cmd.c

File preview with syntax highlighting.

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