blob: 2804c59f2f699f1bfbf54287d0825cd00adccc53 [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
2 * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved.
3 *
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 * This file was originally distributed by Qualcomm Atheros, Inc.
24 * under proprietary terms before Copyright ownership was assigned
25 * to the Linux Foundation.
26 */
27
28/**
29 * DOC: wlan_hdd_scan.c
30 *
31 * WLAN Host Device Driver scan implementation
32 */
33
34#include <linux/wireless.h>
35#include <net/cfg80211.h>
36
37#include "wlan_hdd_includes.h"
38#include "cds_api.h"
39#include "cds_api.h"
40#include "ani_global.h"
41#include "dot11f.h"
42#include "cds_sched.h"
43#include "wlan_hdd_p2p.h"
44#include "wlan_hdd_trace.h"
45#include "wlan_hdd_scan.h"
46#include "cds_concurrency.h"
47#include "wma_api.h"
48
49#define MAX_RATES 12
50#define HDD_WAKE_LOCK_SCAN_DURATION (5 * 1000) /* in msec */
51
52#define SCAN_DONE_EVENT_BUF_SIZE 4096
53#define RATE_MASK 0x7f
54
55/**
56 * typedef tSSIDBcastType - SSID broadcast type
57 * @eBCAST_UNKNOWN: Broadcast unknown
58 * @eBCAST_NORMAL: Broadcast normal
59 * @eBCAST_HIDDEN: Broadcast hidden
60 */
61typedef enum eSSIDBcastType {
62 eBCAST_UNKNOWN = 0,
63 eBCAST_NORMAL = 1,
64 eBCAST_HIDDEN = 2,
65} tSSIDBcastType;
66
67
68/**
69 * typedef hdd_scan_info_t - HDD scan info
70 * @dev: Pointer to net device
71 * @info: Pointer to request info
72 * @start: Start pointer
73 * @end: End pointer
74 */
75typedef struct hdd_scan_info {
76 struct net_device *dev;
77 struct iw_request_info *info;
78 char *start;
79 char *end;
80} hdd_scan_info_t, *hdd_scan_info_tp;
81
82/**
83 * hdd_translate_abg_rate_to_mbps_rate() - translate abg rate to Mbps rate
84 * @pFcRate: Rate pointer
85 *
86 * Return: Mbps rate in integer
87 */
88static int32_t hdd_translate_abg_rate_to_mbps_rate(uint8_t *pFcRate)
89{
90 /* Slightly more sophisticated processing has to take place here.
91 * Basic rates are rounded DOWN. HT rates are rounded UP
92 */
93 return ((((int32_t) *pFcRate) & 0x007f) * 1000000) / 2;
94}
95
96/**
97 * hdd_add_iw_stream_event() - add iw stream event
98 * @cmd: Command
99 * @length: Length
100 * @data: Pointer to data
101 * @pscanInfo: Pointer to scan info
102 * @last_event: Pointer to pointer to last event
103 * @current_event: Pointer to pointer to current event
104 *
105 * Return: 0 for success, non zero for failure
106 */
107static int hdd_add_iw_stream_event(int cmd, int length, char *data,
108 hdd_scan_info_t *pscanInfo,
109 char **last_event,
110 char **current_event)
111{
112 struct iw_event event;
113
114 *last_event = *current_event;
115 cdf_mem_zero(&event, sizeof(struct iw_event));
116 event.cmd = cmd;
117 event.u.data.flags = 1;
118 event.u.data.length = length;
119 *current_event =
120 iwe_stream_add_point(pscanInfo->info, *current_event,
121 pscanInfo->end, &event, data);
122
123 if (*last_event == *current_event) {
124 /* no space to add event */
125 hddLog(LOGE, "%s: no space left to add event", __func__);
126 return -E2BIG; /* Error code, may be E2BIG */
127 }
128
129 return 0;
130}
131
132/**
133 * hdd_get_wparsn_ies() - get wpa RSN IEs
134 * @ieFields: Pointer to the Bss Descriptor IEs
135 * @ie_length: IE Length
136 * @last_event: Points to last event
137 * @current_event: Points to current event
138 *
139 * This function extract the WPA/RSN IE from the Bss descriptor IEs fields
140 *
141 * Return: 0 for success, non zero for failure
142 */
143static int hdd_get_wparsn_ies(uint8_t *ieFields, uint16_t ie_length,
144 char **last_event, char **current_event,
145 hdd_scan_info_t *pscanInfo)
146{
147 uint8_t eid, elen, *element;
148 uint16_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 eid = element[0];
157 elen = element[1];
158
159 /* If element length is greater than total remaining ie length,
160 * break the loop
161 */
162 if ((elen + 2) > tie_length)
163 break;
164
165 switch (eid) {
166 case DOT11F_EID_WPA:
167 case DOT11F_EID_RSN:
168#ifdef FEATURE_WLAN_WAPI
169 case DOT11F_EID_WAPI:
170#endif
171 if (hdd_add_iw_stream_event
172 (IWEVGENIE, elen + 2, (char *)element, pscanInfo,
173 last_event, current_event) < 0)
174 return -E2BIG;
175 break;
176
177 default:
178 break;
179 }
180
181 /* Next element */
182 tie_length -= (2 + elen);
183 element += 2 + elen;
184 }
185
186 return 0;
187}
188
189/**
190 * hdd_indicate_scan_result() - indicate scan results
191 * @scanInfo: Pointer to the scan info structure.
192 * @descriptor: Pointer to the Bss Descriptor.
193 *
194 * This function returns the scan results to the wpa_supplicant
195 *
196 * @Return: 0 for success, non zero for failure
197 */
198#define MAX_CUSTOM_LEN 64
199static int hdd_indicate_scan_result(hdd_scan_info_t *scanInfo,
200 tCsrScanResultInfo *scan_result)
201{
202 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(scanInfo->dev);
203 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter);
204 tSirBssDescription *descriptor = &scan_result->BssDescriptor;
205 struct iw_event event;
206 char *current_event = scanInfo->start;
207 char *end = scanInfo->end;
208 char *last_event;
209 char *current_pad;
210 uint16_t ie_length = 0;
211 uint16_t capabilityInfo;
212 char *modestr;
213 int error;
214 char custom[MAX_CUSTOM_LEN];
215 char *p;
216
217 hddLog(LOG1, "hdd_indicate_scan_result " MAC_ADDRESS_STR,
218 MAC_ADDR_ARRAY(descriptor->bssId));
219
220 error = 0;
221 last_event = current_event;
222 cdf_mem_zero(&event, sizeof(event));
223
224 /* BSSID */
225 event.cmd = SIOCGIWAP;
226 event.u.ap_addr.sa_family = ARPHRD_ETHER;
227 cdf_mem_copy(event.u.ap_addr.sa_data, descriptor->bssId,
228 sizeof(descriptor->bssId));
229 current_event = iwe_stream_add_event(scanInfo->info, current_event, end,
230 &event, IW_EV_ADDR_LEN);
231
232 if (last_event == current_event) {
233 /* no space to add event */
234 /* Error code may be E2BIG */
235 hddLog(LOGE, "hdd_indicate_scan_result: no space for SIOCGIWAP ");
236 return -E2BIG;
237 }
238
239 last_event = current_event;
240 cdf_mem_zero(&event, sizeof(struct iw_event));
241
242 /* Protocol Name */
243 event.cmd = SIOCGIWNAME;
244
245 switch (descriptor->nwType) {
246 case eSIR_11A_NW_TYPE:
247 modestr = "a";
248 break;
249 case eSIR_11B_NW_TYPE:
250 modestr = "b";
251 break;
252 case eSIR_11G_NW_TYPE:
253 modestr = "g";
254 break;
255 case eSIR_11N_NW_TYPE:
256 modestr = "n";
257 break;
258 default:
259 hddLog(LOGW, "%s: Unknown network type [%d]",
260 __func__, descriptor->nwType);
261 modestr = "?";
262 break;
263 }
264 snprintf(event.u.name, IFNAMSIZ, "IEEE 802.11%s", modestr);
265 current_event = iwe_stream_add_event(scanInfo->info, current_event, end,
266 &event, IW_EV_CHAR_LEN);
267
268 if (last_event == current_event) { /* no space to add event */
269 hddLog(LOGE,
270 "hdd_indicate_scan_result: no space for SIOCGIWNAME");
271 /* Error code, may be E2BIG */
272 return -E2BIG;
273 }
274
275 last_event = current_event;
276 cdf_mem_zero(&event, sizeof(struct iw_event));
277
278 /*Freq */
279 event.cmd = SIOCGIWFREQ;
280
281 event.u.freq.m = descriptor->channelId;
282 event.u.freq.e = 0;
283 event.u.freq.i = 0;
284 current_event = iwe_stream_add_event(scanInfo->info, current_event, end,
285 &event, IW_EV_FREQ_LEN);
286
287 if (last_event == current_event) { /* no space to add event */
288 hddLog(LOGE,
289 "hdd_indicate_scan_result: no space for SIOCGIWFREQ");
290 return -E2BIG;
291 }
292
293 last_event = current_event;
294 cdf_mem_zero(&event, sizeof(struct iw_event));
295
296 /* BSS Mode */
297 event.cmd = SIOCGIWMODE;
298
299 capabilityInfo = descriptor->capabilityInfo;
300
301 if (SIR_MAC_GET_ESS(capabilityInfo)) {
302 event.u.mode = IW_MODE_MASTER;
303 } else if (SIR_MAC_GET_IBSS(capabilityInfo)) {
304 event.u.mode = IW_MODE_ADHOC;
305 } else {
306 /* neither ESS or IBSS */
307 event.u.mode = IW_MODE_AUTO;
308 }
309
310 current_event = iwe_stream_add_event(scanInfo->info, current_event, end,
311 &event, IW_EV_UINT_LEN);
312
313 if (last_event == current_event) { /* no space to add event */
314 hddLog(LOGE,
315 "hdd_indicate_scan_result: no space for SIOCGIWMODE");
316 return -E2BIG;
317 }
318 /* To extract SSID */
319 ie_length = GET_IE_LEN_IN_BSS(descriptor->length);
320
321 if (ie_length > 0) {
322 /* dot11BeaconIEs is a large struct, so we make it static to
323 avoid stack overflow. This API is only invoked via ioctl,
324 so it is serialized by the kernel rtnl_lock and hence does
325 not need to be reentrant */
326 static tDot11fBeaconIEs dot11BeaconIEs;
327 tDot11fIESSID *pDot11SSID;
328 tDot11fIESuppRates *pDot11SuppRates;
329 tDot11fIEExtSuppRates *pDot11ExtSuppRates;
330 tDot11fIEHTCaps *pDot11IEHTCaps;
331 int numBasicRates = 0;
332 int maxNumRates = 0;
333
334 pDot11IEHTCaps = NULL;
335
336 dot11f_unpack_beacon_i_es((tpAniSirGlobal)
337 hHal, (uint8_t *) descriptor->ieFields,
338 ie_length, &dot11BeaconIEs);
339
340 pDot11SSID = &dot11BeaconIEs.SSID;
341
342 if (pDot11SSID->present) {
343 last_event = current_event;
344 cdf_mem_zero(&event, sizeof(struct iw_event));
345
346 event.cmd = SIOCGIWESSID;
347 event.u.data.flags = 1;
348 event.u.data.length = scan_result->ssId.length;
349 current_event =
350 iwe_stream_add_point(scanInfo->info, current_event,
351 end, &event,
352 (char *)scan_result->ssId.
353 ssId);
354
355 if (last_event == current_event) { /* no space to add event */
356 hddLog(LOGE,
357 "hdd_indicate_scan_result: no space for SIOCGIWESSID");
358 return -E2BIG;
359 }
360 }
361
362 if (hdd_get_wparsn_ies
363 ((uint8_t *) descriptor->ieFields, ie_length, &last_event,
364 &current_event, scanInfo) < 0) {
365 hddLog(LOGE,
366 "hdd_indicate_scan_result: no space for SIOCGIWESSID");
367 return -E2BIG;
368 }
369
370 last_event = current_event;
371 current_pad = current_event + IW_EV_LCP_LEN;
372 cdf_mem_zero(&event, sizeof(struct iw_event));
373
374 /*Rates */
375 event.cmd = SIOCGIWRATE;
376
377 pDot11SuppRates = &dot11BeaconIEs.SuppRates;
378
379 if (pDot11SuppRates->present) {
380 int i;
381
382 numBasicRates = pDot11SuppRates->num_rates;
383 for (i = 0; i < pDot11SuppRates->num_rates; i++) {
384 if (0 != (pDot11SuppRates->rates[i] & 0x7F)) {
385 event.u.bitrate.value =
386 hdd_translate_abg_rate_to_mbps_rate
387 (&pDot11SuppRates->rates[i]);
388
389 current_pad =
390 iwe_stream_add_value(scanInfo->info,
391 current_event,
392 current_pad,
393 end, &event,
394 IW_EV_PARAM_LEN);
395 }
396 }
397
398 }
399
400 pDot11ExtSuppRates = &dot11BeaconIEs.ExtSuppRates;
401
402 if (pDot11ExtSuppRates->present) {
403 int i, no_of_rates;
404 maxNumRates =
405 numBasicRates + pDot11ExtSuppRates->num_rates;
406
407 /* Check to make sure the total number of rates
408 * doesn't exceed IW_MAX_BITRATES
409 */
410
411 maxNumRates = CDF_MIN(maxNumRates, IW_MAX_BITRATES);
412
413 if ((maxNumRates - numBasicRates) > MAX_RATES) {
414 no_of_rates = MAX_RATES;
415 hddLog(LOGW,
416 "Accessing array out of bound that array is pDot11ExtSuppRates->rates ");
417 } else {
418 no_of_rates = maxNumRates - numBasicRates;
419 }
420 for (i = 0; i < no_of_rates; i++) {
421 if (0 != (pDot11ExtSuppRates->rates[i] & 0x7F)) {
422 event.u.bitrate.value =
423 hdd_translate_abg_rate_to_mbps_rate
424 (&pDot11ExtSuppRates->rates[i]);
425
426 current_pad =
427 iwe_stream_add_value(scanInfo->info,
428 current_event,
429 current_pad,
430 end, &event,
431 IW_EV_PARAM_LEN);
432 }
433 }
434 }
435
436 if ((current_pad - current_event) >= IW_EV_LCP_LEN) {
437 current_event = current_pad;
438 } else {
439 if (last_event == current_event) { /* no space to add event */
440 hddLog(LOGE,
441 "hdd_indicate_scan_result: no space for SIOCGIWRATE");
442 return -E2BIG;
443 }
444 }
445
446 last_event = current_event;
447 cdf_mem_zero(&event, sizeof(struct iw_event));
448
449 event.cmd = SIOCGIWENCODE;
450
451 if (SIR_MAC_GET_PRIVACY(capabilityInfo)) {
452 event.u.data.flags =
453 IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
454 } else {
455 event.u.data.flags = IW_ENCODE_DISABLED;
456 }
457 event.u.data.length = 0;
458
459 current_event =
460 iwe_stream_add_point(scanInfo->info, current_event, end,
461 &event, (char *)pDot11SSID->ssid);
462 if (last_event == current_event) {
463 hddLog(LOGE,
464 "hdd_indicate_scan_result: no space for SIOCGIWENCODE");
465 return -E2BIG;
466 }
467 }
468
469 last_event = current_event;
470 cdf_mem_zero(&event, sizeof(struct iw_event));
471
472 /* RSSI */
473 event.cmd = IWEVQUAL;
474 event.u.qual.qual = descriptor->rssi;
475 event.u.qual.noise = descriptor->sinr;
476 event.u.qual.level = CDF_MIN((descriptor->rssi + descriptor->sinr), 0);
477
478 event.u.qual.updated = IW_QUAL_ALL_UPDATED;
479
480 current_event = iwe_stream_add_event(scanInfo->info, current_event,
481 end, &event, IW_EV_QUAL_LEN);
482
483 if (last_event == current_event) { /* no space to add event */
484 hddLog(LOGE, "hdd_indicate_scan_result: no space for IWEVQUAL");
485 return -E2BIG;
486 }
487
488 /* AGE */
489 event.cmd = IWEVCUSTOM;
490 p = custom;
491 p += scnprintf(p, MAX_CUSTOM_LEN, " Age: %lu",
492 cdf_mc_timer_get_system_ticks() -
493 descriptor->nReceivedTime);
494 event.u.data.length = p - custom;
495 current_event = iwe_stream_add_point(scanInfo->info, current_event, end,
496 &event, custom);
497 if (last_event == current_event) { /* no space to add event */
498 hddLog(LOGE,
499 "hdd_indicate_scan_result: no space for IWEVCUSTOM (age)");
500 return -E2BIG;
501 }
502
503 scanInfo->start = current_event;
504
505 return 0;
506}
507
508
509/**
510 * wlan_hdd_scan_request_enqueue() - enqueue Scan Request
511 * @adapter: Pointer to the adapter
512 * @scan_req: Pointer to the scan request
513 *
514 * Enqueue scan request in the global HDD scan list.This list
515 * stores the active scan request information.
516 *
517 * Return: 0 on success, error number otherwise
518 */
519static int wlan_hdd_scan_request_enqueue(hdd_adapter_t *adapter,
520 struct cfg80211_scan_request *scan_req,
521 uint8_t source, uint32_t scan_id,
522 uint32_t timestamp)
523{
524 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
525 struct hdd_scan_req *hdd_scan_req;
526 CDF_STATUS status;
527
528 ENTER();
529 hdd_scan_req = cdf_mem_malloc(sizeof(*hdd_scan_req));
530 if (NULL == hdd_scan_req) {
531 hddLog(LOGP, FL("malloc failed for Scan req"));
532 return -ENOMEM;
533 }
534
535 hdd_scan_req->adapter = adapter;
536 hdd_scan_req->scan_request = scan_req;
537 hdd_scan_req->source = source;
538 hdd_scan_req->scan_id = scan_id;
539 hdd_scan_req->timestamp = timestamp;
540
541 cdf_spin_lock(&hdd_ctx->hdd_scan_req_q_lock);
542 status = cdf_list_insert_back(&hdd_ctx->hdd_scan_req_q,
543 &hdd_scan_req->node);
544 cdf_spin_unlock(&hdd_ctx->hdd_scan_req_q_lock);
545
546 if (CDF_STATUS_SUCCESS != status) {
547 hdd_err("Failed to enqueue Scan Req");
548 cdf_mem_free(hdd_scan_req);
549 return -EINVAL;
550 }
551 EXIT();
552 return 0;
553}
554
555/**
556 * wlan_hdd_scan_request_dequeue() - dequeue scan request
557 * @hdd_ctx: Global HDD context
558 * @scan_id: scan id
559 * @req: scan request
560 * @source : returns source of the scan request
561 * @timestamp: scan request timestamp
562 *
563 * Return: CDF_STATUS
564 */
565CDF_STATUS wlan_hdd_scan_request_dequeue(hdd_context_t *hdd_ctx,
566 uint32_t scan_id, struct cfg80211_scan_request **req, uint8_t *source,
567 uint32_t *timestamp)
568{
569 CDF_STATUS status = CDF_STATUS_E_FAILURE;
570 struct hdd_scan_req *hdd_scan_req;
571 cdf_list_node_t *pNode = NULL, *ppNode = NULL;
572
573 hdd_info("Dequeue Scan id: %d", scan_id);
574
575 if ((source == NULL) && (timestamp == NULL) && (req == NULL))
576 return CDF_STATUS_E_NULL_VALUE;
577
578 cdf_spin_lock(&hdd_ctx->hdd_scan_req_q_lock);
579
580 if (list_empty(&hdd_ctx->hdd_scan_req_q.anchor)) {
581 cdf_spin_unlock(&hdd_ctx->hdd_scan_req_q_lock);
582 return CDF_STATUS_E_FAILURE;
583 }
584
585 if (CDF_STATUS_SUCCESS !=
586 cdf_list_peek_front(&hdd_ctx->hdd_scan_req_q, &ppNode)) {
587 cdf_spin_unlock(&hdd_ctx->hdd_scan_req_q_lock);
588 hdd_err("Failed to remove Scan Req from queue");
589 return CDF_STATUS_E_FAILURE;
590 }
591
592 do {
593 pNode = ppNode;
594 hdd_scan_req = (struct hdd_scan_req *)pNode;
595 if (hdd_scan_req->scan_id == scan_id) {
596 status = cdf_list_remove_node(&hdd_ctx->hdd_scan_req_q,
597 pNode);
598 if (status == CDF_STATUS_SUCCESS) {
599 *req = hdd_scan_req->scan_request;
600 *source = hdd_scan_req->source;
601 *timestamp = hdd_scan_req->timestamp;
602 cdf_mem_free(hdd_scan_req);
603 cdf_spin_unlock(&hdd_ctx->hdd_scan_req_q_lock);
604 hdd_info("removed Scan id: %d, req = %p",
605 scan_id, req);
606 return CDF_STATUS_SUCCESS;
607 } else {
608 cdf_spin_unlock(&hdd_ctx->hdd_scan_req_q_lock);
609 hdd_err("Failed to remove node scan id %d",
610 scan_id);
611 return status;
612 }
613 }
614 } while (CDF_STATUS_SUCCESS ==
615 cdf_list_peek_next(&hdd_ctx->hdd_scan_req_q, pNode, &ppNode));
616
617 cdf_spin_unlock(&hdd_ctx->hdd_scan_req_q_lock);
618 hdd_err("Failed to find scan id %d", scan_id);
619 return status;
620}
621
622/**
623 * hdd_scan_request_callback() - scan complete callback from SME
624 * @halHandle: Pointer to the Hal Handle
625 * @pContext: Pointer to the data context
626 * @sessionId: Session identifier
627 * @scanId: Scan ID
628 * @status: CSR Status
629 *
630 * The sme module calls this callback function once it finish the scan request
631 * and this function notifies the scan complete event to the wpa_supplicant.
632 *
633 * Return: 0 for success, non zero for failure
634 */
635
636static CDF_STATUS
637hdd_scan_request_callback(tHalHandle halHandle, void *pContext,
638 uint8_t sessionId, uint32_t scanId,
639 eCsrScanStatus status)
640{
641 struct net_device *dev = (struct net_device *)pContext;
642 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
643 hdd_context_t *hddctx = WLAN_HDD_GET_CTX(pAdapter);
644 union iwreq_data wrqu;
645 int we_event;
646 char *msg;
647 uint8_t source;
648 struct cfg80211_scan_request *req;
649 uint32_t timestamp;
650 uint32_t size = 0;
651
652 ENTER();
653 hddLog(LOGW,
654 "%s called with halHandle = %p, pContext = %p, scanID = %d,"
655 " returned status = %d", __func__, halHandle, pContext,
656 (int)scanId, (int)status);
657
658 /* if there is a scan request pending when the wlan driver is unloaded
659 * we may be invoked as SME flushes its pending queue. If that is the
660 * case, the underlying net_device may have already been destroyed, so
661 * do some quick sanity before proceeding
662 */
663 if (pAdapter->dev != dev) {
664 hddLog(LOGW, "%s: device mismatch %p vs %p",
665 __func__, pAdapter->dev, dev);
666 return CDF_STATUS_SUCCESS;
667 }
668
669 wlan_hdd_scan_request_dequeue(hddctx, scanId, &req, &source,
670 &timestamp);
671
672 if (req != NULL)
673 hdd_err("Got unexpected request struct for Scan id %d",
674 scanId);
675
676 cdf_spin_lock(&hddctx->hdd_scan_req_q_lock);
677 cdf_list_size(&(hddctx->hdd_scan_req_q), &size);
678 if (!size)
679 /* Scan is no longer pending */
680 pAdapter->scan_info.mScanPending = false;
681 cdf_spin_unlock(&hddctx->hdd_scan_req_q_lock);
682
683 /* notify any applications that may be interested */
684 memset(&wrqu, '\0', sizeof(wrqu));
685 we_event = SIOCGIWSCAN;
686 msg = NULL;
687 wireless_send_event(dev, we_event, &wrqu, msg);
688
689 EXIT();
690 return CDF_STATUS_SUCCESS;
691}
692
693/**
694 * __iw_set_scan() - set scan request
695 * @dev: Pointer to the net device
696 * @info: Pointer to the iw_request_info
697 * @wrqu: Pointer to the iwreq_data
698 * @extra: Pointer to the data
699 *
700 * This function process the scan request from the wpa_supplicant
701 * and set the scan request to the SME
702 *
703 * Return: 0 for success, non zero for failure
704 */
705
706static int __iw_set_scan(struct net_device *dev, struct iw_request_info *info,
707 union iwreq_data *wrqu, char *extra)
708{
709 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
710 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(pAdapter);
711 hdd_wext_state_t *pwextBuf = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter);
712 tCsrScanRequest scanRequest;
713 CDF_STATUS status = CDF_STATUS_SUCCESS;
714 struct iw_scan_req *scanReq = (struct iw_scan_req *)extra;
715 hdd_adapter_t *con_sap_adapter;
716 uint16_t con_dfs_ch;
717 int ret;
718
719 ENTER();
720
721 hdd_ctx = WLAN_HDD_GET_CTX(pAdapter);
722 ret = wlan_hdd_validate_context(hdd_ctx);
723 if (0 != ret)
724 return ret;
725
726 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, "%s: enter !!!",
727 __func__);
728
729 /* Block All Scan during DFS operation and send null scan result */
730 con_sap_adapter = hdd_get_con_sap_adapter(pAdapter, true);
731 if (con_sap_adapter) {
732 con_dfs_ch = con_sap_adapter->sessionCtx.ap.operatingChannel;
733
734 if (CDS_IS_DFS_CH(con_dfs_ch)) {
735 hddLog(LOGW, FL("##In DFS Master mode. Scan aborted"));
736 return -EOPNOTSUPP;
737 }
738 }
739
740 cdf_mem_zero(&scanRequest, sizeof(scanRequest));
741
742 if (NULL != wrqu->data.pointer) {
743 /* set scanType, active or passive */
744 if ((IW_SCAN_TYPE_ACTIVE == scanReq->scan_type) ||
745 (eSIR_ACTIVE_SCAN == hdd_ctx->ioctl_scan_mode)) {
746 scanRequest.scanType = eSIR_ACTIVE_SCAN;
747 } else {
748 scanRequest.scanType = eSIR_PASSIVE_SCAN;
749 }
750
751 /* set bssid using sockaddr from iw_scan_req */
752 cdf_mem_copy(scanRequest.bssid.bytes,
753 &scanReq->bssid.sa_data,
754 CDF_MAC_ADDR_SIZE);
755
756 if (wrqu->data.flags & IW_SCAN_THIS_ESSID) {
757
758 if (scanReq->essid_len) {
759 scanRequest.SSIDs.numOfSSIDs = 1;
760 scanRequest.SSIDs.SSIDList =
761 (tCsrSSIDInfo *)
762 cdf_mem_malloc(sizeof(tCsrSSIDInfo));
763 if (scanRequest.SSIDs.SSIDList) {
764 scanRequest.SSIDs.SSIDList->SSID.
765 length = scanReq->essid_len;
766 cdf_mem_copy(scanRequest.SSIDs.
767 SSIDList->SSID.ssId,
768 scanReq->essid,
769 scanReq->essid_len);
770 } else {
771 scanRequest.SSIDs.numOfSSIDs = 0;
772 CDF_TRACE(CDF_MODULE_ID_HDD,
773 CDF_TRACE_LEVEL_ERROR,
774 "%s: Unable to allocate memory",
775 __func__);
776 CDF_ASSERT(0);
777 }
778 }
779 }
780
781 /* set min and max channel time */
782 scanRequest.minChnTime = scanReq->min_channel_time;
783 scanRequest.maxChnTime = scanReq->max_channel_time;
784
785 } else {
786 if (hdd_ctx->ioctl_scan_mode == eSIR_ACTIVE_SCAN) {
787 /* set the scan type to active */
788 scanRequest.scanType = eSIR_ACTIVE_SCAN;
789 } else {
790 scanRequest.scanType = eSIR_PASSIVE_SCAN;
791 }
792
793 cdf_set_macaddr_broadcast(&scanRequest.bssid);
794
795 /* set min and max channel time to zero */
796 scanRequest.minChnTime = 0;
797 scanRequest.maxChnTime = 0;
798 }
799
800 /* set BSSType to default type */
801 scanRequest.BSSType = eCSR_BSS_TYPE_ANY;
802
803 /*Scan all the channels */
804 scanRequest.ChannelInfo.numOfChannels = 0;
805
806 scanRequest.ChannelInfo.ChannelList = NULL;
807
808 /* set requestType to full scan */
809 scanRequest.requestType = eCSR_SCAN_REQUEST_FULL_SCAN;
810
811 /* if previous genIE is not NULL, update ScanIE */
812 if (0 != pwextBuf->genIE.length) {
813 memset(&pAdapter->scan_info.scanAddIE, 0,
814 sizeof(pAdapter->scan_info.scanAddIE));
815 memcpy(pAdapter->scan_info.scanAddIE.addIEdata,
816 pwextBuf->genIE.addIEdata, pwextBuf->genIE.length);
817 pAdapter->scan_info.scanAddIE.length = pwextBuf->genIE.length;
818
819 pwextBuf->roamProfile.pAddIEScan =
820 pAdapter->scan_info.scanAddIE.addIEdata;
821 pwextBuf->roamProfile.nAddIEScanLength =
822 pAdapter->scan_info.scanAddIE.length;
823
824 /* clear previous genIE after use it */
825 memset(&pwextBuf->genIE, 0, sizeof(pwextBuf->genIE));
826 }
827
828 /* push addIEScan in scanRequset if exist */
829 if (pAdapter->scan_info.scanAddIE.addIEdata &&
830 pAdapter->scan_info.scanAddIE.length) {
831 scanRequest.uIEFieldLen = pAdapter->scan_info.scanAddIE.length;
832 scanRequest.pIEField = pAdapter->scan_info.scanAddIE.addIEdata;
833 }
834 scanRequest.timestamp = cdf_mc_timer_get_system_ticks();
835 status = sme_scan_request((WLAN_HDD_GET_CTX(pAdapter))->hHal,
836 pAdapter->sessionId, &scanRequest,
837 &hdd_scan_request_callback, dev);
838 if (!CDF_IS_STATUS_SUCCESS(status)) {
839 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_FATAL,
840 "%s:sme_scan_request fail %d!!!", __func__, status);
841 goto error;
842 }
843
844 wlan_hdd_scan_request_enqueue(pAdapter, NULL, NL_SCAN,
845 scanRequest.scan_id,
846 scanRequest.timestamp);
847
848 pAdapter->scan_info.mScanPending = true;
849error:
850 if ((wrqu->data.flags & IW_SCAN_THIS_ESSID) && (scanReq->essid_len))
851 cdf_mem_free(scanRequest.SSIDs.SSIDList);
852 EXIT();
853 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, "%s: exit !!!",
854 __func__);
855 return status;
856}
857
858/**
859 * iw_set_scan() - SSR wrapper for __iw_set_scan
860 * @dev: Pointer to the net device.
861 * @info: Pointer to the iw_request_info.
862 * @wrqu: Pointer to the iwreq_data.
863 * @extra: Pointer to the data.
864 *
865 * Return: 0 on success, error number otherwise
866 */
867int iw_set_scan(struct net_device *dev, struct iw_request_info *info,
868 union iwreq_data *wrqu, char *extra)
869{
870 int ret;
871
872 cds_ssr_protect(__func__);
873 ret = __iw_set_scan(dev, info, wrqu, extra);
874 cds_ssr_unprotect(__func__);
875
876 return ret;
877}
878
879/**
880 * __iw_get_scan() - get scan
881 * @dev: Pointer to the net device.
882 * @info: Pointer to the iw_request_info.
883 * @wrqu: Pointer to the iwreq_data.
884 * @extra: Pointer to the data.
885 *
886 * This function returns the scan results to the wpa_supplicant
887 *
888 * Return: 0 for success, non zero for failure
889 */
890
891static int __iw_get_scan(struct net_device *dev,
892 struct iw_request_info *info,
893 union iwreq_data *wrqu, char *extra)
894{
895 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
896 hdd_context_t *hdd_ctx;
897 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter);
898 tCsrScanResultInfo *pScanResult;
899 CDF_STATUS status = CDF_STATUS_SUCCESS;
900 hdd_scan_info_t scanInfo;
901 tScanResultHandle pResult;
902 int i = 0;
903 int ret;
904
905 ENTER();
906
907 hdd_ctx = WLAN_HDD_GET_CTX(pAdapter);
908 ret = wlan_hdd_validate_context(hdd_ctx);
909 if (0 != ret)
910 return ret;
911
912 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO,
913 "%s: enter buffer length %d!!!", __func__,
914 (wrqu->data.length) ? wrqu->data.length : IW_SCAN_MAX_DATA);
915
916 if (true == pAdapter->scan_info.mScanPending) {
917 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_FATAL,
918 "%s:mScanPending is true !!!", __func__);
919 return -EAGAIN;
920 }
921
922 scanInfo.dev = dev;
923 scanInfo.start = extra;
924 scanInfo.info = info;
925
926 if (0 == wrqu->data.length) {
927 scanInfo.end = extra + IW_SCAN_MAX_DATA;
928 } else {
929 scanInfo.end = extra + wrqu->data.length;
930 }
931
932 status = sme_scan_get_result(hHal, pAdapter->sessionId, NULL, &pResult);
933
934 if (NULL == pResult) {
935 /* no scan results */
936 hddLog(LOG1, "iw_get_scan: NULL Scan Result ");
937 return 0;
938 }
939
940 pScanResult = sme_scan_result_get_first(hHal, pResult);
941
942 while (pScanResult) {
943 status = hdd_indicate_scan_result(&scanInfo, pScanResult);
944 if (0 != status) {
945 break;
946 }
947 i++;
948 pScanResult = sme_scan_result_get_next(hHal, pResult);
949 }
950
951 sme_scan_result_purge(hHal, pResult);
952
953 EXIT();
954 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO,
955 "%s: exit total %d BSS reported !!!", __func__, i);
956 return status;
957}
958
959/**
960 * iw_get_scan() - SSR wrapper function for __iw_get_scan
961 * @dev: Pointer to the net device.
962 * @info: Pointer to the iw_request_info.
963 * @wrqu: Pointer to the iwreq_data.
964 * @extra: Pointer to the data.
965 *
966 * Return: 0 on success, error number otherwise
967 */
968int iw_get_scan(struct net_device *dev,
969 struct iw_request_info *info,
970 union iwreq_data *wrqu, char *extra)
971{
972 int ret;
973
974 cds_ssr_protect(__func__);
975 ret = __iw_get_scan(dev, info, wrqu, extra);
976 cds_ssr_unprotect(__func__);
977
978 return ret;
979}
980
981/**
982 * hdd_abort_mac_scan() - aborts ongoing mac scan
983 * @pHddCtx: Pointer to hdd context
984 * @sessionId: session id
985 * @reason: abort reason
986 *
987 * Abort any MAC scan if in progress
988 *
989 * Return: none
990 */
991void hdd_abort_mac_scan(hdd_context_t *pHddCtx, uint8_t sessionId,
992 eCsrAbortReason reason)
993{
994 sme_abort_mac_scan(pHddCtx->hHal, sessionId, reason);
995}
996
997/**
998 * hdd_vendor_scan_callback() - Scan completed callback event
999 * @hddctx: HDD context
1000 * @req : Scan request
1001 * @aborted : true scan aborted false scan success
1002 *
1003 * This function sends scan completed callback event to NL.
1004 *
1005 * Return: none
1006 */
1007static void hdd_vendor_scan_callback(hdd_adapter_t *adapter,
1008 struct cfg80211_scan_request *req,
1009 bool aborted)
1010{
1011 hdd_context_t *hddctx = WLAN_HDD_GET_CTX(adapter);
1012 struct sk_buff *skb;
1013 struct nlattr *attr;
1014 int i;
1015 uint8_t scan_status;
1016 uint64_t cookie;
1017
1018 ENTER();
1019
1020 if (WLAN_HDD_ADAPTER_MAGIC != adapter->magic) {
1021 hdd_err("Invalid adapter magic");
1022 return;
1023 }
1024 skb = cfg80211_vendor_event_alloc(hddctx->wiphy, NULL,
1025 SCAN_DONE_EVENT_BUF_SIZE + 4 + NLMSG_HDRLEN,
1026 QCA_NL80211_VENDOR_SUBCMD_SCAN_DONE_INDEX,
1027 GFP_KERNEL);
1028
1029 if (!skb) {
1030 hdd_err("skb alloc failed");
1031 return;
1032 }
1033
1034 if (0 != hdd_vendor_put_ifindex(skb, adapter->dev->ifindex))
1035 goto nla_put_failure;
1036
1037 cookie = (uintptr_t)req;
1038
1039 attr = nla_nest_start(skb, QCA_WLAN_VENDOR_ATTR_SCAN_SSIDS);
1040 if (!attr)
1041 goto nla_put_failure;
1042 for (i = 0; i < req->n_ssids; i++) {
1043 if (nla_put(skb, i, req->ssids[i].ssid_len, req->ssids[i].ssid))
1044 goto nla_put_failure;
1045 }
1046 nla_nest_end(skb, attr);
1047
1048 attr = nla_nest_start(skb, QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES);
1049 if (!attr)
1050 goto nla_put_failure;
1051 for (i = 0; i < req->n_channels; i++) {
1052 if (nla_put_u32(skb, i, req->channels[i]->center_freq))
1053 goto nla_put_failure;
1054 }
1055 nla_nest_end(skb, attr);
1056
1057 if (req->ie &&
1058 nla_put(skb, QCA_WLAN_VENDOR_ATTR_SCAN_IE, req->ie_len,
1059 req->ie))
1060 goto nla_put_failure;
1061
1062 if (req->flags &&
1063 nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_SCAN_FLAGS, req->flags))
1064 goto nla_put_failure;
1065
1066 if (nla_put_u64(skb, QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE, cookie))
1067 goto nla_put_failure;
1068
1069 scan_status = (aborted == true) ? VENDOR_SCAN_STATUS_ABORTED :
1070 VENDOR_SCAN_STATUS_NEW_RESULTS;
1071 if (nla_put_u8(skb, QCA_WLAN_VENDOR_ATTR_SCAN_STATUS, scan_status))
1072 goto nla_put_failure;
1073
1074 cfg80211_vendor_event(skb, GFP_KERNEL);
1075 return;
1076
1077nla_put_failure:
1078 kfree_skb(skb);
1079 return;
1080}
1081
1082/**
1083 * hdd_cfg80211_scan_done_callback() - scan done callback function called after
1084 * scan is finished
1085 * @halHandle: Pointer to handle
1086 * @pContext: Pointer to context
1087 * @sessionId: Session Id
1088 * @scanId: Scan Id
1089 * @status: Scan status
1090 *
1091 * Return: CDF status
1092 */
1093static CDF_STATUS hdd_cfg80211_scan_done_callback(tHalHandle halHandle,
1094 void *pContext,
1095 uint8_t sessionId,
1096 uint32_t scanId,
1097 eCsrScanStatus status)
1098{
1099 struct net_device *dev = (struct net_device *)pContext;
1100 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
1101 hdd_scaninfo_t *pScanInfo = &pAdapter->scan_info;
1102 struct cfg80211_scan_request *req = NULL;
1103 bool aborted = false;
1104 hdd_context_t *hddctx = WLAN_HDD_GET_CTX(pAdapter);
1105 int ret = 0;
1106 uint8_t source;
1107 uint32_t scan_time;
1108 uint32_t size = 0;
1109
1110 hddLog(CDF_TRACE_LEVEL_INFO,
1111 "%s called with hal = %p, pContext = %p, ID = %d, status = %d",
1112 __func__, halHandle, pContext, (int)scanId, (int)status);
1113
1114 pScanInfo->mScanPendingCounter = 0;
1115
1116 if (pScanInfo->mScanPending != true) {
1117 CDF_ASSERT(pScanInfo->mScanPending);
1118 goto allow_suspend;
1119 }
1120
1121 if (CDF_STATUS_SUCCESS !=
1122 wlan_hdd_scan_request_dequeue(hddctx, scanId, &req, &source,
1123 &scan_time)) {
1124 hdd_err("Dequeue of scan request failed ID: %d", scanId);
1125 goto allow_suspend;
1126 }
1127
1128 ret = wlan_hdd_cfg80211_update_bss((WLAN_HDD_GET_CTX(pAdapter))->wiphy,
1129 pAdapter, scan_time);
1130 if (0 > ret)
1131 hddLog(CDF_TRACE_LEVEL_INFO, "%s: NO SCAN result", __func__);
1132
1133 /*
1134 * cfg80211_scan_done informing NL80211 about completion
1135 * of scanning
1136 */
1137 if (status == eCSR_SCAN_ABORT || status == eCSR_SCAN_FAILURE) {
1138 aborted = true;
1139 }
1140
1141 cdf_spin_lock(&hddctx->hdd_scan_req_q_lock);
1142 cdf_list_size(&(hddctx->hdd_scan_req_q), &size);
1143 if (!size) {
1144 /* Scan is no longer pending */
1145 pScanInfo->mScanPending = false;
1146 complete(&pScanInfo->abortscan_event_var);
1147 }
1148 cdf_spin_unlock(&hddctx->hdd_scan_req_q_lock);
1149 /*
1150 * Scan can be triggred from NL or vendor scan
1151 * - If scan is triggered from NL then cfg80211 scan done should be
1152 * called to updated scan completion to NL.
1153 * - If scan is triggred through vendor command then
1154 * scan done event will be posted
1155 */
1156 if (NL_SCAN == source)
1157 cfg80211_scan_done(req, aborted);
1158 else
1159 hdd_vendor_scan_callback(pAdapter, req, aborted);
1160
1161allow_suspend:
1162 if (!size) {
1163 /* release the wake lock at the end of the scan */
1164 hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_SCAN);
1165
1166 /* Acquire wakelock to handle the case where APP's tries
1167 * to suspend immediatly after the driver gets connect
1168 * request(i.e after scan) from supplicant, this result in
1169 * app's is suspending and not ableto process the connect
1170 * request to AP
1171 */
1172 hdd_prevent_suspend_timeout(1000,
1173 WIFI_POWER_EVENT_WAKELOCK_SCAN);
1174 }
1175
1176#ifdef FEATURE_WLAN_TDLS
1177 wlan_hdd_tdls_scan_done_callback(pAdapter);
1178#endif
1179
1180 EXIT();
1181 return 0;
1182}
1183
1184
1185/**
1186 * wlan_hdd_cfg80211_scan_block_cb() - scan block work handler
1187 * @work: Pointer to work
1188 *
1189 * Return: none
1190 */
1191static void wlan_hdd_cfg80211_scan_block_cb(struct work_struct *work)
1192{
1193 hdd_adapter_t *adapter = container_of(work,
1194 hdd_adapter_t, scan_block_work);
1195 struct cfg80211_scan_request *request = adapter->request;
1196
1197 request->n_ssids = 0;
1198 request->n_channels = 0;
1199
1200 hddLog(LOGE,
1201 FL("##In DFS Master mode. Scan aborted. Null result sent"));
1202 cfg80211_scan_done(request, true);
1203 adapter->request = NULL;
1204}
1205
1206/**
1207 * __wlan_hdd_cfg80211_scan() - API to process cfg80211 scan request
1208 * @wiphy: Pointer to wiphy
1209 * @dev: Pointer to net device
1210 * @request: Pointer to scan request
1211 * @source: scan request source(NL/Vendor scan)
1212 *
1213 * This API responds to scan trigger and update cfg80211 scan database
1214 * later, scan dump command can be used to recieve scan results
1215 *
1216 * Return: 0 for success, non zero for failure
1217 */
1218static int __wlan_hdd_cfg80211_scan(struct wiphy *wiphy,
1219#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0))
1220 struct net_device *dev,
1221#endif
1222 struct cfg80211_scan_request *request,
1223 uint8_t source)
1224{
1225#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
1226 struct net_device *dev = request->wdev->netdev;
1227#endif
1228 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
1229 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
1230 hdd_wext_state_t *pwextBuf = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter);
1231 struct hdd_config *cfg_param = NULL;
1232 tCsrScanRequest scan_req;
1233 uint8_t *channelList = NULL, i;
1234 int status;
1235 hdd_scaninfo_t *pScanInfo = NULL;
1236 uint8_t *pP2pIe = NULL;
1237 hdd_adapter_t *con_sap_adapter;
1238 uint16_t con_dfs_ch;
1239
1240 ENTER();
1241
1242 if (CDF_FTM_MODE == hdd_get_conparam()) {
1243 hddLog(LOGE, FL("Command not allowed in FTM mode"));
1244 return -EINVAL;
1245 }
1246
1247 MTRACE(cdf_trace(CDF_MODULE_ID_HDD,
1248 TRACE_CODE_HDD_CFG80211_SCAN,
1249 pAdapter->sessionId, request->n_channels));
1250
1251 hddLog(LOG1, FL("Device_mode %s(%d)"),
1252 hdd_device_mode_to_string(pAdapter->device_mode),
1253 pAdapter->device_mode);
1254
1255 status = wlan_hdd_validate_context(pHddCtx);
1256
1257 if (0 != status) {
1258 hddLog(LOGE, FL("HDD context is not valid"));
1259 return status;
1260 }
1261
1262 cfg_param = pHddCtx->config;
1263 pScanInfo = &pAdapter->scan_info;
1264
1265 /* Block All Scan during DFS operation and send null scan result */
1266 con_sap_adapter = hdd_get_con_sap_adapter(pAdapter, true);
1267 if (con_sap_adapter) {
1268 con_dfs_ch = con_sap_adapter->sessionCtx.ap.sapConfig.channel;
1269 if (con_dfs_ch == AUTO_CHANNEL_SELECT)
1270 con_dfs_ch =
1271 con_sap_adapter->sessionCtx.ap.operatingChannel;
1272
1273 if (CDS_IS_DFS_CH(con_dfs_ch)) {
1274 /* Provide empty scan result during DFS operation since
1275 * scanning not supported during DFS. Reason is
1276 * following case:
1277 * DFS is supported only in SCC for MBSSID Mode.
1278 * We shall not return EBUSY or ENOTSUPP as when Primary
1279 * AP is operating in DFS channel and secondary AP is
1280 * started. Though we force SCC in driver, the hostapd
1281 * issues obss scan before starting secAP. This results
1282 * in MCC in DFS mode. Thus we return null scan result.
1283 * If we return scan failure hostapd fails secondary AP
1284 * startup.
1285 */
1286 pAdapter->request = request;
1287
1288#ifdef CONFIG_CNSS
1289 cnss_init_work(&pAdapter->scan_block_work,
1290 wlan_hdd_cfg80211_scan_block_cb);
1291#else
1292 INIT_WORK(&pAdapter->scan_block_work,
1293 wlan_hdd_cfg80211_scan_block_cb);
1294#endif
1295 schedule_work(&pAdapter->scan_block_work);
1296 return 0;
1297 }
1298 }
1299 if (!wma_is_hw_dbs_capable()) {
1300 if (true == pScanInfo->mScanPending) {
1301 if (MAX_PENDING_LOG >
1302 pScanInfo->mScanPendingCounter++) {
1303 hddLog(LOGE, FL("mScanPending is true"));
1304 }
1305 return -EBUSY;
1306 }
1307
1308 /* Don't Allow Scan and return busy if Remain On
1309 * Channel and action frame is pending
1310 * Otherwise Cancel Remain On Channel and allow Scan
1311 * If no action frame pending
1312 */
1313 if (0 != wlan_hdd_check_remain_on_channel(pAdapter)) {
1314 hddLog(LOGE, FL("Remain On Channel Pending"));
1315 return -EBUSY;
1316 }
1317 }
1318#ifdef FEATURE_WLAN_TDLS
1319 /* if tdls disagree scan right now, return immediately.
1320 * tdls will schedule the scan when scan is allowed.
1321 * (return SUCCESS)
1322 * or will reject the scan if any TDLS is in progress.
1323 * (return -EBUSY)
1324 */
1325 status = wlan_hdd_tdls_scan_callback(pAdapter, wiphy,
1326#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0))
1327 dev,
1328#endif
1329 request);
1330 if (status <= 0) {
1331 if (!status)
1332 hddLog(LOGE,
1333 FL("TDLS in progress.scan rejected %d"),
1334 status);
1335 else
1336 hddLog(LOGE, FL("TDLS teardown is ongoing %d"),
1337 status);
1338 return status;
1339 }
1340#endif
1341
1342 /* Check if scan is allowed at this point of time */
1343 if (cds_is_connection_in_progress(pHddCtx)) {
1344 hddLog(LOGE, FL("Scan not allowed"));
1345 return -EBUSY;
1346 }
1347
1348 cdf_mem_zero(&scan_req, sizeof(scan_req));
1349
1350 hddLog(LOG1, "scan request for ssid = %d", request->n_ssids);
1351 scan_req.timestamp = cdf_mc_timer_get_system_ticks();
1352
1353 /* Even though supplicant doesn't provide any SSIDs, n_ssids is
1354 * set to 1. Because of this, driver is assuming that this is not
1355 * wildcard scan and so is not aging out the scan results.
1356 */
1357 if ((request->ssids) && (request->n_ssids == 1) &&
1358 ('\0' == request->ssids->ssid[0])) {
1359 request->n_ssids = 0;
1360 }
1361
1362 if ((request->ssids) && (0 < request->n_ssids)) {
1363 tCsrSSIDInfo *SsidInfo;
1364 int j;
1365 scan_req.SSIDs.numOfSSIDs = request->n_ssids;
1366 /* Allocate num_ssid tCsrSSIDInfo structure */
1367 SsidInfo = scan_req.SSIDs.SSIDList =
1368 cdf_mem_malloc(request->n_ssids * sizeof(tCsrSSIDInfo));
1369
1370 if (NULL == scan_req.SSIDs.SSIDList) {
1371 hddLog(LOGE, FL("memory alloc failed SSIDInfo buffer"));
1372 return -ENOMEM;
1373 }
1374
1375 /* copy all the ssid's and their length */
1376 for (j = 0; j < request->n_ssids; j++, SsidInfo++) {
1377 /* get the ssid length */
1378 SsidInfo->SSID.length = request->ssids[j].ssid_len;
1379 cdf_mem_copy(SsidInfo->SSID.ssId,
1380 &request->ssids[j].ssid[0],
1381 SsidInfo->SSID.length);
1382 SsidInfo->SSID.ssId[SsidInfo->SSID.length] = '\0';
1383 hddLog(LOG1, FL("SSID number %d: %s"), j,
1384 SsidInfo->SSID.ssId);
1385 }
1386 /* set the scan type to active */
1387 scan_req.scanType = eSIR_ACTIVE_SCAN;
1388 } else if (WLAN_HDD_P2P_GO == pAdapter->device_mode) {
1389 /* set the scan type to active */
1390 scan_req.scanType = eSIR_ACTIVE_SCAN;
1391 } else {
1392 /*
1393 * Set the scan type to passive if there is no ssid list
1394 * provided else set default type configured in the driver.
1395 */
1396 if (!request->ssids)
1397 scan_req.scanType = eSIR_PASSIVE_SCAN;
1398 else
1399 scan_req.scanType = pHddCtx->ioctl_scan_mode;
1400 }
1401 scan_req.minChnTime = cfg_param->nActiveMinChnTime;
1402 scan_req.maxChnTime = cfg_param->nActiveMaxChnTime;
1403
1404 /* set BSSType to default type */
1405 scan_req.BSSType = eCSR_BSS_TYPE_ANY;
1406
1407 if (MAX_CHANNEL < request->n_channels) {
1408 hddLog(LOGW, FL("No of Scan Channels exceeded limit: %d"),
1409 request->n_channels);
1410 request->n_channels = MAX_CHANNEL;
1411 }
1412
1413 hddLog(LOG1, FL("No of Scan Channels: %d"), request->n_channels);
1414
1415 if (request->n_channels) {
1416 char chList[(request->n_channels * 5) + 1];
1417 int len;
1418 channelList = cdf_mem_malloc(request->n_channels);
1419 if (NULL == channelList) {
1420 hddLog(LOGE,
1421 FL("channelList malloc failed channelList"));
1422 status = -ENOMEM;
1423 goto free_mem;
1424 }
1425 for (i = 0, len = 0; i < request->n_channels; i++) {
1426 channelList[i] = request->channels[i]->hw_value;
1427 len += snprintf(chList + len, 5, "%d ", channelList[i]);
1428 }
1429
1430 hddLog(LOG1, FL("Channel-List: %s"), chList);
1431
1432 }
1433 scan_req.ChannelInfo.numOfChannels = request->n_channels;
1434 scan_req.ChannelInfo.ChannelList = channelList;
1435
1436 /* set requestType to full scan */
1437 scan_req.requestType = eCSR_SCAN_REQUEST_FULL_SCAN;
1438
1439 /* Flush the scan results(only p2p beacons) for STA scan and P2P
1440 * search (Flush on both full scan and social scan but not on single
1441 * channel scan).P2P search happens on 3 social channels (1, 6, 11)
1442 */
1443
1444 /* Supplicant does single channel scan after 8-way handshake
1445 * and in that case driver shoudnt flush scan results. If
1446 * driver flushes the scan results here and unfortunately if
1447 * the AP doesnt respond to our probe req then association
1448 * fails which is not desired
1449 */
1450
1451 if (request->n_channels != WLAN_HDD_P2P_SINGLE_CHANNEL_SCAN) {
1452 hddLog(CDF_TRACE_LEVEL_DEBUG, "Flushing P2P Results");
1453 sme_scan_flush_p2p_result(WLAN_HDD_GET_HAL_CTX(pAdapter),
1454 pAdapter->sessionId);
1455 }
1456
1457 if (request->ie_len) {
1458 /* save this for future association (join requires this) */
1459 memset(&pScanInfo->scanAddIE, 0, sizeof(pScanInfo->scanAddIE));
1460 memcpy(pScanInfo->scanAddIE.addIEdata, request->ie,
1461 request->ie_len);
1462 pScanInfo->scanAddIE.length = request->ie_len;
1463
1464 if ((WLAN_HDD_INFRA_STATION == pAdapter->device_mode) ||
1465 (WLAN_HDD_P2P_CLIENT == pAdapter->device_mode) ||
1466 (WLAN_HDD_P2P_DEVICE == pAdapter->device_mode)
1467 ) {
1468 pwextBuf->roamProfile.pAddIEScan =
1469 pScanInfo->scanAddIE.addIEdata;
1470 pwextBuf->roamProfile.nAddIEScanLength =
1471 pScanInfo->scanAddIE.length;
1472 }
1473
1474 scan_req.uIEFieldLen = pScanInfo->scanAddIE.length;
1475 scan_req.pIEField = pScanInfo->scanAddIE.addIEdata;
1476
1477 pP2pIe = wlan_hdd_get_p2p_ie_ptr((uint8_t *) request->ie,
1478 request->ie_len);
1479 if (pP2pIe != NULL) {
1480#ifdef WLAN_FEATURE_P2P_DEBUG
1481 if (((global_p2p_connection_status == P2P_GO_NEG_COMPLETED)
1482 || (global_p2p_connection_status ==
1483 P2P_GO_NEG_PROCESS))
1484 && (WLAN_HDD_P2P_CLIENT == pAdapter->device_mode)) {
1485 global_p2p_connection_status =
1486 P2P_CLIENT_CONNECTING_STATE_1;
1487 hddLog(LOGE,
1488 FL("[P2P State] Changing state from Go nego completed to Connection is started"));
1489 hddLog(LOGE,
1490 FL("[P2P]P2P Scanning is started for 8way Handshake"));
1491 } else
1492 if ((global_p2p_connection_status ==
1493 P2P_CLIENT_DISCONNECTED_STATE)
1494 && (WLAN_HDD_P2P_CLIENT ==
1495 pAdapter->device_mode)) {
1496 global_p2p_connection_status =
1497 P2P_CLIENT_CONNECTING_STATE_2;
1498 hddLog(LOGE,
1499 FL("[P2P State] Changing state from Disconnected state to Connection is started"));
1500 hddLog(LOGE,
1501 FL("[P2P]P2P Scanning is started for 4way Handshake"));
1502 }
1503#endif
1504
1505 /* no_cck will be set during p2p find to disable 11b rates */
1506 if (request->no_cck) {
1507 hddLog(CDF_TRACE_LEVEL_INFO,
1508 "%s: This is a P2P Search", __func__);
1509 scan_req.p2pSearch = 1;
1510
1511 if (request->n_channels ==
1512 WLAN_HDD_P2P_SOCIAL_CHANNELS) {
1513 /* set requestType to P2P Discovery */
1514 scan_req.requestType =
1515 eCSR_SCAN_P2P_DISCOVERY;
1516 }
1517
1518 /*
1519 * Skip Dfs Channel in case of P2P Search if it is set in
1520 * ini file
1521 */
1522 if (cfg_param->skipDfsChnlInP2pSearch) {
1523 scan_req.skipDfsChnlInP2pSearch = 1;
1524 } else {
1525 scan_req.skipDfsChnlInP2pSearch = 0;
1526 }
1527
1528 }
1529 }
1530 }
1531
1532 /* acquire the wakelock to avoid the apps suspend during the scan. To
1533 * address the following issues.
1534 * 1) Disconnected scenario: we are not allowing the suspend as WLAN is not in
1535 * BMPS/IMPS this result in android trying to suspend aggressively and backing off
1536 * for long time, this result in apps running at full power for long time.
1537 * 2) Connected scenario: If we allow the suspend during the scan, RIVA will
1538 * be stuck in full power because of resume BMPS
1539 */
1540 hdd_prevent_suspend_timeout(HDD_WAKE_LOCK_SCAN_DURATION,
1541 WIFI_POWER_EVENT_WAKELOCK_SCAN);
1542
1543 hddLog(LOG2,
1544 FL("requestType %d, scanType %d, minChnTime %d, maxChnTime %d,p2pSearch %d, skipDfsChnlIn P2pSearch %d"),
1545 scan_req.requestType, scan_req.scanType,
1546 scan_req.minChnTime, scan_req.maxChnTime,
1547 scan_req.p2pSearch, scan_req.skipDfsChnlInP2pSearch);
1548
1549 status = sme_scan_request(WLAN_HDD_GET_HAL_CTX(pAdapter),
1550 pAdapter->sessionId, &scan_req,
1551 &hdd_cfg80211_scan_done_callback, dev);
1552
1553 if (CDF_STATUS_SUCCESS != status) {
1554 hddLog(LOGE, FL("sme_scan_request returned error %d"), status);
1555 if (CDF_STATUS_E_RESOURCES == status) {
1556 hddLog(LOGE,
1557 FL("HO is in progress.So defer the scan by informing busy"));
1558 status = -EBUSY;
1559 } else {
1560 status = -EIO;
1561 }
1562
1563 hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_SCAN);
1564 goto free_mem;
1565 }
1566 wlan_hdd_scan_request_enqueue(pAdapter, request, source,
1567 scan_req.scan_id, scan_req.timestamp);
1568 pAdapter->scan_info.mScanPending = true;
1569
1570free_mem:
1571 if (scan_req.SSIDs.SSIDList)
1572 cdf_mem_free(scan_req.SSIDs.SSIDList);
1573
1574 if (channelList)
1575 cdf_mem_free(channelList);
1576
1577 EXIT();
1578 return status;
1579}
1580
1581/**
1582 * wlan_hdd_cfg80211_scan() - API to process cfg80211 scan request
1583 * @wiphy: Pointer to wiphy
1584 * @dev: Pointer to net device
1585 * @request: Pointer to scan request
1586 *
1587 * This API responds to scan trigger and update cfg80211 scan database
1588 * later, scan dump command can be used to recieve scan results
1589 *
1590 * Return: 0 for success, non zero for failure
1591 */
1592int wlan_hdd_cfg80211_scan(struct wiphy *wiphy,
1593#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0))
1594 struct net_device *dev,
1595#endif
1596 struct cfg80211_scan_request *request)
1597{
1598 int ret;
1599 cds_ssr_protect(__func__);
1600 ret = __wlan_hdd_cfg80211_scan(wiphy,
1601#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0))
1602 dev,
1603#endif
1604 request, NL_SCAN);
1605 cds_ssr_unprotect(__func__);
1606 return ret;
1607}
1608
1609/**
1610 * wlan_hdd_get_rates() -API to get the rates from scan request
1611 * @wiphy: Pointer to wiphy
1612 * @band: Band
1613 * @rates: array of rates
1614 * @rate_count: number of rates
1615 *
1616 * Return: o for failure, rate bitmap for success
1617 */
1618static uint32_t wlan_hdd_get_rates(struct wiphy *wiphy,
1619 enum ieee80211_band band,
1620 const u8 *rates, unsigned int rate_count)
1621{
1622 uint32_t j, count, rate_bitmap = 0;
1623 uint32_t rate;
1624 bool found;
1625
1626 for (count = 0; count < rate_count; count++) {
1627 rate = ((rates[count]) & RATE_MASK) * 5;
1628 found = false;
1629 for (j = 0; j < wiphy->bands[band]->n_bitrates; j++) {
1630 if (wiphy->bands[band]->bitrates[j].bitrate == rate) {
1631 found = true;
1632 rate_bitmap |= (1 << j);
1633 break;
1634 }
1635 }
1636 if (!found)
1637 return 0;
1638 }
1639 return rate_bitmap;
1640}
1641
1642/**
1643 * wlan_hdd_send_scan_start_event() -API to send the scan start event
1644 * @wiphy: Pointer to wiphy
1645 * @wdev: Pointer to net device
1646 * @cookie: scan identifier
1647 *
1648 * Return: return 0 on success and negative error code on failure
1649 */
1650static int wlan_hdd_send_scan_start_event(struct wiphy *wiphy,
1651 struct wireless_dev *wdev, uint64_t cookie)
1652{
1653 struct sk_buff *skb;
1654 int ret;
1655
1656 skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, sizeof(u64) +
1657 NLA_HDRLEN + NLMSG_HDRLEN);
1658 if (!skb) {
1659 hddLog(LOGE, FL(" reply skb alloc failed"));
1660 return -ENOMEM;
1661 }
1662
1663 if (nla_put_u64(skb, QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE, cookie)) {
1664 hddLog(LOGE, FL("nla put fail"));
1665 kfree_skb(skb);
1666 return -EINVAL;
1667 }
1668
1669 ret = cfg80211_vendor_cmd_reply(skb);
1670
1671 /* Send a scan started event to supplicant */
1672 skb = cfg80211_vendor_event_alloc(wiphy, wdev,
1673 sizeof(u64) + 4 + NLMSG_HDRLEN,
1674 QCA_NL80211_VENDOR_SUBCMD_SCAN_INDEX, GFP_KERNEL);
1675 if (!skb) {
1676 hddLog(LOGE, FL("skb alloc failed"));
1677 return -ENOMEM;
1678 }
1679
1680 ret = hdd_vendor_put_ifindex(skb, wdev->netdev->ifindex);
1681 if (ret) {
1682 kfree_skb(skb);
1683 return -EINVAL;
1684 }
1685
1686 if (nla_put_u64(skb, QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE, cookie)) {
1687 kfree_skb(skb);
1688 return -EINVAL;
1689 }
1690 cfg80211_vendor_event(skb, GFP_KERNEL);
1691
1692 return ret;
1693}
1694/**
1695 * __wlan_hdd_cfg80211_vendor_scan() - API to process venor scan request
1696 * @wiphy: Pointer to wiphy
1697 * @wdev: Pointer to net device
1698 * @data : Pointer to the data
1699 * @data_len : length of the data
1700 *
1701 * API to process venor scan request.
1702 *
1703 * Return: return 0 on success and negative error code on failure
1704 */
1705static int __wlan_hdd_cfg80211_vendor_scan(struct wiphy *wiphy,
1706 struct wireless_dev *wdev, const void *data,
1707 int data_len)
1708{
1709 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_SCAN_MAX + 1];
1710 struct cfg80211_scan_request *request = NULL;
1711 struct nlattr *attr;
1712 enum ieee80211_band band;
1713 uint8_t n_channels = 0, n_ssid = 0, ie_len = 0;
1714 uint32_t tmp, count, j;
1715 unsigned int len;
1716 struct ieee80211_channel *chan;
1717 hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
1718 int ret;
1719
1720 ENTER();
1721
1722 ret = wlan_hdd_validate_context(hdd_ctx);
1723 if (0 != ret)
1724 return ret;
1725
1726 if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_SCAN_MAX, data,
1727 data_len, NULL)) {
1728 hdd_err("Invalid ATTR");
1729 return -EINVAL;
1730 }
1731
1732 if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES]) {
1733 nla_for_each_nested(attr,
1734 tb[QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES], tmp)
1735 n_channels++;
1736 } else {
1737 for (band = 0; band < IEEE80211_NUM_BANDS; band++)
1738 if (wiphy->bands[band])
1739 n_channels += wiphy->bands[band]->n_channels;
1740 }
1741
1742 if (MAX_CHANNEL < n_channels) {
1743 hdd_err("Exceed max number of channels: %d", n_channels);
1744 return -EINVAL;
1745 }
1746 if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_SSIDS])
1747 nla_for_each_nested(attr,
1748 tb[QCA_WLAN_VENDOR_ATTR_SCAN_SSIDS], tmp)
1749 n_ssid++;
1750
1751 if (MAX_SCAN_SSID < n_ssid) {
1752 hdd_err("Exceed max number of SSID: %d", n_ssid);
1753 return -EINVAL;
1754 }
1755
1756 if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_IE])
1757 ie_len = nla_len(tb[QCA_WLAN_VENDOR_ATTR_SCAN_IE]);
1758 else
1759 ie_len = 0;
1760
1761 len = sizeof(*request) + (sizeof(*request->ssids) * n_ssid) +
1762 (sizeof(*request->channels) * n_channels) + ie_len;
1763
1764 request = cdf_mem_malloc(len);
1765 if (!request)
1766 goto error;
1767 if (n_ssid)
1768 request->ssids = (void *)&request->channels[n_channels];
1769 request->n_ssids = n_ssid;
1770 if (ie_len) {
1771 if (request->ssids)
1772 request->ie = (void *)(request->ssids + n_ssid);
1773 else
1774 request->ie = (void *)(request->channels + n_channels);
1775 }
1776
1777 count = 0;
1778 if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES]) {
1779 nla_for_each_nested(attr,
1780 tb[QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES],
1781 tmp) {
1782 chan = __ieee80211_get_channel(wiphy,
1783 nla_get_u32(attr));
1784 if (!chan)
1785 goto error;
1786 if (chan->flags & IEEE80211_CHAN_DISABLED)
1787 continue;
1788 request->channels[count] = chan;
1789 count++;
1790 }
1791 } else {
1792 for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
1793 if (!wiphy->bands[band])
1794 continue;
1795 for (j = 0; j < wiphy->bands[band]->n_channels;
1796 j++) {
1797 chan = &wiphy->bands[band]->channels[j];
1798 if (chan->flags & IEEE80211_CHAN_DISABLED)
1799 continue;
1800 request->channels[count] = chan;
1801 count++;
1802 }
1803 }
1804 }
1805
1806 if (!count)
1807 goto error;
1808
1809 request->n_channels = count;
1810 count = 0;
1811 if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_SSIDS]) {
1812 nla_for_each_nested(attr, tb[QCA_WLAN_VENDOR_ATTR_SCAN_SSIDS],
1813 tmp) {
1814 request->ssids[count].ssid_len = nla_len(attr);
1815 memcpy(request->ssids[count].ssid, nla_data(attr),
1816 nla_len(attr));
1817 count++;
1818 }
1819 }
1820
1821 if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_IE]) {
1822 request->ie_len = nla_len(tb[QCA_WLAN_VENDOR_ATTR_SCAN_IE]);
1823 memcpy((void *)request->ie,
1824 nla_data(tb[QCA_WLAN_VENDOR_ATTR_SCAN_IE]),
1825 request->ie_len);
1826 }
1827
1828 for (count = 0; count < IEEE80211_NUM_BANDS; count++)
1829 if (wiphy->bands[count])
1830 request->rates[count] =
1831 (1 << wiphy->bands[count]->n_bitrates) - 1;
1832
1833 if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_SUPP_RATES]) {
1834 nla_for_each_nested(attr,
1835 tb[QCA_WLAN_VENDOR_ATTR_SCAN_SUPP_RATES],
1836 tmp) {
1837 band = nla_type(attr);
1838 if (!wiphy->bands[band])
1839 continue;
1840 request->rates[band] = wlan_hdd_get_rates(wiphy,
1841 band, nla_data(attr),
1842 nla_len(attr));
1843 }
1844 }
1845
1846 if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_FLAGS]) {
1847 request->flags =
1848 nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_SCAN_FLAGS]);
1849 if ((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) &&
1850 !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) {
1851 hddLog(LOGE, FL("LOW PRIORITY SCAN not supported"));
1852 goto error;
1853 }
1854 }
1855 request->no_cck =
1856 nla_get_flag(tb[QCA_WLAN_VENDOR_ATTR_SCAN_TX_NO_CCK_RATE]);
1857 request->wdev = wdev;
1858 request->wiphy = wiphy;
1859 request->scan_start = jiffies;
1860
1861 if (0 != __wlan_hdd_cfg80211_scan(wiphy, request, VENDOR_SCAN))
1862 goto error;
1863
1864 ret = wlan_hdd_send_scan_start_event(wiphy, wdev, (uintptr_t)request);
1865
1866 return ret;
1867error:
1868 hdd_err("Scan Request Failed");
1869 cdf_mem_free(request);
1870 return -EINVAL;
1871}
1872
1873/**
1874 * wlan_hdd_cfg80211_vendor_scan() -API to process venor scan request
1875 * @wiphy: Pointer to wiphy
1876 * @dev: Pointer to net device
1877 * @data : Pointer to the data
1878 * @data_len : length of the data
1879 *
1880 * This is called from userspace to request scan.
1881 *
1882 * Return: Return the Success or Failure code.
1883 */
1884int wlan_hdd_cfg80211_vendor_scan(struct wiphy *wiphy,
1885 struct wireless_dev *wdev, const void *data,
1886 int data_len)
1887{
1888 int ret;
1889
1890 cds_ssr_protect(__func__);
1891 ret = __wlan_hdd_cfg80211_vendor_scan(wiphy, wdev,
1892 data, data_len);
1893 cds_ssr_unprotect(__func__);
1894
1895 return ret;
1896}
1897/**
1898 * wlan_hdd_scan_abort() - abort ongoing scan
1899 * @pAdapter: Pointer to interface adapter
1900 *
1901 * Return: 0 for success, non zero for failure
1902 */
1903#ifdef FEATURE_WLAN_SCAN_PNO
1904int wlan_hdd_scan_abort(hdd_adapter_t *pAdapter)
1905{
1906 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
1907 hdd_scaninfo_t *pScanInfo = NULL;
1908 unsigned long rc;
1909
1910 pScanInfo = &pAdapter->scan_info;
1911
1912 if (pScanInfo->mScanPending) {
1913 INIT_COMPLETION(pScanInfo->abortscan_event_var);
1914 hdd_abort_mac_scan(pHddCtx, pAdapter->sessionId,
1915 eCSR_SCAN_ABORT_DEFAULT);
1916
1917 rc = wait_for_completion_timeout(
1918 &pScanInfo->abortscan_event_var,
1919 msecs_to_jiffies(5000));
1920 if (!rc) {
1921 hddLog(LOGE,
1922 FL("Timeout occurred while waiting for abort scan"));
1923 return -ETIME;
1924 }
1925 }
1926 return 0;
1927}
1928
1929/**
1930 * hdd_sched_scan_callback - scheduled scan callback
1931 * @callbackContext: Callback context
1932 * @pPrefNetworkFoundInd: Preferred network found indication
1933 *
1934 * This is a callback function that is registerd with SME that is
1935 * invoked when a preferred network is discovered by firmware.
1936 *
1937 * Return: none
1938 */
1939static void
1940hdd_sched_scan_callback(void *callbackContext,
1941 tSirPrefNetworkFoundInd *pPrefNetworkFoundInd)
1942{
1943 int ret;
1944 hdd_adapter_t *pAdapter = (hdd_adapter_t *) callbackContext;
1945 hdd_context_t *pHddCtx;
1946
1947 ENTER();
1948
1949 if (NULL == pAdapter) {
1950 hddLog(LOGE, FL("HDD adapter is Null"));
1951 return;
1952 }
1953
1954 pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
1955 if (NULL == pHddCtx) {
1956 hddLog(LOGE, FL("HDD context is Null!!!"));
1957 return;
1958 }
1959
1960 spin_lock(&pHddCtx->schedScan_lock);
1961 if (true == pHddCtx->isWiphySuspended) {
1962 pHddCtx->isSchedScanUpdatePending = true;
1963 spin_unlock(&pHddCtx->schedScan_lock);
1964 hddLog(LOG1,
1965 FL("Update cfg80211 scan database after it resume"));
1966 return;
1967 }
1968 spin_unlock(&pHddCtx->schedScan_lock);
1969
1970 ret = wlan_hdd_cfg80211_update_bss(pHddCtx->wiphy, pAdapter, 0);
1971
1972 if (0 > ret)
1973 hddLog(LOG1, FL("NO SCAN result"));
1974
1975 cfg80211_sched_scan_results(pHddCtx->wiphy);
1976 hddLog(LOG1,
1977 FL("cfg80211 scan result database updated"));
1978}
1979
1980/**
1981 * wlan_hdd_is_pno_allowed() - Check if PNO is allowed
1982 * @adapter: HDD Device Adapter
1983 *
1984 * The PNO Start request is coming from upper layers.
1985 * It is to be allowed only for Infra STA device type
1986 * and the link should be in a disconnected state.
1987 *
1988 * Return: Success if PNO is allowed, Failure otherwise.
1989 */
1990static CDF_STATUS wlan_hdd_is_pno_allowed(hdd_adapter_t *adapter)
1991{
1992 hddLog(LOG1,
1993 FL("dev_mode=%d, conn_state=%d, session ID=%d"),
1994 adapter->device_mode,
1995 adapter->sessionCtx.station.conn_info.connState,
1996 adapter->sessionId);
1997 if ((adapter->device_mode == WLAN_HDD_INFRA_STATION) &&
1998 (eConnectionState_NotConnected ==
1999 adapter->sessionCtx.station.conn_info.connState))
2000 return CDF_STATUS_SUCCESS;
2001 else
2002 return CDF_STATUS_E_FAILURE;
2003
2004}
2005
2006/**
2007 * __wlan_hdd_cfg80211_sched_scan_start() - cfg80211 scheduled scan(pno) start
2008 * @wiphy: Pointer to wiphy
2009 * @dev: Pointer network device
2010 * @request: Pointer to cfg80211 scheduled scan start request
2011 *
2012 * Return: 0 for success, non zero for failure
2013 */
2014static int __wlan_hdd_cfg80211_sched_scan_start(struct wiphy *wiphy,
2015 struct net_device *dev,
2016 struct
2017 cfg80211_sched_scan_request
2018 *request)
2019{
2020 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
2021 tpSirPNOScanReq pPnoRequest = NULL;
2022 hdd_context_t *pHddCtx;
2023 tHalHandle hHal;
2024 uint32_t i, indx, num_ch, tempInterval, j;
2025 u8 valid_ch[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
2026 u8 channels_allowed[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
2027 uint32_t num_channels_allowed = WNI_CFG_VALID_CHANNEL_LIST_LEN;
2028 CDF_STATUS status = CDF_STATUS_E_FAILURE;
2029 int ret = 0;
2030 hdd_scaninfo_t *pScanInfo = &pAdapter->scan_info;
2031 struct hdd_config *config = NULL;
2032 uint32_t num_ignore_dfs_ch = 0;
2033
2034 if (CDF_FTM_MODE == hdd_get_conparam()) {
2035 hddLog(LOGE, FL("Command not allowed in FTM mode"));
2036 return -EINVAL;
2037 }
2038
2039 pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
2040 ret = wlan_hdd_validate_context(pHddCtx);
2041
2042 if (0 != ret) {
2043 hddLog(LOGE, FL("HDD context is not valid"));
2044 return ret;
2045 }
2046
2047 config = pHddCtx->config;
2048 hHal = WLAN_HDD_GET_HAL_CTX(pAdapter);
2049 if (NULL == hHal) {
2050 hddLog(LOGE, FL("HAL context is Null!!!"));
2051 return -EINVAL;
2052 }
2053
2054 if ((WLAN_HDD_INFRA_STATION == pAdapter->device_mode) &&
2055 (eConnectionState_Connecting ==
2056 (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))->conn_info.connState)) {
2057 hddLog(LOGE,
2058 FL("%p(%d) Connection in progress: sched_scan_start denied (EBUSY)"),
2059 WLAN_HDD_GET_STATION_CTX_PTR(pAdapter),
2060 pAdapter->sessionId);
2061 return -EBUSY;
2062 }
2063
2064 /*
2065 * The current umac is unable to handle the SCAN_PREEMPT and SCAN_DEQUEUED
2066 * so its necessary to terminate the existing scan which is already issued
2067 * otherwise the host won't enter into the suspend state due to the reason
2068 * that the wlan wakelock which was held in the wlan_hdd_cfg80211_scan
2069 * function.
2070 */
2071 sme_scan_flush_result(hHal);
2072 if (true == pScanInfo->mScanPending) {
2073 ret = wlan_hdd_scan_abort(pAdapter);
2074 if (ret < 0) {
2075 hddLog(LOGE,
2076 FL("aborting the existing scan is unsuccessful"));
2077 return -EBUSY;
2078 }
2079 }
2080
2081 if (CDF_STATUS_E_FAILURE == wlan_hdd_is_pno_allowed(pAdapter)) {
2082 hddLog(LOGE, FL("pno is not allowed"));
2083 return -ENOTSUPP;
2084 }
2085
2086 pPnoRequest = (tpSirPNOScanReq) cdf_mem_malloc(sizeof(tSirPNOScanReq));
2087 if (NULL == pPnoRequest) {
2088 hddLog(LOGE, FL("cdf_mem_malloc failed"));
2089 return -ENOMEM;
2090 }
2091
2092 memset(pPnoRequest, 0, sizeof(tSirPNOScanReq));
2093 pPnoRequest->enable = 1; /*Enable PNO */
2094 pPnoRequest->ucNetworksCount = request->n_match_sets;
2095
2096 if ((!pPnoRequest->ucNetworksCount) ||
2097 (pPnoRequest->ucNetworksCount > SIR_PNO_MAX_SUPP_NETWORKS)) {
2098 hddLog(LOGE, FL("Network input is not correct %d"),
2099 pPnoRequest->ucNetworksCount);
2100 ret = -EINVAL;
2101 goto error;
2102 }
2103
2104 if (SIR_PNO_MAX_NETW_CHANNELS_EX < request->n_channels) {
2105 hddLog(LOGE, FL("Incorrect number of channels %d"),
2106 request->n_channels);
2107 ret = -EINVAL;
2108 goto error;
2109 }
2110
2111 /* Framework provides one set of channels(all)
2112 * common for all saved profile */
2113 if (0 != sme_cfg_get_str(hHal, WNI_CFG_VALID_CHANNEL_LIST,
2114 channels_allowed, &num_channels_allowed)) {
2115 hddLog(LOGE,
2116 FL("failed to get valid channel list"));
2117 ret = -EINVAL;
2118 goto error;
2119 }
2120 /* Checking each channel against allowed channel list */
2121 num_ch = 0;
2122 if (request->n_channels) {
2123 char chList[(request->n_channels * 5) + 1];
2124 int len;
2125 for (i = 0, len = 0; i < request->n_channels; i++) {
2126 for (indx = 0; indx < num_channels_allowed; indx++) {
2127 if (request->channels[i]->hw_value ==
2128 channels_allowed[indx]) {
2129
2130 if ((!config->enable_dfs_pno_chnl_scan)
2131 && (CHANNEL_STATE_DFS ==
2132 cds_get_channel_state(
2133 channels_allowed[indx]))) {
2134 CDF_TRACE(CDF_MODULE_ID_HDD,
2135 CDF_TRACE_LEVEL_INFO,
2136 "%s : Dropping DFS channel : %d",
2137 __func__,
2138 channels_allowed[indx]);
2139 num_ignore_dfs_ch++;
2140 break;
2141 }
2142
2143 valid_ch[num_ch++] =
2144 request->channels[i]->hw_value;
2145 len +=
2146 snprintf(chList + len, 5, "%d ",
2147 request->channels[i]->
2148 hw_value);
2149 break;
2150 }
2151 }
2152 }
2153 hddLog(LOG1, FL("Channel-List: %s "), chList);
2154
2155 /* If all channels are DFS and dropped,
2156 * then ignore the PNO request
2157 */
2158 if (num_ignore_dfs_ch == request->n_channels) {
2159 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO,
2160 "%s : All requested channels are DFS channels",
2161 __func__);
2162 ret = -EINVAL;
2163 goto error;
2164 }
2165
2166 }
2167 /* Filling per profile params */
2168 for (i = 0; i < pPnoRequest->ucNetworksCount; i++) {
2169 pPnoRequest->aNetworks[i].ssId.length =
2170 request->match_sets[i].ssid.ssid_len;
2171
2172 if ((0 == pPnoRequest->aNetworks[i].ssId.length) ||
2173 (pPnoRequest->aNetworks[i].ssId.length > 32)) {
2174 hddLog(LOGE,
2175 FL(" SSID Len %d is not correct for network %d"),
2176 pPnoRequest->aNetworks[i].ssId.length, i);
2177 ret = -EINVAL;
2178 goto error;
2179 }
2180
2181 memcpy(pPnoRequest->aNetworks[i].ssId.ssId,
2182 request->match_sets[i].ssid.ssid,
2183 request->match_sets[i].ssid.ssid_len);
2184 pPnoRequest->aNetworks[i].authentication = 0; /*eAUTH_TYPE_ANY */
2185 pPnoRequest->aNetworks[i].encryption = 0; /*eED_ANY */
2186 pPnoRequest->aNetworks[i].bcastNetwType = 0; /*eBCAST_UNKNOWN */
2187
2188 /*Copying list of valid channel into request */
2189 memcpy(pPnoRequest->aNetworks[i].aChannels, valid_ch, num_ch);
2190 pPnoRequest->aNetworks[i].ucChannelCount = num_ch;
2191#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
2192 pPnoRequest->aNetworks[i].rssiThreshold =
2193 request->match_sets[i].rssi_thold;
2194#else
2195 pPnoRequest->aNetworks[i].rssiThreshold = 0; /* Default value */
2196#endif
2197 }
2198
2199 for (i = 0; i < request->n_ssids; i++) {
2200 j = 0;
2201 while (j < pPnoRequest->ucNetworksCount) {
2202 if ((pPnoRequest->aNetworks[j].ssId.length ==
2203 request->ssids[i].ssid_len) &&
2204 (0 == memcmp(pPnoRequest->aNetworks[j].ssId.ssId,
2205 request->ssids[i].ssid,
2206 pPnoRequest->aNetworks[j].ssId.
2207 length))) {
2208 pPnoRequest->aNetworks[j].bcastNetwType =
2209 eBCAST_HIDDEN;
2210 break;
2211 }
2212 j++;
2213 }
2214 }
2215 hddLog(LOG1, FL("Number of hidden networks being Configured = %d"),
2216 request->n_ssids);
2217
2218 hddLog(LOG1, FL("request->ie_len = %zu"), request->ie_len);
2219 if ((0 < request->ie_len) && (NULL != request->ie)) {
2220 pPnoRequest->us24GProbeTemplateLen = request->ie_len;
2221 memcpy(&pPnoRequest->p24GProbeTemplate, request->ie,
2222 pPnoRequest->us24GProbeTemplateLen);
2223
2224 pPnoRequest->us5GProbeTemplateLen = request->ie_len;
2225 memcpy(&pPnoRequest->p5GProbeTemplate, request->ie,
2226 pPnoRequest->us5GProbeTemplateLen);
2227 }
2228
2229 /* Driver gets only one time interval which is hardcoded in
2230 * supplicant for 10000ms. Taking power consumption into account 6 timers
2231 * will be used, Timervalue is increased exponentially i.e 10,20,40,
2232 * 80,160,320 secs. And number of scan cycle for each timer
2233 * is configurable through INI param gPNOScanTimerRepeatValue.
2234 * If it is set to 0 only one timer will be used and PNO scan cycle
2235 * will be repeated after each interval specified by supplicant
2236 * till PNO is disabled.
2237 */
2238 if (0 == pHddCtx->config->configPNOScanTimerRepeatValue)
2239 pPnoRequest->scanTimers.ucScanTimersCount =
2240 HDD_PNO_SCAN_TIMERS_SET_ONE;
2241 else
2242 pPnoRequest->scanTimers.ucScanTimersCount =
2243 HDD_PNO_SCAN_TIMERS_SET_MULTIPLE;
2244
2245 tempInterval = (request->interval) / 1000;
2246 hddLog(LOG1,
2247 FL("Base scan interval = %d PNOScanTimerRepeatValue = %d"),
2248 tempInterval, pHddCtx->config->configPNOScanTimerRepeatValue);
2249 for (i = 0; i < pPnoRequest->scanTimers.ucScanTimersCount; i++) {
2250 pPnoRequest->scanTimers.aTimerValues[i].uTimerRepeat =
2251 pHddCtx->config->configPNOScanTimerRepeatValue;
2252 pPnoRequest->scanTimers.aTimerValues[i].uTimerValue =
2253 tempInterval;
2254 tempInterval *= 2;
2255 }
2256 /* Repeat last timer until pno disabled. */
2257 pPnoRequest->scanTimers.aTimerValues[i - 1].uTimerRepeat = 0;
2258
2259 pPnoRequest->modePNO = SIR_PNO_MODE_IMMEDIATE;
2260
2261 hddLog(LOG1,
2262 FL("SessionId %d, enable %d, modePNO %d, ucScanTimersCount %d"),
2263 pAdapter->sessionId, pPnoRequest->enable,
2264 pPnoRequest->modePNO,
2265 pPnoRequest->scanTimers.ucScanTimersCount);
2266
2267 status = sme_set_preferred_network_list(WLAN_HDD_GET_HAL_CTX(pAdapter),
2268 pPnoRequest,
2269 pAdapter->sessionId,
2270 hdd_sched_scan_callback,
2271 pAdapter);
2272 if (CDF_STATUS_SUCCESS != status) {
2273 hddLog(LOGE, FL("Failed to enable PNO"));
2274 ret = -EINVAL;
2275 goto error;
2276 }
2277
2278 hddLog(LOG1, FL("PNO scanRequest offloaded"));
2279
2280error:
2281 cdf_mem_free(pPnoRequest);
2282 return ret;
2283}
2284
2285/**
2286 * wlan_hdd_cfg80211_sched_scan_start() - cfg80211 scheduled scan(pno) start
2287 * @wiphy: Pointer to wiphy
2288 * @dev: Pointer network device
2289 * @request: Pointer to cfg80211 scheduled scan start request
2290 *
2291 * Return: 0 for success, non zero for failure
2292 */
2293int wlan_hdd_cfg80211_sched_scan_start(struct wiphy *wiphy,
2294 struct net_device *dev,
2295 struct cfg80211_sched_scan_request
2296 *request)
2297{
2298 int ret;
2299
2300 cds_ssr_protect(__func__);
2301 ret = __wlan_hdd_cfg80211_sched_scan_start(wiphy, dev, request);
2302 cds_ssr_unprotect(__func__);
2303
2304 return ret;
2305}
2306
2307/**
2308 * __wlan_hdd_cfg80211_sched_scan_stop() - stop cfg80211 scheduled scan(pno)
2309 * @wiphy: Pointer to wiphy
2310 * @dev: Pointer network device
2311 *
2312 * Return: 0 for success, non zero for failure
2313 */
2314static int __wlan_hdd_cfg80211_sched_scan_stop(struct wiphy *wiphy,
2315 struct net_device *dev)
2316{
2317 CDF_STATUS status = CDF_STATUS_E_FAILURE;
2318 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
2319 hdd_context_t *pHddCtx;
2320 tHalHandle hHal;
2321 tpSirPNOScanReq pPnoRequest = NULL;
2322 int ret = 0;
2323
2324 ENTER();
2325
2326 if (CDF_FTM_MODE == hdd_get_conparam()) {
2327 hddLog(LOGE, FL("Command not allowed in FTM mode"));
2328 return -EINVAL;
2329 }
2330
2331 pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
2332
2333 if (NULL == pHddCtx) {
2334 hddLog(LOGE, FL("HDD context is Null"));
2335 return -ENODEV;
2336 }
2337
2338 /* The return 0 is intentional when isLogpInProgress and
2339 * isLoadUnloadInProgress. We did observe a crash due to a return of
2340 * failure in sched_scan_stop , especially for a case where the unload
2341 * of the happens at the same time. The function __cfg80211_stop_sched_scan
2342 * was clearing rdev->sched_scan_req only when the sched_scan_stop returns
2343 * success. If it returns a failure , then its next invocation due to the
2344 * clean up of the second interface will have the dev pointer corresponding
2345 * to the first one leading to a crash.
2346 */
2347 if (pHddCtx->isLogpInProgress) {
2348 hddLog(LOGE, FL("LOGP in Progress. Ignore!!!"));
2349 return ret;
2350 }
2351
2352 if ((pHddCtx->isLoadInProgress) || (pHddCtx->isUnloadInProgress)) {
2353 hddLog(LOGE, FL("Unloading/Loading in Progress. Ignore!!!"));
2354 return ret;
2355 }
2356
2357 hHal = WLAN_HDD_GET_HAL_CTX(pAdapter);
2358 if (NULL == hHal) {
2359 hddLog(LOGE, FL(" HAL context is Null!!!"));
2360 return -EINVAL;
2361 }
2362
2363 pPnoRequest = (tpSirPNOScanReq) cdf_mem_malloc(sizeof(tSirPNOScanReq));
2364 if (NULL == pPnoRequest) {
2365 hddLog(LOGE, FL("cdf_mem_malloc failed"));
2366 return -ENOMEM;
2367 }
2368
2369 memset(pPnoRequest, 0, sizeof(tSirPNOScanReq));
2370 pPnoRequest->enable = 0; /* Disable PNO */
2371 pPnoRequest->ucNetworksCount = 0;
2372
2373 status = sme_set_preferred_network_list(hHal, pPnoRequest,
2374 pAdapter->sessionId,
2375 NULL, pAdapter);
2376 if (CDF_STATUS_SUCCESS != status) {
2377 hddLog(LOGE, FL("Failed to disabled PNO"));
2378 ret = -EINVAL;
2379 }
2380
2381 hddLog(LOG1, FL("PNO scan disabled"));
2382
2383 cdf_mem_free(pPnoRequest);
2384
2385 EXIT();
2386 return ret;
2387}
2388
2389/**
2390 * wlan_hdd_cfg80211_sched_scan_stop() - stop cfg80211 scheduled scan(pno)
2391 * @wiphy: Pointer to wiphy
2392 * @dev: Pointer network device
2393 *
2394 * Return: 0 for success, non zero for failure
2395 */
2396int wlan_hdd_cfg80211_sched_scan_stop(struct wiphy *wiphy,
2397 struct net_device *dev)
2398{
2399 int ret;
2400
2401 cds_ssr_protect(__func__);
2402 ret = __wlan_hdd_cfg80211_sched_scan_stop(wiphy, dev);
2403 cds_ssr_unprotect(__func__);
2404
2405 return ret;
2406}
2407#endif /*FEATURE_WLAN_SCAN_PNO */
2408
2409/**
2410 * hdd_vendor_put_ifindex() -send interface index
2411 * @skb: buffer pointer
2412 * @ifindex: interface index
2413 *
2414 * Send the IF index to differentiate the events on each interface
2415 * Return: 0 for success, non zero for failure
2416 */
2417int hdd_vendor_put_ifindex(struct sk_buff *skb, int ifindex)
2418{
2419 struct nlattr *attr;
2420
2421 nla_nest_cancel(skb, ((void **)skb->cb)[2]);
2422 if (nla_put_u32(skb, NL80211_ATTR_IFINDEX, ifindex))
2423 return -EINVAL;
2424
2425 attr = nla_nest_start(skb, NL80211_ATTR_VENDOR_DATA);
2426 ((void **)skb->cb)[2] = attr;
2427
2428 return 0;
2429}