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