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