blob: 3303e1f59dd5f85eb394eac931799895a2008db7 [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302 * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003 *
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 * DOC: wlan_hdd_ext_scan.c
24 *
25 * WLAN Host Device Driver EXT SCAN feature implementation
26 *
27 */
28
29#ifdef FEATURE_WLAN_EXTSCAN
30
31#include "wlan_hdd_ext_scan.h"
32#include "cds_utils.h"
33#include "cds_sched.h"
34
35/* amount of time to wait for a synchronous request/response operation */
36#define WLAN_WAIT_TIME_EXTSCAN 1000
37
38/**
39 * struct hdd_ext_scan_context - hdd ext scan context
40 * @request_id: userspace-assigned ID associated with the request
41 * @response_event: Ext scan wait event
42 * @response_status: Status returned by FW in response to a request
43 * @ignore_cached_results: Flag to ignore cached results or not
44 * @context_lock: Spinlock to serialize all context accesses
45 * @capability_response: Ext scan capability response data from target
46 */
47struct hdd_ext_scan_context {
48 uint32_t request_id;
49 int response_status;
50 bool ignore_cached_results;
51 struct completion response_event;
52 spinlock_t context_lock;
53 struct ext_scan_capabilities_response capability_response;
54};
55static struct hdd_ext_scan_context ext_scan_context;
56
57static const struct nla_policy wlan_hdd_extscan_config_policy
58[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX + 1] = {
59 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID] = {
60 .type = NLA_U32},
61 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_GET_VALID_CHANNELS_CONFIG_PARAM_WIFI_BAND] = {
62 .type = NLA_U32},
63 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_CHANNEL] = {.type = NLA_U32},
64 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_DWELL_TIME] = {
65 .type = NLA_U32},
66 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_PASSIVE] = {.type = NLA_U8},
67 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_CLASS] = {.type = NLA_U8},
68
69 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_INDEX] = {.type = NLA_U8},
70 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_BAND] = {.type = NLA_U8},
71 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_PERIOD] = {.type = NLA_U32},
72 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_REPORT_EVENTS] = {
73 .type = NLA_U8},
74 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_NUM_CHANNEL_SPECS] = {
75 .type = NLA_U32},
76 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_BASE_PERIOD] = {
77 .type = NLA_U32},
78 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_MAX_AP_PER_SCAN] = {
79 .type = NLA_U32},
80 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_REPORT_THRESHOLD_PERCENT] = {
81 .type = NLA_U8},
82 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_REPORT_THRESHOLD_NUM_SCANS] = {
83 .type = NLA_U8 },
84 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_NUM_BUCKETS] = {
85 .type = NLA_U8},
86 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_GET_CACHED_SCAN_RESULTS_CONFIG_PARAM_FLUSH] = {
87 .type = NLA_U8},
88
89 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_GET_CACHED_SCAN_RESULTS_CONFIG_PARAM_MAX] = {
90 .type = NLA_U32},
91 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_BSSID] = {
92 .type = NLA_UNSPEC},
93 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_RSSI_LOW] = {
94 .type = NLA_S32},
95 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_RSSI_HIGH] = {
96 .type = NLA_S32},
97 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_CHANNEL] = {
98 .type = NLA_U32},
99 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_BSSID_HOTLIST_PARAMS_NUM_AP] = {
100 .type = NLA_U32},
101 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_RSSI_SAMPLE_SIZE] = {
102 .type = NLA_U32},
103 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_LOST_AP_SAMPLE_SIZE] = {
104 .type = NLA_U32},
105 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_MIN_BREACHING] = {
106 .type = NLA_U32},
107 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_NUM_AP] = {
108 .type = NLA_U32},
109 [QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_NUM_NETWORKS] = {
110 .type = NLA_U32 },
111 [QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_SSID] = {
112 .type = NLA_BINARY,
113 .len = IEEE80211_MAX_SSID_LEN },
114 [QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_RSSI_THRESHOLD] = {
115 .type = NLA_S8 },
116 [QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_FLAGS] = {
117 .type = NLA_U8 },
118 [QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_AUTH_BIT] = {
119 .type = NLA_U8 },
120 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM_SSID] = {
121 .type = NLA_BINARY,
122 .len = IEEE80211_MAX_SSID_LEN + 1 },
123 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_HOTLIST_PARAMS_LOST_SSID_SAMPLE_SIZE] = {
124 .type = NLA_U32 },
125 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_HOTLIST_PARAMS_NUM_SSID] = {
126 .type = NLA_U32 },
127 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM_BAND] = {
128 .type = NLA_U8 },
129 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM_RSSI_LOW] = {
130 .type = NLA_S32 },
131 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM_RSSI_HIGH] = {
132 .type = NLA_S32 },
133 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_CONFIGURATION_FLAGS] = {
134 .type = NLA_U32 },
135};
136
137static const struct nla_policy
138wlan_hdd_extscan_results_policy[QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_MAX + 1] = {
139 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_BEACON_PERIOD] = {
140 .type = NLA_U16},
141 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_CAPABILITY] = {
142 .type = NLA_U16},
143};
144
145/**
146 * wlan_hdd_cfg80211_extscan_get_capabilities_rsp() - response from target
147 * @ctx: Pointer to hdd context
148 * @data: Pointer to ext scan capabilities response from fw
149 *
150 * Return: None
151 */
152static void
153wlan_hdd_cfg80211_extscan_get_capabilities_rsp(void *ctx,
154 struct ext_scan_capabilities_response *data)
155{
156 struct hdd_ext_scan_context *context;
157 hdd_context_t *hdd_ctx = ctx;
158
159 ENTER();
160
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530161 if (wlan_hdd_validate_context(hdd_ctx))
162 return;
163 if (!data) {
164 hddLog(LOGE, FL("data is null"));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800165 return;
166 }
167
168 context = &ext_scan_context;
169
170 spin_lock(&context->context_lock);
171 /* validate response received from target*/
172 if (context->request_id != data->requestId) {
173 spin_unlock(&context->context_lock);
174 hddLog(LOGE,
175 FL("Target response id did not match: request_id %d response_id %d"),
176 context->request_id, data->requestId);
177 return;
178 } else {
179 context->capability_response = *data;
180 complete(&context->response_event);
181 }
182
183 spin_unlock(&context->context_lock);
184
185 return;
186}
187
188/*
189 * define short names for the global vendor params
190 * used by hdd_extscan_nl_fill_bss()
191 */
192#define PARAM_TIME_STAMP \
193 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_TIME_STAMP
194#define PARAM_SSID \
195 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_SSID
196#define PARAM_BSSID \
197 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_BSSID
198#define PARAM_CHANNEL \
199 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_CHANNEL
200#define PARAM_RSSI \
201 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RSSI
202#define PARAM_RTT \
203 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RTT
204#define PARAM_RTT_SD \
205 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RTT_SD
206#define PARAM_BEACON_PERIOD \
207 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_BEACON_PERIOD
208#define PARAM_CAPABILITY \
209 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_CAPABILITY
210#define PARAM_IE_LENGTH \
211 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_IE_LENGTH
212#define PARAM_IE_DATA \
213 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_IE_DATA
214
215/** hdd_extscan_nl_fill_bss() - extscan nl fill bss
216 * @skb: socket buffer
217 * @ap: bss information
218 * @idx: nesting index
219 *
220 * Return: 0 on success; error number otherwise
221 */
222static int hdd_extscan_nl_fill_bss(struct sk_buff *skb, tSirWifiScanResult *ap,
223 int idx)
224{
225 struct nlattr *nla_ap;
226
227 nla_ap = nla_nest_start(skb, idx);
228 if (!nla_ap)
229 return -EINVAL;
230
231 if (nla_put_u64(skb, PARAM_TIME_STAMP, ap->ts) ||
232 nla_put(skb, PARAM_SSID, sizeof(ap->ssid), ap->ssid) ||
233 nla_put(skb, PARAM_BSSID, sizeof(ap->bssid), ap->bssid.bytes) ||
234 nla_put_u32(skb, PARAM_CHANNEL, ap->channel) ||
235 nla_put_s32(skb, PARAM_RSSI, ap->rssi) ||
236 nla_put_u32(skb, PARAM_RTT, ap->rtt) ||
237 nla_put_u32(skb, PARAM_RTT_SD, ap->rtt_sd) ||
238 nla_put_u16(skb, PARAM_BEACON_PERIOD, ap->beaconPeriod) ||
239 nla_put_u16(skb, PARAM_CAPABILITY, ap->capability) ||
240 nla_put_u16(skb, PARAM_IE_LENGTH, ap->ieLength)) {
241 hddLog(LOGE, FL("put fail"));
242 return -EINVAL;
243 }
244
245 if (ap->ieLength)
246 if (nla_put(skb, PARAM_IE_DATA, ap->ieLength, ap->ieData)) {
247 hddLog(LOGE, FL("put fail"));
248 return -EINVAL;
249 }
250
251 nla_nest_end(skb, nla_ap);
252
253 return 0;
254}
255/*
256 * done with short names for the global vendor params
257 * used by hdd_extscan_nl_fill_bss()
258 */
259#undef PARAM_TIME_STAMP
260#undef PARAM_SSID
261#undef PARAM_BSSID
262#undef PARAM_CHANNEL
263#undef PARAM_RSSI
264#undef PARAM_RTT
265#undef PARAM_RTT_SD
266#undef PARAM_BEACON_PERIOD
267#undef PARAM_CAPABILITY
268#undef PARAM_IE_LENGTH
269#undef PARAM_IE_DATA
270
271/** wlan_hdd_cfg80211_extscan_cached_results_ind() - get cached results
272 * @ctx: hdd global context
273 * @data: cached results
274 *
275 * This function reads the cached results %data, populated the NL
276 * attributes and sends the NL event to the upper layer.
277 *
278 * Return: none
279 */
280static void
281wlan_hdd_cfg80211_extscan_cached_results_ind(void *ctx,
282 struct extscan_cached_scan_results *data)
283{
284 hdd_context_t *pHddCtx = ctx;
285 struct sk_buff *skb = NULL;
286 struct hdd_ext_scan_context *context;
287 struct extscan_cached_scan_result *result;
288 tSirWifiScanResult *ap;
289 uint32_t i, j, nl_buf_len;
290 bool ignore_cached_results = false;
291
292 ENTER();
293
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530294 if (wlan_hdd_validate_context(pHddCtx))
295 return;
296 if (!data) {
297 hddLog(LOGE, FL("data is null"));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800298 return;
299 }
300
301 context = &ext_scan_context;
302 spin_lock(&context->context_lock);
303 ignore_cached_results = context->ignore_cached_results;
304 spin_unlock(&context->context_lock);
305
306 if (ignore_cached_results) {
307 hddLog(LOGE,
308 FL("Ignore the cached results received after timeout"));
309 return;
310 }
311
312#define EXTSCAN_CACHED_NEST_HDRLEN NLA_HDRLEN
313#define EXTSCAN_CACHED_NL_FIXED_TLV \
314 ((sizeof(data->request_id) + NLA_HDRLEN) + \
315 (sizeof(data->num_scan_ids) + NLA_HDRLEN) + \
316 (sizeof(data->more_data) + NLA_HDRLEN))
317#define EXTSCAN_CACHED_NL_SCAN_ID_TLV \
318 ((sizeof(result->scan_id) + NLA_HDRLEN) + \
319 (sizeof(result->flags) + NLA_HDRLEN) + \
320 (sizeof(result->num_results) + NLA_HDRLEN))
321#define EXTSCAN_CACHED_NL_SCAN_RESULTS_TLV \
322 ((sizeof(ap->ts) + NLA_HDRLEN) + \
323 (sizeof(ap->ssid) + NLA_HDRLEN) + \
324 (sizeof(ap->bssid) + NLA_HDRLEN) + \
325 (sizeof(ap->channel) + NLA_HDRLEN) + \
326 (sizeof(ap->rssi) + NLA_HDRLEN) + \
327 (sizeof(ap->rtt) + NLA_HDRLEN) + \
328 (sizeof(ap->rtt_sd) + NLA_HDRLEN) + \
329 (sizeof(ap->beaconPeriod) + NLA_HDRLEN) + \
330 (sizeof(ap->capability) + NLA_HDRLEN) + \
331 (sizeof(ap->ieLength) + NLA_HDRLEN))
332#define EXTSCAN_CACHED_NL_SCAN_RESULTS_IE_DATA_TLV \
333 (ap->ieLength + NLA_HDRLEN)
334
335 nl_buf_len = NLMSG_HDRLEN;
336 nl_buf_len += EXTSCAN_CACHED_NL_FIXED_TLV;
337 if (data->num_scan_ids) {
338 nl_buf_len += sizeof(result->scan_id) + NLA_HDRLEN;
339 nl_buf_len += EXTSCAN_CACHED_NEST_HDRLEN;
340 result = &data->result[0];
341 for (i = 0; i < data->num_scan_ids; i++) {
342 nl_buf_len += EXTSCAN_CACHED_NEST_HDRLEN;
343 nl_buf_len += EXTSCAN_CACHED_NL_SCAN_ID_TLV;
344 nl_buf_len += EXTSCAN_CACHED_NEST_HDRLEN;
345
346 ap = &result->ap[0];
347 for (j = 0; j < result->num_results; j++) {
348 nl_buf_len += EXTSCAN_CACHED_NEST_HDRLEN;
349 nl_buf_len +=
350 EXTSCAN_CACHED_NL_SCAN_RESULTS_TLV;
351 if (ap->ieLength)
352 nl_buf_len +=
353 EXTSCAN_CACHED_NL_SCAN_RESULTS_IE_DATA_TLV;
354 ap++;
355 }
356 result++;
357 }
358 }
359
360 hddLog(LOG1, FL("nl_buf_len = %u"), nl_buf_len);
361 skb = cfg80211_vendor_cmd_alloc_reply_skb(pHddCtx->wiphy, nl_buf_len);
362
363 if (!skb) {
364 hddLog(LOGE, FL("cfg80211_vendor_cmd_alloc_reply_skb failed"));
365 goto fail;
366 }
367 hddLog(LOG1, "Req Id %u Num_scan_ids %u More Data %u",
368 data->request_id, data->num_scan_ids, data->more_data);
369
370 result = &data->result[0];
371 for (i = 0; i < data->num_scan_ids; i++) {
372 hddLog(LOG1, "[i=%d] scan_id %u flags %u num_results %u",
373 i, result->scan_id, result->flags, result->num_results);
374
375 ap = &result->ap[0];
376 for (j = 0; j < result->num_results; j++) {
377 /*
378 * Firmware returns timestamp from ext scan start till
379 * BSSID was cached (in micro seconds). Add this with
380 * time gap between system boot up to ext scan start
381 * to derive the time since boot when the
382 * BSSID was cached.
383 */
384 ap->ts += pHddCtx->ext_scan_start_since_boot;
385 hddLog(LOG1, "Timestamp %llu "
386 "Ssid: %s "
387 "Bssid (" MAC_ADDRESS_STR ") "
388 "Channel %u "
389 "Rssi %d "
390 "RTT %u "
391 "RTT_SD %u "
392 "Beacon Period %u "
393 "Capability 0x%x "
394 "Ie length %d",
395 ap->ts,
396 ap->ssid,
397 MAC_ADDR_ARRAY(ap->bssid.bytes),
398 ap->channel,
399 ap->rssi,
400 ap->rtt,
401 ap->rtt_sd,
402 ap->beaconPeriod,
403 ap->capability,
404 ap->ieLength);
405 ap++;
406 }
407 result++;
408 }
409
410 if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID,
411 data->request_id) ||
412 nla_put_u32(skb,
413 QCA_WLAN_VENDOR_ATTR_EXTSCAN_NUM_RESULTS_AVAILABLE,
414 data->num_scan_ids) ||
415 nla_put_u8(skb,
416 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_MORE_DATA,
417 data->more_data)) {
418 hddLog(LOGE, FL("put fail"));
419 goto fail;
420 }
421
422 if (data->num_scan_ids) {
423 struct nlattr *nla_results;
424 result = &data->result[0];
425
426 if (nla_put_u32(skb,
427 QCA_WLAN_VENDOR_ATTR_EXTSCAN_CACHED_RESULTS_SCAN_ID,
428 result->scan_id)) {
429 hddLog(LOGE, FL("put fail"));
430 goto fail;
431 }
432 nla_results = nla_nest_start(skb,
433 QCA_WLAN_VENDOR_ATTR_EXTSCAN_CACHED_RESULTS_LIST);
434 if (!nla_results)
435 goto fail;
436
437 for (i = 0; i < data->num_scan_ids; i++) {
438 struct nlattr *nla_result;
439 struct nlattr *nla_aps;
440
441 nla_result = nla_nest_start(skb, i);
442 if (!nla_result)
443 goto fail;
444
445 if (nla_put_u32(skb,
446 QCA_WLAN_VENDOR_ATTR_EXTSCAN_CACHED_RESULTS_SCAN_ID,
447 result->scan_id) ||
448 nla_put_u32(skb,
449 QCA_WLAN_VENDOR_ATTR_EXTSCAN_CACHED_RESULTS_FLAGS,
450 result->flags) ||
451 nla_put_u32(skb,
452 QCA_WLAN_VENDOR_ATTR_EXTSCAN_NUM_RESULTS_AVAILABLE,
453 result->num_results)) {
454 hddLog(LOGE, FL("put fail"));
455 goto fail;
456 }
457
458 nla_aps = nla_nest_start(skb,
459 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_LIST);
460 if (!nla_aps)
461 goto fail;
462
463 ap = &result->ap[0];
464 for (j = 0; j < result->num_results; j++) {
465 if (hdd_extscan_nl_fill_bss(skb, ap, j))
466 goto fail;
467
468 ap++;
469 }
470 nla_nest_end(skb, nla_aps);
471 nla_nest_end(skb, nla_result);
472 result++;
473 }
474 nla_nest_end(skb, nla_results);
475 }
476
477 cfg80211_vendor_cmd_reply(skb);
478
479 if (!data->more_data) {
480 spin_lock(&context->context_lock);
481 context->response_status = 0;
482 complete(&context->response_event);
483 spin_unlock(&context->context_lock);
484 }
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530485 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800486 return;
487
488fail:
489 if (skb)
490 kfree_skb(skb);
491
492 spin_lock(&context->context_lock);
493 context->response_status = -EINVAL;
494 spin_unlock(&context->context_lock);
495
496 return;
497}
498
499/**
500 * wlan_hdd_cfg80211_extscan_hotlist_match_ind() - hot list match ind
501 * @ctx: Pointer to hdd context
502 * @pData: Pointer to ext scan result event
503 *
Srinivas Girigowdafe3e5b32015-11-23 11:56:36 -0800504 * This callback execute in atomic context and must not invoke any
505 * blocking calls.
506 *
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800507 * Return: none
508 */
509static void
510wlan_hdd_cfg80211_extscan_hotlist_match_ind(void *ctx,
511 struct extscan_hotlist_match *data)
512{
513 hdd_context_t *pHddCtx = ctx;
514 struct sk_buff *skb = NULL;
515 uint32_t i, index;
Srinivas Girigowdafe3e5b32015-11-23 11:56:36 -0800516 int flags = cds_get_gfp_flags();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800517
518 ENTER();
519
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530520 if (wlan_hdd_validate_context(pHddCtx))
521 return;
522 if (!data) {
523 hddLog(LOGE, FL("data is null"));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800524 return;
525 }
526
527 if (data->ap_found)
528 index = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_AP_FOUND_INDEX;
529 else
530 index = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_AP_LOST_INDEX;
531
532 skb = cfg80211_vendor_event_alloc(
533 pHddCtx->wiphy,
534 NULL,
535 EXTSCAN_EVENT_BUF_SIZE + NLMSG_HDRLEN,
Srinivas Girigowdafe3e5b32015-11-23 11:56:36 -0800536 index, flags);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800537
538 if (!skb) {
539 hddLog(LOGE, FL("cfg80211_vendor_event_alloc failed"));
540 return;
541 }
542 hdd_info("Req Id: %u Num_APs: %u MoreData: %u ap_found: %u",
543 data->requestId, data->numOfAps, data->moreData,
544 data->ap_found);
545
546 for (i = 0; i < data->numOfAps; i++) {
Anurag Chouhan50220ce2016-02-18 20:11:33 +0530547 data->ap[i].ts = qdf_get_monotonic_boottime();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800548
549 hddLog(LOG1, "[i=%d] Timestamp %llu "
550 "Ssid: %s "
551 "Bssid (" MAC_ADDRESS_STR ") "
552 "Channel %u "
553 "Rssi %d "
554 "RTT %u "
555 "RTT_SD %u",
556 i,
557 data->ap[i].ts,
558 data->ap[i].ssid,
559 MAC_ADDR_ARRAY(data->ap[i].bssid.bytes),
560 data->ap[i].channel,
561 data->ap[i].rssi,
562 data->ap[i].rtt, data->ap[i].rtt_sd);
563 }
564
565 if (nla_put_u32(skb,
566 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID,
567 data->requestId) ||
568 nla_put_u32(skb,
569 QCA_WLAN_VENDOR_ATTR_EXTSCAN_NUM_RESULTS_AVAILABLE,
570 data->numOfAps)) {
571 hddLog(LOGE, FL("put fail"));
572 goto fail;
573 }
574
575 if (data->numOfAps) {
576 struct nlattr *aps;
577
578 aps = nla_nest_start(skb,
579 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_LIST);
580 if (!aps)
581 goto fail;
582
583 for (i = 0; i < data->numOfAps; i++) {
584 struct nlattr *ap;
585
586 ap = nla_nest_start(skb, i);
587 if (!ap)
588 goto fail;
589
590 if (nla_put_u64(skb,
591 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_TIME_STAMP,
592 data->ap[i].ts) ||
593 nla_put(skb,
594 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_SSID,
595 sizeof(data->ap[i].ssid),
596 data->ap[i].ssid) ||
597 nla_put(skb,
598 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_BSSID,
599 sizeof(data->ap[i].bssid),
600 data->ap[i].bssid.bytes) ||
601 nla_put_u32(skb,
602 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_CHANNEL,
603 data->ap[i].channel) ||
604 nla_put_s32(skb,
605 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RSSI,
606 data->ap[i].rssi) ||
607 nla_put_u32(skb,
608 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RTT,
609 data->ap[i].rtt) ||
610 nla_put_u32(skb,
611 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RTT_SD,
612 data->ap[i].rtt_sd))
613 goto fail;
614
615 nla_nest_end(skb, ap);
616 }
617 nla_nest_end(skb, aps);
618
619 if (nla_put_u8(skb,
620 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_MORE_DATA,
621 data->moreData))
622 goto fail;
623 }
624
Srinivas Girigowdafe3e5b32015-11-23 11:56:36 -0800625 cfg80211_vendor_event(skb, flags);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530626 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800627 return;
628
629fail:
630 kfree_skb(skb);
631 return;
632}
633
634/**
635 * wlan_hdd_cfg80211_extscan_signif_wifi_change_results_ind() -
636 * significant wifi change results indication
637 * @ctx: Pointer to hdd context
638 * @pData: Pointer to signif wifi change event
639 *
Srinivas Girigowdafe3e5b32015-11-23 11:56:36 -0800640 * This callback execute in atomic context and must not invoke any
641 * blocking calls.
642 *
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800643 * Return: none
644 */
645static void
646wlan_hdd_cfg80211_extscan_signif_wifi_change_results_ind(
647 void *ctx,
648 tpSirWifiSignificantChangeEvent pData)
649{
650 hdd_context_t *pHddCtx = (hdd_context_t *) ctx;
651 struct sk_buff *skb = NULL;
652 tSirWifiSignificantChange *ap_info;
653 int32_t *rssi;
654 uint32_t i, j;
Srinivas Girigowdafe3e5b32015-11-23 11:56:36 -0800655 int flags = cds_get_gfp_flags();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800656
657 ENTER();
658
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530659 if (wlan_hdd_validate_context(pHddCtx))
660 return;
661 if (!pData) {
662 hddLog(LOGE, FL("pData is null"));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800663 return;
664 }
665
666 skb = cfg80211_vendor_event_alloc(
667 pHddCtx->wiphy,
668 NULL,
669 EXTSCAN_EVENT_BUF_SIZE + NLMSG_HDRLEN,
670 QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SIGNIFICANT_CHANGE_INDEX,
Srinivas Girigowdafe3e5b32015-11-23 11:56:36 -0800671 flags);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800672
673 if (!skb) {
674 hddLog(LOGE, FL("cfg80211_vendor_event_alloc failed"));
675 return;
676 }
677 hddLog(LOG1, "Req Id %u Num results %u More Data %u",
678 pData->requestId, pData->numResults, pData->moreData);
679
680 ap_info = &pData->ap[0];
681 for (i = 0; i < pData->numResults; i++) {
682 hddLog(LOG1, "[i=%d] "
683 "Bssid (" MAC_ADDRESS_STR ") "
684 "Channel %u "
685 "numOfRssi %d",
686 i,
687 MAC_ADDR_ARRAY(ap_info->bssid.bytes),
688 ap_info->channel, ap_info->numOfRssi);
689 rssi = &(ap_info)->rssi[0];
690 for (j = 0; j < ap_info->numOfRssi; j++)
691 hddLog(LOG1, "Rssi %d", *rssi++);
692
693 ap_info += ap_info->numOfRssi * sizeof(*rssi);
694 }
695
696 if (nla_put_u32(skb,
697 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID,
698 pData->requestId) ||
699 nla_put_u32(skb,
700 QCA_WLAN_VENDOR_ATTR_EXTSCAN_NUM_RESULTS_AVAILABLE,
701 pData->numResults)) {
702 hddLog(LOGE, FL("put fail"));
703 goto fail;
704 }
705
706 if (pData->numResults) {
707 struct nlattr *aps;
708
709 aps = nla_nest_start(skb,
710 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_LIST);
711 if (!aps)
712 goto fail;
713
714 ap_info = &pData->ap[0];
715 for (i = 0; i < pData->numResults; i++) {
716 struct nlattr *ap;
717
718 ap = nla_nest_start(skb, i);
719 if (!ap)
720 goto fail;
721
722 if (nla_put(skb,
723 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_BSSID,
Anurag Chouhan6d760662016-02-20 16:05:43 +0530724 QDF_MAC_ADDR_SIZE, ap_info->bssid.bytes) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800725 nla_put_u32(skb,
726 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_CHANNEL,
727 ap_info->channel) ||
728 nla_put_u32(skb,
729 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_NUM_RSSI,
730 ap_info->numOfRssi) ||
731 nla_put(skb,
732 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_RSSI_LIST,
733 sizeof(s32) * ap_info->numOfRssi,
734 &(ap_info)->rssi[0]))
735 goto fail;
736
737 nla_nest_end(skb, ap);
738
739 ap_info += ap_info->numOfRssi * sizeof(*rssi);
740 }
741 nla_nest_end(skb, aps);
742
743 if (nla_put_u8(skb,
744 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_MORE_DATA,
745 pData->moreData))
746 goto fail;
747 }
748
Srinivas Girigowdafe3e5b32015-11-23 11:56:36 -0800749 cfg80211_vendor_event(skb, flags);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800750 return;
751
752fail:
753 kfree_skb(skb);
754 return;
755
756}
757
758/**
759 * wlan_hdd_cfg80211_extscan_full_scan_result_event() - full scan result event
760 * @ctx: Pointer to hdd context
761 * @pData: Pointer to full scan result event
762 *
Srinivas Girigowdafe3e5b32015-11-23 11:56:36 -0800763 * This callback execute in atomic context and must not invoke any
764 * blocking calls.
765 *
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800766 * Return: none
767 */
768static void
769wlan_hdd_cfg80211_extscan_full_scan_result_event(void *ctx,
770 tpSirWifiFullScanResultEvent
771 pData)
772{
773 hdd_context_t *pHddCtx = (hdd_context_t *) ctx;
774 struct sk_buff *skb = NULL;
775#ifdef CONFIG_CNSS
776 struct timespec ts;
777#endif
Srinivas Girigowdafe3e5b32015-11-23 11:56:36 -0800778 int flags = cds_get_gfp_flags();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800779
780 ENTER();
781
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530782 if (wlan_hdd_validate_context(pHddCtx))
783 return;
784 if (!pData) {
785 hddLog(LOGE, FL("pData is null"));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800786 return;
787 }
788
789 if ((sizeof(*pData) + pData->ap.ieLength) >= EXTSCAN_EVENT_BUF_SIZE) {
790 hddLog(LOGE,
791 FL("Frame exceeded NL size limitation, drop it!!"));
792 return;
793 }
794 skb = cfg80211_vendor_event_alloc(
795 pHddCtx->wiphy,
796 NULL,
797 EXTSCAN_EVENT_BUF_SIZE + NLMSG_HDRLEN,
798 QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_FULL_SCAN_RESULT_INDEX,
Srinivas Girigowdafe3e5b32015-11-23 11:56:36 -0800799 flags);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800800
801 if (!skb) {
802 hddLog(LOGE, FL("cfg80211_vendor_event_alloc failed"));
803 return;
804 }
805
806 pData->ap.channel = cds_chan_to_freq(pData->ap.channel);
807#ifdef CONFIG_CNSS
808 /* Android does not want the time stamp from the frame.
809 Instead it wants a monotonic increasing value since boot */
810 cnss_get_monotonic_boottime(&ts);
811 pData->ap.ts = ((u64)ts.tv_sec * 1000000) + (ts.tv_nsec / 1000);
812#endif
813 hddLog(LOG1, "Req Id %u More Data %u", pData->requestId,
814 pData->moreData);
815 hddLog(LOG1, "AP Info: Timestamp %llu Ssid: %s "
816 "Bssid (" MAC_ADDRESS_STR ") "
817 "Channel %u "
818 "Rssi %d "
819 "RTT %u "
820 "RTT_SD %u "
821 "Bcn Period %d "
822 "Capability 0x%X "
823 "IE Length %d",
824 pData->ap.ts,
825 pData->ap.ssid,
826 MAC_ADDR_ARRAY(pData->ap.bssid.bytes),
827 pData->ap.channel,
828 pData->ap.rssi,
829 pData->ap.rtt,
830 pData->ap.rtt_sd,
831 pData->ap.beaconPeriod,
832 pData->ap.capability, pData->ap.ieLength);
833
834 if (nla_put_u32(skb,
835 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID,
836 pData->requestId) ||
837 nla_put_u64(skb,
838 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_TIME_STAMP,
839 pData->ap.ts) ||
840 nla_put(skb,
841 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_SSID,
842 sizeof(pData->ap.ssid),
843 pData->ap.ssid) ||
844 nla_put(skb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_BSSID,
845 sizeof(pData->ap.bssid),
846 pData->ap.bssid.bytes) ||
847 nla_put_u32(skb,
848 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_CHANNEL,
849 pData->ap.channel) ||
850 nla_put_s32(skb,
851 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RSSI,
852 pData->ap.rssi) ||
853 nla_put_u32(skb,
854 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RTT,
855 pData->ap.rtt) ||
856 nla_put_u32(skb,
857 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RTT_SD,
858 pData->ap.rtt_sd) ||
859 nla_put_u16(skb,
860 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_BEACON_PERIOD,
861 pData->ap.beaconPeriod) ||
862 nla_put_u16(skb,
863 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_CAPABILITY,
864 pData->ap.capability) ||
865 nla_put_u32(skb,
866 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_IE_LENGTH,
867 pData->ap.ieLength) ||
868 nla_put_u8(skb,
869 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_MORE_DATA,
870 pData->moreData)) {
871 hddLog(LOGE, FL("nla put fail"));
872 goto nla_put_failure;
873 }
874
875 if (pData->ap.ieLength) {
876 if (nla_put(skb,
877 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_IE_DATA,
878 pData->ap.ieLength, pData->ap.ieData))
879 goto nla_put_failure;
880 }
881
Srinivas Girigowdafe3e5b32015-11-23 11:56:36 -0800882 cfg80211_vendor_event(skb, flags);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530883 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800884 return;
885
886nla_put_failure:
887 kfree_skb(skb);
888 return;
889}
890
891/**
892 * wlan_hdd_cfg80211_extscan_scan_res_available_event() - scan result event
893 * @ctx: Pointer to hdd context
894 * @pData: Pointer to scan results available indication param
895 *
Srinivas Girigowdafe3e5b32015-11-23 11:56:36 -0800896 * This callback execute in atomic context and must not invoke any
897 * blocking calls.
898 *
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800899 * Return: none
900 */
901static void
902wlan_hdd_cfg80211_extscan_scan_res_available_event(
903 void *ctx,
904 tpSirExtScanResultsAvailableIndParams pData)
905{
906 hdd_context_t *pHddCtx = (hdd_context_t *) ctx;
907 struct sk_buff *skb = NULL;
Srinivas Girigowdafe3e5b32015-11-23 11:56:36 -0800908 int flags = cds_get_gfp_flags();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800909
910 ENTER();
911
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530912 if (wlan_hdd_validate_context(pHddCtx))
913 return;
914 if (!pData) {
915 hddLog(LOGE, FL("pData is null"));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800916 return;
917 }
918
919 skb = cfg80211_vendor_event_alloc(
920 pHddCtx->wiphy,
921 NULL,
922 EXTSCAN_EVENT_BUF_SIZE + NLMSG_HDRLEN,
923 QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SCAN_RESULTS_AVAILABLE_INDEX,
Srinivas Girigowdafe3e5b32015-11-23 11:56:36 -0800924 flags);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800925
926 if (!skb) {
927 hddLog(LOGE, FL("cfg80211_vendor_event_alloc failed"));
928 return;
929 }
930
931 hddLog(LOG1, "Req Id %u Num results %u",
932 pData->requestId, pData->numResultsAvailable);
933 if (nla_put_u32(skb,
934 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID,
935 pData->requestId) ||
936 nla_put_u32(skb,
937 QCA_WLAN_VENDOR_ATTR_EXTSCAN_NUM_RESULTS_AVAILABLE,
938 pData->numResultsAvailable)) {
939 hddLog(LOGE, FL("nla put fail"));
940 goto nla_put_failure;
941 }
942
Srinivas Girigowdafe3e5b32015-11-23 11:56:36 -0800943 cfg80211_vendor_event(skb, flags);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530944 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800945 return;
946
947nla_put_failure:
948 kfree_skb(skb);
949 return;
950}
951
952/**
953 * wlan_hdd_cfg80211_extscan_scan_progress_event() - scan progress event
954 * @ctx: Pointer to hdd context
955 * @pData: Pointer to scan event indication param
956 *
Srinivas Girigowdafe3e5b32015-11-23 11:56:36 -0800957 * This callback execute in atomic context and must not invoke any
958 * blocking calls.
959 *
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800960 * Return: none
961 */
962static void
963wlan_hdd_cfg80211_extscan_scan_progress_event(void *ctx,
964 tpSirExtScanOnScanEventIndParams
965 pData)
966{
967 hdd_context_t *pHddCtx = (hdd_context_t *) ctx;
968 struct sk_buff *skb = NULL;
Srinivas Girigowdafe3e5b32015-11-23 11:56:36 -0800969 int flags = cds_get_gfp_flags();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800970
971 ENTER();
972
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530973 if (wlan_hdd_validate_context(pHddCtx))
974 return;
975 if (!pData) {
976 hddLog(LOGE, FL("pData is null"));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800977 return;
978 }
979
980 skb = cfg80211_vendor_event_alloc(
981 pHddCtx->wiphy,
982 NULL,
983 EXTSCAN_EVENT_BUF_SIZE + NLMSG_HDRLEN,
984 QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SCAN_EVENT_INDEX,
Srinivas Girigowdafe3e5b32015-11-23 11:56:36 -0800985 flags);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800986
987 if (!skb) {
988 hddLog(LOGE, FL("cfg80211_vendor_event_alloc failed"));
989 return;
990 }
991 hddLog(LOG1, "Req Id %u Scan event type %u Scan event status %u",
992 pData->requestId, pData->scanEventType, pData->status);
993
994 if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID,
995 pData->requestId) ||
996 nla_put_u8(skb,
997 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_EVENT_TYPE,
998 pData->scanEventType) ||
999 nla_put_u32(skb,
1000 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_EVENT_STATUS,
1001 pData->status)) {
1002 hddLog(LOGE, FL("nla put fail"));
1003 goto nla_put_failure;
1004 }
1005
Srinivas Girigowdafe3e5b32015-11-23 11:56:36 -08001006 cfg80211_vendor_event(skb, flags);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301007 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001008 return;
1009
1010nla_put_failure:
1011 kfree_skb(skb);
1012 return;
1013}
1014
1015/**
1016 * wlan_hdd_cfg80211_extscan_epno_match_found() - pno match found
1017 * @hddctx: HDD context
1018 * @data: matched network data
1019 *
1020 * This function reads the matched network data and fills NL vendor attributes
1021 * and send it to upper layer.
Srinivas Girigowdafe3e5b32015-11-23 11:56:36 -08001022 * This callback execute in atomic context and must not invoke any
1023 * blocking calls.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001024 *
1025 * Return: 0 on success, error number otherwise
1026 */
1027static void
1028wlan_hdd_cfg80211_extscan_epno_match_found(void *ctx,
1029 struct pno_match_found *data)
1030{
1031 hdd_context_t *pHddCtx = (hdd_context_t *)ctx;
1032 struct sk_buff *skb = NULL;
1033 uint32_t len, i;
Srinivas Girigowdafe3e5b32015-11-23 11:56:36 -08001034 int flags = cds_get_gfp_flags();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001035
1036 ENTER();
1037
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301038 if (wlan_hdd_validate_context(pHddCtx))
1039 return;
1040 if (!data) {
1041 hddLog(LOGE, FL("data is null"));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001042 return;
1043 }
1044
1045 /*
1046 * If the number of match found APs including IE data exceeds NL 4K size
1047 * limitation, drop that beacon/probe rsp frame.
1048 */
1049 len = sizeof(*data) +
1050 (data->num_results + sizeof(tSirWifiScanResult));
1051 for (i = 0; i < data->num_results; i++)
1052 len += data->ap[i].ieLength;
1053
1054 if (len >= EXTSCAN_EVENT_BUF_SIZE) {
1055 hddLog(LOGE, FL("Frame exceeded NL size limitation, drop it!"));
1056 return;
1057 }
1058
1059 skb = cfg80211_vendor_event_alloc(pHddCtx->wiphy,
1060 NULL,
1061 EXTSCAN_EVENT_BUF_SIZE + NLMSG_HDRLEN,
1062 QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_NETWORK_FOUND_INDEX,
Srinivas Girigowdafe3e5b32015-11-23 11:56:36 -08001063 flags);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001064
1065 if (!skb) {
1066 hddLog(LOGE, FL("cfg80211_vendor_event_alloc failed"));
1067 return;
1068 }
1069
1070 hddLog(LOG1, "Req Id %u More Data %u num_results %d",
1071 data->request_id, data->more_data, data->num_results);
1072 for (i = 0; i < data->num_results; i++) {
1073 data->ap[i].channel = cds_chan_to_freq(data->ap[i].channel);
1074 hddLog(LOG1, "AP Info: Timestamp %llu) Ssid: %s "
1075 "Bssid (" MAC_ADDRESS_STR ") "
1076 "Channel %u "
1077 "Rssi %d "
1078 "RTT %u "
1079 "RTT_SD %u "
1080 "Bcn Period %d "
1081 "Capability 0x%X "
1082 "IE Length %d",
1083 data->ap[i].ts,
1084 data->ap[i].ssid,
1085 MAC_ADDR_ARRAY(data->ap[i].bssid.bytes),
1086 data->ap[i].channel,
1087 data->ap[i].rssi,
1088 data->ap[i].rtt,
1089 data->ap[i].rtt_sd,
1090 data->ap[i].beaconPeriod,
1091 data->ap[i].capability,
1092 data->ap[i].ieLength);
1093 }
1094
1095 if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID,
1096 data->request_id) ||
1097 nla_put_u32(skb,
1098 QCA_WLAN_VENDOR_ATTR_EXTSCAN_NUM_RESULTS_AVAILABLE,
1099 data->num_results) ||
1100 nla_put_u8(skb,
1101 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_MORE_DATA,
1102 data->more_data)) {
1103 hddLog(LOGE, FL("nla put fail"));
1104 goto fail;
1105 }
1106
1107 if (data->num_results) {
1108 struct nlattr *nla_aps;
1109 nla_aps = nla_nest_start(skb,
1110 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_LIST);
1111 if (!nla_aps)
1112 goto fail;
1113
1114 for (i = 0; i < data->num_results; i++) {
1115 if (hdd_extscan_nl_fill_bss(skb, &data->ap[i], i))
1116 goto fail;
1117 }
1118 nla_nest_end(skb, nla_aps);
1119 }
1120
Srinivas Girigowdafe3e5b32015-11-23 11:56:36 -08001121 cfg80211_vendor_event(skb, flags);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001122 return;
1123
1124fail:
1125 kfree_skb(skb);
1126 return;
1127}
1128
1129/**
1130 * wlan_hdd_cfg80211_passpoint_match_found() - passpoint match found
1131 * @hddctx: HDD context
1132 * @data: matched network data
1133 *
1134 * This function reads the match network %data and fill in the skb with
1135 * NL attributes and send up the NL event
Srinivas Girigowdafe3e5b32015-11-23 11:56:36 -08001136 * This callback execute in atomic context and must not invoke any
1137 * blocking calls.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001138 *
1139 * Return: none
1140 */
1141static void
1142wlan_hdd_cfg80211_passpoint_match_found(void *ctx,
1143 struct wifi_passpoint_match *data)
1144{
1145 hdd_context_t *pHddCtx = ctx;
1146 struct sk_buff *skb = NULL;
1147 uint32_t len, i, num_matches = 1, more_data = 0;
Srinivas Girigowdafe3e5b32015-11-23 11:56:36 -08001148 struct nlattr *nla_aps, *nla_bss;
1149 int flags = cds_get_gfp_flags();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001150
1151 ENTER();
1152
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301153 if (wlan_hdd_validate_context(pHddCtx))
1154 return;
1155 if (!data) {
1156 hddLog(LOGE, FL("data is null"));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001157 return;
1158 }
1159
1160 len = sizeof(*data) + data->ap.ieLength + data->anqp_len;
1161 if (len >= EXTSCAN_EVENT_BUF_SIZE) {
1162 hddLog(LOGE, FL("Result exceeded NL size limitation, drop it"));
1163 return;
1164 }
1165
1166 skb = cfg80211_vendor_event_alloc(pHddCtx->wiphy,
1167 NULL,
1168 EXTSCAN_EVENT_BUF_SIZE + NLMSG_HDRLEN,
1169 QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_PASSPOINT_NETWORK_FOUND_INDEX,
Srinivas Girigowdafe3e5b32015-11-23 11:56:36 -08001170 flags);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001171
1172 if (!skb) {
1173 hddLog(LOGE, FL("cfg80211_vendor_event_alloc failed"));
1174 return;
1175 }
1176
1177 hddLog(LOG1, "Req Id %u Id %u ANQP length %u num_matches %u",
1178 data->request_id, data->id, data->anqp_len, num_matches);
1179 for (i = 0; i < num_matches; i++) {
1180 hddLog(LOG1, "AP Info: Timestamp %llu Ssid: %s "
1181 "Bssid (" MAC_ADDRESS_STR ") "
1182 "Channel %u "
1183 "Rssi %d "
1184 "RTT %u "
1185 "RTT_SD %u "
1186 "Bcn Period %d "
1187 "Capability 0x%X "
1188 "IE Length %d",
1189 data->ap.ts,
1190 data->ap.ssid,
1191 MAC_ADDR_ARRAY(data->ap.bssid.bytes),
1192 data->ap.channel,
1193 data->ap.rssi,
1194 data->ap.rtt,
1195 data->ap.rtt_sd,
1196 data->ap.beaconPeriod,
1197 data->ap.capability,
1198 data->ap.ieLength);
1199 }
1200
1201 if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID,
1202 data->request_id) ||
1203 nla_put_u32(skb,
1204 QCA_WLAN_VENDOR_ATTR_EXTSCAN_PNO_RESULTS_PASSPOINT_NETWORK_FOUND_NUM_MATCHES,
1205 num_matches) ||
1206 nla_put_u8(skb,
1207 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_MORE_DATA,
1208 more_data)) {
1209 hddLog(LOGE, FL("nla put fail"));
1210 goto fail;
1211 }
1212
1213 nla_aps = nla_nest_start(skb,
1214 QCA_WLAN_VENDOR_ATTR_EXTSCAN_PNO_RESULTS_PASSPOINT_MATCH_RESULT_LIST);
1215 if (!nla_aps)
1216 goto fail;
1217
1218 for (i = 0; i < num_matches; i++) {
1219 struct nlattr *nla_ap;
1220
1221 nla_ap = nla_nest_start(skb, i);
1222 if (!nla_ap)
1223 goto fail;
1224
1225 if (nla_put_u32(skb,
1226 QCA_WLAN_VENDOR_ATTR_EXTSCAN_PNO_RESULTS_PASSPOINT_MATCH_ID,
1227 data->id) ||
1228 nla_put_u32(skb,
1229 QCA_WLAN_VENDOR_ATTR_EXTSCAN_PNO_RESULTS_PASSPOINT_MATCH_ANQP_LEN,
1230 data->anqp_len)) {
1231 goto fail;
1232 }
1233
1234 if (data->anqp_len)
1235 if (nla_put(skb,
1236 QCA_WLAN_VENDOR_ATTR_EXTSCAN_PNO_RESULTS_PASSPOINT_MATCH_ANQP,
1237 data->anqp_len, data->anqp))
1238 goto fail;
1239
1240 nla_bss = nla_nest_start(skb,
1241 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_LIST);
1242 if (!nla_bss)
1243 goto fail;
1244
1245 if (hdd_extscan_nl_fill_bss(skb, &data->ap, 0))
1246 goto fail;
1247
1248 nla_nest_end(skb, nla_bss);
1249 nla_nest_end(skb, nla_ap);
1250 }
1251 nla_nest_end(skb, nla_aps);
1252
Srinivas Girigowdafe3e5b32015-11-23 11:56:36 -08001253 cfg80211_vendor_event(skb, flags);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001254 return;
1255
1256fail:
1257 kfree_skb(skb);
1258 return;
1259}
1260
1261/**
1262 * wlan_hdd_cfg80211_extscan_hotlist_ssid_match_ind() -
1263 * Handle an SSID hotlist match event
1264 * @ctx: HDD context registered with SME
1265 * @event: The SSID hotlist match event
1266 *
1267 * This function will take an SSID match event that was generated by
1268 * firmware and will convert it into a cfg80211 vendor event which is
1269 * sent to userspace.
Srinivas Girigowdafe3e5b32015-11-23 11:56:36 -08001270 * This callback execute in atomic context and must not invoke any
1271 * blocking calls.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001272 *
1273 * Return: none
1274 */
1275static void
1276wlan_hdd_cfg80211_extscan_hotlist_ssid_match_ind(void *ctx,
1277 tpSirWifiScanResultEvent event)
1278{
1279 hdd_context_t *hdd_ctx = ctx;
1280 struct sk_buff *skb;
1281 uint32_t i, index;
Srinivas Girigowdafe3e5b32015-11-23 11:56:36 -08001282 int flags = cds_get_gfp_flags();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001283
1284 ENTER();
1285
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301286 if (wlan_hdd_validate_context(hdd_ctx))
1287 return;
1288 if (!event) {
1289 hddLog(LOGE, FL("event is null"));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001290 return;
1291 }
1292
1293 if (event->ap_found) {
1294 index = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_SSID_FOUND_INDEX;
1295 hddLog(LOG1, "SSID hotlist found");
1296 } else {
1297 index = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_SSID_LOST_INDEX;
1298 hddLog(LOG1, "SSID hotlist lost");
1299 }
1300
1301 skb = cfg80211_vendor_event_alloc(hdd_ctx->wiphy,
1302 NULL,
1303 EXTSCAN_EVENT_BUF_SIZE + NLMSG_HDRLEN,
Srinivas Girigowdafe3e5b32015-11-23 11:56:36 -08001304 index, flags);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001305
1306 if (!skb) {
1307 hddLog(LOGE, FL("cfg80211_vendor_event_alloc failed"));
1308 return;
1309 }
1310 hddLog(LOG1, "Req Id %u, Num results %u, More Data %u",
1311 event->requestId, event->numOfAps, event->moreData);
1312
1313 for (i = 0; i < event->numOfAps; i++) {
1314 hddLog(LOG1, "[i=%d] Timestamp %llu "
1315 "Ssid: %s "
1316 "Bssid (" MAC_ADDRESS_STR ") "
1317 "Channel %u "
1318 "Rssi %d "
1319 "RTT %u "
1320 "RTT_SD %u",
1321 i,
1322 event->ap[i].ts,
1323 event->ap[i].ssid,
1324 MAC_ADDR_ARRAY(event->ap[i].bssid.bytes),
1325 event->ap[i].channel,
1326 event->ap[i].rssi,
1327 event->ap[i].rtt,
1328 event->ap[i].rtt_sd);
1329 }
1330
1331 if (nla_put_u32(skb,
1332 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID,
1333 event->requestId) ||
1334 nla_put_u32(skb,
1335 QCA_WLAN_VENDOR_ATTR_EXTSCAN_NUM_RESULTS_AVAILABLE,
1336 event->numOfAps)) {
1337 hddLog(LOGE, FL("put fail"));
1338 goto fail;
1339 }
1340
1341 if (event->numOfAps) {
1342 struct nlattr *aps;
1343 aps = nla_nest_start(skb,
1344 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_LIST);
1345 if (!aps) {
1346 hddLog(LOGE, FL("nest fail"));
1347 goto fail;
1348 }
1349
1350 for (i = 0; i < event->numOfAps; i++) {
1351 struct nlattr *ap;
1352
1353 ap = nla_nest_start(skb, i);
1354 if (!ap) {
1355 hddLog(LOGE, FL("nest fail"));
1356 goto fail;
1357 }
1358
1359 if (nla_put_u64(skb,
1360 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_TIME_STAMP,
1361 event->ap[i].ts) ||
1362 nla_put(skb,
1363 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_SSID,
1364 sizeof(event->ap[i].ssid),
1365 event->ap[i].ssid) ||
1366 nla_put(skb,
1367 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_BSSID,
1368 sizeof(event->ap[i].bssid),
1369 event->ap[i].bssid.bytes) ||
1370 nla_put_u32(skb,
1371 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_CHANNEL,
1372 event->ap[i].channel) ||
1373 nla_put_s32(skb,
1374 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RSSI,
1375 event->ap[i].rssi) ||
1376 nla_put_u32(skb,
1377 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RTT,
1378 event->ap[i].rtt) ||
1379 nla_put_u32(skb,
1380 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RTT_SD,
1381 event->ap[i].rtt_sd)) {
1382 hddLog(LOGE, FL("put fail"));
1383 goto fail;
1384 }
1385 nla_nest_end(skb, ap);
1386 }
1387 nla_nest_end(skb, aps);
1388
1389 if (nla_put_u8(skb,
1390 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_MORE_DATA,
1391 event->moreData)) {
1392 hddLog(LOGE, FL("put fail"));
1393 goto fail;
1394 }
1395 }
1396
Srinivas Girigowdafe3e5b32015-11-23 11:56:36 -08001397 cfg80211_vendor_event(skb, flags);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001398 return;
1399
1400fail:
1401 kfree_skb(skb);
1402 return;
1403}
1404
1405/**
1406 * wlan_hdd_cfg80211_extscan_generic_rsp() -
1407 * Handle a generic ExtScan Response message
1408 * @ctx: HDD context registered with SME
1409 * @response: The ExtScan response from firmware
1410 *
1411 * This function will handle a generic ExtScan response message from
1412 * firmware and will communicate the result to the userspace thread
1413 * that is waiting for the response.
1414 *
1415 * Return: none
1416 */
1417static void
1418wlan_hdd_cfg80211_extscan_generic_rsp
1419 (void *ctx,
1420 struct sir_extscan_generic_response *response)
1421{
1422 hdd_context_t *hdd_ctx = ctx;
1423 struct hdd_ext_scan_context *context;
1424
1425 ENTER();
1426
1427 if (wlan_hdd_validate_context(hdd_ctx) || !response) {
1428 hddLog(LOGE,
1429 FL("HDD context is not valid or response(%p) is null"),
1430 response);
1431 return;
1432 }
1433
1434 hddLog(LOG1, FL("request %u status %u"),
1435 response->request_id, response->status);
1436
1437 context = &ext_scan_context;
1438 spin_lock(&context->context_lock);
1439 if (context->request_id == response->request_id) {
1440 context->response_status = response->status ? -EINVAL : 0;
1441 complete(&context->response_event);
1442 }
1443 spin_unlock(&context->context_lock);
1444
1445 return;
1446}
1447
1448/**
1449 * wlan_hdd_cfg80211_extscan_callback() - ext scan callback
1450 * @ctx: Pointer to hdd context
1451 * @evType: Event type
1452 * @pMag: Pointer to message
1453 *
1454 * Return: none
1455 */
1456void wlan_hdd_cfg80211_extscan_callback(void *ctx, const uint16_t evType,
1457 void *pMsg)
1458{
1459 hdd_context_t *pHddCtx = (hdd_context_t *) ctx;
1460
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301461 ENTER();
1462
1463 if (wlan_hdd_validate_context(pHddCtx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001464 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001465
1466 hddLog(LOG1, FL("Rcvd Event %d"), evType);
1467
1468 switch (evType) {
1469 case eSIR_EXTSCAN_CACHED_RESULTS_RSP:
1470 /* There is no need to send this response to upper layer
1471 Just log the message */
1472 hddLog(LOG1,
1473 FL("Rcvd eSIR_EXTSCAN_CACHED_RESULTS_RSP"));
1474 break;
1475
1476 case eSIR_EXTSCAN_GET_CAPABILITIES_IND:
1477 wlan_hdd_cfg80211_extscan_get_capabilities_rsp(ctx,
1478 (struct ext_scan_capabilities_response *) pMsg);
1479 break;
1480
1481 case eSIR_EXTSCAN_HOTLIST_MATCH_IND:
1482 wlan_hdd_cfg80211_extscan_hotlist_match_ind(ctx, pMsg);
1483 break;
1484
1485 case eSIR_EXTSCAN_SIGNIFICANT_WIFI_CHANGE_RESULTS_IND:
1486 wlan_hdd_cfg80211_extscan_signif_wifi_change_results_ind(ctx,
1487 (tpSirWifiSignificantChangeEvent) pMsg);
1488 break;
1489
1490 case eSIR_EXTSCAN_CACHED_RESULTS_IND:
1491 wlan_hdd_cfg80211_extscan_cached_results_ind(ctx, pMsg);
1492 break;
1493
1494 case eSIR_EXTSCAN_SCAN_RES_AVAILABLE_IND:
1495 wlan_hdd_cfg80211_extscan_scan_res_available_event(ctx,
1496 (tpSirExtScanResultsAvailableIndParams) pMsg);
1497 break;
1498
1499 case eSIR_EXTSCAN_FULL_SCAN_RESULT_IND:
1500 wlan_hdd_cfg80211_extscan_full_scan_result_event(ctx,
1501 (tpSirWifiFullScanResultEvent) pMsg);
1502 break;
1503
1504 case eSIR_EPNO_NETWORK_FOUND_IND:
1505 wlan_hdd_cfg80211_extscan_epno_match_found(ctx,
1506 (struct pno_match_found *)pMsg);
1507 break;
1508
1509 case eSIR_EXTSCAN_HOTLIST_SSID_MATCH_IND:
1510 wlan_hdd_cfg80211_extscan_hotlist_ssid_match_ind(ctx,
1511 (tpSirWifiScanResultEvent)pMsg);
1512 break;
1513
1514 case eSIR_EXTSCAN_SCAN_PROGRESS_EVENT_IND:
1515 wlan_hdd_cfg80211_extscan_scan_progress_event(ctx,
1516 (tpSirExtScanOnScanEventIndParams) pMsg);
1517 break;
1518
1519 case eSIR_PASSPOINT_NETWORK_FOUND_IND:
1520 wlan_hdd_cfg80211_passpoint_match_found(ctx,
1521 (struct wifi_passpoint_match *) pMsg);
1522 break;
1523
1524 case eSIR_EXTSCAN_START_RSP:
1525 case eSIR_EXTSCAN_STOP_RSP:
1526 case eSIR_EXTSCAN_SET_BSSID_HOTLIST_RSP:
1527 case eSIR_EXTSCAN_RESET_BSSID_HOTLIST_RSP:
1528 case eSIR_EXTSCAN_SET_SIGNIFICANT_WIFI_CHANGE_RSP:
1529 case eSIR_EXTSCAN_RESET_SIGNIFICANT_WIFI_CHANGE_RSP:
1530 case eSIR_EXTSCAN_SET_SSID_HOTLIST_RSP:
1531 case eSIR_EXTSCAN_RESET_SSID_HOTLIST_RSP:
1532 wlan_hdd_cfg80211_extscan_generic_rsp(ctx, pMsg);
1533 break;
1534
1535 default:
1536 hddLog(LOGE, FL("Unknown event type %u"), evType);
1537 break;
1538 }
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301539 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001540}
1541
1542/*
1543 * define short names for the global vendor params
1544 * used by wlan_hdd_send_ext_scan_capability()
1545 */
1546#define PARAM_REQUEST_ID \
1547 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID
1548#define PARAM_STATUS \
1549 QCA_WLAN_VENDOR_ATTR_EXTSCAN_STATUS
1550#define MAX_SCAN_CACHE_SIZE \
1551 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_SCAN_CACHE_SIZE
1552#define MAX_SCAN_BUCKETS \
1553 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_SCAN_BUCKETS
1554#define MAX_AP_CACHE_PER_SCAN \
1555 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_AP_CACHE_PER_SCAN
1556#define MAX_RSSI_SAMPLE_SIZE \
1557 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_RSSI_SAMPLE_SIZE
1558#define MAX_SCAN_RPT_THRHOLD \
1559 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_SCAN_REPORTING_THRESHOLD
1560#define MAX_HOTLIST_BSSIDS \
1561 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_HOTLIST_BSSIDS
1562#define MAX_SIGNIFICANT_WIFI_CHANGE_APS \
1563 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_SIGNIFICANT_WIFI_CHANGE_APS
1564#define MAX_BSSID_HISTORY_ENTRIES \
1565 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_BSSID_HISTORY_ENTRIES
1566#define MAX_HOTLIST_SSIDS \
1567 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_HOTLIST_SSIDS
1568#define MAX_NUM_EPNO_NETS \
1569 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_NUM_EPNO_NETS
1570#define MAX_NUM_EPNO_NETS_BY_SSID \
1571 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_NUM_EPNO_NETS_BY_SSID
1572#define MAX_NUM_WHITELISTED_SSID \
1573 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_NUM_WHITELISTED_SSID
1574
1575/**
1576 * wlan_hdd_send_ext_scan_capability - send ext scan capability to user space
1577 * @hdd_ctx: Pointer to hdd context
1578 *
1579 * Return: 0 for success, non-zero for failure
1580 */
1581static int wlan_hdd_send_ext_scan_capability(hdd_context_t *hdd_ctx)
1582{
1583 int ret;
1584 struct sk_buff *skb;
1585 struct ext_scan_capabilities_response *data;
1586 uint32_t nl_buf_len;
1587
1588 ret = wlan_hdd_validate_context(hdd_ctx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301589 if (0 != ret)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001590 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001591
1592 data = &(ext_scan_context.capability_response);
1593
1594 nl_buf_len = NLMSG_HDRLEN;
1595 nl_buf_len += (sizeof(data->requestId) + NLA_HDRLEN) +
1596 (sizeof(data->status) + NLA_HDRLEN) +
1597 (sizeof(data->max_scan_cache_size) + NLA_HDRLEN) +
1598 (sizeof(data->max_scan_buckets) + NLA_HDRLEN) +
1599 (sizeof(data->max_ap_cache_per_scan) + NLA_HDRLEN) +
1600 (sizeof(data->max_rssi_sample_size) + NLA_HDRLEN) +
1601 (sizeof(data->max_scan_reporting_threshold) + NLA_HDRLEN) +
1602 (sizeof(data->max_hotlist_bssids) + NLA_HDRLEN) +
1603 (sizeof(data->max_significant_wifi_change_aps) + NLA_HDRLEN) +
1604 (sizeof(data->max_bssid_history_entries) + NLA_HDRLEN) +
1605 (sizeof(data->max_hotlist_ssids) + NLA_HDRLEN) +
1606 (sizeof(data->max_number_epno_networks) + NLA_HDRLEN) +
1607 (sizeof(data->max_number_epno_networks_by_ssid) + NLA_HDRLEN) +
1608 (sizeof(data->max_number_of_white_listed_ssid) + NLA_HDRLEN);
1609
1610 skb = cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, nl_buf_len);
1611
1612 if (!skb) {
1613 hddLog(LOGE, FL("cfg80211_vendor_cmd_alloc_reply_skb failed"));
1614 return -ENOMEM;
1615 }
1616
1617
1618 hddLog(LOG1, "Req Id %u", data->requestId);
1619 hddLog(LOG1, "Status %u", data->status);
1620 hddLog(LOG1, "Scan cache size %u",
1621 data->max_scan_cache_size);
1622 hddLog(LOG1, "Scan buckets %u", data->max_scan_buckets);
1623 hddLog(LOG1, "Max AP per scan %u",
1624 data->max_ap_cache_per_scan);
1625 hddLog(LOG1, "max_rssi_sample_size %u",
1626 data->max_rssi_sample_size);
1627 hddLog(LOG1, "max_scan_reporting_threshold %u",
1628 data->max_scan_reporting_threshold);
1629 hddLog(LOG1, "max_hotlist_bssids %u",
1630 data->max_hotlist_bssids);
1631 hddLog(LOG1, "max_significant_wifi_change_aps %u",
1632 data->max_significant_wifi_change_aps);
1633 hddLog(LOG1, "max_bssid_history_entries %u",
1634 data->max_bssid_history_entries);
1635 hddLog(LOG1, "max_hotlist_ssids %u", data->max_hotlist_ssids);
1636 hddLog(LOG1, "max_number_epno_networks %u",
1637 data->max_number_epno_networks);
1638 hddLog(LOG1, "max_number_epno_networks_by_ssid %u",
1639 data->max_number_epno_networks_by_ssid);
1640 hddLog(LOG1, "max_number_of_white_listed_ssid %u",
1641 data->max_number_of_white_listed_ssid);
1642
1643 if (nla_put_u32(skb, PARAM_REQUEST_ID, data->requestId) ||
1644 nla_put_u32(skb, PARAM_STATUS, data->status) ||
1645 nla_put_u32(skb, MAX_SCAN_CACHE_SIZE, data->max_scan_cache_size) ||
1646 nla_put_u32(skb, MAX_SCAN_BUCKETS, data->max_scan_buckets) ||
1647 nla_put_u32(skb, MAX_AP_CACHE_PER_SCAN,
1648 data->max_ap_cache_per_scan) ||
1649 nla_put_u32(skb, MAX_RSSI_SAMPLE_SIZE,
1650 data->max_rssi_sample_size) ||
1651 nla_put_u32(skb, MAX_SCAN_RPT_THRHOLD,
1652 data->max_scan_reporting_threshold) ||
1653 nla_put_u32(skb, MAX_HOTLIST_BSSIDS, data->max_hotlist_bssids) ||
1654 nla_put_u32(skb, MAX_SIGNIFICANT_WIFI_CHANGE_APS,
1655 data->max_significant_wifi_change_aps) ||
1656 nla_put_u32(skb, MAX_BSSID_HISTORY_ENTRIES,
1657 data->max_bssid_history_entries) ||
1658 nla_put_u32(skb, MAX_HOTLIST_SSIDS, data->max_hotlist_ssids) ||
1659 nla_put_u32(skb, MAX_NUM_EPNO_NETS,
1660 data->max_number_epno_networks) ||
1661 nla_put_u32(skb, MAX_NUM_EPNO_NETS_BY_SSID,
1662 data->max_number_epno_networks_by_ssid) ||
1663 nla_put_u32(skb, MAX_NUM_WHITELISTED_SSID,
1664 data->max_number_of_white_listed_ssid)) {
1665 hddLog(LOGE, FL("nla put fail"));
1666 goto nla_put_failure;
1667 }
1668
1669 cfg80211_vendor_cmd_reply(skb);
1670 return 0;
1671
1672nla_put_failure:
1673 kfree_skb(skb);
1674 return -EINVAL;
1675}
1676/*
1677 * done with short names for the global vendor params
1678 * used by wlan_hdd_send_ext_scan_capability()
1679 */
1680#undef PARAM_REQUEST_ID
1681#undef PARAM_STATUS
1682#undef MAX_SCAN_CACHE_SIZE
1683#undef MAX_SCAN_BUCKETS
1684#undef MAX_AP_CACHE_PER_SCAN
1685#undef MAX_RSSI_SAMPLE_SIZE
1686#undef MAX_SCAN_RPT_THRHOLD
1687#undef MAX_HOTLIST_BSSIDS
1688#undef MAX_SIGNIFICANT_WIFI_CHANGE_APS
1689#undef MAX_BSSID_HISTORY_ENTRIES
1690#undef MAX_HOTLIST_SSIDS
1691#undef MAX_NUM_EPNO_NETS
1692#undef MAX_NUM_EPNO_NETS_BY_SSID
1693#undef MAX_NUM_WHITELISTED_SSID
1694
1695/**
1696 * __wlan_hdd_cfg80211_extscan_get_capabilities() - get ext scan capabilities
1697 * @wiphy: Pointer to wireless phy
1698 * @wdev: Pointer to wireless device
1699 * @data: Pointer to data
1700 * @data_len: Data length
1701 *
1702 * Return: none
1703 */
1704static int __wlan_hdd_cfg80211_extscan_get_capabilities(struct wiphy *wiphy,
1705 struct wireless_dev *wdev,
1706 const void *data, int data_len)
1707{
1708 int ret;
1709 unsigned long rc;
1710 struct hdd_ext_scan_context *context;
1711 tpSirGetExtScanCapabilitiesReqParams pReqMsg = NULL;
1712 struct net_device *dev = wdev->netdev;
1713 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
1714 hdd_context_t *pHddCtx = wiphy_priv(wiphy);
1715 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX +
1716 1];
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301717 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001718
Jeff Johnson1f61b612016-02-12 16:28:33 -08001719 ENTER_DEV(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001720
Anurag Chouhan6d760662016-02-20 16:05:43 +05301721 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001722 hdd_err("Command not allowed in FTM mode");
1723 return -EPERM;
1724 }
1725
1726 ret = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301727 if (0 != ret)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001728 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001729
1730 if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX,
1731 data, data_len, wlan_hdd_extscan_config_policy)) {
1732 hddLog(LOGE, FL("Invalid ATTR"));
1733 return -EINVAL;
1734 }
1735
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301736 pReqMsg = qdf_mem_malloc(sizeof(*pReqMsg));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001737 if (!pReqMsg) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301738 hddLog(LOGE, FL("qdf_mem_malloc failed"));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001739 return -ENOMEM;
1740 }
1741
1742 /* Parse and fetch request Id */
1743 if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]) {
1744 hddLog(LOGE, FL("attr request id failed"));
1745 goto fail;
1746 }
1747
1748 pReqMsg->requestId =
1749 nla_get_u32(tb
1750 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]);
1751 pReqMsg->sessionId = pAdapter->sessionId;
1752 hddLog(LOG1, FL("Req Id %d Session Id %d"),
1753 pReqMsg->requestId, pReqMsg->sessionId);
1754
1755 context = &ext_scan_context;
1756 spin_lock(&context->context_lock);
1757 context->request_id = pReqMsg->requestId;
1758 INIT_COMPLETION(context->response_event);
1759 spin_unlock(&context->context_lock);
1760
1761 status = sme_ext_scan_get_capabilities(pHddCtx->hHal, pReqMsg);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301762 if (!QDF_IS_STATUS_SUCCESS(status)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001763 hddLog(LOGE, FL("sme_ext_scan_get_capabilities failed(err=%d)"),
1764 status);
1765 goto fail;
1766 }
1767
1768 rc = wait_for_completion_timeout(&context->response_event,
1769 msecs_to_jiffies(WLAN_WAIT_TIME_EXTSCAN));
1770 if (!rc) {
1771 hddLog(LOGE, FL("Target response timed out"));
1772 return -ETIMEDOUT;
1773 }
1774
1775 ret = wlan_hdd_send_ext_scan_capability(pHddCtx);
1776 if (ret)
1777 hddLog(LOGE, FL("Failed to send ext scan capability to user space"));
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301778 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001779 return ret;
1780fail:
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301781 qdf_mem_free(pReqMsg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001782 return -EINVAL;
1783}
1784
1785/**
1786 * wlan_hdd_cfg80211_extscan_get_capabilities() - get ext scan capabilities
1787 * @wiphy: Pointer to wiphy
1788 * @wdev: Pointer to wdev
1789 * @data: Pointer to data
1790 * @data_len: Data length
1791 *
1792 * Return: 0 for success, non-zero for failure
1793 */
1794int wlan_hdd_cfg80211_extscan_get_capabilities(struct wiphy *wiphy,
1795 struct wireless_dev *wdev,
1796 const void *data, int data_len)
1797{
1798 int ret = 0;
1799
1800 cds_ssr_protect(__func__);
1801 ret = __wlan_hdd_cfg80211_extscan_get_capabilities(wiphy, wdev, data,
1802 data_len);
1803 cds_ssr_unprotect(__func__);
1804
1805 return ret;
1806}
1807
1808/*
1809 * define short names for the global vendor params
1810 * used by wlan_hdd_cfg80211_extscan_get_cached_results()
1811 */
1812#define PARAM_MAX \
1813 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX
1814#define PARAM_REQUEST_ID \
1815 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID
1816#define PARAM_FLUSH \
1817 QCA_WLAN_VENDOR_ATTR_EXTSCAN_GET_CACHED_SCAN_RESULTS_CONFIG_PARAM_FLUSH
1818/**
1819 * __wlan_hdd_cfg80211_extscan_get_cached_results() - extscan get cached results
1820 * @wiphy: wiphy pointer
1821 * @wdev: pointer to struct wireless_dev
1822 * @data: pointer to incoming NL vendor data
1823 * @data_len: length of @data
1824 *
1825 * This function parses the incoming NL vendor command data attributes and
1826 * invokes the SME Api and blocks on a completion variable.
1827 * Each WMI event with cached scan results data chunk results in
1828 * function call wlan_hdd_cfg80211_extscan_cached_results_ind and each
1829 * data chunk is sent up the layer in cfg80211_vendor_cmd_alloc_reply_skb.
1830 *
1831 * If timeout happens before receiving all of the data, this function sets
1832 * a context variable @ignore_cached_results to %true, all of the next data
1833 * chunks are checked against this variable and dropped.
1834 *
1835 * Return: 0 on success; error number otherwise.
1836 */
1837static int __wlan_hdd_cfg80211_extscan_get_cached_results(struct wiphy *wiphy,
1838 struct wireless_dev
1839 *wdev, const void *data,
1840 int data_len)
1841{
1842 tpSirExtScanGetCachedResultsReqParams pReqMsg = NULL;
1843 struct net_device *dev = wdev->netdev;
1844 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
1845 hdd_context_t *pHddCtx = wiphy_priv(wiphy);
1846 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX +
1847 1];
1848 struct hdd_ext_scan_context *context;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301849 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001850 int retval = 0;
1851 unsigned long rc;
1852
Jeff Johnson1f61b612016-02-12 16:28:33 -08001853 ENTER_DEV(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001854
Anurag Chouhan6d760662016-02-20 16:05:43 +05301855 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001856 hdd_err("Command not allowed in FTM mode");
1857 return -EPERM;
1858 }
1859
1860 retval = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301861 if (0 != retval)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001862 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001863
1864 if (nla_parse(tb, PARAM_MAX, data, data_len,
1865 wlan_hdd_extscan_config_policy)) {
1866 hddLog(LOGE, FL("Invalid ATTR"));
1867 return -EINVAL;
1868 }
1869
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301870 pReqMsg = qdf_mem_malloc(sizeof(*pReqMsg));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001871 if (!pReqMsg) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301872 hddLog(LOGE, FL("qdf_mem_malloc failed"));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001873 return -ENOMEM;
1874 }
1875
1876 /* Parse and fetch request Id */
1877 if (!tb[PARAM_REQUEST_ID]) {
1878 hddLog(LOGE, FL("attr request id failed"));
1879 goto fail;
1880 }
1881
1882 pReqMsg->requestId = nla_get_u32(tb[PARAM_REQUEST_ID]);
1883 pReqMsg->sessionId = pAdapter->sessionId;
1884 hddLog(LOG1, FL("Req Id %d Session Id %d"),
1885 pReqMsg->requestId, pReqMsg->sessionId);
1886
1887 /* Parse and fetch flush parameter */
1888 if (!tb[PARAM_FLUSH]) {
1889 hddLog(LOGE, FL("attr flush failed"));
1890 goto fail;
1891 }
1892 pReqMsg->flush = nla_get_u8(tb[PARAM_FLUSH]);
1893 hddLog(LOG1, FL("Flush %d"), pReqMsg->flush);
1894
1895 context = &ext_scan_context;
1896 spin_lock(&context->context_lock);
1897 context->request_id = pReqMsg->requestId;
1898 context->ignore_cached_results = false;
1899 INIT_COMPLETION(context->response_event);
1900 spin_unlock(&context->context_lock);
1901
1902 status = sme_get_cached_results(pHddCtx->hHal, pReqMsg);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301903 if (!QDF_IS_STATUS_SUCCESS(status)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001904 hddLog(LOGE,
1905 FL("sme_get_cached_results failed(err=%d)"), status);
1906 goto fail;
1907 }
1908
1909 rc = wait_for_completion_timeout(&context->response_event,
1910 msecs_to_jiffies(WLAN_WAIT_TIME_EXTSCAN));
1911 if (!rc) {
1912 hddLog(LOGE, FL("Target response timed out"));
1913 retval = -ETIMEDOUT;
1914 spin_lock(&context->context_lock);
1915 context->ignore_cached_results = true;
1916 spin_unlock(&context->context_lock);
1917 } else {
1918 spin_lock(&context->context_lock);
1919 retval = context->response_status;
1920 spin_unlock(&context->context_lock);
1921 }
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301922 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001923 return retval;
1924
1925fail:
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301926 qdf_mem_free(pReqMsg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001927 return -EINVAL;
1928}
1929/*
1930 * done with short names for the global vendor params
1931 * used by wlan_hdd_cfg80211_extscan_get_cached_results()
1932 */
1933#undef PARAM_MAX
1934#undef PARAM_REQUEST_ID
1935#undef PARAM_FLUSH
1936
1937/**
1938 * wlan_hdd_cfg80211_extscan_get_cached_results() - extscan get cached results
1939 * @wiphy: wiphy pointer
1940 * @wdev: pointer to struct wireless_dev
1941 * @data: pointer to incoming NL vendor data
1942 * @data_len: length of @data
1943 *
1944 * This function parses the incoming NL vendor command data attributes and
1945 * invokes the SME Api and blocks on a completion variable.
1946 * Each WMI event with cached scan results data chunk results in
1947 * function call wlan_hdd_cfg80211_extscan_cached_results_ind and each
1948 * data chunk is sent up the layer in cfg80211_vendor_cmd_alloc_reply_skb.
1949 *
1950 * If timeout happens before receiving all of the data, this function sets
1951 * a context variable @ignore_cached_results to %true, all of the next data
1952 * chunks are checked against this variable and dropped.
1953 *
1954 * Return: 0 on success; error number otherwise.
1955 */
1956int wlan_hdd_cfg80211_extscan_get_cached_results(struct wiphy *wiphy,
1957 struct wireless_dev *wdev,
1958 const void *data, int data_len)
1959{
1960 int ret = 0;
1961
1962 cds_ssr_protect(__func__);
1963 ret = __wlan_hdd_cfg80211_extscan_get_cached_results(wiphy, wdev, data,
1964 data_len);
1965 cds_ssr_unprotect(__func__);
1966
1967 return ret;
1968}
1969
1970/**
1971 * __wlan_hdd_cfg80211_extscan_set_bssid_hotlist() - set bssid hot list
1972 * @wiphy: Pointer to wireless phy
1973 * @wdev: Pointer to wireless device
1974 * @data: Pointer to data
1975 * @data_len: Data length
1976 *
1977 * Return: none
1978 */
1979static int
1980__wlan_hdd_cfg80211_extscan_set_bssid_hotlist(struct wiphy *wiphy,
1981 struct wireless_dev
1982 *wdev, const void *data,
1983 int data_len)
1984{
1985 tpSirExtScanSetBssidHotListReqParams pReqMsg = NULL;
1986 struct net_device *dev = wdev->netdev;
1987 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
1988 hdd_context_t *pHddCtx = wiphy_priv(wiphy);
1989 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX +
1990 1];
1991 struct nlattr *tb2[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX
1992 + 1];
1993 struct nlattr *apTh;
1994 struct hdd_ext_scan_context *context;
1995 uint32_t request_id;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301996 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001997 uint8_t i;
1998 int rem, retval;
1999 unsigned long rc;
2000
Jeff Johnson1f61b612016-02-12 16:28:33 -08002001 ENTER_DEV(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002002
Anurag Chouhan6d760662016-02-20 16:05:43 +05302003 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002004 hdd_err("Command not allowed in FTM mode");
2005 return -EPERM;
2006 }
2007
2008 retval = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05302009 if (0 != retval)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002010 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002011
2012 if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX,
2013 data, data_len, wlan_hdd_extscan_config_policy)) {
2014 hddLog(LOGE, FL("Invalid ATTR"));
2015 return -EINVAL;
2016 }
2017
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302018 pReqMsg = qdf_mem_malloc(sizeof(*pReqMsg));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002019 if (!pReqMsg) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302020 hddLog(LOGE, FL("qdf_mem_malloc failed"));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002021 return -ENOMEM;
2022 }
2023
2024 /* Parse and fetch request Id */
2025 if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]) {
2026 hddLog(LOGE, FL("attr request id failed"));
2027 goto fail;
2028 }
2029
2030 pReqMsg->requestId =
2031 nla_get_u32(tb
2032 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]);
2033 hddLog(LOG1, FL("Req Id %d"), pReqMsg->requestId);
2034
2035 /* Parse and fetch number of APs */
2036 if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BSSID_HOTLIST_PARAMS_NUM_AP]) {
2037 hddLog(LOGE, FL("attr number of AP failed"));
2038 goto fail;
2039 }
2040 pReqMsg->numAp =
2041 nla_get_u32(tb
2042 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_BSSID_HOTLIST_PARAMS_NUM_AP]);
2043 pReqMsg->sessionId = pAdapter->sessionId;
2044 hddLog(LOG1, FL("Number of AP %d Session Id %d"),
2045 pReqMsg->numAp, pReqMsg->sessionId);
2046
2047 /* Parse and fetch lost ap sample size */
2048 if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BSSID_HOTLIST_PARAMS_LOST_AP_SAMPLE_SIZE]) {
2049 hddLog(LOGE, FL("attr lost ap sample size failed"));
2050 goto fail;
2051 }
2052
2053 pReqMsg->lost_ap_sample_size = nla_get_u32(
2054 tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BSSID_HOTLIST_PARAMS_LOST_AP_SAMPLE_SIZE]);
2055 hddLog(LOG1, FL("Lost ap sample size %d"),
2056 pReqMsg->lost_ap_sample_size);
2057
2058 i = 0;
2059 nla_for_each_nested(apTh,
2060 tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM],
2061 rem) {
2062 if (nla_parse
2063 (tb2, QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX,
2064 nla_data(apTh), nla_len(apTh),
2065 wlan_hdd_extscan_config_policy)) {
2066 hddLog(LOGE, FL("nla_parse failed"));
2067 goto fail;
2068 }
2069
2070 /* Parse and fetch MAC address */
2071 if (!tb2[QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_BSSID]) {
2072 hddLog(LOGE, FL("attr mac address failed"));
2073 goto fail;
2074 }
2075 nla_memcpy(pReqMsg->ap[i].bssid.bytes,
2076 tb2
2077 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_BSSID],
Anurag Chouhan6d760662016-02-20 16:05:43 +05302078 QDF_MAC_ADDR_SIZE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002079 hddLog(LOG1, MAC_ADDRESS_STR,
2080 MAC_ADDR_ARRAY(pReqMsg->ap[i].bssid.bytes));
2081
2082 /* Parse and fetch low RSSI */
2083 if (!tb2
2084 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_RSSI_LOW]) {
2085 hddLog(LOGE, FL("attr low RSSI failed"));
2086 goto fail;
2087 }
2088 pReqMsg->ap[i].low =
2089 nla_get_s32(tb2
2090 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_RSSI_LOW]);
2091 hddLog(LOG1, FL("RSSI low %d"), pReqMsg->ap[i].low);
2092
2093 /* Parse and fetch high RSSI */
2094 if (!tb2
2095 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_RSSI_HIGH]) {
2096 hddLog(LOGE, FL("attr high RSSI failed"));
2097 goto fail;
2098 }
2099 pReqMsg->ap[i].high =
2100 nla_get_s32(tb2
2101 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_RSSI_HIGH]);
2102 hddLog(LOG1, FL("RSSI High %d"), pReqMsg->ap[i].high);
2103
2104 i++;
2105 }
2106
2107 context = &ext_scan_context;
2108 spin_lock(&context->context_lock);
2109 INIT_COMPLETION(context->response_event);
2110 context->request_id = request_id = pReqMsg->requestId;
2111 spin_unlock(&context->context_lock);
2112
2113 status = sme_set_bss_hotlist(pHddCtx->hHal, pReqMsg);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302114 if (!QDF_IS_STATUS_SUCCESS(status)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002115 hddLog(LOGE, FL("sme_set_bss_hotlist failed(err=%d)"), status);
2116 goto fail;
2117 }
2118
2119 /* request was sent -- wait for the response */
2120 rc = wait_for_completion_timeout
2121 (&context->response_event,
2122 msecs_to_jiffies(WLAN_WAIT_TIME_EXTSCAN));
2123
2124 if (!rc) {
2125 hddLog(LOGE, FL("sme_set_bss_hotlist timed out"));
2126 retval = -ETIMEDOUT;
2127 } else {
2128 spin_lock(&context->context_lock);
2129 if (context->request_id == request_id)
2130 retval = context->response_status;
2131 else
2132 retval = -EINVAL;
2133 spin_unlock(&context->context_lock);
2134 }
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05302135 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002136 return retval;
2137
2138fail:
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302139 qdf_mem_free(pReqMsg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002140 return -EINVAL;
2141}
2142
2143/**
2144 * wlan_hdd_cfg80211_extscan_set_bssid_hotlist() - set ext scan bssid hotlist
2145 * @wiphy: Pointer to wiphy
2146 * @wdev: Pointer to wdev
2147 * @data: Pointer to data
2148 * @data_len: Data length
2149 *
2150 * Return: 0 for success, non-zero for failure
2151 */
2152int wlan_hdd_cfg80211_extscan_set_bssid_hotlist(struct wiphy *wiphy,
2153 struct wireless_dev *wdev,
2154 const void *data, int data_len)
2155{
2156 int ret = 0;
2157
2158 cds_ssr_protect(__func__);
2159 ret = __wlan_hdd_cfg80211_extscan_set_bssid_hotlist(wiphy, wdev, data,
2160 data_len);
2161 cds_ssr_unprotect(__func__);
2162
2163 return ret;
2164}
2165
2166
2167/**
2168 * __wlan_hdd_cfg80211_extscan_set_significant_change () - set significant change
2169 * @wiphy: Pointer to wireless phy
2170 * @wdev: Pointer to wireless device
2171 * @data: Pointer to data
2172 * @data_len: Data length
2173 *
2174 * Return: none
2175 */
2176static int
2177__wlan_hdd_cfg80211_extscan_set_significant_change(struct wiphy *wiphy,
2178 struct wireless_dev
2179 *wdev, const void *data,
2180 int data_len)
2181{
2182 tpSirExtScanSetSigChangeReqParams pReqMsg = NULL;
2183 struct net_device *dev = wdev->netdev;
2184 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
2185 hdd_context_t *pHddCtx = wiphy_priv(wiphy);
2186 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX +
2187 1];
2188 struct nlattr *tb2[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX
2189 + 1];
2190 struct nlattr *apTh;
2191 struct hdd_ext_scan_context *context;
2192 uint32_t request_id;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302193 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002194 uint8_t i;
2195 int rem, retval;
2196 unsigned long rc;
2197
Jeff Johnson1f61b612016-02-12 16:28:33 -08002198 ENTER_DEV(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002199
Anurag Chouhan6d760662016-02-20 16:05:43 +05302200 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002201 hdd_err("Command not allowed in FTM mode");
2202 return -EPERM;
2203 }
2204
2205 retval = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05302206 if (0 != retval)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002207 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002208
2209 if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX,
2210 data, data_len, wlan_hdd_extscan_config_policy)) {
2211 hddLog(LOGE, FL("Invalid ATTR"));
2212 return -EINVAL;
2213 }
2214
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302215 pReqMsg = qdf_mem_malloc(sizeof(*pReqMsg));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002216 if (!pReqMsg) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302217 hddLog(LOGE, FL("qdf_mem_malloc failed"));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002218 return -ENOMEM;
2219 }
2220
2221 /* Parse and fetch request Id */
2222 if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]) {
2223 hddLog(LOGE, FL("attr request id failed"));
2224 goto fail;
2225 }
2226
2227 pReqMsg->requestId =
2228 nla_get_u32(tb
2229 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]);
2230 hddLog(LOG1, FL("Req Id %d"), pReqMsg->requestId);
2231
2232 /* Parse and fetch RSSI sample size */
2233 if (!tb
2234 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_RSSI_SAMPLE_SIZE]) {
2235 hddLog(LOGE, FL("attr RSSI sample size failed"));
2236 goto fail;
2237 }
2238 pReqMsg->rssiSampleSize =
2239 nla_get_u32(tb
2240 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_RSSI_SAMPLE_SIZE]);
2241 hddLog(LOG1, FL("RSSI sample size %u"), pReqMsg->rssiSampleSize);
2242
2243 /* Parse and fetch lost AP sample size */
2244 if (!tb
2245 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_LOST_AP_SAMPLE_SIZE]) {
2246 hddLog(LOGE, FL("attr lost AP sample size failed"));
2247 goto fail;
2248 }
2249 pReqMsg->lostApSampleSize =
2250 nla_get_u32(tb
2251 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_LOST_AP_SAMPLE_SIZE]);
2252 hddLog(LOG1, FL("Lost AP sample size %u"), pReqMsg->lostApSampleSize);
2253
2254 /* Parse and fetch AP min breacing */
2255 if (!tb
2256 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_MIN_BREACHING]) {
2257 hddLog(LOGE, FL("attr AP min breaching"));
2258 goto fail;
2259 }
2260 pReqMsg->minBreaching =
2261 nla_get_u32(tb
2262 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_MIN_BREACHING]);
2263 hddLog(LOG1, FL("AP min breaching %u"), pReqMsg->minBreaching);
2264
2265 /* Parse and fetch number of APs */
2266 if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_NUM_AP]) {
2267 hddLog(LOGE, FL("attr number of AP failed"));
2268 goto fail;
2269 }
2270 pReqMsg->numAp =
2271 nla_get_u32(tb
2272 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_NUM_AP]);
2273 pReqMsg->sessionId = pAdapter->sessionId;
2274 hddLog(LOG1, FL("Number of AP %d Session Id %d"),
2275 pReqMsg->numAp, pReqMsg->sessionId);
2276
2277 i = 0;
2278 nla_for_each_nested(apTh,
2279 tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM],
2280 rem) {
2281 if (nla_parse
2282 (tb2, QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX,
2283 nla_data(apTh), nla_len(apTh),
2284 wlan_hdd_extscan_config_policy)) {
2285 hddLog(LOGE, FL("nla_parse failed"));
2286 goto fail;
2287 }
2288
2289 /* Parse and fetch MAC address */
2290 if (!tb2[QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_BSSID]) {
2291 hddLog(LOGE, FL("attr mac address failed"));
2292 goto fail;
2293 }
2294 nla_memcpy(pReqMsg->ap[i].bssid.bytes,
2295 tb2
2296 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_BSSID],
Anurag Chouhan6d760662016-02-20 16:05:43 +05302297 QDF_MAC_ADDR_SIZE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002298 hddLog(LOG1, MAC_ADDRESS_STR,
2299 MAC_ADDR_ARRAY(pReqMsg->ap[i].bssid.bytes));
2300
2301 /* Parse and fetch low RSSI */
2302 if (!tb2
2303 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_RSSI_LOW]) {
2304 hddLog(LOGE, FL("attr low RSSI failed"));
2305 goto fail;
2306 }
2307 pReqMsg->ap[i].low =
2308 nla_get_s32(tb2
2309 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_RSSI_LOW]);
2310 hddLog(LOG1, FL("RSSI low %d"), pReqMsg->ap[i].low);
2311
2312 /* Parse and fetch high RSSI */
2313 if (!tb2
2314 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_RSSI_HIGH]) {
2315 hddLog(LOGE, FL("attr high RSSI failed"));
2316 goto fail;
2317 }
2318 pReqMsg->ap[i].high =
2319 nla_get_s32(tb2
2320 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_RSSI_HIGH]);
2321 hddLog(LOG1, FL("RSSI High %d"), pReqMsg->ap[i].high);
2322
2323 i++;
2324 }
2325
2326 context = &ext_scan_context;
2327 spin_lock(&context->context_lock);
2328 INIT_COMPLETION(context->response_event);
2329 context->request_id = request_id = pReqMsg->requestId;
2330 spin_unlock(&context->context_lock);
2331
2332 status = sme_set_significant_change(pHddCtx->hHal, pReqMsg);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302333 if (!QDF_IS_STATUS_SUCCESS(status)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002334 hddLog(LOGE,
2335 FL("sme_set_significant_change failed(err=%d)"), status);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302336 qdf_mem_free(pReqMsg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002337 return -EINVAL;
2338 }
2339
2340 /* request was sent -- wait for the response */
2341 rc = wait_for_completion_timeout(&context->response_event,
2342 msecs_to_jiffies(WLAN_WAIT_TIME_EXTSCAN));
2343
2344 if (!rc) {
2345 hddLog(LOGE, FL("sme_set_significant_change timed out"));
2346 retval = -ETIMEDOUT;
2347 } else {
2348 spin_lock(&context->context_lock);
2349 if (context->request_id == request_id)
2350 retval = context->response_status;
2351 else
2352 retval = -EINVAL;
2353 spin_unlock(&context->context_lock);
2354 }
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05302355 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002356 return retval;
2357
2358fail:
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302359 qdf_mem_free(pReqMsg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002360 return -EINVAL;
2361}
2362
2363/**
2364 * wlan_hdd_cfg80211_extscan_set_significant_change() - set significant change
2365 * @wiphy: Pointer to wireless phy
2366 * @wdev: Pointer to wireless device
2367 * @data: Pointer to data
2368 * @data_len: Data length
2369 *
2370 * Return: 0 on success, negative errno on failure
2371 */
2372int wlan_hdd_cfg80211_extscan_set_significant_change(struct wiphy *wiphy,
2373 struct wireless_dev *wdev,
2374 const void *data, int data_len)
2375{
2376 int ret = 0;
2377
2378 cds_ssr_protect(__func__);
2379 ret = __wlan_hdd_cfg80211_extscan_set_significant_change(wiphy, wdev,
2380 data, data_len);
2381 cds_ssr_unprotect(__func__);
2382
2383 return ret;
2384}
2385
2386/**
2387 * hdd_remove_dsrc_channels () - remove dsrc chanels
2388 * @wiphy: Pointer to wireless phy
2389 * @chan_list: channel list
2390 * @num_channels: number of channels
2391 *
2392 * Return: none
2393 */
2394void hdd_remove_dsrc_channels(struct wiphy *wiphy, uint32_t *chan_list,
2395 uint8_t *num_channels)
2396{
2397 uint8_t num_chan_temp = 0;
2398 int i;
2399
2400 for (i = 0; i < *num_channels; i++) {
2401 if (!cds_is_dsrc_channel(chan_list[i])) {
2402 chan_list[num_chan_temp] = chan_list[i];
2403 num_chan_temp++;
2404 }
2405 }
2406
2407 *num_channels = num_chan_temp;
2408}
2409
2410/**
2411 * hdd_remove_indoor_channels () - remove indoor channels
2412 * @wiphy: Pointer to wireless phy
2413 * @chan_list: channel list
2414 * @num_channels: number of channels
2415 *
2416 * Return: none
2417 */
2418#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
2419void hdd_remove_indoor_channels(struct wiphy *wiphy, uint32_t *chan_list,
2420 uint8_t *num_channels)
2421{
2422 uint8_t num_chan_temp = 0;
2423 int i, j, k;
2424
2425 for (i = 0; i < *num_channels; i++)
2426 for (j = 0; j < IEEE80211_NUM_BANDS; j++) {
2427 if (wiphy->bands[j] == NULL)
2428 continue;
2429 for (k = 0; k < wiphy->bands[j]->n_channels; k++) {
2430 if ((chan_list[i] ==
2431 wiphy->bands[j]->channels[k].center_freq)
2432 && (!(wiphy->bands[j]->channels[k].flags &
2433 IEEE80211_CHAN_INDOOR_ONLY))
2434 ) {
2435 chan_list[num_chan_temp] = chan_list[i];
2436 num_chan_temp++;
2437 }
2438 }
2439 }
2440
2441 *num_channels = num_chan_temp;
2442}
2443#else
2444void hdd_remove_indoor_channels(struct wiphy *wiphy, uint32_t *chan_list,
2445 uint8_t *num_channels)
2446{
2447 *num_channels = 0;
2448}
2449#endif
2450
2451/**
2452 * __wlan_hdd_cfg80211_extscan_get_valid_channels () - get valid channels
2453 * @wiphy: Pointer to wireless phy
2454 * @wdev: Pointer to wireless device
2455 * @data: Pointer to data
2456 * @data_len: Data length
2457 *
2458 * Return: none
2459 */
2460static int
2461__wlan_hdd_cfg80211_extscan_get_valid_channels(struct wiphy *wiphy,
2462 struct wireless_dev
2463 *wdev, const void *data,
2464 int data_len)
2465{
2466 hdd_context_t *pHddCtx = wiphy_priv(wiphy);
2467 struct net_device *dev = wdev->netdev;
2468 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
2469 uint32_t chan_list[WNI_CFG_VALID_CHANNEL_LIST_LEN] = {0};
2470 uint8_t num_channels = 0;
2471 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX +
2472 1];
2473 uint32_t requestId, maxChannels;
2474 tWifiBand wifiBand;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302475 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002476 struct sk_buff *reply_skb;
2477 uint8_t i;
2478 int ret;
2479
Jeff Johnson1f61b612016-02-12 16:28:33 -08002480 ENTER_DEV(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002481
Anurag Chouhan6d760662016-02-20 16:05:43 +05302482 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002483 hdd_err("Command not allowed in FTM mode");
2484 return -EPERM;
2485 }
2486
2487 ret = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05302488 if (0 != ret)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002489 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002490
2491 if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX,
2492 data, data_len, wlan_hdd_extscan_config_policy)) {
2493 hddLog(LOGE, FL("Invalid ATTR"));
2494 return -EINVAL;
2495 }
2496
2497 /* Parse and fetch request Id */
2498 if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]) {
2499 hddLog(LOGE, FL("attr request id failed"));
2500 return -EINVAL;
2501 }
2502 requestId =
2503 nla_get_u32(tb
2504 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]);
2505 hddLog(LOG1, FL("Req Id %d"), requestId);
2506
2507 /* Parse and fetch wifi band */
2508 if (!tb
2509 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_GET_VALID_CHANNELS_CONFIG_PARAM_WIFI_BAND]) {
2510 hddLog(LOGE, FL("attr wifi band failed"));
2511 return -EINVAL;
2512 }
2513 wifiBand =
2514 nla_get_u32(tb
2515 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_GET_VALID_CHANNELS_CONFIG_PARAM_WIFI_BAND]);
2516 hddLog(LOG1, FL("Wifi band %d"), wifiBand);
2517
2518 if (!tb
2519 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_GET_VALID_CHANNELS_CONFIG_PARAM_MAX_CHANNELS]) {
2520 hddLog(LOGE, FL("attr max channels failed"));
2521 return -EINVAL;
2522 }
2523 maxChannels =
2524 nla_get_u32(tb
2525 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_GET_VALID_CHANNELS_CONFIG_PARAM_MAX_CHANNELS]);
2526 hddLog(LOG1, FL("Max channels %d"), maxChannels);
2527 status = sme_get_valid_channels_by_band((tHalHandle) (pHddCtx->hHal),
2528 wifiBand, chan_list,
2529 &num_channels);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302530 if (QDF_STATUS_SUCCESS != status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002531 hddLog(LOGE,
2532 FL("sme_get_valid_channels_by_band failed (err=%d)"),
2533 status);
2534 return -EINVAL;
2535 }
2536
Anurag Chouhan6d760662016-02-20 16:05:43 +05302537 num_channels = QDF_MIN(num_channels, maxChannels);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002538
2539 hdd_remove_dsrc_channels(wiphy, chan_list, &num_channels);
2540
2541 if ((WLAN_HDD_SOFTAP == pAdapter->device_mode) ||
2542 !strncmp(hdd_get_fwpath(), "ap", 2))
2543 hdd_remove_indoor_channels(wiphy, chan_list, &num_channels);
2544
2545 hddLog(LOG1, FL("Number of channels %d"), num_channels);
2546 for (i = 0; i < num_channels; i++)
2547 hddLog(LOG1, "Channel: %u ", chan_list[i]);
2548
2549 reply_skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, sizeof(u32) +
2550 sizeof(u32) *
2551 num_channels +
2552 NLMSG_HDRLEN);
2553
2554 if (reply_skb) {
2555 if (nla_put_u32(reply_skb,
2556 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_NUM_CHANNELS,
2557 num_channels) ||
2558 nla_put(reply_skb,
2559 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CHANNELS,
2560 sizeof(u32) * num_channels, chan_list)) {
2561 hddLog(LOGE, FL("nla put fail"));
2562 kfree_skb(reply_skb);
2563 return -EINVAL;
2564 }
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05302565 ret = cfg80211_vendor_cmd_reply(reply_skb);
2566 EXIT();
2567 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002568 }
2569
2570 hddLog(LOGE, FL("valid channels: buffer alloc fail"));
2571 return -EINVAL;
2572}
2573
2574/**
2575 * wlan_hdd_cfg80211_extscan_get_valid_channels() - get ext scan valid channels
2576 * @wiphy: Pointer to wireless phy
2577 * @wdev: Pointer to wireless device
2578 * @data: Pointer to data
2579 * @data_len: Data length
2580 *
2581 * Return: 0 on success, negative errno on failure
2582 */
2583int wlan_hdd_cfg80211_extscan_get_valid_channels(struct wiphy *wiphy,
2584 struct wireless_dev *wdev,
2585 const void *data, int data_len)
2586{
2587 int ret = 0;
2588
2589 cds_ssr_protect(__func__);
2590 ret = __wlan_hdd_cfg80211_extscan_get_valid_channels(wiphy, wdev, data,
2591 data_len);
2592 cds_ssr_unprotect(__func__);
2593
2594 return ret;
2595}
2596
2597/**
2598 * hdd_extscan_update_dwell_time_limits() - update dwell times
2599 * @req_msg: Pointer to request message
2600 * @bkt_idx: Index of current bucket being processed
2601 * @active_min: minimum active dwell time
2602 * @active_max: maximum active dwell time
2603 * @passive_min: minimum passive dwell time
2604 * @passive_max: maximum passive dwell time
2605 *
2606 * Return: none
2607 */
2608static void hdd_extscan_update_dwell_time_limits(
2609 tpSirWifiScanCmdReqParams req_msg, uint32_t bkt_idx,
2610 uint32_t active_min, uint32_t active_max,
2611 uint32_t passive_min, uint32_t passive_max)
2612{
2613 /* update per-bucket dwell times */
2614 if (req_msg->buckets[bkt_idx].min_dwell_time_active >
2615 active_min) {
2616 req_msg->buckets[bkt_idx].min_dwell_time_active =
2617 active_min;
2618 }
2619 if (req_msg->buckets[bkt_idx].max_dwell_time_active <
2620 active_max) {
2621 req_msg->buckets[bkt_idx].max_dwell_time_active =
2622 active_max;
2623 }
2624 if (req_msg->buckets[bkt_idx].min_dwell_time_passive >
2625 passive_min) {
2626 req_msg->buckets[bkt_idx].min_dwell_time_passive =
2627 passive_min;
2628 }
2629 if (req_msg->buckets[bkt_idx].max_dwell_time_passive <
2630 passive_max) {
2631 req_msg->buckets[bkt_idx].max_dwell_time_passive =
2632 passive_max;
2633 }
2634 /* update dwell-time across all buckets */
2635 if (req_msg->min_dwell_time_active >
2636 req_msg->buckets[bkt_idx].min_dwell_time_active) {
2637 req_msg->min_dwell_time_active =
2638 req_msg->buckets[bkt_idx].min_dwell_time_active;
2639 }
2640 if (req_msg->max_dwell_time_active <
2641 req_msg->buckets[bkt_idx].max_dwell_time_active) {
2642 req_msg->max_dwell_time_active =
2643 req_msg->buckets[bkt_idx].max_dwell_time_active;
2644 }
2645 if (req_msg->min_dwell_time_passive >
2646 req_msg->buckets[bkt_idx].min_dwell_time_passive) {
2647 req_msg->min_dwell_time_passive =
2648 req_msg->buckets[bkt_idx].min_dwell_time_passive;
2649 }
2650 if (req_msg->max_dwell_time_passive >
2651 req_msg->buckets[bkt_idx].max_dwell_time_passive) {
2652 req_msg->max_dwell_time_passive =
2653 req_msg->buckets[bkt_idx].max_dwell_time_passive;
2654 }
2655}
2656
2657/**
2658 * hdd_extscan_channel_max_reached() - channel max reached
2659 * @req: extscan request structure
2660 * @total_channels: total number of channels
2661 *
2662 * Return: true if total channels reached max, false otherwise
2663 */
2664static bool hdd_extscan_channel_max_reached(tSirWifiScanCmdReqParams *req,
2665 uint8_t total_channels)
2666{
2667 if (total_channels == WLAN_EXTSCAN_MAX_CHANNELS) {
2668 hdd_warn(
2669 "max #of channels %d reached, take only first %d bucket(s)",
2670 total_channels, req->numBuckets);
2671 return true;
2672 }
2673 return false;
2674}
2675
2676/**
2677 * hdd_extscan_start_fill_bucket_channel_spec() - fill bucket channel spec
2678 * @hdd_ctx: HDD global context
2679 * @req_msg: Pointer to request structure
2680 * @tb: pointer to NL attributes
2681 *
2682 * Return: 0 on success; error number otherwise
2683 */
2684static int hdd_extscan_start_fill_bucket_channel_spec(
2685 hdd_context_t *hdd_ctx,
2686 tpSirWifiScanCmdReqParams req_msg,
2687 struct nlattr **tb)
2688{
2689 struct nlattr *bucket[
2690 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX + 1];
2691 struct nlattr *channel[
2692 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX + 1];
2693 struct nlattr *buckets;
2694 struct nlattr *channels;
2695 int rem1, rem2;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302696 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002697 uint8_t bkt_index, j, num_channels, total_channels = 0;
2698 uint32_t chan_list[WNI_CFG_VALID_CHANNEL_LIST_LEN] = {0};
2699
2700 uint32_t min_dwell_time_active_bucket =
2701 hdd_ctx->config->extscan_active_max_chn_time;
2702 uint32_t max_dwell_time_active_bucket =
2703 hdd_ctx->config->extscan_active_max_chn_time;
2704 uint32_t min_dwell_time_passive_bucket =
2705 hdd_ctx->config->extscan_passive_max_chn_time;
2706 uint32_t max_dwell_time_passive_bucket =
2707 hdd_ctx->config->extscan_passive_max_chn_time;
2708
2709 bkt_index = 0;
2710 req_msg->min_dwell_time_active =
2711 req_msg->max_dwell_time_active =
2712 hdd_ctx->config->extscan_active_max_chn_time;
2713
2714 req_msg->min_dwell_time_passive =
2715 req_msg->max_dwell_time_passive =
2716 hdd_ctx->config->extscan_passive_max_chn_time;
2717 req_msg->numBuckets = 0;
2718
2719 nla_for_each_nested(buckets,
2720 tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC], rem1) {
2721 if (nla_parse(bucket,
2722 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX,
2723 nla_data(buckets), nla_len(buckets), NULL)) {
2724 hddLog(LOGE, FL("nla_parse failed"));
2725 return -EINVAL;
2726 }
2727
2728 /* Parse and fetch bucket spec */
2729 if (!bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_INDEX]) {
2730 hddLog(LOGE, FL("attr bucket index failed"));
2731 return -EINVAL;
2732 }
2733 req_msg->buckets[bkt_index].bucket = nla_get_u8(
2734 bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_INDEX]);
2735 hddLog(LOG1, FL("Bucket spec Index %d"),
2736 req_msg->buckets[bkt_index].bucket);
2737
2738 /* Parse and fetch wifi band */
2739 if (!bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_BAND]) {
2740 hddLog(LOGE, FL("attr wifi band failed"));
2741 return -EINVAL;
2742 }
2743 req_msg->buckets[bkt_index].band = nla_get_u8(
2744 bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_BAND]);
2745 hddLog(LOG1, FL("Wifi band %d"),
2746 req_msg->buckets[bkt_index].band);
2747
2748 /* Parse and fetch period */
2749 if (!bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_PERIOD]) {
2750 hddLog(LOGE, FL("attr period failed"));
2751 return -EINVAL;
2752 }
2753 req_msg->buckets[bkt_index].period = nla_get_u32(
2754 bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_PERIOD]);
2755 hddLog(LOG1, FL("period %d"),
2756 req_msg->buckets[bkt_index].period);
2757
2758 /* Parse and fetch report events */
2759 if (!bucket[
2760 QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_REPORT_EVENTS]) {
2761 hddLog(LOGE, FL("attr report events failed"));
2762 return -EINVAL;
2763 }
2764 req_msg->buckets[bkt_index].reportEvents = nla_get_u8(
2765 bucket[
2766 QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_REPORT_EVENTS]);
2767 hddLog(LOG1, FL("report events %d"),
2768 req_msg->buckets[bkt_index].reportEvents);
2769
2770 /* Parse and fetch max period */
2771 if (!bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_MAX_PERIOD]) {
2772 hddLog(LOGE, FL("attr max period failed"));
2773 return -EINVAL;
2774 }
2775 req_msg->buckets[bkt_index].max_period = nla_get_u32(
2776 bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_MAX_PERIOD]);
2777 hddLog(LOG1, FL("max period %u"),
2778 req_msg->buckets[bkt_index].max_period);
2779
2780 /* Parse and fetch exponent */
2781 if (!bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_EXPONENT]) {
2782 hddLog(LOGE, FL("attr exponent failed"));
2783 return -EINVAL;
2784 }
2785 req_msg->buckets[bkt_index].exponent = nla_get_u32(
2786 bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_EXPONENT]);
2787 hddLog(LOG1, FL("exponent %u"),
2788 req_msg->buckets[bkt_index].exponent);
2789
2790 /* Parse and fetch step count */
2791 if (!bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_STEP_COUNT]) {
2792 hddLog(LOGE, FL("attr step count failed"));
2793 return -EINVAL;
2794 }
2795 req_msg->buckets[bkt_index].step_count = nla_get_u32(
2796 bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_STEP_COUNT]);
2797 hddLog(LOG1, FL("Step count %u"),
2798 req_msg->buckets[bkt_index].step_count);
2799
2800 /* start with known good values for bucket dwell times */
2801 req_msg->buckets[bkt_index].min_dwell_time_active =
2802 req_msg->buckets[bkt_index].max_dwell_time_active =
2803 hdd_ctx->config->extscan_active_max_chn_time;
2804
2805 req_msg->buckets[bkt_index].min_dwell_time_passive =
2806 req_msg->buckets[bkt_index].max_dwell_time_passive =
2807 hdd_ctx->config->extscan_passive_max_chn_time;
2808
2809 /* Framework shall pass the channel list if the input WiFi band
2810 * is WIFI_BAND_UNSPECIFIED.
2811 * If the input WiFi band is specified (any value other than
2812 * WIFI_BAND_UNSPECIFIED) then driver populates the channel list
2813 */
2814 if (req_msg->buckets[bkt_index].band != WIFI_BAND_UNSPECIFIED) {
2815 if (hdd_extscan_channel_max_reached(req_msg,
2816 total_channels))
2817 return 0;
2818
2819 num_channels = 0;
2820 hddLog(LOG1, "WiFi band is specified, driver to fill channel list");
2821 status = sme_get_valid_channels_by_band(hdd_ctx->hHal,
2822 req_msg->buckets[bkt_index].band,
2823 chan_list, &num_channels);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302824 if (!QDF_IS_STATUS_SUCCESS(status)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002825 hddLog(LOGE,
2826 FL("sme_GetValidChannelsByBand failed (err=%d)"),
2827 status);
2828 return -EINVAL;
2829 }
2830 hddLog(LOG1, FL("before trimming, num_channels: %d"),
2831 num_channels);
2832
2833 req_msg->buckets[bkt_index].numChannels =
Anurag Chouhan6d760662016-02-20 16:05:43 +05302834 QDF_MIN(num_channels,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002835 (WLAN_EXTSCAN_MAX_CHANNELS -
2836 total_channels));
2837 hdd_info("Adj Num channels/bucket: %d total_channels: %d",
2838 req_msg->buckets[bkt_index].numChannels,
2839 total_channels);
2840 total_channels +=
2841 req_msg->buckets[bkt_index].numChannels;
2842
2843 for (j = 0; j < req_msg->buckets[bkt_index].numChannels;
2844 j++) {
2845 req_msg->buckets[bkt_index].channels[j].channel =
2846 chan_list[j];
2847 req_msg->buckets[bkt_index].channels[j].
2848 chnlClass = 0;
2849 if (CDS_IS_PASSIVE_OR_DISABLE_CH(
2850 cds_freq_to_chan(chan_list[j]))) {
2851 req_msg->buckets[bkt_index].channels[j].
2852 passive = 1;
2853 req_msg->buckets[bkt_index].channels[j].
2854 dwellTimeMs =
2855 hdd_ctx->config->
2856 extscan_passive_max_chn_time;
2857 /* reconfigure per-bucket dwell time */
2858 if (min_dwell_time_passive_bucket >
2859 req_msg->buckets[bkt_index].channels[j].dwellTimeMs) {
2860 min_dwell_time_passive_bucket =
2861 req_msg->buckets[bkt_index].channels[j].dwellTimeMs;
2862 }
2863 if (max_dwell_time_passive_bucket <
2864 req_msg->buckets[bkt_index].channels[j].dwellTimeMs) {
2865 max_dwell_time_passive_bucket =
2866 req_msg->buckets[bkt_index].channels[j].dwellTimeMs;
2867 }
2868
2869 } else {
2870 req_msg->buckets[bkt_index].channels[j].
2871 passive = 0;
2872 req_msg->buckets[bkt_index].channels[j].
2873 dwellTimeMs =
2874 hdd_ctx->config->extscan_active_max_chn_time;
2875 /* reconfigure per-bucket dwell times */
2876 if (min_dwell_time_active_bucket >
2877 req_msg->buckets[bkt_index].channels[j].dwellTimeMs) {
2878 min_dwell_time_active_bucket =
2879 req_msg->buckets[bkt_index].channels[j].dwellTimeMs;
2880 }
2881 if (max_dwell_time_active_bucket <
2882 req_msg->buckets[bkt_index].channels[j].dwellTimeMs) {
2883 max_dwell_time_active_bucket =
2884 req_msg->buckets[bkt_index].channels[j].dwellTimeMs;
2885 }
2886
2887 }
2888
2889 hddLog(LOG1,
2890 "Channel: %u Passive: %u Dwell time: %u ms Class: %u",
2891 req_msg->buckets[bkt_index].channels[j].channel,
2892 req_msg->buckets[bkt_index].channels[j].passive,
2893 req_msg->buckets[bkt_index].channels[j].dwellTimeMs,
2894 req_msg->buckets[bkt_index].channels[j].chnlClass);
2895 }
2896
2897 hdd_extscan_update_dwell_time_limits(
2898 req_msg, bkt_index,
2899 min_dwell_time_active_bucket,
2900 max_dwell_time_active_bucket,
2901 min_dwell_time_passive_bucket,
2902 max_dwell_time_passive_bucket);
2903
2904 hddLog(LOG1, FL("bkt_index:%d actv_min:%d actv_max:%d pass_min:%d pass_max:%d"),
2905 bkt_index,
2906 req_msg->buckets[bkt_index].min_dwell_time_active,
2907 req_msg->buckets[bkt_index].max_dwell_time_active,
2908 req_msg->buckets[bkt_index].min_dwell_time_passive,
2909 req_msg->buckets[bkt_index].max_dwell_time_passive);
2910
2911 bkt_index++;
2912 req_msg->numBuckets++;
2913 continue;
2914 }
2915
2916 /* Parse and fetch number of channels */
2917 if (!bucket[
2918 QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_NUM_CHANNEL_SPECS]) {
2919 hddLog(LOGE, FL("attr num channels failed"));
2920 return -EINVAL;
2921 }
2922 req_msg->buckets[bkt_index].numChannels =
2923 nla_get_u32(bucket[
2924 QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_NUM_CHANNEL_SPECS]);
2925 hdd_info("before trimming: num channels %d",
2926 req_msg->buckets[bkt_index].numChannels);
2927
2928 req_msg->buckets[bkt_index].numChannels =
Anurag Chouhan6d760662016-02-20 16:05:43 +05302929 QDF_MIN(req_msg->buckets[bkt_index].numChannels,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002930 (WLAN_EXTSCAN_MAX_CHANNELS - total_channels));
2931 hdd_info("Num channels/bucket: %d total_channels: %d",
2932 req_msg->buckets[bkt_index].numChannels,
2933 total_channels);
2934 if (hdd_extscan_channel_max_reached(req_msg, total_channels))
2935 return 0;
2936
2937 if (!bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC]) {
2938 hddLog(LOGE, FL("attr channel spec failed"));
2939 return -EINVAL;
2940 }
2941
2942 j = 0;
2943 nla_for_each_nested(channels,
2944 bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC], rem2) {
Jeff Johnson56951332015-10-29 11:26:02 -07002945 if ((j >= req_msg->buckets[bkt_index].numChannels) ||
2946 hdd_extscan_channel_max_reached(req_msg,
2947 total_channels))
2948 break;
2949
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002950 if (nla_parse(channel,
2951 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX,
2952 nla_data(channels), nla_len(channels),
2953 wlan_hdd_extscan_config_policy)) {
2954 hddLog(LOGE, FL("nla_parse failed"));
2955 return -EINVAL;
2956 }
2957
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002958 /* Parse and fetch channel */
2959 if (!channel[
2960 QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_CHANNEL]) {
2961 hddLog(LOGE, FL("attr channel failed"));
2962 return -EINVAL;
2963 }
2964 req_msg->buckets[bkt_index].channels[j].channel =
2965 nla_get_u32(channel[
2966 QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_CHANNEL]);
2967 hddLog(LOG1, FL("channel %u"),
2968 req_msg->buckets[bkt_index].channels[j].channel);
2969
2970 /* Parse and fetch dwell time */
2971 if (!channel[
2972 QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_DWELL_TIME]) {
2973 hddLog(LOGE, FL("attr dwelltime failed"));
2974 return -EINVAL;
2975 }
2976 req_msg->buckets[bkt_index].channels[j].dwellTimeMs =
2977 nla_get_u32(channel[
2978 QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_DWELL_TIME]);
2979
2980 /* Override dwell time if required */
2981 if (req_msg->buckets[bkt_index].channels[j].dwellTimeMs <
2982 hdd_ctx->config->extscan_active_min_chn_time ||
2983 req_msg->buckets[bkt_index].channels[j].dwellTimeMs >
2984 hdd_ctx->config->extscan_active_max_chn_time) {
2985 hddLog(LOG1, FL("WiFi band is unspecified, dwellTime:%d"),
2986 req_msg->buckets[bkt_index].channels[j].dwellTimeMs);
2987
2988 if (CDS_IS_PASSIVE_OR_DISABLE_CH(
2989 cds_freq_to_chan(
2990 req_msg->buckets[bkt_index].channels[j].channel))) {
2991 req_msg->buckets[bkt_index].channels[j].dwellTimeMs =
2992 hdd_ctx->config->extscan_passive_max_chn_time;
2993 } else {
2994 req_msg->buckets[bkt_index].channels[j].dwellTimeMs =
2995 hdd_ctx->config->extscan_active_max_chn_time;
2996 }
2997 }
2998
2999 hddLog(LOG1, FL("New Dwell time %u ms"),
3000 req_msg->buckets[bkt_index].channels[j].dwellTimeMs);
3001
3002 if (CDS_IS_PASSIVE_OR_DISABLE_CH(
3003 cds_freq_to_chan(
3004 req_msg->buckets[bkt_index].channels[j].channel))) {
3005 if (min_dwell_time_passive_bucket >
3006 req_msg->buckets[bkt_index].channels[j].dwellTimeMs) {
3007 min_dwell_time_passive_bucket =
3008 req_msg->buckets[bkt_index].channels[j].dwellTimeMs;
3009 }
3010 if (max_dwell_time_passive_bucket <
3011 req_msg->buckets[bkt_index].channels[j].dwellTimeMs) {
3012 max_dwell_time_passive_bucket =
3013 req_msg->buckets[bkt_index].channels[j].dwellTimeMs;
3014 }
3015 } else {
3016 if (min_dwell_time_active_bucket >
3017 req_msg->buckets[bkt_index].channels[j].dwellTimeMs) {
3018 min_dwell_time_active_bucket =
3019 req_msg->buckets[bkt_index].channels[j].dwellTimeMs;
3020 }
3021 if (max_dwell_time_active_bucket <
3022 req_msg->buckets[bkt_index].channels[j].dwellTimeMs) {
3023 max_dwell_time_active_bucket =
3024 req_msg->buckets[bkt_index].channels[j].dwellTimeMs;
3025 }
3026 }
3027
3028 /* Parse and fetch channel spec passive */
3029 if (!channel[
3030 QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_PASSIVE]) {
3031 hddLog(LOGE,
3032 FL("attr channel spec passive failed"));
3033 return -EINVAL;
3034 }
3035 req_msg->buckets[bkt_index].channels[j].passive =
3036 nla_get_u8(channel[
3037 QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_PASSIVE]);
3038 hddLog(LOG1, FL("Chnl spec passive %u"),
3039 req_msg->buckets[bkt_index].channels[j].passive);
3040 /* Override scan type if required */
3041 if (CDS_IS_PASSIVE_OR_DISABLE_CH(
3042 cds_freq_to_chan(
3043 req_msg->buckets[bkt_index].channels[j].channel))) {
3044 req_msg->buckets[bkt_index].channels[j].passive = true;
3045 } else {
3046 req_msg->buckets[bkt_index].channels[j].passive = false;
3047 }
3048 j++;
3049 total_channels++;
3050 }
3051
3052 hdd_extscan_update_dwell_time_limits(
3053 req_msg, bkt_index,
3054 min_dwell_time_active_bucket,
3055 max_dwell_time_active_bucket,
3056 min_dwell_time_passive_bucket,
3057 max_dwell_time_passive_bucket);
3058
3059 hddLog(LOG1, FL("bktIndex:%d actv_min:%d actv_max:%d pass_min:%d pass_max:%d"),
3060 bkt_index,
3061 req_msg->buckets[bkt_index].min_dwell_time_active,
3062 req_msg->buckets[bkt_index].max_dwell_time_active,
3063 req_msg->buckets[bkt_index].min_dwell_time_passive,
3064 req_msg->buckets[bkt_index].max_dwell_time_passive);
3065
3066 bkt_index++;
3067 req_msg->numBuckets++;
3068 }
3069
3070 hddLog(LOG1, FL("Global: actv_min:%d actv_max:%d pass_min:%d pass_max:%d"),
3071 req_msg->min_dwell_time_active,
3072 req_msg->max_dwell_time_active,
3073 req_msg->min_dwell_time_passive,
3074 req_msg->max_dwell_time_passive);
3075
3076 return 0;
3077}
3078
3079/*
3080 * hdd_extscan_map_usr_drv_config_flags() - map userspace to driver config flags
3081 * @config_flags - [input] configuration flags.
3082 *
3083 * This function maps user space received configuration flags to
3084 * driver representation.
3085 *
3086 * Return: configuration flags
3087 */
3088static uint32_t hdd_extscan_map_usr_drv_config_flags(uint32_t config_flags)
3089{
3090 uint32_t configuration_flags = 0;
3091
3092 if (config_flags & EXTSCAN_LP_EXTENDED_BATCHING)
3093 configuration_flags |= EXTSCAN_LP_EXTENDED_BATCHING;
3094
3095 return configuration_flags;
3096}
3097
3098/*
3099 * define short names for the global vendor params
3100 * used by __wlan_hdd_cfg80211_extscan_start()
3101 */
3102#define PARAM_MAX \
3103 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX
3104#define PARAM_REQUEST_ID \
3105 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID
3106#define PARAM_BASE_PERIOD \
3107 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_BASE_PERIOD
3108#define PARAM_MAX_AP_PER_SCAN \
3109 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_MAX_AP_PER_SCAN
3110#define PARAM_RPT_THRHLD_PERCENT \
3111 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_REPORT_THRESHOLD_PERCENT
3112#define PARAM_RPT_THRHLD_NUM_SCANS \
3113 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_REPORT_THRESHOLD_NUM_SCANS
3114#define PARAM_NUM_BUCKETS \
3115 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_NUM_BUCKETS
3116#define PARAM_CONFIG_FLAGS \
3117 QCA_WLAN_VENDOR_ATTR_EXTSCAN_CONFIGURATION_FLAGS
3118
3119/**
3120 * __wlan_hdd_cfg80211_extscan_start() - ext scan start
3121 * @wiphy: Pointer to wireless phy
3122 * @wdev: Pointer to wireless device
3123 * @data: Pointer to data
3124 * @data_len: Length of @data
3125 *
3126 * Return: 0 on success; error number otherwise
3127 */
3128static int
3129__wlan_hdd_cfg80211_extscan_start(struct wiphy *wiphy,
3130 struct wireless_dev *wdev,
3131 const void *data,
3132 int data_len)
3133{
3134 tpSirWifiScanCmdReqParams pReqMsg = NULL;
3135 struct net_device *dev = wdev->netdev;
3136 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
3137 hdd_context_t *pHddCtx = wiphy_priv(wiphy);
3138 struct nlattr *tb[PARAM_MAX + 1];
3139 struct hdd_ext_scan_context *context;
3140 uint32_t request_id, num_buckets;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303141 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003142 int retval;
3143 unsigned long rc;
3144
Jeff Johnson1f61b612016-02-12 16:28:33 -08003145 ENTER_DEV(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003146
Anurag Chouhan6d760662016-02-20 16:05:43 +05303147 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003148 hdd_err("Command not allowed in FTM mode");
3149 return -EPERM;
3150 }
3151
3152 retval = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05303153 if (0 != retval)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003154 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003155
3156 if (nla_parse(tb, PARAM_MAX, data, data_len,
3157 wlan_hdd_extscan_config_policy)) {
3158 hddLog(LOGE, FL("Invalid ATTR"));
3159 return -EINVAL;
3160 }
3161
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303162 pReqMsg = qdf_mem_malloc(sizeof(*pReqMsg));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003163 if (!pReqMsg) {
3164 hddLog(LOGE, FL("memory allocation failed"));
3165 return -ENOMEM;
3166 }
3167
3168 /* Parse and fetch request Id */
3169 if (!tb[PARAM_REQUEST_ID]) {
3170 hddLog(LOGE, FL("attr request id failed"));
3171 goto fail;
3172 }
3173
3174 pReqMsg->requestId = nla_get_u32(tb[PARAM_REQUEST_ID]);
3175 pReqMsg->sessionId = pAdapter->sessionId;
3176 hddLog(LOG1, FL("Req Id %d Session Id %d"),
3177 pReqMsg->requestId,
3178 pReqMsg->sessionId);
3179
3180 /* Parse and fetch base period */
3181 if (!tb[PARAM_BASE_PERIOD]) {
3182 hddLog(LOGE, FL("attr base period failed"));
3183 goto fail;
3184 }
3185 pReqMsg->basePeriod = nla_get_u32(tb[PARAM_BASE_PERIOD]);
3186 hddLog(LOG1, FL("Base Period %d"),
3187 pReqMsg->basePeriod);
3188
3189 /* Parse and fetch max AP per scan */
3190 if (!tb[PARAM_MAX_AP_PER_SCAN]) {
3191 hddLog(LOGE, FL("attr max_ap_per_scan failed"));
3192 goto fail;
3193 }
3194 pReqMsg->maxAPperScan = nla_get_u32(tb[PARAM_MAX_AP_PER_SCAN]);
3195 hddLog(LOG1, FL("Max AP per Scan %d"), pReqMsg->maxAPperScan);
3196
3197 /* Parse and fetch report threshold percent */
3198 if (!tb[PARAM_RPT_THRHLD_PERCENT]) {
3199 hddLog(LOGE, FL("attr report_threshold percent failed"));
3200 goto fail;
3201 }
3202 pReqMsg->report_threshold_percent = nla_get_u8(tb[PARAM_RPT_THRHLD_PERCENT]);
3203 hddLog(LOG1, FL("Report Threshold percent %d"),
3204 pReqMsg->report_threshold_percent);
3205
3206 /* Parse and fetch report threshold num scans */
3207 if (!tb[PARAM_RPT_THRHLD_NUM_SCANS]) {
3208 hddLog(LOGE, FL("attr report_threshold num scans failed"));
3209 goto fail;
3210 }
3211 pReqMsg->report_threshold_num_scans = nla_get_u8(tb[PARAM_RPT_THRHLD_NUM_SCANS]);
3212 hddLog(LOG1, FL("Report Threshold num scans %d"),
3213 pReqMsg->report_threshold_num_scans);
3214
3215 /* Parse and fetch number of buckets */
3216 if (!tb[PARAM_NUM_BUCKETS]) {
3217 hddLog(LOGE, FL("attr number of buckets failed"));
3218 goto fail;
3219 }
3220 num_buckets = nla_get_u8(tb[PARAM_NUM_BUCKETS]);
3221 if (num_buckets > WLAN_EXTSCAN_MAX_BUCKETS) {
3222 hdd_warn("Exceeded MAX number of buckets: %d",
3223 WLAN_EXTSCAN_MAX_BUCKETS);
3224 }
3225 hdd_info("Input: Number of Buckets %d", num_buckets);
3226
3227 /* This is optional attribute, if not present set it to 0 */
3228 if (!tb[PARAM_CONFIG_FLAGS])
3229 pReqMsg->configuration_flags = 0;
3230 else
3231 pReqMsg->configuration_flags =
3232 hdd_extscan_map_usr_drv_config_flags(
3233 nla_get_u32(tb[PARAM_CONFIG_FLAGS]));
3234
3235 hddLog(LOG1, FL("Configuration flags: %u"),
3236 pReqMsg->configuration_flags);
3237
3238 if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC]) {
3239 hddLog(LOGE, FL("attr bucket spec failed"));
3240 goto fail;
3241 }
3242
3243 if (hdd_extscan_start_fill_bucket_channel_spec(pHddCtx, pReqMsg, tb))
3244 goto fail;
3245
3246 context = &ext_scan_context;
3247 spin_lock(&context->context_lock);
3248 INIT_COMPLETION(context->response_event);
3249 context->request_id = request_id = pReqMsg->requestId;
3250 spin_unlock(&context->context_lock);
3251
3252 status = sme_ext_scan_start(pHddCtx->hHal, pReqMsg);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303253 if (!QDF_IS_STATUS_SUCCESS(status)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003254 hddLog(LOGE,
3255 FL("sme_ext_scan_start failed(err=%d)"), status);
3256 goto fail;
3257 }
3258
Anurag Chouhan50220ce2016-02-18 20:11:33 +05303259 pHddCtx->ext_scan_start_since_boot = qdf_get_monotonic_boottime();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003260 hddLog(LOG1, FL("Timestamp since boot: %llu"),
3261 pHddCtx->ext_scan_start_since_boot);
3262
3263 /* request was sent -- wait for the response */
3264 rc = wait_for_completion_timeout(&context->response_event,
3265 msecs_to_jiffies(WLAN_WAIT_TIME_EXTSCAN));
3266
3267 if (!rc) {
3268 hddLog(LOGE, FL("sme_ext_scan_start timed out"));
3269 retval = -ETIMEDOUT;
3270 } else {
3271 spin_lock(&context->context_lock);
3272 if (context->request_id == request_id)
3273 retval = context->response_status;
3274 else
3275 retval = -EINVAL;
3276 spin_unlock(&context->context_lock);
3277 }
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05303278 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003279 return retval;
3280
3281fail:
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303282 qdf_mem_free(pReqMsg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003283 return -EINVAL;
3284}
3285/*
3286 * done with short names for the global vendor params
3287 * used by __wlan_hdd_cfg80211_extscan_start()
3288 */
3289#undef PARAM_MAX
3290#undef PARAM_REQUEST_ID
3291#undef PARAM_BASE_PERIOD
3292#undef PARAMS_MAX_AP_PER_SCAN
3293#undef PARAMS_RPT_THRHLD_PERCENT
3294#undef PARAMS_RPT_THRHLD_NUM_SCANS
3295#undef PARAMS_NUM_BUCKETS
3296#undef PARAM_CONFIG_FLAGS
3297
3298/**
3299 * wlan_hdd_cfg80211_extscan_start() - start extscan
3300 * @wiphy: Pointer to wireless phy.
3301 * @wdev: Pointer to wireless device.
3302 * @data: Pointer to input data.
3303 * @data_len: Length of @data.
3304 *
3305 * Return: 0 on success, negative errno on failure
3306 */
3307int wlan_hdd_cfg80211_extscan_start(struct wiphy *wiphy,
3308 struct wireless_dev *wdev,
3309 const void *data, int data_len)
3310{
3311 int ret = 0;
3312
3313 cds_ssr_protect(__func__);
3314 ret = __wlan_hdd_cfg80211_extscan_start(wiphy, wdev, data, data_len);
3315 cds_ssr_unprotect(__func__);
3316
3317 return ret;
3318}
3319
3320
3321/*
3322 * define short names for the global vendor params
3323 * used by __wlan_hdd_cfg80211_extscan_stop()
3324 */
3325#define PARAM_MAX \
3326 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX
3327#define PARAM_REQUEST_ID \
3328 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID
3329
3330/**
3331 * __wlan_hdd_cfg80211_extscan_stop() - ext scan stop
3332 * @wiphy: Pointer to wireless phy
3333 * @wdev: Pointer to wireless device
3334 * @data: Pointer to data
3335 * @data_len: Data length
3336 *
3337 * Return: none
3338 */
3339static int
3340__wlan_hdd_cfg80211_extscan_stop(struct wiphy *wiphy,
3341 struct wireless_dev *wdev,
3342 const void *data, int data_len)
3343{
3344 tpSirExtScanStopReqParams pReqMsg = NULL;
3345 struct net_device *dev = wdev->netdev;
3346 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
3347 hdd_context_t *pHddCtx = wiphy_priv(wiphy);
3348 struct nlattr *tb[PARAM_MAX + 1];
3349 struct hdd_ext_scan_context *context;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303350 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003351 uint32_t request_id;
3352 int retval;
3353 unsigned long rc;
3354
Jeff Johnson1f61b612016-02-12 16:28:33 -08003355 ENTER_DEV(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003356
Anurag Chouhan6d760662016-02-20 16:05:43 +05303357 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003358 hdd_err("Command not allowed in FTM mode");
3359 return -EPERM;
3360 }
3361
3362 retval = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05303363 if (0 != retval)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003364 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003365
3366 if (nla_parse(tb, PARAM_MAX, data, data_len,
3367 wlan_hdd_extscan_config_policy)) {
3368 hddLog(LOGE, FL("Invalid ATTR"));
3369 return -EINVAL;
3370 }
3371
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303372 pReqMsg = qdf_mem_malloc(sizeof(*pReqMsg));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003373 if (!pReqMsg) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303374 hddLog(LOGE, FL("qdf_mem_malloc failed"));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003375 return -ENOMEM;
3376 }
3377
3378 /* Parse and fetch request Id */
3379 if (!tb[PARAM_REQUEST_ID]) {
3380 hddLog(LOGE, FL("attr request id failed"));
3381 goto fail;
3382 }
3383
3384 pReqMsg->requestId = nla_get_u32(tb[PARAM_REQUEST_ID]);
3385 pReqMsg->sessionId = pAdapter->sessionId;
3386 hddLog(LOG1, FL("Req Id %d Session Id %d"),
3387 pReqMsg->requestId, pReqMsg->sessionId);
3388
3389 context = &ext_scan_context;
3390 spin_lock(&context->context_lock);
3391 INIT_COMPLETION(context->response_event);
3392 context->request_id = request_id = pReqMsg->requestId;
3393 spin_unlock(&context->context_lock);
3394
3395 status = sme_ext_scan_stop(pHddCtx->hHal, pReqMsg);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303396 if (!QDF_IS_STATUS_SUCCESS(status)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003397 hddLog(LOGE,
3398 FL("sme_ext_scan_stop failed(err=%d)"), status);
3399 goto fail;
3400 }
3401
3402 /* request was sent -- wait for the response */
3403 rc = wait_for_completion_timeout(&context->response_event,
3404 msecs_to_jiffies(WLAN_WAIT_TIME_EXTSCAN));
3405
3406 if (!rc) {
3407 hddLog(LOGE, FL("sme_ext_scan_stop timed out"));
3408 retval = -ETIMEDOUT;
3409 } else {
3410 spin_lock(&context->context_lock);
3411 if (context->request_id == request_id)
3412 retval = context->response_status;
3413 else
3414 retval = -EINVAL;
3415 spin_unlock(&context->context_lock);
3416 }
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05303417 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003418 return retval;
3419
3420fail:
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303421 qdf_mem_free(pReqMsg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003422 return -EINVAL;
3423}
3424/*
3425 * done with short names for the global vendor params
3426 * used by wlan_hdd_cfg80211_extscan_stop()
3427 */
3428#undef PARAM_MAX
3429#undef PARAM_REQUEST_ID
3430
3431
3432/**
3433 * wlan_hdd_cfg80211_extscan_stop() - stop extscan
3434 * @wiphy: Pointer to wireless phy.
3435 * @wdev: Pointer to wireless device.
3436 * @data: Pointer to input data.
3437 * @data_len: Length of @data.
3438 *
3439 * Return: 0 on success, negative errno on failure
3440 */
3441int wlan_hdd_cfg80211_extscan_stop(struct wiphy *wiphy,
3442 struct wireless_dev *wdev,
3443 const void *data, int data_len)
3444{
3445 int ret = 0;
3446
3447 cds_ssr_protect(__func__);
3448 ret = __wlan_hdd_cfg80211_extscan_stop(wiphy, wdev, data, data_len);
3449 cds_ssr_unprotect(__func__);
3450
3451 return ret;
3452}
3453
3454
3455/**
3456 * __wlan_hdd_cfg80211_extscan_reset_bssid_hotlist() - reset bssid hotlist
3457 * @wiphy: Pointer to wireless phy
3458 * @wdev: Pointer to wireless device
3459 * @data: Pointer to data
3460 * @data_len: Data length
3461 *
3462 * Return: none
3463 */
3464static int
3465__wlan_hdd_cfg80211_extscan_reset_bssid_hotlist(struct wiphy *wiphy,
3466 struct wireless_dev
3467 *wdev, const void *data,
3468 int data_len)
3469{
3470 tpSirExtScanResetBssidHotlistReqParams pReqMsg = NULL;
3471 struct net_device *dev = wdev->netdev;
3472 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
3473 hdd_context_t *pHddCtx = wiphy_priv(wiphy);
3474 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX +
3475 1];
3476 struct hdd_ext_scan_context *context;
3477 uint32_t request_id;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303478 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003479 int retval;
3480 unsigned long rc;
3481
Jeff Johnson1f61b612016-02-12 16:28:33 -08003482 ENTER_DEV(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003483
Anurag Chouhan6d760662016-02-20 16:05:43 +05303484 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003485 hdd_err("Command not allowed in FTM mode");
3486 return -EPERM;
3487 }
3488
3489 retval = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05303490 if (0 != retval)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003491 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003492
3493 if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX,
3494 data, data_len, wlan_hdd_extscan_config_policy)) {
3495 hddLog(LOGE, FL("Invalid ATTR"));
3496 return -EINVAL;
3497 }
3498
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303499 pReqMsg = qdf_mem_malloc(sizeof(*pReqMsg));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003500 if (!pReqMsg) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303501 hddLog(LOGE, FL("qdf_mem_malloc failed"));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003502 return -ENOMEM;
3503 }
3504
3505 /* Parse and fetch request Id */
3506 if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]) {
3507 hddLog(LOGE, FL("attr request id failed"));
3508 goto fail;
3509 }
3510
3511 pReqMsg->requestId =
3512 nla_get_u32(tb
3513 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]);
3514 pReqMsg->sessionId = pAdapter->sessionId;
3515 hddLog(LOG1, FL("Req Id %d Session Id %d"),
3516 pReqMsg->requestId, pReqMsg->sessionId);
3517
3518 context = &ext_scan_context;
3519 spin_lock(&context->context_lock);
3520 INIT_COMPLETION(context->response_event);
3521 context->request_id = request_id = pReqMsg->requestId;
3522 spin_unlock(&context->context_lock);
3523
3524 status = sme_reset_bss_hotlist(pHddCtx->hHal, pReqMsg);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303525 if (!QDF_IS_STATUS_SUCCESS(status)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003526 hddLog(LOGE,
3527 FL("sme_reset_bss_hotlist failed(err=%d)"), status);
3528 goto fail;
3529 }
3530
3531 /* request was sent -- wait for the response */
3532 rc = wait_for_completion_timeout
3533 (&context->response_event,
3534 msecs_to_jiffies(WLAN_WAIT_TIME_EXTSCAN));
3535 if (!rc) {
3536 hddLog(LOGE, FL("sme_reset_bss_hotlist timed out"));
3537 retval = -ETIMEDOUT;
3538 } else {
3539 spin_lock(&context->context_lock);
3540 if (context->request_id == request_id)
3541 retval = context->response_status;
3542 else
3543 retval = -EINVAL;
3544 spin_unlock(&context->context_lock);
3545 }
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05303546 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003547 return retval;
3548
3549fail:
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303550 qdf_mem_free(pReqMsg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003551 return -EINVAL;
3552}
3553
3554/**
3555 * wlan_hdd_cfg80211_extscan_reset_bssid_hotlist() - reset bssid hot list
3556 * @wiphy: Pointer to wireless phy
3557 * @wdev: Pointer to wireless device
3558 * @data: Pointer to data
3559 * @data_len: Data length
3560 *
3561 * Return: 0 on success, negative errno on failure
3562 */
3563int wlan_hdd_cfg80211_extscan_reset_bssid_hotlist(struct wiphy *wiphy,
3564 struct wireless_dev *wdev,
3565 const void *data, int data_len)
3566{
3567 int ret = 0;
3568
3569 cds_ssr_protect(__func__);
3570 ret = __wlan_hdd_cfg80211_extscan_reset_bssid_hotlist(wiphy, wdev,
3571 data, data_len);
3572 cds_ssr_unprotect(__func__);
3573
3574 return ret;
3575}
3576
3577/**
3578 * __wlan_hdd_cfg80211_extscan_reset_significant_change() -
3579 * reset significant change
3580 * @wiphy: Pointer to wireless phy
3581 * @wdev: Pointer to wireless device
3582 * @data: Pointer to data
3583 * @data_len: Data length
3584 *
3585 * Return: none
3586 */
3587static int
3588__wlan_hdd_cfg80211_extscan_reset_significant_change(struct wiphy
3589 *wiphy,
3590 struct
3591 wireless_dev
3592 *wdev, const void *data,
3593 int data_len)
3594{
3595 tpSirExtScanResetSignificantChangeReqParams pReqMsg = NULL;
3596 struct net_device *dev = wdev->netdev;
3597 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
3598 hdd_context_t *pHddCtx = wiphy_priv(wiphy);
3599 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX +
3600 1];
3601 struct hdd_ext_scan_context *context;
3602 uint32_t request_id;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303603 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003604 int retval;
3605 unsigned long rc;
3606
Jeff Johnson1f61b612016-02-12 16:28:33 -08003607 ENTER_DEV(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003608
Anurag Chouhan6d760662016-02-20 16:05:43 +05303609 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003610 hdd_err("Command not allowed in FTM mode");
3611 return -EPERM;
3612 }
3613
3614 retval = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05303615 if (0 != retval)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003616 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003617
3618 if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX,
3619 data, data_len, wlan_hdd_extscan_config_policy)) {
3620 hddLog(LOGE, FL("Invalid ATTR"));
3621 return -EINVAL;
3622 }
3623
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303624 pReqMsg = qdf_mem_malloc(sizeof(*pReqMsg));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003625 if (!pReqMsg) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303626 hddLog(LOGE, FL("qdf_mem_malloc failed"));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003627 return -ENOMEM;
3628 }
3629
3630 /* Parse and fetch request Id */
3631 if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]) {
3632 hddLog(LOGE, FL("attr request id failed"));
3633 goto fail;
3634 }
3635
3636 pReqMsg->requestId =
3637 nla_get_u32(tb
3638 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]);
3639 pReqMsg->sessionId = pAdapter->sessionId;
3640 hddLog(LOG1, FL("Req Id %d Session Id %d"),
3641 pReqMsg->requestId, pReqMsg->sessionId);
3642
3643 context = &ext_scan_context;
3644 spin_lock(&context->context_lock);
3645 INIT_COMPLETION(context->response_event);
3646 context->request_id = request_id = pReqMsg->requestId;
3647 spin_unlock(&context->context_lock);
3648
3649 status = sme_reset_significant_change(pHddCtx->hHal, pReqMsg);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303650 if (!QDF_IS_STATUS_SUCCESS(status)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003651 hddLog(LOGE, FL("sme_reset_significant_change failed(err=%d)"),
3652 status);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303653 qdf_mem_free(pReqMsg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003654 return -EINVAL;
3655 }
3656
3657 /* request was sent -- wait for the response */
3658 rc = wait_for_completion_timeout(&context->response_event,
3659 msecs_to_jiffies(WLAN_WAIT_TIME_EXTSCAN));
3660
3661 if (!rc) {
3662 hddLog(LOGE, FL("sme_ResetSignificantChange timed out"));
3663 retval = -ETIMEDOUT;
3664 } else {
3665 spin_lock(&context->context_lock);
3666 if (context->request_id == request_id)
3667 retval = context->response_status;
3668 else
3669 retval = -EINVAL;
3670 spin_unlock(&context->context_lock);
3671 }
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05303672 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003673 return retval;
3674
3675fail:
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303676 qdf_mem_free(pReqMsg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003677 return -EINVAL;
3678}
3679
3680/**
3681 * wlan_hdd_cfg80211_extscan_reset_significant_change() - reset significant
3682 * change
3683 * @wiphy: Pointer to wireless phy
3684 * @wdev: Pointer to wireless device
3685 * @data: Pointer to data
3686 * @data_len: Data length
3687 *
3688 * Return: 0 on success, negative errno on failure
3689 */
3690int wlan_hdd_cfg80211_extscan_reset_significant_change(struct wiphy *wiphy,
3691 struct wireless_dev *wdev,
3692 const void *data, int data_len)
3693{
3694 int ret = 0;
3695
3696 cds_ssr_protect(__func__);
3697 ret = __wlan_hdd_cfg80211_extscan_reset_significant_change(wiphy, wdev,
3698 data, data_len);
3699 cds_ssr_unprotect(__func__);
3700
3701 return ret;
3702}
3703
3704
3705/**
3706 * hdd_extscan_epno_fill_network_list() - epno fill network list
3707 * @hddctx: HDD context
3708 * @req_msg: request message
3709 * @tb: vendor attribute table
3710 *
3711 * This function reads the network block NL vendor attributes from %tb and
3712 * fill in the epno request message.
3713 *
3714 * Return: 0 on success, error number otherwise
3715 */
3716static int hdd_extscan_epno_fill_network_list(
3717 hdd_context_t *hddctx,
3718 struct wifi_epno_params *req_msg,
3719 struct nlattr **tb)
3720{
3721 struct nlattr *network[
3722 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX + 1];
3723 struct nlattr *networks;
3724 int rem1, ssid_len;
3725 uint8_t index, *ssid;
3726
3727 index = 0;
3728 nla_for_each_nested(networks,
3729 tb[QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORKS_LIST],
3730 rem1) {
3731 if (nla_parse(network,
3732 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX,
3733 nla_data(networks), nla_len(networks), NULL)) {
3734 hddLog(LOGE, FL("nla_parse failed"));
3735 return -EINVAL;
3736 }
3737
3738 /* Parse and fetch ssid */
3739 if (!network[QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_SSID]) {
3740 hddLog(LOGE, FL("attr network ssid failed"));
3741 return -EINVAL;
3742 }
3743 ssid_len = nla_len(
3744 network[QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_SSID]);
3745
3746 /* Decrement by 1, don't count null character */
3747 ssid_len--;
3748
3749 req_msg->networks[index].ssid.length = ssid_len;
3750 hddLog(LOG1, FL("network ssid length %d"), ssid_len);
3751 ssid = nla_data(network[QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_SSID]);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303752 qdf_mem_copy(req_msg->networks[index].ssid.ssId,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003753 ssid, ssid_len);
3754 hddLog(LOG1, FL("Ssid (%.*s)"),
3755 req_msg->networks[index].ssid.length,
3756 req_msg->networks[index].ssid.ssId);
3757
3758 /* Parse and fetch rssi threshold */
3759 if (!network[QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_RSSI_THRESHOLD]) {
3760 hddLog(LOGE, FL("attr rssi threshold failed"));
3761 return -EINVAL;
3762 }
3763 req_msg->networks[index].rssi_threshold = nla_get_s8(
3764 network[QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_RSSI_THRESHOLD]);
3765 hddLog(LOG1, FL("rssi threshold %d"),
3766 req_msg->networks[index].rssi_threshold);
3767
3768 /* Parse and fetch epno flags */
3769 if (!network[QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_FLAGS]) {
3770 hddLog(LOGE, FL("attr epno flags failed"));
3771 return -EINVAL;
3772 }
3773 req_msg->networks[index].flags = nla_get_u8(
3774 network[QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_FLAGS]);
3775 hddLog(LOG1, FL("flags %u"), req_msg->networks[index].flags);
3776
3777 /* Parse and fetch auth bit */
3778 if (!network[QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_AUTH_BIT]) {
3779 hddLog(LOGE, FL("attr auth bit failed"));
3780 return -EINVAL;
3781 }
3782 req_msg->networks[index].auth_bit_field = nla_get_u8(
3783 network[QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_AUTH_BIT]);
3784 hddLog(LOG1, FL("auth bit %u"),
3785 req_msg->networks[index].auth_bit_field);
3786
3787 index++;
3788 }
3789 return 0;
3790}
3791
3792/**
3793 * __wlan_hdd_cfg80211_set_epno_list() - epno set network list
3794 * @wiphy: wiphy
3795 * @wdev: pointer to wireless dev
3796 * @data: data pointer
3797 * @data_len: data length
3798 *
3799 * This function reads the NL vendor attributes from %tb and
3800 * fill in the epno request message.
3801 *
3802 * Return: 0 on success, error number otherwise
3803 */
3804static int __wlan_hdd_cfg80211_set_epno_list(struct wiphy *wiphy,
3805 struct wireless_dev *wdev,
3806 const void *data,
3807 int data_len)
3808{
3809 struct wifi_epno_params *req_msg = NULL;
3810 struct net_device *dev = wdev->netdev;
3811 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
3812 hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
3813 struct nlattr *tb[
3814 QCA_WLAN_VENDOR_ATTR_PNO_MAX + 1];
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303815 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003816 uint32_t num_networks, len;
3817 int ret_val;
3818
Jeff Johnson1f61b612016-02-12 16:28:33 -08003819 ENTER_DEV(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003820
3821 ret_val = wlan_hdd_validate_context(hdd_ctx);
3822 if (ret_val)
3823 return ret_val;
3824
Anurag Chouhan6d760662016-02-20 16:05:43 +05303825 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003826 hdd_err("Command not allowed in FTM mode");
3827 return -EPERM;
3828 }
3829
3830 if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_PNO_MAX,
3831 data, data_len,
3832 wlan_hdd_extscan_config_policy)) {
3833 hddLog(LOGE, FL("Invalid ATTR"));
3834 return -EINVAL;
3835 }
3836
3837 /* Parse and fetch number of networks */
3838 if (!tb[QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_NUM_NETWORKS]) {
3839 hddLog(LOGE, FL("attr num networks failed"));
3840 return -EINVAL;
3841 }
3842 num_networks = nla_get_u32(
3843 tb[QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_NUM_NETWORKS]);
3844 hddLog(LOG1, FL("num networks %u"), num_networks);
3845
3846 len = sizeof(*req_msg) +
3847 (num_networks * sizeof(struct wifi_epno_network));
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303848 req_msg = qdf_mem_malloc(len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003849 if (!req_msg) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303850 hddLog(LOGE, FL("qdf_mem_malloc failed"));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003851 return -ENOMEM;
3852 }
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303853 qdf_mem_zero(req_msg, len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003854 req_msg->num_networks = num_networks;
3855
3856 /* Parse and fetch request Id */
3857 if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]) {
3858 hddLog(LOGE, FL("attr request id failed"));
3859 goto fail;
3860 }
3861 req_msg->request_id = nla_get_u32(
3862 tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]);
3863 hddLog(LOG1, FL("Req Id %u"), req_msg->request_id);
3864
3865 req_msg->session_id = adapter->sessionId;
3866 hddLog(LOG1, FL("Session Id %d"), req_msg->session_id);
3867
3868 if (hdd_extscan_epno_fill_network_list(hdd_ctx, req_msg, tb))
3869 goto fail;
3870
3871 status = sme_set_epno_list(hdd_ctx->hHal, req_msg);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303872 if (!QDF_IS_STATUS_SUCCESS(status)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003873 hddLog(LOGE, FL("sme_set_epno_list failed(err=%d)"), status);
3874 goto fail;
3875 }
3876
3877 EXIT();
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303878 qdf_mem_free(req_msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003879 return 0;
3880
3881fail:
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303882 qdf_mem_free(req_msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003883 return -EINVAL;
3884}
3885
3886 /**
3887 * wlan_hdd_cfg80211_set_epno_list() - epno set network list
3888 * @wiphy: wiphy
3889 * @wdev: pointer to wireless dev
3890 * @data: data pointer
3891 * @data_len: data length
3892 *
3893 * This function reads the NL vendor attributes from %tb and
3894 * fill in the epno request message.
3895 *
3896 * Return: 0 on success, error number otherwise
3897 */
3898int wlan_hdd_cfg80211_set_epno_list(struct wiphy *wiphy,
3899 struct wireless_dev *wdev,
3900 const void *data,
3901 int data_len)
3902{
3903 int ret;
3904
3905 cds_ssr_protect(__func__);
3906 ret = __wlan_hdd_cfg80211_set_epno_list(wiphy, wdev,
3907 data, data_len);
3908 cds_ssr_unprotect(__func__);
3909
3910 return ret;
3911}
3912
3913/**
3914 * hdd_extscan_passpoint_fill_network_list() - passpoint fill network list
3915 * @hddctx: HDD context
3916 * @req_msg: request message
3917 * @tb: vendor attribute table
3918 *
3919 * This function reads the network block NL vendor attributes from %tb and
3920 * fill in the passpoint request message.
3921 *
3922 * Return: 0 on success, error number otherwise
3923 */
3924static int hdd_extscan_passpoint_fill_network_list(
3925 hdd_context_t *hddctx,
3926 struct wifi_passpoint_req *req_msg,
3927 struct nlattr **tb)
3928{
3929 struct nlattr *network[QCA_WLAN_VENDOR_ATTR_PNO_MAX + 1];
3930 struct nlattr *networks;
3931 int rem1, len;
3932 uint8_t index;
3933
3934 index = 0;
3935 nla_for_each_nested(networks,
3936 tb[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_LIST_PARAM_NETWORK_ARRAY],
3937 rem1) {
3938 if (nla_parse(network,
3939 QCA_WLAN_VENDOR_ATTR_PNO_MAX,
3940 nla_data(networks), nla_len(networks), NULL)) {
3941 hddLog(LOGE, FL("nla_parse failed"));
3942 return -EINVAL;
3943 }
3944
3945 /* Parse and fetch identifier */
3946 if (!network[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ID]) {
3947 hddLog(LOGE, FL("attr passpoint id failed"));
3948 return -EINVAL;
3949 }
3950 req_msg->networks[index].id = nla_get_u32(
3951 network[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ID]);
3952 hddLog(LOG1, FL("Id %u"), req_msg->networks[index].id);
3953
3954 /* Parse and fetch realm */
3955 if (!network[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_REALM]) {
3956 hddLog(LOGE, FL("attr realm failed"));
3957 return -EINVAL;
3958 }
3959 len = nla_len(
3960 network[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_REALM]);
3961 if (len < 0 || len > SIR_PASSPOINT_REALM_LEN) {
3962 hddLog(LOGE, FL("Invalid realm size %d"), len);
3963 return -EINVAL;
3964 }
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303965 qdf_mem_copy(req_msg->networks[index].realm,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003966 nla_data(network[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_REALM]),
3967 len);
3968 hddLog(LOG1, FL("realm len %d"), len);
3969 hddLog(LOG1, FL("realm: %s"), req_msg->networks[index].realm);
3970
3971 /* Parse and fetch roaming consortium ids */
3972 if (!network[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ROAM_CNSRTM_ID]) {
3973 hddLog(LOGE, FL("attr roaming consortium ids failed"));
3974 return -EINVAL;
3975 }
3976 nla_memcpy(&req_msg->networks[index].roaming_consortium_ids,
3977 network[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ROAM_CNSRTM_ID],
3978 sizeof(req_msg->networks[0].roaming_consortium_ids));
3979 hddLog(LOG1, FL("roaming consortium ids"));
3980
3981 /* Parse and fetch plmn */
3982 if (!network[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ROAM_PLMN]) {
3983 hddLog(LOGE, FL("attr plmn failed"));
3984 return -EINVAL;
3985 }
3986 nla_memcpy(&req_msg->networks[index].plmn,
3987 network[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ROAM_PLMN],
3988 SIR_PASSPOINT_PLMN_LEN);
3989 hddLog(LOG1, FL("plmn %02x:%02x:%02x)"),
3990 req_msg->networks[index].plmn[0],
3991 req_msg->networks[index].plmn[1],
3992 req_msg->networks[index].plmn[2]);
3993
3994 index++;
3995 }
3996 return 0;
3997}
3998
3999/**
4000 * __wlan_hdd_cfg80211_set_passpoint_list() - set passpoint network list
4001 * @wiphy: wiphy
4002 * @wdev: pointer to wireless dev
4003 * @data: data pointer
4004 * @data_len: data length
4005 *
4006 * This function reads the NL vendor attributes from %tb and
4007 * fill in the passpoint request message.
4008 *
4009 * Return: 0 on success, error number otherwise
4010 */
4011static int __wlan_hdd_cfg80211_set_passpoint_list(struct wiphy *wiphy,
4012 struct wireless_dev *wdev,
4013 const void *data,
4014 int data_len)
4015{
4016 struct wifi_passpoint_req *req_msg = NULL;
4017 struct net_device *dev = wdev->netdev;
4018 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
4019 hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
4020 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_PNO_MAX + 1];
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304021 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004022 uint32_t num_networks = 0;
4023 int ret;
4024
Jeff Johnson1f61b612016-02-12 16:28:33 -08004025 ENTER_DEV(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004026
4027 ret = wlan_hdd_validate_context(hdd_ctx);
4028 if (ret)
4029 return ret;
4030
Anurag Chouhan6d760662016-02-20 16:05:43 +05304031 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004032 hdd_err("Command not allowed in FTM mode");
4033 return -EPERM;
4034 }
4035
4036 if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_PNO_MAX, data, data_len,
4037 wlan_hdd_extscan_config_policy)) {
4038 hddLog(LOGE, FL("Invalid ATTR"));
4039 return -EINVAL;
4040 }
4041
4042 /* Parse and fetch number of networks */
4043 if (!tb[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_LIST_PARAM_NUM]) {
4044 hddLog(LOGE, FL("attr num networks failed"));
4045 return -EINVAL;
4046 }
4047 num_networks = nla_get_u32(
4048 tb[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_LIST_PARAM_NUM]);
4049 hddLog(LOG1, FL("num networks %u"), num_networks);
4050
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304051 req_msg = qdf_mem_malloc(sizeof(*req_msg) +
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004052 (num_networks * sizeof(req_msg->networks[0])));
4053 if (!req_msg) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304054 hddLog(LOGE, FL("qdf_mem_malloc failed"));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004055 return -ENOMEM;
4056 }
4057 req_msg->num_networks = num_networks;
4058
4059 /* Parse and fetch request Id */
4060 if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]) {
4061 hddLog(LOGE, FL("attr request id failed"));
4062 goto fail;
4063 }
4064 req_msg->request_id = nla_get_u32(
4065 tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]);
4066
4067 req_msg->session_id = adapter->sessionId;
4068 hddLog(LOG1, FL("Req Id %u Session Id %d"), req_msg->request_id,
4069 req_msg->session_id);
4070
4071 if (hdd_extscan_passpoint_fill_network_list(hdd_ctx, req_msg, tb))
4072 goto fail;
4073
4074 status = sme_set_passpoint_list(hdd_ctx->hHal, req_msg);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304075 if (!QDF_IS_STATUS_SUCCESS(status)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004076 hddLog(LOGE,
4077 FL("sme_set_passpoint_list failed(err=%d)"), status);
4078 goto fail;
4079 }
4080
4081 EXIT();
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304082 qdf_mem_free(req_msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004083 return 0;
4084
4085fail:
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304086 qdf_mem_free(req_msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004087 return -EINVAL;
4088}
4089
4090/**
4091 * wlan_hdd_cfg80211_set_passpoint_list() - set passpoint network list
4092 * @wiphy: wiphy
4093 * @wdev: pointer to wireless dev
4094 * @data: data pointer
4095 * @data_len: data length
4096 *
4097 * This function reads the NL vendor attributes from %tb and
4098 * fill in the passpoint request message.
4099 *
4100 * Return: 0 on success, error number otherwise
4101 */
4102int wlan_hdd_cfg80211_set_passpoint_list(struct wiphy *wiphy,
4103 struct wireless_dev *wdev,
4104 const void *data,
4105 int data_len)
4106{
4107 int ret;
4108
4109 cds_ssr_protect(__func__);
4110 ret = __wlan_hdd_cfg80211_set_passpoint_list(wiphy, wdev,
4111 data, data_len);
4112 cds_ssr_unprotect(__func__);
4113
4114 return ret;
4115}
4116
4117/**
4118 * __wlan_hdd_cfg80211_reset_passpoint_list() - reset passpoint network list
4119 * @wiphy: wiphy
4120 * @wdev: pointer to wireless dev
4121 * @data: data pointer
4122 * @data_len: data length
4123 *
4124 * This function resets passpoint networks list
4125 *
4126 * Return: 0 on success, error number otherwise
4127 */
4128static int __wlan_hdd_cfg80211_reset_passpoint_list(struct wiphy *wiphy,
4129 struct wireless_dev *wdev,
4130 const void *data,
4131 int data_len)
4132{
4133 struct wifi_passpoint_req *req_msg = NULL;
4134 struct net_device *dev = wdev->netdev;
4135 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
4136 hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
4137 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_PNO_MAX + 1];
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304138 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004139 int ret;
4140
Jeff Johnson1f61b612016-02-12 16:28:33 -08004141 ENTER_DEV(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004142
4143 ret = wlan_hdd_validate_context(hdd_ctx);
4144 if (ret)
4145 return ret;
4146
Anurag Chouhan6d760662016-02-20 16:05:43 +05304147 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004148 hdd_err("Command not allowed in FTM mode");
4149 return -EPERM;
4150 }
4151
4152 if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_PNO_MAX, data, data_len,
4153 wlan_hdd_extscan_config_policy)) {
4154 hddLog(LOGE, FL("Invalid ATTR"));
4155 return -EINVAL;
4156 }
4157
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304158 req_msg = qdf_mem_malloc(sizeof(*req_msg));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004159 if (!req_msg) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304160 hddLog(LOGE, FL("qdf_mem_malloc failed"));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004161 return -ENOMEM;
4162 }
4163
4164 /* Parse and fetch request Id */
4165 if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]) {
4166 hddLog(LOGE, FL("attr request id failed"));
4167 goto fail;
4168 }
4169 req_msg->request_id = nla_get_u32(
4170 tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]);
4171
4172 req_msg->session_id = adapter->sessionId;
4173 hddLog(LOG1, FL("Req Id %u Session Id %d"),
4174 req_msg->request_id, req_msg->session_id);
4175
4176 status = sme_reset_passpoint_list(hdd_ctx->hHal, req_msg);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304177 if (!QDF_IS_STATUS_SUCCESS(status)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004178 hddLog(LOGE,
4179 FL("sme_reset_passpoint_list failed(err=%d)"), status);
4180 goto fail;
4181 }
4182
4183 EXIT();
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304184 qdf_mem_free(req_msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004185 return 0;
4186
4187fail:
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304188 qdf_mem_free(req_msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004189 return -EINVAL;
4190}
4191
4192/**
4193 * wlan_hdd_cfg80211_reset_passpoint_list() - reset passpoint network list
4194 * @wiphy: wiphy
4195 * @wdev: pointer to wireless dev
4196 * @data: data pointer
4197 * @data_len: data length
4198 *
4199 * This function resets passpoint networks list
4200 *
4201 * Return: 0 on success, error number otherwise
4202 */
4203int wlan_hdd_cfg80211_reset_passpoint_list(struct wiphy *wiphy,
4204 struct wireless_dev *wdev,
4205 const void *data,
4206 int data_len)
4207{
4208 int ret;
4209
4210 cds_ssr_protect(__func__);
4211 ret = __wlan_hdd_cfg80211_reset_passpoint_list(wiphy, wdev,
4212 data, data_len);
4213 cds_ssr_unprotect(__func__);
4214
4215 return ret;
4216}
4217
4218/*
4219 * define short names for the global vendor params
4220 * used by __wlan_hdd_cfg80211_extscan_set_ssid_hotlist()
4221 */
4222#define PARAM_MAX \
4223 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX
4224#define PARAM_REQUEST_ID \
4225 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID
4226#define PARAMS_LOST_SSID_SAMPLE_SIZE \
4227 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_HOTLIST_PARAMS_LOST_SSID_SAMPLE_SIZE
4228#define PARAMS_NUM_SSID \
4229 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_HOTLIST_PARAMS_NUM_SSID
4230#define THRESHOLD_PARAM \
4231 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM
4232#define PARAM_SSID \
4233 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM_SSID
4234#define PARAM_BAND \
4235 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM_BAND
4236#define PARAM_RSSI_LOW \
4237 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM_RSSI_LOW
4238#define PARAM_RSSI_HIGH \
4239 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM_RSSI_HIGH
4240
4241/**
4242 * __wlan_hdd_cfg80211_extscan_set_ssid_hotlist() - set ssid hot list
4243 * @wiphy: Pointer to wireless phy
4244 * @wdev: Pointer to wireless device
4245 * @data: Pointer to data
4246 * @data_len: Data length
4247 *
4248 * Return: 0 on success, negative errno on failure
4249 */
4250static int
4251__wlan_hdd_cfg80211_extscan_set_ssid_hotlist(struct wiphy *wiphy,
4252 struct wireless_dev *wdev,
4253 const void *data,
4254 int data_len)
4255{
4256 struct sir_set_ssid_hotlist_request *request;
4257 struct net_device *dev = wdev->netdev;
4258 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
4259 hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
4260 struct nlattr *tb[PARAM_MAX + 1];
4261 struct nlattr *tb2[PARAM_MAX + 1];
4262 struct nlattr *ssids;
4263 struct hdd_ext_scan_context *context;
4264 uint32_t request_id;
4265 char ssid_string[SIR_MAC_MAX_SSID_LENGTH + 1];
4266 int ssid_len, i, rem;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304267 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004268 int retval;
4269 unsigned long rc;
4270
Jeff Johnson1f61b612016-02-12 16:28:33 -08004271 ENTER_DEV(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004272
Anurag Chouhan6d760662016-02-20 16:05:43 +05304273 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004274 hdd_err("Command not allowed in FTM mode");
4275 return -EPERM;
4276 }
4277
4278 retval = wlan_hdd_validate_context(hdd_ctx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05304279 if (0 != retval)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004280 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004281
4282 if (nla_parse(tb, PARAM_MAX,
4283 data, data_len,
4284 wlan_hdd_extscan_config_policy)) {
4285 hddLog(LOGE, FL("Invalid ATTR"));
4286 return -EINVAL;
4287 }
4288
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304289 request = qdf_mem_malloc(sizeof(*request));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004290 if (!request) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304291 hddLog(LOGE, FL("qdf_mem_malloc failed"));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004292 return -ENOMEM;
4293 }
4294
4295 /* Parse and fetch request Id */
4296 if (!tb[PARAM_REQUEST_ID]) {
4297 hddLog(LOGE, FL("attr request id failed"));
4298 goto fail;
4299 }
4300
4301 request->request_id = nla_get_u32(tb[PARAM_REQUEST_ID]);
4302 hddLog(LOG1, FL("Request Id %d"), request->request_id);
4303
4304 /* Parse and fetch lost SSID sample size */
4305 if (!tb[PARAMS_LOST_SSID_SAMPLE_SIZE]) {
4306 hddLog(LOGE, FL("attr number of Ssid failed"));
4307 goto fail;
4308 }
4309 request->lost_ssid_sample_size =
4310 nla_get_u32(tb[PARAMS_LOST_SSID_SAMPLE_SIZE]);
4311 hddLog(LOG1, FL("Lost SSID Sample Size %d"),
4312 request->lost_ssid_sample_size);
4313
4314 /* Parse and fetch number of hotlist SSID */
4315 if (!tb[PARAMS_NUM_SSID]) {
4316 hddLog(LOGE, FL("attr number of Ssid failed"));
4317 goto fail;
4318 }
4319 request->ssid_count = nla_get_u32(tb[PARAMS_NUM_SSID]);
4320 hddLog(LOG1, FL("Number of SSID %d"), request->ssid_count);
4321
4322 request->session_id = adapter->sessionId;
4323 hddLog(LOG1, FL("Session Id %d"), request->session_id);
4324
4325 i = 0;
4326 nla_for_each_nested(ssids, tb[THRESHOLD_PARAM], rem) {
4327 if (i >= WLAN_EXTSCAN_MAX_HOTLIST_SSIDS) {
4328 hddLog(LOGE,
4329 FL("Too Many SSIDs, %d exceeds %d"),
4330 i, WLAN_EXTSCAN_MAX_HOTLIST_SSIDS);
4331 break;
4332 }
4333 if (nla_parse(tb2, PARAM_MAX,
4334 nla_data(ssids), nla_len(ssids),
4335 wlan_hdd_extscan_config_policy)) {
4336 hddLog(LOGE, FL("nla_parse failed"));
4337 goto fail;
4338 }
4339
4340 /* Parse and fetch SSID */
4341 if (!tb2[PARAM_SSID]) {
4342 hddLog(LOGE, FL("attr ssid failed"));
4343 goto fail;
4344 }
4345 nla_memcpy(ssid_string,
4346 tb2[PARAM_SSID],
4347 sizeof(ssid_string));
4348 hddLog(LOG1, FL("SSID %s"),
4349 ssid_string);
4350 ssid_len = strlen(ssid_string);
4351 memcpy(request->ssids[i].ssid.ssId, ssid_string, ssid_len);
4352 request->ssids[i].ssid.length = ssid_len;
4353
4354 /* Parse and fetch low RSSI */
4355 if (!tb2[PARAM_BAND]) {
4356 hddLog(LOGE, FL("attr band failed"));
4357 goto fail;
4358 }
4359 request->ssids[i].band = nla_get_u8(tb2[PARAM_BAND]);
4360 hddLog(LOG1, FL("band %d"), request->ssids[i].band);
4361
4362 /* Parse and fetch low RSSI */
4363 if (!tb2[PARAM_RSSI_LOW]) {
4364 hddLog(LOGE, FL("attr low RSSI failed"));
4365 goto fail;
4366 }
4367 request->ssids[i].rssi_low = nla_get_s32(tb2[PARAM_RSSI_LOW]);
4368 hddLog(LOG1, FL("RSSI low %d"), request->ssids[i].rssi_low);
4369
4370 /* Parse and fetch high RSSI */
4371 if (!tb2[PARAM_RSSI_HIGH]) {
4372 hddLog(LOGE, FL("attr high RSSI failed"));
4373 goto fail;
4374 }
4375 request->ssids[i].rssi_high = nla_get_u32(tb2[PARAM_RSSI_HIGH]);
4376 hddLog(LOG1, FL("RSSI high %d"), request->ssids[i].rssi_high);
4377 i++;
4378 }
4379
4380 context = &ext_scan_context;
4381 spin_lock(&context->context_lock);
4382 INIT_COMPLETION(context->response_event);
4383 context->request_id = request_id = request->request_id;
4384 spin_unlock(&context->context_lock);
4385
4386 status = sme_set_ssid_hotlist(hdd_ctx->hHal, request);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304387 if (!QDF_IS_STATUS_SUCCESS(status)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004388 hddLog(LOGE,
4389 FL("sme_set_ssid_hotlist failed(err=%d)"), status);
4390 goto fail;
4391 }
4392
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304393 qdf_mem_free(request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004394
4395 /* request was sent -- wait for the response */
4396 rc = wait_for_completion_timeout(&context->response_event,
4397 msecs_to_jiffies
4398 (WLAN_WAIT_TIME_EXTSCAN));
4399 if (!rc) {
4400 hddLog(LOGE, FL("sme_set_ssid_hotlist timed out"));
4401 retval = -ETIMEDOUT;
4402 } else {
4403 spin_lock(&context->context_lock);
4404 if (context->request_id == request_id)
4405 retval = context->response_status;
4406 else
4407 retval = -EINVAL;
4408 spin_unlock(&context->context_lock);
4409 }
4410
4411 return retval;
4412
4413fail:
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304414 qdf_mem_free(request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004415 return -EINVAL;
4416}
4417
4418/*
4419 * done with short names for the global vendor params
4420 * used by wlan_hdd_cfg80211_extscan_set_ssid_hotlist()
4421 */
4422#undef PARAM_MAX
4423#undef PARAM_REQUEST_ID
4424#undef PARAMS_NUM_SSID
4425#undef THRESHOLD_PARAM
4426#undef PARAM_SSID
4427#undef PARAM_BAND
4428#undef PARAM_RSSI_LOW
4429#undef PARAM_RSSI_HIGH
4430
4431/**
4432 * wlan_hdd_cfg80211_extscan_set_ssid_hotlist() - set ssid hot list
4433 * @wiphy: Pointer to wireless phy
4434 * @wdev: Pointer to wireless device
4435 * @data: Pointer to data
4436 * @data_len: Data length
4437 *
4438 * Return: 0 on success, negative errno on failure
4439 */
4440int
4441wlan_hdd_cfg80211_extscan_set_ssid_hotlist(struct wiphy *wiphy,
4442 struct wireless_dev *wdev,
4443 const void *data,
4444 int data_len)
4445{
4446 int ret;
4447
4448 cds_ssr_protect(__func__);
4449 ret = __wlan_hdd_cfg80211_extscan_set_ssid_hotlist(wiphy, wdev, data,
4450 data_len);
4451 cds_ssr_unprotect(__func__);
4452
4453 return ret;
4454}
4455
4456/*
4457 * define short names for the global vendor params
4458 * used by __wlan_hdd_cfg80211_extscan_reset_ssid_hotlist()
4459 */
4460#define PARAM_MAX \
4461 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX
4462#define PARAM_REQUEST_ID \
4463 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID
4464
4465/**
4466 * __wlan_hdd_cfg80211_extscan_reset_ssid_hotlist() - reset ssid hot list
4467 * @wiphy: Pointer to wireless phy
4468 * @wdev: Pointer to wireless device
4469 * @data: Pointer to data
4470 * @data_len: Data length
4471 *
4472 * Return: 0 on success, negative errno on failure
4473 */
4474static int
4475__wlan_hdd_cfg80211_extscan_reset_ssid_hotlist(struct wiphy *wiphy,
4476 struct wireless_dev *wdev,
4477 const void *data,
4478 int data_len)
4479{
4480 struct sir_set_ssid_hotlist_request *request;
4481 struct net_device *dev = wdev->netdev;
4482 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
4483 hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
4484 struct nlattr *tb[PARAM_MAX + 1];
4485 struct hdd_ext_scan_context *context;
4486 uint32_t request_id;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304487 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004488 int retval;
4489 unsigned long rc;
4490
Jeff Johnson1f61b612016-02-12 16:28:33 -08004491 ENTER_DEV(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004492
Anurag Chouhan6d760662016-02-20 16:05:43 +05304493 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004494 hdd_err("Command not allowed in FTM mode");
4495 return -EPERM;
4496 }
4497
4498 retval = wlan_hdd_validate_context(hdd_ctx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05304499 if (0 != retval)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004500 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004501
4502 if (nla_parse(tb, PARAM_MAX,
4503 data, data_len,
4504 wlan_hdd_extscan_config_policy)) {
4505 hddLog(LOGE, FL("Invalid ATTR"));
4506 return -EINVAL;
4507 }
4508
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304509 request = qdf_mem_malloc(sizeof(*request));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004510 if (!request) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304511 hddLog(LOGE, FL("qdf_mem_malloc failed"));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004512 return -ENOMEM;
4513 }
4514
4515 /* Parse and fetch request Id */
4516 if (!tb[PARAM_REQUEST_ID]) {
4517 hddLog(LOGE, FL("attr request id failed"));
4518 goto fail;
4519 }
4520
4521 request->request_id = nla_get_u32(tb[PARAM_REQUEST_ID]);
4522 hddLog(LOG1, FL("Request Id %d"), request->request_id);
4523
4524 request->session_id = adapter->sessionId;
4525 hddLog(LOG1, FL("Session Id %d"), request->session_id);
4526
4527 request->lost_ssid_sample_size = 0;
4528 request->ssid_count = 0;
4529
4530 context = &ext_scan_context;
4531 spin_lock(&context->context_lock);
4532 INIT_COMPLETION(context->response_event);
4533 context->request_id = request_id = request->request_id;
4534 spin_unlock(&context->context_lock);
4535
4536 status = sme_set_ssid_hotlist(hdd_ctx->hHal, request);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304537 if (!QDF_IS_STATUS_SUCCESS(status)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004538 hddLog(LOGE,
4539 FL("sme_reset_ssid_hotlist failed(err=%d)"), status);
4540 goto fail;
4541 }
4542
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304543 qdf_mem_free(request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004544
4545 /* request was sent -- wait for the response */
4546 rc = wait_for_completion_timeout(&context->response_event,
4547 msecs_to_jiffies
4548 (WLAN_WAIT_TIME_EXTSCAN));
4549 if (!rc) {
4550 hddLog(LOGE, FL("sme_reset_ssid_hotlist timed out"));
4551 retval = -ETIMEDOUT;
4552 } else {
4553 spin_lock(&context->context_lock);
4554 if (context->request_id == request_id)
4555 retval = context->response_status;
4556 else
4557 retval = -EINVAL;
4558 spin_unlock(&context->context_lock);
4559 }
4560
4561 return retval;
4562
4563fail:
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304564 qdf_mem_free(request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004565 return -EINVAL;
4566}
4567
4568/*
4569 * done with short names for the global vendor params
4570 * used by wlan_hdd_cfg80211_extscan_reset_ssid_hotlist()
4571 */
4572#undef PARAM_MAX
4573#undef PARAM_REQUEST_ID
4574
4575/**
4576 * wlan_hdd_cfg80211_extscan_reset_ssid_hotlist() - reset ssid hot list
4577 * @wiphy: Pointer to wireless phy
4578 * @wdev: Pointer to wireless device
4579 * @data: Pointer to data
4580 * @data_len: Data length
4581 *
4582 * Return: 0 on success, negative errno on failure
4583 */
4584int
4585wlan_hdd_cfg80211_extscan_reset_ssid_hotlist(struct wiphy *wiphy,
4586 struct wireless_dev *wdev,
4587 const void *data,
4588 int data_len)
4589{
4590 int ret;
4591
4592 cds_ssr_protect(__func__);
4593 ret = __wlan_hdd_cfg80211_extscan_reset_ssid_hotlist(wiphy, wdev,
4594 data, data_len);
4595 cds_ssr_unprotect(__func__);
4596
4597 return ret;
4598}
4599
4600/**
4601 * wlan_hdd_init_completion_extwow() - Initialize ext wow variable
4602 * @hdd_ctx: Global HDD context
4603 *
4604 * Return: none
4605 */
4606#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
4607static inline void wlan_hdd_init_completion_extwow(hdd_context_t *pHddCtx)
4608{
4609 init_completion(&pHddCtx->ready_to_extwow);
4610}
4611#else
4612static inline void wlan_hdd_init_completion_extwow(hdd_context_t *pHddCtx)
4613{
4614 return;
4615}
4616#endif
4617
4618/**
4619 * wlan_hdd_cfg80211_extscan_init() - Initialize the ExtScan feature
4620 * @hdd_ctx: Global HDD context
4621 *
4622 * Return: none
4623 */
4624void wlan_hdd_cfg80211_extscan_init(hdd_context_t *hdd_ctx)
4625{
4626 wlan_hdd_init_completion_extwow(hdd_ctx);
4627 init_completion(&ext_scan_context.response_event);
4628 spin_lock_init(&ext_scan_context.context_lock);
4629}
4630
4631#endif /* FEATURE_WLAN_EXTSCAN */