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