Linux Audio

Check our new training course

Loading...
Note: File does not exist in v5.4.
   1/*
   2 * Marvell Wireless LAN device driver: scan ioctl and command handling
   3 *
   4 * Copyright (C) 2011, Marvell International Ltd.
   5 *
   6 * This software file (the "File") is distributed by Marvell International
   7 * Ltd. 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 "decl.h"
  21#include "ioctl.h"
  22#include "util.h"
  23#include "fw.h"
  24#include "main.h"
  25#include "11n.h"
  26#include "cfg80211.h"
  27
  28/* The maximum number of channels the firmware can scan per command */
  29#define MWIFIEX_MAX_CHANNELS_PER_SPECIFIC_SCAN   14
  30
  31#define MWIFIEX_CHANNELS_PER_SCAN_CMD            4
  32
  33/* Memory needed to store a max sized Channel List TLV for a firmware scan */
  34#define CHAN_TLV_MAX_SIZE  (sizeof(struct mwifiex_ie_types_header)         \
  35				+ (MWIFIEX_MAX_CHANNELS_PER_SPECIFIC_SCAN     \
  36				*sizeof(struct mwifiex_chan_scan_param_set)))
  37
  38/* Memory needed to store supported rate */
  39#define RATE_TLV_MAX_SIZE   (sizeof(struct mwifiex_ie_types_rates_param_set) \
  40				+ HOSTCMD_SUPPORTED_RATES)
  41
  42/* Memory needed to store a max number/size WildCard SSID TLV for a firmware
  43	scan */
  44#define WILDCARD_SSID_TLV_MAX_SIZE  \
  45	(MWIFIEX_MAX_SSID_LIST_LENGTH *					\
  46		(sizeof(struct mwifiex_ie_types_wildcard_ssid_params)	\
  47			+ IEEE80211_MAX_SSID_LEN))
  48
  49/* Maximum memory needed for a mwifiex_scan_cmd_config with all TLVs at max */
  50#define MAX_SCAN_CFG_ALLOC (sizeof(struct mwifiex_scan_cmd_config)        \
  51				+ sizeof(struct mwifiex_ie_types_num_probes)   \
  52				+ sizeof(struct mwifiex_ie_types_htcap)       \
  53				+ CHAN_TLV_MAX_SIZE                 \
  54				+ RATE_TLV_MAX_SIZE                 \
  55				+ WILDCARD_SSID_TLV_MAX_SIZE)
  56
  57
  58union mwifiex_scan_cmd_config_tlv {
  59	/* Scan configuration (variable length) */
  60	struct mwifiex_scan_cmd_config config;
  61	/* Max allocated block */
  62	u8 config_alloc_buf[MAX_SCAN_CFG_ALLOC];
  63};
  64
  65enum cipher_suite {
  66	CIPHER_SUITE_TKIP,
  67	CIPHER_SUITE_CCMP,
  68	CIPHER_SUITE_MAX
  69};
  70static u8 mwifiex_wpa_oui[CIPHER_SUITE_MAX][4] = {
  71	{ 0x00, 0x50, 0xf2, 0x02 },	/* TKIP */
  72	{ 0x00, 0x50, 0xf2, 0x04 },	/* AES  */
  73};
  74static u8 mwifiex_rsn_oui[CIPHER_SUITE_MAX][4] = {
  75	{ 0x00, 0x0f, 0xac, 0x02 },	/* TKIP */
  76	{ 0x00, 0x0f, 0xac, 0x04 },	/* AES  */
  77};
  78
  79/*
  80 * This function parses a given IE for a given OUI.
  81 *
  82 * This is used to parse a WPA/RSN IE to find if it has
  83 * a given oui in PTK.
  84 */
  85static u8
  86mwifiex_search_oui_in_ie(struct ie_body *iebody, u8 *oui)
  87{
  88	u8 count;
  89
  90	count = iebody->ptk_cnt[0];
  91
  92	/* There could be multiple OUIs for PTK hence
  93	   1) Take the length.
  94	   2) Check all the OUIs for AES.
  95	   3) If one of them is AES then pass success. */
  96	while (count) {
  97		if (!memcmp(iebody->ptk_body, oui, sizeof(iebody->ptk_body)))
  98			return MWIFIEX_OUI_PRESENT;
  99
 100		--count;
 101		if (count)
 102			iebody = (struct ie_body *) ((u8 *) iebody +
 103						sizeof(iebody->ptk_body));
 104	}
 105
 106	pr_debug("info: %s: OUI is not found in PTK\n", __func__);
 107	return MWIFIEX_OUI_NOT_PRESENT;
 108}
 109
 110/*
 111 * This function checks if a given OUI is present in a RSN IE.
 112 *
 113 * The function first checks if a RSN IE is present or not in the
 114 * BSS descriptor. It tries to locate the OUI only if such an IE is
 115 * present.
 116 */
 117static u8
 118mwifiex_is_rsn_oui_present(struct mwifiex_bssdescriptor *bss_desc, u32 cipher)
 119{
 120	u8 *oui;
 121	struct ie_body *iebody;
 122	u8 ret = MWIFIEX_OUI_NOT_PRESENT;
 123
 124	if (((bss_desc->bcn_rsn_ie) && ((*(bss_desc->bcn_rsn_ie)).
 125					ieee_hdr.element_id == WLAN_EID_RSN))) {
 126		iebody = (struct ie_body *)
 127			 (((u8 *) bss_desc->bcn_rsn_ie->data) +
 128			 RSN_GTK_OUI_OFFSET);
 129		oui = &mwifiex_rsn_oui[cipher][0];
 130		ret = mwifiex_search_oui_in_ie(iebody, oui);
 131		if (ret)
 132			return ret;
 133	}
 134	return ret;
 135}
 136
 137/*
 138 * This function checks if a given OUI is present in a WPA IE.
 139 *
 140 * The function first checks if a WPA IE is present or not in the
 141 * BSS descriptor. It tries to locate the OUI only if such an IE is
 142 * present.
 143 */
 144static u8
 145mwifiex_is_wpa_oui_present(struct mwifiex_bssdescriptor *bss_desc, u32 cipher)
 146{
 147	u8 *oui;
 148	struct ie_body *iebody;
 149	u8 ret = MWIFIEX_OUI_NOT_PRESENT;
 150
 151	if (((bss_desc->bcn_wpa_ie) && ((*(bss_desc->bcn_wpa_ie)).
 152				      vend_hdr.element_id == WLAN_EID_WPA))) {
 153		iebody = (struct ie_body *) bss_desc->bcn_wpa_ie->data;
 154		oui = &mwifiex_wpa_oui[cipher][0];
 155		ret = mwifiex_search_oui_in_ie(iebody, oui);
 156		if (ret)
 157			return ret;
 158	}
 159	return ret;
 160}
 161
 162/*
 163 * This function compares two SSIDs and checks if they match.
 164 */
 165s32
 166mwifiex_ssid_cmp(struct mwifiex_802_11_ssid *ssid1,
 167		 struct mwifiex_802_11_ssid *ssid2)
 168{
 169	if (!ssid1 || !ssid2 || (ssid1->ssid_len != ssid2->ssid_len))
 170		return -1;
 171	return memcmp(ssid1->ssid, ssid2->ssid, ssid1->ssid_len);
 172}
 173
 174/*
 175 * Sends IOCTL request to get the best BSS.
 176 *
 177 * This function allocates the IOCTL request buffer, fills it
 178 * with requisite parameters and calls the IOCTL handler.
 179 */
 180int mwifiex_find_best_bss(struct mwifiex_private *priv,
 181			  struct mwifiex_ssid_bssid *ssid_bssid)
 182{
 183	struct mwifiex_ssid_bssid tmp_ssid_bssid;
 184	u8 *mac;
 185
 186	if (!ssid_bssid)
 187		return -1;
 188
 189	memcpy(&tmp_ssid_bssid, ssid_bssid,
 190	       sizeof(struct mwifiex_ssid_bssid));
 191
 192	if (!mwifiex_bss_ioctl_find_bss(priv, &tmp_ssid_bssid)) {
 193		memcpy(ssid_bssid, &tmp_ssid_bssid,
 194		       sizeof(struct mwifiex_ssid_bssid));
 195		mac = (u8 *) &ssid_bssid->bssid;
 196		dev_dbg(priv->adapter->dev, "cmd: found network: ssid=%s,"
 197				" %pM\n", ssid_bssid->ssid.ssid, mac);
 198		return 0;
 199	}
 200
 201	return -1;
 202}
 203
 204/*
 205 * Sends IOCTL request to start a scan with user configurations.
 206 *
 207 * This function allocates the IOCTL request buffer, fills it
 208 * with requisite parameters and calls the IOCTL handler.
 209 *
 210 * Upon completion, it also generates a wireless event to notify
 211 * applications.
 212 */
 213int mwifiex_set_user_scan_ioctl(struct mwifiex_private *priv,
 214				struct mwifiex_user_scan_cfg *scan_req)
 215{
 216	int status;
 217
 218	priv->adapter->cmd_wait_q.condition = false;
 219
 220	status = mwifiex_scan_networks(priv, scan_req);
 221	if (!status)
 222		status = mwifiex_wait_queue_complete(priv->adapter);
 223
 224	return status;
 225}
 226
 227/*
 228 * This function checks if wapi is enabled in driver and scanned network is
 229 * compatible with it.
 230 */
 231static bool
 232mwifiex_is_network_compatible_for_wapi(struct mwifiex_private *priv,
 233				       struct mwifiex_bssdescriptor *bss_desc)
 234{
 235	if (priv->sec_info.wapi_enabled &&
 236	    (bss_desc->bcn_wapi_ie &&
 237	     ((*(bss_desc->bcn_wapi_ie)).ieee_hdr.element_id ==
 238			WLAN_EID_BSS_AC_ACCESS_DELAY))) {
 239		return true;
 240	}
 241	return false;
 242}
 243
 244/*
 245 * This function checks if driver is configured with no security mode and
 246 * scanned network is compatible with it.
 247 */
 248static bool
 249mwifiex_is_network_compatible_for_no_sec(struct mwifiex_private *priv,
 250				       struct mwifiex_bssdescriptor *bss_desc)
 251{
 252	if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED
 253	    && !priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled
 254	    && ((!bss_desc->bcn_wpa_ie) ||
 255		((*(bss_desc->bcn_wpa_ie)).vend_hdr.element_id !=
 256	    WLAN_EID_WPA))
 257	    && ((!bss_desc->bcn_rsn_ie) ||
 258		((*(bss_desc->bcn_rsn_ie)).ieee_hdr.element_id !=
 259	    WLAN_EID_RSN))
 260	    && !priv->sec_info.encryption_mode
 261	    && !bss_desc->privacy) {
 262		return true;
 263	}
 264	return false;
 265}
 266
 267/*
 268 * This function checks if static WEP is enabled in driver and scanned network
 269 * is compatible with it.
 270 */
 271static bool
 272mwifiex_is_network_compatible_for_static_wep(struct mwifiex_private *priv,
 273				       struct mwifiex_bssdescriptor *bss_desc)
 274{
 275	if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_ENABLED
 276	    && !priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled
 277	    && bss_desc->privacy) {
 278		return true;
 279	}
 280	return false;
 281}
 282
 283/*
 284 * This function checks if wpa is enabled in driver and scanned network is
 285 * compatible with it.
 286 */
 287static bool
 288mwifiex_is_network_compatible_for_wpa(struct mwifiex_private *priv,
 289				      struct mwifiex_bssdescriptor *bss_desc,
 290				      int index)
 291{
 292	if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED
 293	    && priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled
 294	    && ((bss_desc->bcn_wpa_ie) && ((*(bss_desc->bcn_wpa_ie)).vend_hdr.
 295						element_id == WLAN_EID_WPA))
 296	   /*
 297	    * Privacy bit may NOT be set in some APs like
 298	    * LinkSys WRT54G && bss_desc->privacy
 299	    */
 300	 ) {
 301		dev_dbg(priv->adapter->dev, "info: %s: WPA: index=%d"
 302			" wpa_ie=%#x wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s "
 303			"EncMode=%#x privacy=%#x\n", __func__, index,
 304			(bss_desc->bcn_wpa_ie) ?
 305			(*(bss_desc->bcn_wpa_ie)).
 306			vend_hdr.element_id : 0,
 307			(bss_desc->bcn_rsn_ie) ?
 308			(*(bss_desc->bcn_rsn_ie)).
 309			ieee_hdr.element_id : 0,
 310			(priv->sec_info.wep_status ==
 311			MWIFIEX_802_11_WEP_ENABLED) ? "e" : "d",
 312			(priv->sec_info.wpa_enabled) ? "e" : "d",
 313			(priv->sec_info.wpa2_enabled) ? "e" : "d",
 314			priv->sec_info.encryption_mode,
 315			bss_desc->privacy);
 316		return true;
 317	}
 318	return false;
 319}
 320
 321/*
 322 * This function checks if wpa2 is enabled in driver and scanned network is
 323 * compatible with it.
 324 */
 325static bool
 326mwifiex_is_network_compatible_for_wpa2(struct mwifiex_private *priv,
 327				       struct mwifiex_bssdescriptor *bss_desc,
 328				       int index)
 329{
 330	if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED
 331	   && !priv->sec_info.wpa_enabled && priv->sec_info.wpa2_enabled
 332	   && ((bss_desc->bcn_rsn_ie) && ((*(bss_desc->bcn_rsn_ie)).ieee_hdr.
 333						element_id == WLAN_EID_RSN))
 334	   /*
 335	    * Privacy bit may NOT be set in some APs like
 336	    * LinkSys WRT54G && bss_desc->privacy
 337	    */
 338	 ) {
 339		dev_dbg(priv->adapter->dev, "info: %s: WPA2: index=%d"
 340			" wpa_ie=%#x wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s "
 341			"EncMode=%#x privacy=%#x\n", __func__, index,
 342			(bss_desc->bcn_wpa_ie) ?
 343			(*(bss_desc->bcn_wpa_ie)).
 344			vend_hdr.element_id : 0,
 345			(bss_desc->bcn_rsn_ie) ?
 346			(*(bss_desc->bcn_rsn_ie)).
 347			ieee_hdr.element_id : 0,
 348			(priv->sec_info.wep_status ==
 349			MWIFIEX_802_11_WEP_ENABLED) ? "e" : "d",
 350			(priv->sec_info.wpa_enabled) ? "e" : "d",
 351			(priv->sec_info.wpa2_enabled) ? "e" : "d",
 352			priv->sec_info.encryption_mode,
 353			bss_desc->privacy);
 354		return true;
 355	}
 356	return false;
 357}
 358
 359/*
 360 * This function checks if adhoc AES is enabled in driver and scanned network is
 361 * compatible with it.
 362 */
 363static bool
 364mwifiex_is_network_compatible_for_adhoc_aes(struct mwifiex_private *priv,
 365				       struct mwifiex_bssdescriptor *bss_desc)
 366{
 367	if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED
 368	    && !priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled
 369	    && ((!bss_desc->bcn_wpa_ie) || ((*(bss_desc->bcn_wpa_ie)).vend_hdr.
 370		   element_id != WLAN_EID_WPA))
 371	    && ((!bss_desc->bcn_rsn_ie) || ((*(bss_desc->bcn_rsn_ie)).ieee_hdr.
 372		   element_id != WLAN_EID_RSN))
 373	    && !priv->sec_info.encryption_mode
 374	    && bss_desc->privacy) {
 375		return true;
 376	}
 377	return false;
 378}
 379
 380/*
 381 * This function checks if dynamic WEP is enabled in driver and scanned network
 382 * is compatible with it.
 383 */
 384static bool
 385mwifiex_is_network_compatible_for_dynamic_wep(struct mwifiex_private *priv,
 386				       struct mwifiex_bssdescriptor *bss_desc,
 387				       int index)
 388{
 389	if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED
 390	    && !priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled
 391	    && ((!bss_desc->bcn_wpa_ie) || ((*(bss_desc->bcn_wpa_ie)).vend_hdr.
 392		   element_id != WLAN_EID_WPA))
 393	    && ((!bss_desc->bcn_rsn_ie) || ((*(bss_desc->bcn_rsn_ie)).ieee_hdr.
 394		   element_id != WLAN_EID_RSN))
 395	    && priv->sec_info.encryption_mode
 396	    && bss_desc->privacy) {
 397		dev_dbg(priv->adapter->dev, "info: %s: dynamic "
 398			"WEP: index=%d wpa_ie=%#x wpa2_ie=%#x "
 399			"EncMode=%#x privacy=%#x\n",
 400			__func__, index,
 401			(bss_desc->bcn_wpa_ie) ?
 402			(*(bss_desc->bcn_wpa_ie)).
 403			vend_hdr.element_id : 0,
 404			(bss_desc->bcn_rsn_ie) ?
 405			(*(bss_desc->bcn_rsn_ie)).
 406			ieee_hdr.element_id : 0,
 407			priv->sec_info.encryption_mode,
 408			bss_desc->privacy);
 409		return true;
 410	}
 411	return false;
 412}
 413
 414/*
 415 * This function checks if a scanned network is compatible with the driver
 416 * settings.
 417 *
 418 *   WEP     WPA    WPA2   ad-hoc encrypt                  Network
 419 * enabled enabled enabled  AES    mode   Privacy WPA WPA2 Compatible
 420 *    0       0       0      0     NONE      0     0   0   yes No security
 421 *    0       1       0      0      x        1x    1   x   yes WPA (disable
 422 *                                                         HT if no AES)
 423 *    0       0       1      0      x        1x    x   1   yes WPA2 (disable
 424 *                                                         HT if no AES)
 425 *    0       0       0      1     NONE      1     0   0   yes Ad-hoc AES
 426 *    1       0       0      0     NONE      1     0   0   yes Static WEP
 427 *                                                         (disable HT)
 428 *    0       0       0      0    !=NONE     1     0   0   yes Dynamic WEP
 429 *
 430 * Compatibility is not matched while roaming, except for mode.
 431 */
 432static s32
 433mwifiex_is_network_compatible(struct mwifiex_private *priv, u32 index, u32 mode)
 434{
 435	struct mwifiex_adapter *adapter = priv->adapter;
 436	struct mwifiex_bssdescriptor *bss_desc;
 437
 438	bss_desc = &adapter->scan_table[index];
 439	bss_desc->disable_11n = false;
 440
 441	/* Don't check for compatibility if roaming */
 442	if (priv->media_connected && (priv->bss_mode == NL80211_IFTYPE_STATION)
 443	    && (bss_desc->bss_mode == NL80211_IFTYPE_STATION))
 444		return index;
 445
 446	if (priv->wps.session_enable) {
 447		dev_dbg(adapter->dev,
 448			"info: return success directly in WPS period\n");
 449		return index;
 450	}
 451
 452	if (mwifiex_is_network_compatible_for_wapi(priv, bss_desc)) {
 453		dev_dbg(adapter->dev, "info: return success for WAPI AP\n");
 454		return index;
 455	}
 456
 457	if (bss_desc->bss_mode == mode) {
 458		if (mwifiex_is_network_compatible_for_no_sec(priv, bss_desc)) {
 459			/* No security */
 460			return index;
 461		} else if (mwifiex_is_network_compatible_for_static_wep(priv,
 462								bss_desc)) {
 463			/* Static WEP enabled */
 464			dev_dbg(adapter->dev, "info: Disable 11n in WEP mode.\n");
 465			bss_desc->disable_11n = true;
 466			return index;
 467		} else if (mwifiex_is_network_compatible_for_wpa(priv, bss_desc,
 468								 index)) {
 469			/* WPA enabled */
 470			if (((priv->adapter->config_bands & BAND_GN
 471			      || priv->adapter->config_bands & BAND_AN)
 472			      && bss_desc->bcn_ht_cap)
 473			      && !mwifiex_is_wpa_oui_present(bss_desc,
 474					CIPHER_SUITE_CCMP)) {
 475
 476				if (mwifiex_is_wpa_oui_present(bss_desc,
 477					    CIPHER_SUITE_TKIP)) {
 478					dev_dbg(adapter->dev,
 479						"info: Disable 11n if AES "
 480						"is not supported by AP\n");
 481					bss_desc->disable_11n = true;
 482				} else {
 483					return -1;
 484				}
 485			}
 486			return index;
 487		} else if (mwifiex_is_network_compatible_for_wpa2(priv,
 488							bss_desc, index)) {
 489			/* WPA2 enabled */
 490			if (((priv->adapter->config_bands & BAND_GN
 491			      || priv->adapter->config_bands & BAND_AN)
 492			      && bss_desc->bcn_ht_cap)
 493			      && !mwifiex_is_rsn_oui_present(bss_desc,
 494					CIPHER_SUITE_CCMP)) {
 495
 496				if (mwifiex_is_rsn_oui_present(bss_desc,
 497					    CIPHER_SUITE_TKIP)) {
 498					dev_dbg(adapter->dev,
 499						"info: Disable 11n if AES "
 500						"is not supported by AP\n");
 501					bss_desc->disable_11n = true;
 502				} else {
 503					return -1;
 504				}
 505			}
 506			return index;
 507		} else if (mwifiex_is_network_compatible_for_adhoc_aes(priv,
 508								bss_desc)) {
 509			/* Ad-hoc AES enabled */
 510			return index;
 511		} else if (mwifiex_is_network_compatible_for_dynamic_wep(priv,
 512							bss_desc, index)) {
 513			/* Dynamic WEP enabled */
 514			return index;
 515		}
 516
 517		/* Security doesn't match */
 518		dev_dbg(adapter->dev, "info: %s: failed: index=%d "
 519		       "wpa_ie=%#x wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s EncMode"
 520		       "=%#x privacy=%#x\n",
 521		       __func__, index,
 522		       (bss_desc->bcn_wpa_ie) ?
 523		       (*(bss_desc->bcn_wpa_ie)).vend_hdr.
 524		       element_id : 0,
 525		       (bss_desc->bcn_rsn_ie) ?
 526		       (*(bss_desc->bcn_rsn_ie)).ieee_hdr.
 527		       element_id : 0,
 528		       (priv->sec_info.wep_status ==
 529				MWIFIEX_802_11_WEP_ENABLED) ? "e" : "d",
 530		       (priv->sec_info.wpa_enabled) ? "e" : "d",
 531		       (priv->sec_info.wpa2_enabled) ? "e" : "d",
 532		       priv->sec_info.encryption_mode, bss_desc->privacy);
 533		return -1;
 534	}
 535
 536	/* Mode doesn't match */
 537	return -1;
 538}
 539
 540/*
 541 * This function finds the best SSID in the scan list.
 542 *
 543 * It searches the scan table for the best SSID that also matches the current
 544 * adapter network preference (mode, security etc.).
 545 */
 546static s32
 547mwifiex_find_best_network_in_list(struct mwifiex_private *priv)
 548{
 549	struct mwifiex_adapter *adapter = priv->adapter;
 550	u32 mode = priv->bss_mode;
 551	s32 best_net = -1;
 552	s32 best_rssi = 0;
 553	u32 i;
 554
 555	dev_dbg(adapter->dev, "info: num of BSSIDs = %d\n",
 556				adapter->num_in_scan_table);
 557
 558	for (i = 0; i < adapter->num_in_scan_table; i++) {
 559		switch (mode) {
 560		case NL80211_IFTYPE_STATION:
 561		case NL80211_IFTYPE_ADHOC:
 562			if (mwifiex_is_network_compatible(priv, i, mode) >= 0) {
 563				if (SCAN_RSSI(adapter->scan_table[i].rssi) >
 564				    best_rssi) {
 565					best_rssi = SCAN_RSSI(adapter->
 566							  scan_table[i].rssi);
 567					best_net = i;
 568				}
 569			}
 570			break;
 571		case NL80211_IFTYPE_UNSPECIFIED:
 572		default:
 573			if (SCAN_RSSI(adapter->scan_table[i].rssi) >
 574			    best_rssi) {
 575				best_rssi = SCAN_RSSI(adapter->scan_table[i].
 576						      rssi);
 577				best_net = i;
 578			}
 579			break;
 580		}
 581	}
 582
 583	return best_net;
 584}
 585
 586/*
 587 * This function creates a channel list for the driver to scan, based
 588 * on region/band information.
 589 *
 590 * This routine is used for any scan that is not provided with a
 591 * specific channel list to scan.
 592 */
 593static void
 594mwifiex_scan_create_channel_list(struct mwifiex_private *priv,
 595				const struct mwifiex_user_scan_cfg
 596				*user_scan_in,
 597				struct mwifiex_chan_scan_param_set
 598				*scan_chan_list,
 599				u8 filtered_scan)
 600{
 601	enum ieee80211_band band;
 602	struct ieee80211_supported_band *sband;
 603	struct ieee80211_channel *ch;
 604	struct mwifiex_adapter *adapter = priv->adapter;
 605	int chan_idx = 0, i;
 606	u8 scan_type;
 607
 608	for (band = 0; (band < IEEE80211_NUM_BANDS) ; band++) {
 609
 610		if (!priv->wdev->wiphy->bands[band])
 611			continue;
 612
 613		sband = priv->wdev->wiphy->bands[band];
 614
 615		for (i = 0; (i < sband->n_channels) ; i++, chan_idx++) {
 616			ch = &sband->channels[i];
 617			if (ch->flags & IEEE80211_CHAN_DISABLED)
 618				continue;
 619			scan_chan_list[chan_idx].radio_type = band;
 620			scan_type = ch->flags & IEEE80211_CHAN_PASSIVE_SCAN;
 621			if (user_scan_in &&
 622				user_scan_in->chan_list[0].scan_time)
 623				scan_chan_list[chan_idx].max_scan_time =
 624					cpu_to_le16((u16) user_scan_in->
 625					chan_list[0].scan_time);
 626			else if (scan_type == MWIFIEX_SCAN_TYPE_PASSIVE)
 627				scan_chan_list[chan_idx].max_scan_time =
 628					cpu_to_le16(adapter->passive_scan_time);
 629			else
 630				scan_chan_list[chan_idx].max_scan_time =
 631					cpu_to_le16(adapter->active_scan_time);
 632			if (scan_type == MWIFIEX_SCAN_TYPE_PASSIVE)
 633				scan_chan_list[chan_idx].chan_scan_mode_bitmap
 634					|= MWIFIEX_PASSIVE_SCAN;
 635			else
 636				scan_chan_list[chan_idx].chan_scan_mode_bitmap
 637					&= ~MWIFIEX_PASSIVE_SCAN;
 638			scan_chan_list[chan_idx].chan_number =
 639							(u32) ch->hw_value;
 640			if (filtered_scan) {
 641				scan_chan_list[chan_idx].max_scan_time =
 642				cpu_to_le16(adapter->specific_scan_time);
 643				scan_chan_list[chan_idx].chan_scan_mode_bitmap
 644					|= MWIFIEX_DISABLE_CHAN_FILT;
 645			}
 646		}
 647
 648	}
 649}
 650
 651/*
 652 * This function constructs and sends multiple scan config commands to
 653 * the firmware.
 654 *
 655 * Previous routines in the code flow have created a scan command configuration
 656 * with any requested TLVs.  This function splits the channel TLV into maximum
 657 * channels supported per scan lists and sends the portion of the channel TLV,
 658 * along with the other TLVs, to the firmware.
 659 */
 660static int
 661mwifiex_scan_channel_list(struct mwifiex_private *priv,
 662			  u32 max_chan_per_scan, u8 filtered_scan,
 663			  struct mwifiex_scan_cmd_config *scan_cfg_out,
 664			  struct mwifiex_ie_types_chan_list_param_set
 665			  *chan_tlv_out,
 666			  struct mwifiex_chan_scan_param_set *scan_chan_list)
 667{
 668	int ret = 0;
 669	struct mwifiex_chan_scan_param_set *tmp_chan_list;
 670	struct mwifiex_chan_scan_param_set *start_chan;
 671
 672	u32 tlv_idx;
 673	u32 total_scan_time;
 674	u32 done_early;
 675
 676	if (!scan_cfg_out || !chan_tlv_out || !scan_chan_list) {
 677		dev_dbg(priv->adapter->dev,
 678			"info: Scan: Null detect: %p, %p, %p\n",
 679		       scan_cfg_out, chan_tlv_out, scan_chan_list);
 680		return -1;
 681	}
 682
 683	chan_tlv_out->header.type = cpu_to_le16(TLV_TYPE_CHANLIST);
 684
 685	/* Set the temp channel struct pointer to the start of the desired
 686	   list */
 687	tmp_chan_list = scan_chan_list;
 688
 689	/* Loop through the desired channel list, sending a new firmware scan
 690	   commands for each max_chan_per_scan channels (or for 1,6,11
 691	   individually if configured accordingly) */
 692	while (tmp_chan_list->chan_number) {
 693
 694		tlv_idx = 0;
 695		total_scan_time = 0;
 696		chan_tlv_out->header.len = 0;
 697		start_chan = tmp_chan_list;
 698		done_early = false;
 699
 700		/*
 701		 * Construct the Channel TLV for the scan command.  Continue to
 702		 * insert channel TLVs until:
 703		 *   - the tlv_idx hits the maximum configured per scan command
 704		 *   - the next channel to insert is 0 (end of desired channel
 705		 *     list)
 706		 *   - done_early is set (controlling individual scanning of
 707		 *     1,6,11)
 708		 */
 709		while (tlv_idx < max_chan_per_scan
 710		       && tmp_chan_list->chan_number && !done_early) {
 711
 712			dev_dbg(priv->adapter->dev,
 713				"info: Scan: Chan(%3d), Radio(%d),"
 714				" Mode(%d, %d), Dur(%d)\n",
 715			       tmp_chan_list->chan_number,
 716			       tmp_chan_list->radio_type,
 717			       tmp_chan_list->chan_scan_mode_bitmap
 718			       & MWIFIEX_PASSIVE_SCAN,
 719			       (tmp_chan_list->chan_scan_mode_bitmap
 720			       & MWIFIEX_DISABLE_CHAN_FILT) >> 1,
 721			       le16_to_cpu(tmp_chan_list->max_scan_time));
 722
 723			/* Copy the current channel TLV to the command being
 724			   prepared */
 725			memcpy(chan_tlv_out->chan_scan_param + tlv_idx,
 726			       tmp_chan_list,
 727			       sizeof(chan_tlv_out->chan_scan_param));
 728
 729			/* Increment the TLV header length by the size
 730			   appended */
 731			chan_tlv_out->header.len =
 732			cpu_to_le16(le16_to_cpu(chan_tlv_out->header.len) +
 733			(sizeof(chan_tlv_out->chan_scan_param)));
 734
 735			/*
 736			 * The tlv buffer length is set to the number of bytes
 737			 * of the between the channel tlv pointer and the start
 738			 * of the tlv buffer.  This compensates for any TLVs
 739			 * that were appended before the channel list.
 740			 */
 741			scan_cfg_out->tlv_buf_len = (u32) ((u8 *) chan_tlv_out -
 742							scan_cfg_out->tlv_buf);
 743
 744			/* Add the size of the channel tlv header and the data
 745			   length */
 746			scan_cfg_out->tlv_buf_len +=
 747				(sizeof(chan_tlv_out->header)
 748				 + le16_to_cpu(chan_tlv_out->header.len));
 749
 750			/* Increment the index to the channel tlv we are
 751			   constructing */
 752			tlv_idx++;
 753
 754			/* Count the total scan time per command */
 755			total_scan_time +=
 756				le16_to_cpu(tmp_chan_list->max_scan_time);
 757
 758			done_early = false;
 759
 760			/* Stop the loop if the *current* channel is in the
 761			   1,6,11 set and we are not filtering on a BSSID
 762			   or SSID. */
 763			if (!filtered_scan && (tmp_chan_list->chan_number == 1
 764				|| tmp_chan_list->chan_number == 6
 765				|| tmp_chan_list->chan_number == 11))
 766				done_early = true;
 767
 768			/* Increment the tmp pointer to the next channel to
 769			   be scanned */
 770			tmp_chan_list++;
 771
 772			/* Stop the loop if the *next* channel is in the 1,6,11
 773			   set.  This will cause it to be the only channel
 774			   scanned on the next interation */
 775			if (!filtered_scan && (tmp_chan_list->chan_number == 1
 776				|| tmp_chan_list->chan_number == 6
 777				|| tmp_chan_list->chan_number == 11))
 778				done_early = true;
 779		}
 780
 781		/* The total scan time should be less than scan command timeout
 782		   value */
 783		if (total_scan_time > MWIFIEX_MAX_TOTAL_SCAN_TIME) {
 784			dev_err(priv->adapter->dev, "total scan time %dms"
 785				" is over limit (%dms), scan skipped\n",
 786				total_scan_time, MWIFIEX_MAX_TOTAL_SCAN_TIME);
 787			ret = -1;
 788			break;
 789		}
 790
 791		priv->adapter->scan_channels = start_chan;
 792
 793		/* Send the scan command to the firmware with the specified
 794		   cfg */
 795		ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11_SCAN,
 796					     HostCmd_ACT_GEN_SET, 0,
 797					     scan_cfg_out);
 798		if (ret)
 799			break;
 800	}
 801
 802	if (ret)
 803		return -1;
 804
 805	return 0;
 806}
 807
 808/*
 809 * This function constructs a scan command configuration structure to use
 810 * in scan commands.
 811 *
 812 * Application layer or other functions can invoke network scanning
 813 * with a scan configuration supplied in a user scan configuration structure.
 814 * This structure is used as the basis of one or many scan command configuration
 815 * commands that are sent to the command processing module and eventually to the
 816 * firmware.
 817 *
 818 * This function creates a scan command configuration structure  based on the
 819 * following user supplied parameters (if present):
 820 *      - SSID filter
 821 *      - BSSID filter
 822 *      - Number of Probes to be sent
 823 *      - Channel list
 824 *
 825 * If the SSID or BSSID filter is not present, the filter is disabled/cleared.
 826 * If the number of probes is not set, adapter default setting is used.
 827 */
 828static void
 829mwifiex_scan_setup_scan_config(struct mwifiex_private *priv,
 830			       const struct mwifiex_user_scan_cfg *user_scan_in,
 831			       struct mwifiex_scan_cmd_config *scan_cfg_out,
 832			       struct mwifiex_ie_types_chan_list_param_set
 833			       **chan_list_out,
 834			       struct mwifiex_chan_scan_param_set
 835			       *scan_chan_list,
 836			       u8 *max_chan_per_scan, u8 *filtered_scan,
 837			       u8 *scan_current_only)
 838{
 839	struct mwifiex_adapter *adapter = priv->adapter;
 840	struct mwifiex_ie_types_num_probes *num_probes_tlv;
 841	struct mwifiex_ie_types_wildcard_ssid_params *wildcard_ssid_tlv;
 842	struct mwifiex_ie_types_rates_param_set *rates_tlv;
 843	const u8 zero_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
 844	u8 *tlv_pos;
 845	u32 num_probes;
 846	u32 ssid_len;
 847	u32 chan_idx;
 848	u32 scan_type;
 849	u16 scan_dur;
 850	u8 channel;
 851	u8 radio_type;
 852	u32 ssid_idx;
 853	u8 ssid_filter;
 854	u8 rates[MWIFIEX_SUPPORTED_RATES];
 855	u32 rates_size;
 856	struct mwifiex_ie_types_htcap *ht_cap;
 857
 858	/* The tlv_buf_len is calculated for each scan command.  The TLVs added
 859	   in this routine will be preserved since the routine that sends the
 860	   command will append channelTLVs at *chan_list_out.  The difference
 861	   between the *chan_list_out and the tlv_buf start will be used to
 862	   calculate the size of anything we add in this routine. */
 863	scan_cfg_out->tlv_buf_len = 0;
 864
 865	/* Running tlv pointer.  Assigned to chan_list_out at end of function
 866	   so later routines know where channels can be added to the command
 867	   buf */
 868	tlv_pos = scan_cfg_out->tlv_buf;
 869
 870	/* Initialize the scan as un-filtered; the flag is later set to TRUE
 871	   below if a SSID or BSSID filter is sent in the command */
 872	*filtered_scan = false;
 873
 874	/* Initialize the scan as not being only on the current channel.  If
 875	   the channel list is customized, only contains one channel, and is
 876	   the active channel, this is set true and data flow is not halted. */
 877	*scan_current_only = false;
 878
 879	if (user_scan_in) {
 880
 881		/* Default the ssid_filter flag to TRUE, set false under
 882		   certain wildcard conditions and qualified by the existence
 883		   of an SSID list before marking the scan as filtered */
 884		ssid_filter = true;
 885
 886		/* Set the BSS type scan filter, use Adapter setting if
 887		   unset */
 888		scan_cfg_out->bss_mode =
 889			(user_scan_in->bss_mode ? (u8) user_scan_in->
 890			 bss_mode : (u8) adapter->scan_mode);
 891
 892		/* Set the number of probes to send, use Adapter setting
 893		   if unset */
 894		num_probes =
 895			(user_scan_in->num_probes ? user_scan_in->
 896			 num_probes : adapter->scan_probes);
 897
 898		/*
 899		 * Set the BSSID filter to the incoming configuration,
 900		 * if non-zero.  If not set, it will remain disabled
 901		 * (all zeros).
 902		 */
 903		memcpy(scan_cfg_out->specific_bssid,
 904		       user_scan_in->specific_bssid,
 905		       sizeof(scan_cfg_out->specific_bssid));
 906
 907		for (ssid_idx = 0;
 908		     ((ssid_idx < ARRAY_SIZE(user_scan_in->ssid_list))
 909		      && (*user_scan_in->ssid_list[ssid_idx].ssid
 910			  || user_scan_in->ssid_list[ssid_idx].max_len));
 911		     ssid_idx++) {
 912
 913			ssid_len = strlen(user_scan_in->ssid_list[ssid_idx].
 914					  ssid) + 1;
 915
 916			wildcard_ssid_tlv =
 917				(struct mwifiex_ie_types_wildcard_ssid_params *)
 918				tlv_pos;
 919			wildcard_ssid_tlv->header.type =
 920				cpu_to_le16(TLV_TYPE_WILDCARDSSID);
 921			wildcard_ssid_tlv->header.len = cpu_to_le16(
 922				(u16) (ssid_len + sizeof(wildcard_ssid_tlv->
 923							 max_ssid_length)));
 924			wildcard_ssid_tlv->max_ssid_length =
 925				user_scan_in->ssid_list[ssid_idx].max_len;
 926
 927			memcpy(wildcard_ssid_tlv->ssid,
 928			       user_scan_in->ssid_list[ssid_idx].ssid,
 929			       ssid_len);
 930
 931			tlv_pos += (sizeof(wildcard_ssid_tlv->header)
 932				+ le16_to_cpu(wildcard_ssid_tlv->header.len));
 933
 934			dev_dbg(adapter->dev, "info: scan: ssid_list[%d]: %s, %d\n",
 935				ssid_idx, wildcard_ssid_tlv->ssid,
 936				wildcard_ssid_tlv->max_ssid_length);
 937
 938			/* Empty wildcard ssid with a maxlen will match many or
 939			   potentially all SSIDs (maxlen == 32), therefore do
 940			   not treat the scan as
 941			   filtered. */
 942			if (!ssid_len && wildcard_ssid_tlv->max_ssid_length)
 943				ssid_filter = false;
 944
 945		}
 946
 947		/*
 948		 *  The default number of channels sent in the command is low to
 949		 *  ensure the response buffer from the firmware does not
 950		 *  truncate scan results.  That is not an issue with an SSID
 951		 *  or BSSID filter applied to the scan results in the firmware.
 952		 */
 953		if ((ssid_idx && ssid_filter)
 954		    || memcmp(scan_cfg_out->specific_bssid, &zero_mac,
 955			      sizeof(zero_mac)))
 956			*filtered_scan = true;
 957	} else {
 958		scan_cfg_out->bss_mode = (u8) adapter->scan_mode;
 959		num_probes = adapter->scan_probes;
 960	}
 961
 962	/*
 963	 *  If a specific BSSID or SSID is used, the number of channels in the
 964	 *  scan command will be increased to the absolute maximum.
 965	 */
 966	if (*filtered_scan)
 967		*max_chan_per_scan = MWIFIEX_MAX_CHANNELS_PER_SPECIFIC_SCAN;
 968	else
 969		*max_chan_per_scan = MWIFIEX_CHANNELS_PER_SCAN_CMD;
 970
 971	/* If the input config or adapter has the number of Probes set,
 972	   add tlv */
 973	if (num_probes) {
 974
 975		dev_dbg(adapter->dev, "info: scan: num_probes = %d\n",
 976						num_probes);
 977
 978		num_probes_tlv = (struct mwifiex_ie_types_num_probes *) tlv_pos;
 979		num_probes_tlv->header.type = cpu_to_le16(TLV_TYPE_NUMPROBES);
 980		num_probes_tlv->header.len =
 981			cpu_to_le16(sizeof(num_probes_tlv->num_probes));
 982		num_probes_tlv->num_probes = cpu_to_le16((u16) num_probes);
 983
 984		tlv_pos += sizeof(num_probes_tlv->header) +
 985			le16_to_cpu(num_probes_tlv->header.len);
 986
 987	}
 988
 989	/* Append rates tlv */
 990	memset(rates, 0, sizeof(rates));
 991
 992	rates_size = mwifiex_get_supported_rates(priv, rates);
 993
 994	rates_tlv = (struct mwifiex_ie_types_rates_param_set *) tlv_pos;
 995	rates_tlv->header.type = cpu_to_le16(WLAN_EID_SUPP_RATES);
 996	rates_tlv->header.len = cpu_to_le16((u16) rates_size);
 997	memcpy(rates_tlv->rates, rates, rates_size);
 998	tlv_pos += sizeof(rates_tlv->header) + rates_size;
 999
1000	dev_dbg(adapter->dev, "info: SCAN_CMD: Rates size = %d\n", rates_size);
1001
1002	if (ISSUPP_11NENABLED(priv->adapter->fw_cap_info)
1003	    && (priv->adapter->config_bands & BAND_GN
1004		|| priv->adapter->config_bands & BAND_AN)) {
1005		ht_cap = (struct mwifiex_ie_types_htcap *) tlv_pos;
1006		memset(ht_cap, 0, sizeof(struct mwifiex_ie_types_htcap));
1007		ht_cap->header.type = cpu_to_le16(WLAN_EID_HT_CAPABILITY);
1008		ht_cap->header.len =
1009				cpu_to_le16(sizeof(struct ieee80211_ht_cap));
1010		radio_type =
1011			mwifiex_band_to_radio_type(priv->adapter->config_bands);
1012		mwifiex_fill_cap_info(priv, radio_type, ht_cap);
1013		tlv_pos += sizeof(struct mwifiex_ie_types_htcap);
1014	}
1015
1016	/* Append vendor specific IE TLV */
1017	mwifiex_cmd_append_vsie_tlv(priv, MWIFIEX_VSIE_MASK_SCAN, &tlv_pos);
1018
1019	/*
1020	 * Set the output for the channel TLV to the address in the tlv buffer
1021	 *   past any TLVs that were added in this function (SSID, num_probes).
1022	 *   Channel TLVs will be added past this for each scan command,
1023	 *   preserving the TLVs that were previously added.
1024	 */
1025	*chan_list_out =
1026		(struct mwifiex_ie_types_chan_list_param_set *) tlv_pos;
1027
1028	if (user_scan_in && user_scan_in->chan_list[0].chan_number) {
1029
1030		dev_dbg(adapter->dev, "info: Scan: Using supplied channel list\n");
1031
1032		for (chan_idx = 0;
1033		     chan_idx < MWIFIEX_USER_SCAN_CHAN_MAX
1034		     && user_scan_in->chan_list[chan_idx].chan_number;
1035		     chan_idx++) {
1036
1037			channel = user_scan_in->chan_list[chan_idx].chan_number;
1038			(scan_chan_list + chan_idx)->chan_number = channel;
1039
1040			radio_type =
1041				user_scan_in->chan_list[chan_idx].radio_type;
1042			(scan_chan_list + chan_idx)->radio_type = radio_type;
1043
1044			scan_type = user_scan_in->chan_list[chan_idx].scan_type;
1045
1046			if (scan_type == MWIFIEX_SCAN_TYPE_PASSIVE)
1047				(scan_chan_list +
1048				 chan_idx)->chan_scan_mode_bitmap
1049					|= MWIFIEX_PASSIVE_SCAN;
1050			else
1051				(scan_chan_list +
1052				 chan_idx)->chan_scan_mode_bitmap
1053					&= ~MWIFIEX_PASSIVE_SCAN;
1054
1055			if (user_scan_in->chan_list[chan_idx].scan_time) {
1056				scan_dur = (u16) user_scan_in->
1057					chan_list[chan_idx].scan_time;
1058			} else {
1059				if (scan_type == MWIFIEX_SCAN_TYPE_PASSIVE)
1060					scan_dur = adapter->passive_scan_time;
1061				else if (*filtered_scan)
1062					scan_dur = adapter->specific_scan_time;
1063				else
1064					scan_dur = adapter->active_scan_time;
1065			}
1066
1067			(scan_chan_list + chan_idx)->min_scan_time =
1068				cpu_to_le16(scan_dur);
1069			(scan_chan_list + chan_idx)->max_scan_time =
1070				cpu_to_le16(scan_dur);
1071		}
1072
1073		/* Check if we are only scanning the current channel */
1074		if ((chan_idx == 1)
1075		    && (user_scan_in->chan_list[0].chan_number
1076			== priv->curr_bss_params.bss_descriptor.channel)) {
1077			*scan_current_only = true;
1078			dev_dbg(adapter->dev,
1079				"info: Scan: Scanning current channel only\n");
1080		}
1081
1082	} else {
1083		dev_dbg(adapter->dev,
1084				"info: Scan: Creating full region channel list\n");
1085		mwifiex_scan_create_channel_list(priv, user_scan_in,
1086						 scan_chan_list,
1087						 *filtered_scan);
1088	}
1089}
1090
1091/*
1092 * This function inspects the scan response buffer for pointers to
1093 * expected TLVs.
1094 *
1095 * TLVs can be included at the end of the scan response BSS information.
1096 *
1097 * Data in the buffer is parsed pointers to TLVs that can potentially
1098 * be passed back in the response.
1099 */
1100static void
1101mwifiex_ret_802_11_scan_get_tlv_ptrs(struct mwifiex_adapter *adapter,
1102				     struct mwifiex_ie_types_data *tlv,
1103				     u32 tlv_buf_size, u32 req_tlv_type,
1104				     struct mwifiex_ie_types_data **tlv_data)
1105{
1106	struct mwifiex_ie_types_data *current_tlv;
1107	u32 tlv_buf_left;
1108	u32 tlv_type;
1109	u32 tlv_len;
1110
1111	current_tlv = tlv;
1112	tlv_buf_left = tlv_buf_size;
1113	*tlv_data = NULL;
1114
1115	dev_dbg(adapter->dev, "info: SCAN_RESP: tlv_buf_size = %d\n",
1116						tlv_buf_size);
1117
1118	while (tlv_buf_left >= sizeof(struct mwifiex_ie_types_header)) {
1119
1120		tlv_type = le16_to_cpu(current_tlv->header.type);
1121		tlv_len = le16_to_cpu(current_tlv->header.len);
1122
1123		if (sizeof(tlv->header) + tlv_len > tlv_buf_left) {
1124			dev_err(adapter->dev, "SCAN_RESP: TLV buffer corrupt\n");
1125			break;
1126		}
1127
1128		if (req_tlv_type == tlv_type) {
1129			switch (tlv_type) {
1130			case TLV_TYPE_TSFTIMESTAMP:
1131				dev_dbg(adapter->dev, "info: SCAN_RESP: TSF "
1132					"timestamp TLV, len = %d\n", tlv_len);
1133				*tlv_data = (struct mwifiex_ie_types_data *)
1134					current_tlv;
1135				break;
1136			case TLV_TYPE_CHANNELBANDLIST:
1137				dev_dbg(adapter->dev, "info: SCAN_RESP: channel"
1138					" band list TLV, len = %d\n", tlv_len);
1139				*tlv_data = (struct mwifiex_ie_types_data *)
1140					current_tlv;
1141				break;
1142			default:
1143				dev_err(adapter->dev,
1144					"SCAN_RESP: unhandled TLV = %d\n",
1145				       tlv_type);
1146				/* Give up, this seems corrupted */
1147				return;
1148			}
1149		}
1150
1151		if (*tlv_data)
1152			break;
1153
1154
1155		tlv_buf_left -= (sizeof(tlv->header) + tlv_len);
1156		current_tlv =
1157			(struct mwifiex_ie_types_data *) (current_tlv->data +
1158							  tlv_len);
1159
1160	}			/* while */
1161}
1162
1163/*
1164 * This function interprets a BSS scan response returned from the firmware.
1165 *
1166 * The various fixed fields and IEs are parsed and passed back for a BSS
1167 * probe response or beacon from scan command. Information is recorded as
1168 * needed in the scan table for that entry.
1169 *
1170 * The following IE types are recognized and parsed -
1171 *      - SSID
1172 *      - Supported rates
1173 *      - FH parameters set
1174 *      - DS parameters set
1175 *      - CF parameters set
1176 *      - IBSS parameters set
1177 *      - ERP information
1178 *      - Extended supported rates
1179 *      - Vendor specific (221)
1180 *      - RSN IE
1181 *      - WAPI IE
1182 *      - HT capability
1183 *      - HT operation
1184 *      - BSS Coexistence 20/40
1185 *      - Extended capability
1186 *      - Overlapping BSS scan parameters
1187 */
1188static int
1189mwifiex_interpret_bss_desc_with_ie(struct mwifiex_adapter *adapter,
1190				   struct mwifiex_bssdescriptor *bss_entry,
1191				   u8 **beacon_info, u32 *bytes_left)
1192{
1193	int ret = 0;
1194	u8 element_id;
1195	struct ieee_types_fh_param_set *fh_param_set;
1196	struct ieee_types_ds_param_set *ds_param_set;
1197	struct ieee_types_cf_param_set *cf_param_set;
1198	struct ieee_types_ibss_param_set *ibss_param_set;
1199	__le16 beacon_interval;
1200	__le16 capabilities;
1201	u8 *current_ptr;
1202	u8 *rate;
1203	u8 element_len;
1204	u16 total_ie_len;
1205	u8 bytes_to_copy;
1206	u8 rate_size;
1207	u16 beacon_size;
1208	u8 found_data_rate_ie;
1209	u32 bytes_left_for_current_beacon;
1210	struct ieee_types_vendor_specific *vendor_ie;
1211	const u8 wpa_oui[4] = { 0x00, 0x50, 0xf2, 0x01 };
1212	const u8 wmm_oui[4] = { 0x00, 0x50, 0xf2, 0x02 };
1213
1214	found_data_rate_ie = false;
1215	rate_size = 0;
1216	beacon_size = 0;
1217
1218	if (*bytes_left >= sizeof(beacon_size)) {
1219		/* Extract & convert beacon size from the command buffer */
1220		memcpy(&beacon_size, *beacon_info, sizeof(beacon_size));
1221		*bytes_left -= sizeof(beacon_size);
1222		*beacon_info += sizeof(beacon_size);
1223	}
1224
1225	if (!beacon_size || beacon_size > *bytes_left) {
1226		*beacon_info += *bytes_left;
1227		*bytes_left = 0;
1228		return -1;
1229	}
1230
1231	/* Initialize the current working beacon pointer for this BSS
1232	   iteration */
1233	current_ptr = *beacon_info;
1234
1235	/* Advance the return beacon pointer past the current beacon */
1236	*beacon_info += beacon_size;
1237	*bytes_left -= beacon_size;
1238
1239	bytes_left_for_current_beacon = beacon_size;
1240
1241	memcpy(bss_entry->mac_address, current_ptr, ETH_ALEN);
1242	dev_dbg(adapter->dev, "info: InterpretIE: AP MAC Addr: %pM\n",
1243						bss_entry->mac_address);
1244
1245	current_ptr += ETH_ALEN;
1246	bytes_left_for_current_beacon -= ETH_ALEN;
1247
1248	if (bytes_left_for_current_beacon < 12) {
1249		dev_err(adapter->dev, "InterpretIE: not enough bytes left\n");
1250		return -1;
1251	}
1252
1253	/*
1254	 * Next 4 fields are RSSI, time stamp, beacon interval,
1255	 *   and capability information
1256	 */
1257
1258	/* RSSI is 1 byte long */
1259	bss_entry->rssi = (s32) (*current_ptr);
1260	dev_dbg(adapter->dev, "info: InterpretIE: RSSI=%02X\n", *current_ptr);
1261	current_ptr += 1;
1262	bytes_left_for_current_beacon -= 1;
1263
1264	/*
1265	 *  The RSSI is not part of the beacon/probe response.  After we have
1266	 *    advanced current_ptr past the RSSI field, save the remaining
1267	 *    data for use at the application layer
1268	 */
1269	bss_entry->beacon_buf = current_ptr;
1270	bss_entry->beacon_buf_size = bytes_left_for_current_beacon;
1271
1272	/* Time stamp is 8 bytes long */
1273	memcpy(bss_entry->time_stamp, current_ptr, 8);
1274	current_ptr += 8;
1275	bytes_left_for_current_beacon -= 8;
1276
1277	/* Beacon interval is 2 bytes long */
1278	memcpy(&beacon_interval, current_ptr, 2);
1279	bss_entry->beacon_period = le16_to_cpu(beacon_interval);
1280	current_ptr += 2;
1281	bytes_left_for_current_beacon -= 2;
1282
1283	/* Capability information is 2 bytes long */
1284	memcpy(&capabilities, current_ptr, 2);
1285	dev_dbg(adapter->dev, "info: InterpretIE: capabilities=0x%X\n",
1286	       capabilities);
1287	bss_entry->cap_info_bitmap = le16_to_cpu(capabilities);
1288	current_ptr += 2;
1289	bytes_left_for_current_beacon -= 2;
1290
1291	/* Rest of the current buffer are IE's */
1292	dev_dbg(adapter->dev, "info: InterpretIE: IELength for this AP = %d\n",
1293	       bytes_left_for_current_beacon);
1294
1295	if (bss_entry->cap_info_bitmap & WLAN_CAPABILITY_PRIVACY) {
1296		dev_dbg(adapter->dev, "info: InterpretIE: AP WEP enabled\n");
1297		bss_entry->privacy = MWIFIEX_802_11_PRIV_FILTER_8021X_WEP;
1298	} else {
1299		bss_entry->privacy = MWIFIEX_802_11_PRIV_FILTER_ACCEPT_ALL;
1300	}
1301
1302	if (bss_entry->cap_info_bitmap & WLAN_CAPABILITY_IBSS)
1303		bss_entry->bss_mode = NL80211_IFTYPE_ADHOC;
1304	else
1305		bss_entry->bss_mode = NL80211_IFTYPE_STATION;
1306
1307
1308	/* Process variable IE */
1309	while (bytes_left_for_current_beacon >= 2) {
1310		element_id = *current_ptr;
1311		element_len = *(current_ptr + 1);
1312		total_ie_len = element_len + sizeof(struct ieee_types_header);
1313
1314		if (bytes_left_for_current_beacon < total_ie_len) {
1315			dev_err(adapter->dev, "err: InterpretIE: in processing"
1316				" IE, bytes left < IE length\n");
1317			bytes_left_for_current_beacon = 0;
1318			ret = -1;
1319			continue;
1320		}
1321		switch (element_id) {
1322		case WLAN_EID_SSID:
1323			bss_entry->ssid.ssid_len = element_len;
1324			memcpy(bss_entry->ssid.ssid, (current_ptr + 2),
1325			       element_len);
1326			dev_dbg(adapter->dev, "info: InterpretIE: ssid: %-32s\n",
1327			       bss_entry->ssid.ssid);
1328			break;
1329
1330		case WLAN_EID_SUPP_RATES:
1331			memcpy(bss_entry->data_rates, current_ptr + 2,
1332			       element_len);
1333			memcpy(bss_entry->supported_rates, current_ptr + 2,
1334			       element_len);
1335			rate_size = element_len;
1336			found_data_rate_ie = true;
1337			break;
1338
1339		case WLAN_EID_FH_PARAMS:
1340			fh_param_set =
1341				(struct ieee_types_fh_param_set *) current_ptr;
1342			memcpy(&bss_entry->phy_param_set.fh_param_set,
1343			       fh_param_set,
1344			       sizeof(struct ieee_types_fh_param_set));
1345			break;
1346
1347		case WLAN_EID_DS_PARAMS:
1348			ds_param_set =
1349				(struct ieee_types_ds_param_set *) current_ptr;
1350
1351			bss_entry->channel = ds_param_set->current_chan;
1352
1353			memcpy(&bss_entry->phy_param_set.ds_param_set,
1354			       ds_param_set,
1355			       sizeof(struct ieee_types_ds_param_set));
1356			break;
1357
1358		case WLAN_EID_CF_PARAMS:
1359			cf_param_set =
1360				(struct ieee_types_cf_param_set *) current_ptr;
1361			memcpy(&bss_entry->ss_param_set.cf_param_set,
1362			       cf_param_set,
1363			       sizeof(struct ieee_types_cf_param_set));
1364			break;
1365
1366		case WLAN_EID_IBSS_PARAMS:
1367			ibss_param_set =
1368				(struct ieee_types_ibss_param_set *)
1369				current_ptr;
1370			memcpy(&bss_entry->ss_param_set.ibss_param_set,
1371			       ibss_param_set,
1372			       sizeof(struct ieee_types_ibss_param_set));
1373			break;
1374
1375		case WLAN_EID_ERP_INFO:
1376			bss_entry->erp_flags = *(current_ptr + 2);
1377			break;
1378
1379		case WLAN_EID_EXT_SUPP_RATES:
1380			/*
1381			 * Only process extended supported rate
1382			 * if data rate is already found.
1383			 * Data rate IE should come before
1384			 * extended supported rate IE
1385			 */
1386			if (found_data_rate_ie) {
1387				if ((element_len + rate_size) >
1388				    MWIFIEX_SUPPORTED_RATES)
1389					bytes_to_copy =
1390						(MWIFIEX_SUPPORTED_RATES -
1391						 rate_size);
1392				else
1393					bytes_to_copy = element_len;
1394
1395				rate = (u8 *) bss_entry->data_rates;
1396				rate += rate_size;
1397				memcpy(rate, current_ptr + 2, bytes_to_copy);
1398
1399				rate = (u8 *) bss_entry->supported_rates;
1400				rate += rate_size;
1401				memcpy(rate, current_ptr + 2, bytes_to_copy);
1402			}
1403			break;
1404
1405		case WLAN_EID_VENDOR_SPECIFIC:
1406			vendor_ie = (struct ieee_types_vendor_specific *)
1407					current_ptr;
1408
1409			if (!memcmp
1410			    (vendor_ie->vend_hdr.oui, wpa_oui,
1411			     sizeof(wpa_oui))) {
1412				bss_entry->bcn_wpa_ie =
1413					(struct ieee_types_vendor_specific *)
1414					current_ptr;
1415				bss_entry->wpa_offset = (u16) (current_ptr -
1416							bss_entry->beacon_buf);
1417			} else if (!memcmp(vendor_ie->vend_hdr.oui, wmm_oui,
1418				    sizeof(wmm_oui))) {
1419				if (total_ie_len ==
1420				    sizeof(struct ieee_types_wmm_parameter)
1421				    || total_ie_len ==
1422				    sizeof(struct ieee_types_wmm_info))
1423					/*
1424					 * Only accept and copy the WMM IE if
1425					 * it matches the size expected for the
1426					 * WMM Info IE or the WMM Parameter IE.
1427					 */
1428					memcpy((u8 *) &bss_entry->wmm_ie,
1429					       current_ptr, total_ie_len);
1430			}
1431			break;
1432		case WLAN_EID_RSN:
1433			bss_entry->bcn_rsn_ie =
1434				(struct ieee_types_generic *) current_ptr;
1435			bss_entry->rsn_offset = (u16) (current_ptr -
1436							bss_entry->beacon_buf);
1437			break;
1438		case WLAN_EID_BSS_AC_ACCESS_DELAY:
1439			bss_entry->bcn_wapi_ie =
1440				(struct ieee_types_generic *) current_ptr;
1441			bss_entry->wapi_offset = (u16) (current_ptr -
1442							bss_entry->beacon_buf);
1443			break;
1444		case WLAN_EID_HT_CAPABILITY:
1445			bss_entry->bcn_ht_cap = (struct ieee80211_ht_cap *)
1446					(current_ptr +
1447					sizeof(struct ieee_types_header));
1448			bss_entry->ht_cap_offset = (u16) (current_ptr +
1449					sizeof(struct ieee_types_header) -
1450					bss_entry->beacon_buf);
1451			break;
1452		case WLAN_EID_HT_INFORMATION:
1453			bss_entry->bcn_ht_info = (struct ieee80211_ht_info *)
1454					(current_ptr +
1455					sizeof(struct ieee_types_header));
1456			bss_entry->ht_info_offset = (u16) (current_ptr +
1457					sizeof(struct ieee_types_header) -
1458					bss_entry->beacon_buf);
1459			break;
1460		case WLAN_EID_BSS_COEX_2040:
1461			bss_entry->bcn_bss_co_2040 = (u8 *) (current_ptr +
1462					sizeof(struct ieee_types_header));
1463			bss_entry->bss_co_2040_offset = (u16) (current_ptr +
1464					sizeof(struct ieee_types_header) -
1465						bss_entry->beacon_buf);
1466			break;
1467		case WLAN_EID_EXT_CAPABILITY:
1468			bss_entry->bcn_ext_cap = (u8 *) (current_ptr +
1469					sizeof(struct ieee_types_header));
1470			bss_entry->ext_cap_offset = (u16) (current_ptr +
1471					sizeof(struct ieee_types_header) -
1472					bss_entry->beacon_buf);
1473			break;
1474		case WLAN_EID_OVERLAP_BSS_SCAN_PARAM:
1475			bss_entry->bcn_obss_scan =
1476				(struct ieee_types_obss_scan_param *)
1477				current_ptr;
1478			bss_entry->overlap_bss_offset = (u16) (current_ptr -
1479							bss_entry->beacon_buf);
1480			break;
1481		default:
1482			break;
1483		}
1484
1485		current_ptr += element_len + 2;
1486
1487		/* Need to account for IE ID and IE Len */
1488		bytes_left_for_current_beacon -= (element_len + 2);
1489
1490	}	/* while (bytes_left_for_current_beacon > 2) */
1491	return ret;
1492}
1493
1494/*
1495 * This function adjusts the pointers used in beacon buffers to reflect
1496 * shifts.
1497 *
1498 * The memory allocated for beacon buffers is of fixed sizes where all the
1499 * saved beacons must be stored. New beacons are added in the free portion
1500 * of this memory, space permitting; while duplicate beacon buffers are
1501 * placed at the same start location. However, since duplicate beacon
1502 * buffers may not match the size of the old one, all the following buffers
1503 * in the memory must be shifted to either make space, or to fill up freed
1504 * up space.
1505 *
1506 * This function is used to update the beacon buffer pointers that are past
1507 * an existing beacon buffer that is updated with a new one of different
1508 * size. The pointers are shifted by a fixed amount, either forward or
1509 * backward.
1510 *
1511 * the following pointers in every affected beacon buffers are changed, if
1512 * present -
1513 *      - WPA IE pointer
1514 *      - RSN IE pointer
1515 *      - WAPI IE pointer
1516 *      - HT capability IE pointer
1517 *      - HT information IE pointer
1518 *      - BSS coexistence 20/40 IE pointer
1519 *      - Extended capability IE pointer
1520 *      - Overlapping BSS scan parameter IE pointer
1521 */
1522static void
1523mwifiex_adjust_beacon_buffer_ptrs(struct mwifiex_private *priv, u8 advance,
1524				  u8 *bcn_store, u32 rem_bcn_size,
1525				  u32 num_of_ent)
1526{
1527	struct mwifiex_adapter *adapter = priv->adapter;
1528	u32 adj_idx;
1529	for (adj_idx = 0; adj_idx < num_of_ent; adj_idx++) {
1530		if (adapter->scan_table[adj_idx].beacon_buf > bcn_store) {
1531
1532			if (advance)
1533				adapter->scan_table[adj_idx].beacon_buf +=
1534					rem_bcn_size;
1535			else
1536				adapter->scan_table[adj_idx].beacon_buf -=
1537					rem_bcn_size;
1538
1539			if (adapter->scan_table[adj_idx].bcn_wpa_ie)
1540				adapter->scan_table[adj_idx].bcn_wpa_ie =
1541				(struct ieee_types_vendor_specific *)
1542				(adapter->scan_table[adj_idx].beacon_buf +
1543				 adapter->scan_table[adj_idx].wpa_offset);
1544			if (adapter->scan_table[adj_idx].bcn_rsn_ie)
1545				adapter->scan_table[adj_idx].bcn_rsn_ie =
1546				(struct ieee_types_generic *)
1547				(adapter->scan_table[adj_idx].beacon_buf +
1548				 adapter->scan_table[adj_idx].rsn_offset);
1549			if (adapter->scan_table[adj_idx].bcn_wapi_ie)
1550				adapter->scan_table[adj_idx].bcn_wapi_ie =
1551				(struct ieee_types_generic *)
1552				(adapter->scan_table[adj_idx].beacon_buf +
1553				 adapter->scan_table[adj_idx].wapi_offset);
1554			if (adapter->scan_table[adj_idx].bcn_ht_cap)
1555				adapter->scan_table[adj_idx].bcn_ht_cap =
1556				(struct ieee80211_ht_cap *)
1557				(adapter->scan_table[adj_idx].beacon_buf +
1558				 adapter->scan_table[adj_idx].ht_cap_offset);
1559
1560			if (adapter->scan_table[adj_idx].bcn_ht_info)
1561				adapter->scan_table[adj_idx].bcn_ht_info =
1562				(struct ieee80211_ht_info *)
1563				(adapter->scan_table[adj_idx].beacon_buf +
1564				 adapter->scan_table[adj_idx].ht_info_offset);
1565			if (adapter->scan_table[adj_idx].bcn_bss_co_2040)
1566				adapter->scan_table[adj_idx].bcn_bss_co_2040 =
1567				(u8 *)
1568				(adapter->scan_table[adj_idx].beacon_buf +
1569			       adapter->scan_table[adj_idx].bss_co_2040_offset);
1570			if (adapter->scan_table[adj_idx].bcn_ext_cap)
1571				adapter->scan_table[adj_idx].bcn_ext_cap =
1572				(u8 *)
1573				(adapter->scan_table[adj_idx].beacon_buf +
1574				 adapter->scan_table[adj_idx].ext_cap_offset);
1575			if (adapter->scan_table[adj_idx].bcn_obss_scan)
1576				adapter->scan_table[adj_idx].bcn_obss_scan =
1577				(struct ieee_types_obss_scan_param *)
1578				(adapter->scan_table[adj_idx].beacon_buf +
1579			       adapter->scan_table[adj_idx].overlap_bss_offset);
1580		}
1581	}
1582}
1583
1584/*
1585 * This function updates the pointers used in beacon buffer for given bss
1586 * descriptor to reflect shifts
1587 *
1588 * Following pointers are updated
1589 *      - WPA IE pointer
1590 *      - RSN IE pointer
1591 *      - WAPI IE pointer
1592 *      - HT capability IE pointer
1593 *      - HT information IE pointer
1594 *      - BSS coexistence 20/40 IE pointer
1595 *      - Extended capability IE pointer
1596 *      - Overlapping BSS scan parameter IE pointer
1597 */
1598static void
1599mwifiex_update_beacon_buffer_ptrs(struct mwifiex_bssdescriptor *beacon)
1600{
1601	if (beacon->bcn_wpa_ie)
1602		beacon->bcn_wpa_ie = (struct ieee_types_vendor_specific *)
1603			(beacon->beacon_buf + beacon->wpa_offset);
1604	if (beacon->bcn_rsn_ie)
1605		beacon->bcn_rsn_ie = (struct ieee_types_generic *)
1606			(beacon->beacon_buf + beacon->rsn_offset);
1607	if (beacon->bcn_wapi_ie)
1608		beacon->bcn_wapi_ie = (struct ieee_types_generic *)
1609			(beacon->beacon_buf + beacon->wapi_offset);
1610	if (beacon->bcn_ht_cap)
1611		beacon->bcn_ht_cap = (struct ieee80211_ht_cap *)
1612			(beacon->beacon_buf + beacon->ht_cap_offset);
1613	if (beacon->bcn_ht_info)
1614		beacon->bcn_ht_info = (struct ieee80211_ht_info *)
1615			(beacon->beacon_buf + beacon->ht_info_offset);
1616	if (beacon->bcn_bss_co_2040)
1617		beacon->bcn_bss_co_2040 = (u8 *) (beacon->beacon_buf +
1618			beacon->bss_co_2040_offset);
1619	if (beacon->bcn_ext_cap)
1620		beacon->bcn_ext_cap = (u8 *) (beacon->beacon_buf +
1621			beacon->ext_cap_offset);
1622	if (beacon->bcn_obss_scan)
1623		beacon->bcn_obss_scan = (struct ieee_types_obss_scan_param *)
1624			(beacon->beacon_buf + beacon->overlap_bss_offset);
1625}
1626
1627/*
1628 * This function stores a beacon or probe response for a BSS returned
1629 * in the scan.
1630 *
1631 * This stores a new scan response or an update for a previous scan response.
1632 * New entries need to verify that they do not exceed the total amount of
1633 * memory allocated for the table.
1634 *
1635 * Replacement entries need to take into consideration the amount of space
1636 * currently allocated for the beacon/probe response and adjust the entry
1637 * as needed.
1638 *
1639 * A small amount of extra pad (SCAN_BEACON_ENTRY_PAD) is generally reserved
1640 * for an entry in case it is a beacon since a probe response for the
1641 * network will by larger per the standard.  This helps to reduce the
1642 * amount of memory copying to fit a new probe response into an entry
1643 * already occupied by a network's previously stored beacon.
1644 */
1645static void
1646mwifiex_ret_802_11_scan_store_beacon(struct mwifiex_private *priv,
1647				     u32 beacon_idx, u32 num_of_ent,
1648				     struct mwifiex_bssdescriptor *new_beacon)
1649{
1650	struct mwifiex_adapter *adapter = priv->adapter;
1651	u8 *bcn_store;
1652	u32 new_bcn_size;
1653	u32 old_bcn_size;
1654	u32 bcn_space;
1655
1656	if (adapter->scan_table[beacon_idx].beacon_buf) {
1657
1658		new_bcn_size = new_beacon->beacon_buf_size;
1659		old_bcn_size = adapter->scan_table[beacon_idx].beacon_buf_size;
1660		bcn_space = adapter->scan_table[beacon_idx].beacon_buf_size_max;
1661		bcn_store = adapter->scan_table[beacon_idx].beacon_buf;
1662
1663		/* Set the max to be the same as current entry unless changed
1664		   below */
1665		new_beacon->beacon_buf_size_max = bcn_space;
1666		if (new_bcn_size == old_bcn_size) {
1667			/*
1668			 * Beacon is the same size as the previous entry.
1669			 *   Replace the previous contents with the scan result
1670			 */
1671			memcpy(bcn_store, new_beacon->beacon_buf,
1672			       new_beacon->beacon_buf_size);
1673
1674		} else if (new_bcn_size <= bcn_space) {
1675			/*
1676			 * New beacon size will fit in the amount of space
1677			 *   we have previously allocated for it
1678			 */
1679
1680			/* Copy the new beacon buffer entry over the old one */
1681			memcpy(bcn_store, new_beacon->beacon_buf, new_bcn_size);
1682
1683			/*
1684			 *  If the old beacon size was less than the maximum
1685			 *  we had alloted for the entry, and the new entry
1686			 *  is even smaller, reset the max size to the old
1687			 *  beacon entry and compress the storage space
1688			 *  (leaving a new pad space of (old_bcn_size -
1689			 *  new_bcn_size).
1690			 */
1691			if (old_bcn_size < bcn_space
1692			    && new_bcn_size <= old_bcn_size) {
1693				/*
1694				 * Old Beacon size is smaller than the alloted
1695				 * storage size. Shrink the alloted storage
1696				 * space.
1697				 */
1698				dev_dbg(adapter->dev, "info: AppControl:"
1699					" smaller duplicate beacon "
1700				       "(%d), old = %d, new = %d, space = %d,"
1701				       "left = %d\n",
1702				       beacon_idx, old_bcn_size, new_bcn_size,
1703				       bcn_space,
1704				       (int)(sizeof(adapter->bcn_buf) -
1705					(adapter->bcn_buf_end -
1706					 adapter->bcn_buf)));
1707
1708				/*
1709				 *  memmove (since the memory overlaps) the
1710				 *  data after the beacon we just stored to the
1711				 *  end of the current beacon.  This cleans up
1712				 *  any unused space the old larger beacon was
1713				 *  using in the buffer
1714				 */
1715				memmove(bcn_store + old_bcn_size,
1716					bcn_store + bcn_space,
1717					adapter->bcn_buf_end - (bcn_store +
1718								   bcn_space));
1719
1720				/*
1721				 * Decrement the end pointer by the difference
1722				 * between the old larger size and the new
1723				 * smaller size since we are using less space
1724				 * due to the new beacon being smaller
1725				 */
1726				adapter->bcn_buf_end -=
1727					(bcn_space - old_bcn_size);
1728
1729				/* Set the maximum storage size to the old
1730				   beacon size */
1731				new_beacon->beacon_buf_size_max = old_bcn_size;
1732
1733				/* Adjust beacon buffer pointers that are past
1734				   the current */
1735				mwifiex_adjust_beacon_buffer_ptrs(priv, 0,
1736					bcn_store, (bcn_space - old_bcn_size),
1737					num_of_ent);
1738			}
1739		} else if (adapter->bcn_buf_end + (new_bcn_size - bcn_space)
1740			   < (adapter->bcn_buf + sizeof(adapter->bcn_buf))) {
1741			/*
1742			 * Beacon is larger than space previously allocated
1743			 * (bcn_space) and there is enough space left in the
1744			 * beaconBuffer to store the additional data
1745			 */
1746			dev_dbg(adapter->dev, "info: AppControl:"
1747				" larger duplicate beacon (%d), "
1748			       "old = %d, new = %d, space = %d, left = %d\n",
1749			       beacon_idx, old_bcn_size, new_bcn_size,
1750			       bcn_space,
1751			       (int)(sizeof(adapter->bcn_buf) -
1752				(adapter->bcn_buf_end -
1753				 adapter->bcn_buf)));
1754
1755			/*
1756			 * memmove (since the memory overlaps) the data
1757			 *  after the beacon we just stored to the end of
1758			 *  the current beacon.  This moves the data for
1759			 *  the beacons after this further in memory to
1760			 *  make space for the new larger beacon we are
1761			 *  about to copy in.
1762			 */
1763			memmove(bcn_store + new_bcn_size,
1764				bcn_store + bcn_space,
1765				adapter->bcn_buf_end - (bcn_store + bcn_space));
1766
1767			/* Copy the new beacon buffer entry over the old one */
1768			memcpy(bcn_store, new_beacon->beacon_buf, new_bcn_size);
1769
1770			/* Move the beacon end pointer by the amount of new
1771			   beacon data we are adding */
1772			adapter->bcn_buf_end += (new_bcn_size - bcn_space);
1773
1774			/*
1775			 * This entry is bigger than the alloted max space
1776			 *  previously reserved.  Increase the max space to
1777			 *  be equal to the new beacon size
1778			 */
1779			new_beacon->beacon_buf_size_max = new_bcn_size;
1780
1781			/* Adjust beacon buffer pointers that are past the
1782			   current */
1783			mwifiex_adjust_beacon_buffer_ptrs(priv, 1, bcn_store,
1784						(new_bcn_size - bcn_space),
1785						num_of_ent);
1786		} else {
1787			/*
1788			 * Beacon is larger than the previously allocated space,
1789			 * but there is not enough free space to store the
1790			 * additional data.
1791			 */
1792			dev_err(adapter->dev, "AppControl: larger duplicate "
1793				" beacon (%d), old = %d new = %d, space = %d,"
1794				" left = %d\n", beacon_idx, old_bcn_size,
1795				new_bcn_size, bcn_space,
1796				(int)(sizeof(adapter->bcn_buf) -
1797				(adapter->bcn_buf_end - adapter->bcn_buf)));
1798
1799			/* Storage failure, keep old beacon intact */
1800			new_beacon->beacon_buf_size = old_bcn_size;
1801			if (new_beacon->bcn_wpa_ie)
1802				new_beacon->wpa_offset =
1803					adapter->scan_table[beacon_idx].
1804					wpa_offset;
1805			if (new_beacon->bcn_rsn_ie)
1806				new_beacon->rsn_offset =
1807					adapter->scan_table[beacon_idx].
1808					rsn_offset;
1809			if (new_beacon->bcn_wapi_ie)
1810				new_beacon->wapi_offset =
1811					adapter->scan_table[beacon_idx].
1812					wapi_offset;
1813			if (new_beacon->bcn_ht_cap)
1814				new_beacon->ht_cap_offset =
1815					adapter->scan_table[beacon_idx].
1816					ht_cap_offset;
1817			if (new_beacon->bcn_ht_info)
1818				new_beacon->ht_info_offset =
1819					adapter->scan_table[beacon_idx].
1820					ht_info_offset;
1821			if (new_beacon->bcn_bss_co_2040)
1822				new_beacon->bss_co_2040_offset =
1823					adapter->scan_table[beacon_idx].
1824					bss_co_2040_offset;
1825			if (new_beacon->bcn_ext_cap)
1826				new_beacon->ext_cap_offset =
1827					adapter->scan_table[beacon_idx].
1828					ext_cap_offset;
1829			if (new_beacon->bcn_obss_scan)
1830				new_beacon->overlap_bss_offset =
1831					adapter->scan_table[beacon_idx].
1832					overlap_bss_offset;
1833		}
1834		/* Point the new entry to its permanent storage space */
1835		new_beacon->beacon_buf = bcn_store;
1836		mwifiex_update_beacon_buffer_ptrs(new_beacon);
1837	} else {
1838		/*
1839		 * No existing beacon data exists for this entry, check to see
1840		 *   if we can fit it in the remaining space
1841		 */
1842		if (adapter->bcn_buf_end + new_beacon->beacon_buf_size +
1843		    SCAN_BEACON_ENTRY_PAD < (adapter->bcn_buf +
1844					     sizeof(adapter->bcn_buf))) {
1845
1846			/*
1847			 * Copy the beacon buffer data from the local entry to
1848			 * the adapter dev struct buffer space used to store
1849			 * the raw beacon data for each entry in the scan table
1850			 */
1851			memcpy(adapter->bcn_buf_end, new_beacon->beacon_buf,
1852			       new_beacon->beacon_buf_size);
1853
1854			/* Update the beacon ptr to point to the table save
1855			   area */
1856			new_beacon->beacon_buf = adapter->bcn_buf_end;
1857			new_beacon->beacon_buf_size_max =
1858				(new_beacon->beacon_buf_size +
1859				 SCAN_BEACON_ENTRY_PAD);
1860
1861			mwifiex_update_beacon_buffer_ptrs(new_beacon);
1862
1863			/* Increment the end pointer by the size reserved */
1864			adapter->bcn_buf_end += new_beacon->beacon_buf_size_max;
1865
1866			dev_dbg(adapter->dev, "info: AppControl: beacon[%02d]"
1867				" sz=%03d, used = %04d, left = %04d\n",
1868			       beacon_idx,
1869			       new_beacon->beacon_buf_size,
1870			       (int)(adapter->bcn_buf_end - adapter->bcn_buf),
1871			       (int)(sizeof(adapter->bcn_buf) -
1872				(adapter->bcn_buf_end -
1873				 adapter->bcn_buf)));
1874		} else {
1875			/* No space for new beacon */
1876			dev_dbg(adapter->dev, "info: AppControl: no space for"
1877				" beacon (%d): %pM sz=%03d, left=%03d\n",
1878			       beacon_idx, new_beacon->mac_address,
1879			       new_beacon->beacon_buf_size,
1880			       (int)(sizeof(adapter->bcn_buf) -
1881				(adapter->bcn_buf_end -
1882				 adapter->bcn_buf)));
1883
1884			/* Storage failure; clear storage records for this
1885			   bcn */
1886			new_beacon->beacon_buf = NULL;
1887			new_beacon->beacon_buf_size = 0;
1888			new_beacon->beacon_buf_size_max = 0;
1889			new_beacon->bcn_wpa_ie = NULL;
1890			new_beacon->wpa_offset = 0;
1891			new_beacon->bcn_rsn_ie = NULL;
1892			new_beacon->rsn_offset = 0;
1893			new_beacon->bcn_wapi_ie = NULL;
1894			new_beacon->wapi_offset = 0;
1895			new_beacon->bcn_ht_cap = NULL;
1896			new_beacon->ht_cap_offset = 0;
1897			new_beacon->bcn_ht_info = NULL;
1898			new_beacon->ht_info_offset = 0;
1899			new_beacon->bcn_bss_co_2040 = NULL;
1900			new_beacon->bss_co_2040_offset = 0;
1901			new_beacon->bcn_ext_cap = NULL;
1902			new_beacon->ext_cap_offset = 0;
1903			new_beacon->bcn_obss_scan = NULL;
1904			new_beacon->overlap_bss_offset = 0;
1905		}
1906	}
1907}
1908
1909/*
1910 * This function restores a beacon buffer of the current BSS descriptor.
1911 */
1912static void mwifiex_restore_curr_bcn(struct mwifiex_private *priv)
1913{
1914	struct mwifiex_adapter *adapter = priv->adapter;
1915	struct mwifiex_bssdescriptor *curr_bss =
1916		&priv->curr_bss_params.bss_descriptor;
1917	unsigned long flags;
1918
1919	if (priv->curr_bcn_buf &&
1920	    ((adapter->bcn_buf_end + priv->curr_bcn_size) <
1921	     (adapter->bcn_buf + sizeof(adapter->bcn_buf)))) {
1922		spin_lock_irqsave(&priv->curr_bcn_buf_lock, flags);
1923
1924		/* restore the current beacon buffer */
1925		memcpy(adapter->bcn_buf_end, priv->curr_bcn_buf,
1926		       priv->curr_bcn_size);
1927		curr_bss->beacon_buf = adapter->bcn_buf_end;
1928		curr_bss->beacon_buf_size = priv->curr_bcn_size;
1929		adapter->bcn_buf_end += priv->curr_bcn_size;
1930
1931		/* adjust the pointers in the current BSS descriptor */
1932		if (curr_bss->bcn_wpa_ie)
1933			curr_bss->bcn_wpa_ie =
1934				(struct ieee_types_vendor_specific *)
1935				(curr_bss->beacon_buf +
1936				 curr_bss->wpa_offset);
1937
1938		if (curr_bss->bcn_rsn_ie)
1939			curr_bss->bcn_rsn_ie = (struct ieee_types_generic *)
1940				(curr_bss->beacon_buf +
1941				 curr_bss->rsn_offset);
1942
1943		if (curr_bss->bcn_ht_cap)
1944			curr_bss->bcn_ht_cap = (struct ieee80211_ht_cap *)
1945				(curr_bss->beacon_buf +
1946				 curr_bss->ht_cap_offset);
1947
1948		if (curr_bss->bcn_ht_info)
1949			curr_bss->bcn_ht_info = (struct ieee80211_ht_info *)
1950				(curr_bss->beacon_buf +
1951				 curr_bss->ht_info_offset);
1952
1953		if (curr_bss->bcn_bss_co_2040)
1954			curr_bss->bcn_bss_co_2040 =
1955				(u8 *) (curr_bss->beacon_buf +
1956				 curr_bss->bss_co_2040_offset);
1957
1958		if (curr_bss->bcn_ext_cap)
1959			curr_bss->bcn_ext_cap = (u8 *) (curr_bss->beacon_buf +
1960				 curr_bss->ext_cap_offset);
1961
1962		if (curr_bss->bcn_obss_scan)
1963			curr_bss->bcn_obss_scan =
1964				(struct ieee_types_obss_scan_param *)
1965				(curr_bss->beacon_buf +
1966				 curr_bss->overlap_bss_offset);
1967
1968		spin_unlock_irqrestore(&priv->curr_bcn_buf_lock, flags);
1969
1970		dev_dbg(adapter->dev, "info: current beacon restored %d\n",
1971		       priv->curr_bcn_size);
1972	} else {
1973		dev_warn(adapter->dev,
1974			"curr_bcn_buf not saved or bcn_buf has no space\n");
1975	}
1976}
1977
1978/*
1979 * This function post processes the scan table after a new scan command has
1980 * completed.
1981 *
1982 * It inspects each entry of the scan table and tries to find an entry that
1983 * matches with our current associated/joined network from the scan. If
1984 * one is found, the stored copy of the BSS descriptor of our current network
1985 * is updated.
1986 *
1987 * It also debug dumps the current scan table contents after processing is over.
1988 */
1989static void
1990mwifiex_process_scan_results(struct mwifiex_private *priv)
1991{
1992	struct mwifiex_adapter *adapter = priv->adapter;
1993	s32 j;
1994	u32 i;
1995	unsigned long flags;
1996
1997	if (priv->media_connected) {
1998
1999		j = mwifiex_find_ssid_in_list(priv, &priv->curr_bss_params.
2000					      bss_descriptor.ssid,
2001					      priv->curr_bss_params.
2002					      bss_descriptor.mac_address,
2003					      priv->bss_mode);
2004
2005		if (j >= 0) {
2006			spin_lock_irqsave(&priv->curr_bcn_buf_lock, flags);
2007			priv->curr_bss_params.bss_descriptor.bcn_wpa_ie = NULL;
2008			priv->curr_bss_params.bss_descriptor.wpa_offset = 0;
2009			priv->curr_bss_params.bss_descriptor.bcn_rsn_ie = NULL;
2010			priv->curr_bss_params.bss_descriptor.rsn_offset = 0;
2011			priv->curr_bss_params.bss_descriptor.bcn_wapi_ie = NULL;
2012			priv->curr_bss_params.bss_descriptor.wapi_offset = 0;
2013			priv->curr_bss_params.bss_descriptor.bcn_ht_cap = NULL;
2014			priv->curr_bss_params.bss_descriptor.ht_cap_offset =
2015				0;
2016			priv->curr_bss_params.bss_descriptor.bcn_ht_info = NULL;
2017			priv->curr_bss_params.bss_descriptor.ht_info_offset =
2018				0;
2019			priv->curr_bss_params.bss_descriptor.bcn_bss_co_2040 =
2020				NULL;
2021			priv->curr_bss_params.bss_descriptor.
2022				bss_co_2040_offset = 0;
2023			priv->curr_bss_params.bss_descriptor.bcn_ext_cap = NULL;
2024			priv->curr_bss_params.bss_descriptor.ext_cap_offset = 0;
2025			priv->curr_bss_params.bss_descriptor.
2026				bcn_obss_scan = NULL;
2027			priv->curr_bss_params.bss_descriptor.
2028				overlap_bss_offset = 0;
2029			priv->curr_bss_params.bss_descriptor.beacon_buf = NULL;
2030			priv->curr_bss_params.bss_descriptor.beacon_buf_size =
2031				0;
2032			priv->curr_bss_params.bss_descriptor.
2033				beacon_buf_size_max = 0;
2034
2035			dev_dbg(adapter->dev, "info: Found current ssid/bssid"
2036				" in list @ index #%d\n", j);
2037			/* Make a copy of current BSSID descriptor */
2038			memcpy(&priv->curr_bss_params.bss_descriptor,
2039			       &adapter->scan_table[j],
2040			       sizeof(priv->curr_bss_params.bss_descriptor));
2041
2042			mwifiex_save_curr_bcn(priv);
2043			spin_unlock_irqrestore(&priv->curr_bcn_buf_lock, flags);
2044
2045		} else {
2046			mwifiex_restore_curr_bcn(priv);
2047		}
2048	}
2049
2050	for (i = 0; i < adapter->num_in_scan_table; i++)
2051		dev_dbg(adapter->dev, "info: scan:(%02d) %pM "
2052		       "RSSI[%03d], SSID[%s]\n",
2053		       i, adapter->scan_table[i].mac_address,
2054		       (s32) adapter->scan_table[i].rssi,
2055		       adapter->scan_table[i].ssid.ssid);
2056}
2057
2058/*
2059 * This function converts radio type scan parameter to a band configuration
2060 * to be used in join command.
2061 */
2062static u8
2063mwifiex_radio_type_to_band(u8 radio_type)
2064{
2065	switch (radio_type) {
2066	case HostCmd_SCAN_RADIO_TYPE_A:
2067		return BAND_A;
2068	case HostCmd_SCAN_RADIO_TYPE_BG:
2069	default:
2070		return BAND_G;
2071	}
2072}
2073
2074/*
2075 * This function deletes a specific indexed entry from the scan table.
2076 *
2077 * This also compacts the remaining entries and adjusts any buffering
2078 * of beacon/probe response data if needed.
2079 */
2080static void
2081mwifiex_scan_delete_table_entry(struct mwifiex_private *priv, s32 table_idx)
2082{
2083	struct mwifiex_adapter *adapter = priv->adapter;
2084	u32 del_idx;
2085	u32 beacon_buf_adj;
2086	u8 *beacon_buf;
2087
2088	/*
2089	 * Shift the saved beacon buffer data for the scan table back over the
2090	 *   entry being removed.  Update the end of buffer pointer.  Save the
2091	 *   deleted buffer allocation size for pointer adjustments for entries
2092	 *   compacted after the deleted index.
2093	 */
2094	beacon_buf_adj = adapter->scan_table[table_idx].beacon_buf_size_max;
2095
2096	dev_dbg(adapter->dev, "info: Scan: Delete Entry %d, beacon buffer "
2097		"removal = %d bytes\n", table_idx, beacon_buf_adj);
2098
2099	/* Check if the table entry had storage allocated for its beacon */
2100	if (beacon_buf_adj) {
2101		beacon_buf = adapter->scan_table[table_idx].beacon_buf;
2102
2103		/*
2104		 * Remove the entry's buffer space, decrement the table end
2105		 * pointer by the amount we are removing
2106		 */
2107		adapter->bcn_buf_end -= beacon_buf_adj;
2108
2109		dev_dbg(adapter->dev, "info: scan: delete entry %d,"
2110			" compact data: %p <- %p (sz = %d)\n",
2111		       table_idx, beacon_buf,
2112		       beacon_buf + beacon_buf_adj,
2113		       (int)(adapter->bcn_buf_end - beacon_buf));
2114
2115		/*
2116		 * Compact data storage.  Copy all data after the deleted
2117		 * entry's end address (beacon_buf + beacon_buf_adj) back
2118		 * to the original start address (beacon_buf).
2119		 *
2120		 * Scan table entries affected by the move will have their
2121		 * entry pointer adjusted below.
2122		 *
2123		 * Use memmove since the dest/src memory regions overlap.
2124		 */
2125		memmove(beacon_buf, beacon_buf + beacon_buf_adj,
2126			adapter->bcn_buf_end - beacon_buf);
2127	}
2128
2129	dev_dbg(adapter->dev,
2130		"info: Scan: Delete Entry %d, num_in_scan_table = %d\n",
2131	       table_idx, adapter->num_in_scan_table);
2132
2133	/* Shift all of the entries after the table_idx back by one, compacting
2134	   the table and removing the requested entry */
2135	for (del_idx = table_idx; (del_idx + 1) < adapter->num_in_scan_table;
2136	     del_idx++) {
2137		/* Copy the next entry over this one */
2138		memcpy(adapter->scan_table + del_idx,
2139		       adapter->scan_table + del_idx + 1,
2140		       sizeof(struct mwifiex_bssdescriptor));
2141
2142		/*
2143		 * Adjust this entry's pointer to its beacon buffer based on
2144		 * the removed/compacted entry from the deleted index.  Don't
2145		 * decrement if the buffer pointer is NULL (no data stored for
2146		 * this entry).
2147		 */
2148		if (adapter->scan_table[del_idx].beacon_buf) {
2149			adapter->scan_table[del_idx].beacon_buf -=
2150				beacon_buf_adj;
2151			if (adapter->scan_table[del_idx].bcn_wpa_ie)
2152				adapter->scan_table[del_idx].bcn_wpa_ie =
2153					(struct ieee_types_vendor_specific *)
2154					(adapter->scan_table[del_idx].
2155					 beacon_buf +
2156					 adapter->scan_table[del_idx].
2157					 wpa_offset);
2158			if (adapter->scan_table[del_idx].bcn_rsn_ie)
2159				adapter->scan_table[del_idx].bcn_rsn_ie =
2160					(struct ieee_types_generic *)
2161					(adapter->scan_table[del_idx].
2162					 beacon_buf +
2163					 adapter->scan_table[del_idx].
2164					 rsn_offset);
2165			if (adapter->scan_table[del_idx].bcn_wapi_ie)
2166				adapter->scan_table[del_idx].bcn_wapi_ie =
2167					(struct ieee_types_generic *)
2168					(adapter->scan_table[del_idx].beacon_buf
2169					 + adapter->scan_table[del_idx].
2170					 wapi_offset);
2171			if (adapter->scan_table[del_idx].bcn_ht_cap)
2172				adapter->scan_table[del_idx].bcn_ht_cap =
2173					(struct ieee80211_ht_cap *)
2174					(adapter->scan_table[del_idx].beacon_buf
2175					 + adapter->scan_table[del_idx].
2176					  ht_cap_offset);
2177
2178			if (adapter->scan_table[del_idx].bcn_ht_info)
2179				adapter->scan_table[del_idx].bcn_ht_info =
2180					(struct ieee80211_ht_info *)
2181					(adapter->scan_table[del_idx].beacon_buf
2182					 + adapter->scan_table[del_idx].
2183					  ht_info_offset);
2184			if (adapter->scan_table[del_idx].bcn_bss_co_2040)
2185				adapter->scan_table[del_idx].bcn_bss_co_2040 =
2186					(u8 *)
2187					(adapter->scan_table[del_idx].beacon_buf
2188					 + adapter->scan_table[del_idx].
2189					   bss_co_2040_offset);
2190			if (adapter->scan_table[del_idx].bcn_ext_cap)
2191				adapter->scan_table[del_idx].bcn_ext_cap =
2192					(u8 *)
2193					(adapter->scan_table[del_idx].beacon_buf
2194					 + adapter->scan_table[del_idx].
2195					     ext_cap_offset);
2196			if (adapter->scan_table[del_idx].bcn_obss_scan)
2197				adapter->scan_table[del_idx].
2198					bcn_obss_scan =
2199					(struct ieee_types_obss_scan_param *)
2200					(adapter->scan_table[del_idx].beacon_buf
2201					 + adapter->scan_table[del_idx].
2202					     overlap_bss_offset);
2203		}
2204	}
2205
2206	/* The last entry is invalid now that it has been deleted or moved
2207	   back */
2208	memset(adapter->scan_table + adapter->num_in_scan_table - 1,
2209	       0x00, sizeof(struct mwifiex_bssdescriptor));
2210
2211	adapter->num_in_scan_table--;
2212}
2213
2214/*
2215 * This function deletes all occurrences of a given SSID from the scan table.
2216 *
2217 * This iterates through the scan table and deletes all entries that match
2218 * the given SSID. It also compacts the remaining scan table entries.
2219 */
2220static int
2221mwifiex_scan_delete_ssid_table_entry(struct mwifiex_private *priv,
2222				     struct mwifiex_802_11_ssid *del_ssid)
2223{
2224	s32 table_idx = -1;
2225
2226	dev_dbg(priv->adapter->dev, "info: scan: delete ssid entry: %-32s\n",
2227			del_ssid->ssid);
2228
2229	/* If the requested SSID is found in the table, delete it.  Then keep
2230	   searching the table for multiple entires for the SSID until no
2231	   more are found */
2232	while ((table_idx = mwifiex_find_ssid_in_list(priv, del_ssid, NULL,
2233					NL80211_IFTYPE_UNSPECIFIED)) >= 0) {
2234		dev_dbg(priv->adapter->dev,
2235			"info: Scan: Delete SSID Entry: Found Idx = %d\n",
2236		       table_idx);
2237		mwifiex_scan_delete_table_entry(priv, table_idx);
2238	}
2239
2240	return table_idx == -1 ? -1 : 0;
2241}
2242
2243/*
2244 * This is an internal function used to start a scan based on an input
2245 * configuration.
2246 *
2247 * This uses the input user scan configuration information when provided in
2248 * order to send the appropriate scan commands to firmware to populate or
2249 * update the internal driver scan table.
2250 */
2251int mwifiex_scan_networks(struct mwifiex_private *priv,
2252			  const struct mwifiex_user_scan_cfg *user_scan_in)
2253{
2254	int ret = 0;
2255	struct mwifiex_adapter *adapter = priv->adapter;
2256	struct cmd_ctrl_node *cmd_node;
2257	union mwifiex_scan_cmd_config_tlv *scan_cfg_out;
2258	struct mwifiex_ie_types_chan_list_param_set *chan_list_out;
2259	u32 buf_size;
2260	struct mwifiex_chan_scan_param_set *scan_chan_list;
2261	u8 keep_previous_scan;
2262	u8 filtered_scan;
2263	u8 scan_current_chan_only;
2264	u8 max_chan_per_scan;
2265	unsigned long flags;
2266
2267	if (adapter->scan_processing) {
2268		dev_dbg(adapter->dev, "cmd: Scan already in process...\n");
2269		return ret;
2270	}
2271
2272	spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
2273	adapter->scan_processing = true;
2274	spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
2275
2276	if (priv->scan_block) {
2277		dev_dbg(adapter->dev,
2278			"cmd: Scan is blocked during association...\n");
2279		return ret;
2280	}
2281
2282	scan_cfg_out = kzalloc(sizeof(union mwifiex_scan_cmd_config_tlv),
2283					GFP_KERNEL);
2284	if (!scan_cfg_out) {
2285		dev_err(adapter->dev, "failed to alloc scan_cfg_out\n");
2286		return -ENOMEM;
2287	}
2288
2289	buf_size = sizeof(struct mwifiex_chan_scan_param_set) *
2290			MWIFIEX_USER_SCAN_CHAN_MAX;
2291	scan_chan_list = kzalloc(buf_size, GFP_KERNEL);
2292	if (!scan_chan_list) {
2293		dev_err(adapter->dev, "failed to alloc scan_chan_list\n");
2294		kfree(scan_cfg_out);
2295		return -ENOMEM;
2296	}
2297
2298	keep_previous_scan = false;
2299
2300	mwifiex_scan_setup_scan_config(priv, user_scan_in,
2301				       &scan_cfg_out->config, &chan_list_out,
2302				       scan_chan_list, &max_chan_per_scan,
2303				       &filtered_scan, &scan_current_chan_only);
2304
2305	if (user_scan_in)
2306		keep_previous_scan = user_scan_in->keep_previous_scan;
2307
2308
2309	if (!keep_previous_scan) {
2310		memset(adapter->scan_table, 0x00,
2311		       sizeof(struct mwifiex_bssdescriptor) * IW_MAX_AP);
2312		adapter->num_in_scan_table = 0;
2313		adapter->bcn_buf_end = adapter->bcn_buf;
2314	}
2315
2316	ret = mwifiex_scan_channel_list(priv, max_chan_per_scan, filtered_scan,
2317					&scan_cfg_out->config, chan_list_out,
2318					scan_chan_list);
2319
2320	/* Get scan command from scan_pending_q and put to cmd_pending_q */
2321	if (!ret) {
2322		spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
2323		if (!list_empty(&adapter->scan_pending_q)) {
2324			cmd_node = list_first_entry(&adapter->scan_pending_q,
2325						struct cmd_ctrl_node, list);
2326			list_del(&cmd_node->list);
2327			spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
2328									flags);
2329			mwifiex_insert_cmd_to_pending_q(adapter, cmd_node,
2330							true);
2331		} else {
2332			spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
2333					       flags);
2334		}
2335	} else {
2336		spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
2337		adapter->scan_processing = true;
2338		spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
2339	}
2340
2341	kfree(scan_cfg_out);
2342	kfree(scan_chan_list);
2343	return ret;
2344}
2345
2346/*
2347 * This function prepares a scan command to be sent to the firmware.
2348 *
2349 * This uses the scan command configuration sent to the command processing
2350 * module in command preparation stage to configure a scan command structure
2351 * to send to firmware.
2352 *
2353 * The fixed fields specifying the BSS type and BSSID filters as well as a
2354 * variable number/length of TLVs are sent in the command to firmware.
2355 *
2356 * Preparation also includes -
2357 *      - Setting command ID, and proper size
2358 *      - Ensuring correct endian-ness
2359 */
2360int mwifiex_cmd_802_11_scan(struct host_cmd_ds_command *cmd,
2361			    struct mwifiex_scan_cmd_config *scan_cfg)
2362{
2363	struct host_cmd_ds_802_11_scan *scan_cmd = &cmd->params.scan;
2364
2365	/* Set fixed field variables in scan command */
2366	scan_cmd->bss_mode = scan_cfg->bss_mode;
2367	memcpy(scan_cmd->bssid, scan_cfg->specific_bssid,
2368	       sizeof(scan_cmd->bssid));
2369	memcpy(scan_cmd->tlv_buffer, scan_cfg->tlv_buf, scan_cfg->tlv_buf_len);
2370
2371	cmd->command = cpu_to_le16(HostCmd_CMD_802_11_SCAN);
2372
2373	/* Size is equal to the sizeof(fixed portions) + the TLV len + header */
2374	cmd->size = cpu_to_le16((u16) (sizeof(scan_cmd->bss_mode)
2375					  + sizeof(scan_cmd->bssid)
2376					  + scan_cfg->tlv_buf_len + S_DS_GEN));
2377
2378	return 0;
2379}
2380
2381/*
2382 * This function handles the command response of scan.
2383 *
2384 * The response buffer for the scan command has the following
2385 * memory layout:
2386 *
2387 *      .-------------------------------------------------------------.
2388 *      |  Header (4 * sizeof(t_u16)):  Standard command response hdr |
2389 *      .-------------------------------------------------------------.
2390 *      |  BufSize (t_u16) : sizeof the BSS Description data          |
2391 *      .-------------------------------------------------------------.
2392 *      |  NumOfSet (t_u8) : Number of BSS Descs returned             |
2393 *      .-------------------------------------------------------------.
2394 *      |  BSSDescription data (variable, size given in BufSize)      |
2395 *      .-------------------------------------------------------------.
2396 *      |  TLV data (variable, size calculated using Header->Size,    |
2397 *      |            BufSize and sizeof the fixed fields above)       |
2398 *      .-------------------------------------------------------------.
2399 */
2400int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
2401			    struct host_cmd_ds_command *resp)
2402{
2403	int ret = 0;
2404	struct mwifiex_adapter *adapter = priv->adapter;
2405	struct cmd_ctrl_node *cmd_node;
2406	struct host_cmd_ds_802_11_scan_rsp *scan_rsp;
2407	struct mwifiex_bssdescriptor *bss_new_entry = NULL;
2408	struct mwifiex_ie_types_data *tlv_data;
2409	struct mwifiex_ie_types_tsf_timestamp *tsf_tlv;
2410	u8 *bss_info;
2411	u32 scan_resp_size;
2412	u32 bytes_left;
2413	u32 num_in_table;
2414	u32 bss_idx;
2415	u32 idx;
2416	u32 tlv_buf_size;
2417	long long tsf_val;
2418	struct mwifiex_chan_freq_power *cfp;
2419	struct mwifiex_ie_types_chan_band_list_param_set *chan_band_tlv;
2420	struct chan_band_param_set *chan_band;
2421	u8 band;
2422	u8 is_bgscan_resp;
2423	unsigned long flags;
2424
2425	is_bgscan_resp = (le16_to_cpu(resp->command)
2426		== HostCmd_CMD_802_11_BG_SCAN_QUERY);
2427	if (is_bgscan_resp)
2428		scan_rsp = &resp->params.bg_scan_query_resp.scan_resp;
2429	else
2430		scan_rsp = &resp->params.scan_resp;
2431
2432
2433	if (scan_rsp->number_of_sets > IW_MAX_AP) {
2434		dev_err(adapter->dev, "SCAN_RESP: too many AP returned (%d)\n",
2435		       scan_rsp->number_of_sets);
2436		ret = -1;
2437		goto done;
2438	}
2439
2440	bytes_left = le16_to_cpu(scan_rsp->bss_descript_size);
2441	dev_dbg(adapter->dev, "info: SCAN_RESP: bss_descript_size %d\n",
2442						bytes_left);
2443
2444	scan_resp_size = le16_to_cpu(resp->size);
2445
2446	dev_dbg(adapter->dev,
2447		"info: SCAN_RESP: returned %d APs before parsing\n",
2448	       scan_rsp->number_of_sets);
2449
2450	num_in_table = adapter->num_in_scan_table;
2451	bss_info = scan_rsp->bss_desc_and_tlv_buffer;
2452
2453	/*
2454	 * The size of the TLV buffer is equal to the entire command response
2455	 *   size (scan_resp_size) minus the fixed fields (sizeof()'s), the
2456	 *   BSS Descriptions (bss_descript_size as bytesLef) and the command
2457	 *   response header (S_DS_GEN)
2458	 */
2459	tlv_buf_size = scan_resp_size - (bytes_left
2460					 + sizeof(scan_rsp->bss_descript_size)
2461					 + sizeof(scan_rsp->number_of_sets)
2462					 + S_DS_GEN);
2463
2464	tlv_data = (struct mwifiex_ie_types_data *) (scan_rsp->
2465						 bss_desc_and_tlv_buffer +
2466						 bytes_left);
2467
2468	/* Search the TLV buffer space in the scan response for any valid
2469	   TLVs */
2470	mwifiex_ret_802_11_scan_get_tlv_ptrs(adapter, tlv_data, tlv_buf_size,
2471					     TLV_TYPE_TSFTIMESTAMP,
2472					     (struct mwifiex_ie_types_data **)
2473					     &tsf_tlv);
2474
2475	/* Search the TLV buffer space in the scan response for any valid
2476	   TLVs */
2477	mwifiex_ret_802_11_scan_get_tlv_ptrs(adapter, tlv_data, tlv_buf_size,
2478					     TLV_TYPE_CHANNELBANDLIST,
2479					     (struct mwifiex_ie_types_data **)
2480					     &chan_band_tlv);
2481
2482	/*
2483	 *  Process each scan response returned (scan_rsp->number_of_sets).
2484	 *  Save the information in the bss_new_entry and then insert into the
2485	 *  driver scan table either as an update to an existing entry
2486	 *  or as an addition at the end of the table
2487	 */
2488	bss_new_entry = kzalloc(sizeof(struct mwifiex_bssdescriptor),
2489				GFP_KERNEL);
2490	if (!bss_new_entry) {
2491		dev_err(adapter->dev, " failed to alloc bss_new_entry\n");
2492		return -ENOMEM;
2493	}
2494
2495	for (idx = 0; idx < scan_rsp->number_of_sets && bytes_left; idx++) {
2496		/* Zero out the bss_new_entry we are about to store info in */
2497		memset(bss_new_entry, 0x00,
2498		       sizeof(struct mwifiex_bssdescriptor));
2499
2500		if (mwifiex_interpret_bss_desc_with_ie(adapter, bss_new_entry,
2501							&bss_info,
2502							&bytes_left)) {
2503			/* Error parsing/interpreting scan response, skipped */
2504			dev_err(adapter->dev, "SCAN_RESP: "
2505			       "mwifiex_interpret_bss_desc_with_ie "
2506			       "returned ERROR\n");
2507			continue;
2508		}
2509
2510		/* Process the data fields and IEs returned for this BSS */
2511		dev_dbg(adapter->dev, "info: SCAN_RESP: BSSID = %pM\n",
2512		       bss_new_entry->mac_address);
2513
2514		/* Search the scan table for the same bssid */
2515		for (bss_idx = 0; bss_idx < num_in_table; bss_idx++) {
2516			if (memcmp(bss_new_entry->mac_address,
2517				adapter->scan_table[bss_idx].mac_address,
2518				sizeof(bss_new_entry->mac_address))) {
2519				continue;
2520			}
2521			/*
2522			 * If the SSID matches as well, it is a
2523			 * duplicate of this entry.  Keep the bss_idx
2524			 * set to this entry so we replace the old
2525			 * contents in the table
2526			 */
2527			if ((bss_new_entry->ssid.ssid_len
2528				== adapter->scan_table[bss_idx]. ssid.ssid_len)
2529					&& (!memcmp(bss_new_entry->ssid.ssid,
2530					adapter->scan_table[bss_idx].ssid.ssid,
2531					bss_new_entry->ssid.ssid_len))) {
2532				dev_dbg(adapter->dev, "info: SCAN_RESP:"
2533					" duplicate of index: %d\n", bss_idx);
2534				break;
2535			}
2536		}
2537		/*
2538		 * If the bss_idx is equal to the number of entries in
2539		 * the table, the new entry was not a duplicate; append
2540		 * it to the scan table
2541		 */
2542		if (bss_idx == num_in_table) {
2543			/* Range check the bss_idx, keep it limited to
2544			   the last entry */
2545			if (bss_idx == IW_MAX_AP)
2546				bss_idx--;
2547			else
2548				num_in_table++;
2549		}
2550
2551		/*
2552		 * Save the beacon/probe response returned for later application
2553		 * retrieval.  Duplicate beacon/probe responses are updated if
2554		 * possible
2555		 */
2556		mwifiex_ret_802_11_scan_store_beacon(priv, bss_idx,
2557						num_in_table, bss_new_entry);
2558		/*
2559		 * If the TSF TLV was appended to the scan results, save this
2560		 * entry's TSF value in the networkTSF field.The networkTSF is
2561		 * the firmware's TSF value at the time the beacon or probe
2562		 * response was received.
2563		 */
2564		if (tsf_tlv) {
2565			memcpy(&tsf_val, &tsf_tlv->tsf_data[idx * TSF_DATA_SIZE]
2566					, sizeof(tsf_val));
2567			memcpy(&bss_new_entry->network_tsf, &tsf_val,
2568					sizeof(bss_new_entry->network_tsf));
2569		}
2570		band = BAND_G;
2571		if (chan_band_tlv) {
2572			chan_band = &chan_band_tlv->chan_band_param[idx];
2573			band = mwifiex_radio_type_to_band(chan_band->radio_type
2574					& (BIT(0) | BIT(1)));
2575		}
2576
2577		/* Save the band designation for this entry for use in join */
2578		bss_new_entry->bss_band = band;
2579		cfp = mwifiex_get_cfp_by_band_and_channel_from_cfg80211(priv,
2580					(u8) bss_new_entry->bss_band,
2581					(u16)bss_new_entry->channel);
2582
2583		if (cfp)
2584			bss_new_entry->freq = cfp->freq;
2585		else
2586			bss_new_entry->freq = 0;
2587
2588		/* Copy the locally created bss_new_entry to the scan table */
2589		memcpy(&adapter->scan_table[bss_idx], bss_new_entry,
2590		       sizeof(adapter->scan_table[bss_idx]));
2591
2592	}
2593
2594	dev_dbg(adapter->dev,
2595		"info: SCAN_RESP: Scanned %2d APs, %d valid, %d total\n",
2596	       scan_rsp->number_of_sets,
2597	       num_in_table - adapter->num_in_scan_table, num_in_table);
2598
2599	/* Update the total number of BSSIDs in the scan table */
2600	adapter->num_in_scan_table = num_in_table;
2601
2602	spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
2603	if (list_empty(&adapter->scan_pending_q)) {
2604		spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
2605		spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
2606		adapter->scan_processing = false;
2607		spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
2608		/*
2609		 * Process the resulting scan table:
2610		 *   - Remove any bad ssids
2611		 *   - Update our current BSS information from scan data
2612		 */
2613		mwifiex_process_scan_results(priv);
2614
2615		/* Need to indicate IOCTL complete */
2616		if (adapter->curr_cmd->wait_q_enabled) {
2617			adapter->cmd_wait_q.status = 0;
2618			mwifiex_complete_cmd(adapter);
2619		}
2620		if (priv->report_scan_result)
2621			priv->report_scan_result = false;
2622		if (priv->scan_pending_on_block) {
2623			priv->scan_pending_on_block = false;
2624			up(&priv->async_sem);
2625		}
2626
2627	} else {
2628		/* Get scan command from scan_pending_q and put to
2629		   cmd_pending_q */
2630		cmd_node = list_first_entry(&adapter->scan_pending_q,
2631					    struct cmd_ctrl_node, list);
2632		list_del(&cmd_node->list);
2633		spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
2634
2635		mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, true);
2636	}
2637
2638done:
2639	kfree((u8 *) bss_new_entry);
2640	return ret;
2641}
2642
2643/*
2644 * This function prepares command for background scan query.
2645 *
2646 * Preparation includes -
2647 *      - Setting command ID and proper size
2648 *      - Setting background scan flush parameter
2649 *      - Ensuring correct endian-ness
2650 */
2651int mwifiex_cmd_802_11_bg_scan_query(struct host_cmd_ds_command *cmd)
2652{
2653	struct host_cmd_ds_802_11_bg_scan_query *bg_query =
2654		&cmd->params.bg_scan_query;
2655
2656	cmd->command = cpu_to_le16(HostCmd_CMD_802_11_BG_SCAN_QUERY);
2657	cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_bg_scan_query)
2658				+ S_DS_GEN);
2659
2660	bg_query->flush = 1;
2661
2662	return 0;
2663}
2664
2665/*
2666 * This function finds a SSID in the scan table.
2667 *
2668 * A BSSID may optionally be provided to qualify the SSID.
2669 * For non-Auto mode, further check is made to make sure the
2670 * BSS found in the scan table is compatible with the current
2671 * settings of the driver.
2672 */
2673s32
2674mwifiex_find_ssid_in_list(struct mwifiex_private *priv,
2675			  struct mwifiex_802_11_ssid *ssid, u8 *bssid,
2676			  u32 mode)
2677{
2678	struct mwifiex_adapter *adapter = priv->adapter;
2679	s32 net = -1, j;
2680	u8 best_rssi = 0;
2681	u32 i;
2682
2683	dev_dbg(adapter->dev, "info: num of entries in table = %d\n",
2684	       adapter->num_in_scan_table);
2685
2686	/*
2687	 * Loop through the table until the maximum is reached or until a match
2688	 *   is found based on the bssid field comparison
2689	 */
2690	for (i = 0;
2691	     i < adapter->num_in_scan_table && (!bssid || (bssid && net < 0));
2692	     i++) {
2693		if (!mwifiex_ssid_cmp(&adapter->scan_table[i].ssid, ssid) &&
2694		    (!bssid
2695		     || !memcmp(adapter->scan_table[i].mac_address, bssid,
2696				ETH_ALEN))
2697		    &&
2698		    (mwifiex_get_cfp_by_band_and_channel_from_cfg80211
2699		     (priv, (u8) adapter->scan_table[i].bss_band,
2700		      (u16) adapter->scan_table[i].channel))) {
2701			switch (mode) {
2702			case NL80211_IFTYPE_STATION:
2703			case NL80211_IFTYPE_ADHOC:
2704				j = mwifiex_is_network_compatible(priv, i,
2705								  mode);
2706
2707				if (j >= 0) {
2708					if (SCAN_RSSI
2709					    (adapter->scan_table[i].rssi) >
2710					    best_rssi) {
2711						best_rssi = SCAN_RSSI(adapter->
2712								  scan_table
2713								  [i].rssi);
2714						net = i;
2715					}
2716				} else {
2717					if (net == -1)
2718						net = j;
2719				}
2720				break;
2721			case NL80211_IFTYPE_UNSPECIFIED:
2722			default:
2723				/*
2724				 * Do not check compatibility if the mode
2725				 * requested is Auto/Unknown.  Allows generic
2726				 * find to work without verifying against the
2727				 * Adapter security settings
2728				 */
2729				if (SCAN_RSSI(adapter->scan_table[i].rssi) >
2730				    best_rssi) {
2731					best_rssi = SCAN_RSSI(adapter->
2732							  scan_table[i].rssi);
2733					net = i;
2734				}
2735				break;
2736			}
2737		}
2738	}
2739
2740	return net;
2741}
2742
2743/*
2744 * This function finds a specific compatible BSSID in the scan list.
2745 *
2746 * This function loops through the scan table looking for a compatible
2747 * match. If a BSSID matches, but the BSS is found to be not compatible
2748 * the function ignores it and continues to search through the rest of
2749 * the entries in case there is an AP with multiple SSIDs assigned to
2750 * the same BSSID.
2751 */
2752s32
2753mwifiex_find_bssid_in_list(struct mwifiex_private *priv, u8 *bssid,
2754			   u32 mode)
2755{
2756	struct mwifiex_adapter *adapter = priv->adapter;
2757	s32 net = -1;
2758	u32 i;
2759
2760	if (!bssid)
2761		return -1;
2762
2763	dev_dbg(adapter->dev, "info: FindBSSID: Num of BSSIDs = %d\n",
2764	       adapter->num_in_scan_table);
2765
2766	/*
2767	 * Look through the scan table for a compatible match. The ret return
2768	 *   variable will be equal to the index in the scan table (greater
2769	 *   than zero) if the network is compatible.  The loop will continue
2770	 *   past a matched bssid that is not compatible in case there is an
2771	 *   AP with multiple SSIDs assigned to the same BSSID
2772	 */
2773	for (i = 0; net < 0 && i < adapter->num_in_scan_table; i++) {
2774		if (!memcmp
2775		    (adapter->scan_table[i].mac_address, bssid, ETH_ALEN)
2776			&& mwifiex_get_cfp_by_band_and_channel_from_cfg80211
2777								(priv,
2778							    (u8) adapter->
2779							    scan_table[i].
2780							    bss_band,
2781							    (u16) adapter->
2782							    scan_table[i].
2783							    channel)) {
2784			switch (mode) {
2785			case NL80211_IFTYPE_STATION:
2786			case NL80211_IFTYPE_ADHOC:
2787				net = mwifiex_is_network_compatible(priv, i,
2788								    mode);
2789				break;
2790			default:
2791				net = i;
2792				break;
2793			}
2794		}
2795	}
2796
2797	return net;
2798}
2799
2800/*
2801 * This function inserts scan command node to the scan pending queue.
2802 */
2803void
2804mwifiex_queue_scan_cmd(struct mwifiex_private *priv,
2805		       struct cmd_ctrl_node *cmd_node)
2806{
2807	struct mwifiex_adapter *adapter = priv->adapter;
2808	unsigned long flags;
2809
2810	cmd_node->wait_q_enabled = true;
2811	spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
2812	list_add_tail(&cmd_node->list, &adapter->scan_pending_q);
2813	spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
2814}
2815
2816/*
2817 * This function finds an AP with specific ssid in the scan list.
2818 */
2819int mwifiex_find_best_network(struct mwifiex_private *priv,
2820			      struct mwifiex_ssid_bssid *req_ssid_bssid)
2821{
2822	struct mwifiex_adapter *adapter = priv->adapter;
2823	struct mwifiex_bssdescriptor *req_bss;
2824	s32 i;
2825
2826	memset(req_ssid_bssid, 0, sizeof(struct mwifiex_ssid_bssid));
2827
2828	i = mwifiex_find_best_network_in_list(priv);
2829
2830	if (i >= 0) {
2831		req_bss = &adapter->scan_table[i];
2832		memcpy(&req_ssid_bssid->ssid, &req_bss->ssid,
2833		       sizeof(struct mwifiex_802_11_ssid));
2834		memcpy((u8 *) &req_ssid_bssid->bssid,
2835		       (u8 *) &req_bss->mac_address, ETH_ALEN);
2836
2837		/* Make sure we are in the right mode */
2838		if (priv->bss_mode == NL80211_IFTYPE_UNSPECIFIED)
2839			priv->bss_mode = req_bss->bss_mode;
2840	}
2841
2842	if (!req_ssid_bssid->ssid.ssid_len)
2843		return -1;
2844
2845	dev_dbg(adapter->dev, "info: Best network found = [%s], "
2846	       "[%pM]\n", req_ssid_bssid->ssid.ssid,
2847	       req_ssid_bssid->bssid);
2848
2849	return 0;
2850}
2851
2852/*
2853 * This function sends a scan command for all available channels to the
2854 * firmware, filtered on a specific SSID.
2855 */
2856static int mwifiex_scan_specific_ssid(struct mwifiex_private *priv,
2857				      struct mwifiex_802_11_ssid *req_ssid)
2858{
2859	struct mwifiex_adapter *adapter = priv->adapter;
2860	int ret = 0;
2861	struct mwifiex_user_scan_cfg *scan_cfg;
2862
2863	if (!req_ssid)
2864		return -1;
2865
2866	if (adapter->scan_processing) {
2867		dev_dbg(adapter->dev, "cmd: Scan already in process...\n");
2868		return ret;
2869	}
2870
2871	if (priv->scan_block) {
2872		dev_dbg(adapter->dev,
2873			"cmd: Scan is blocked during association...\n");
2874		return ret;
2875	}
2876
2877	mwifiex_scan_delete_ssid_table_entry(priv, req_ssid);
2878
2879	scan_cfg = kzalloc(sizeof(struct mwifiex_user_scan_cfg), GFP_KERNEL);
2880	if (!scan_cfg) {
2881		dev_err(adapter->dev, "failed to alloc scan_cfg\n");
2882		return -ENOMEM;
2883	}
2884
2885	memcpy(scan_cfg->ssid_list[0].ssid, req_ssid->ssid,
2886	       req_ssid->ssid_len);
2887	scan_cfg->keep_previous_scan = true;
2888
2889	ret = mwifiex_scan_networks(priv, scan_cfg);
2890
2891	kfree(scan_cfg);
2892	return ret;
2893}
2894
2895/*
2896 * Sends IOCTL request to start a scan.
2897 *
2898 * This function allocates the IOCTL request buffer, fills it
2899 * with requisite parameters and calls the IOCTL handler.
2900 *
2901 * Scan command can be issued for both normal scan and specific SSID
2902 * scan, depending upon whether an SSID is provided or not.
2903 */
2904int mwifiex_request_scan(struct mwifiex_private *priv,
2905			 struct mwifiex_802_11_ssid *req_ssid)
2906{
2907	int ret;
2908
2909	if (down_interruptible(&priv->async_sem)) {
2910		dev_err(priv->adapter->dev, "%s: acquire semaphore\n",
2911						__func__);
2912		return -1;
2913	}
2914	priv->scan_pending_on_block = true;
2915
2916	priv->adapter->cmd_wait_q.condition = false;
2917
2918	if (req_ssid && req_ssid->ssid_len != 0)
2919		/* Specific SSID scan */
2920		ret = mwifiex_scan_specific_ssid(priv, req_ssid);
2921	else
2922		/* Normal scan */
2923		ret = mwifiex_scan_networks(priv, NULL);
2924
2925	if (!ret)
2926		ret = mwifiex_wait_queue_complete(priv->adapter);
2927
2928	if (ret == -1) {
2929		priv->scan_pending_on_block = false;
2930		up(&priv->async_sem);
2931	}
2932
2933	return ret;
2934}
2935
2936/*
2937 * This function appends the vendor specific IE TLV to a buffer.
2938 */
2939int
2940mwifiex_cmd_append_vsie_tlv(struct mwifiex_private *priv,
2941			    u16 vsie_mask, u8 **buffer)
2942{
2943	int id, ret_len = 0;
2944	struct mwifiex_ie_types_vendor_param_set *vs_param_set;
2945
2946	if (!buffer)
2947		return 0;
2948	if (!(*buffer))
2949		return 0;
2950
2951	/*
2952	 * Traverse through the saved vendor specific IE array and append
2953	 * the selected(scan/assoc/adhoc) IE as TLV to the command
2954	 */
2955	for (id = 0; id < MWIFIEX_MAX_VSIE_NUM; id++) {
2956		if (priv->vs_ie[id].mask & vsie_mask) {
2957			vs_param_set =
2958				(struct mwifiex_ie_types_vendor_param_set *)
2959				*buffer;
2960			vs_param_set->header.type =
2961				cpu_to_le16(TLV_TYPE_PASSTHROUGH);
2962			vs_param_set->header.len =
2963				cpu_to_le16((((u16) priv->vs_ie[id].ie[1])
2964				& 0x00FF) + 2);
2965			memcpy(vs_param_set->ie, priv->vs_ie[id].ie,
2966			       le16_to_cpu(vs_param_set->header.len));
2967			*buffer += le16_to_cpu(vs_param_set->header.len) +
2968				   sizeof(struct mwifiex_ie_types_header);
2969			ret_len += le16_to_cpu(vs_param_set->header.len) +
2970				   sizeof(struct mwifiex_ie_types_header);
2971		}
2972	}
2973	return ret_len;
2974}
2975
2976/*
2977 * This function saves a beacon buffer of the current BSS descriptor.
2978 *
2979 * The current beacon buffer is saved so that it can be restored in the
2980 * following cases that makes the beacon buffer not to contain the current
2981 * ssid's beacon buffer.
2982 *      - The current ssid was not found somehow in the last scan.
2983 *      - The current ssid was the last entry of the scan table and overloaded.
2984 */
2985void
2986mwifiex_save_curr_bcn(struct mwifiex_private *priv)
2987{
2988	struct mwifiex_bssdescriptor *curr_bss =
2989		&priv->curr_bss_params.bss_descriptor;
2990
2991	if (!curr_bss->beacon_buf_size)
2992		return;
2993
2994	/* allocate beacon buffer at 1st time; or if it's size has changed */
2995	if (!priv->curr_bcn_buf ||
2996			priv->curr_bcn_size != curr_bss->beacon_buf_size) {
2997		priv->curr_bcn_size = curr_bss->beacon_buf_size;
2998
2999		kfree(priv->curr_bcn_buf);
3000		priv->curr_bcn_buf = kzalloc(curr_bss->beacon_buf_size,
3001						GFP_KERNEL);
3002		if (!priv->curr_bcn_buf) {
3003			dev_err(priv->adapter->dev,
3004					"failed to alloc curr_bcn_buf\n");
3005			return;
3006		}
3007	}
3008
3009	memcpy(priv->curr_bcn_buf, curr_bss->beacon_buf,
3010		curr_bss->beacon_buf_size);
3011	dev_dbg(priv->adapter->dev, "info: current beacon saved %d\n",
3012		priv->curr_bcn_size);
3013}
3014
3015/*
3016 * This function frees the current BSS descriptor beacon buffer.
3017 */
3018void
3019mwifiex_free_curr_bcn(struct mwifiex_private *priv)
3020{
3021	kfree(priv->curr_bcn_buf);
3022	priv->curr_bcn_buf = NULL;
3023}