brintos

brintos / linux-shallow public Read only

0
0
Text · 39.2 KiB · d3cba68 Raw
1498 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * NXP Wireless LAN device driver: functions for station ioctl4 *5 * Copyright 2011-2020 NXP6 */7 8#include "decl.h"9#include "ioctl.h"10#include "util.h"11#include "fw.h"12#include "main.h"13#include "wmm.h"14#include "11n.h"15#include "cfg80211.h"16 17static int disconnect_on_suspend;18module_param(disconnect_on_suspend, int, 0644);19 20/*21 * Copies the multicast address list from device to driver.22 *23 * This function does not validate the destination memory for24 * size, and the calling function must ensure enough memory is25 * available.26 */27int mwifiex_copy_mcast_addr(struct mwifiex_multicast_list *mlist,28			    struct net_device *dev)29{30	int i = 0;31	struct netdev_hw_addr *ha;32 33	netdev_for_each_mc_addr(ha, dev)34		memcpy(&mlist->mac_list[i++], ha->addr, ETH_ALEN);35 36	return i;37}38 39/*40 * Wait queue completion handler.41 *42 * This function waits on a cmd wait queue. It also cancels the pending43 * request after waking up, in case of errors.44 */45int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter,46				struct cmd_ctrl_node *cmd_queued)47{48	int status;49 50	/* Wait for completion */51	status = wait_event_interruptible_timeout(adapter->cmd_wait_q.wait,52						  *(cmd_queued->condition),53						  (12 * HZ));54	if (status <= 0) {55		if (status == 0)56			status = -ETIMEDOUT;57		mwifiex_dbg(adapter, ERROR, "cmd_wait_q terminated: %d\n",58			    status);59		mwifiex_cancel_all_pending_cmd(adapter);60		return status;61	}62 63	status = adapter->cmd_wait_q.status;64	adapter->cmd_wait_q.status = 0;65 66	return status;67}68 69/*70 * This function prepares the correct firmware command and71 * issues it to set the multicast list.72 *73 * This function can be used to enable promiscuous mode, or enable all74 * multicast packets, or to enable selective multicast.75 */76int mwifiex_request_set_multicast_list(struct mwifiex_private *priv,77				struct mwifiex_multicast_list *mcast_list)78{79	int ret = 0;80	u16 old_pkt_filter;81 82	old_pkt_filter = priv->curr_pkt_filter;83 84	if (mcast_list->mode == MWIFIEX_PROMISC_MODE) {85		mwifiex_dbg(priv->adapter, INFO,86			    "info: Enable Promiscuous mode\n");87		priv->curr_pkt_filter |= HostCmd_ACT_MAC_PROMISCUOUS_ENABLE;88		priv->curr_pkt_filter &=89			~HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE;90	} else {91		/* Multicast */92		priv->curr_pkt_filter &= ~HostCmd_ACT_MAC_PROMISCUOUS_ENABLE;93		if (mcast_list->mode == MWIFIEX_ALL_MULTI_MODE) {94			mwifiex_dbg(priv->adapter, INFO,95				    "info: Enabling All Multicast!\n");96			priv->curr_pkt_filter |=97				HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE;98		} else {99			priv->curr_pkt_filter &=100				~HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE;101			mwifiex_dbg(priv->adapter, INFO,102				    "info: Set multicast list=%d\n",103				    mcast_list->num_multicast_addr);104			/* Send multicast addresses to firmware */105			ret = mwifiex_send_cmd(priv,106					       HostCmd_CMD_MAC_MULTICAST_ADR,107					       HostCmd_ACT_GEN_SET, 0,108					       mcast_list, false);109		}110	}111	mwifiex_dbg(priv->adapter, INFO,112		    "info: old_pkt_filter=%#x, curr_pkt_filter=%#x\n",113		    old_pkt_filter, priv->curr_pkt_filter);114	if (old_pkt_filter != priv->curr_pkt_filter) {115		ret = mwifiex_send_cmd(priv, HostCmd_CMD_MAC_CONTROL,116				       HostCmd_ACT_GEN_SET,117				       0, &priv->curr_pkt_filter, false);118	}119 120	return ret;121}122 123/*124 * This function fills bss descriptor structure using provided125 * information.126 * beacon_ie buffer is allocated in this function. It is caller's127 * responsibility to free the memory.128 */129int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv,130			      struct cfg80211_bss *bss,131			      struct mwifiex_bssdescriptor *bss_desc)132{133	u8 *beacon_ie;134	size_t beacon_ie_len;135	struct mwifiex_bss_priv *bss_priv = (void *)bss->priv;136	const struct cfg80211_bss_ies *ies;137 138	rcu_read_lock();139	ies = rcu_dereference(bss->ies);140	beacon_ie = kmemdup(ies->data, ies->len, GFP_ATOMIC);141	beacon_ie_len = ies->len;142	bss_desc->timestamp = ies->tsf;143	rcu_read_unlock();144 145	if (!beacon_ie) {146		mwifiex_dbg(priv->adapter, ERROR,147			    " failed to alloc beacon_ie\n");148		return -ENOMEM;149	}150 151	memcpy(bss_desc->mac_address, bss->bssid, ETH_ALEN);152	bss_desc->rssi = bss->signal;153	/* The caller of this function will free beacon_ie */154	bss_desc->beacon_buf = beacon_ie;155	bss_desc->beacon_buf_size = beacon_ie_len;156	bss_desc->beacon_period = bss->beacon_interval;157	bss_desc->cap_info_bitmap = bss->capability;158	bss_desc->bss_band = bss_priv->band;159	bss_desc->fw_tsf = bss_priv->fw_tsf;160	if (bss_desc->cap_info_bitmap & WLAN_CAPABILITY_PRIVACY) {161		mwifiex_dbg(priv->adapter, INFO,162			    "info: InterpretIE: AP WEP enabled\n");163		bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_8021X_WEP;164	} else {165		bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_ACCEPT_ALL;166	}167	if (bss_desc->cap_info_bitmap & WLAN_CAPABILITY_IBSS)168		bss_desc->bss_mode = NL80211_IFTYPE_ADHOC;169	else170		bss_desc->bss_mode = NL80211_IFTYPE_STATION;171 172	/* Disable 11ac by default. Enable it only where there173	 * exist VHT_CAP IE in AP beacon174	 */175	bss_desc->disable_11ac = true;176 177	if (bss_desc->cap_info_bitmap & WLAN_CAPABILITY_SPECTRUM_MGMT)178		bss_desc->sensed_11h = true;179 180	return mwifiex_update_bss_desc_with_ie(priv->adapter, bss_desc);181}182 183void mwifiex_dnld_txpwr_table(struct mwifiex_private *priv)184{185	if (priv->adapter->dt_node) {186		char txpwr[] = {"marvell,00_txpwrlimit"};187 188		memcpy(&txpwr[8], priv->adapter->country_code, 2);189		mwifiex_dnld_dt_cfgdata(priv, priv->adapter->dt_node, txpwr);190	}191}192 193static int mwifiex_process_country_ie(struct mwifiex_private *priv,194				      struct cfg80211_bss *bss)195{196	const u8 *country_ie;197	u8 country_ie_len;198	struct mwifiex_802_11d_domain_reg *domain_info =199					&priv->adapter->domain_reg;200 201	rcu_read_lock();202	country_ie = ieee80211_bss_get_ie(bss, WLAN_EID_COUNTRY);203	if (!country_ie) {204		rcu_read_unlock();205		return 0;206	}207 208	country_ie_len = country_ie[1];209	if (country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN) {210		rcu_read_unlock();211		return 0;212	}213 214	if (!strncmp(priv->adapter->country_code, &country_ie[2], 2)) {215		rcu_read_unlock();216		mwifiex_dbg(priv->adapter, INFO,217			    "11D: skip setting domain info in FW\n");218		return 0;219	}220 221	if (country_ie_len >222	    (IEEE80211_COUNTRY_STRING_LEN + MWIFIEX_MAX_TRIPLET_802_11D)) {223		rcu_read_unlock();224		mwifiex_dbg(priv->adapter, ERROR,225			    "11D: country_ie_len overflow!, deauth AP\n");226		return -EINVAL;227	}228 229	memcpy(priv->adapter->country_code, &country_ie[2], 2);230 231	domain_info->country_code[0] = country_ie[2];232	domain_info->country_code[1] = country_ie[3];233	domain_info->country_code[2] = ' ';234 235	country_ie_len -= IEEE80211_COUNTRY_STRING_LEN;236 237	domain_info->no_of_triplet =238		country_ie_len / sizeof(struct ieee80211_country_ie_triplet);239 240	memcpy((u8 *)domain_info->triplet,241	       &country_ie[2] + IEEE80211_COUNTRY_STRING_LEN, country_ie_len);242 243	rcu_read_unlock();244 245	if (mwifiex_send_cmd(priv, HostCmd_CMD_802_11D_DOMAIN_INFO,246			     HostCmd_ACT_GEN_SET, 0, NULL, false)) {247		mwifiex_dbg(priv->adapter, ERROR,248			    "11D: setting domain info in FW fail\n");249		return -1;250	}251 252	mwifiex_dnld_txpwr_table(priv);253 254	return 0;255}256 257/*258 * In Ad-Hoc mode, the IBSS is created if not found in scan list.259 * In both Ad-Hoc and infra mode, an deauthentication is performed260 * first.261 */262int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss,263		      struct cfg80211_ssid *req_ssid)264{265	int ret;266	struct mwifiex_adapter *adapter = priv->adapter;267	struct mwifiex_bssdescriptor *bss_desc = NULL;268 269	priv->scan_block = false;270 271	if (bss) {272		if (adapter->region_code == 0x00 &&273		    mwifiex_process_country_ie(priv, bss))274			return -EINVAL;275 276		/* Allocate and fill new bss descriptor */277		bss_desc = kzalloc(sizeof(struct mwifiex_bssdescriptor),278				   GFP_KERNEL);279		if (!bss_desc)280			return -ENOMEM;281 282		ret = mwifiex_fill_new_bss_desc(priv, bss, bss_desc);283		if (ret)284			goto done;285	}286 287	if (priv->bss_mode == NL80211_IFTYPE_STATION ||288	    priv->bss_mode == NL80211_IFTYPE_P2P_CLIENT) {289		u8 config_bands;290 291		if (!bss_desc)292			return -1;293 294		if (mwifiex_band_to_radio_type(bss_desc->bss_band) ==295						HostCmd_SCAN_RADIO_TYPE_BG) {296			config_bands = BAND_B | BAND_G | BAND_GN;297		} else {298			config_bands = BAND_A | BAND_AN;299			if (adapter->fw_bands & BAND_AAC)300				config_bands |= BAND_AAC;301		}302 303		if (!((config_bands | adapter->fw_bands) & ~adapter->fw_bands))304			adapter->config_bands = config_bands;305 306		ret = mwifiex_check_network_compatibility(priv, bss_desc);307		if (ret)308			goto done;309 310		if (mwifiex_11h_get_csa_closed_channel(priv) ==311							(u8)bss_desc->channel) {312			mwifiex_dbg(adapter, ERROR,313				    "Attempt to reconnect on csa closed chan(%d)\n",314				    bss_desc->channel);315			ret = -1;316			goto done;317		}318 319		mwifiex_dbg(adapter, INFO,320			    "info: SSID found in scan list ...\t"321			    "associating...\n");322 323		mwifiex_stop_net_dev_queue(priv->netdev, adapter);324		if (netif_carrier_ok(priv->netdev))325			netif_carrier_off(priv->netdev);326 327		/* Clear any past association response stored for328		 * application retrieval */329		priv->assoc_rsp_size = 0;330		ret = mwifiex_associate(priv, bss_desc);331 332		/* If auth type is auto and association fails using open mode,333		 * try to connect using shared mode */334		if (ret == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG &&335		    priv->sec_info.is_authtype_auto &&336		    priv->sec_info.wep_enabled) {337			priv->sec_info.authentication_mode =338						NL80211_AUTHTYPE_SHARED_KEY;339			ret = mwifiex_associate(priv, bss_desc);340		}341 342		if (bss && !priv->adapter->host_mlme_enabled)343			cfg80211_put_bss(priv->adapter->wiphy, bss);344	} else {345		/* Adhoc mode */346		/* If the requested SSID matches current SSID, return */347		if (bss_desc && bss_desc->ssid.ssid_len &&348		    cfg80211_ssid_eq(&priv->curr_bss_params.bss_descriptor.ssid,349				     &bss_desc->ssid)) {350			ret = 0;351			goto done;352		}353 354		priv->adhoc_is_link_sensed = false;355 356		ret = mwifiex_check_network_compatibility(priv, bss_desc);357 358		mwifiex_stop_net_dev_queue(priv->netdev, adapter);359		if (netif_carrier_ok(priv->netdev))360			netif_carrier_off(priv->netdev);361 362		if (!ret) {363			mwifiex_dbg(adapter, INFO,364				    "info: network found in scan\t"365				    " list. Joining...\n");366			ret = mwifiex_adhoc_join(priv, bss_desc);367			if (bss)368				cfg80211_put_bss(priv->adapter->wiphy, bss);369		} else {370			mwifiex_dbg(adapter, INFO,371				    "info: Network not found in\t"372				    "the list, creating adhoc with ssid = %s\n",373				    req_ssid->ssid);374			ret = mwifiex_adhoc_start(priv, req_ssid);375		}376	}377 378done:379	/* beacon_ie buffer was allocated in function380	 * mwifiex_fill_new_bss_desc(). Free it now.381	 */382	if (bss_desc)383		kfree(bss_desc->beacon_buf);384	kfree(bss_desc);385 386	if (ret < 0)387		priv->attempted_bss_desc = NULL;388 389	return ret;390}391 392/*393 * IOCTL request handler to set host sleep configuration.394 *395 * This function prepares the correct firmware command and396 * issues it.397 */398int mwifiex_set_hs_params(struct mwifiex_private *priv, u16 action,399			  int cmd_type, struct mwifiex_ds_hs_cfg *hs_cfg)400 401{402	struct mwifiex_adapter *adapter = priv->adapter;403	int status = 0;404	u32 prev_cond = 0;405 406	if (!hs_cfg)407		return -ENOMEM;408 409	switch (action) {410	case HostCmd_ACT_GEN_SET:411		if (adapter->pps_uapsd_mode) {412			mwifiex_dbg(adapter, INFO,413				    "info: Host Sleep IOCTL\t"414				    "is blocked in UAPSD/PPS mode\n");415			status = -1;416			break;417		}418		if (hs_cfg->is_invoke_hostcmd) {419			if (hs_cfg->conditions == HS_CFG_CANCEL) {420				if (!test_bit(MWIFIEX_IS_HS_CONFIGURED,421					      &adapter->work_flags))422					/* Already cancelled */423					break;424				/* Save previous condition */425				prev_cond = le32_to_cpu(adapter->hs_cfg426							.conditions);427				adapter->hs_cfg.conditions =428						cpu_to_le32(hs_cfg->conditions);429			} else if (hs_cfg->conditions) {430				adapter->hs_cfg.conditions =431						cpu_to_le32(hs_cfg->conditions);432				adapter->hs_cfg.gpio = (u8)hs_cfg->gpio;433				if (hs_cfg->gap)434					adapter->hs_cfg.gap = (u8)hs_cfg->gap;435			} else if (adapter->hs_cfg.conditions ==436				   cpu_to_le32(HS_CFG_CANCEL)) {437				/* Return failure if no parameters for HS438				   enable */439				status = -1;440				break;441			}442 443			status = mwifiex_send_cmd(priv,444						  HostCmd_CMD_802_11_HS_CFG_ENH,445						  HostCmd_ACT_GEN_SET, 0,446						  &adapter->hs_cfg,447						  cmd_type == MWIFIEX_SYNC_CMD);448 449			if (hs_cfg->conditions == HS_CFG_CANCEL)450				/* Restore previous condition */451				adapter->hs_cfg.conditions =452						cpu_to_le32(prev_cond);453		} else {454			adapter->hs_cfg.conditions =455						cpu_to_le32(hs_cfg->conditions);456			adapter->hs_cfg.gpio = (u8)hs_cfg->gpio;457			adapter->hs_cfg.gap = (u8)hs_cfg->gap;458		}459		break;460	case HostCmd_ACT_GEN_GET:461		hs_cfg->conditions = le32_to_cpu(adapter->hs_cfg.conditions);462		hs_cfg->gpio = adapter->hs_cfg.gpio;463		hs_cfg->gap = adapter->hs_cfg.gap;464		break;465	default:466		status = -1;467		break;468	}469 470	return status;471}472 473/*474 * Sends IOCTL request to cancel the existing Host Sleep configuration.475 *476 * This function allocates the IOCTL request buffer, fills it477 * with requisite parameters and calls the IOCTL handler.478 */479int mwifiex_cancel_hs(struct mwifiex_private *priv, int cmd_type)480{481	struct mwifiex_ds_hs_cfg hscfg;482 483	hscfg.conditions = HS_CFG_CANCEL;484	hscfg.is_invoke_hostcmd = true;485 486	return mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_SET,487				    cmd_type, &hscfg);488}489EXPORT_SYMBOL_GPL(mwifiex_cancel_hs);490 491/*492 * Sends IOCTL request to cancel the existing Host Sleep configuration.493 *494 * This function allocates the IOCTL request buffer, fills it495 * with requisite parameters and calls the IOCTL handler.496 */497int mwifiex_enable_hs(struct mwifiex_adapter *adapter)498{499	struct mwifiex_ds_hs_cfg hscfg;500	struct mwifiex_private *priv;501	int i;502 503	if (disconnect_on_suspend) {504		for (i = 0; i < adapter->priv_num; i++) {505			priv = adapter->priv[i];506			mwifiex_deauthenticate(priv, NULL);507		}508	}509 510	priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA);511 512	if (priv && priv->sched_scanning) {513#ifdef CONFIG_PM514		if (priv->wdev.wiphy->wowlan_config &&515		    !priv->wdev.wiphy->wowlan_config->nd_config) {516#endif517			mwifiex_dbg(adapter, CMD, "aborting bgscan!\n");518			mwifiex_stop_bg_scan(priv);519			cfg80211_sched_scan_stopped(priv->wdev.wiphy, 0);520#ifdef CONFIG_PM521		}522#endif523	}524 525	if (adapter->hs_activated) {526		mwifiex_dbg(adapter, CMD,527			    "cmd: HS Already activated\n");528		return true;529	}530 531	adapter->hs_activate_wait_q_woken = false;532 533	memset(&hscfg, 0, sizeof(hscfg));534	hscfg.is_invoke_hostcmd = true;535 536	set_bit(MWIFIEX_IS_HS_ENABLING, &adapter->work_flags);537	mwifiex_cancel_all_pending_cmd(adapter);538 539	if (mwifiex_set_hs_params(mwifiex_get_priv(adapter,540						   MWIFIEX_BSS_ROLE_STA),541				  HostCmd_ACT_GEN_SET, MWIFIEX_SYNC_CMD,542				  &hscfg)) {543		mwifiex_dbg(adapter, ERROR,544			    "IOCTL request HS enable failed\n");545		return false;546	}547 548	if (wait_event_interruptible_timeout(adapter->hs_activate_wait_q,549					     adapter->hs_activate_wait_q_woken,550					     (10 * HZ)) <= 0) {551		mwifiex_dbg(adapter, ERROR,552			    "hs_activate_wait_q terminated\n");553		return false;554	}555 556	return true;557}558EXPORT_SYMBOL_GPL(mwifiex_enable_hs);559 560/*561 * IOCTL request handler to get BSS information.562 *563 * This function collates the information from different driver structures564 * to send to the user.565 */566int mwifiex_get_bss_info(struct mwifiex_private *priv,567			 struct mwifiex_bss_info *info)568{569	struct mwifiex_adapter *adapter = priv->adapter;570	struct mwifiex_bssdescriptor *bss_desc;571 572	if (!info)573		return -1;574 575	bss_desc = &priv->curr_bss_params.bss_descriptor;576 577	info->bss_mode = priv->bss_mode;578 579	memcpy(&info->ssid, &bss_desc->ssid, sizeof(struct cfg80211_ssid));580 581	memcpy(&info->bssid, &bss_desc->mac_address, ETH_ALEN);582 583	info->bss_chan = bss_desc->channel;584 585	memcpy(info->country_code, adapter->country_code,586	       IEEE80211_COUNTRY_STRING_LEN);587 588	info->media_connected = priv->media_connected;589 590	info->max_power_level = priv->max_tx_power_level;591	info->min_power_level = priv->min_tx_power_level;592 593	info->adhoc_state = priv->adhoc_state;594 595	info->bcn_nf_last = priv->bcn_nf_last;596 597	if (priv->sec_info.wep_enabled)598		info->wep_status = true;599	else600		info->wep_status = false;601 602	info->is_hs_configured = test_bit(MWIFIEX_IS_HS_CONFIGURED,603					  &adapter->work_flags);604	info->is_deep_sleep = adapter->is_deep_sleep;605 606	return 0;607}608 609/*610 * The function disables auto deep sleep mode.611 */612int mwifiex_disable_auto_ds(struct mwifiex_private *priv)613{614	struct mwifiex_ds_auto_ds auto_ds = {615		.auto_ds = DEEP_SLEEP_OFF,616	};617 618	return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_PS_MODE_ENH,619				DIS_AUTO_PS, BITMAP_AUTO_DS, &auto_ds, true);620}621EXPORT_SYMBOL_GPL(mwifiex_disable_auto_ds);622 623/*624 * Sends IOCTL request to get the data rate.625 *626 * This function allocates the IOCTL request buffer, fills it627 * with requisite parameters and calls the IOCTL handler.628 */629int mwifiex_drv_get_data_rate(struct mwifiex_private *priv, u32 *rate)630{631	int ret;632 633	ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_TX_RATE_QUERY,634			       HostCmd_ACT_GEN_GET, 0, NULL, true);635 636	if (!ret) {637		if (priv->is_data_rate_auto)638			*rate = mwifiex_index_to_data_rate(priv, priv->tx_rate,639							   priv->tx_htinfo);640		else641			*rate = priv->data_rate;642	}643 644	return ret;645}646 647/*648 * IOCTL request handler to set tx power configuration.649 *650 * This function prepares the correct firmware command and651 * issues it.652 *653 * For non-auto power mode, all the following power groups are set -654 *      - Modulation class HR/DSSS655 *      - Modulation class OFDM656 *      - Modulation class HTBW20657 *      - Modulation class HTBW40658 */659int mwifiex_set_tx_power(struct mwifiex_private *priv,660			 struct mwifiex_power_cfg *power_cfg)661{662	int ret;663	struct host_cmd_ds_txpwr_cfg *txp_cfg;664	struct mwifiex_types_power_group *pg_tlv;665	struct mwifiex_power_group *pg;666	u8 *buf;667	u16 dbm = 0;668 669	if (!power_cfg->is_power_auto) {670		dbm = (u16) power_cfg->power_level;671		if ((dbm < priv->min_tx_power_level) ||672		    (dbm > priv->max_tx_power_level)) {673			mwifiex_dbg(priv->adapter, ERROR,674				    "txpower value %d dBm\t"675				    "is out of range (%d dBm-%d dBm)\n",676				    dbm, priv->min_tx_power_level,677				    priv->max_tx_power_level);678			return -1;679		}680	}681	buf = kzalloc(MWIFIEX_SIZE_OF_CMD_BUFFER, GFP_KERNEL);682	if (!buf)683		return -ENOMEM;684 685	txp_cfg = (struct host_cmd_ds_txpwr_cfg *) buf;686	txp_cfg->action = cpu_to_le16(HostCmd_ACT_GEN_SET);687	if (!power_cfg->is_power_auto) {688		u16 dbm_min = power_cfg->is_power_fixed ?689			      dbm : priv->min_tx_power_level;690 691		txp_cfg->mode = cpu_to_le32(1);692		pg_tlv = (struct mwifiex_types_power_group *)693			 (buf + sizeof(struct host_cmd_ds_txpwr_cfg));694		pg_tlv->type = cpu_to_le16(TLV_TYPE_POWER_GROUP);695		pg_tlv->length =696			cpu_to_le16(4 * sizeof(struct mwifiex_power_group));697		pg = (struct mwifiex_power_group *)698		     (buf + sizeof(struct host_cmd_ds_txpwr_cfg)699		      + sizeof(struct mwifiex_types_power_group));700		/* Power group for modulation class HR/DSSS */701		pg->first_rate_code = 0x00;702		pg->last_rate_code = 0x03;703		pg->modulation_class = MOD_CLASS_HR_DSSS;704		pg->power_step = 0;705		pg->power_min = (s8) dbm_min;706		pg->power_max = (s8) dbm;707		pg++;708		/* Power group for modulation class OFDM */709		pg->first_rate_code = 0x00;710		pg->last_rate_code = 0x07;711		pg->modulation_class = MOD_CLASS_OFDM;712		pg->power_step = 0;713		pg->power_min = (s8) dbm_min;714		pg->power_max = (s8) dbm;715		pg++;716		/* Power group for modulation class HTBW20 */717		pg->first_rate_code = 0x00;718		pg->last_rate_code = 0x20;719		pg->modulation_class = MOD_CLASS_HT;720		pg->power_step = 0;721		pg->power_min = (s8) dbm_min;722		pg->power_max = (s8) dbm;723		pg->ht_bandwidth = HT_BW_20;724		pg++;725		/* Power group for modulation class HTBW40 */726		pg->first_rate_code = 0x00;727		pg->last_rate_code = 0x20;728		pg->modulation_class = MOD_CLASS_HT;729		pg->power_step = 0;730		pg->power_min = (s8) dbm_min;731		pg->power_max = (s8) dbm;732		pg->ht_bandwidth = HT_BW_40;733	}734	ret = mwifiex_send_cmd(priv, HostCmd_CMD_TXPWR_CFG,735			       HostCmd_ACT_GEN_SET, 0, buf, true);736 737	kfree(buf);738	return ret;739}740 741/*742 * IOCTL request handler to get power save mode.743 *744 * This function prepares the correct firmware command and745 * issues it.746 */747int mwifiex_drv_set_power(struct mwifiex_private *priv, u32 *ps_mode)748{749	int ret;750	struct mwifiex_adapter *adapter = priv->adapter;751	u16 sub_cmd;752 753	if (*ps_mode)754		adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_PSP;755	else756		adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_CAM;757	sub_cmd = (*ps_mode) ? EN_AUTO_PS : DIS_AUTO_PS;758	ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_PS_MODE_ENH,759			       sub_cmd, BITMAP_STA_PS, NULL, true);760	if ((!ret) && (sub_cmd == DIS_AUTO_PS))761		ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_PS_MODE_ENH,762				       GET_PS, 0, NULL, false);763 764	return ret;765}766 767/*768 * IOCTL request handler to set/reset WPA IE.769 *770 * The supplied WPA IE is treated as a opaque buffer. Only the first field771 * is checked to determine WPA version. If buffer length is zero, the existing772 * WPA IE is reset.773 */774static int mwifiex_set_wpa_ie(struct mwifiex_private *priv,775			      u8 *ie_data_ptr, u16 ie_len)776{777	if (ie_len) {778		if (ie_len > sizeof(priv->wpa_ie)) {779			mwifiex_dbg(priv->adapter, ERROR,780				    "failed to copy WPA IE, too big\n");781			return -1;782		}783		memcpy(priv->wpa_ie, ie_data_ptr, ie_len);784		priv->wpa_ie_len = ie_len;785		mwifiex_dbg(priv->adapter, CMD,786			    "cmd: Set Wpa_ie_len=%d IE=%#x\n",787			    priv->wpa_ie_len, priv->wpa_ie[0]);788 789		if (priv->wpa_ie[0] == WLAN_EID_VENDOR_SPECIFIC) {790			priv->sec_info.wpa_enabled = true;791		} else if (priv->wpa_ie[0] == WLAN_EID_RSN) {792			priv->sec_info.wpa2_enabled = true;793		} else {794			priv->sec_info.wpa_enabled = false;795			priv->sec_info.wpa2_enabled = false;796		}797	} else {798		memset(priv->wpa_ie, 0, sizeof(priv->wpa_ie));799		priv->wpa_ie_len = 0;800		mwifiex_dbg(priv->adapter, INFO,801			    "info: reset wpa_ie_len=%d IE=%#x\n",802			    priv->wpa_ie_len, priv->wpa_ie[0]);803		priv->sec_info.wpa_enabled = false;804		priv->sec_info.wpa2_enabled = false;805	}806 807	return 0;808}809 810/*811 * IOCTL request handler to set/reset WAPI IE.812 *813 * The supplied WAPI IE is treated as a opaque buffer. Only the first field814 * is checked to internally enable WAPI. If buffer length is zero, the existing815 * WAPI IE is reset.816 */817static int mwifiex_set_wapi_ie(struct mwifiex_private *priv,818			       u8 *ie_data_ptr, u16 ie_len)819{820	if (ie_len) {821		if (ie_len > sizeof(priv->wapi_ie)) {822			mwifiex_dbg(priv->adapter, ERROR,823				    "info: failed to copy WAPI IE, too big\n");824			return -1;825		}826		memcpy(priv->wapi_ie, ie_data_ptr, ie_len);827		priv->wapi_ie_len = ie_len;828		mwifiex_dbg(priv->adapter, CMD,829			    "cmd: Set wapi_ie_len=%d IE=%#x\n",830			    priv->wapi_ie_len, priv->wapi_ie[0]);831 832		if (priv->wapi_ie[0] == WLAN_EID_BSS_AC_ACCESS_DELAY)833			priv->sec_info.wapi_enabled = true;834	} else {835		memset(priv->wapi_ie, 0, sizeof(priv->wapi_ie));836		priv->wapi_ie_len = ie_len;837		mwifiex_dbg(priv->adapter, INFO,838			    "info: Reset wapi_ie_len=%d IE=%#x\n",839			    priv->wapi_ie_len, priv->wapi_ie[0]);840		priv->sec_info.wapi_enabled = false;841	}842	return 0;843}844 845/*846 * IOCTL request handler to set/reset WPS IE.847 *848 * The supplied WPS IE is treated as a opaque buffer. Only the first field849 * is checked to internally enable WPS. If buffer length is zero, the existing850 * WPS IE is reset.851 */852static int mwifiex_set_wps_ie(struct mwifiex_private *priv,853			       u8 *ie_data_ptr, u16 ie_len)854{855	if (ie_len) {856		if (ie_len > MWIFIEX_MAX_VSIE_LEN) {857			mwifiex_dbg(priv->adapter, ERROR,858				    "info: failed to copy WPS IE, too big\n");859			return -1;860		}861 862		priv->wps_ie = kzalloc(MWIFIEX_MAX_VSIE_LEN, GFP_KERNEL);863		if (!priv->wps_ie)864			return -ENOMEM;865 866		memcpy(priv->wps_ie, ie_data_ptr, ie_len);867		priv->wps_ie_len = ie_len;868		mwifiex_dbg(priv->adapter, CMD,869			    "cmd: Set wps_ie_len=%d IE=%#x\n",870			    priv->wps_ie_len, priv->wps_ie[0]);871	} else {872		kfree(priv->wps_ie);873		priv->wps_ie_len = ie_len;874		mwifiex_dbg(priv->adapter, INFO,875			    "info: Reset wps_ie_len=%d\n", priv->wps_ie_len);876	}877	return 0;878}879 880/*881 * IOCTL request handler to set WAPI key.882 *883 * This function prepares the correct firmware command and884 * issues it.885 */886static int mwifiex_sec_ioctl_set_wapi_key(struct mwifiex_private *priv,887			       struct mwifiex_ds_encrypt_key *encrypt_key)888{889 890	return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL,891				HostCmd_ACT_GEN_SET, KEY_INFO_ENABLED,892				encrypt_key, true);893}894 895/*896 * IOCTL request handler to set WEP network key.897 *898 * This function prepares the correct firmware command and899 * issues it, after validation checks.900 */901static int mwifiex_sec_ioctl_set_wep_key(struct mwifiex_private *priv,902			      struct mwifiex_ds_encrypt_key *encrypt_key)903{904	struct mwifiex_adapter *adapter = priv->adapter;905	int ret;906	struct mwifiex_wep_key *wep_key;907	int index;908 909	if (priv->wep_key_curr_index >= NUM_WEP_KEYS)910		priv->wep_key_curr_index = 0;911	wep_key = &priv->wep_key[priv->wep_key_curr_index];912	index = encrypt_key->key_index;913	if (encrypt_key->key_disable) {914		priv->sec_info.wep_enabled = 0;915	} else if (!encrypt_key->key_len) {916		/* Copy the required key as the current key */917		wep_key = &priv->wep_key[index];918		if (!wep_key->key_length) {919			mwifiex_dbg(adapter, ERROR,920				    "key not set, so cannot enable it\n");921			return -1;922		}923 924		if (adapter->key_api_major_ver == KEY_API_VER_MAJOR_V2) {925			memcpy(encrypt_key->key_material,926			       wep_key->key_material, wep_key->key_length);927			encrypt_key->key_len = wep_key->key_length;928		}929 930		priv->wep_key_curr_index = (u16) index;931		priv->sec_info.wep_enabled = 1;932	} else {933		wep_key = &priv->wep_key[index];934		memset(wep_key, 0, sizeof(struct mwifiex_wep_key));935		/* Copy the key in the driver */936		memcpy(wep_key->key_material,937		       encrypt_key->key_material,938		       encrypt_key->key_len);939		wep_key->key_index = index;940		wep_key->key_length = encrypt_key->key_len;941		priv->sec_info.wep_enabled = 1;942	}943	if (wep_key->key_length) {944		void *enc_key;945 946		if (encrypt_key->key_disable) {947			memset(&priv->wep_key[index], 0,948			       sizeof(struct mwifiex_wep_key));949			goto done;950		}951 952		if (adapter->key_api_major_ver == KEY_API_VER_MAJOR_V2)953			enc_key = encrypt_key;954		else955			enc_key = NULL;956 957		/* Send request to firmware */958		ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL,959				       HostCmd_ACT_GEN_SET, 0, enc_key, false);960		if (ret)961			return ret;962	}963 964done:965	if (priv->sec_info.wep_enabled)966		priv->curr_pkt_filter |= HostCmd_ACT_MAC_WEP_ENABLE;967	else968		priv->curr_pkt_filter &= ~HostCmd_ACT_MAC_WEP_ENABLE;969 970	ret = mwifiex_send_cmd(priv, HostCmd_CMD_MAC_CONTROL,971			       HostCmd_ACT_GEN_SET, 0,972			       &priv->curr_pkt_filter, true);973 974	return ret;975}976 977/*978 * IOCTL request handler to set WPA key.979 *980 * This function prepares the correct firmware command and981 * issues it, after validation checks.982 *983 * Current driver only supports key length of up to 32 bytes.984 *985 * This function can also be used to disable a currently set key.986 */987static int mwifiex_sec_ioctl_set_wpa_key(struct mwifiex_private *priv,988			      struct mwifiex_ds_encrypt_key *encrypt_key)989{990	int ret;991	u8 remove_key = false;992	struct host_cmd_ds_802_11_key_material *ibss_key;993 994	/* Current driver only supports key length of up to 32 bytes */995	if (encrypt_key->key_len > WLAN_MAX_KEY_LEN) {996		mwifiex_dbg(priv->adapter, ERROR,997			    "key length too long\n");998		return -1;999	}1000 1001	if (priv->bss_mode == NL80211_IFTYPE_ADHOC) {1002		/*1003		 * IBSS/WPA-None uses only one key (Group) for both receiving1004		 * and sending unicast and multicast packets.1005		 */1006		/* Send the key as PTK to firmware */1007		encrypt_key->key_index = MWIFIEX_KEY_INDEX_UNICAST;1008		ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL,1009				       HostCmd_ACT_GEN_SET,1010				       KEY_INFO_ENABLED, encrypt_key, false);1011		if (ret)1012			return ret;1013 1014		ibss_key = &priv->aes_key;1015		memset(ibss_key, 0,1016		       sizeof(struct host_cmd_ds_802_11_key_material));1017		/* Copy the key in the driver */1018		memcpy(ibss_key->key_param_set.key, encrypt_key->key_material,1019		       encrypt_key->key_len);1020		memcpy(&ibss_key->key_param_set.key_len, &encrypt_key->key_len,1021		       sizeof(ibss_key->key_param_set.key_len));1022		ibss_key->key_param_set.key_type_id1023			= cpu_to_le16(KEY_TYPE_ID_TKIP);1024		ibss_key->key_param_set.key_info = cpu_to_le16(KEY_ENABLED);1025 1026		/* Send the key as GTK to firmware */1027		encrypt_key->key_index = ~MWIFIEX_KEY_INDEX_UNICAST;1028	}1029 1030	if (!encrypt_key->key_index)1031		encrypt_key->key_index = MWIFIEX_KEY_INDEX_UNICAST;1032 1033	if (remove_key)1034		ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL,1035				       HostCmd_ACT_GEN_SET,1036				       !KEY_INFO_ENABLED, encrypt_key, true);1037	else1038		ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL,1039				       HostCmd_ACT_GEN_SET,1040				       KEY_INFO_ENABLED, encrypt_key, true);1041 1042	return ret;1043}1044 1045/*1046 * IOCTL request handler to set/get network keys.1047 *1048 * This is a generic key handling function which supports WEP, WPA1049 * and WAPI.1050 */1051static int1052mwifiex_sec_ioctl_encrypt_key(struct mwifiex_private *priv,1053			      struct mwifiex_ds_encrypt_key *encrypt_key)1054{1055	int status;1056 1057	if (encrypt_key->is_wapi_key)1058		status = mwifiex_sec_ioctl_set_wapi_key(priv, encrypt_key);1059	else if (encrypt_key->key_len > WLAN_KEY_LEN_WEP104)1060		status = mwifiex_sec_ioctl_set_wpa_key(priv, encrypt_key);1061	else1062		status = mwifiex_sec_ioctl_set_wep_key(priv, encrypt_key);1063	return status;1064}1065 1066/*1067 * This function returns the driver version.1068 */1069int1070mwifiex_drv_get_driver_version(struct mwifiex_adapter *adapter, char *version,1071			       int max_len)1072{1073	union {1074		__le32 l;1075		u8 c[4];1076	} ver;1077	char fw_ver[32];1078 1079	ver.l = cpu_to_le32(adapter->fw_release_number);1080	sprintf(fw_ver, "%u.%u.%u.p%u", ver.c[2], ver.c[1], ver.c[0], ver.c[3]);1081 1082	snprintf(version, max_len, driver_version, fw_ver);1083 1084	mwifiex_dbg(adapter, MSG, "info: MWIFIEX VERSION: %s\n", version);1085 1086	return 0;1087}1088 1089/*1090 * Sends IOCTL request to set encoding parameters.1091 *1092 * This function allocates the IOCTL request buffer, fills it1093 * with requisite parameters and calls the IOCTL handler.1094 */1095int mwifiex_set_encode(struct mwifiex_private *priv, struct key_params *kp,1096		       const u8 *key, int key_len, u8 key_index,1097		       const u8 *mac_addr, int disable)1098{1099	struct mwifiex_ds_encrypt_key encrypt_key;1100 1101	memset(&encrypt_key, 0, sizeof(encrypt_key));1102	encrypt_key.key_len = key_len;1103	encrypt_key.key_index = key_index;1104 1105	if (kp && kp->cipher == WLAN_CIPHER_SUITE_AES_CMAC)1106		encrypt_key.is_igtk_key = true;1107 1108	if (!disable) {1109		if (key_len)1110			memcpy(encrypt_key.key_material, key, key_len);1111		else1112			encrypt_key.is_current_wep_key = true;1113 1114		if (mac_addr)1115			memcpy(encrypt_key.mac_addr, mac_addr, ETH_ALEN);1116		if (kp && kp->seq && kp->seq_len) {1117			memcpy(encrypt_key.pn, kp->seq, kp->seq_len);1118			encrypt_key.pn_len = kp->seq_len;1119			encrypt_key.is_rx_seq_valid = true;1120		}1121	} else {1122		encrypt_key.key_disable = true;1123		if (mac_addr)1124			memcpy(encrypt_key.mac_addr, mac_addr, ETH_ALEN);1125	}1126 1127	return mwifiex_sec_ioctl_encrypt_key(priv, &encrypt_key);1128}1129 1130/*1131 * Sends IOCTL request to get extended version.1132 *1133 * This function allocates the IOCTL request buffer, fills it1134 * with requisite parameters and calls the IOCTL handler.1135 */1136int1137mwifiex_get_ver_ext(struct mwifiex_private *priv, u32 version_str_sel)1138{1139	struct mwifiex_ver_ext ver_ext;1140 1141	memset(&ver_ext, 0, sizeof(ver_ext));1142	ver_ext.version_str_sel = version_str_sel;1143	if (mwifiex_send_cmd(priv, HostCmd_CMD_VERSION_EXT,1144			     HostCmd_ACT_GEN_GET, 0, &ver_ext, true))1145		return -1;1146 1147	return 0;1148}1149 1150int1151mwifiex_remain_on_chan_cfg(struct mwifiex_private *priv, u16 action,1152			   struct ieee80211_channel *chan,1153			   unsigned int duration)1154{1155	struct host_cmd_ds_remain_on_chan roc_cfg;1156	u8 sc;1157 1158	memset(&roc_cfg, 0, sizeof(roc_cfg));1159	roc_cfg.action = cpu_to_le16(action);1160	if (action == HostCmd_ACT_GEN_SET) {1161		roc_cfg.band_cfg = chan->band;1162		sc = mwifiex_chan_type_to_sec_chan_offset(NL80211_CHAN_NO_HT);1163		roc_cfg.band_cfg |= (sc << 2);1164 1165		roc_cfg.channel =1166			ieee80211_frequency_to_channel(chan->center_freq);1167		roc_cfg.duration = cpu_to_le32(duration);1168	}1169	if (mwifiex_send_cmd(priv, HostCmd_CMD_REMAIN_ON_CHAN,1170			     action, 0, &roc_cfg, true)) {1171		mwifiex_dbg(priv->adapter, ERROR,1172			    "failed to remain on channel\n");1173		return -1;1174	}1175 1176	return roc_cfg.status;1177}1178 1179/*1180 * Sends IOCTL request to get statistics information.1181 *1182 * This function allocates the IOCTL request buffer, fills it1183 * with requisite parameters and calls the IOCTL handler.1184 */1185int1186mwifiex_get_stats_info(struct mwifiex_private *priv,1187		       struct mwifiex_ds_get_stats *log)1188{1189	return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_GET_LOG,1190				HostCmd_ACT_GEN_GET, 0, log, true);1191}1192 1193/*1194 * IOCTL request handler to read/write register.1195 *1196 * This function prepares the correct firmware command and1197 * issues it.1198 *1199 * Access to the following registers are supported -1200 *      - MAC1201 *      - BBP1202 *      - RF1203 *      - PMIC1204 *      - CAU1205 */1206static int mwifiex_reg_mem_ioctl_reg_rw(struct mwifiex_private *priv,1207					struct mwifiex_ds_reg_rw *reg_rw,1208					u16 action)1209{1210	u16 cmd_no;1211 1212	switch (reg_rw->type) {1213	case MWIFIEX_REG_MAC:1214		cmd_no = HostCmd_CMD_MAC_REG_ACCESS;1215		break;1216	case MWIFIEX_REG_BBP:1217		cmd_no = HostCmd_CMD_BBP_REG_ACCESS;1218		break;1219	case MWIFIEX_REG_RF:1220		cmd_no = HostCmd_CMD_RF_REG_ACCESS;1221		break;1222	case MWIFIEX_REG_PMIC:1223		cmd_no = HostCmd_CMD_PMIC_REG_ACCESS;1224		break;1225	case MWIFIEX_REG_CAU:1226		cmd_no = HostCmd_CMD_CAU_REG_ACCESS;1227		break;1228	default:1229		return -1;1230	}1231 1232	return mwifiex_send_cmd(priv, cmd_no, action, 0, reg_rw, true);1233}1234 1235/*1236 * Sends IOCTL request to write to a register.1237 *1238 * This function allocates the IOCTL request buffer, fills it1239 * with requisite parameters and calls the IOCTL handler.1240 */1241int1242mwifiex_reg_write(struct mwifiex_private *priv, u32 reg_type,1243		  u32 reg_offset, u32 reg_value)1244{1245	struct mwifiex_ds_reg_rw reg_rw;1246 1247	reg_rw.type = reg_type;1248	reg_rw.offset = reg_offset;1249	reg_rw.value = reg_value;1250 1251	return mwifiex_reg_mem_ioctl_reg_rw(priv, &reg_rw, HostCmd_ACT_GEN_SET);1252}1253 1254/*1255 * Sends IOCTL request to read from a register.1256 *1257 * This function allocates the IOCTL request buffer, fills it1258 * with requisite parameters and calls the IOCTL handler.1259 */1260int1261mwifiex_reg_read(struct mwifiex_private *priv, u32 reg_type,1262		 u32 reg_offset, u32 *value)1263{1264	int ret;1265	struct mwifiex_ds_reg_rw reg_rw;1266 1267	reg_rw.type = reg_type;1268	reg_rw.offset = reg_offset;1269	ret = mwifiex_reg_mem_ioctl_reg_rw(priv, &reg_rw, HostCmd_ACT_GEN_GET);1270 1271	if (ret)1272		goto done;1273 1274	*value = reg_rw.value;1275 1276done:1277	return ret;1278}1279 1280/*1281 * Sends IOCTL request to read from EEPROM.1282 *1283 * This function allocates the IOCTL request buffer, fills it1284 * with requisite parameters and calls the IOCTL handler.1285 */1286int1287mwifiex_eeprom_read(struct mwifiex_private *priv, u16 offset, u16 bytes,1288		    u8 *value)1289{1290	int ret;1291	struct mwifiex_ds_read_eeprom rd_eeprom;1292 1293	rd_eeprom.offset =  offset;1294	rd_eeprom.byte_count = bytes;1295 1296	/* Send request to firmware */1297	ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_EEPROM_ACCESS,1298			       HostCmd_ACT_GEN_GET, 0, &rd_eeprom, true);1299 1300	if (!ret)1301		memcpy(value, rd_eeprom.value, min((u16)MAX_EEPROM_DATA,1302		       rd_eeprom.byte_count));1303	return ret;1304}1305 1306/*1307 * This function sets a generic IE. In addition to generic IE, it can1308 * also handle WPA, WPA2 and WAPI IEs.1309 */1310static int1311mwifiex_set_gen_ie_helper(struct mwifiex_private *priv, u8 *ie_data_ptr,1312			  u16 ie_len)1313{1314	struct ieee_types_vendor_header *pvendor_ie;1315	static const u8 wpa_oui[] = { 0x00, 0x50, 0xf2, 0x01 };1316	static const u8 wps_oui[] = { 0x00, 0x50, 0xf2, 0x04 };1317	u16 unparsed_len = ie_len, cur_ie_len;1318 1319	/* If the passed length is zero, reset the buffer */1320	if (!ie_len) {1321		priv->gen_ie_buf_len = 0;1322		priv->wps.session_enable = false;1323		return 0;1324	} else if (!ie_data_ptr ||1325		   ie_len <= sizeof(struct ieee_types_header)) {1326		return -1;1327	}1328	pvendor_ie = (struct ieee_types_vendor_header *) ie_data_ptr;1329 1330	while (pvendor_ie) {1331		cur_ie_len = pvendor_ie->len + sizeof(struct ieee_types_header);1332 1333		if (pvendor_ie->element_id == WLAN_EID_RSN) {1334			/* IE is a WPA/WPA2 IE so call set_wpa function */1335			mwifiex_set_wpa_ie(priv, (u8 *)pvendor_ie, cur_ie_len);1336			priv->wps.session_enable = false;1337			goto next_ie;1338		}1339 1340		if (pvendor_ie->element_id == WLAN_EID_BSS_AC_ACCESS_DELAY) {1341			/* IE is a WAPI IE so call set_wapi function */1342			mwifiex_set_wapi_ie(priv, (u8 *)pvendor_ie,1343					    cur_ie_len);1344			goto next_ie;1345		}1346 1347		if (pvendor_ie->element_id == WLAN_EID_VENDOR_SPECIFIC) {1348			/* Test to see if it is a WPA IE, if not, then1349			 * it is a gen IE1350			 */1351			if (!memcmp(&pvendor_ie->oui, wpa_oui,1352				    sizeof(wpa_oui))) {1353				/* IE is a WPA/WPA2 IE so call set_wpa function1354				 */1355				mwifiex_set_wpa_ie(priv, (u8 *)pvendor_ie,1356						   cur_ie_len);1357				priv->wps.session_enable = false;1358				goto next_ie;1359			}1360 1361			if (!memcmp(&pvendor_ie->oui, wps_oui,1362				    sizeof(wps_oui))) {1363				/* Test to see if it is a WPS IE,1364				 * if so, enable wps session flag1365				 */1366				priv->wps.session_enable = true;1367				mwifiex_dbg(priv->adapter, MSG,1368					    "WPS Session Enabled.\n");1369				mwifiex_set_wps_ie(priv, (u8 *)pvendor_ie,1370						   cur_ie_len);1371				goto next_ie;1372			}1373		}1374 1375		/* Saved in gen_ie, such as P2P IE.etc.*/1376 1377		/* Verify that the passed length is not larger than the1378		 * available space remaining in the buffer1379		 */1380		if (cur_ie_len <1381		    (sizeof(priv->gen_ie_buf) - priv->gen_ie_buf_len)) {1382			/* Append the passed data to the end1383			 * of the genIeBuffer1384			 */1385			memcpy(priv->gen_ie_buf + priv->gen_ie_buf_len,1386			       (u8 *)pvendor_ie, cur_ie_len);1387			/* Increment the stored buffer length by the1388			 * size passed1389			 */1390			priv->gen_ie_buf_len += cur_ie_len;1391		}1392 1393next_ie:1394		unparsed_len -= cur_ie_len;1395 1396		if (unparsed_len <= sizeof(struct ieee_types_header))1397			pvendor_ie = NULL;1398		else1399			pvendor_ie = (struct ieee_types_vendor_header *)1400				(((u8 *)pvendor_ie) + cur_ie_len);1401	}1402 1403	return 0;1404}1405 1406/*1407 * IOCTL request handler to set/get generic IE.1408 *1409 * In addition to various generic IEs, this function can also be1410 * used to set the ARP filter.1411 */1412static int mwifiex_misc_ioctl_gen_ie(struct mwifiex_private *priv,1413				     struct mwifiex_ds_misc_gen_ie *gen_ie,1414				     u16 action)1415{1416	struct mwifiex_adapter *adapter = priv->adapter;1417 1418	switch (gen_ie->type) {1419	case MWIFIEX_IE_TYPE_GEN_IE:1420		if (action == HostCmd_ACT_GEN_GET) {1421			gen_ie->len = priv->wpa_ie_len;1422			memcpy(gen_ie->ie_data, priv->wpa_ie, gen_ie->len);1423		} else {1424			mwifiex_set_gen_ie_helper(priv, gen_ie->ie_data,1425						  (u16) gen_ie->len);1426		}1427		break;1428	case MWIFIEX_IE_TYPE_ARP_FILTER:1429		memset(adapter->arp_filter, 0, sizeof(adapter->arp_filter));1430		if (gen_ie->len > ARP_FILTER_MAX_BUF_SIZE) {1431			adapter->arp_filter_size = 0;1432			mwifiex_dbg(adapter, ERROR,1433				    "invalid ARP filter size\n");1434			return -1;1435		} else {1436			memcpy(adapter->arp_filter, gen_ie->ie_data,1437			       gen_ie->len);1438			adapter->arp_filter_size = gen_ie->len;1439		}1440		break;1441	default:1442		mwifiex_dbg(adapter, ERROR, "invalid IE type\n");1443		return -1;1444	}1445	return 0;1446}1447 1448/*1449 * Sends IOCTL request to set a generic IE.1450 *1451 * This function allocates the IOCTL request buffer, fills it1452 * with requisite parameters and calls the IOCTL handler.1453 */1454int1455mwifiex_set_gen_ie(struct mwifiex_private *priv, const u8 *ie, int ie_len)1456{1457	struct mwifiex_ds_misc_gen_ie gen_ie;1458 1459	if (ie_len > IEEE_MAX_IE_SIZE)1460		return -EFAULT;1461 1462	gen_ie.type = MWIFIEX_IE_TYPE_GEN_IE;1463	gen_ie.len = ie_len;1464	memcpy(gen_ie.ie_data, ie, ie_len);1465	if (mwifiex_misc_ioctl_gen_ie(priv, &gen_ie, HostCmd_ACT_GEN_SET))1466		return -EFAULT;1467 1468	return 0;1469}1470 1471/* This function get Host Sleep wake up reason.1472 *1473 */1474int mwifiex_get_wakeup_reason(struct mwifiex_private *priv, u16 action,1475			      int cmd_type,1476			      struct mwifiex_ds_wakeup_reason *wakeup_reason)1477{1478	int status = 0;1479 1480	status = mwifiex_send_cmd(priv, HostCmd_CMD_HS_WAKEUP_REASON,1481				  HostCmd_ACT_GEN_GET, 0, wakeup_reason,1482				  cmd_type == MWIFIEX_SYNC_CMD);1483 1484	return status;1485}1486 1487int mwifiex_get_chan_info(struct mwifiex_private *priv,1488			  struct mwifiex_channel_band *channel_band)1489{1490	int status = 0;1491 1492	status = mwifiex_send_cmd(priv, HostCmd_CMD_STA_CONFIGURE,1493				  HostCmd_ACT_GEN_GET, 0, channel_band,1494				  MWIFIEX_SYNC_CMD);1495 1496	return status;1497}1498