blob: 6f6bb506a95912d74d4ada5d9d494045b3ab450c [file] [log] [blame]
Jeff Johnson295189b2012-06-20 16:38:30 -07001/*
Jeff Johnson32d95a32012-09-10 13:15:23 -07002 * Copyright (c) 2012, The Linux Foundation. All rights reserved.
Jeff Johnson295189b2012-06-20 16:38:30 -07003 *
4 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
5 *
6 *
7 * Permission to use, copy, modify, and/or distribute this software for
8 * any purpose with or without fee is hereby granted, provided that the
9 * above copyright notice and this permission notice appear in all
10 * copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
13 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
15 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
16 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
17 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
18 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19 * PERFORMANCE OF THIS SOFTWARE.
20 */
21
22/**========================================================================
23
24 \file wlan_hdd_scan.c
25
26 \brief WLAN Host Device Driver implementation
27
28 Copyright 2008 (c) Qualcomm, Incorporated. All Rights Reserved.
29
30 Qualcomm Confidential and Proprietary.
31
32 ========================================================================*/
33
34/**=========================================================================
35
36 EDIT HISTORY FOR FILE
37
38
39 This section contains comments describing changes made to the module.
40 Notice that changes are listed in reverse chronological order.
41
42
43 $Header:$ $DateTime: $ $Author: $
44
45
46 when who what, where, why
47 -------- --- --------------------------------------------------------
48 04/5/09 Shailender Created module.
49
50 ==========================================================================*/
51 /* To extract the Scan results */
52
53/* Add a stream event */
54
55#include <wlan_qct_driver.h>
56#include <wlan_hdd_includes.h>
57#include <vos_api.h>
58#include <palTypes.h>
59#include <aniGlobal.h>
60#include <dot11f.h>
61#ifdef WLAN_BTAMP_FEATURE
62#include "bap_hdd_misc.h"
63#endif
64
65#ifdef CONFIG_CFG80211
66#include <linux/wireless.h>
67#include <net/cfg80211.h>
68#endif
69
70#define GET_IE_LEN_IN_BSS(lenInBss) ( lenInBss + sizeof(lenInBss) - \
71 ((int) OFFSET_OF( tSirBssDescription, ieFields)))
72
73#define WEXT_CSCAN_HEADER "CSCAN S\x01\x00\x00S\x00"
74#define WEXT_CSCAN_HEADER_SIZE 12
75#define WEXT_CSCAN_SSID_SECTION 'S'
76#define WEXT_CSCAN_CHANNEL_SECTION 'C'
77#define WEXT_CSCAN_NPROBE_SECTION 'N'
78#define WEXT_CSCAN_ACTV_DWELL_SECTION 'A'
79#define WEXT_CSCAN_PASV_DWELL_SECTION 'P'
80#define WEXT_CSCAN_HOME_DWELL_SECTION 'H'
81#define WEXT_CSCAN_TYPE_SECTION 'T'
82#define WEXT_CSCAN_PENDING_SECTION 'O'
83#define WEXT_CSCAN_TYPE_DEFAULT 0
84#define WEXT_CSCAN_TYPE_PASSIVE 1
85#define WEXT_CSCAN_PASV_DWELL_TIME 130
86#define WEXT_CSCAN_PASV_DWELL_TIME_DEF 250
87#define WEXT_CSCAN_PASV_DWELL_TIME_MAX 3000
88#define WEXT_CSCAN_HOME_DWELL_TIME 130
89#define MAX_RATES 12
90
91#define WEXT_CSCAN_SCAN_DONE_WAIT_TIME 2000
92
93typedef struct hdd_scan_info{
94 struct net_device *dev;
95 struct iw_request_info *info;
96 char *start;
97 char *end;
98} hdd_scan_info_t, *hdd_scan_info_tp;
99
100static v_S31_t hdd_TranslateABGRateToMbpsRate(v_U8_t *pFcRate)
101{
102
103 /** Slightly more sophisticated processing has to take place here.
104 Basic rates are rounded DOWN. HT rates are rounded UP.*/
105 return ( (( ((v_S31_t) *pFcRate) & 0x007f) * 1000000) / 2);
106}
107
108
109static eHalStatus hdd_AddIwStreamEvent(int cmd, int length, char* data, hdd_scan_info_t *pscanInfo, char **last_event, char **current_event )
110{
111 struct iw_event event;
112
113 *last_event = *current_event;
114 vos_mem_zero(&event, sizeof (struct iw_event));
115 event.cmd = cmd;
116 event.u.data.flags = 1;
117 event.u.data.length = length;
118 *current_event = iwe_stream_add_point (pscanInfo->info,*current_event, pscanInfo->end, &event, data);
119
120 if(*last_event == *current_event)
121 {
122 /* no space to add event */
123 return -E2BIG; /* Error code, may be E2BIG */
124 }
125
126 return 0;
127}
128
129/**---------------------------------------------------------------------------
130
131 \brief hdd_GetWPARSNIEs() -
132
133 This function extract the WPA/RSN IE from the Bss descriptor IEs fields
134
135 \param - ieFields - Pointer to the Bss Descriptor IEs.
136 - ie_length - IE Length.
137 - last_event -Points to the last event.
138 - current_event - Points to the
139 \return - 0 for success, non zero for failure
140
141 --------------------------------------------------------------------------*/
142
143
144/* Extract the WPA and/or RSN IEs */
145static eHalStatus hdd_GetWPARSNIEs( v_U8_t *ieFields, v_U16_t ie_length, char **last_event, char **current_event, hdd_scan_info_t *pscanInfo )
146{
147 v_U8_t eid, elen, *element;
148 v_U16_t tie_length=0;
149
150 ENTER();
151
152 element = ieFields;
153 tie_length = ie_length;
154
155 while( tie_length > 2 && element != NULL )
156 {
157 eid = element[0];
158 elen = element[1];
159
160 /*If element length is greater than total remaining ie length,
161 *break the loop*/
162 if ((elen+2) > tie_length)
163 break;
164
165 switch(eid)
166 {
167 case DOT11F_EID_WPA:
168 case DOT11F_EID_RSN:
169#ifdef FEATURE_WLAN_WAPI
170 case DOT11F_EID_WAPI:
171#endif
172 if(hdd_AddIwStreamEvent( IWEVGENIE, elen+2, (char*)element, pscanInfo, last_event, current_event ) < 0 )
173 return -E2BIG;
174 break;
175
176 default:
177 break;
178 }
179
180 /* Next element */
181 tie_length -= (2 + elen);
182 element += 2 + elen;
183 }
184
185 return 0;
186}
187
188/**---------------------------------------------------------------------------
189
190 \brief hdd_IndicateScanResult() -
191
192 This function returns the scan results to the wpa_supplicant
193
194 \param - scanInfo - Pointer to the scan info structure.
195 - descriptor - Pointer to the Bss Descriptor.
196
197 \return - 0 for success, non zero for failure
198
199 --------------------------------------------------------------------------*/
200#define MAX_CUSTOM_LEN 64
201static eHalStatus hdd_IndicateScanResult(hdd_scan_info_t *scanInfo, tCsrScanResultInfo *scan_result)
202{
203 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(scanInfo->dev) ;
204 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter);
205 tSirBssDescription *descriptor = &scan_result->BssDescriptor;
206 struct iw_event event;
207 char *current_event = scanInfo->start;
208 char *end = scanInfo->end;
209 char *last_event;
210 char *current_pad;
211 v_U16_t ie_length = 0;
212 v_U16_t capabilityInfo;
213 char *modestr;
214 int error;
215 char custom[MAX_CUSTOM_LEN];
216 char *p;
217
218 hddLog( LOG1, "hdd_IndicateScanResult %02x:%02x:%02x:%02x:%02x:%02x",
219 descriptor->bssId[0],
220 descriptor->bssId[1],
221 descriptor->bssId[2],
222 descriptor->bssId[3],
223 descriptor->bssId[4],
224 descriptor->bssId[5]);
225
226 error = 0;
227 last_event = current_event;
228 vos_mem_zero(&event, sizeof (event));
229
230 /* BSSID */
231 event.cmd = SIOCGIWAP;
232 event.u.ap_addr.sa_family = ARPHRD_ETHER;
233 vos_mem_copy (event.u.ap_addr.sa_data, descriptor->bssId,
234 sizeof (descriptor->bssId));
235 current_event = iwe_stream_add_event(scanInfo->info,current_event, end,
236 &event, IW_EV_ADDR_LEN);
237
238 if (last_event == current_event)
239 {
240 /* no space to add event */
241 /* Error code may be E2BIG */
242 hddLog( LOGW, "hdd_IndicateScanResult: no space for SIOCGIWAP ");
243 return -E2BIG;
244 }
245
246 last_event = current_event;
247 vos_mem_zero(&event, sizeof (struct iw_event));
248
249 /* Protocol Name */
250 event.cmd = SIOCGIWNAME;
251
252 switch (descriptor->nwType)
253 {
254 case eSIR_11A_NW_TYPE:
255 modestr = "a";
256 break;
257 case eSIR_11B_NW_TYPE:
258 modestr = "b";
259 break;
260 case eSIR_11G_NW_TYPE:
261 modestr = "g";
262 break;
263 case eSIR_11N_NW_TYPE:
264 modestr = "n";
265 break;
266 default:
267 hddLog( LOGW, "%s: Unknown network type [%d]",
268 __FUNCTION__, descriptor->nwType);
269 modestr = "?";
270 break;
271 }
272 snprintf(event.u.name, IFNAMSIZ, "IEEE 802.11%s", modestr);
273 current_event = iwe_stream_add_event(scanInfo->info,current_event, end,
274 &event, IW_EV_CHAR_LEN);
275
276 if (last_event == current_event)
277 { /* no space to add event */
278 hddLog( LOGW, "hdd_IndicateScanResult: no space for SIOCGIWNAME");
279 /* Error code, may be E2BIG */
280 return -E2BIG;
281 }
282
283 last_event = current_event;
284 vos_mem_zero( &event, sizeof (struct iw_event));
285
286 /*Freq*/
287 event.cmd = SIOCGIWFREQ;
288
289 event.u.freq.m = descriptor->channelId;
290 event.u.freq.e = 0;
291 event.u.freq.i = 0;
292 current_event = iwe_stream_add_event(scanInfo->info,current_event, end,
293 &event, IW_EV_FREQ_LEN);
294
295 if (last_event == current_event)
296 { /* no space to add event */
297 return -E2BIG;
298 }
299
300 last_event = current_event;
301 vos_mem_zero( &event, sizeof (struct iw_event));
302
303 /* BSS Mode */
304 event.cmd = SIOCGIWMODE;
305
306 capabilityInfo = descriptor->capabilityInfo;
307
308 if (SIR_MAC_GET_ESS(capabilityInfo))
309 {
310 event.u.mode = IW_MODE_INFRA;
311 }
312 else if (SIR_MAC_GET_IBSS(capabilityInfo))
313 {
314 event.u.mode = IW_MODE_ADHOC;
315 }
316 else
317 {
318 /* neither ESS or IBSS */
319 event.u.mode = IW_MODE_AUTO;
320 }
321
322 current_event = iwe_stream_add_event(scanInfo->info,current_event, end,
323 &event, IW_EV_UINT_LEN);
324
325 if (last_event == current_event)
326 { /* no space to add event */
327 hddLog( LOGW, "hdd_IndicateScanResult: no space for SIOCGIWMODE");
328 return -E2BIG;
329 }
330 /* To extract SSID */
331 ie_length = GET_IE_LEN_IN_BSS( descriptor->length );
332
333 if (ie_length > 0)
334 {
335 tDot11fBeaconIEs dot11BeaconIEs;
336 tDot11fIESSID *pDot11SSID;
337 tDot11fIESuppRates *pDot11SuppRates;
338 tDot11fIEExtSuppRates *pDot11ExtSuppRates;
339 tDot11fIEHTCaps *pDot11IEHTCaps;
340 int numBasicRates = 0;
341 int maxNumRates = 0;
342
343 pDot11IEHTCaps = NULL;
344
345 dot11fUnpackBeaconIEs ((tpAniSirGlobal)
346 hHal, (tANI_U8 *) descriptor->ieFields, ie_length, &dot11BeaconIEs);
347
348 pDot11SSID = &dot11BeaconIEs.SSID;
349
350
351 if (pDot11SSID->present ) {
352 last_event = current_event;
353 vos_mem_zero (&event, sizeof (struct iw_event));
354
355 event.cmd = SIOCGIWESSID;
356 event.u.data.flags = 1;
357 event.u.data.length = scan_result->ssId.length;
358 current_event = iwe_stream_add_point (scanInfo->info,current_event, end,
359 &event, (char *)scan_result->ssId.ssId);
360
361 if(last_event == current_event)
362 { /* no space to add event */
363 hddLog( LOGW, "hdd_IndicateScanResult: no space for SIOCGIWESSID");
364 return -E2BIG;
365 }
366 }
367
368 if( hdd_GetWPARSNIEs( ( tANI_U8 *) descriptor->ieFields, ie_length, &last_event, &current_event, scanInfo ) < 0 )
369 {
370 hddLog( LOGW, "hdd_IndicateScanResult: no space for SIOCGIWESSID");
371 return -E2BIG;
372 }
373
374 last_event = current_event;
375 current_pad = current_event + IW_EV_LCP_LEN;
376 vos_mem_zero( &event, sizeof (struct iw_event));
377
378 /*Rates*/
379 event.cmd = SIOCGIWRATE;
380
381
382 pDot11SuppRates = &dot11BeaconIEs.SuppRates;
383
384 if (pDot11SuppRates->present )
385 {
386 int i;
387
388 numBasicRates = pDot11SuppRates->num_rates;;
389 for (i=0; i<pDot11SuppRates->num_rates; i++)
390 {
391 if (0 != (pDot11SuppRates->rates[i] & 0x7F))
392 {
393 event.u.bitrate.value = hdd_TranslateABGRateToMbpsRate (
394 &pDot11SuppRates->rates[i]);
395
396 current_pad = iwe_stream_add_value (scanInfo->info,current_event,
397 current_pad, end, &event, IW_EV_PARAM_LEN);
398 }
399 }
400
401 }
402
403 pDot11ExtSuppRates = &dot11BeaconIEs.ExtSuppRates;
404
405 if (pDot11ExtSuppRates->present )
406 {
407 int i,no_of_rates;
408 maxNumRates = numBasicRates + pDot11ExtSuppRates->num_rates;
409
410 /* Check to make sure the total number of rates
411 doesn't exceed IW_MAX_BITRATES */
412
413 maxNumRates = VOS_MIN(maxNumRates , IW_MAX_BITRATES);
414
415 if((maxNumRates - numBasicRates) > MAX_RATES)
416 {
417 no_of_rates = MAX_RATES;
418 hddLog( LOGW, "Accessing array out of bound that array is pDot11ExtSuppRates->rates ");
419 }
420 else
421 {
422 no_of_rates = maxNumRates - numBasicRates;
423 }
424 for ( i=0; i< no_of_rates ; i++ )
425 {
426 if (0 != (pDot11ExtSuppRates->rates[i] & 0x7F))
427 {
428 event.u.bitrate.value = hdd_TranslateABGRateToMbpsRate (
429 &pDot11ExtSuppRates->rates[i]);
430
431 current_pad = iwe_stream_add_value (scanInfo->info,current_event,
432 current_pad, end, &event, IW_EV_PARAM_LEN);
433 }
434 }
435 }
436
437
438 if ((current_pad - current_event) >= IW_EV_LCP_LEN)
439 {
440 current_event = current_pad;
441 }
442 else
443 {
444 if (last_event == current_event)
445 { /* no space to add event */
446 hddLog( LOGW, "hdd_IndicateScanResult: no space for SIOCGIWRATE");
447 return -E2BIG;
448 }
449 }
450
451 last_event = current_event;
452 vos_mem_zero (&event, sizeof (struct iw_event));
453
454
455 event.cmd = SIOCGIWENCODE;
456
457 if (SIR_MAC_GET_PRIVACY(capabilityInfo))
458 {
459 event.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
460 }
461 else
462 {
463 event.u.data.flags = IW_ENCODE_DISABLED;
464 }
465 event.u.data.length = 0;
466
467 current_event = iwe_stream_add_point(scanInfo->info,current_event, end, &event, (char *)pDot11SSID->ssid);
468
469
470 if(last_event == current_event)
471 { /* no space to add event
472 Error code, may be E2BIG */
473 return -E2BIG;
474 }
475 }
476
477 last_event = current_event;
478 vos_mem_zero( &event, sizeof (struct iw_event));
479
480 /*RSSI*/
481 event.cmd = IWEVQUAL;
482 event.u.qual.qual = descriptor->rssi;
483 event.u.qual.noise = descriptor->sinr;
484
485 /*To keep the rssi icon of the connected AP in the scan window
486 *and the rssi icon of the wireless networks in sync */
487 if (( eConnectionState_Associated ==
488 pAdapter->sessionCtx.station.conn_info.connState ) &&
489 ( VOS_TRUE == vos_mem_compare(descriptor->bssId,
490 pAdapter->sessionCtx.station.conn_info.bssId,
491 WNI_CFG_BSSID_LEN)))
492 {
493 event.u.qual.level = pAdapter->rssi;
494 }
495 else
496 {
497 event.u.qual.level = VOS_MIN ((descriptor->rssi + descriptor->sinr), 0);
498 }
499
500 event.u.qual.updated = IW_QUAL_ALL_UPDATED;
501
502 current_event = iwe_stream_add_event(scanInfo->info,current_event,
503 end, &event, IW_EV_QUAL_LEN);
504
505 if(last_event == current_event)
506 { /* no space to add event */
507 hddLog( LOGW, "hdd_IndicateScanResult: no space for IWEVQUAL");
508 return -E2BIG;
509 }
510
511
512 /* AGE */
513 event.cmd = IWEVCUSTOM;
514 p = custom;
515 p += snprintf(p, MAX_CUSTOM_LEN, " Age: %lu",
516 vos_timer_get_system_ticks() - descriptor->nReceivedTime);
517 event.u.data.length = p - custom;
518 current_event = iwe_stream_add_point (scanInfo->info,current_event, end,
519 &event, custom);
520 if(last_event == current_event)
521 { /* no space to add event */
522 hddLog( LOGW, "hdd_IndicateScanResult: no space for IWEVCUSTOM (age)");
523 return -E2BIG;
524 }
525
526 scanInfo->start = current_event;
527
528 return 0;
529}
530
531/**---------------------------------------------------------------------------
532
533 \brief hdd_ScanRequestCallback() -
534
535 The sme module calls this callback function once it finish the scan request
536 and this function notifies the scan complete event to the wpa_supplicant.
537
538 \param - halHandle - Pointer to the Hal Handle.
539 - pContext - Pointer to the data context.
540 - scanId - Scan ID.
541 - status - CSR Status.
542 \return - 0 for success, non zero for failure
543
544 --------------------------------------------------------------------------*/
545
546static eHalStatus hdd_ScanRequestCallback(tHalHandle halHandle, void *pContext,
547 tANI_U32 scanId, eCsrScanStatus status)
548{
549 struct net_device *dev = (struct net_device *) pContext;
550 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev) ;
551 union iwreq_data wrqu;
552 int we_event;
553 char *msg;
554
555 ENTER();
556
557 hddLog(LOGW,"%s called with halHandle = %p, pContext = %p, scanID = %d,"
558 " returned status = %d", __FUNCTION__, halHandle, pContext,
559 (int) scanId, (int) status);
560
561 /* if there is a scan request pending when the wlan driver is unloaded
562 we may be invoked as SME flushes its pending queue. If that is the
563 case, the underlying net_device may have already been destroyed, so
564 do some quick sanity before proceeding */
565 if (pAdapter->dev != dev)
566 {
567 hddLog(LOGW, "%s: device mismatch %p vs %p",
568 __FUNCTION__, pAdapter->dev, dev);
569 return eHAL_STATUS_SUCCESS;
570 }
571
572 /* Check the scanId */
573 if (pAdapter->scan_info.scanId != scanId)
574 {
575 hddLog(LOGW, "%s called with mismatched scanId pAdapter->scan_info.scanId = %d "
576 "scanId = %d ", __FUNCTION__, (int) pAdapter->scan_info.scanId,
577 (int) scanId);
578 }
579
580 /* Scan is no longer pending */
581 pAdapter->scan_info.mScanPending = VOS_FALSE;
582
583 // notify any applications that may be interested
584 memset(&wrqu, '\0', sizeof(wrqu));
585 we_event = SIOCGIWSCAN;
586 msg = NULL;
587 wireless_send_event(dev, we_event, &wrqu, msg);
588
589 EXIT();
590
591 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: exit !!!",__func__);
592
593 return eHAL_STATUS_SUCCESS;
594}
595
596/**---------------------------------------------------------------------------
597
598 \brief iw_set_scan() -
599
600 This function process the scan request from the wpa_supplicant
601 and set the scan request to the SME
602
603 \param - dev - Pointer to the net device.
604 - info - Pointer to the iw_request_info.
605 - wrqu - Pointer to the iwreq_data.
606 - extra - Pointer to the data.
607 \return - 0 for success, non zero for failure
608
609 --------------------------------------------------------------------------*/
610
611
612int iw_set_scan(struct net_device *dev, struct iw_request_info *info,
613 union iwreq_data *wrqu, char *extra)
614{
615 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev) ;
616 hdd_wext_state_t *pwextBuf = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter);
617 tCsrScanRequest scanRequest;
618 v_U32_t scanId = 0;
619 eHalStatus status = eHAL_STATUS_SUCCESS;
620 struct iw_scan_req *scanReq = (struct iw_scan_req *)extra;
621
622 ENTER();
623
624 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: enter !!!",__func__);
625
626#ifdef WLAN_BTAMP_FEATURE
627 //Scan not supported when AMP traffic is on.
628 if( VOS_TRUE == WLANBAP_AmpSessionOn() )
629 {
630 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, "%s: No scanning when AMP is on",__func__);
631 return eHAL_STATUS_SUCCESS;
632 }
633#endif
634 if(pAdapter->scan_info.mScanPending == TRUE)
635 {
636 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL, "%s:mScanPending is TRUE !!!",__func__);
637 return eHAL_STATUS_SUCCESS;
638 }
639
640 if ((WLAN_HDD_GET_CTX(pAdapter))->isLogpInProgress) {
641 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL, "%s:LOGP in Progress. Ignore!!!",__func__);
642 return eHAL_STATUS_SUCCESS;
643 }
644 vos_mem_zero( &scanRequest, sizeof(scanRequest));
645
646 if (NULL != wrqu->data.pointer)
647 {
648 /* set scanType, active or passive */
649 if ((IW_SCAN_TYPE_ACTIVE == scanReq->scan_type) || (eSIR_ACTIVE_SCAN == pAdapter->scan_info.scan_mode))
650 {
651 scanRequest.scanType = eSIR_ACTIVE_SCAN;
652 }
653 else
654 {
655 scanRequest.scanType = eSIR_PASSIVE_SCAN;
656 }
657
658 /* set bssid using sockaddr from iw_scan_req */
659 vos_mem_copy(scanRequest.bssid,
660 &scanReq->bssid.sa_data, sizeof(scanRequest.bssid) );
661
662 if (wrqu->data.flags & IW_SCAN_THIS_ESSID) {
663
664 if(scanReq->essid_len) {
665 scanRequest.SSIDs.numOfSSIDs = 1;
666 scanRequest.SSIDs.SSIDList =( tCsrSSIDInfo *)vos_mem_malloc(sizeof(tCsrSSIDInfo));
667 if(scanRequest.SSIDs.SSIDList) {
668 scanRequest.SSIDs.SSIDList->SSID.length = scanReq->essid_len;
669 vos_mem_copy(scanRequest.SSIDs.SSIDList-> SSID.ssId,scanReq->essid,scanReq->essid_len);
670 }
671 else
672 {
673 scanRequest.SSIDs.numOfSSIDs = 0;
674 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, "%s: Unable to allocate memory",__FUNCTION__);
675 VOS_ASSERT(0);
676 }
677 }
678 }
679
680 /* set min and max channel time */
681 scanRequest.minChnTime = scanReq->min_channel_time;
682 scanRequest.maxChnTime = scanReq->max_channel_time;
683
684 }
685 else
686 {
687 if(pAdapter->scan_info.scan_mode == eSIR_ACTIVE_SCAN) {
688 /* set the scan type to active */
689 scanRequest.scanType = eSIR_ACTIVE_SCAN;
690 } else {
691 scanRequest.scanType = eSIR_PASSIVE_SCAN;
692 }
693
694 vos_mem_set( scanRequest.bssid, sizeof( tCsrBssid ), 0xff );
695
696 /* set min and max channel time to zero */
697 scanRequest.minChnTime = 0;
698 scanRequest.maxChnTime = 0;
699 }
700
701 /* set BSSType to default type */
702 scanRequest.BSSType = eCSR_BSS_TYPE_ANY;
703
704 /*Scan all the channels */
705 scanRequest.ChannelInfo.numOfChannels = 0;
706
707 scanRequest.ChannelInfo.ChannelList = NULL;
708
709 /* set requestType to full scan */
710 scanRequest.requestType = eCSR_SCAN_REQUEST_FULL_SCAN;
711
712 /* if previous genIE is not NULL, update ScanIE */
713 if (0 != pwextBuf->genIE.length)
714 {
715 memset( &pAdapter->scan_info.scanAddIE, 0, sizeof(pAdapter->scan_info.scanAddIE) );
716 memcpy( pAdapter->scan_info.scanAddIE.addIEdata, pwextBuf->genIE.addIEdata,
717 pwextBuf->genIE.length );
718 pAdapter->scan_info.scanAddIE.length = pwextBuf->genIE.length;
719
720 pwextBuf->roamProfile.pAddIEScan = pAdapter->scan_info.scanAddIE.addIEdata;
721 pwextBuf->roamProfile.nAddIEScanLength = pAdapter->scan_info.scanAddIE.length;
722
723 /* clear previous genIE after use it */
724 memset( &pwextBuf->genIE, 0, sizeof(pwextBuf->genIE) );
725 }
726
727 /* push addIEScan in scanRequset if exist */
728 if (pAdapter->scan_info.scanAddIE.addIEdata &&
729 pAdapter->scan_info.scanAddIE.length)
730 {
731 scanRequest.uIEFieldLen = pAdapter->scan_info.scanAddIE.length;
732 scanRequest.pIEField = pAdapter->scan_info.scanAddIE.addIEdata;
733 }
734
735 status = sme_ScanRequest( (WLAN_HDD_GET_CTX(pAdapter))->hHal, pAdapter->sessionId,&scanRequest, &scanId, &hdd_ScanRequestCallback, dev );
736 if (!HAL_STATUS_SUCCESS(status))
737 {
738 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL, "%s:sme_ScanRequest fail %d!!!",__func__, status);
739 goto error;
740 }
741
742 pAdapter->scan_info.mScanPending = TRUE;
743
744 pAdapter->scan_info.scanId = scanId;
745
746error:
747 if ((wrqu->data.flags & IW_SCAN_THIS_ESSID) && (scanReq->essid_len))
748 vos_mem_free(scanRequest.SSIDs.SSIDList);
749
750 EXIT();
751
752 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: exit !!!",__func__);
753 return status;
754}
755
756/**---------------------------------------------------------------------------
757
758 \brief iw_get_scan() -
759
760 This function returns the scan results to the wpa_supplicant
761
762 \param - dev - Pointer to the net device.
763 - info - Pointer to the iw_request_info.
764 - wrqu - Pointer to the iwreq_data.
765 - extra - Pointer to the data.
766 \return - 0 for success, non zero for failure
767
768 --------------------------------------------------------------------------*/
769
770
771int iw_get_scan(struct net_device *dev,
772 struct iw_request_info *info,
773 union iwreq_data *wrqu, char *extra)
774{
775 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev) ;
776 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter);
777 tCsrScanResultInfo *pScanResult;
778 eHalStatus status = eHAL_STATUS_SUCCESS;
779 hdd_scan_info_t scanInfo;
780 tScanResultHandle pResult;
781 int i = 0;
782
783 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: enter buffer length %d!!!",
784 __func__, (wrqu->data.length)?wrqu->data.length:IW_SCAN_MAX_DATA);
785 ENTER();
786
787 if (TRUE == pAdapter->scan_info.mScanPending)
788 {
789 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL, "%s:mScanPending is TRUE !!!",__func__);
790 return -EAGAIN;
791 }
792
793 if ((WLAN_HDD_GET_CTX(pAdapter))->isLogpInProgress) {
794 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL, "%s:LOGP in Progress. Ignore!!!",__func__);
795 return -EAGAIN;
796 }
797
798 scanInfo.dev = dev;
799 scanInfo.start = extra;
800 scanInfo.info = info;
801
802 if (0 == wrqu->data.length)
803 {
804 scanInfo.end = extra + IW_SCAN_MAX_DATA;
805 }
806 else
807 {
808 scanInfo.end = extra + wrqu->data.length;
809 }
810
811 status = sme_ScanGetResult(hHal,pAdapter->sessionId,NULL,&pResult);
812
813 if (NULL == pResult)
814 {
815 // no scan results
816 hddLog(LOG1,"iw_get_scan: NULL Scan Result ");
817 return 0;
818 }
819
820 pScanResult = sme_ScanResultGetFirst(hHal, pResult);
821
822 while (pScanResult)
823 {
824 status = hdd_IndicateScanResult(&scanInfo, pScanResult);
825 if (0 != status)
826 {
827 break;
828 }
829 i++;
830 pScanResult = sme_ScanResultGetNext(hHal, pResult);
831 }
832
833 sme_ScanResultPurge(hHal, pResult);
834
835 EXIT();
836 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: exit total %d BSS reported !!!",__func__, i);
837 return status;
838}
839
840#if 0
841static eHalStatus hdd_CscanRequestCallback(tHalHandle halHandle, void *pContext,
842 tANI_U32 scanId, eCsrScanStatus status)
843{
844 struct net_device *dev = (struct net_device *) pContext;
845 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev) ;
846 hdd_wext_state_t *pwextBuf = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter);
847 union iwreq_data wrqu;
848 int we_event;
849 char *msg;
850 VOS_STATUS vos_status = VOS_STATUS_SUCCESS;
851 ENTER();
852
853 hddLog(LOG1,"%s called with halHandle = %p, pContext = %p, scanID = %d,"
854 " returned status = %d", __FUNCTION__, halHandle, pContext,
855 (int) scanId, (int) status);
856
857 /* Check the scanId */
858 if (pwextBuf->scanId != scanId)
859 {
860 hddLog(LOGW, "%s called with mismatched scanId pWextState->scanId = %d "
861 "scanId = %d ", __FUNCTION__, (int) pwextBuf->scanId,
862 (int) scanId);
863 }
864
865 /* Scan is no longer pending */
866 pwextBuf->mScanPending = VOS_FALSE;
867
868 // notify any applications that may be interested
869 memset(&wrqu, '\0', sizeof(wrqu));
870 we_event = SIOCGIWSCAN;
871 msg = NULL;
872 wireless_send_event(dev, we_event, &wrqu, msg);
873
874 vos_status = vos_event_set(&pwextBuf->vosevent);
875
876 if (!VOS_IS_STATUS_SUCCESS(vos_status))
877 {
878 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, ("ERROR: HDD vos_event_set failed!!"));
879 return VOS_STATUS_E_FAILURE;
880 }
881
882 EXIT();
883 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: exit !!!",__func__);
884
885 return eHAL_STATUS_SUCCESS;
886}
887#endif
888
889int iw_set_cscan(struct net_device *dev, struct iw_request_info *info,
890 union iwreq_data *wrqu, char *extra)
891{
892 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev) ;
893 hdd_wext_state_t *pwextBuf = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter);
894 tCsrScanRequest scanRequest;
895 v_U32_t scanId = 0;
896 eHalStatus status = eHAL_STATUS_SUCCESS;
897 v_U8_t channelIdx;
898
899 ENTER();
900 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: enter !!!",__func__);
901
902#ifdef WLAN_BTAMP_FEATURE
903 //Scan not supported when AMP traffic is on.
904 if( VOS_TRUE == WLANBAP_AmpSessionOn() )
905 {
906 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, "%s: No scanning when AMP is on",__func__);
907 return eHAL_STATUS_SUCCESS;
908 }
909#endif
910
911 if ((WLAN_HDD_GET_CTX(pAdapter))->isLogpInProgress)
912 {
913 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL, "%s:LOGP in Progress. Ignore!!!",__func__);
914 return eHAL_STATUS_SUCCESS;
915 }
916
917 vos_mem_zero( &scanRequest, sizeof(scanRequest));
918 if (NULL != wrqu->data.pointer)
919 {
920 char *str_ptr = NULL;
921 tCsrSSIDInfo *SsidInfo = NULL;
922 int num_ssid = 0;
923 int i, j, ssid_start;
924 hdd_scan_pending_option_e scanPendingOption = WEXT_SCAN_PENDING_GIVEUP;
925
926 /* save the original buffer */
927 str_ptr = wrqu->data.pointer;
928
929 i = WEXT_CSCAN_HEADER_SIZE;
930
931 if( WEXT_CSCAN_PENDING_SECTION == str_ptr[i] )
932 {
933 scanPendingOption = (hdd_scan_pending_option_e)str_ptr[++i];
934 ++i;
935 }
936 pAdapter->scan_info.scan_pending_option = scanPendingOption;
937
938 if(pAdapter->scan_info.mScanPending == TRUE)
939 {
940 hddLog(LOG1,"%s: mScanPending is TRUE",__func__);
941 /* If any scan is pending, just giveup this scan request */
942 if(WEXT_SCAN_PENDING_GIVEUP == scanPendingOption)
943 {
944 pAdapter->scan_info.waitScanResult = FALSE;
945 return eHAL_STATUS_SUCCESS;
946 }
947 /* If any scan pending, wait till finish current scan,
948 and try this scan request when previous scan finish */
949 else if(WEXT_SCAN_PENDING_DELAY == scanPendingOption)
950 {
951 pAdapter->scan_info.waitScanResult = TRUE;
952 vos_event_reset(&pAdapter->scan_info.scan_finished_event);
953 if(vos_wait_single_event(&pAdapter->scan_info.scan_finished_event,
954 WEXT_CSCAN_SCAN_DONE_WAIT_TIME))
955 {
956 hddLog(LOG1,"%s: Previous SCAN does not finished on time",__func__);
957 return eHAL_STATUS_SUCCESS;
958 }
959 }
960 /* Piggyback previous scan result */
961 else if(WEXT_SCAN_PENDING_PIGGYBACK == scanPendingOption)
962 {
963 pAdapter->scan_info.waitScanResult = TRUE;
964 return eHAL_STATUS_SUCCESS;
965 }
966 }
967 pAdapter->scan_info.waitScanResult = FALSE;
968
969 /* Check for scan IE */
970 while( WEXT_CSCAN_SSID_SECTION == str_ptr[i] )
971 {
972 /* ssid_len */
973 if(str_ptr[++i] != WEXT_CSCAN_CHANNEL_SECTION)
974 {
975 /* total number of ssid's */
976 num_ssid++;
977 /* increment length filed */
978 i += str_ptr[i] + 1;
979 }
980 /* i should be saved and it will be pointing to 'C' */
981 }
982
983 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: numSsid %d !!!",__func__, num_ssid);
984 if( num_ssid )
985 {
986 /* To be fixed in SME and PE: override the number of ssid with 1,
987 * as SME and PE does not handle multiple SSID in scan request
988 * */
989 scanRequest.SSIDs.numOfSSIDs = num_ssid;
990 /* Allocate num_ssid tCsrSSIDInfo structure */
991 SsidInfo = scanRequest.SSIDs.SSIDList =( tCsrSSIDInfo *)vos_mem_malloc(num_ssid*sizeof(tCsrSSIDInfo));
992 if(NULL == scanRequest.SSIDs.SSIDList) {
993 hddLog(VOS_TRACE_LEVEL_ERROR, "memory alloc failed SSIDInfo buffer");
994 return -ENOMEM;
995 }
996
997 /* copy all the ssid's and their length */
998 ssid_start = WEXT_CSCAN_HEADER_SIZE + 1;/* skipping 'S' */
999 for(j = 0; j < num_ssid; j++) {
1000 if( SIR_MAC_MAX_SSID_LENGTH < str_ptr[ssid_start]){
1001 scanRequest.SSIDs.numOfSSIDs -= 1;
1002 } else{
1003 /* get the ssid length */
1004 SsidInfo->SSID.length = str_ptr[ssid_start++];
1005 vos_mem_copy(SsidInfo->SSID.ssId, &str_ptr[ssid_start], SsidInfo->SSID.length);
1006 hddLog(VOS_TRACE_LEVEL_INFO_HIGH, "SSID number %d: %s\n", j, SsidInfo->SSID.ssId);
1007 }
1008 /* skipping length */
1009 ssid_start += str_ptr[ssid_start - 1] + 1;
1010 /* Store next ssid info */
1011 SsidInfo++;
1012 }
1013 }
1014
1015 /* Check for Channel IE */
1016 if ( WEXT_CSCAN_CHANNEL_SECTION == str_ptr[i])
1017 {
1018 if( str_ptr[++i] == 0 )
1019 {
1020 scanRequest.ChannelInfo.numOfChannels = 0;
1021 scanRequest.ChannelInfo.ChannelList = NULL;
1022 i++;
1023 }
1024 else {
1025
1026 /* increment the counter */
1027 scanRequest.ChannelInfo.numOfChannels = str_ptr[i++];
1028 /* store temp channel list */
1029 /* SME expects 1 byte channel content */
1030 scanRequest.ChannelInfo.ChannelList = vos_mem_malloc(scanRequest.ChannelInfo.numOfChannels * sizeof(v_U8_t));
1031 if(NULL == scanRequest.ChannelInfo.ChannelList)
1032 {
1033 hddLog(VOS_TRACE_LEVEL_INFO_HIGH, "memory alloc failed for channel list creation");
1034 status = -ENOMEM;
1035 goto exit_point;
1036 }
1037
1038 for(channelIdx = 0; channelIdx < scanRequest.ChannelInfo.numOfChannels; channelIdx++)
1039 {
1040 /* SCAN request from upper layer has 2 bytes channel */
1041 scanRequest.ChannelInfo.ChannelList[channelIdx] = (v_U8_t)str_ptr[i];
1042 i += sizeof(v_U16_t);
1043 }
1044 }
1045 }
1046
1047 /* Set default */
1048 scanRequest.scanType = eSIR_ACTIVE_SCAN;
1049 scanRequest.minChnTime = 0;
1050 scanRequest.maxChnTime = 0;
1051
1052 /* Now i is pointing to passive dwell dwell time */
1053 /* 'P',min dwell time, max dwell time */
1054 /* next two offsets contain min and max channel time */
1055 if( WEXT_CSCAN_PASV_DWELL_SECTION == (str_ptr[i]) )
1056 {
1057 /* No SSID specified, num_ssid == 0, then start paasive scan */
1058 if (!num_ssid || (eSIR_PASSIVE_SCAN == pAdapter->scan_info.scan_mode))
1059 {
1060 scanRequest.scanType = eSIR_PASSIVE_SCAN;
1061 scanRequest.minChnTime = (v_U8_t)str_ptr[++i];//scanReq->min_channel_time;
1062 scanRequest.maxChnTime = (v_U8_t)str_ptr[++i];//scanReq->max_channel_time;
1063 i++;
1064 }
1065 else
1066 {
1067 i += 3;
1068 }
1069 }
1070
1071 /* H indicates active channel time */
1072 if( WEXT_CSCAN_HOME_DWELL_SECTION == (str_ptr[i]) )
1073 {
1074 if (num_ssid || (eSIR_ACTIVE_SCAN == pAdapter->scan_info.scan_mode))
1075 {
1076 scanRequest.scanType = eSIR_ACTIVE_SCAN;
1077 scanRequest.minChnTime = str_ptr[++i];//scanReq->min_channel_time;
1078 scanRequest.maxChnTime = str_ptr[++i];//scanReq->max_channel_time;
1079 i++;
1080 }
1081 else
1082 {
1083 i +=3;
1084 }
1085 }
1086 scanRequest.BSSType = eCSR_BSS_TYPE_ANY;
1087 /* set requestType to full scan */
1088 scanRequest.requestType = eCSR_SCAN_REQUEST_FULL_SCAN;
1089 pAdapter->scan_info.mScanPending = TRUE;
1090
1091 /* if previous genIE is not NULL, update ScanIE */
1092 if(0 != pwextBuf->genIE.length)
1093 {
1094 memset( &pAdapter->scan_info.scanAddIE, 0, sizeof(pAdapter->scan_info.scanAddIE) );
1095 memcpy( pAdapter->scan_info.scanAddIE.addIEdata, pwextBuf->genIE.addIEdata,
1096 pwextBuf->genIE.length );
1097 pAdapter->scan_info.scanAddIE.length = pwextBuf->genIE.length;
1098
1099 pwextBuf->roamProfile.pAddIEScan = pAdapter->scan_info.scanAddIE.addIEdata;
1100 pwextBuf->roamProfile.nAddIEScanLength = pAdapter->scan_info.scanAddIE.length;
1101
1102 /* clear previous genIE after use it */
1103 memset( &pwextBuf->genIE, 0, sizeof(pwextBuf->genIE) );
1104 }
1105
1106 /* push addIEScan in scanRequset if exist */
1107 if (pAdapter->scan_info.scanAddIE.addIEdata &&
1108 pAdapter->scan_info.scanAddIE.length)
1109 {
1110 scanRequest.uIEFieldLen = pAdapter->scan_info.scanAddIE.length;
1111 scanRequest.pIEField = pAdapter->scan_info.scanAddIE.addIEdata;
1112 }
1113
1114 status = sme_ScanRequest( (WLAN_HDD_GET_CTX(pAdapter))->hHal,
1115 pAdapter->sessionId,&scanRequest, &scanId, &hdd_ScanRequestCallback, dev );
1116 if( !HAL_STATUS_SUCCESS(status) )
1117 {
1118 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL, "%s: SME scan fail status %d !!!",__func__, status);
1119 pAdapter->scan_info.mScanPending = FALSE;
1120 status = -EINVAL;
1121 goto exit_point;
1122 }
1123
1124 pAdapter->scan_info.scanId = scanId;
1125
1126 } //end of data->pointer
1127 else {
1128 status = -1;
1129 }
1130
1131exit_point:
1132
1133 /* free ssidlist */
1134 if (scanRequest.SSIDs.SSIDList)
1135 {
1136 vos_mem_free(scanRequest.SSIDs.SSIDList);
1137 }
1138 /* free the channel list */
1139 if(scanRequest.ChannelInfo.ChannelList)
1140 {
1141 vos_mem_free((void*)scanRequest.ChannelInfo.ChannelList);
1142 }
1143
1144 EXIT();
1145 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: exit !!!",__func__);
1146 return status;
1147}
1148
1149/* Abort any MAC scan if in progress */
1150void hdd_abort_mac_scan(hdd_context_t* pHddCtx)
1151{
1152 sme_AbortMacScan(pHddCtx->hHal);
1153}
1154