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