blob: 1b73597b242fdad0f45c4865314e5cb481ffb08d [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,
1226#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0))
1227 struct net_device *dev,
1228#endif
1229 struct cfg80211_scan_request *request,
1230 uint8_t source)
1231{
1232#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
1233 struct net_device *dev = request->wdev->netdev;
1234#endif
1235 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
1236 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
1237 hdd_wext_state_t *pwextBuf = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter);
1238 struct hdd_config *cfg_param = NULL;
1239 tCsrScanRequest scan_req;
1240 uint8_t *channelList = NULL, i;
1241 int status;
1242 hdd_scaninfo_t *pScanInfo = NULL;
1243 uint8_t *pP2pIe = NULL;
1244 hdd_adapter_t *con_sap_adapter;
1245 uint16_t con_dfs_ch;
1246
1247 ENTER();
1248
1249 if (CDF_FTM_MODE == hdd_get_conparam()) {
1250 hddLog(LOGE, FL("Command not allowed in FTM mode"));
1251 return -EINVAL;
1252 }
1253
1254 MTRACE(cdf_trace(CDF_MODULE_ID_HDD,
1255 TRACE_CODE_HDD_CFG80211_SCAN,
1256 pAdapter->sessionId, request->n_channels));
1257
1258 hddLog(LOG1, FL("Device_mode %s(%d)"),
1259 hdd_device_mode_to_string(pAdapter->device_mode),
1260 pAdapter->device_mode);
1261
1262 status = wlan_hdd_validate_context(pHddCtx);
1263
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301264 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001265 return status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001266
1267 cfg_param = pHddCtx->config;
1268 pScanInfo = &pAdapter->scan_info;
1269
1270 /* Block All Scan during DFS operation and send null scan result */
1271 con_sap_adapter = hdd_get_con_sap_adapter(pAdapter, true);
1272 if (con_sap_adapter) {
1273 con_dfs_ch = con_sap_adapter->sessionCtx.ap.sapConfig.channel;
1274 if (con_dfs_ch == AUTO_CHANNEL_SELECT)
1275 con_dfs_ch =
1276 con_sap_adapter->sessionCtx.ap.operatingChannel;
1277
1278 if (CDS_IS_DFS_CH(con_dfs_ch)) {
1279 /* Provide empty scan result during DFS operation since
1280 * scanning not supported during DFS. Reason is
1281 * following case:
1282 * DFS is supported only in SCC for MBSSID Mode.
1283 * We shall not return EBUSY or ENOTSUPP as when Primary
1284 * AP is operating in DFS channel and secondary AP is
1285 * started. Though we force SCC in driver, the hostapd
1286 * issues obss scan before starting secAP. This results
1287 * in MCC in DFS mode. Thus we return null scan result.
1288 * If we return scan failure hostapd fails secondary AP
1289 * startup.
1290 */
1291 pAdapter->request = request;
1292
1293#ifdef CONFIG_CNSS
1294 cnss_init_work(&pAdapter->scan_block_work,
1295 wlan_hdd_cfg80211_scan_block_cb);
1296#else
1297 INIT_WORK(&pAdapter->scan_block_work,
1298 wlan_hdd_cfg80211_scan_block_cb);
1299#endif
1300 schedule_work(&pAdapter->scan_block_work);
1301 return 0;
1302 }
1303 }
1304 if (!wma_is_hw_dbs_capable()) {
1305 if (true == pScanInfo->mScanPending) {
1306 if (MAX_PENDING_LOG >
1307 pScanInfo->mScanPendingCounter++) {
1308 hddLog(LOGE, FL("mScanPending is true"));
1309 }
1310 return -EBUSY;
1311 }
1312
1313 /* Don't Allow Scan and return busy if Remain On
1314 * Channel and action frame is pending
1315 * Otherwise Cancel Remain On Channel and allow Scan
1316 * If no action frame pending
1317 */
1318 if (0 != wlan_hdd_check_remain_on_channel(pAdapter)) {
1319 hddLog(LOGE, FL("Remain On Channel Pending"));
1320 return -EBUSY;
1321 }
1322 }
1323#ifdef FEATURE_WLAN_TDLS
1324 /* if tdls disagree scan right now, return immediately.
1325 * tdls will schedule the scan when scan is allowed.
1326 * (return SUCCESS)
1327 * or will reject the scan if any TDLS is in progress.
1328 * (return -EBUSY)
1329 */
1330 status = wlan_hdd_tdls_scan_callback(pAdapter, wiphy,
1331#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0))
1332 dev,
1333#endif
1334 request);
1335 if (status <= 0) {
1336 if (!status)
1337 hddLog(LOGE,
1338 FL("TDLS in progress.scan rejected %d"),
1339 status);
1340 else
1341 hddLog(LOGE, FL("TDLS teardown is ongoing %d"),
1342 status);
1343 return status;
1344 }
1345#endif
1346
1347 /* Check if scan is allowed at this point of time */
1348 if (cds_is_connection_in_progress(pHddCtx)) {
1349 hddLog(LOGE, FL("Scan not allowed"));
1350 return -EBUSY;
1351 }
1352
1353 cdf_mem_zero(&scan_req, sizeof(scan_req));
1354
1355 hddLog(LOG1, "scan request for ssid = %d", request->n_ssids);
1356 scan_req.timestamp = cdf_mc_timer_get_system_ticks();
1357
1358 /* Even though supplicant doesn't provide any SSIDs, n_ssids is
1359 * set to 1. Because of this, driver is assuming that this is not
1360 * wildcard scan and so is not aging out the scan results.
1361 */
1362 if ((request->ssids) && (request->n_ssids == 1) &&
1363 ('\0' == request->ssids->ssid[0])) {
1364 request->n_ssids = 0;
1365 }
1366
1367 if ((request->ssids) && (0 < request->n_ssids)) {
1368 tCsrSSIDInfo *SsidInfo;
1369 int j;
1370 scan_req.SSIDs.numOfSSIDs = request->n_ssids;
1371 /* Allocate num_ssid tCsrSSIDInfo structure */
1372 SsidInfo = scan_req.SSIDs.SSIDList =
1373 cdf_mem_malloc(request->n_ssids * sizeof(tCsrSSIDInfo));
1374
1375 if (NULL == scan_req.SSIDs.SSIDList) {
1376 hddLog(LOGE, FL("memory alloc failed SSIDInfo buffer"));
1377 return -ENOMEM;
1378 }
1379
1380 /* copy all the ssid's and their length */
1381 for (j = 0; j < request->n_ssids; j++, SsidInfo++) {
1382 /* get the ssid length */
1383 SsidInfo->SSID.length = request->ssids[j].ssid_len;
1384 cdf_mem_copy(SsidInfo->SSID.ssId,
1385 &request->ssids[j].ssid[0],
1386 SsidInfo->SSID.length);
1387 SsidInfo->SSID.ssId[SsidInfo->SSID.length] = '\0';
1388 hddLog(LOG1, FL("SSID number %d: %s"), j,
1389 SsidInfo->SSID.ssId);
1390 }
1391 /* set the scan type to active */
1392 scan_req.scanType = eSIR_ACTIVE_SCAN;
1393 } else if (WLAN_HDD_P2P_GO == pAdapter->device_mode) {
1394 /* set the scan type to active */
1395 scan_req.scanType = eSIR_ACTIVE_SCAN;
1396 } else {
1397 /*
1398 * Set the scan type to passive if there is no ssid list
1399 * provided else set default type configured in the driver.
1400 */
1401 if (!request->ssids)
1402 scan_req.scanType = eSIR_PASSIVE_SCAN;
1403 else
1404 scan_req.scanType = pHddCtx->ioctl_scan_mode;
1405 }
1406 scan_req.minChnTime = cfg_param->nActiveMinChnTime;
1407 scan_req.maxChnTime = cfg_param->nActiveMaxChnTime;
1408
1409 /* set BSSType to default type */
1410 scan_req.BSSType = eCSR_BSS_TYPE_ANY;
1411
1412 if (MAX_CHANNEL < request->n_channels) {
1413 hddLog(LOGW, FL("No of Scan Channels exceeded limit: %d"),
1414 request->n_channels);
1415 request->n_channels = MAX_CHANNEL;
1416 }
1417
1418 hddLog(LOG1, FL("No of Scan Channels: %d"), request->n_channels);
1419
1420 if (request->n_channels) {
1421 char chList[(request->n_channels * 5) + 1];
1422 int len;
1423 channelList = cdf_mem_malloc(request->n_channels);
1424 if (NULL == channelList) {
1425 hddLog(LOGE,
1426 FL("channelList malloc failed channelList"));
1427 status = -ENOMEM;
1428 goto free_mem;
1429 }
1430 for (i = 0, len = 0; i < request->n_channels; i++) {
1431 channelList[i] = request->channels[i]->hw_value;
1432 len += snprintf(chList + len, 5, "%d ", channelList[i]);
1433 }
1434
1435 hddLog(LOG1, FL("Channel-List: %s"), chList);
1436
1437 }
1438 scan_req.ChannelInfo.numOfChannels = request->n_channels;
1439 scan_req.ChannelInfo.ChannelList = channelList;
1440
1441 /* set requestType to full scan */
1442 scan_req.requestType = eCSR_SCAN_REQUEST_FULL_SCAN;
1443
1444 /* Flush the scan results(only p2p beacons) for STA scan and P2P
1445 * search (Flush on both full scan and social scan but not on single
1446 * channel scan).P2P search happens on 3 social channels (1, 6, 11)
1447 */
1448
1449 /* Supplicant does single channel scan after 8-way handshake
1450 * and in that case driver shoudnt flush scan results. If
1451 * driver flushes the scan results here and unfortunately if
1452 * the AP doesnt respond to our probe req then association
1453 * fails which is not desired
1454 */
1455
1456 if (request->n_channels != WLAN_HDD_P2P_SINGLE_CHANNEL_SCAN) {
1457 hddLog(CDF_TRACE_LEVEL_DEBUG, "Flushing P2P Results");
1458 sme_scan_flush_p2p_result(WLAN_HDD_GET_HAL_CTX(pAdapter),
1459 pAdapter->sessionId);
1460 }
1461
1462 if (request->ie_len) {
1463 /* save this for future association (join requires this) */
1464 memset(&pScanInfo->scanAddIE, 0, sizeof(pScanInfo->scanAddIE));
1465 memcpy(pScanInfo->scanAddIE.addIEdata, request->ie,
1466 request->ie_len);
1467 pScanInfo->scanAddIE.length = request->ie_len;
1468
1469 if ((WLAN_HDD_INFRA_STATION == pAdapter->device_mode) ||
1470 (WLAN_HDD_P2P_CLIENT == pAdapter->device_mode) ||
1471 (WLAN_HDD_P2P_DEVICE == pAdapter->device_mode)
1472 ) {
1473 pwextBuf->roamProfile.pAddIEScan =
1474 pScanInfo->scanAddIE.addIEdata;
1475 pwextBuf->roamProfile.nAddIEScanLength =
1476 pScanInfo->scanAddIE.length;
1477 }
1478
1479 scan_req.uIEFieldLen = pScanInfo->scanAddIE.length;
1480 scan_req.pIEField = pScanInfo->scanAddIE.addIEdata;
1481
1482 pP2pIe = wlan_hdd_get_p2p_ie_ptr((uint8_t *) request->ie,
1483 request->ie_len);
1484 if (pP2pIe != NULL) {
1485#ifdef WLAN_FEATURE_P2P_DEBUG
1486 if (((global_p2p_connection_status == P2P_GO_NEG_COMPLETED)
1487 || (global_p2p_connection_status ==
1488 P2P_GO_NEG_PROCESS))
1489 && (WLAN_HDD_P2P_CLIENT == pAdapter->device_mode)) {
1490 global_p2p_connection_status =
1491 P2P_CLIENT_CONNECTING_STATE_1;
1492 hddLog(LOGE,
1493 FL("[P2P State] Changing state from Go nego completed to Connection is started"));
1494 hddLog(LOGE,
1495 FL("[P2P]P2P Scanning is started for 8way Handshake"));
1496 } else
1497 if ((global_p2p_connection_status ==
1498 P2P_CLIENT_DISCONNECTED_STATE)
1499 && (WLAN_HDD_P2P_CLIENT ==
1500 pAdapter->device_mode)) {
1501 global_p2p_connection_status =
1502 P2P_CLIENT_CONNECTING_STATE_2;
1503 hddLog(LOGE,
1504 FL("[P2P State] Changing state from Disconnected state to Connection is started"));
1505 hddLog(LOGE,
1506 FL("[P2P]P2P Scanning is started for 4way Handshake"));
1507 }
1508#endif
1509
1510 /* no_cck will be set during p2p find to disable 11b rates */
1511 if (request->no_cck) {
1512 hddLog(CDF_TRACE_LEVEL_INFO,
1513 "%s: This is a P2P Search", __func__);
1514 scan_req.p2pSearch = 1;
1515
1516 if (request->n_channels ==
1517 WLAN_HDD_P2P_SOCIAL_CHANNELS) {
1518 /* set requestType to P2P Discovery */
1519 scan_req.requestType =
1520 eCSR_SCAN_P2P_DISCOVERY;
1521 }
1522
1523 /*
1524 * Skip Dfs Channel in case of P2P Search if it is set in
1525 * ini file
1526 */
1527 if (cfg_param->skipDfsChnlInP2pSearch) {
1528 scan_req.skipDfsChnlInP2pSearch = 1;
1529 } else {
1530 scan_req.skipDfsChnlInP2pSearch = 0;
1531 }
1532
1533 }
1534 }
1535 }
1536
1537 /* acquire the wakelock to avoid the apps suspend during the scan. To
1538 * address the following issues.
1539 * 1) Disconnected scenario: we are not allowing the suspend as WLAN is not in
1540 * BMPS/IMPS this result in android trying to suspend aggressively and backing off
1541 * for long time, this result in apps running at full power for long time.
1542 * 2) Connected scenario: If we allow the suspend during the scan, RIVA will
1543 * be stuck in full power because of resume BMPS
1544 */
1545 hdd_prevent_suspend_timeout(HDD_WAKE_LOCK_SCAN_DURATION,
1546 WIFI_POWER_EVENT_WAKELOCK_SCAN);
1547
1548 hddLog(LOG2,
1549 FL("requestType %d, scanType %d, minChnTime %d, maxChnTime %d,p2pSearch %d, skipDfsChnlIn P2pSearch %d"),
1550 scan_req.requestType, scan_req.scanType,
1551 scan_req.minChnTime, scan_req.maxChnTime,
1552 scan_req.p2pSearch, scan_req.skipDfsChnlInP2pSearch);
1553
1554 status = sme_scan_request(WLAN_HDD_GET_HAL_CTX(pAdapter),
1555 pAdapter->sessionId, &scan_req,
1556 &hdd_cfg80211_scan_done_callback, dev);
1557
1558 if (CDF_STATUS_SUCCESS != status) {
1559 hddLog(LOGE, FL("sme_scan_request returned error %d"), status);
1560 if (CDF_STATUS_E_RESOURCES == status) {
1561 hddLog(LOGE,
1562 FL("HO is in progress.So defer the scan by informing busy"));
1563 status = -EBUSY;
1564 } else {
1565 status = -EIO;
1566 }
1567
1568 hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_SCAN);
1569 goto free_mem;
1570 }
1571 wlan_hdd_scan_request_enqueue(pAdapter, request, source,
1572 scan_req.scan_id, scan_req.timestamp);
1573 pAdapter->scan_info.mScanPending = true;
1574
1575free_mem:
1576 if (scan_req.SSIDs.SSIDList)
1577 cdf_mem_free(scan_req.SSIDs.SSIDList);
1578
1579 if (channelList)
1580 cdf_mem_free(channelList);
1581
1582 EXIT();
1583 return status;
1584}
1585
1586/**
1587 * wlan_hdd_cfg80211_scan() - API to process cfg80211 scan request
1588 * @wiphy: Pointer to wiphy
1589 * @dev: Pointer to net device
1590 * @request: Pointer to scan request
1591 *
1592 * This API responds to scan trigger and update cfg80211 scan database
1593 * later, scan dump command can be used to recieve scan results
1594 *
1595 * Return: 0 for success, non zero for failure
1596 */
1597int wlan_hdd_cfg80211_scan(struct wiphy *wiphy,
1598#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0))
1599 struct net_device *dev,
1600#endif
1601 struct cfg80211_scan_request *request)
1602{
1603 int ret;
1604 cds_ssr_protect(__func__);
1605 ret = __wlan_hdd_cfg80211_scan(wiphy,
1606#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0))
1607 dev,
1608#endif
1609 request, NL_SCAN);
1610 cds_ssr_unprotect(__func__);
1611 return ret;
1612}
1613
1614/**
1615 * wlan_hdd_get_rates() -API to get the rates from scan request
1616 * @wiphy: Pointer to wiphy
1617 * @band: Band
1618 * @rates: array of rates
1619 * @rate_count: number of rates
1620 *
1621 * Return: o for failure, rate bitmap for success
1622 */
1623static uint32_t wlan_hdd_get_rates(struct wiphy *wiphy,
1624 enum ieee80211_band band,
1625 const u8 *rates, unsigned int rate_count)
1626{
1627 uint32_t j, count, rate_bitmap = 0;
1628 uint32_t rate;
1629 bool found;
1630
1631 for (count = 0; count < rate_count; count++) {
1632 rate = ((rates[count]) & RATE_MASK) * 5;
1633 found = false;
1634 for (j = 0; j < wiphy->bands[band]->n_bitrates; j++) {
1635 if (wiphy->bands[band]->bitrates[j].bitrate == rate) {
1636 found = true;
1637 rate_bitmap |= (1 << j);
1638 break;
1639 }
1640 }
1641 if (!found)
1642 return 0;
1643 }
1644 return rate_bitmap;
1645}
1646
1647/**
1648 * wlan_hdd_send_scan_start_event() -API to send the scan start event
1649 * @wiphy: Pointer to wiphy
1650 * @wdev: Pointer to net device
1651 * @cookie: scan identifier
1652 *
1653 * Return: return 0 on success and negative error code on failure
1654 */
1655static int wlan_hdd_send_scan_start_event(struct wiphy *wiphy,
1656 struct wireless_dev *wdev, uint64_t cookie)
1657{
1658 struct sk_buff *skb;
1659 int ret;
1660
1661 skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, sizeof(u64) +
1662 NLA_HDRLEN + NLMSG_HDRLEN);
1663 if (!skb) {
1664 hddLog(LOGE, FL(" reply skb alloc failed"));
1665 return -ENOMEM;
1666 }
1667
1668 if (nla_put_u64(skb, QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE, cookie)) {
1669 hddLog(LOGE, FL("nla put fail"));
1670 kfree_skb(skb);
1671 return -EINVAL;
1672 }
1673
1674 ret = cfg80211_vendor_cmd_reply(skb);
1675
1676 /* Send a scan started event to supplicant */
1677 skb = cfg80211_vendor_event_alloc(wiphy, wdev,
1678 sizeof(u64) + 4 + NLMSG_HDRLEN,
1679 QCA_NL80211_VENDOR_SUBCMD_SCAN_INDEX, GFP_KERNEL);
1680 if (!skb) {
1681 hddLog(LOGE, FL("skb alloc failed"));
1682 return -ENOMEM;
1683 }
1684
1685 ret = hdd_vendor_put_ifindex(skb, wdev->netdev->ifindex);
1686 if (ret) {
1687 kfree_skb(skb);
1688 return -EINVAL;
1689 }
1690
1691 if (nla_put_u64(skb, QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE, cookie)) {
1692 kfree_skb(skb);
1693 return -EINVAL;
1694 }
1695 cfg80211_vendor_event(skb, GFP_KERNEL);
1696
1697 return ret;
1698}
1699/**
1700 * __wlan_hdd_cfg80211_vendor_scan() - API to process venor scan request
1701 * @wiphy: Pointer to wiphy
1702 * @wdev: Pointer to net device
1703 * @data : Pointer to the data
1704 * @data_len : length of the data
1705 *
1706 * API to process venor scan request.
1707 *
1708 * Return: return 0 on success and negative error code on failure
1709 */
1710static int __wlan_hdd_cfg80211_vendor_scan(struct wiphy *wiphy,
1711 struct wireless_dev *wdev, const void *data,
1712 int data_len)
1713{
1714 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_SCAN_MAX + 1];
1715 struct cfg80211_scan_request *request = NULL;
1716 struct nlattr *attr;
1717 enum ieee80211_band band;
1718 uint8_t n_channels = 0, n_ssid = 0, ie_len = 0;
1719 uint32_t tmp, count, j;
1720 unsigned int len;
1721 struct ieee80211_channel *chan;
1722 hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
1723 int ret;
1724
1725 ENTER();
1726
1727 ret = wlan_hdd_validate_context(hdd_ctx);
1728 if (0 != ret)
1729 return ret;
1730
1731 if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_SCAN_MAX, data,
1732 data_len, NULL)) {
1733 hdd_err("Invalid ATTR");
1734 return -EINVAL;
1735 }
1736
1737 if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES]) {
1738 nla_for_each_nested(attr,
1739 tb[QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES], tmp)
1740 n_channels++;
1741 } else {
1742 for (band = 0; band < IEEE80211_NUM_BANDS; band++)
1743 if (wiphy->bands[band])
1744 n_channels += wiphy->bands[band]->n_channels;
1745 }
1746
1747 if (MAX_CHANNEL < n_channels) {
1748 hdd_err("Exceed max number of channels: %d", n_channels);
1749 return -EINVAL;
1750 }
1751 if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_SSIDS])
1752 nla_for_each_nested(attr,
1753 tb[QCA_WLAN_VENDOR_ATTR_SCAN_SSIDS], tmp)
1754 n_ssid++;
1755
1756 if (MAX_SCAN_SSID < n_ssid) {
1757 hdd_err("Exceed max number of SSID: %d", n_ssid);
1758 return -EINVAL;
1759 }
1760
1761 if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_IE])
1762 ie_len = nla_len(tb[QCA_WLAN_VENDOR_ATTR_SCAN_IE]);
1763 else
1764 ie_len = 0;
1765
1766 len = sizeof(*request) + (sizeof(*request->ssids) * n_ssid) +
1767 (sizeof(*request->channels) * n_channels) + ie_len;
1768
1769 request = cdf_mem_malloc(len);
1770 if (!request)
1771 goto error;
1772 if (n_ssid)
1773 request->ssids = (void *)&request->channels[n_channels];
1774 request->n_ssids = n_ssid;
1775 if (ie_len) {
1776 if (request->ssids)
1777 request->ie = (void *)(request->ssids + n_ssid);
1778 else
1779 request->ie = (void *)(request->channels + n_channels);
1780 }
1781
1782 count = 0;
1783 if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES]) {
1784 nla_for_each_nested(attr,
1785 tb[QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES],
1786 tmp) {
1787 chan = __ieee80211_get_channel(wiphy,
1788 nla_get_u32(attr));
1789 if (!chan)
1790 goto error;
1791 if (chan->flags & IEEE80211_CHAN_DISABLED)
1792 continue;
1793 request->channels[count] = chan;
1794 count++;
1795 }
1796 } else {
1797 for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
1798 if (!wiphy->bands[band])
1799 continue;
1800 for (j = 0; j < wiphy->bands[band]->n_channels;
1801 j++) {
1802 chan = &wiphy->bands[band]->channels[j];
1803 if (chan->flags & IEEE80211_CHAN_DISABLED)
1804 continue;
1805 request->channels[count] = chan;
1806 count++;
1807 }
1808 }
1809 }
1810
1811 if (!count)
1812 goto error;
1813
1814 request->n_channels = count;
1815 count = 0;
1816 if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_SSIDS]) {
1817 nla_for_each_nested(attr, tb[QCA_WLAN_VENDOR_ATTR_SCAN_SSIDS],
1818 tmp) {
1819 request->ssids[count].ssid_len = nla_len(attr);
1820 memcpy(request->ssids[count].ssid, nla_data(attr),
1821 nla_len(attr));
1822 count++;
1823 }
1824 }
1825
1826 if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_IE]) {
1827 request->ie_len = nla_len(tb[QCA_WLAN_VENDOR_ATTR_SCAN_IE]);
1828 memcpy((void *)request->ie,
1829 nla_data(tb[QCA_WLAN_VENDOR_ATTR_SCAN_IE]),
1830 request->ie_len);
1831 }
1832
1833 for (count = 0; count < IEEE80211_NUM_BANDS; count++)
1834 if (wiphy->bands[count])
1835 request->rates[count] =
1836 (1 << wiphy->bands[count]->n_bitrates) - 1;
1837
1838 if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_SUPP_RATES]) {
1839 nla_for_each_nested(attr,
1840 tb[QCA_WLAN_VENDOR_ATTR_SCAN_SUPP_RATES],
1841 tmp) {
1842 band = nla_type(attr);
1843 if (!wiphy->bands[band])
1844 continue;
1845 request->rates[band] = wlan_hdd_get_rates(wiphy,
1846 band, nla_data(attr),
1847 nla_len(attr));
1848 }
1849 }
1850
1851 if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_FLAGS]) {
1852 request->flags =
1853 nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_SCAN_FLAGS]);
1854 if ((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) &&
1855 !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) {
1856 hddLog(LOGE, FL("LOW PRIORITY SCAN not supported"));
1857 goto error;
1858 }
1859 }
1860 request->no_cck =
1861 nla_get_flag(tb[QCA_WLAN_VENDOR_ATTR_SCAN_TX_NO_CCK_RATE]);
1862 request->wdev = wdev;
1863 request->wiphy = wiphy;
1864 request->scan_start = jiffies;
1865
1866 if (0 != __wlan_hdd_cfg80211_scan(wiphy, request, VENDOR_SCAN))
1867 goto error;
1868
1869 ret = wlan_hdd_send_scan_start_event(wiphy, wdev, (uintptr_t)request);
1870
1871 return ret;
1872error:
1873 hdd_err("Scan Request Failed");
1874 cdf_mem_free(request);
1875 return -EINVAL;
1876}
1877
1878/**
1879 * wlan_hdd_cfg80211_vendor_scan() -API to process venor scan request
1880 * @wiphy: Pointer to wiphy
1881 * @dev: Pointer to net device
1882 * @data : Pointer to the data
1883 * @data_len : length of the data
1884 *
1885 * This is called from userspace to request scan.
1886 *
1887 * Return: Return the Success or Failure code.
1888 */
1889int wlan_hdd_cfg80211_vendor_scan(struct wiphy *wiphy,
1890 struct wireless_dev *wdev, const void *data,
1891 int data_len)
1892{
1893 int ret;
1894
1895 cds_ssr_protect(__func__);
1896 ret = __wlan_hdd_cfg80211_vendor_scan(wiphy, wdev,
1897 data, data_len);
1898 cds_ssr_unprotect(__func__);
1899
1900 return ret;
1901}
1902/**
1903 * wlan_hdd_scan_abort() - abort ongoing scan
1904 * @pAdapter: Pointer to interface adapter
1905 *
1906 * Return: 0 for success, non zero for failure
1907 */
1908#ifdef FEATURE_WLAN_SCAN_PNO
1909int wlan_hdd_scan_abort(hdd_adapter_t *pAdapter)
1910{
1911 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
1912 hdd_scaninfo_t *pScanInfo = NULL;
1913 unsigned long rc;
1914
1915 pScanInfo = &pAdapter->scan_info;
1916
1917 if (pScanInfo->mScanPending) {
1918 INIT_COMPLETION(pScanInfo->abortscan_event_var);
1919 hdd_abort_mac_scan(pHddCtx, pAdapter->sessionId,
1920 eCSR_SCAN_ABORT_DEFAULT);
1921
1922 rc = wait_for_completion_timeout(
1923 &pScanInfo->abortscan_event_var,
1924 msecs_to_jiffies(5000));
1925 if (!rc) {
1926 hddLog(LOGE,
1927 FL("Timeout occurred while waiting for abort scan"));
1928 return -ETIME;
1929 }
1930 }
1931 return 0;
1932}
1933
1934/**
1935 * hdd_sched_scan_callback - scheduled scan callback
1936 * @callbackContext: Callback context
1937 * @pPrefNetworkFoundInd: Preferred network found indication
1938 *
1939 * This is a callback function that is registerd with SME that is
1940 * invoked when a preferred network is discovered by firmware.
1941 *
1942 * Return: none
1943 */
1944static void
1945hdd_sched_scan_callback(void *callbackContext,
1946 tSirPrefNetworkFoundInd *pPrefNetworkFoundInd)
1947{
1948 int ret;
1949 hdd_adapter_t *pAdapter = (hdd_adapter_t *) callbackContext;
1950 hdd_context_t *pHddCtx;
1951
1952 ENTER();
1953
1954 if (NULL == pAdapter) {
1955 hddLog(LOGE, FL("HDD adapter is Null"));
1956 return;
1957 }
1958
1959 pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
1960 if (NULL == pHddCtx) {
1961 hddLog(LOGE, FL("HDD context is Null!!!"));
1962 return;
1963 }
1964
1965 spin_lock(&pHddCtx->schedScan_lock);
1966 if (true == pHddCtx->isWiphySuspended) {
1967 pHddCtx->isSchedScanUpdatePending = true;
1968 spin_unlock(&pHddCtx->schedScan_lock);
1969 hddLog(LOG1,
1970 FL("Update cfg80211 scan database after it resume"));
1971 return;
1972 }
1973 spin_unlock(&pHddCtx->schedScan_lock);
1974
1975 ret = wlan_hdd_cfg80211_update_bss(pHddCtx->wiphy, pAdapter, 0);
1976
1977 if (0 > ret)
1978 hddLog(LOG1, FL("NO SCAN result"));
1979
1980 cfg80211_sched_scan_results(pHddCtx->wiphy);
1981 hddLog(LOG1,
1982 FL("cfg80211 scan result database updated"));
1983}
1984
1985/**
1986 * wlan_hdd_is_pno_allowed() - Check if PNO is allowed
1987 * @adapter: HDD Device Adapter
1988 *
1989 * The PNO Start request is coming from upper layers.
1990 * It is to be allowed only for Infra STA device type
1991 * and the link should be in a disconnected state.
1992 *
1993 * Return: Success if PNO is allowed, Failure otherwise.
1994 */
1995static CDF_STATUS wlan_hdd_is_pno_allowed(hdd_adapter_t *adapter)
1996{
1997 hddLog(LOG1,
1998 FL("dev_mode=%d, conn_state=%d, session ID=%d"),
1999 adapter->device_mode,
2000 adapter->sessionCtx.station.conn_info.connState,
2001 adapter->sessionId);
2002 if ((adapter->device_mode == WLAN_HDD_INFRA_STATION) &&
2003 (eConnectionState_NotConnected ==
2004 adapter->sessionCtx.station.conn_info.connState))
2005 return CDF_STATUS_SUCCESS;
2006 else
2007 return CDF_STATUS_E_FAILURE;
2008
2009}
2010
2011/**
2012 * __wlan_hdd_cfg80211_sched_scan_start() - cfg80211 scheduled scan(pno) start
2013 * @wiphy: Pointer to wiphy
2014 * @dev: Pointer network device
2015 * @request: Pointer to cfg80211 scheduled scan start request
2016 *
2017 * Return: 0 for success, non zero for failure
2018 */
2019static int __wlan_hdd_cfg80211_sched_scan_start(struct wiphy *wiphy,
2020 struct net_device *dev,
2021 struct
2022 cfg80211_sched_scan_request
2023 *request)
2024{
2025 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
2026 tpSirPNOScanReq pPnoRequest = NULL;
2027 hdd_context_t *pHddCtx;
2028 tHalHandle hHal;
2029 uint32_t i, indx, num_ch, tempInterval, j;
2030 u8 valid_ch[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
2031 u8 channels_allowed[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
2032 uint32_t num_channels_allowed = WNI_CFG_VALID_CHANNEL_LIST_LEN;
2033 CDF_STATUS status = CDF_STATUS_E_FAILURE;
2034 int ret = 0;
2035 hdd_scaninfo_t *pScanInfo = &pAdapter->scan_info;
2036 struct hdd_config *config = NULL;
2037 uint32_t num_ignore_dfs_ch = 0;
2038
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05302039 ENTER();
2040
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002041 if (CDF_FTM_MODE == hdd_get_conparam()) {
2042 hddLog(LOGE, FL("Command not allowed in FTM mode"));
2043 return -EINVAL;
2044 }
2045
2046 pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
2047 ret = wlan_hdd_validate_context(pHddCtx);
2048
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05302049 if (0 != ret)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002050 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002051
2052 config = pHddCtx->config;
2053 hHal = WLAN_HDD_GET_HAL_CTX(pAdapter);
2054 if (NULL == hHal) {
2055 hddLog(LOGE, FL("HAL context is Null!!!"));
2056 return -EINVAL;
2057 }
2058
2059 if ((WLAN_HDD_INFRA_STATION == pAdapter->device_mode) &&
2060 (eConnectionState_Connecting ==
2061 (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))->conn_info.connState)) {
2062 hddLog(LOGE,
2063 FL("%p(%d) Connection in progress: sched_scan_start denied (EBUSY)"),
2064 WLAN_HDD_GET_STATION_CTX_PTR(pAdapter),
2065 pAdapter->sessionId);
2066 return -EBUSY;
2067 }
2068
Sreelakshmi Konamki6744cff2015-09-07 12:10:39 +05302069 MTRACE(cdf_trace(CDF_MODULE_ID_HDD,
2070 TRACE_CODE_HDD_CFG80211_SCHED_SCAN_START,
2071 pAdapter->sessionId, pAdapter->device_mode));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002072 /*
2073 * The current umac is unable to handle the SCAN_PREEMPT and SCAN_DEQUEUED
2074 * so its necessary to terminate the existing scan which is already issued
2075 * otherwise the host won't enter into the suspend state due to the reason
2076 * that the wlan wakelock which was held in the wlan_hdd_cfg80211_scan
2077 * function.
2078 */
2079 sme_scan_flush_result(hHal);
2080 if (true == pScanInfo->mScanPending) {
2081 ret = wlan_hdd_scan_abort(pAdapter);
2082 if (ret < 0) {
2083 hddLog(LOGE,
2084 FL("aborting the existing scan is unsuccessful"));
2085 return -EBUSY;
2086 }
2087 }
2088
2089 if (CDF_STATUS_E_FAILURE == wlan_hdd_is_pno_allowed(pAdapter)) {
2090 hddLog(LOGE, FL("pno is not allowed"));
2091 return -ENOTSUPP;
2092 }
2093
2094 pPnoRequest = (tpSirPNOScanReq) cdf_mem_malloc(sizeof(tSirPNOScanReq));
2095 if (NULL == pPnoRequest) {
2096 hddLog(LOGE, FL("cdf_mem_malloc failed"));
2097 return -ENOMEM;
2098 }
2099
2100 memset(pPnoRequest, 0, sizeof(tSirPNOScanReq));
2101 pPnoRequest->enable = 1; /*Enable PNO */
2102 pPnoRequest->ucNetworksCount = request->n_match_sets;
2103
2104 if ((!pPnoRequest->ucNetworksCount) ||
2105 (pPnoRequest->ucNetworksCount > SIR_PNO_MAX_SUPP_NETWORKS)) {
2106 hddLog(LOGE, FL("Network input is not correct %d"),
2107 pPnoRequest->ucNetworksCount);
2108 ret = -EINVAL;
2109 goto error;
2110 }
2111
2112 if (SIR_PNO_MAX_NETW_CHANNELS_EX < request->n_channels) {
2113 hddLog(LOGE, FL("Incorrect number of channels %d"),
2114 request->n_channels);
2115 ret = -EINVAL;
2116 goto error;
2117 }
2118
2119 /* Framework provides one set of channels(all)
2120 * common for all saved profile */
2121 if (0 != sme_cfg_get_str(hHal, WNI_CFG_VALID_CHANNEL_LIST,
2122 channels_allowed, &num_channels_allowed)) {
2123 hddLog(LOGE,
2124 FL("failed to get valid channel list"));
2125 ret = -EINVAL;
2126 goto error;
2127 }
2128 /* Checking each channel against allowed channel list */
2129 num_ch = 0;
2130 if (request->n_channels) {
2131 char chList[(request->n_channels * 5) + 1];
2132 int len;
2133 for (i = 0, len = 0; i < request->n_channels; i++) {
2134 for (indx = 0; indx < num_channels_allowed; indx++) {
2135 if (request->channels[i]->hw_value ==
2136 channels_allowed[indx]) {
2137
2138 if ((!config->enable_dfs_pno_chnl_scan)
2139 && (CHANNEL_STATE_DFS ==
2140 cds_get_channel_state(
2141 channels_allowed[indx]))) {
2142 CDF_TRACE(CDF_MODULE_ID_HDD,
2143 CDF_TRACE_LEVEL_INFO,
2144 "%s : Dropping DFS channel : %d",
2145 __func__,
2146 channels_allowed[indx]);
2147 num_ignore_dfs_ch++;
2148 break;
2149 }
2150
2151 valid_ch[num_ch++] =
2152 request->channels[i]->hw_value;
2153 len +=
2154 snprintf(chList + len, 5, "%d ",
2155 request->channels[i]->
2156 hw_value);
2157 break;
2158 }
2159 }
2160 }
2161 hddLog(LOG1, FL("Channel-List: %s "), chList);
2162
2163 /* If all channels are DFS and dropped,
2164 * then ignore the PNO request
2165 */
2166 if (num_ignore_dfs_ch == request->n_channels) {
2167 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO,
2168 "%s : All requested channels are DFS channels",
2169 __func__);
2170 ret = -EINVAL;
2171 goto error;
2172 }
2173
2174 }
2175 /* Filling per profile params */
2176 for (i = 0; i < pPnoRequest->ucNetworksCount; i++) {
2177 pPnoRequest->aNetworks[i].ssId.length =
2178 request->match_sets[i].ssid.ssid_len;
2179
2180 if ((0 == pPnoRequest->aNetworks[i].ssId.length) ||
2181 (pPnoRequest->aNetworks[i].ssId.length > 32)) {
2182 hddLog(LOGE,
2183 FL(" SSID Len %d is not correct for network %d"),
2184 pPnoRequest->aNetworks[i].ssId.length, i);
2185 ret = -EINVAL;
2186 goto error;
2187 }
2188
2189 memcpy(pPnoRequest->aNetworks[i].ssId.ssId,
2190 request->match_sets[i].ssid.ssid,
2191 request->match_sets[i].ssid.ssid_len);
2192 pPnoRequest->aNetworks[i].authentication = 0; /*eAUTH_TYPE_ANY */
2193 pPnoRequest->aNetworks[i].encryption = 0; /*eED_ANY */
2194 pPnoRequest->aNetworks[i].bcastNetwType = 0; /*eBCAST_UNKNOWN */
2195
2196 /*Copying list of valid channel into request */
2197 memcpy(pPnoRequest->aNetworks[i].aChannels, valid_ch, num_ch);
2198 pPnoRequest->aNetworks[i].ucChannelCount = num_ch;
2199#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
2200 pPnoRequest->aNetworks[i].rssiThreshold =
2201 request->match_sets[i].rssi_thold;
2202#else
2203 pPnoRequest->aNetworks[i].rssiThreshold = 0; /* Default value */
2204#endif
2205 }
2206
2207 for (i = 0; i < request->n_ssids; i++) {
2208 j = 0;
2209 while (j < pPnoRequest->ucNetworksCount) {
2210 if ((pPnoRequest->aNetworks[j].ssId.length ==
2211 request->ssids[i].ssid_len) &&
2212 (0 == memcmp(pPnoRequest->aNetworks[j].ssId.ssId,
2213 request->ssids[i].ssid,
2214 pPnoRequest->aNetworks[j].ssId.
2215 length))) {
2216 pPnoRequest->aNetworks[j].bcastNetwType =
2217 eBCAST_HIDDEN;
2218 break;
2219 }
2220 j++;
2221 }
2222 }
2223 hddLog(LOG1, FL("Number of hidden networks being Configured = %d"),
2224 request->n_ssids);
2225
2226 hddLog(LOG1, FL("request->ie_len = %zu"), request->ie_len);
2227 if ((0 < request->ie_len) && (NULL != request->ie)) {
2228 pPnoRequest->us24GProbeTemplateLen = request->ie_len;
2229 memcpy(&pPnoRequest->p24GProbeTemplate, request->ie,
2230 pPnoRequest->us24GProbeTemplateLen);
2231
2232 pPnoRequest->us5GProbeTemplateLen = request->ie_len;
2233 memcpy(&pPnoRequest->p5GProbeTemplate, request->ie,
2234 pPnoRequest->us5GProbeTemplateLen);
2235 }
2236
2237 /* Driver gets only one time interval which is hardcoded in
2238 * supplicant for 10000ms. Taking power consumption into account 6 timers
2239 * will be used, Timervalue is increased exponentially i.e 10,20,40,
2240 * 80,160,320 secs. And number of scan cycle for each timer
2241 * is configurable through INI param gPNOScanTimerRepeatValue.
2242 * If it is set to 0 only one timer will be used and PNO scan cycle
2243 * will be repeated after each interval specified by supplicant
2244 * till PNO is disabled.
2245 */
2246 if (0 == pHddCtx->config->configPNOScanTimerRepeatValue)
2247 pPnoRequest->scanTimers.ucScanTimersCount =
2248 HDD_PNO_SCAN_TIMERS_SET_ONE;
2249 else
2250 pPnoRequest->scanTimers.ucScanTimersCount =
2251 HDD_PNO_SCAN_TIMERS_SET_MULTIPLE;
2252
2253 tempInterval = (request->interval) / 1000;
2254 hddLog(LOG1,
2255 FL("Base scan interval = %d PNOScanTimerRepeatValue = %d"),
2256 tempInterval, pHddCtx->config->configPNOScanTimerRepeatValue);
2257 for (i = 0; i < pPnoRequest->scanTimers.ucScanTimersCount; i++) {
2258 pPnoRequest->scanTimers.aTimerValues[i].uTimerRepeat =
2259 pHddCtx->config->configPNOScanTimerRepeatValue;
2260 pPnoRequest->scanTimers.aTimerValues[i].uTimerValue =
2261 tempInterval;
2262 tempInterval *= 2;
2263 }
2264 /* Repeat last timer until pno disabled. */
2265 pPnoRequest->scanTimers.aTimerValues[i - 1].uTimerRepeat = 0;
2266
2267 pPnoRequest->modePNO = SIR_PNO_MODE_IMMEDIATE;
2268
2269 hddLog(LOG1,
2270 FL("SessionId %d, enable %d, modePNO %d, ucScanTimersCount %d"),
2271 pAdapter->sessionId, pPnoRequest->enable,
2272 pPnoRequest->modePNO,
2273 pPnoRequest->scanTimers.ucScanTimersCount);
2274
2275 status = sme_set_preferred_network_list(WLAN_HDD_GET_HAL_CTX(pAdapter),
2276 pPnoRequest,
2277 pAdapter->sessionId,
2278 hdd_sched_scan_callback,
2279 pAdapter);
2280 if (CDF_STATUS_SUCCESS != status) {
2281 hddLog(LOGE, FL("Failed to enable PNO"));
2282 ret = -EINVAL;
2283 goto error;
2284 }
2285
2286 hddLog(LOG1, FL("PNO scanRequest offloaded"));
2287
2288error:
2289 cdf_mem_free(pPnoRequest);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05302290 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002291 return ret;
2292}
2293
2294/**
2295 * wlan_hdd_cfg80211_sched_scan_start() - cfg80211 scheduled scan(pno) start
2296 * @wiphy: Pointer to wiphy
2297 * @dev: Pointer network device
2298 * @request: Pointer to cfg80211 scheduled scan start request
2299 *
2300 * Return: 0 for success, non zero for failure
2301 */
2302int wlan_hdd_cfg80211_sched_scan_start(struct wiphy *wiphy,
2303 struct net_device *dev,
2304 struct cfg80211_sched_scan_request
2305 *request)
2306{
2307 int ret;
2308
2309 cds_ssr_protect(__func__);
2310 ret = __wlan_hdd_cfg80211_sched_scan_start(wiphy, dev, request);
2311 cds_ssr_unprotect(__func__);
2312
2313 return ret;
2314}
2315
2316/**
2317 * __wlan_hdd_cfg80211_sched_scan_stop() - stop cfg80211 scheduled scan(pno)
2318 * @wiphy: Pointer to wiphy
2319 * @dev: Pointer network device
2320 *
2321 * Return: 0 for success, non zero for failure
2322 */
2323static int __wlan_hdd_cfg80211_sched_scan_stop(struct wiphy *wiphy,
2324 struct net_device *dev)
2325{
2326 CDF_STATUS status = CDF_STATUS_E_FAILURE;
2327 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
2328 hdd_context_t *pHddCtx;
2329 tHalHandle hHal;
2330 tpSirPNOScanReq pPnoRequest = NULL;
2331 int ret = 0;
2332
2333 ENTER();
2334
2335 if (CDF_FTM_MODE == hdd_get_conparam()) {
2336 hddLog(LOGE, FL("Command not allowed in FTM mode"));
2337 return -EINVAL;
2338 }
2339
2340 pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
2341
2342 if (NULL == pHddCtx) {
2343 hddLog(LOGE, FL("HDD context is Null"));
2344 return -ENODEV;
2345 }
2346
2347 /* The return 0 is intentional when isLogpInProgress and
2348 * isLoadUnloadInProgress. We did observe a crash due to a return of
2349 * failure in sched_scan_stop , especially for a case where the unload
2350 * of the happens at the same time. The function __cfg80211_stop_sched_scan
2351 * was clearing rdev->sched_scan_req only when the sched_scan_stop returns
2352 * success. If it returns a failure , then its next invocation due to the
2353 * clean up of the second interface will have the dev pointer corresponding
2354 * to the first one leading to a crash.
2355 */
2356 if (pHddCtx->isLogpInProgress) {
2357 hddLog(LOGE, FL("LOGP in Progress. Ignore!!!"));
2358 return ret;
2359 }
2360
2361 if ((pHddCtx->isLoadInProgress) || (pHddCtx->isUnloadInProgress)) {
2362 hddLog(LOGE, FL("Unloading/Loading in Progress. Ignore!!!"));
2363 return ret;
2364 }
2365
2366 hHal = WLAN_HDD_GET_HAL_CTX(pAdapter);
2367 if (NULL == hHal) {
2368 hddLog(LOGE, FL(" HAL context is Null!!!"));
2369 return -EINVAL;
2370 }
2371
2372 pPnoRequest = (tpSirPNOScanReq) cdf_mem_malloc(sizeof(tSirPNOScanReq));
2373 if (NULL == pPnoRequest) {
2374 hddLog(LOGE, FL("cdf_mem_malloc failed"));
2375 return -ENOMEM;
2376 }
2377
2378 memset(pPnoRequest, 0, sizeof(tSirPNOScanReq));
2379 pPnoRequest->enable = 0; /* Disable PNO */
2380 pPnoRequest->ucNetworksCount = 0;
2381
Sreelakshmi Konamki6744cff2015-09-07 12:10:39 +05302382 MTRACE(cdf_trace(CDF_MODULE_ID_HDD,
2383 TRACE_CODE_HDD_CFG80211_SCHED_SCAN_STOP,
2384 pAdapter->sessionId, pAdapter->device_mode));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002385 status = sme_set_preferred_network_list(hHal, pPnoRequest,
2386 pAdapter->sessionId,
2387 NULL, pAdapter);
2388 if (CDF_STATUS_SUCCESS != status) {
2389 hddLog(LOGE, FL("Failed to disabled PNO"));
2390 ret = -EINVAL;
2391 }
2392
2393 hddLog(LOG1, FL("PNO scan disabled"));
2394
2395 cdf_mem_free(pPnoRequest);
2396
2397 EXIT();
2398 return ret;
2399}
2400
2401/**
2402 * wlan_hdd_cfg80211_sched_scan_stop() - stop cfg80211 scheduled scan(pno)
2403 * @wiphy: Pointer to wiphy
2404 * @dev: Pointer network device
2405 *
2406 * Return: 0 for success, non zero for failure
2407 */
2408int wlan_hdd_cfg80211_sched_scan_stop(struct wiphy *wiphy,
2409 struct net_device *dev)
2410{
2411 int ret;
2412
2413 cds_ssr_protect(__func__);
2414 ret = __wlan_hdd_cfg80211_sched_scan_stop(wiphy, dev);
2415 cds_ssr_unprotect(__func__);
2416
2417 return ret;
2418}
2419#endif /*FEATURE_WLAN_SCAN_PNO */
2420
2421/**
2422 * hdd_vendor_put_ifindex() -send interface index
2423 * @skb: buffer pointer
2424 * @ifindex: interface index
2425 *
2426 * Send the IF index to differentiate the events on each interface
2427 * Return: 0 for success, non zero for failure
2428 */
2429int hdd_vendor_put_ifindex(struct sk_buff *skb, int ifindex)
2430{
2431 struct nlattr *attr;
2432
2433 nla_nest_cancel(skb, ((void **)skb->cb)[2]);
2434 if (nla_put_u32(skb, NL80211_ATTR_IFINDEX, ifindex))
2435 return -EINVAL;
2436
2437 attr = nla_nest_start(skb, NL80211_ATTR_VENDOR_DATA);
2438 ((void **)skb->cb)[2] = attr;
2439
2440 return 0;
2441}