blob: 46c0cfc55550640f86c6e6d5149efbb175c504a8 [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
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800726 /* Block All Scan during DFS operation and send null scan result */
727 con_sap_adapter = hdd_get_con_sap_adapter(pAdapter, true);
728 if (con_sap_adapter) {
729 con_dfs_ch = con_sap_adapter->sessionCtx.ap.operatingChannel;
730
731 if (CDS_IS_DFS_CH(con_dfs_ch)) {
732 hddLog(LOGW, FL("##In DFS Master mode. Scan aborted"));
733 return -EOPNOTSUPP;
734 }
735 }
736
737 cdf_mem_zero(&scanRequest, sizeof(scanRequest));
738
739 if (NULL != wrqu->data.pointer) {
740 /* set scanType, active or passive */
741 if ((IW_SCAN_TYPE_ACTIVE == scanReq->scan_type) ||
742 (eSIR_ACTIVE_SCAN == hdd_ctx->ioctl_scan_mode)) {
743 scanRequest.scanType = eSIR_ACTIVE_SCAN;
744 } else {
745 scanRequest.scanType = eSIR_PASSIVE_SCAN;
746 }
747
748 /* set bssid using sockaddr from iw_scan_req */
749 cdf_mem_copy(scanRequest.bssid.bytes,
750 &scanReq->bssid.sa_data,
751 CDF_MAC_ADDR_SIZE);
752
753 if (wrqu->data.flags & IW_SCAN_THIS_ESSID) {
754
755 if (scanReq->essid_len) {
756 scanRequest.SSIDs.numOfSSIDs = 1;
757 scanRequest.SSIDs.SSIDList =
758 (tCsrSSIDInfo *)
759 cdf_mem_malloc(sizeof(tCsrSSIDInfo));
760 if (scanRequest.SSIDs.SSIDList) {
761 scanRequest.SSIDs.SSIDList->SSID.
762 length = scanReq->essid_len;
763 cdf_mem_copy(scanRequest.SSIDs.
764 SSIDList->SSID.ssId,
765 scanReq->essid,
766 scanReq->essid_len);
767 } else {
768 scanRequest.SSIDs.numOfSSIDs = 0;
769 CDF_TRACE(CDF_MODULE_ID_HDD,
770 CDF_TRACE_LEVEL_ERROR,
771 "%s: Unable to allocate memory",
772 __func__);
773 CDF_ASSERT(0);
774 }
775 }
776 }
777
778 /* set min and max channel time */
779 scanRequest.minChnTime = scanReq->min_channel_time;
780 scanRequest.maxChnTime = scanReq->max_channel_time;
781
782 } else {
783 if (hdd_ctx->ioctl_scan_mode == eSIR_ACTIVE_SCAN) {
784 /* set the scan type to active */
785 scanRequest.scanType = eSIR_ACTIVE_SCAN;
786 } else {
787 scanRequest.scanType = eSIR_PASSIVE_SCAN;
788 }
789
790 cdf_set_macaddr_broadcast(&scanRequest.bssid);
791
792 /* set min and max channel time to zero */
793 scanRequest.minChnTime = 0;
794 scanRequest.maxChnTime = 0;
795 }
796
797 /* set BSSType to default type */
798 scanRequest.BSSType = eCSR_BSS_TYPE_ANY;
799
800 /*Scan all the channels */
801 scanRequest.ChannelInfo.numOfChannels = 0;
802
803 scanRequest.ChannelInfo.ChannelList = NULL;
804
805 /* set requestType to full scan */
806 scanRequest.requestType = eCSR_SCAN_REQUEST_FULL_SCAN;
807
808 /* if previous genIE is not NULL, update ScanIE */
809 if (0 != pwextBuf->genIE.length) {
810 memset(&pAdapter->scan_info.scanAddIE, 0,
811 sizeof(pAdapter->scan_info.scanAddIE));
812 memcpy(pAdapter->scan_info.scanAddIE.addIEdata,
813 pwextBuf->genIE.addIEdata, pwextBuf->genIE.length);
814 pAdapter->scan_info.scanAddIE.length = pwextBuf->genIE.length;
815
816 pwextBuf->roamProfile.pAddIEScan =
817 pAdapter->scan_info.scanAddIE.addIEdata;
818 pwextBuf->roamProfile.nAddIEScanLength =
819 pAdapter->scan_info.scanAddIE.length;
820
821 /* clear previous genIE after use it */
822 memset(&pwextBuf->genIE, 0, sizeof(pwextBuf->genIE));
823 }
824
825 /* push addIEScan in scanRequset if exist */
826 if (pAdapter->scan_info.scanAddIE.addIEdata &&
827 pAdapter->scan_info.scanAddIE.length) {
828 scanRequest.uIEFieldLen = pAdapter->scan_info.scanAddIE.length;
829 scanRequest.pIEField = pAdapter->scan_info.scanAddIE.addIEdata;
830 }
831 scanRequest.timestamp = cdf_mc_timer_get_system_ticks();
832 status = sme_scan_request((WLAN_HDD_GET_CTX(pAdapter))->hHal,
833 pAdapter->sessionId, &scanRequest,
834 &hdd_scan_request_callback, dev);
835 if (!CDF_IS_STATUS_SUCCESS(status)) {
836 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_FATAL,
837 "%s:sme_scan_request fail %d!!!", __func__, status);
838 goto error;
839 }
840
841 wlan_hdd_scan_request_enqueue(pAdapter, NULL, NL_SCAN,
842 scanRequest.scan_id,
843 scanRequest.timestamp);
844
845 pAdapter->scan_info.mScanPending = true;
846error:
847 if ((wrqu->data.flags & IW_SCAN_THIS_ESSID) && (scanReq->essid_len))
848 cdf_mem_free(scanRequest.SSIDs.SSIDList);
849 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800850 return status;
851}
852
853/**
854 * iw_set_scan() - SSR wrapper for __iw_set_scan
855 * @dev: Pointer to the net device.
856 * @info: Pointer to the iw_request_info.
857 * @wrqu: Pointer to the iwreq_data.
858 * @extra: Pointer to the data.
859 *
860 * Return: 0 on success, error number otherwise
861 */
862int iw_set_scan(struct net_device *dev, struct iw_request_info *info,
863 union iwreq_data *wrqu, char *extra)
864{
865 int ret;
866
867 cds_ssr_protect(__func__);
868 ret = __iw_set_scan(dev, info, wrqu, extra);
869 cds_ssr_unprotect(__func__);
870
871 return ret;
872}
873
874/**
875 * __iw_get_scan() - get scan
876 * @dev: Pointer to the net device.
877 * @info: Pointer to the iw_request_info.
878 * @wrqu: Pointer to the iwreq_data.
879 * @extra: Pointer to the data.
880 *
881 * This function returns the scan results to the wpa_supplicant
882 *
883 * Return: 0 for success, non zero for failure
884 */
885
886static int __iw_get_scan(struct net_device *dev,
887 struct iw_request_info *info,
888 union iwreq_data *wrqu, char *extra)
889{
890 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
891 hdd_context_t *hdd_ctx;
892 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter);
893 tCsrScanResultInfo *pScanResult;
894 CDF_STATUS status = CDF_STATUS_SUCCESS;
895 hdd_scan_info_t scanInfo;
896 tScanResultHandle pResult;
897 int i = 0;
898 int ret;
899
900 ENTER();
901
902 hdd_ctx = WLAN_HDD_GET_CTX(pAdapter);
903 ret = wlan_hdd_validate_context(hdd_ctx);
904 if (0 != ret)
905 return ret;
906
907 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO,
908 "%s: enter buffer length %d!!!", __func__,
909 (wrqu->data.length) ? wrqu->data.length : IW_SCAN_MAX_DATA);
910
911 if (true == pAdapter->scan_info.mScanPending) {
912 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_FATAL,
913 "%s:mScanPending is true !!!", __func__);
914 return -EAGAIN;
915 }
916
917 scanInfo.dev = dev;
918 scanInfo.start = extra;
919 scanInfo.info = info;
920
921 if (0 == wrqu->data.length) {
922 scanInfo.end = extra + IW_SCAN_MAX_DATA;
923 } else {
924 scanInfo.end = extra + wrqu->data.length;
925 }
926
927 status = sme_scan_get_result(hHal, pAdapter->sessionId, NULL, &pResult);
928
929 if (NULL == pResult) {
930 /* no scan results */
931 hddLog(LOG1, "iw_get_scan: NULL Scan Result ");
932 return 0;
933 }
934
935 pScanResult = sme_scan_result_get_first(hHal, pResult);
936
937 while (pScanResult) {
938 status = hdd_indicate_scan_result(&scanInfo, pScanResult);
939 if (0 != status) {
940 break;
941 }
942 i++;
943 pScanResult = sme_scan_result_get_next(hHal, pResult);
944 }
945
946 sme_scan_result_purge(hHal, pResult);
947
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800948 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO,
949 "%s: exit total %d BSS reported !!!", __func__, i);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530950 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800951 return status;
952}
953
954/**
955 * iw_get_scan() - SSR wrapper function for __iw_get_scan
956 * @dev: Pointer to the net device.
957 * @info: Pointer to the iw_request_info.
958 * @wrqu: Pointer to the iwreq_data.
959 * @extra: Pointer to the data.
960 *
961 * Return: 0 on success, error number otherwise
962 */
963int iw_get_scan(struct net_device *dev,
964 struct iw_request_info *info,
965 union iwreq_data *wrqu, char *extra)
966{
967 int ret;
968
969 cds_ssr_protect(__func__);
970 ret = __iw_get_scan(dev, info, wrqu, extra);
971 cds_ssr_unprotect(__func__);
972
973 return ret;
974}
975
976/**
977 * hdd_abort_mac_scan() - aborts ongoing mac scan
978 * @pHddCtx: Pointer to hdd context
979 * @sessionId: session id
980 * @reason: abort reason
981 *
982 * Abort any MAC scan if in progress
983 *
984 * Return: none
985 */
986void hdd_abort_mac_scan(hdd_context_t *pHddCtx, uint8_t sessionId,
987 eCsrAbortReason reason)
988{
989 sme_abort_mac_scan(pHddCtx->hHal, sessionId, reason);
990}
991
992/**
993 * hdd_vendor_scan_callback() - Scan completed callback event
994 * @hddctx: HDD context
995 * @req : Scan request
996 * @aborted : true scan aborted false scan success
997 *
998 * This function sends scan completed callback event to NL.
999 *
1000 * Return: none
1001 */
1002static void hdd_vendor_scan_callback(hdd_adapter_t *adapter,
1003 struct cfg80211_scan_request *req,
1004 bool aborted)
1005{
1006 hdd_context_t *hddctx = WLAN_HDD_GET_CTX(adapter);
1007 struct sk_buff *skb;
1008 struct nlattr *attr;
1009 int i;
1010 uint8_t scan_status;
1011 uint64_t cookie;
1012
1013 ENTER();
1014
1015 if (WLAN_HDD_ADAPTER_MAGIC != adapter->magic) {
1016 hdd_err("Invalid adapter magic");
1017 return;
1018 }
1019 skb = cfg80211_vendor_event_alloc(hddctx->wiphy, NULL,
1020 SCAN_DONE_EVENT_BUF_SIZE + 4 + NLMSG_HDRLEN,
1021 QCA_NL80211_VENDOR_SUBCMD_SCAN_DONE_INDEX,
1022 GFP_KERNEL);
1023
1024 if (!skb) {
1025 hdd_err("skb alloc failed");
1026 return;
1027 }
1028
1029 if (0 != hdd_vendor_put_ifindex(skb, adapter->dev->ifindex))
1030 goto nla_put_failure;
1031
1032 cookie = (uintptr_t)req;
1033
1034 attr = nla_nest_start(skb, QCA_WLAN_VENDOR_ATTR_SCAN_SSIDS);
1035 if (!attr)
1036 goto nla_put_failure;
1037 for (i = 0; i < req->n_ssids; i++) {
1038 if (nla_put(skb, i, req->ssids[i].ssid_len, req->ssids[i].ssid))
1039 goto nla_put_failure;
1040 }
1041 nla_nest_end(skb, attr);
1042
1043 attr = nla_nest_start(skb, QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES);
1044 if (!attr)
1045 goto nla_put_failure;
1046 for (i = 0; i < req->n_channels; i++) {
1047 if (nla_put_u32(skb, i, req->channels[i]->center_freq))
1048 goto nla_put_failure;
1049 }
1050 nla_nest_end(skb, attr);
1051
1052 if (req->ie &&
1053 nla_put(skb, QCA_WLAN_VENDOR_ATTR_SCAN_IE, req->ie_len,
1054 req->ie))
1055 goto nla_put_failure;
1056
1057 if (req->flags &&
1058 nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_SCAN_FLAGS, req->flags))
1059 goto nla_put_failure;
1060
1061 if (nla_put_u64(skb, QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE, cookie))
1062 goto nla_put_failure;
1063
1064 scan_status = (aborted == true) ? VENDOR_SCAN_STATUS_ABORTED :
1065 VENDOR_SCAN_STATUS_NEW_RESULTS;
1066 if (nla_put_u8(skb, QCA_WLAN_VENDOR_ATTR_SCAN_STATUS, scan_status))
1067 goto nla_put_failure;
1068
1069 cfg80211_vendor_event(skb, GFP_KERNEL);
1070 return;
1071
1072nla_put_failure:
1073 kfree_skb(skb);
1074 return;
1075}
1076
1077/**
1078 * hdd_cfg80211_scan_done_callback() - scan done callback function called after
1079 * scan is finished
1080 * @halHandle: Pointer to handle
1081 * @pContext: Pointer to context
1082 * @sessionId: Session Id
1083 * @scanId: Scan Id
1084 * @status: Scan status
1085 *
1086 * Return: CDF status
1087 */
1088static CDF_STATUS hdd_cfg80211_scan_done_callback(tHalHandle halHandle,
1089 void *pContext,
1090 uint8_t sessionId,
1091 uint32_t scanId,
1092 eCsrScanStatus status)
1093{
1094 struct net_device *dev = (struct net_device *)pContext;
1095 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
1096 hdd_scaninfo_t *pScanInfo = &pAdapter->scan_info;
1097 struct cfg80211_scan_request *req = NULL;
1098 bool aborted = false;
1099 hdd_context_t *hddctx = WLAN_HDD_GET_CTX(pAdapter);
1100 int ret = 0;
1101 uint8_t source;
1102 uint32_t scan_time;
1103 uint32_t size = 0;
1104
Bhargav Shah1efa55c2015-11-04 11:58:27 +05301105 ret = wlan_hdd_validate_context(hddctx);
1106 if (0 != ret)
1107 return CDF_STATUS_E_INVAL;
1108
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001109 hddLog(CDF_TRACE_LEVEL_INFO,
1110 "%s called with hal = %p, pContext = %p, ID = %d, status = %d",
1111 __func__, halHandle, pContext, (int)scanId, (int)status);
1112
1113 pScanInfo->mScanPendingCounter = 0;
1114
1115 if (pScanInfo->mScanPending != true) {
1116 CDF_ASSERT(pScanInfo->mScanPending);
1117 goto allow_suspend;
1118 }
1119
1120 if (CDF_STATUS_SUCCESS !=
1121 wlan_hdd_scan_request_dequeue(hddctx, scanId, &req, &source,
1122 &scan_time)) {
1123 hdd_err("Dequeue of scan request failed ID: %d", scanId);
1124 goto allow_suspend;
1125 }
1126
1127 ret = wlan_hdd_cfg80211_update_bss((WLAN_HDD_GET_CTX(pAdapter))->wiphy,
1128 pAdapter, scan_time);
1129 if (0 > ret)
1130 hddLog(CDF_TRACE_LEVEL_INFO, "%s: NO SCAN result", __func__);
1131
1132 /*
1133 * cfg80211_scan_done informing NL80211 about completion
1134 * of scanning
1135 */
1136 if (status == eCSR_SCAN_ABORT || status == eCSR_SCAN_FAILURE) {
1137 aborted = true;
1138 }
1139
1140 cdf_spin_lock(&hddctx->hdd_scan_req_q_lock);
1141 cdf_list_size(&(hddctx->hdd_scan_req_q), &size);
1142 if (!size) {
1143 /* Scan is no longer pending */
1144 pScanInfo->mScanPending = false;
1145 complete(&pScanInfo->abortscan_event_var);
1146 }
1147 cdf_spin_unlock(&hddctx->hdd_scan_req_q_lock);
1148 /*
1149 * Scan can be triggred from NL or vendor scan
1150 * - If scan is triggered from NL then cfg80211 scan done should be
1151 * called to updated scan completion to NL.
1152 * - If scan is triggred through vendor command then
1153 * scan done event will be posted
1154 */
1155 if (NL_SCAN == source)
1156 cfg80211_scan_done(req, aborted);
1157 else
1158 hdd_vendor_scan_callback(pAdapter, req, aborted);
1159
1160allow_suspend:
1161 if (!size) {
1162 /* release the wake lock at the end of the scan */
1163 hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_SCAN);
1164
1165 /* Acquire wakelock to handle the case where APP's tries
1166 * to suspend immediatly after the driver gets connect
1167 * request(i.e after scan) from supplicant, this result in
1168 * app's is suspending and not ableto process the connect
1169 * request to AP
1170 */
1171 hdd_prevent_suspend_timeout(1000,
1172 WIFI_POWER_EVENT_WAKELOCK_SCAN);
1173 }
1174
1175#ifdef FEATURE_WLAN_TDLS
1176 wlan_hdd_tdls_scan_done_callback(pAdapter);
1177#endif
1178
1179 EXIT();
1180 return 0;
1181}
1182
1183
1184/**
1185 * wlan_hdd_cfg80211_scan_block_cb() - scan block work handler
1186 * @work: Pointer to work
1187 *
1188 * Return: none
1189 */
1190static void wlan_hdd_cfg80211_scan_block_cb(struct work_struct *work)
1191{
1192 hdd_adapter_t *adapter = container_of(work,
1193 hdd_adapter_t, scan_block_work);
Mukul Sharma06adf262015-10-30 21:26:40 +05301194 struct cfg80211_scan_request *request;
1195 if (WLAN_HDD_ADAPTER_MAGIC != adapter->magic) {
1196 hddLog(LOGE,
1197 "%s: HDD adapter context is invalid", __func__);
1198 return;
1199 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001200
Mukul Sharma06adf262015-10-30 21:26:40 +05301201 request = adapter->request;
1202 if (request) {
1203 request->n_ssids = 0;
1204 request->n_channels = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001205
Mukul Sharma06adf262015-10-30 21:26:40 +05301206 hddLog(LOGE,
1207 FL("##In DFS Master mode. Scan aborted. Null result sent"));
1208 cfg80211_scan_done(request, true);
1209 adapter->request = NULL;
1210 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001211}
1212
1213/**
1214 * __wlan_hdd_cfg80211_scan() - API to process cfg80211 scan request
1215 * @wiphy: Pointer to wiphy
1216 * @dev: Pointer to net device
1217 * @request: Pointer to scan request
1218 * @source: scan request source(NL/Vendor scan)
1219 *
1220 * This API responds to scan trigger and update cfg80211 scan database
1221 * later, scan dump command can be used to recieve scan results
1222 *
1223 * Return: 0 for success, non zero for failure
1224 */
1225static int __wlan_hdd_cfg80211_scan(struct wiphy *wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001226 struct cfg80211_scan_request *request,
1227 uint8_t source)
1228{
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001229 struct net_device *dev = request->wdev->netdev;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001230 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
1231 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
1232 hdd_wext_state_t *pwextBuf = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter);
1233 struct hdd_config *cfg_param = NULL;
1234 tCsrScanRequest scan_req;
1235 uint8_t *channelList = NULL, i;
1236 int status;
1237 hdd_scaninfo_t *pScanInfo = NULL;
1238 uint8_t *pP2pIe = NULL;
1239 hdd_adapter_t *con_sap_adapter;
1240 uint16_t con_dfs_ch;
1241
1242 ENTER();
1243
Peng Xuf5d60c82015-10-02 17:17:03 -07001244 if (CDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001245 hddLog(LOGE, FL("Command not allowed in FTM mode"));
1246 return -EINVAL;
1247 }
1248
1249 MTRACE(cdf_trace(CDF_MODULE_ID_HDD,
1250 TRACE_CODE_HDD_CFG80211_SCAN,
1251 pAdapter->sessionId, request->n_channels));
1252
1253 hddLog(LOG1, FL("Device_mode %s(%d)"),
1254 hdd_device_mode_to_string(pAdapter->device_mode),
1255 pAdapter->device_mode);
1256
1257 status = wlan_hdd_validate_context(pHddCtx);
1258
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301259 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001260 return status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001261
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,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001326 request);
1327 if (status <= 0) {
1328 if (!status)
1329 hddLog(LOGE,
1330 FL("TDLS in progress.scan rejected %d"),
1331 status);
1332 else
1333 hddLog(LOGE, FL("TDLS teardown is ongoing %d"),
1334 status);
1335 return status;
1336 }
1337#endif
1338
1339 /* Check if scan is allowed at this point of time */
1340 if (cds_is_connection_in_progress(pHddCtx)) {
1341 hddLog(LOGE, FL("Scan not allowed"));
1342 return -EBUSY;
1343 }
1344
1345 cdf_mem_zero(&scan_req, sizeof(scan_req));
1346
1347 hddLog(LOG1, "scan request for ssid = %d", request->n_ssids);
1348 scan_req.timestamp = cdf_mc_timer_get_system_ticks();
1349
1350 /* Even though supplicant doesn't provide any SSIDs, n_ssids is
1351 * set to 1. Because of this, driver is assuming that this is not
1352 * wildcard scan and so is not aging out the scan results.
1353 */
1354 if ((request->ssids) && (request->n_ssids == 1) &&
1355 ('\0' == request->ssids->ssid[0])) {
1356 request->n_ssids = 0;
1357 }
1358
1359 if ((request->ssids) && (0 < request->n_ssids)) {
1360 tCsrSSIDInfo *SsidInfo;
1361 int j;
1362 scan_req.SSIDs.numOfSSIDs = request->n_ssids;
1363 /* Allocate num_ssid tCsrSSIDInfo structure */
1364 SsidInfo = scan_req.SSIDs.SSIDList =
1365 cdf_mem_malloc(request->n_ssids * sizeof(tCsrSSIDInfo));
1366
1367 if (NULL == scan_req.SSIDs.SSIDList) {
1368 hddLog(LOGE, FL("memory alloc failed SSIDInfo buffer"));
1369 return -ENOMEM;
1370 }
1371
1372 /* copy all the ssid's and their length */
1373 for (j = 0; j < request->n_ssids; j++, SsidInfo++) {
1374 /* get the ssid length */
1375 SsidInfo->SSID.length = request->ssids[j].ssid_len;
1376 cdf_mem_copy(SsidInfo->SSID.ssId,
1377 &request->ssids[j].ssid[0],
1378 SsidInfo->SSID.length);
1379 SsidInfo->SSID.ssId[SsidInfo->SSID.length] = '\0';
1380 hddLog(LOG1, FL("SSID number %d: %s"), j,
1381 SsidInfo->SSID.ssId);
1382 }
1383 /* set the scan type to active */
1384 scan_req.scanType = eSIR_ACTIVE_SCAN;
1385 } else if (WLAN_HDD_P2P_GO == pAdapter->device_mode) {
1386 /* set the scan type to active */
1387 scan_req.scanType = eSIR_ACTIVE_SCAN;
1388 } else {
1389 /*
1390 * Set the scan type to passive if there is no ssid list
1391 * provided else set default type configured in the driver.
1392 */
1393 if (!request->ssids)
1394 scan_req.scanType = eSIR_PASSIVE_SCAN;
1395 else
1396 scan_req.scanType = pHddCtx->ioctl_scan_mode;
1397 }
1398 scan_req.minChnTime = cfg_param->nActiveMinChnTime;
1399 scan_req.maxChnTime = cfg_param->nActiveMaxChnTime;
1400
1401 /* set BSSType to default type */
1402 scan_req.BSSType = eCSR_BSS_TYPE_ANY;
1403
1404 if (MAX_CHANNEL < request->n_channels) {
1405 hddLog(LOGW, FL("No of Scan Channels exceeded limit: %d"),
1406 request->n_channels);
1407 request->n_channels = MAX_CHANNEL;
1408 }
1409
1410 hddLog(LOG1, FL("No of Scan Channels: %d"), request->n_channels);
1411
1412 if (request->n_channels) {
1413 char chList[(request->n_channels * 5) + 1];
1414 int len;
1415 channelList = cdf_mem_malloc(request->n_channels);
1416 if (NULL == channelList) {
1417 hddLog(LOGE,
1418 FL("channelList malloc failed channelList"));
1419 status = -ENOMEM;
1420 goto free_mem;
1421 }
1422 for (i = 0, len = 0; i < request->n_channels; i++) {
1423 channelList[i] = request->channels[i]->hw_value;
1424 len += snprintf(chList + len, 5, "%d ", channelList[i]);
1425 }
1426
1427 hddLog(LOG1, FL("Channel-List: %s"), chList);
1428
1429 }
1430 scan_req.ChannelInfo.numOfChannels = request->n_channels;
1431 scan_req.ChannelInfo.ChannelList = channelList;
1432
1433 /* set requestType to full scan */
1434 scan_req.requestType = eCSR_SCAN_REQUEST_FULL_SCAN;
1435
1436 /* Flush the scan results(only p2p beacons) for STA scan and P2P
1437 * search (Flush on both full scan and social scan but not on single
1438 * channel scan).P2P search happens on 3 social channels (1, 6, 11)
1439 */
1440
1441 /* Supplicant does single channel scan after 8-way handshake
1442 * and in that case driver shoudnt flush scan results. If
1443 * driver flushes the scan results here and unfortunately if
1444 * the AP doesnt respond to our probe req then association
1445 * fails which is not desired
1446 */
1447
1448 if (request->n_channels != WLAN_HDD_P2P_SINGLE_CHANNEL_SCAN) {
1449 hddLog(CDF_TRACE_LEVEL_DEBUG, "Flushing P2P Results");
1450 sme_scan_flush_p2p_result(WLAN_HDD_GET_HAL_CTX(pAdapter),
1451 pAdapter->sessionId);
1452 }
1453
1454 if (request->ie_len) {
1455 /* save this for future association (join requires this) */
1456 memset(&pScanInfo->scanAddIE, 0, sizeof(pScanInfo->scanAddIE));
1457 memcpy(pScanInfo->scanAddIE.addIEdata, request->ie,
1458 request->ie_len);
1459 pScanInfo->scanAddIE.length = request->ie_len;
1460
1461 if ((WLAN_HDD_INFRA_STATION == pAdapter->device_mode) ||
1462 (WLAN_HDD_P2P_CLIENT == pAdapter->device_mode) ||
1463 (WLAN_HDD_P2P_DEVICE == pAdapter->device_mode)
1464 ) {
1465 pwextBuf->roamProfile.pAddIEScan =
1466 pScanInfo->scanAddIE.addIEdata;
1467 pwextBuf->roamProfile.nAddIEScanLength =
1468 pScanInfo->scanAddIE.length;
1469 }
1470
1471 scan_req.uIEFieldLen = pScanInfo->scanAddIE.length;
1472 scan_req.pIEField = pScanInfo->scanAddIE.addIEdata;
1473
1474 pP2pIe = wlan_hdd_get_p2p_ie_ptr((uint8_t *) request->ie,
1475 request->ie_len);
1476 if (pP2pIe != NULL) {
1477#ifdef WLAN_FEATURE_P2P_DEBUG
1478 if (((global_p2p_connection_status == P2P_GO_NEG_COMPLETED)
1479 || (global_p2p_connection_status ==
1480 P2P_GO_NEG_PROCESS))
1481 && (WLAN_HDD_P2P_CLIENT == pAdapter->device_mode)) {
1482 global_p2p_connection_status =
1483 P2P_CLIENT_CONNECTING_STATE_1;
1484 hddLog(LOGE,
1485 FL("[P2P State] Changing state from Go nego completed to Connection is started"));
1486 hddLog(LOGE,
1487 FL("[P2P]P2P Scanning is started for 8way Handshake"));
1488 } else
1489 if ((global_p2p_connection_status ==
1490 P2P_CLIENT_DISCONNECTED_STATE)
1491 && (WLAN_HDD_P2P_CLIENT ==
1492 pAdapter->device_mode)) {
1493 global_p2p_connection_status =
1494 P2P_CLIENT_CONNECTING_STATE_2;
1495 hddLog(LOGE,
1496 FL("[P2P State] Changing state from Disconnected state to Connection is started"));
1497 hddLog(LOGE,
1498 FL("[P2P]P2P Scanning is started for 4way Handshake"));
1499 }
1500#endif
1501
1502 /* no_cck will be set during p2p find to disable 11b rates */
1503 if (request->no_cck) {
1504 hddLog(CDF_TRACE_LEVEL_INFO,
1505 "%s: This is a P2P Search", __func__);
1506 scan_req.p2pSearch = 1;
1507
1508 if (request->n_channels ==
1509 WLAN_HDD_P2P_SOCIAL_CHANNELS) {
1510 /* set requestType to P2P Discovery */
1511 scan_req.requestType =
1512 eCSR_SCAN_P2P_DISCOVERY;
1513 }
1514
1515 /*
1516 * Skip Dfs Channel in case of P2P Search if it is set in
1517 * ini file
1518 */
1519 if (cfg_param->skipDfsChnlInP2pSearch) {
1520 scan_req.skipDfsChnlInP2pSearch = 1;
1521 } else {
1522 scan_req.skipDfsChnlInP2pSearch = 0;
1523 }
1524
1525 }
1526 }
1527 }
1528
1529 /* acquire the wakelock to avoid the apps suspend during the scan. To
1530 * address the following issues.
1531 * 1) Disconnected scenario: we are not allowing the suspend as WLAN is not in
1532 * BMPS/IMPS this result in android trying to suspend aggressively and backing off
1533 * for long time, this result in apps running at full power for long time.
1534 * 2) Connected scenario: If we allow the suspend during the scan, RIVA will
1535 * be stuck in full power because of resume BMPS
1536 */
1537 hdd_prevent_suspend_timeout(HDD_WAKE_LOCK_SCAN_DURATION,
1538 WIFI_POWER_EVENT_WAKELOCK_SCAN);
1539
1540 hddLog(LOG2,
1541 FL("requestType %d, scanType %d, minChnTime %d, maxChnTime %d,p2pSearch %d, skipDfsChnlIn P2pSearch %d"),
1542 scan_req.requestType, scan_req.scanType,
1543 scan_req.minChnTime, scan_req.maxChnTime,
1544 scan_req.p2pSearch, scan_req.skipDfsChnlInP2pSearch);
Edhar, Mahesh Kumar6a501522015-11-20 10:14:13 +05301545#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 7, 0))
1546 if (request->flags & NL80211_SCAN_FLAG_FLUSH)
1547 sme_scan_flush_result(WLAN_HDD_GET_HAL_CTX(pAdapter));
1548#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001549 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,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001593 struct cfg80211_scan_request *request)
1594{
1595 int ret;
1596 cds_ssr_protect(__func__);
1597 ret = __wlan_hdd_cfg80211_scan(wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001598 request, NL_SCAN);
1599 cds_ssr_unprotect(__func__);
1600 return ret;
1601}
1602
1603/**
1604 * wlan_hdd_get_rates() -API to get the rates from scan request
1605 * @wiphy: Pointer to wiphy
1606 * @band: Band
1607 * @rates: array of rates
1608 * @rate_count: number of rates
1609 *
1610 * Return: o for failure, rate bitmap for success
1611 */
1612static uint32_t wlan_hdd_get_rates(struct wiphy *wiphy,
1613 enum ieee80211_band band,
1614 const u8 *rates, unsigned int rate_count)
1615{
1616 uint32_t j, count, rate_bitmap = 0;
1617 uint32_t rate;
1618 bool found;
1619
1620 for (count = 0; count < rate_count; count++) {
1621 rate = ((rates[count]) & RATE_MASK) * 5;
1622 found = false;
1623 for (j = 0; j < wiphy->bands[band]->n_bitrates; j++) {
1624 if (wiphy->bands[band]->bitrates[j].bitrate == rate) {
1625 found = true;
1626 rate_bitmap |= (1 << j);
1627 break;
1628 }
1629 }
1630 if (!found)
1631 return 0;
1632 }
1633 return rate_bitmap;
1634}
1635
1636/**
1637 * wlan_hdd_send_scan_start_event() -API to send the scan start event
1638 * @wiphy: Pointer to wiphy
1639 * @wdev: Pointer to net device
1640 * @cookie: scan identifier
1641 *
1642 * Return: return 0 on success and negative error code on failure
1643 */
1644static int wlan_hdd_send_scan_start_event(struct wiphy *wiphy,
1645 struct wireless_dev *wdev, uint64_t cookie)
1646{
1647 struct sk_buff *skb;
1648 int ret;
1649
1650 skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, sizeof(u64) +
1651 NLA_HDRLEN + NLMSG_HDRLEN);
1652 if (!skb) {
1653 hddLog(LOGE, FL(" reply skb alloc failed"));
1654 return -ENOMEM;
1655 }
1656
1657 if (nla_put_u64(skb, QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE, cookie)) {
1658 hddLog(LOGE, FL("nla put fail"));
1659 kfree_skb(skb);
1660 return -EINVAL;
1661 }
1662
1663 ret = cfg80211_vendor_cmd_reply(skb);
1664
1665 /* Send a scan started event to supplicant */
1666 skb = cfg80211_vendor_event_alloc(wiphy, wdev,
1667 sizeof(u64) + 4 + NLMSG_HDRLEN,
1668 QCA_NL80211_VENDOR_SUBCMD_SCAN_INDEX, GFP_KERNEL);
1669 if (!skb) {
1670 hddLog(LOGE, FL("skb alloc failed"));
1671 return -ENOMEM;
1672 }
1673
1674 ret = hdd_vendor_put_ifindex(skb, wdev->netdev->ifindex);
1675 if (ret) {
1676 kfree_skb(skb);
1677 return -EINVAL;
1678 }
1679
1680 if (nla_put_u64(skb, QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE, cookie)) {
1681 kfree_skb(skb);
1682 return -EINVAL;
1683 }
1684 cfg80211_vendor_event(skb, GFP_KERNEL);
1685
1686 return ret;
1687}
1688/**
1689 * __wlan_hdd_cfg80211_vendor_scan() - API to process venor scan request
1690 * @wiphy: Pointer to wiphy
1691 * @wdev: Pointer to net device
1692 * @data : Pointer to the data
1693 * @data_len : length of the data
1694 *
1695 * API to process venor scan request.
1696 *
1697 * Return: return 0 on success and negative error code on failure
1698 */
1699static int __wlan_hdd_cfg80211_vendor_scan(struct wiphy *wiphy,
1700 struct wireless_dev *wdev, const void *data,
1701 int data_len)
1702{
1703 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_SCAN_MAX + 1];
1704 struct cfg80211_scan_request *request = NULL;
1705 struct nlattr *attr;
1706 enum ieee80211_band band;
1707 uint8_t n_channels = 0, n_ssid = 0, ie_len = 0;
1708 uint32_t tmp, count, j;
1709 unsigned int len;
1710 struct ieee80211_channel *chan;
1711 hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
1712 int ret;
1713
1714 ENTER();
1715
1716 ret = wlan_hdd_validate_context(hdd_ctx);
1717 if (0 != ret)
1718 return ret;
1719
1720 if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_SCAN_MAX, data,
1721 data_len, NULL)) {
1722 hdd_err("Invalid ATTR");
1723 return -EINVAL;
1724 }
1725
1726 if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES]) {
1727 nla_for_each_nested(attr,
1728 tb[QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES], tmp)
1729 n_channels++;
1730 } else {
1731 for (band = 0; band < IEEE80211_NUM_BANDS; band++)
1732 if (wiphy->bands[band])
1733 n_channels += wiphy->bands[band]->n_channels;
1734 }
1735
1736 if (MAX_CHANNEL < n_channels) {
1737 hdd_err("Exceed max number of channels: %d", n_channels);
1738 return -EINVAL;
1739 }
1740 if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_SSIDS])
1741 nla_for_each_nested(attr,
1742 tb[QCA_WLAN_VENDOR_ATTR_SCAN_SSIDS], tmp)
1743 n_ssid++;
1744
1745 if (MAX_SCAN_SSID < n_ssid) {
1746 hdd_err("Exceed max number of SSID: %d", n_ssid);
1747 return -EINVAL;
1748 }
1749
1750 if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_IE])
1751 ie_len = nla_len(tb[QCA_WLAN_VENDOR_ATTR_SCAN_IE]);
1752 else
1753 ie_len = 0;
1754
1755 len = sizeof(*request) + (sizeof(*request->ssids) * n_ssid) +
1756 (sizeof(*request->channels) * n_channels) + ie_len;
1757
1758 request = cdf_mem_malloc(len);
1759 if (!request)
1760 goto error;
1761 if (n_ssid)
1762 request->ssids = (void *)&request->channels[n_channels];
1763 request->n_ssids = n_ssid;
1764 if (ie_len) {
1765 if (request->ssids)
1766 request->ie = (void *)(request->ssids + n_ssid);
1767 else
1768 request->ie = (void *)(request->channels + n_channels);
1769 }
1770
1771 count = 0;
1772 if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES]) {
1773 nla_for_each_nested(attr,
1774 tb[QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES],
1775 tmp) {
1776 chan = __ieee80211_get_channel(wiphy,
1777 nla_get_u32(attr));
1778 if (!chan)
1779 goto error;
1780 if (chan->flags & IEEE80211_CHAN_DISABLED)
1781 continue;
1782 request->channels[count] = chan;
1783 count++;
1784 }
1785 } else {
1786 for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
1787 if (!wiphy->bands[band])
1788 continue;
1789 for (j = 0; j < wiphy->bands[band]->n_channels;
1790 j++) {
1791 chan = &wiphy->bands[band]->channels[j];
1792 if (chan->flags & IEEE80211_CHAN_DISABLED)
1793 continue;
1794 request->channels[count] = chan;
1795 count++;
1796 }
1797 }
1798 }
1799
1800 if (!count)
1801 goto error;
1802
1803 request->n_channels = count;
1804 count = 0;
1805 if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_SSIDS]) {
1806 nla_for_each_nested(attr, tb[QCA_WLAN_VENDOR_ATTR_SCAN_SSIDS],
1807 tmp) {
1808 request->ssids[count].ssid_len = nla_len(attr);
1809 memcpy(request->ssids[count].ssid, nla_data(attr),
1810 nla_len(attr));
1811 count++;
1812 }
1813 }
1814
1815 if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_IE]) {
1816 request->ie_len = nla_len(tb[QCA_WLAN_VENDOR_ATTR_SCAN_IE]);
1817 memcpy((void *)request->ie,
1818 nla_data(tb[QCA_WLAN_VENDOR_ATTR_SCAN_IE]),
1819 request->ie_len);
1820 }
1821
1822 for (count = 0; count < IEEE80211_NUM_BANDS; count++)
1823 if (wiphy->bands[count])
1824 request->rates[count] =
1825 (1 << wiphy->bands[count]->n_bitrates) - 1;
1826
1827 if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_SUPP_RATES]) {
1828 nla_for_each_nested(attr,
1829 tb[QCA_WLAN_VENDOR_ATTR_SCAN_SUPP_RATES],
1830 tmp) {
1831 band = nla_type(attr);
1832 if (!wiphy->bands[band])
1833 continue;
1834 request->rates[band] = wlan_hdd_get_rates(wiphy,
1835 band, nla_data(attr),
1836 nla_len(attr));
1837 }
1838 }
1839
1840 if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_FLAGS]) {
1841 request->flags =
1842 nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_SCAN_FLAGS]);
1843 if ((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) &&
1844 !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) {
1845 hddLog(LOGE, FL("LOW PRIORITY SCAN not supported"));
1846 goto error;
1847 }
1848 }
1849 request->no_cck =
1850 nla_get_flag(tb[QCA_WLAN_VENDOR_ATTR_SCAN_TX_NO_CCK_RATE]);
1851 request->wdev = wdev;
1852 request->wiphy = wiphy;
1853 request->scan_start = jiffies;
1854
1855 if (0 != __wlan_hdd_cfg80211_scan(wiphy, request, VENDOR_SCAN))
1856 goto error;
1857
1858 ret = wlan_hdd_send_scan_start_event(wiphy, wdev, (uintptr_t)request);
1859
1860 return ret;
1861error:
1862 hdd_err("Scan Request Failed");
1863 cdf_mem_free(request);
1864 return -EINVAL;
1865}
1866
1867/**
1868 * wlan_hdd_cfg80211_vendor_scan() -API to process venor scan request
1869 * @wiphy: Pointer to wiphy
1870 * @dev: Pointer to net device
1871 * @data : Pointer to the data
1872 * @data_len : length of the data
1873 *
1874 * This is called from userspace to request scan.
1875 *
1876 * Return: Return the Success or Failure code.
1877 */
1878int wlan_hdd_cfg80211_vendor_scan(struct wiphy *wiphy,
1879 struct wireless_dev *wdev, const void *data,
1880 int data_len)
1881{
1882 int ret;
1883
1884 cds_ssr_protect(__func__);
1885 ret = __wlan_hdd_cfg80211_vendor_scan(wiphy, wdev,
1886 data, data_len);
1887 cds_ssr_unprotect(__func__);
1888
1889 return ret;
1890}
1891/**
1892 * wlan_hdd_scan_abort() - abort ongoing scan
1893 * @pAdapter: Pointer to interface adapter
1894 *
1895 * Return: 0 for success, non zero for failure
1896 */
1897#ifdef FEATURE_WLAN_SCAN_PNO
1898int wlan_hdd_scan_abort(hdd_adapter_t *pAdapter)
1899{
1900 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
1901 hdd_scaninfo_t *pScanInfo = NULL;
1902 unsigned long rc;
1903
1904 pScanInfo = &pAdapter->scan_info;
1905
1906 if (pScanInfo->mScanPending) {
1907 INIT_COMPLETION(pScanInfo->abortscan_event_var);
1908 hdd_abort_mac_scan(pHddCtx, pAdapter->sessionId,
1909 eCSR_SCAN_ABORT_DEFAULT);
1910
1911 rc = wait_for_completion_timeout(
1912 &pScanInfo->abortscan_event_var,
1913 msecs_to_jiffies(5000));
1914 if (!rc) {
1915 hddLog(LOGE,
1916 FL("Timeout occurred while waiting for abort scan"));
1917 return -ETIME;
1918 }
1919 }
1920 return 0;
1921}
1922
1923/**
1924 * hdd_sched_scan_callback - scheduled scan callback
1925 * @callbackContext: Callback context
1926 * @pPrefNetworkFoundInd: Preferred network found indication
1927 *
1928 * This is a callback function that is registerd with SME that is
1929 * invoked when a preferred network is discovered by firmware.
1930 *
1931 * Return: none
1932 */
1933static void
1934hdd_sched_scan_callback(void *callbackContext,
1935 tSirPrefNetworkFoundInd *pPrefNetworkFoundInd)
1936{
1937 int ret;
1938 hdd_adapter_t *pAdapter = (hdd_adapter_t *) callbackContext;
1939 hdd_context_t *pHddCtx;
1940
1941 ENTER();
1942
1943 if (NULL == pAdapter) {
1944 hddLog(LOGE, FL("HDD adapter is Null"));
1945 return;
1946 }
1947
1948 pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
1949 if (NULL == pHddCtx) {
1950 hddLog(LOGE, FL("HDD context is Null!!!"));
1951 return;
1952 }
1953
1954 spin_lock(&pHddCtx->schedScan_lock);
1955 if (true == pHddCtx->isWiphySuspended) {
1956 pHddCtx->isSchedScanUpdatePending = true;
1957 spin_unlock(&pHddCtx->schedScan_lock);
1958 hddLog(LOG1,
1959 FL("Update cfg80211 scan database after it resume"));
1960 return;
1961 }
1962 spin_unlock(&pHddCtx->schedScan_lock);
1963
1964 ret = wlan_hdd_cfg80211_update_bss(pHddCtx->wiphy, pAdapter, 0);
1965
1966 if (0 > ret)
1967 hddLog(LOG1, FL("NO SCAN result"));
1968
1969 cfg80211_sched_scan_results(pHddCtx->wiphy);
1970 hddLog(LOG1,
1971 FL("cfg80211 scan result database updated"));
1972}
1973
1974/**
1975 * wlan_hdd_is_pno_allowed() - Check if PNO is allowed
1976 * @adapter: HDD Device Adapter
1977 *
1978 * The PNO Start request is coming from upper layers.
1979 * It is to be allowed only for Infra STA device type
1980 * and the link should be in a disconnected state.
1981 *
1982 * Return: Success if PNO is allowed, Failure otherwise.
1983 */
1984static CDF_STATUS wlan_hdd_is_pno_allowed(hdd_adapter_t *adapter)
1985{
1986 hddLog(LOG1,
1987 FL("dev_mode=%d, conn_state=%d, session ID=%d"),
1988 adapter->device_mode,
1989 adapter->sessionCtx.station.conn_info.connState,
1990 adapter->sessionId);
1991 if ((adapter->device_mode == WLAN_HDD_INFRA_STATION) &&
1992 (eConnectionState_NotConnected ==
1993 adapter->sessionCtx.station.conn_info.connState))
1994 return CDF_STATUS_SUCCESS;
1995 else
1996 return CDF_STATUS_E_FAILURE;
1997
1998}
1999
2000/**
2001 * __wlan_hdd_cfg80211_sched_scan_start() - cfg80211 scheduled scan(pno) start
2002 * @wiphy: Pointer to wiphy
2003 * @dev: Pointer network device
2004 * @request: Pointer to cfg80211 scheduled scan start request
2005 *
2006 * Return: 0 for success, non zero for failure
2007 */
2008static int __wlan_hdd_cfg80211_sched_scan_start(struct wiphy *wiphy,
2009 struct net_device *dev,
2010 struct
2011 cfg80211_sched_scan_request
2012 *request)
2013{
2014 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
2015 tpSirPNOScanReq pPnoRequest = NULL;
2016 hdd_context_t *pHddCtx;
2017 tHalHandle hHal;
Srinivas Girigowdabdc98162015-09-17 11:06:07 -07002018 uint32_t i, indx, num_ch, j;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002019 u8 valid_ch[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
2020 u8 channels_allowed[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
2021 uint32_t num_channels_allowed = WNI_CFG_VALID_CHANNEL_LIST_LEN;
2022 CDF_STATUS status = CDF_STATUS_E_FAILURE;
2023 int ret = 0;
2024 hdd_scaninfo_t *pScanInfo = &pAdapter->scan_info;
2025 struct hdd_config *config = NULL;
2026 uint32_t num_ignore_dfs_ch = 0;
2027
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05302028 ENTER();
2029
Peng Xuf5d60c82015-10-02 17:17:03 -07002030 if (CDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002031 hddLog(LOGE, FL("Command not allowed in FTM mode"));
2032 return -EINVAL;
2033 }
2034
2035 pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
2036 ret = wlan_hdd_validate_context(pHddCtx);
2037
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05302038 if (0 != ret)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002039 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002040
2041 config = pHddCtx->config;
2042 hHal = WLAN_HDD_GET_HAL_CTX(pAdapter);
2043 if (NULL == hHal) {
2044 hddLog(LOGE, FL("HAL context is Null!!!"));
2045 return -EINVAL;
2046 }
2047
2048 if ((WLAN_HDD_INFRA_STATION == pAdapter->device_mode) &&
2049 (eConnectionState_Connecting ==
2050 (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))->conn_info.connState)) {
2051 hddLog(LOGE,
2052 FL("%p(%d) Connection in progress: sched_scan_start denied (EBUSY)"),
2053 WLAN_HDD_GET_STATION_CTX_PTR(pAdapter),
2054 pAdapter->sessionId);
2055 return -EBUSY;
2056 }
2057
Sreelakshmi Konamki6744cff2015-09-07 12:10:39 +05302058 MTRACE(cdf_trace(CDF_MODULE_ID_HDD,
2059 TRACE_CODE_HDD_CFG80211_SCHED_SCAN_START,
2060 pAdapter->sessionId, pAdapter->device_mode));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002061 /*
2062 * The current umac is unable to handle the SCAN_PREEMPT and SCAN_DEQUEUED
2063 * so its necessary to terminate the existing scan which is already issued
2064 * otherwise the host won't enter into the suspend state due to the reason
2065 * that the wlan wakelock which was held in the wlan_hdd_cfg80211_scan
2066 * function.
2067 */
2068 sme_scan_flush_result(hHal);
2069 if (true == pScanInfo->mScanPending) {
2070 ret = wlan_hdd_scan_abort(pAdapter);
2071 if (ret < 0) {
2072 hddLog(LOGE,
2073 FL("aborting the existing scan is unsuccessful"));
2074 return -EBUSY;
2075 }
2076 }
2077
2078 if (CDF_STATUS_E_FAILURE == wlan_hdd_is_pno_allowed(pAdapter)) {
2079 hddLog(LOGE, FL("pno is not allowed"));
2080 return -ENOTSUPP;
2081 }
2082
2083 pPnoRequest = (tpSirPNOScanReq) cdf_mem_malloc(sizeof(tSirPNOScanReq));
2084 if (NULL == pPnoRequest) {
2085 hddLog(LOGE, FL("cdf_mem_malloc failed"));
2086 return -ENOMEM;
2087 }
2088
2089 memset(pPnoRequest, 0, sizeof(tSirPNOScanReq));
2090 pPnoRequest->enable = 1; /*Enable PNO */
2091 pPnoRequest->ucNetworksCount = request->n_match_sets;
2092
2093 if ((!pPnoRequest->ucNetworksCount) ||
2094 (pPnoRequest->ucNetworksCount > SIR_PNO_MAX_SUPP_NETWORKS)) {
2095 hddLog(LOGE, FL("Network input is not correct %d"),
2096 pPnoRequest->ucNetworksCount);
2097 ret = -EINVAL;
2098 goto error;
2099 }
2100
2101 if (SIR_PNO_MAX_NETW_CHANNELS_EX < request->n_channels) {
2102 hddLog(LOGE, FL("Incorrect number of channels %d"),
2103 request->n_channels);
2104 ret = -EINVAL;
2105 goto error;
2106 }
2107
2108 /* Framework provides one set of channels(all)
2109 * common for all saved profile */
2110 if (0 != sme_cfg_get_str(hHal, WNI_CFG_VALID_CHANNEL_LIST,
2111 channels_allowed, &num_channels_allowed)) {
2112 hddLog(LOGE,
2113 FL("failed to get valid channel list"));
2114 ret = -EINVAL;
2115 goto error;
2116 }
2117 /* Checking each channel against allowed channel list */
2118 num_ch = 0;
2119 if (request->n_channels) {
2120 char chList[(request->n_channels * 5) + 1];
2121 int len;
2122 for (i = 0, len = 0; i < request->n_channels; i++) {
2123 for (indx = 0; indx < num_channels_allowed; indx++) {
2124 if (request->channels[i]->hw_value ==
2125 channels_allowed[indx]) {
2126
2127 if ((!config->enable_dfs_pno_chnl_scan)
2128 && (CHANNEL_STATE_DFS ==
2129 cds_get_channel_state(
2130 channels_allowed[indx]))) {
2131 CDF_TRACE(CDF_MODULE_ID_HDD,
2132 CDF_TRACE_LEVEL_INFO,
2133 "%s : Dropping DFS channel : %d",
2134 __func__,
2135 channels_allowed[indx]);
2136 num_ignore_dfs_ch++;
2137 break;
2138 }
2139
2140 valid_ch[num_ch++] =
2141 request->channels[i]->hw_value;
2142 len +=
2143 snprintf(chList + len, 5, "%d ",
2144 request->channels[i]->
2145 hw_value);
2146 break;
2147 }
2148 }
2149 }
2150 hddLog(LOG1, FL("Channel-List: %s "), chList);
2151
2152 /* If all channels are DFS and dropped,
2153 * then ignore the PNO request
2154 */
2155 if (num_ignore_dfs_ch == request->n_channels) {
2156 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO,
2157 "%s : All requested channels are DFS channels",
2158 __func__);
2159 ret = -EINVAL;
2160 goto error;
2161 }
2162
2163 }
2164 /* Filling per profile params */
2165 for (i = 0; i < pPnoRequest->ucNetworksCount; i++) {
2166 pPnoRequest->aNetworks[i].ssId.length =
2167 request->match_sets[i].ssid.ssid_len;
2168
2169 if ((0 == pPnoRequest->aNetworks[i].ssId.length) ||
2170 (pPnoRequest->aNetworks[i].ssId.length > 32)) {
2171 hddLog(LOGE,
2172 FL(" SSID Len %d is not correct for network %d"),
2173 pPnoRequest->aNetworks[i].ssId.length, i);
2174 ret = -EINVAL;
2175 goto error;
2176 }
2177
2178 memcpy(pPnoRequest->aNetworks[i].ssId.ssId,
2179 request->match_sets[i].ssid.ssid,
2180 request->match_sets[i].ssid.ssid_len);
2181 pPnoRequest->aNetworks[i].authentication = 0; /*eAUTH_TYPE_ANY */
2182 pPnoRequest->aNetworks[i].encryption = 0; /*eED_ANY */
2183 pPnoRequest->aNetworks[i].bcastNetwType = 0; /*eBCAST_UNKNOWN */
2184
2185 /*Copying list of valid channel into request */
2186 memcpy(pPnoRequest->aNetworks[i].aChannels, valid_ch, num_ch);
2187 pPnoRequest->aNetworks[i].ucChannelCount = num_ch;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002188 pPnoRequest->aNetworks[i].rssiThreshold =
2189 request->match_sets[i].rssi_thold;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002190 }
2191
2192 for (i = 0; i < request->n_ssids; i++) {
2193 j = 0;
2194 while (j < pPnoRequest->ucNetworksCount) {
2195 if ((pPnoRequest->aNetworks[j].ssId.length ==
2196 request->ssids[i].ssid_len) &&
2197 (0 == memcmp(pPnoRequest->aNetworks[j].ssId.ssId,
2198 request->ssids[i].ssid,
2199 pPnoRequest->aNetworks[j].ssId.
2200 length))) {
2201 pPnoRequest->aNetworks[j].bcastNetwType =
2202 eBCAST_HIDDEN;
2203 break;
2204 }
2205 j++;
2206 }
2207 }
2208 hddLog(LOG1, FL("Number of hidden networks being Configured = %d"),
2209 request->n_ssids);
2210
2211 hddLog(LOG1, FL("request->ie_len = %zu"), request->ie_len);
2212 if ((0 < request->ie_len) && (NULL != request->ie)) {
2213 pPnoRequest->us24GProbeTemplateLen = request->ie_len;
2214 memcpy(&pPnoRequest->p24GProbeTemplate, request->ie,
2215 pPnoRequest->us24GProbeTemplateLen);
2216
2217 pPnoRequest->us5GProbeTemplateLen = request->ie_len;
2218 memcpy(&pPnoRequest->p5GProbeTemplate, request->ie,
2219 pPnoRequest->us5GProbeTemplateLen);
2220 }
2221
Srinivas Girigowdabdc98162015-09-17 11:06:07 -07002222 /*
2223 * Driver gets only one time interval which is hard coded in
2224 * supplicant for 10000ms. Taking power consumption into account
2225 * firmware after gPNOScanTimerRepeatValue times fast_scan_period
2226 * switches slow_scan_period. This is less frequent scans and firmware
2227 * shall be in slow_scan_period mode until next PNO Start.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002228 */
Srinivas Girigowdabdc98162015-09-17 11:06:07 -07002229 pPnoRequest->fast_scan_period = request->interval;
2230 pPnoRequest->fast_scan_max_cycles =
2231 config->configPNOScanTimerRepeatValue;
2232 pPnoRequest->slow_scan_period =
2233 config->pno_slow_scan_multiplier *
2234 pPnoRequest->fast_scan_period;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002235
Srinivas Girigowdabdc98162015-09-17 11:06:07 -07002236 hdd_info("Base scan interval: %d sec PNOScanTimerRepeatValue: %d",
2237 (request->interval / 1000),
2238 config->configPNOScanTimerRepeatValue);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002239
2240 pPnoRequest->modePNO = SIR_PNO_MODE_IMMEDIATE;
2241
Srinivas Girigowdabdc98162015-09-17 11:06:07 -07002242 hdd_info("SessionId %d, enable %d, modePNO %d",
2243 pAdapter->sessionId, pPnoRequest->enable, pPnoRequest->modePNO);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002244
2245 status = sme_set_preferred_network_list(WLAN_HDD_GET_HAL_CTX(pAdapter),
2246 pPnoRequest,
2247 pAdapter->sessionId,
2248 hdd_sched_scan_callback,
2249 pAdapter);
2250 if (CDF_STATUS_SUCCESS != status) {
2251 hddLog(LOGE, FL("Failed to enable PNO"));
2252 ret = -EINVAL;
2253 goto error;
2254 }
2255
2256 hddLog(LOG1, FL("PNO scanRequest offloaded"));
2257
2258error:
2259 cdf_mem_free(pPnoRequest);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05302260 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002261 return ret;
2262}
2263
2264/**
2265 * wlan_hdd_cfg80211_sched_scan_start() - cfg80211 scheduled scan(pno) start
2266 * @wiphy: Pointer to wiphy
2267 * @dev: Pointer network device
2268 * @request: Pointer to cfg80211 scheduled scan start request
2269 *
2270 * Return: 0 for success, non zero for failure
2271 */
2272int wlan_hdd_cfg80211_sched_scan_start(struct wiphy *wiphy,
2273 struct net_device *dev,
2274 struct cfg80211_sched_scan_request
2275 *request)
2276{
2277 int ret;
2278
2279 cds_ssr_protect(__func__);
2280 ret = __wlan_hdd_cfg80211_sched_scan_start(wiphy, dev, request);
2281 cds_ssr_unprotect(__func__);
2282
2283 return ret;
2284}
2285
2286/**
2287 * __wlan_hdd_cfg80211_sched_scan_stop() - stop cfg80211 scheduled scan(pno)
2288 * @wiphy: Pointer to wiphy
2289 * @dev: Pointer network device
2290 *
2291 * Return: 0 for success, non zero for failure
2292 */
2293static int __wlan_hdd_cfg80211_sched_scan_stop(struct wiphy *wiphy,
2294 struct net_device *dev)
2295{
2296 CDF_STATUS status = CDF_STATUS_E_FAILURE;
2297 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
2298 hdd_context_t *pHddCtx;
2299 tHalHandle hHal;
2300 tpSirPNOScanReq pPnoRequest = NULL;
2301 int ret = 0;
2302
2303 ENTER();
2304
Peng Xuf5d60c82015-10-02 17:17:03 -07002305 if (CDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002306 hddLog(LOGE, FL("Command not allowed in FTM mode"));
2307 return -EINVAL;
2308 }
2309
2310 pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
2311
2312 if (NULL == pHddCtx) {
2313 hddLog(LOGE, FL("HDD context is Null"));
2314 return -ENODEV;
2315 }
2316
2317 /* The return 0 is intentional when isLogpInProgress and
2318 * isLoadUnloadInProgress. We did observe a crash due to a return of
2319 * failure in sched_scan_stop , especially for a case where the unload
2320 * of the happens at the same time. The function __cfg80211_stop_sched_scan
2321 * was clearing rdev->sched_scan_req only when the sched_scan_stop returns
2322 * success. If it returns a failure , then its next invocation due to the
2323 * clean up of the second interface will have the dev pointer corresponding
2324 * to the first one leading to a crash.
2325 */
2326 if (pHddCtx->isLogpInProgress) {
2327 hddLog(LOGE, FL("LOGP in Progress. Ignore!!!"));
2328 return ret;
2329 }
2330
2331 if ((pHddCtx->isLoadInProgress) || (pHddCtx->isUnloadInProgress)) {
2332 hddLog(LOGE, FL("Unloading/Loading in Progress. Ignore!!!"));
2333 return ret;
2334 }
2335
2336 hHal = WLAN_HDD_GET_HAL_CTX(pAdapter);
2337 if (NULL == hHal) {
2338 hddLog(LOGE, FL(" HAL context is Null!!!"));
2339 return -EINVAL;
2340 }
2341
2342 pPnoRequest = (tpSirPNOScanReq) cdf_mem_malloc(sizeof(tSirPNOScanReq));
2343 if (NULL == pPnoRequest) {
2344 hddLog(LOGE, FL("cdf_mem_malloc failed"));
2345 return -ENOMEM;
2346 }
2347
2348 memset(pPnoRequest, 0, sizeof(tSirPNOScanReq));
2349 pPnoRequest->enable = 0; /* Disable PNO */
2350 pPnoRequest->ucNetworksCount = 0;
2351
Sreelakshmi Konamki6744cff2015-09-07 12:10:39 +05302352 MTRACE(cdf_trace(CDF_MODULE_ID_HDD,
2353 TRACE_CODE_HDD_CFG80211_SCHED_SCAN_STOP,
2354 pAdapter->sessionId, pAdapter->device_mode));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002355 status = sme_set_preferred_network_list(hHal, pPnoRequest,
2356 pAdapter->sessionId,
2357 NULL, pAdapter);
2358 if (CDF_STATUS_SUCCESS != status) {
2359 hddLog(LOGE, FL("Failed to disabled PNO"));
2360 ret = -EINVAL;
2361 }
2362
2363 hddLog(LOG1, FL("PNO scan disabled"));
2364
2365 cdf_mem_free(pPnoRequest);
2366
2367 EXIT();
2368 return ret;
2369}
2370
2371/**
2372 * wlan_hdd_cfg80211_sched_scan_stop() - stop cfg80211 scheduled scan(pno)
2373 * @wiphy: Pointer to wiphy
2374 * @dev: Pointer network device
2375 *
2376 * Return: 0 for success, non zero for failure
2377 */
2378int wlan_hdd_cfg80211_sched_scan_stop(struct wiphy *wiphy,
2379 struct net_device *dev)
2380{
2381 int ret;
2382
2383 cds_ssr_protect(__func__);
2384 ret = __wlan_hdd_cfg80211_sched_scan_stop(wiphy, dev);
2385 cds_ssr_unprotect(__func__);
2386
2387 return ret;
2388}
2389#endif /*FEATURE_WLAN_SCAN_PNO */
2390
2391/**
2392 * hdd_vendor_put_ifindex() -send interface index
2393 * @skb: buffer pointer
2394 * @ifindex: interface index
2395 *
2396 * Send the IF index to differentiate the events on each interface
2397 * Return: 0 for success, non zero for failure
2398 */
2399int hdd_vendor_put_ifindex(struct sk_buff *skb, int ifindex)
2400{
2401 struct nlattr *attr;
2402
2403 nla_nest_cancel(skb, ((void **)skb->cb)[2]);
2404 if (nla_put_u32(skb, NL80211_ATTR_IFINDEX, ifindex))
2405 return -EINVAL;
2406
2407 attr = nla_nest_start(skb, NL80211_ATTR_VENDOR_DATA);
2408 ((void **)skb->cb)[2] = attr;
2409
2410 return 0;
2411}