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