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