blob: 4071f771848ccbeca3aae3410e6d6467ebf5e3ff [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
2 * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved.
3 *
4 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
5 *
6 *
7 * Permission to use, copy, modify, and/or distribute this software for
8 * any purpose with or without fee is hereby granted, provided that the
9 * above copyright notice and this permission notice appear in all
10 * copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
13 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
15 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
16 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
17 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
18 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19 * PERFORMANCE OF THIS SOFTWARE.
20 */
21
22/**
23 * 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 *
504 * Return: none
505 */
506static void
507wlan_hdd_cfg80211_extscan_hotlist_match_ind(void *ctx,
508 struct extscan_hotlist_match *data)
509{
510 hdd_context_t *pHddCtx = ctx;
511 struct sk_buff *skb = NULL;
512 uint32_t i, index;
513
514 ENTER();
515
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530516 if (wlan_hdd_validate_context(pHddCtx))
517 return;
518 if (!data) {
519 hddLog(LOGE, FL("data is null"));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800520 return;
521 }
522
523 if (data->ap_found)
524 index = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_AP_FOUND_INDEX;
525 else
526 index = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_AP_LOST_INDEX;
527
528 skb = cfg80211_vendor_event_alloc(
529 pHddCtx->wiphy,
530 NULL,
531 EXTSCAN_EVENT_BUF_SIZE + NLMSG_HDRLEN,
532 index, GFP_KERNEL);
533
534 if (!skb) {
535 hddLog(LOGE, FL("cfg80211_vendor_event_alloc failed"));
536 return;
537 }
538 hdd_info("Req Id: %u Num_APs: %u MoreData: %u ap_found: %u",
539 data->requestId, data->numOfAps, data->moreData,
540 data->ap_found);
541
542 for (i = 0; i < data->numOfAps; i++) {
543 data->ap[i].ts = cdf_get_monotonic_boottime();
544
545 hddLog(LOG1, "[i=%d] Timestamp %llu "
546 "Ssid: %s "
547 "Bssid (" MAC_ADDRESS_STR ") "
548 "Channel %u "
549 "Rssi %d "
550 "RTT %u "
551 "RTT_SD %u",
552 i,
553 data->ap[i].ts,
554 data->ap[i].ssid,
555 MAC_ADDR_ARRAY(data->ap[i].bssid.bytes),
556 data->ap[i].channel,
557 data->ap[i].rssi,
558 data->ap[i].rtt, data->ap[i].rtt_sd);
559 }
560
561 if (nla_put_u32(skb,
562 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID,
563 data->requestId) ||
564 nla_put_u32(skb,
565 QCA_WLAN_VENDOR_ATTR_EXTSCAN_NUM_RESULTS_AVAILABLE,
566 data->numOfAps)) {
567 hddLog(LOGE, FL("put fail"));
568 goto fail;
569 }
570
571 if (data->numOfAps) {
572 struct nlattr *aps;
573
574 aps = nla_nest_start(skb,
575 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_LIST);
576 if (!aps)
577 goto fail;
578
579 for (i = 0; i < data->numOfAps; i++) {
580 struct nlattr *ap;
581
582 ap = nla_nest_start(skb, i);
583 if (!ap)
584 goto fail;
585
586 if (nla_put_u64(skb,
587 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_TIME_STAMP,
588 data->ap[i].ts) ||
589 nla_put(skb,
590 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_SSID,
591 sizeof(data->ap[i].ssid),
592 data->ap[i].ssid) ||
593 nla_put(skb,
594 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_BSSID,
595 sizeof(data->ap[i].bssid),
596 data->ap[i].bssid.bytes) ||
597 nla_put_u32(skb,
598 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_CHANNEL,
599 data->ap[i].channel) ||
600 nla_put_s32(skb,
601 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RSSI,
602 data->ap[i].rssi) ||
603 nla_put_u32(skb,
604 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RTT,
605 data->ap[i].rtt) ||
606 nla_put_u32(skb,
607 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RTT_SD,
608 data->ap[i].rtt_sd))
609 goto fail;
610
611 nla_nest_end(skb, ap);
612 }
613 nla_nest_end(skb, aps);
614
615 if (nla_put_u8(skb,
616 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_MORE_DATA,
617 data->moreData))
618 goto fail;
619 }
620
621 cfg80211_vendor_event(skb, GFP_KERNEL);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530622 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800623 return;
624
625fail:
626 kfree_skb(skb);
627 return;
628}
629
630/**
631 * wlan_hdd_cfg80211_extscan_signif_wifi_change_results_ind() -
632 * significant wifi change results indication
633 * @ctx: Pointer to hdd context
634 * @pData: Pointer to signif wifi change event
635 *
636 * Return: none
637 */
638static void
639wlan_hdd_cfg80211_extscan_signif_wifi_change_results_ind(
640 void *ctx,
641 tpSirWifiSignificantChangeEvent pData)
642{
643 hdd_context_t *pHddCtx = (hdd_context_t *) ctx;
644 struct sk_buff *skb = NULL;
645 tSirWifiSignificantChange *ap_info;
646 int32_t *rssi;
647 uint32_t i, j;
648
649 ENTER();
650
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530651 if (wlan_hdd_validate_context(pHddCtx))
652 return;
653 if (!pData) {
654 hddLog(LOGE, FL("pData is null"));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800655 return;
656 }
657
658 skb = cfg80211_vendor_event_alloc(
659 pHddCtx->wiphy,
660 NULL,
661 EXTSCAN_EVENT_BUF_SIZE + NLMSG_HDRLEN,
662 QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SIGNIFICANT_CHANGE_INDEX,
663 GFP_KERNEL);
664
665 if (!skb) {
666 hddLog(LOGE, FL("cfg80211_vendor_event_alloc failed"));
667 return;
668 }
669 hddLog(LOG1, "Req Id %u Num results %u More Data %u",
670 pData->requestId, pData->numResults, pData->moreData);
671
672 ap_info = &pData->ap[0];
673 for (i = 0; i < pData->numResults; i++) {
674 hddLog(LOG1, "[i=%d] "
675 "Bssid (" MAC_ADDRESS_STR ") "
676 "Channel %u "
677 "numOfRssi %d",
678 i,
679 MAC_ADDR_ARRAY(ap_info->bssid.bytes),
680 ap_info->channel, ap_info->numOfRssi);
681 rssi = &(ap_info)->rssi[0];
682 for (j = 0; j < ap_info->numOfRssi; j++)
683 hddLog(LOG1, "Rssi %d", *rssi++);
684
685 ap_info += ap_info->numOfRssi * sizeof(*rssi);
686 }
687
688 if (nla_put_u32(skb,
689 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID,
690 pData->requestId) ||
691 nla_put_u32(skb,
692 QCA_WLAN_VENDOR_ATTR_EXTSCAN_NUM_RESULTS_AVAILABLE,
693 pData->numResults)) {
694 hddLog(LOGE, FL("put fail"));
695 goto fail;
696 }
697
698 if (pData->numResults) {
699 struct nlattr *aps;
700
701 aps = nla_nest_start(skb,
702 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_LIST);
703 if (!aps)
704 goto fail;
705
706 ap_info = &pData->ap[0];
707 for (i = 0; i < pData->numResults; i++) {
708 struct nlattr *ap;
709
710 ap = nla_nest_start(skb, i);
711 if (!ap)
712 goto fail;
713
714 if (nla_put(skb,
715 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_BSSID,
716 CDF_MAC_ADDR_SIZE, ap_info->bssid.bytes) ||
717 nla_put_u32(skb,
718 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_CHANNEL,
719 ap_info->channel) ||
720 nla_put_u32(skb,
721 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_NUM_RSSI,
722 ap_info->numOfRssi) ||
723 nla_put(skb,
724 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_RSSI_LIST,
725 sizeof(s32) * ap_info->numOfRssi,
726 &(ap_info)->rssi[0]))
727 goto fail;
728
729 nla_nest_end(skb, ap);
730
731 ap_info += ap_info->numOfRssi * sizeof(*rssi);
732 }
733 nla_nest_end(skb, aps);
734
735 if (nla_put_u8(skb,
736 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_MORE_DATA,
737 pData->moreData))
738 goto fail;
739 }
740
741 cfg80211_vendor_event(skb, GFP_KERNEL);
742 return;
743
744fail:
745 kfree_skb(skb);
746 return;
747
748}
749
750/**
751 * wlan_hdd_cfg80211_extscan_full_scan_result_event() - full scan result event
752 * @ctx: Pointer to hdd context
753 * @pData: Pointer to full scan result event
754 *
755 * Return: none
756 */
757static void
758wlan_hdd_cfg80211_extscan_full_scan_result_event(void *ctx,
759 tpSirWifiFullScanResultEvent
760 pData)
761{
762 hdd_context_t *pHddCtx = (hdd_context_t *) ctx;
763 struct sk_buff *skb = NULL;
764#ifdef CONFIG_CNSS
765 struct timespec ts;
766#endif
767
768 ENTER();
769
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530770 if (wlan_hdd_validate_context(pHddCtx))
771 return;
772 if (!pData) {
773 hddLog(LOGE, FL("pData is null"));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800774 return;
775 }
776
777 if ((sizeof(*pData) + pData->ap.ieLength) >= EXTSCAN_EVENT_BUF_SIZE) {
778 hddLog(LOGE,
779 FL("Frame exceeded NL size limitation, drop it!!"));
780 return;
781 }
782 skb = cfg80211_vendor_event_alloc(
783 pHddCtx->wiphy,
784 NULL,
785 EXTSCAN_EVENT_BUF_SIZE + NLMSG_HDRLEN,
786 QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_FULL_SCAN_RESULT_INDEX,
787 GFP_KERNEL);
788
789 if (!skb) {
790 hddLog(LOGE, FL("cfg80211_vendor_event_alloc failed"));
791 return;
792 }
793
794 pData->ap.channel = cds_chan_to_freq(pData->ap.channel);
795#ifdef CONFIG_CNSS
796 /* Android does not want the time stamp from the frame.
797 Instead it wants a monotonic increasing value since boot */
798 cnss_get_monotonic_boottime(&ts);
799 pData->ap.ts = ((u64)ts.tv_sec * 1000000) + (ts.tv_nsec / 1000);
800#endif
801 hddLog(LOG1, "Req Id %u More Data %u", pData->requestId,
802 pData->moreData);
803 hddLog(LOG1, "AP Info: Timestamp %llu Ssid: %s "
804 "Bssid (" MAC_ADDRESS_STR ") "
805 "Channel %u "
806 "Rssi %d "
807 "RTT %u "
808 "RTT_SD %u "
809 "Bcn Period %d "
810 "Capability 0x%X "
811 "IE Length %d",
812 pData->ap.ts,
813 pData->ap.ssid,
814 MAC_ADDR_ARRAY(pData->ap.bssid.bytes),
815 pData->ap.channel,
816 pData->ap.rssi,
817 pData->ap.rtt,
818 pData->ap.rtt_sd,
819 pData->ap.beaconPeriod,
820 pData->ap.capability, pData->ap.ieLength);
821
822 if (nla_put_u32(skb,
823 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID,
824 pData->requestId) ||
825 nla_put_u64(skb,
826 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_TIME_STAMP,
827 pData->ap.ts) ||
828 nla_put(skb,
829 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_SSID,
830 sizeof(pData->ap.ssid),
831 pData->ap.ssid) ||
832 nla_put(skb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_BSSID,
833 sizeof(pData->ap.bssid),
834 pData->ap.bssid.bytes) ||
835 nla_put_u32(skb,
836 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_CHANNEL,
837 pData->ap.channel) ||
838 nla_put_s32(skb,
839 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RSSI,
840 pData->ap.rssi) ||
841 nla_put_u32(skb,
842 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RTT,
843 pData->ap.rtt) ||
844 nla_put_u32(skb,
845 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RTT_SD,
846 pData->ap.rtt_sd) ||
847 nla_put_u16(skb,
848 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_BEACON_PERIOD,
849 pData->ap.beaconPeriod) ||
850 nla_put_u16(skb,
851 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_CAPABILITY,
852 pData->ap.capability) ||
853 nla_put_u32(skb,
854 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_IE_LENGTH,
855 pData->ap.ieLength) ||
856 nla_put_u8(skb,
857 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_MORE_DATA,
858 pData->moreData)) {
859 hddLog(LOGE, FL("nla put fail"));
860 goto nla_put_failure;
861 }
862
863 if (pData->ap.ieLength) {
864 if (nla_put(skb,
865 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_IE_DATA,
866 pData->ap.ieLength, pData->ap.ieData))
867 goto nla_put_failure;
868 }
869
870 cfg80211_vendor_event(skb, GFP_KERNEL);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530871 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800872 return;
873
874nla_put_failure:
875 kfree_skb(skb);
876 return;
877}
878
879/**
880 * wlan_hdd_cfg80211_extscan_scan_res_available_event() - scan result event
881 * @ctx: Pointer to hdd context
882 * @pData: Pointer to scan results available indication param
883 *
884 * Return: none
885 */
886static void
887wlan_hdd_cfg80211_extscan_scan_res_available_event(
888 void *ctx,
889 tpSirExtScanResultsAvailableIndParams pData)
890{
891 hdd_context_t *pHddCtx = (hdd_context_t *) ctx;
892 struct sk_buff *skb = NULL;
893
894 ENTER();
895
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530896 if (wlan_hdd_validate_context(pHddCtx))
897 return;
898 if (!pData) {
899 hddLog(LOGE, FL("pData is null"));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800900 return;
901 }
902
903 skb = cfg80211_vendor_event_alloc(
904 pHddCtx->wiphy,
905 NULL,
906 EXTSCAN_EVENT_BUF_SIZE + NLMSG_HDRLEN,
907 QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SCAN_RESULTS_AVAILABLE_INDEX,
908 GFP_KERNEL);
909
910 if (!skb) {
911 hddLog(LOGE, FL("cfg80211_vendor_event_alloc failed"));
912 return;
913 }
914
915 hddLog(LOG1, "Req Id %u Num results %u",
916 pData->requestId, pData->numResultsAvailable);
917 if (nla_put_u32(skb,
918 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID,
919 pData->requestId) ||
920 nla_put_u32(skb,
921 QCA_WLAN_VENDOR_ATTR_EXTSCAN_NUM_RESULTS_AVAILABLE,
922 pData->numResultsAvailable)) {
923 hddLog(LOGE, FL("nla put fail"));
924 goto nla_put_failure;
925 }
926
927 cfg80211_vendor_event(skb, GFP_KERNEL);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530928 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800929 return;
930
931nla_put_failure:
932 kfree_skb(skb);
933 return;
934}
935
936/**
937 * wlan_hdd_cfg80211_extscan_scan_progress_event() - scan progress event
938 * @ctx: Pointer to hdd context
939 * @pData: Pointer to scan event indication param
940 *
941 * Return: none
942 */
943static void
944wlan_hdd_cfg80211_extscan_scan_progress_event(void *ctx,
945 tpSirExtScanOnScanEventIndParams
946 pData)
947{
948 hdd_context_t *pHddCtx = (hdd_context_t *) ctx;
949 struct sk_buff *skb = NULL;
950
951 ENTER();
952
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530953 if (wlan_hdd_validate_context(pHddCtx))
954 return;
955 if (!pData) {
956 hddLog(LOGE, FL("pData is null"));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800957 return;
958 }
959
960 skb = cfg80211_vendor_event_alloc(
961 pHddCtx->wiphy,
962 NULL,
963 EXTSCAN_EVENT_BUF_SIZE + NLMSG_HDRLEN,
964 QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SCAN_EVENT_INDEX,
965 GFP_KERNEL);
966
967 if (!skb) {
968 hddLog(LOGE, FL("cfg80211_vendor_event_alloc failed"));
969 return;
970 }
971 hddLog(LOG1, "Req Id %u Scan event type %u Scan event status %u",
972 pData->requestId, pData->scanEventType, pData->status);
973
974 if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID,
975 pData->requestId) ||
976 nla_put_u8(skb,
977 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_EVENT_TYPE,
978 pData->scanEventType) ||
979 nla_put_u32(skb,
980 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_EVENT_STATUS,
981 pData->status)) {
982 hddLog(LOGE, FL("nla put fail"));
983 goto nla_put_failure;
984 }
985
986 cfg80211_vendor_event(skb, GFP_KERNEL);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530987 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800988 return;
989
990nla_put_failure:
991 kfree_skb(skb);
992 return;
993}
994
995/**
996 * wlan_hdd_cfg80211_extscan_epno_match_found() - pno match found
997 * @hddctx: HDD context
998 * @data: matched network data
999 *
1000 * This function reads the matched network data and fills NL vendor attributes
1001 * and send it to upper layer.
1002 *
1003 * Return: 0 on success, error number otherwise
1004 */
1005static void
1006wlan_hdd_cfg80211_extscan_epno_match_found(void *ctx,
1007 struct pno_match_found *data)
1008{
1009 hdd_context_t *pHddCtx = (hdd_context_t *)ctx;
1010 struct sk_buff *skb = NULL;
1011 uint32_t len, i;
1012
1013 ENTER();
1014
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301015 if (wlan_hdd_validate_context(pHddCtx))
1016 return;
1017 if (!data) {
1018 hddLog(LOGE, FL("data is null"));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001019 return;
1020 }
1021
1022 /*
1023 * If the number of match found APs including IE data exceeds NL 4K size
1024 * limitation, drop that beacon/probe rsp frame.
1025 */
1026 len = sizeof(*data) +
1027 (data->num_results + sizeof(tSirWifiScanResult));
1028 for (i = 0; i < data->num_results; i++)
1029 len += data->ap[i].ieLength;
1030
1031 if (len >= EXTSCAN_EVENT_BUF_SIZE) {
1032 hddLog(LOGE, FL("Frame exceeded NL size limitation, drop it!"));
1033 return;
1034 }
1035
1036 skb = cfg80211_vendor_event_alloc(pHddCtx->wiphy,
1037 NULL,
1038 EXTSCAN_EVENT_BUF_SIZE + NLMSG_HDRLEN,
1039 QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_NETWORK_FOUND_INDEX,
1040 GFP_KERNEL);
1041
1042 if (!skb) {
1043 hddLog(LOGE, FL("cfg80211_vendor_event_alloc failed"));
1044 return;
1045 }
1046
1047 hddLog(LOG1, "Req Id %u More Data %u num_results %d",
1048 data->request_id, data->more_data, data->num_results);
1049 for (i = 0; i < data->num_results; i++) {
1050 data->ap[i].channel = cds_chan_to_freq(data->ap[i].channel);
1051 hddLog(LOG1, "AP Info: Timestamp %llu) Ssid: %s "
1052 "Bssid (" MAC_ADDRESS_STR ") "
1053 "Channel %u "
1054 "Rssi %d "
1055 "RTT %u "
1056 "RTT_SD %u "
1057 "Bcn Period %d "
1058 "Capability 0x%X "
1059 "IE Length %d",
1060 data->ap[i].ts,
1061 data->ap[i].ssid,
1062 MAC_ADDR_ARRAY(data->ap[i].bssid.bytes),
1063 data->ap[i].channel,
1064 data->ap[i].rssi,
1065 data->ap[i].rtt,
1066 data->ap[i].rtt_sd,
1067 data->ap[i].beaconPeriod,
1068 data->ap[i].capability,
1069 data->ap[i].ieLength);
1070 }
1071
1072 if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID,
1073 data->request_id) ||
1074 nla_put_u32(skb,
1075 QCA_WLAN_VENDOR_ATTR_EXTSCAN_NUM_RESULTS_AVAILABLE,
1076 data->num_results) ||
1077 nla_put_u8(skb,
1078 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_MORE_DATA,
1079 data->more_data)) {
1080 hddLog(LOGE, FL("nla put fail"));
1081 goto fail;
1082 }
1083
1084 if (data->num_results) {
1085 struct nlattr *nla_aps;
1086 nla_aps = nla_nest_start(skb,
1087 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_LIST);
1088 if (!nla_aps)
1089 goto fail;
1090
1091 for (i = 0; i < data->num_results; i++) {
1092 if (hdd_extscan_nl_fill_bss(skb, &data->ap[i], i))
1093 goto fail;
1094 }
1095 nla_nest_end(skb, nla_aps);
1096 }
1097
1098 cfg80211_vendor_event(skb, GFP_KERNEL);
1099 return;
1100
1101fail:
1102 kfree_skb(skb);
1103 return;
1104}
1105
1106/**
1107 * wlan_hdd_cfg80211_passpoint_match_found() - passpoint match found
1108 * @hddctx: HDD context
1109 * @data: matched network data
1110 *
1111 * This function reads the match network %data and fill in the skb with
1112 * NL attributes and send up the NL event
1113 *
1114 * Return: none
1115 */
1116static void
1117wlan_hdd_cfg80211_passpoint_match_found(void *ctx,
1118 struct wifi_passpoint_match *data)
1119{
1120 hdd_context_t *pHddCtx = ctx;
1121 struct sk_buff *skb = NULL;
1122 uint32_t len, i, num_matches = 1, more_data = 0;
1123 struct nlattr *nla_aps;
1124 struct nlattr *nla_bss;
1125
1126 ENTER();
1127
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301128 if (wlan_hdd_validate_context(pHddCtx))
1129 return;
1130 if (!data) {
1131 hddLog(LOGE, FL("data is null"));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001132 return;
1133 }
1134
1135 len = sizeof(*data) + data->ap.ieLength + data->anqp_len;
1136 if (len >= EXTSCAN_EVENT_BUF_SIZE) {
1137 hddLog(LOGE, FL("Result exceeded NL size limitation, drop it"));
1138 return;
1139 }
1140
1141 skb = cfg80211_vendor_event_alloc(pHddCtx->wiphy,
1142 NULL,
1143 EXTSCAN_EVENT_BUF_SIZE + NLMSG_HDRLEN,
1144 QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_PASSPOINT_NETWORK_FOUND_INDEX,
1145 GFP_KERNEL);
1146
1147 if (!skb) {
1148 hddLog(LOGE, FL("cfg80211_vendor_event_alloc failed"));
1149 return;
1150 }
1151
1152 hddLog(LOG1, "Req Id %u Id %u ANQP length %u num_matches %u",
1153 data->request_id, data->id, data->anqp_len, num_matches);
1154 for (i = 0; i < num_matches; i++) {
1155 hddLog(LOG1, "AP Info: Timestamp %llu Ssid: %s "
1156 "Bssid (" MAC_ADDRESS_STR ") "
1157 "Channel %u "
1158 "Rssi %d "
1159 "RTT %u "
1160 "RTT_SD %u "
1161 "Bcn Period %d "
1162 "Capability 0x%X "
1163 "IE Length %d",
1164 data->ap.ts,
1165 data->ap.ssid,
1166 MAC_ADDR_ARRAY(data->ap.bssid.bytes),
1167 data->ap.channel,
1168 data->ap.rssi,
1169 data->ap.rtt,
1170 data->ap.rtt_sd,
1171 data->ap.beaconPeriod,
1172 data->ap.capability,
1173 data->ap.ieLength);
1174 }
1175
1176 if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID,
1177 data->request_id) ||
1178 nla_put_u32(skb,
1179 QCA_WLAN_VENDOR_ATTR_EXTSCAN_PNO_RESULTS_PASSPOINT_NETWORK_FOUND_NUM_MATCHES,
1180 num_matches) ||
1181 nla_put_u8(skb,
1182 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_MORE_DATA,
1183 more_data)) {
1184 hddLog(LOGE, FL("nla put fail"));
1185 goto fail;
1186 }
1187
1188 nla_aps = nla_nest_start(skb,
1189 QCA_WLAN_VENDOR_ATTR_EXTSCAN_PNO_RESULTS_PASSPOINT_MATCH_RESULT_LIST);
1190 if (!nla_aps)
1191 goto fail;
1192
1193 for (i = 0; i < num_matches; i++) {
1194 struct nlattr *nla_ap;
1195
1196 nla_ap = nla_nest_start(skb, i);
1197 if (!nla_ap)
1198 goto fail;
1199
1200 if (nla_put_u32(skb,
1201 QCA_WLAN_VENDOR_ATTR_EXTSCAN_PNO_RESULTS_PASSPOINT_MATCH_ID,
1202 data->id) ||
1203 nla_put_u32(skb,
1204 QCA_WLAN_VENDOR_ATTR_EXTSCAN_PNO_RESULTS_PASSPOINT_MATCH_ANQP_LEN,
1205 data->anqp_len)) {
1206 goto fail;
1207 }
1208
1209 if (data->anqp_len)
1210 if (nla_put(skb,
1211 QCA_WLAN_VENDOR_ATTR_EXTSCAN_PNO_RESULTS_PASSPOINT_MATCH_ANQP,
1212 data->anqp_len, data->anqp))
1213 goto fail;
1214
1215 nla_bss = nla_nest_start(skb,
1216 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_LIST);
1217 if (!nla_bss)
1218 goto fail;
1219
1220 if (hdd_extscan_nl_fill_bss(skb, &data->ap, 0))
1221 goto fail;
1222
1223 nla_nest_end(skb, nla_bss);
1224 nla_nest_end(skb, nla_ap);
1225 }
1226 nla_nest_end(skb, nla_aps);
1227
1228 cfg80211_vendor_event(skb, GFP_KERNEL);
1229 return;
1230
1231fail:
1232 kfree_skb(skb);
1233 return;
1234}
1235
1236/**
1237 * wlan_hdd_cfg80211_extscan_hotlist_ssid_match_ind() -
1238 * Handle an SSID hotlist match event
1239 * @ctx: HDD context registered with SME
1240 * @event: The SSID hotlist match event
1241 *
1242 * This function will take an SSID match event that was generated by
1243 * firmware and will convert it into a cfg80211 vendor event which is
1244 * sent to userspace.
1245 *
1246 * Return: none
1247 */
1248static void
1249wlan_hdd_cfg80211_extscan_hotlist_ssid_match_ind(void *ctx,
1250 tpSirWifiScanResultEvent event)
1251{
1252 hdd_context_t *hdd_ctx = ctx;
1253 struct sk_buff *skb;
1254 uint32_t i, index;
1255
1256 ENTER();
1257
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301258 if (wlan_hdd_validate_context(hdd_ctx))
1259 return;
1260 if (!event) {
1261 hddLog(LOGE, FL("event is null"));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001262 return;
1263 }
1264
1265 if (event->ap_found) {
1266 index = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_SSID_FOUND_INDEX;
1267 hddLog(LOG1, "SSID hotlist found");
1268 } else {
1269 index = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_SSID_LOST_INDEX;
1270 hddLog(LOG1, "SSID hotlist lost");
1271 }
1272
1273 skb = cfg80211_vendor_event_alloc(hdd_ctx->wiphy,
1274 NULL,
1275 EXTSCAN_EVENT_BUF_SIZE + NLMSG_HDRLEN,
1276 index,
1277 GFP_KERNEL);
1278
1279 if (!skb) {
1280 hddLog(LOGE, FL("cfg80211_vendor_event_alloc failed"));
1281 return;
1282 }
1283 hddLog(LOG1, "Req Id %u, Num results %u, More Data %u",
1284 event->requestId, event->numOfAps, event->moreData);
1285
1286 for (i = 0; i < event->numOfAps; i++) {
1287 hddLog(LOG1, "[i=%d] Timestamp %llu "
1288 "Ssid: %s "
1289 "Bssid (" MAC_ADDRESS_STR ") "
1290 "Channel %u "
1291 "Rssi %d "
1292 "RTT %u "
1293 "RTT_SD %u",
1294 i,
1295 event->ap[i].ts,
1296 event->ap[i].ssid,
1297 MAC_ADDR_ARRAY(event->ap[i].bssid.bytes),
1298 event->ap[i].channel,
1299 event->ap[i].rssi,
1300 event->ap[i].rtt,
1301 event->ap[i].rtt_sd);
1302 }
1303
1304 if (nla_put_u32(skb,
1305 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID,
1306 event->requestId) ||
1307 nla_put_u32(skb,
1308 QCA_WLAN_VENDOR_ATTR_EXTSCAN_NUM_RESULTS_AVAILABLE,
1309 event->numOfAps)) {
1310 hddLog(LOGE, FL("put fail"));
1311 goto fail;
1312 }
1313
1314 if (event->numOfAps) {
1315 struct nlattr *aps;
1316 aps = nla_nest_start(skb,
1317 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_LIST);
1318 if (!aps) {
1319 hddLog(LOGE, FL("nest fail"));
1320 goto fail;
1321 }
1322
1323 for (i = 0; i < event->numOfAps; i++) {
1324 struct nlattr *ap;
1325
1326 ap = nla_nest_start(skb, i);
1327 if (!ap) {
1328 hddLog(LOGE, FL("nest fail"));
1329 goto fail;
1330 }
1331
1332 if (nla_put_u64(skb,
1333 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_TIME_STAMP,
1334 event->ap[i].ts) ||
1335 nla_put(skb,
1336 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_SSID,
1337 sizeof(event->ap[i].ssid),
1338 event->ap[i].ssid) ||
1339 nla_put(skb,
1340 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_BSSID,
1341 sizeof(event->ap[i].bssid),
1342 event->ap[i].bssid.bytes) ||
1343 nla_put_u32(skb,
1344 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_CHANNEL,
1345 event->ap[i].channel) ||
1346 nla_put_s32(skb,
1347 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RSSI,
1348 event->ap[i].rssi) ||
1349 nla_put_u32(skb,
1350 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RTT,
1351 event->ap[i].rtt) ||
1352 nla_put_u32(skb,
1353 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RTT_SD,
1354 event->ap[i].rtt_sd)) {
1355 hddLog(LOGE, FL("put fail"));
1356 goto fail;
1357 }
1358 nla_nest_end(skb, ap);
1359 }
1360 nla_nest_end(skb, aps);
1361
1362 if (nla_put_u8(skb,
1363 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_MORE_DATA,
1364 event->moreData)) {
1365 hddLog(LOGE, FL("put fail"));
1366 goto fail;
1367 }
1368 }
1369
1370 cfg80211_vendor_event(skb, GFP_KERNEL);
1371 return;
1372
1373fail:
1374 kfree_skb(skb);
1375 return;
1376}
1377
1378/**
1379 * wlan_hdd_cfg80211_extscan_generic_rsp() -
1380 * Handle a generic ExtScan Response message
1381 * @ctx: HDD context registered with SME
1382 * @response: The ExtScan response from firmware
1383 *
1384 * This function will handle a generic ExtScan response message from
1385 * firmware and will communicate the result to the userspace thread
1386 * that is waiting for the response.
1387 *
1388 * Return: none
1389 */
1390static void
1391wlan_hdd_cfg80211_extscan_generic_rsp
1392 (void *ctx,
1393 struct sir_extscan_generic_response *response)
1394{
1395 hdd_context_t *hdd_ctx = ctx;
1396 struct hdd_ext_scan_context *context;
1397
1398 ENTER();
1399
1400 if (wlan_hdd_validate_context(hdd_ctx) || !response) {
1401 hddLog(LOGE,
1402 FL("HDD context is not valid or response(%p) is null"),
1403 response);
1404 return;
1405 }
1406
1407 hddLog(LOG1, FL("request %u status %u"),
1408 response->request_id, response->status);
1409
1410 context = &ext_scan_context;
1411 spin_lock(&context->context_lock);
1412 if (context->request_id == response->request_id) {
1413 context->response_status = response->status ? -EINVAL : 0;
1414 complete(&context->response_event);
1415 }
1416 spin_unlock(&context->context_lock);
1417
1418 return;
1419}
1420
1421/**
1422 * wlan_hdd_cfg80211_extscan_callback() - ext scan callback
1423 * @ctx: Pointer to hdd context
1424 * @evType: Event type
1425 * @pMag: Pointer to message
1426 *
1427 * Return: none
1428 */
1429void wlan_hdd_cfg80211_extscan_callback(void *ctx, const uint16_t evType,
1430 void *pMsg)
1431{
1432 hdd_context_t *pHddCtx = (hdd_context_t *) ctx;
1433
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301434 ENTER();
1435
1436 if (wlan_hdd_validate_context(pHddCtx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001437 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001438
1439 hddLog(LOG1, FL("Rcvd Event %d"), evType);
1440
1441 switch (evType) {
1442 case eSIR_EXTSCAN_CACHED_RESULTS_RSP:
1443 /* There is no need to send this response to upper layer
1444 Just log the message */
1445 hddLog(LOG1,
1446 FL("Rcvd eSIR_EXTSCAN_CACHED_RESULTS_RSP"));
1447 break;
1448
1449 case eSIR_EXTSCAN_GET_CAPABILITIES_IND:
1450 wlan_hdd_cfg80211_extscan_get_capabilities_rsp(ctx,
1451 (struct ext_scan_capabilities_response *) pMsg);
1452 break;
1453
1454 case eSIR_EXTSCAN_HOTLIST_MATCH_IND:
1455 wlan_hdd_cfg80211_extscan_hotlist_match_ind(ctx, pMsg);
1456 break;
1457
1458 case eSIR_EXTSCAN_SIGNIFICANT_WIFI_CHANGE_RESULTS_IND:
1459 wlan_hdd_cfg80211_extscan_signif_wifi_change_results_ind(ctx,
1460 (tpSirWifiSignificantChangeEvent) pMsg);
1461 break;
1462
1463 case eSIR_EXTSCAN_CACHED_RESULTS_IND:
1464 wlan_hdd_cfg80211_extscan_cached_results_ind(ctx, pMsg);
1465 break;
1466
1467 case eSIR_EXTSCAN_SCAN_RES_AVAILABLE_IND:
1468 wlan_hdd_cfg80211_extscan_scan_res_available_event(ctx,
1469 (tpSirExtScanResultsAvailableIndParams) pMsg);
1470 break;
1471
1472 case eSIR_EXTSCAN_FULL_SCAN_RESULT_IND:
1473 wlan_hdd_cfg80211_extscan_full_scan_result_event(ctx,
1474 (tpSirWifiFullScanResultEvent) pMsg);
1475 break;
1476
1477 case eSIR_EPNO_NETWORK_FOUND_IND:
1478 wlan_hdd_cfg80211_extscan_epno_match_found(ctx,
1479 (struct pno_match_found *)pMsg);
1480 break;
1481
1482 case eSIR_EXTSCAN_HOTLIST_SSID_MATCH_IND:
1483 wlan_hdd_cfg80211_extscan_hotlist_ssid_match_ind(ctx,
1484 (tpSirWifiScanResultEvent)pMsg);
1485 break;
1486
1487 case eSIR_EXTSCAN_SCAN_PROGRESS_EVENT_IND:
1488 wlan_hdd_cfg80211_extscan_scan_progress_event(ctx,
1489 (tpSirExtScanOnScanEventIndParams) pMsg);
1490 break;
1491
1492 case eSIR_PASSPOINT_NETWORK_FOUND_IND:
1493 wlan_hdd_cfg80211_passpoint_match_found(ctx,
1494 (struct wifi_passpoint_match *) pMsg);
1495 break;
1496
1497 case eSIR_EXTSCAN_START_RSP:
1498 case eSIR_EXTSCAN_STOP_RSP:
1499 case eSIR_EXTSCAN_SET_BSSID_HOTLIST_RSP:
1500 case eSIR_EXTSCAN_RESET_BSSID_HOTLIST_RSP:
1501 case eSIR_EXTSCAN_SET_SIGNIFICANT_WIFI_CHANGE_RSP:
1502 case eSIR_EXTSCAN_RESET_SIGNIFICANT_WIFI_CHANGE_RSP:
1503 case eSIR_EXTSCAN_SET_SSID_HOTLIST_RSP:
1504 case eSIR_EXTSCAN_RESET_SSID_HOTLIST_RSP:
1505 wlan_hdd_cfg80211_extscan_generic_rsp(ctx, pMsg);
1506 break;
1507
1508 default:
1509 hddLog(LOGE, FL("Unknown event type %u"), evType);
1510 break;
1511 }
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301512 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001513}
1514
1515/*
1516 * define short names for the global vendor params
1517 * used by wlan_hdd_send_ext_scan_capability()
1518 */
1519#define PARAM_REQUEST_ID \
1520 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID
1521#define PARAM_STATUS \
1522 QCA_WLAN_VENDOR_ATTR_EXTSCAN_STATUS
1523#define MAX_SCAN_CACHE_SIZE \
1524 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_SCAN_CACHE_SIZE
1525#define MAX_SCAN_BUCKETS \
1526 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_SCAN_BUCKETS
1527#define MAX_AP_CACHE_PER_SCAN \
1528 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_AP_CACHE_PER_SCAN
1529#define MAX_RSSI_SAMPLE_SIZE \
1530 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_RSSI_SAMPLE_SIZE
1531#define MAX_SCAN_RPT_THRHOLD \
1532 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_SCAN_REPORTING_THRESHOLD
1533#define MAX_HOTLIST_BSSIDS \
1534 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_HOTLIST_BSSIDS
1535#define MAX_SIGNIFICANT_WIFI_CHANGE_APS \
1536 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_SIGNIFICANT_WIFI_CHANGE_APS
1537#define MAX_BSSID_HISTORY_ENTRIES \
1538 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_BSSID_HISTORY_ENTRIES
1539#define MAX_HOTLIST_SSIDS \
1540 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_HOTLIST_SSIDS
1541#define MAX_NUM_EPNO_NETS \
1542 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_NUM_EPNO_NETS
1543#define MAX_NUM_EPNO_NETS_BY_SSID \
1544 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_NUM_EPNO_NETS_BY_SSID
1545#define MAX_NUM_WHITELISTED_SSID \
1546 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_NUM_WHITELISTED_SSID
1547
1548/**
1549 * wlan_hdd_send_ext_scan_capability - send ext scan capability to user space
1550 * @hdd_ctx: Pointer to hdd context
1551 *
1552 * Return: 0 for success, non-zero for failure
1553 */
1554static int wlan_hdd_send_ext_scan_capability(hdd_context_t *hdd_ctx)
1555{
1556 int ret;
1557 struct sk_buff *skb;
1558 struct ext_scan_capabilities_response *data;
1559 uint32_t nl_buf_len;
1560
1561 ret = wlan_hdd_validate_context(hdd_ctx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301562 if (0 != ret)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001563 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001564
1565 data = &(ext_scan_context.capability_response);
1566
1567 nl_buf_len = NLMSG_HDRLEN;
1568 nl_buf_len += (sizeof(data->requestId) + NLA_HDRLEN) +
1569 (sizeof(data->status) + NLA_HDRLEN) +
1570 (sizeof(data->max_scan_cache_size) + NLA_HDRLEN) +
1571 (sizeof(data->max_scan_buckets) + NLA_HDRLEN) +
1572 (sizeof(data->max_ap_cache_per_scan) + NLA_HDRLEN) +
1573 (sizeof(data->max_rssi_sample_size) + NLA_HDRLEN) +
1574 (sizeof(data->max_scan_reporting_threshold) + NLA_HDRLEN) +
1575 (sizeof(data->max_hotlist_bssids) + NLA_HDRLEN) +
1576 (sizeof(data->max_significant_wifi_change_aps) + NLA_HDRLEN) +
1577 (sizeof(data->max_bssid_history_entries) + NLA_HDRLEN) +
1578 (sizeof(data->max_hotlist_ssids) + NLA_HDRLEN) +
1579 (sizeof(data->max_number_epno_networks) + NLA_HDRLEN) +
1580 (sizeof(data->max_number_epno_networks_by_ssid) + NLA_HDRLEN) +
1581 (sizeof(data->max_number_of_white_listed_ssid) + NLA_HDRLEN);
1582
1583 skb = cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, nl_buf_len);
1584
1585 if (!skb) {
1586 hddLog(LOGE, FL("cfg80211_vendor_cmd_alloc_reply_skb failed"));
1587 return -ENOMEM;
1588 }
1589
1590
1591 hddLog(LOG1, "Req Id %u", data->requestId);
1592 hddLog(LOG1, "Status %u", data->status);
1593 hddLog(LOG1, "Scan cache size %u",
1594 data->max_scan_cache_size);
1595 hddLog(LOG1, "Scan buckets %u", data->max_scan_buckets);
1596 hddLog(LOG1, "Max AP per scan %u",
1597 data->max_ap_cache_per_scan);
1598 hddLog(LOG1, "max_rssi_sample_size %u",
1599 data->max_rssi_sample_size);
1600 hddLog(LOG1, "max_scan_reporting_threshold %u",
1601 data->max_scan_reporting_threshold);
1602 hddLog(LOG1, "max_hotlist_bssids %u",
1603 data->max_hotlist_bssids);
1604 hddLog(LOG1, "max_significant_wifi_change_aps %u",
1605 data->max_significant_wifi_change_aps);
1606 hddLog(LOG1, "max_bssid_history_entries %u",
1607 data->max_bssid_history_entries);
1608 hddLog(LOG1, "max_hotlist_ssids %u", data->max_hotlist_ssids);
1609 hddLog(LOG1, "max_number_epno_networks %u",
1610 data->max_number_epno_networks);
1611 hddLog(LOG1, "max_number_epno_networks_by_ssid %u",
1612 data->max_number_epno_networks_by_ssid);
1613 hddLog(LOG1, "max_number_of_white_listed_ssid %u",
1614 data->max_number_of_white_listed_ssid);
1615
1616 if (nla_put_u32(skb, PARAM_REQUEST_ID, data->requestId) ||
1617 nla_put_u32(skb, PARAM_STATUS, data->status) ||
1618 nla_put_u32(skb, MAX_SCAN_CACHE_SIZE, data->max_scan_cache_size) ||
1619 nla_put_u32(skb, MAX_SCAN_BUCKETS, data->max_scan_buckets) ||
1620 nla_put_u32(skb, MAX_AP_CACHE_PER_SCAN,
1621 data->max_ap_cache_per_scan) ||
1622 nla_put_u32(skb, MAX_RSSI_SAMPLE_SIZE,
1623 data->max_rssi_sample_size) ||
1624 nla_put_u32(skb, MAX_SCAN_RPT_THRHOLD,
1625 data->max_scan_reporting_threshold) ||
1626 nla_put_u32(skb, MAX_HOTLIST_BSSIDS, data->max_hotlist_bssids) ||
1627 nla_put_u32(skb, MAX_SIGNIFICANT_WIFI_CHANGE_APS,
1628 data->max_significant_wifi_change_aps) ||
1629 nla_put_u32(skb, MAX_BSSID_HISTORY_ENTRIES,
1630 data->max_bssid_history_entries) ||
1631 nla_put_u32(skb, MAX_HOTLIST_SSIDS, data->max_hotlist_ssids) ||
1632 nla_put_u32(skb, MAX_NUM_EPNO_NETS,
1633 data->max_number_epno_networks) ||
1634 nla_put_u32(skb, MAX_NUM_EPNO_NETS_BY_SSID,
1635 data->max_number_epno_networks_by_ssid) ||
1636 nla_put_u32(skb, MAX_NUM_WHITELISTED_SSID,
1637 data->max_number_of_white_listed_ssid)) {
1638 hddLog(LOGE, FL("nla put fail"));
1639 goto nla_put_failure;
1640 }
1641
1642 cfg80211_vendor_cmd_reply(skb);
1643 return 0;
1644
1645nla_put_failure:
1646 kfree_skb(skb);
1647 return -EINVAL;
1648}
1649/*
1650 * done with short names for the global vendor params
1651 * used by wlan_hdd_send_ext_scan_capability()
1652 */
1653#undef PARAM_REQUEST_ID
1654#undef PARAM_STATUS
1655#undef MAX_SCAN_CACHE_SIZE
1656#undef MAX_SCAN_BUCKETS
1657#undef MAX_AP_CACHE_PER_SCAN
1658#undef MAX_RSSI_SAMPLE_SIZE
1659#undef MAX_SCAN_RPT_THRHOLD
1660#undef MAX_HOTLIST_BSSIDS
1661#undef MAX_SIGNIFICANT_WIFI_CHANGE_APS
1662#undef MAX_BSSID_HISTORY_ENTRIES
1663#undef MAX_HOTLIST_SSIDS
1664#undef MAX_NUM_EPNO_NETS
1665#undef MAX_NUM_EPNO_NETS_BY_SSID
1666#undef MAX_NUM_WHITELISTED_SSID
1667
1668/**
1669 * __wlan_hdd_cfg80211_extscan_get_capabilities() - get ext scan capabilities
1670 * @wiphy: Pointer to wireless phy
1671 * @wdev: Pointer to wireless device
1672 * @data: Pointer to data
1673 * @data_len: Data length
1674 *
1675 * Return: none
1676 */
1677static int __wlan_hdd_cfg80211_extscan_get_capabilities(struct wiphy *wiphy,
1678 struct wireless_dev *wdev,
1679 const void *data, int data_len)
1680{
1681 int ret;
1682 unsigned long rc;
1683 struct hdd_ext_scan_context *context;
1684 tpSirGetExtScanCapabilitiesReqParams pReqMsg = NULL;
1685 struct net_device *dev = wdev->netdev;
1686 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
1687 hdd_context_t *pHddCtx = wiphy_priv(wiphy);
1688 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX +
1689 1];
1690 CDF_STATUS status;
1691
1692 ENTER();
1693
1694 if (CDF_FTM_MODE == hdd_get_conparam()) {
1695 hdd_err("Command not allowed in FTM mode");
1696 return -EPERM;
1697 }
1698
1699 ret = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301700 if (0 != ret)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001701 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001702
1703 if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX,
1704 data, data_len, wlan_hdd_extscan_config_policy)) {
1705 hddLog(LOGE, FL("Invalid ATTR"));
1706 return -EINVAL;
1707 }
1708
1709 pReqMsg = cdf_mem_malloc(sizeof(*pReqMsg));
1710 if (!pReqMsg) {
1711 hddLog(LOGE, FL("cdf_mem_malloc failed"));
1712 return -ENOMEM;
1713 }
1714
1715 /* Parse and fetch request Id */
1716 if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]) {
1717 hddLog(LOGE, FL("attr request id failed"));
1718 goto fail;
1719 }
1720
1721 pReqMsg->requestId =
1722 nla_get_u32(tb
1723 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]);
1724 pReqMsg->sessionId = pAdapter->sessionId;
1725 hddLog(LOG1, FL("Req Id %d Session Id %d"),
1726 pReqMsg->requestId, pReqMsg->sessionId);
1727
1728 context = &ext_scan_context;
1729 spin_lock(&context->context_lock);
1730 context->request_id = pReqMsg->requestId;
1731 INIT_COMPLETION(context->response_event);
1732 spin_unlock(&context->context_lock);
1733
1734 status = sme_ext_scan_get_capabilities(pHddCtx->hHal, pReqMsg);
1735 if (!CDF_IS_STATUS_SUCCESS(status)) {
1736 hddLog(LOGE, FL("sme_ext_scan_get_capabilities failed(err=%d)"),
1737 status);
1738 goto fail;
1739 }
1740
1741 rc = wait_for_completion_timeout(&context->response_event,
1742 msecs_to_jiffies(WLAN_WAIT_TIME_EXTSCAN));
1743 if (!rc) {
1744 hddLog(LOGE, FL("Target response timed out"));
1745 return -ETIMEDOUT;
1746 }
1747
1748 ret = wlan_hdd_send_ext_scan_capability(pHddCtx);
1749 if (ret)
1750 hddLog(LOGE, FL("Failed to send ext scan capability to user space"));
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301751 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001752 return ret;
1753fail:
1754 cdf_mem_free(pReqMsg);
1755 return -EINVAL;
1756}
1757
1758/**
1759 * wlan_hdd_cfg80211_extscan_get_capabilities() - get ext scan capabilities
1760 * @wiphy: Pointer to wiphy
1761 * @wdev: Pointer to wdev
1762 * @data: Pointer to data
1763 * @data_len: Data length
1764 *
1765 * Return: 0 for success, non-zero for failure
1766 */
1767int wlan_hdd_cfg80211_extscan_get_capabilities(struct wiphy *wiphy,
1768 struct wireless_dev *wdev,
1769 const void *data, int data_len)
1770{
1771 int ret = 0;
1772
1773 cds_ssr_protect(__func__);
1774 ret = __wlan_hdd_cfg80211_extscan_get_capabilities(wiphy, wdev, data,
1775 data_len);
1776 cds_ssr_unprotect(__func__);
1777
1778 return ret;
1779}
1780
1781/*
1782 * define short names for the global vendor params
1783 * used by wlan_hdd_cfg80211_extscan_get_cached_results()
1784 */
1785#define PARAM_MAX \
1786 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX
1787#define PARAM_REQUEST_ID \
1788 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID
1789#define PARAM_FLUSH \
1790 QCA_WLAN_VENDOR_ATTR_EXTSCAN_GET_CACHED_SCAN_RESULTS_CONFIG_PARAM_FLUSH
1791/**
1792 * __wlan_hdd_cfg80211_extscan_get_cached_results() - extscan get cached results
1793 * @wiphy: wiphy pointer
1794 * @wdev: pointer to struct wireless_dev
1795 * @data: pointer to incoming NL vendor data
1796 * @data_len: length of @data
1797 *
1798 * This function parses the incoming NL vendor command data attributes and
1799 * invokes the SME Api and blocks on a completion variable.
1800 * Each WMI event with cached scan results data chunk results in
1801 * function call wlan_hdd_cfg80211_extscan_cached_results_ind and each
1802 * data chunk is sent up the layer in cfg80211_vendor_cmd_alloc_reply_skb.
1803 *
1804 * If timeout happens before receiving all of the data, this function sets
1805 * a context variable @ignore_cached_results to %true, all of the next data
1806 * chunks are checked against this variable and dropped.
1807 *
1808 * Return: 0 on success; error number otherwise.
1809 */
1810static int __wlan_hdd_cfg80211_extscan_get_cached_results(struct wiphy *wiphy,
1811 struct wireless_dev
1812 *wdev, const void *data,
1813 int data_len)
1814{
1815 tpSirExtScanGetCachedResultsReqParams pReqMsg = NULL;
1816 struct net_device *dev = wdev->netdev;
1817 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
1818 hdd_context_t *pHddCtx = wiphy_priv(wiphy);
1819 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX +
1820 1];
1821 struct hdd_ext_scan_context *context;
1822 CDF_STATUS status;
1823 int retval = 0;
1824 unsigned long rc;
1825
1826 ENTER();
1827
1828 if (CDF_FTM_MODE == hdd_get_conparam()) {
1829 hdd_err("Command not allowed in FTM mode");
1830 return -EPERM;
1831 }
1832
1833 retval = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301834 if (0 != retval)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001835 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001836
1837 if (nla_parse(tb, PARAM_MAX, data, data_len,
1838 wlan_hdd_extscan_config_policy)) {
1839 hddLog(LOGE, FL("Invalid ATTR"));
1840 return -EINVAL;
1841 }
1842
1843 pReqMsg = cdf_mem_malloc(sizeof(*pReqMsg));
1844 if (!pReqMsg) {
1845 hddLog(LOGE, FL("cdf_mem_malloc failed"));
1846 return -ENOMEM;
1847 }
1848
1849 /* Parse and fetch request Id */
1850 if (!tb[PARAM_REQUEST_ID]) {
1851 hddLog(LOGE, FL("attr request id failed"));
1852 goto fail;
1853 }
1854
1855 pReqMsg->requestId = nla_get_u32(tb[PARAM_REQUEST_ID]);
1856 pReqMsg->sessionId = pAdapter->sessionId;
1857 hddLog(LOG1, FL("Req Id %d Session Id %d"),
1858 pReqMsg->requestId, pReqMsg->sessionId);
1859
1860 /* Parse and fetch flush parameter */
1861 if (!tb[PARAM_FLUSH]) {
1862 hddLog(LOGE, FL("attr flush failed"));
1863 goto fail;
1864 }
1865 pReqMsg->flush = nla_get_u8(tb[PARAM_FLUSH]);
1866 hddLog(LOG1, FL("Flush %d"), pReqMsg->flush);
1867
1868 context = &ext_scan_context;
1869 spin_lock(&context->context_lock);
1870 context->request_id = pReqMsg->requestId;
1871 context->ignore_cached_results = false;
1872 INIT_COMPLETION(context->response_event);
1873 spin_unlock(&context->context_lock);
1874
1875 status = sme_get_cached_results(pHddCtx->hHal, pReqMsg);
1876 if (!CDF_IS_STATUS_SUCCESS(status)) {
1877 hddLog(LOGE,
1878 FL("sme_get_cached_results failed(err=%d)"), status);
1879 goto fail;
1880 }
1881
1882 rc = wait_for_completion_timeout(&context->response_event,
1883 msecs_to_jiffies(WLAN_WAIT_TIME_EXTSCAN));
1884 if (!rc) {
1885 hddLog(LOGE, FL("Target response timed out"));
1886 retval = -ETIMEDOUT;
1887 spin_lock(&context->context_lock);
1888 context->ignore_cached_results = true;
1889 spin_unlock(&context->context_lock);
1890 } else {
1891 spin_lock(&context->context_lock);
1892 retval = context->response_status;
1893 spin_unlock(&context->context_lock);
1894 }
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301895 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001896 return retval;
1897
1898fail:
1899 cdf_mem_free(pReqMsg);
1900 return -EINVAL;
1901}
1902/*
1903 * done with short names for the global vendor params
1904 * used by wlan_hdd_cfg80211_extscan_get_cached_results()
1905 */
1906#undef PARAM_MAX
1907#undef PARAM_REQUEST_ID
1908#undef PARAM_FLUSH
1909
1910/**
1911 * wlan_hdd_cfg80211_extscan_get_cached_results() - extscan get cached results
1912 * @wiphy: wiphy pointer
1913 * @wdev: pointer to struct wireless_dev
1914 * @data: pointer to incoming NL vendor data
1915 * @data_len: length of @data
1916 *
1917 * This function parses the incoming NL vendor command data attributes and
1918 * invokes the SME Api and blocks on a completion variable.
1919 * Each WMI event with cached scan results data chunk results in
1920 * function call wlan_hdd_cfg80211_extscan_cached_results_ind and each
1921 * data chunk is sent up the layer in cfg80211_vendor_cmd_alloc_reply_skb.
1922 *
1923 * If timeout happens before receiving all of the data, this function sets
1924 * a context variable @ignore_cached_results to %true, all of the next data
1925 * chunks are checked against this variable and dropped.
1926 *
1927 * Return: 0 on success; error number otherwise.
1928 */
1929int wlan_hdd_cfg80211_extscan_get_cached_results(struct wiphy *wiphy,
1930 struct wireless_dev *wdev,
1931 const void *data, int data_len)
1932{
1933 int ret = 0;
1934
1935 cds_ssr_protect(__func__);
1936 ret = __wlan_hdd_cfg80211_extscan_get_cached_results(wiphy, wdev, data,
1937 data_len);
1938 cds_ssr_unprotect(__func__);
1939
1940 return ret;
1941}
1942
1943/**
1944 * __wlan_hdd_cfg80211_extscan_set_bssid_hotlist() - set bssid hot list
1945 * @wiphy: Pointer to wireless phy
1946 * @wdev: Pointer to wireless device
1947 * @data: Pointer to data
1948 * @data_len: Data length
1949 *
1950 * Return: none
1951 */
1952static int
1953__wlan_hdd_cfg80211_extscan_set_bssid_hotlist(struct wiphy *wiphy,
1954 struct wireless_dev
1955 *wdev, const void *data,
1956 int data_len)
1957{
1958 tpSirExtScanSetBssidHotListReqParams pReqMsg = NULL;
1959 struct net_device *dev = wdev->netdev;
1960 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
1961 hdd_context_t *pHddCtx = wiphy_priv(wiphy);
1962 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX +
1963 1];
1964 struct nlattr *tb2[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX
1965 + 1];
1966 struct nlattr *apTh;
1967 struct hdd_ext_scan_context *context;
1968 uint32_t request_id;
1969 CDF_STATUS status;
1970 uint8_t i;
1971 int rem, retval;
1972 unsigned long rc;
1973
1974 ENTER();
1975
1976 if (CDF_FTM_MODE == hdd_get_conparam()) {
1977 hdd_err("Command not allowed in FTM mode");
1978 return -EPERM;
1979 }
1980
1981 retval = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301982 if (0 != retval)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001983 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001984
1985 if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX,
1986 data, data_len, wlan_hdd_extscan_config_policy)) {
1987 hddLog(LOGE, FL("Invalid ATTR"));
1988 return -EINVAL;
1989 }
1990
1991 pReqMsg = cdf_mem_malloc(sizeof(*pReqMsg));
1992 if (!pReqMsg) {
1993 hddLog(LOGE, FL("cdf_mem_malloc failed"));
1994 return -ENOMEM;
1995 }
1996
1997 /* Parse and fetch request Id */
1998 if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]) {
1999 hddLog(LOGE, FL("attr request id failed"));
2000 goto fail;
2001 }
2002
2003 pReqMsg->requestId =
2004 nla_get_u32(tb
2005 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]);
2006 hddLog(LOG1, FL("Req Id %d"), pReqMsg->requestId);
2007
2008 /* Parse and fetch number of APs */
2009 if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BSSID_HOTLIST_PARAMS_NUM_AP]) {
2010 hddLog(LOGE, FL("attr number of AP failed"));
2011 goto fail;
2012 }
2013 pReqMsg->numAp =
2014 nla_get_u32(tb
2015 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_BSSID_HOTLIST_PARAMS_NUM_AP]);
2016 pReqMsg->sessionId = pAdapter->sessionId;
2017 hddLog(LOG1, FL("Number of AP %d Session Id %d"),
2018 pReqMsg->numAp, pReqMsg->sessionId);
2019
2020 /* Parse and fetch lost ap sample size */
2021 if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BSSID_HOTLIST_PARAMS_LOST_AP_SAMPLE_SIZE]) {
2022 hddLog(LOGE, FL("attr lost ap sample size failed"));
2023 goto fail;
2024 }
2025
2026 pReqMsg->lost_ap_sample_size = nla_get_u32(
2027 tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BSSID_HOTLIST_PARAMS_LOST_AP_SAMPLE_SIZE]);
2028 hddLog(LOG1, FL("Lost ap sample size %d"),
2029 pReqMsg->lost_ap_sample_size);
2030
2031 i = 0;
2032 nla_for_each_nested(apTh,
2033 tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM],
2034 rem) {
2035 if (nla_parse
2036 (tb2, QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX,
2037 nla_data(apTh), nla_len(apTh),
2038 wlan_hdd_extscan_config_policy)) {
2039 hddLog(LOGE, FL("nla_parse failed"));
2040 goto fail;
2041 }
2042
2043 /* Parse and fetch MAC address */
2044 if (!tb2[QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_BSSID]) {
2045 hddLog(LOGE, FL("attr mac address failed"));
2046 goto fail;
2047 }
2048 nla_memcpy(pReqMsg->ap[i].bssid.bytes,
2049 tb2
2050 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_BSSID],
2051 CDF_MAC_ADDR_SIZE);
2052 hddLog(LOG1, MAC_ADDRESS_STR,
2053 MAC_ADDR_ARRAY(pReqMsg->ap[i].bssid.bytes));
2054
2055 /* Parse and fetch low RSSI */
2056 if (!tb2
2057 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_RSSI_LOW]) {
2058 hddLog(LOGE, FL("attr low RSSI failed"));
2059 goto fail;
2060 }
2061 pReqMsg->ap[i].low =
2062 nla_get_s32(tb2
2063 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_RSSI_LOW]);
2064 hddLog(LOG1, FL("RSSI low %d"), pReqMsg->ap[i].low);
2065
2066 /* Parse and fetch high RSSI */
2067 if (!tb2
2068 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_RSSI_HIGH]) {
2069 hddLog(LOGE, FL("attr high RSSI failed"));
2070 goto fail;
2071 }
2072 pReqMsg->ap[i].high =
2073 nla_get_s32(tb2
2074 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_RSSI_HIGH]);
2075 hddLog(LOG1, FL("RSSI High %d"), pReqMsg->ap[i].high);
2076
2077 i++;
2078 }
2079
2080 context = &ext_scan_context;
2081 spin_lock(&context->context_lock);
2082 INIT_COMPLETION(context->response_event);
2083 context->request_id = request_id = pReqMsg->requestId;
2084 spin_unlock(&context->context_lock);
2085
2086 status = sme_set_bss_hotlist(pHddCtx->hHal, pReqMsg);
2087 if (!CDF_IS_STATUS_SUCCESS(status)) {
2088 hddLog(LOGE, FL("sme_set_bss_hotlist failed(err=%d)"), status);
2089 goto fail;
2090 }
2091
2092 /* request was sent -- wait for the response */
2093 rc = wait_for_completion_timeout
2094 (&context->response_event,
2095 msecs_to_jiffies(WLAN_WAIT_TIME_EXTSCAN));
2096
2097 if (!rc) {
2098 hddLog(LOGE, FL("sme_set_bss_hotlist timed out"));
2099 retval = -ETIMEDOUT;
2100 } else {
2101 spin_lock(&context->context_lock);
2102 if (context->request_id == request_id)
2103 retval = context->response_status;
2104 else
2105 retval = -EINVAL;
2106 spin_unlock(&context->context_lock);
2107 }
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05302108 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002109 return retval;
2110
2111fail:
2112 cdf_mem_free(pReqMsg);
2113 return -EINVAL;
2114}
2115
2116/**
2117 * wlan_hdd_cfg80211_extscan_set_bssid_hotlist() - set ext scan bssid hotlist
2118 * @wiphy: Pointer to wiphy
2119 * @wdev: Pointer to wdev
2120 * @data: Pointer to data
2121 * @data_len: Data length
2122 *
2123 * Return: 0 for success, non-zero for failure
2124 */
2125int wlan_hdd_cfg80211_extscan_set_bssid_hotlist(struct wiphy *wiphy,
2126 struct wireless_dev *wdev,
2127 const void *data, int data_len)
2128{
2129 int ret = 0;
2130
2131 cds_ssr_protect(__func__);
2132 ret = __wlan_hdd_cfg80211_extscan_set_bssid_hotlist(wiphy, wdev, data,
2133 data_len);
2134 cds_ssr_unprotect(__func__);
2135
2136 return ret;
2137}
2138
2139
2140/**
2141 * __wlan_hdd_cfg80211_extscan_set_significant_change () - set significant change
2142 * @wiphy: Pointer to wireless phy
2143 * @wdev: Pointer to wireless device
2144 * @data: Pointer to data
2145 * @data_len: Data length
2146 *
2147 * Return: none
2148 */
2149static int
2150__wlan_hdd_cfg80211_extscan_set_significant_change(struct wiphy *wiphy,
2151 struct wireless_dev
2152 *wdev, const void *data,
2153 int data_len)
2154{
2155 tpSirExtScanSetSigChangeReqParams pReqMsg = NULL;
2156 struct net_device *dev = wdev->netdev;
2157 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
2158 hdd_context_t *pHddCtx = wiphy_priv(wiphy);
2159 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX +
2160 1];
2161 struct nlattr *tb2[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX
2162 + 1];
2163 struct nlattr *apTh;
2164 struct hdd_ext_scan_context *context;
2165 uint32_t request_id;
2166 CDF_STATUS status;
2167 uint8_t i;
2168 int rem, retval;
2169 unsigned long rc;
2170
2171 ENTER();
2172
2173 if (CDF_FTM_MODE == hdd_get_conparam()) {
2174 hdd_err("Command not allowed in FTM mode");
2175 return -EPERM;
2176 }
2177
2178 retval = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05302179 if (0 != retval)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002180 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002181
2182 if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX,
2183 data, data_len, wlan_hdd_extscan_config_policy)) {
2184 hddLog(LOGE, FL("Invalid ATTR"));
2185 return -EINVAL;
2186 }
2187
2188 pReqMsg = cdf_mem_malloc(sizeof(*pReqMsg));
2189 if (!pReqMsg) {
2190 hddLog(LOGE, FL("cdf_mem_malloc failed"));
2191 return -ENOMEM;
2192 }
2193
2194 /* Parse and fetch request Id */
2195 if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]) {
2196 hddLog(LOGE, FL("attr request id failed"));
2197 goto fail;
2198 }
2199
2200 pReqMsg->requestId =
2201 nla_get_u32(tb
2202 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]);
2203 hddLog(LOG1, FL("Req Id %d"), pReqMsg->requestId);
2204
2205 /* Parse and fetch RSSI sample size */
2206 if (!tb
2207 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_RSSI_SAMPLE_SIZE]) {
2208 hddLog(LOGE, FL("attr RSSI sample size failed"));
2209 goto fail;
2210 }
2211 pReqMsg->rssiSampleSize =
2212 nla_get_u32(tb
2213 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_RSSI_SAMPLE_SIZE]);
2214 hddLog(LOG1, FL("RSSI sample size %u"), pReqMsg->rssiSampleSize);
2215
2216 /* Parse and fetch lost AP sample size */
2217 if (!tb
2218 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_LOST_AP_SAMPLE_SIZE]) {
2219 hddLog(LOGE, FL("attr lost AP sample size failed"));
2220 goto fail;
2221 }
2222 pReqMsg->lostApSampleSize =
2223 nla_get_u32(tb
2224 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_LOST_AP_SAMPLE_SIZE]);
2225 hddLog(LOG1, FL("Lost AP sample size %u"), pReqMsg->lostApSampleSize);
2226
2227 /* Parse and fetch AP min breacing */
2228 if (!tb
2229 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_MIN_BREACHING]) {
2230 hddLog(LOGE, FL("attr AP min breaching"));
2231 goto fail;
2232 }
2233 pReqMsg->minBreaching =
2234 nla_get_u32(tb
2235 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_MIN_BREACHING]);
2236 hddLog(LOG1, FL("AP min breaching %u"), pReqMsg->minBreaching);
2237
2238 /* Parse and fetch number of APs */
2239 if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_NUM_AP]) {
2240 hddLog(LOGE, FL("attr number of AP failed"));
2241 goto fail;
2242 }
2243 pReqMsg->numAp =
2244 nla_get_u32(tb
2245 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_NUM_AP]);
2246 pReqMsg->sessionId = pAdapter->sessionId;
2247 hddLog(LOG1, FL("Number of AP %d Session Id %d"),
2248 pReqMsg->numAp, pReqMsg->sessionId);
2249
2250 i = 0;
2251 nla_for_each_nested(apTh,
2252 tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM],
2253 rem) {
2254 if (nla_parse
2255 (tb2, QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX,
2256 nla_data(apTh), nla_len(apTh),
2257 wlan_hdd_extscan_config_policy)) {
2258 hddLog(LOGE, FL("nla_parse failed"));
2259 goto fail;
2260 }
2261
2262 /* Parse and fetch MAC address */
2263 if (!tb2[QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_BSSID]) {
2264 hddLog(LOGE, FL("attr mac address failed"));
2265 goto fail;
2266 }
2267 nla_memcpy(pReqMsg->ap[i].bssid.bytes,
2268 tb2
2269 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_BSSID],
2270 CDF_MAC_ADDR_SIZE);
2271 hddLog(LOG1, MAC_ADDRESS_STR,
2272 MAC_ADDR_ARRAY(pReqMsg->ap[i].bssid.bytes));
2273
2274 /* Parse and fetch low RSSI */
2275 if (!tb2
2276 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_RSSI_LOW]) {
2277 hddLog(LOGE, FL("attr low RSSI failed"));
2278 goto fail;
2279 }
2280 pReqMsg->ap[i].low =
2281 nla_get_s32(tb2
2282 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_RSSI_LOW]);
2283 hddLog(LOG1, FL("RSSI low %d"), pReqMsg->ap[i].low);
2284
2285 /* Parse and fetch high RSSI */
2286 if (!tb2
2287 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_RSSI_HIGH]) {
2288 hddLog(LOGE, FL("attr high RSSI failed"));
2289 goto fail;
2290 }
2291 pReqMsg->ap[i].high =
2292 nla_get_s32(tb2
2293 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_RSSI_HIGH]);
2294 hddLog(LOG1, FL("RSSI High %d"), pReqMsg->ap[i].high);
2295
2296 i++;
2297 }
2298
2299 context = &ext_scan_context;
2300 spin_lock(&context->context_lock);
2301 INIT_COMPLETION(context->response_event);
2302 context->request_id = request_id = pReqMsg->requestId;
2303 spin_unlock(&context->context_lock);
2304
2305 status = sme_set_significant_change(pHddCtx->hHal, pReqMsg);
2306 if (!CDF_IS_STATUS_SUCCESS(status)) {
2307 hddLog(LOGE,
2308 FL("sme_set_significant_change failed(err=%d)"), status);
2309 cdf_mem_free(pReqMsg);
2310 return -EINVAL;
2311 }
2312
2313 /* request was sent -- wait for the response */
2314 rc = wait_for_completion_timeout(&context->response_event,
2315 msecs_to_jiffies(WLAN_WAIT_TIME_EXTSCAN));
2316
2317 if (!rc) {
2318 hddLog(LOGE, FL("sme_set_significant_change timed out"));
2319 retval = -ETIMEDOUT;
2320 } else {
2321 spin_lock(&context->context_lock);
2322 if (context->request_id == request_id)
2323 retval = context->response_status;
2324 else
2325 retval = -EINVAL;
2326 spin_unlock(&context->context_lock);
2327 }
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05302328 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002329 return retval;
2330
2331fail:
2332 cdf_mem_free(pReqMsg);
2333 return -EINVAL;
2334}
2335
2336/**
2337 * wlan_hdd_cfg80211_extscan_set_significant_change() - set significant change
2338 * @wiphy: Pointer to wireless phy
2339 * @wdev: Pointer to wireless device
2340 * @data: Pointer to data
2341 * @data_len: Data length
2342 *
2343 * Return: 0 on success, negative errno on failure
2344 */
2345int wlan_hdd_cfg80211_extscan_set_significant_change(struct wiphy *wiphy,
2346 struct wireless_dev *wdev,
2347 const void *data, int data_len)
2348{
2349 int ret = 0;
2350
2351 cds_ssr_protect(__func__);
2352 ret = __wlan_hdd_cfg80211_extscan_set_significant_change(wiphy, wdev,
2353 data, data_len);
2354 cds_ssr_unprotect(__func__);
2355
2356 return ret;
2357}
2358
2359/**
2360 * hdd_remove_dsrc_channels () - remove dsrc chanels
2361 * @wiphy: Pointer to wireless phy
2362 * @chan_list: channel list
2363 * @num_channels: number of channels
2364 *
2365 * Return: none
2366 */
2367void hdd_remove_dsrc_channels(struct wiphy *wiphy, uint32_t *chan_list,
2368 uint8_t *num_channels)
2369{
2370 uint8_t num_chan_temp = 0;
2371 int i;
2372
2373 for (i = 0; i < *num_channels; i++) {
2374 if (!cds_is_dsrc_channel(chan_list[i])) {
2375 chan_list[num_chan_temp] = chan_list[i];
2376 num_chan_temp++;
2377 }
2378 }
2379
2380 *num_channels = num_chan_temp;
2381}
2382
2383/**
2384 * hdd_remove_indoor_channels () - remove indoor channels
2385 * @wiphy: Pointer to wireless phy
2386 * @chan_list: channel list
2387 * @num_channels: number of channels
2388 *
2389 * Return: none
2390 */
2391#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
2392void hdd_remove_indoor_channels(struct wiphy *wiphy, uint32_t *chan_list,
2393 uint8_t *num_channels)
2394{
2395 uint8_t num_chan_temp = 0;
2396 int i, j, k;
2397
2398 for (i = 0; i < *num_channels; i++)
2399 for (j = 0; j < IEEE80211_NUM_BANDS; j++) {
2400 if (wiphy->bands[j] == NULL)
2401 continue;
2402 for (k = 0; k < wiphy->bands[j]->n_channels; k++) {
2403 if ((chan_list[i] ==
2404 wiphy->bands[j]->channels[k].center_freq)
2405 && (!(wiphy->bands[j]->channels[k].flags &
2406 IEEE80211_CHAN_INDOOR_ONLY))
2407 ) {
2408 chan_list[num_chan_temp] = chan_list[i];
2409 num_chan_temp++;
2410 }
2411 }
2412 }
2413
2414 *num_channels = num_chan_temp;
2415}
2416#else
2417void hdd_remove_indoor_channels(struct wiphy *wiphy, uint32_t *chan_list,
2418 uint8_t *num_channels)
2419{
2420 *num_channels = 0;
2421}
2422#endif
2423
2424/**
2425 * __wlan_hdd_cfg80211_extscan_get_valid_channels () - get valid channels
2426 * @wiphy: Pointer to wireless phy
2427 * @wdev: Pointer to wireless device
2428 * @data: Pointer to data
2429 * @data_len: Data length
2430 *
2431 * Return: none
2432 */
2433static int
2434__wlan_hdd_cfg80211_extscan_get_valid_channels(struct wiphy *wiphy,
2435 struct wireless_dev
2436 *wdev, const void *data,
2437 int data_len)
2438{
2439 hdd_context_t *pHddCtx = wiphy_priv(wiphy);
2440 struct net_device *dev = wdev->netdev;
2441 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
2442 uint32_t chan_list[WNI_CFG_VALID_CHANNEL_LIST_LEN] = {0};
2443 uint8_t num_channels = 0;
2444 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX +
2445 1];
2446 uint32_t requestId, maxChannels;
2447 tWifiBand wifiBand;
2448 CDF_STATUS status;
2449 struct sk_buff *reply_skb;
2450 uint8_t i;
2451 int ret;
2452
2453 ENTER();
2454
2455 if (CDF_FTM_MODE == hdd_get_conparam()) {
2456 hdd_err("Command not allowed in FTM mode");
2457 return -EPERM;
2458 }
2459
2460 ret = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05302461 if (0 != ret)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002462 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002463
2464 if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX,
2465 data, data_len, wlan_hdd_extscan_config_policy)) {
2466 hddLog(LOGE, FL("Invalid ATTR"));
2467 return -EINVAL;
2468 }
2469
2470 /* Parse and fetch request Id */
2471 if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]) {
2472 hddLog(LOGE, FL("attr request id failed"));
2473 return -EINVAL;
2474 }
2475 requestId =
2476 nla_get_u32(tb
2477 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]);
2478 hddLog(LOG1, FL("Req Id %d"), requestId);
2479
2480 /* Parse and fetch wifi band */
2481 if (!tb
2482 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_GET_VALID_CHANNELS_CONFIG_PARAM_WIFI_BAND]) {
2483 hddLog(LOGE, FL("attr wifi band failed"));
2484 return -EINVAL;
2485 }
2486 wifiBand =
2487 nla_get_u32(tb
2488 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_GET_VALID_CHANNELS_CONFIG_PARAM_WIFI_BAND]);
2489 hddLog(LOG1, FL("Wifi band %d"), wifiBand);
2490
2491 if (!tb
2492 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_GET_VALID_CHANNELS_CONFIG_PARAM_MAX_CHANNELS]) {
2493 hddLog(LOGE, FL("attr max channels failed"));
2494 return -EINVAL;
2495 }
2496 maxChannels =
2497 nla_get_u32(tb
2498 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_GET_VALID_CHANNELS_CONFIG_PARAM_MAX_CHANNELS]);
2499 hddLog(LOG1, FL("Max channels %d"), maxChannels);
2500 status = sme_get_valid_channels_by_band((tHalHandle) (pHddCtx->hHal),
2501 wifiBand, chan_list,
2502 &num_channels);
2503 if (CDF_STATUS_SUCCESS != status) {
2504 hddLog(LOGE,
2505 FL("sme_get_valid_channels_by_band failed (err=%d)"),
2506 status);
2507 return -EINVAL;
2508 }
2509
2510 num_channels = CDF_MIN(num_channels, maxChannels);
2511
2512 hdd_remove_dsrc_channels(wiphy, chan_list, &num_channels);
2513
2514 if ((WLAN_HDD_SOFTAP == pAdapter->device_mode) ||
2515 !strncmp(hdd_get_fwpath(), "ap", 2))
2516 hdd_remove_indoor_channels(wiphy, chan_list, &num_channels);
2517
2518 hddLog(LOG1, FL("Number of channels %d"), num_channels);
2519 for (i = 0; i < num_channels; i++)
2520 hddLog(LOG1, "Channel: %u ", chan_list[i]);
2521
2522 reply_skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, sizeof(u32) +
2523 sizeof(u32) *
2524 num_channels +
2525 NLMSG_HDRLEN);
2526
2527 if (reply_skb) {
2528 if (nla_put_u32(reply_skb,
2529 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_NUM_CHANNELS,
2530 num_channels) ||
2531 nla_put(reply_skb,
2532 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CHANNELS,
2533 sizeof(u32) * num_channels, chan_list)) {
2534 hddLog(LOGE, FL("nla put fail"));
2535 kfree_skb(reply_skb);
2536 return -EINVAL;
2537 }
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05302538 ret = cfg80211_vendor_cmd_reply(reply_skb);
2539 EXIT();
2540 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002541 }
2542
2543 hddLog(LOGE, FL("valid channels: buffer alloc fail"));
2544 return -EINVAL;
2545}
2546
2547/**
2548 * wlan_hdd_cfg80211_extscan_get_valid_channels() - get ext scan valid channels
2549 * @wiphy: Pointer to wireless phy
2550 * @wdev: Pointer to wireless device
2551 * @data: Pointer to data
2552 * @data_len: Data length
2553 *
2554 * Return: 0 on success, negative errno on failure
2555 */
2556int wlan_hdd_cfg80211_extscan_get_valid_channels(struct wiphy *wiphy,
2557 struct wireless_dev *wdev,
2558 const void *data, int data_len)
2559{
2560 int ret = 0;
2561
2562 cds_ssr_protect(__func__);
2563 ret = __wlan_hdd_cfg80211_extscan_get_valid_channels(wiphy, wdev, data,
2564 data_len);
2565 cds_ssr_unprotect(__func__);
2566
2567 return ret;
2568}
2569
2570/**
2571 * hdd_extscan_update_dwell_time_limits() - update dwell times
2572 * @req_msg: Pointer to request message
2573 * @bkt_idx: Index of current bucket being processed
2574 * @active_min: minimum active dwell time
2575 * @active_max: maximum active dwell time
2576 * @passive_min: minimum passive dwell time
2577 * @passive_max: maximum passive dwell time
2578 *
2579 * Return: none
2580 */
2581static void hdd_extscan_update_dwell_time_limits(
2582 tpSirWifiScanCmdReqParams req_msg, uint32_t bkt_idx,
2583 uint32_t active_min, uint32_t active_max,
2584 uint32_t passive_min, uint32_t passive_max)
2585{
2586 /* update per-bucket dwell times */
2587 if (req_msg->buckets[bkt_idx].min_dwell_time_active >
2588 active_min) {
2589 req_msg->buckets[bkt_idx].min_dwell_time_active =
2590 active_min;
2591 }
2592 if (req_msg->buckets[bkt_idx].max_dwell_time_active <
2593 active_max) {
2594 req_msg->buckets[bkt_idx].max_dwell_time_active =
2595 active_max;
2596 }
2597 if (req_msg->buckets[bkt_idx].min_dwell_time_passive >
2598 passive_min) {
2599 req_msg->buckets[bkt_idx].min_dwell_time_passive =
2600 passive_min;
2601 }
2602 if (req_msg->buckets[bkt_idx].max_dwell_time_passive <
2603 passive_max) {
2604 req_msg->buckets[bkt_idx].max_dwell_time_passive =
2605 passive_max;
2606 }
2607 /* update dwell-time across all buckets */
2608 if (req_msg->min_dwell_time_active >
2609 req_msg->buckets[bkt_idx].min_dwell_time_active) {
2610 req_msg->min_dwell_time_active =
2611 req_msg->buckets[bkt_idx].min_dwell_time_active;
2612 }
2613 if (req_msg->max_dwell_time_active <
2614 req_msg->buckets[bkt_idx].max_dwell_time_active) {
2615 req_msg->max_dwell_time_active =
2616 req_msg->buckets[bkt_idx].max_dwell_time_active;
2617 }
2618 if (req_msg->min_dwell_time_passive >
2619 req_msg->buckets[bkt_idx].min_dwell_time_passive) {
2620 req_msg->min_dwell_time_passive =
2621 req_msg->buckets[bkt_idx].min_dwell_time_passive;
2622 }
2623 if (req_msg->max_dwell_time_passive >
2624 req_msg->buckets[bkt_idx].max_dwell_time_passive) {
2625 req_msg->max_dwell_time_passive =
2626 req_msg->buckets[bkt_idx].max_dwell_time_passive;
2627 }
2628}
2629
2630/**
2631 * hdd_extscan_channel_max_reached() - channel max reached
2632 * @req: extscan request structure
2633 * @total_channels: total number of channels
2634 *
2635 * Return: true if total channels reached max, false otherwise
2636 */
2637static bool hdd_extscan_channel_max_reached(tSirWifiScanCmdReqParams *req,
2638 uint8_t total_channels)
2639{
2640 if (total_channels == WLAN_EXTSCAN_MAX_CHANNELS) {
2641 hdd_warn(
2642 "max #of channels %d reached, take only first %d bucket(s)",
2643 total_channels, req->numBuckets);
2644 return true;
2645 }
2646 return false;
2647}
2648
2649/**
2650 * hdd_extscan_start_fill_bucket_channel_spec() - fill bucket channel spec
2651 * @hdd_ctx: HDD global context
2652 * @req_msg: Pointer to request structure
2653 * @tb: pointer to NL attributes
2654 *
2655 * Return: 0 on success; error number otherwise
2656 */
2657static int hdd_extscan_start_fill_bucket_channel_spec(
2658 hdd_context_t *hdd_ctx,
2659 tpSirWifiScanCmdReqParams req_msg,
2660 struct nlattr **tb)
2661{
2662 struct nlattr *bucket[
2663 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX + 1];
2664 struct nlattr *channel[
2665 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX + 1];
2666 struct nlattr *buckets;
2667 struct nlattr *channels;
2668 int rem1, rem2;
2669 CDF_STATUS status;
2670 uint8_t bkt_index, j, num_channels, total_channels = 0;
2671 uint32_t chan_list[WNI_CFG_VALID_CHANNEL_LIST_LEN] = {0};
2672
2673 uint32_t min_dwell_time_active_bucket =
2674 hdd_ctx->config->extscan_active_max_chn_time;
2675 uint32_t max_dwell_time_active_bucket =
2676 hdd_ctx->config->extscan_active_max_chn_time;
2677 uint32_t min_dwell_time_passive_bucket =
2678 hdd_ctx->config->extscan_passive_max_chn_time;
2679 uint32_t max_dwell_time_passive_bucket =
2680 hdd_ctx->config->extscan_passive_max_chn_time;
2681
2682 bkt_index = 0;
2683 req_msg->min_dwell_time_active =
2684 req_msg->max_dwell_time_active =
2685 hdd_ctx->config->extscan_active_max_chn_time;
2686
2687 req_msg->min_dwell_time_passive =
2688 req_msg->max_dwell_time_passive =
2689 hdd_ctx->config->extscan_passive_max_chn_time;
2690 req_msg->numBuckets = 0;
2691
2692 nla_for_each_nested(buckets,
2693 tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC], rem1) {
2694 if (nla_parse(bucket,
2695 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX,
2696 nla_data(buckets), nla_len(buckets), NULL)) {
2697 hddLog(LOGE, FL("nla_parse failed"));
2698 return -EINVAL;
2699 }
2700
2701 /* Parse and fetch bucket spec */
2702 if (!bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_INDEX]) {
2703 hddLog(LOGE, FL("attr bucket index failed"));
2704 return -EINVAL;
2705 }
2706 req_msg->buckets[bkt_index].bucket = nla_get_u8(
2707 bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_INDEX]);
2708 hddLog(LOG1, FL("Bucket spec Index %d"),
2709 req_msg->buckets[bkt_index].bucket);
2710
2711 /* Parse and fetch wifi band */
2712 if (!bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_BAND]) {
2713 hddLog(LOGE, FL("attr wifi band failed"));
2714 return -EINVAL;
2715 }
2716 req_msg->buckets[bkt_index].band = nla_get_u8(
2717 bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_BAND]);
2718 hddLog(LOG1, FL("Wifi band %d"),
2719 req_msg->buckets[bkt_index].band);
2720
2721 /* Parse and fetch period */
2722 if (!bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_PERIOD]) {
2723 hddLog(LOGE, FL("attr period failed"));
2724 return -EINVAL;
2725 }
2726 req_msg->buckets[bkt_index].period = nla_get_u32(
2727 bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_PERIOD]);
2728 hddLog(LOG1, FL("period %d"),
2729 req_msg->buckets[bkt_index].period);
2730
2731 /* Parse and fetch report events */
2732 if (!bucket[
2733 QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_REPORT_EVENTS]) {
2734 hddLog(LOGE, FL("attr report events failed"));
2735 return -EINVAL;
2736 }
2737 req_msg->buckets[bkt_index].reportEvents = nla_get_u8(
2738 bucket[
2739 QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_REPORT_EVENTS]);
2740 hddLog(LOG1, FL("report events %d"),
2741 req_msg->buckets[bkt_index].reportEvents);
2742
2743 /* Parse and fetch max period */
2744 if (!bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_MAX_PERIOD]) {
2745 hddLog(LOGE, FL("attr max period failed"));
2746 return -EINVAL;
2747 }
2748 req_msg->buckets[bkt_index].max_period = nla_get_u32(
2749 bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_MAX_PERIOD]);
2750 hddLog(LOG1, FL("max period %u"),
2751 req_msg->buckets[bkt_index].max_period);
2752
2753 /* Parse and fetch exponent */
2754 if (!bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_EXPONENT]) {
2755 hddLog(LOGE, FL("attr exponent failed"));
2756 return -EINVAL;
2757 }
2758 req_msg->buckets[bkt_index].exponent = nla_get_u32(
2759 bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_EXPONENT]);
2760 hddLog(LOG1, FL("exponent %u"),
2761 req_msg->buckets[bkt_index].exponent);
2762
2763 /* Parse and fetch step count */
2764 if (!bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_STEP_COUNT]) {
2765 hddLog(LOGE, FL("attr step count failed"));
2766 return -EINVAL;
2767 }
2768 req_msg->buckets[bkt_index].step_count = nla_get_u32(
2769 bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_STEP_COUNT]);
2770 hddLog(LOG1, FL("Step count %u"),
2771 req_msg->buckets[bkt_index].step_count);
2772
2773 /* start with known good values for bucket dwell times */
2774 req_msg->buckets[bkt_index].min_dwell_time_active =
2775 req_msg->buckets[bkt_index].max_dwell_time_active =
2776 hdd_ctx->config->extscan_active_max_chn_time;
2777
2778 req_msg->buckets[bkt_index].min_dwell_time_passive =
2779 req_msg->buckets[bkt_index].max_dwell_time_passive =
2780 hdd_ctx->config->extscan_passive_max_chn_time;
2781
2782 /* Framework shall pass the channel list if the input WiFi band
2783 * is WIFI_BAND_UNSPECIFIED.
2784 * If the input WiFi band is specified (any value other than
2785 * WIFI_BAND_UNSPECIFIED) then driver populates the channel list
2786 */
2787 if (req_msg->buckets[bkt_index].band != WIFI_BAND_UNSPECIFIED) {
2788 if (hdd_extscan_channel_max_reached(req_msg,
2789 total_channels))
2790 return 0;
2791
2792 num_channels = 0;
2793 hddLog(LOG1, "WiFi band is specified, driver to fill channel list");
2794 status = sme_get_valid_channels_by_band(hdd_ctx->hHal,
2795 req_msg->buckets[bkt_index].band,
2796 chan_list, &num_channels);
2797 if (!CDF_IS_STATUS_SUCCESS(status)) {
2798 hddLog(LOGE,
2799 FL("sme_GetValidChannelsByBand failed (err=%d)"),
2800 status);
2801 return -EINVAL;
2802 }
2803 hddLog(LOG1, FL("before trimming, num_channels: %d"),
2804 num_channels);
2805
2806 req_msg->buckets[bkt_index].numChannels =
2807 CDF_MIN(num_channels,
2808 (WLAN_EXTSCAN_MAX_CHANNELS -
2809 total_channels));
2810 hdd_info("Adj Num channels/bucket: %d total_channels: %d",
2811 req_msg->buckets[bkt_index].numChannels,
2812 total_channels);
2813 total_channels +=
2814 req_msg->buckets[bkt_index].numChannels;
2815
2816 for (j = 0; j < req_msg->buckets[bkt_index].numChannels;
2817 j++) {
2818 req_msg->buckets[bkt_index].channels[j].channel =
2819 chan_list[j];
2820 req_msg->buckets[bkt_index].channels[j].
2821 chnlClass = 0;
2822 if (CDS_IS_PASSIVE_OR_DISABLE_CH(
2823 cds_freq_to_chan(chan_list[j]))) {
2824 req_msg->buckets[bkt_index].channels[j].
2825 passive = 1;
2826 req_msg->buckets[bkt_index].channels[j].
2827 dwellTimeMs =
2828 hdd_ctx->config->
2829 extscan_passive_max_chn_time;
2830 /* reconfigure per-bucket dwell time */
2831 if (min_dwell_time_passive_bucket >
2832 req_msg->buckets[bkt_index].channels[j].dwellTimeMs) {
2833 min_dwell_time_passive_bucket =
2834 req_msg->buckets[bkt_index].channels[j].dwellTimeMs;
2835 }
2836 if (max_dwell_time_passive_bucket <
2837 req_msg->buckets[bkt_index].channels[j].dwellTimeMs) {
2838 max_dwell_time_passive_bucket =
2839 req_msg->buckets[bkt_index].channels[j].dwellTimeMs;
2840 }
2841
2842 } else {
2843 req_msg->buckets[bkt_index].channels[j].
2844 passive = 0;
2845 req_msg->buckets[bkt_index].channels[j].
2846 dwellTimeMs =
2847 hdd_ctx->config->extscan_active_max_chn_time;
2848 /* reconfigure per-bucket dwell times */
2849 if (min_dwell_time_active_bucket >
2850 req_msg->buckets[bkt_index].channels[j].dwellTimeMs) {
2851 min_dwell_time_active_bucket =
2852 req_msg->buckets[bkt_index].channels[j].dwellTimeMs;
2853 }
2854 if (max_dwell_time_active_bucket <
2855 req_msg->buckets[bkt_index].channels[j].dwellTimeMs) {
2856 max_dwell_time_active_bucket =
2857 req_msg->buckets[bkt_index].channels[j].dwellTimeMs;
2858 }
2859
2860 }
2861
2862 hddLog(LOG1,
2863 "Channel: %u Passive: %u Dwell time: %u ms Class: %u",
2864 req_msg->buckets[bkt_index].channels[j].channel,
2865 req_msg->buckets[bkt_index].channels[j].passive,
2866 req_msg->buckets[bkt_index].channels[j].dwellTimeMs,
2867 req_msg->buckets[bkt_index].channels[j].chnlClass);
2868 }
2869
2870 hdd_extscan_update_dwell_time_limits(
2871 req_msg, bkt_index,
2872 min_dwell_time_active_bucket,
2873 max_dwell_time_active_bucket,
2874 min_dwell_time_passive_bucket,
2875 max_dwell_time_passive_bucket);
2876
2877 hddLog(LOG1, FL("bkt_index:%d actv_min:%d actv_max:%d pass_min:%d pass_max:%d"),
2878 bkt_index,
2879 req_msg->buckets[bkt_index].min_dwell_time_active,
2880 req_msg->buckets[bkt_index].max_dwell_time_active,
2881 req_msg->buckets[bkt_index].min_dwell_time_passive,
2882 req_msg->buckets[bkt_index].max_dwell_time_passive);
2883
2884 bkt_index++;
2885 req_msg->numBuckets++;
2886 continue;
2887 }
2888
2889 /* Parse and fetch number of channels */
2890 if (!bucket[
2891 QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_NUM_CHANNEL_SPECS]) {
2892 hddLog(LOGE, FL("attr num channels failed"));
2893 return -EINVAL;
2894 }
2895 req_msg->buckets[bkt_index].numChannels =
2896 nla_get_u32(bucket[
2897 QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_NUM_CHANNEL_SPECS]);
2898 hdd_info("before trimming: num channels %d",
2899 req_msg->buckets[bkt_index].numChannels);
2900
2901 req_msg->buckets[bkt_index].numChannels =
2902 CDF_MIN(req_msg->buckets[bkt_index].numChannels,
2903 (WLAN_EXTSCAN_MAX_CHANNELS - total_channels));
2904 hdd_info("Num channels/bucket: %d total_channels: %d",
2905 req_msg->buckets[bkt_index].numChannels,
2906 total_channels);
2907 if (hdd_extscan_channel_max_reached(req_msg, total_channels))
2908 return 0;
2909
2910 if (!bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC]) {
2911 hddLog(LOGE, FL("attr channel spec failed"));
2912 return -EINVAL;
2913 }
2914
2915 j = 0;
2916 nla_for_each_nested(channels,
2917 bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC], rem2) {
Jeff Johnson56951332015-10-29 11:26:02 -07002918 if ((j >= req_msg->buckets[bkt_index].numChannels) ||
2919 hdd_extscan_channel_max_reached(req_msg,
2920 total_channels))
2921 break;
2922
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002923 if (nla_parse(channel,
2924 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX,
2925 nla_data(channels), nla_len(channels),
2926 wlan_hdd_extscan_config_policy)) {
2927 hddLog(LOGE, FL("nla_parse failed"));
2928 return -EINVAL;
2929 }
2930
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002931 /* Parse and fetch channel */
2932 if (!channel[
2933 QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_CHANNEL]) {
2934 hddLog(LOGE, FL("attr channel failed"));
2935 return -EINVAL;
2936 }
2937 req_msg->buckets[bkt_index].channels[j].channel =
2938 nla_get_u32(channel[
2939 QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_CHANNEL]);
2940 hddLog(LOG1, FL("channel %u"),
2941 req_msg->buckets[bkt_index].channels[j].channel);
2942
2943 /* Parse and fetch dwell time */
2944 if (!channel[
2945 QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_DWELL_TIME]) {
2946 hddLog(LOGE, FL("attr dwelltime failed"));
2947 return -EINVAL;
2948 }
2949 req_msg->buckets[bkt_index].channels[j].dwellTimeMs =
2950 nla_get_u32(channel[
2951 QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_DWELL_TIME]);
2952
2953 /* Override dwell time if required */
2954 if (req_msg->buckets[bkt_index].channels[j].dwellTimeMs <
2955 hdd_ctx->config->extscan_active_min_chn_time ||
2956 req_msg->buckets[bkt_index].channels[j].dwellTimeMs >
2957 hdd_ctx->config->extscan_active_max_chn_time) {
2958 hddLog(LOG1, FL("WiFi band is unspecified, dwellTime:%d"),
2959 req_msg->buckets[bkt_index].channels[j].dwellTimeMs);
2960
2961 if (CDS_IS_PASSIVE_OR_DISABLE_CH(
2962 cds_freq_to_chan(
2963 req_msg->buckets[bkt_index].channels[j].channel))) {
2964 req_msg->buckets[bkt_index].channels[j].dwellTimeMs =
2965 hdd_ctx->config->extscan_passive_max_chn_time;
2966 } else {
2967 req_msg->buckets[bkt_index].channels[j].dwellTimeMs =
2968 hdd_ctx->config->extscan_active_max_chn_time;
2969 }
2970 }
2971
2972 hddLog(LOG1, FL("New Dwell time %u ms"),
2973 req_msg->buckets[bkt_index].channels[j].dwellTimeMs);
2974
2975 if (CDS_IS_PASSIVE_OR_DISABLE_CH(
2976 cds_freq_to_chan(
2977 req_msg->buckets[bkt_index].channels[j].channel))) {
2978 if (min_dwell_time_passive_bucket >
2979 req_msg->buckets[bkt_index].channels[j].dwellTimeMs) {
2980 min_dwell_time_passive_bucket =
2981 req_msg->buckets[bkt_index].channels[j].dwellTimeMs;
2982 }
2983 if (max_dwell_time_passive_bucket <
2984 req_msg->buckets[bkt_index].channels[j].dwellTimeMs) {
2985 max_dwell_time_passive_bucket =
2986 req_msg->buckets[bkt_index].channels[j].dwellTimeMs;
2987 }
2988 } else {
2989 if (min_dwell_time_active_bucket >
2990 req_msg->buckets[bkt_index].channels[j].dwellTimeMs) {
2991 min_dwell_time_active_bucket =
2992 req_msg->buckets[bkt_index].channels[j].dwellTimeMs;
2993 }
2994 if (max_dwell_time_active_bucket <
2995 req_msg->buckets[bkt_index].channels[j].dwellTimeMs) {
2996 max_dwell_time_active_bucket =
2997 req_msg->buckets[bkt_index].channels[j].dwellTimeMs;
2998 }
2999 }
3000
3001 /* Parse and fetch channel spec passive */
3002 if (!channel[
3003 QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_PASSIVE]) {
3004 hddLog(LOGE,
3005 FL("attr channel spec passive failed"));
3006 return -EINVAL;
3007 }
3008 req_msg->buckets[bkt_index].channels[j].passive =
3009 nla_get_u8(channel[
3010 QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_PASSIVE]);
3011 hddLog(LOG1, FL("Chnl spec passive %u"),
3012 req_msg->buckets[bkt_index].channels[j].passive);
3013 /* Override scan type if required */
3014 if (CDS_IS_PASSIVE_OR_DISABLE_CH(
3015 cds_freq_to_chan(
3016 req_msg->buckets[bkt_index].channels[j].channel))) {
3017 req_msg->buckets[bkt_index].channels[j].passive = true;
3018 } else {
3019 req_msg->buckets[bkt_index].channels[j].passive = false;
3020 }
3021 j++;
3022 total_channels++;
3023 }
3024
3025 hdd_extscan_update_dwell_time_limits(
3026 req_msg, bkt_index,
3027 min_dwell_time_active_bucket,
3028 max_dwell_time_active_bucket,
3029 min_dwell_time_passive_bucket,
3030 max_dwell_time_passive_bucket);
3031
3032 hddLog(LOG1, FL("bktIndex:%d actv_min:%d actv_max:%d pass_min:%d pass_max:%d"),
3033 bkt_index,
3034 req_msg->buckets[bkt_index].min_dwell_time_active,
3035 req_msg->buckets[bkt_index].max_dwell_time_active,
3036 req_msg->buckets[bkt_index].min_dwell_time_passive,
3037 req_msg->buckets[bkt_index].max_dwell_time_passive);
3038
3039 bkt_index++;
3040 req_msg->numBuckets++;
3041 }
3042
3043 hddLog(LOG1, FL("Global: actv_min:%d actv_max:%d pass_min:%d pass_max:%d"),
3044 req_msg->min_dwell_time_active,
3045 req_msg->max_dwell_time_active,
3046 req_msg->min_dwell_time_passive,
3047 req_msg->max_dwell_time_passive);
3048
3049 return 0;
3050}
3051
3052/*
3053 * hdd_extscan_map_usr_drv_config_flags() - map userspace to driver config flags
3054 * @config_flags - [input] configuration flags.
3055 *
3056 * This function maps user space received configuration flags to
3057 * driver representation.
3058 *
3059 * Return: configuration flags
3060 */
3061static uint32_t hdd_extscan_map_usr_drv_config_flags(uint32_t config_flags)
3062{
3063 uint32_t configuration_flags = 0;
3064
3065 if (config_flags & EXTSCAN_LP_EXTENDED_BATCHING)
3066 configuration_flags |= EXTSCAN_LP_EXTENDED_BATCHING;
3067
3068 return configuration_flags;
3069}
3070
3071/*
3072 * define short names for the global vendor params
3073 * used by __wlan_hdd_cfg80211_extscan_start()
3074 */
3075#define PARAM_MAX \
3076 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX
3077#define PARAM_REQUEST_ID \
3078 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID
3079#define PARAM_BASE_PERIOD \
3080 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_BASE_PERIOD
3081#define PARAM_MAX_AP_PER_SCAN \
3082 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_MAX_AP_PER_SCAN
3083#define PARAM_RPT_THRHLD_PERCENT \
3084 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_REPORT_THRESHOLD_PERCENT
3085#define PARAM_RPT_THRHLD_NUM_SCANS \
3086 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_REPORT_THRESHOLD_NUM_SCANS
3087#define PARAM_NUM_BUCKETS \
3088 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_NUM_BUCKETS
3089#define PARAM_CONFIG_FLAGS \
3090 QCA_WLAN_VENDOR_ATTR_EXTSCAN_CONFIGURATION_FLAGS
3091
3092/**
3093 * __wlan_hdd_cfg80211_extscan_start() - ext scan start
3094 * @wiphy: Pointer to wireless phy
3095 * @wdev: Pointer to wireless device
3096 * @data: Pointer to data
3097 * @data_len: Length of @data
3098 *
3099 * Return: 0 on success; error number otherwise
3100 */
3101static int
3102__wlan_hdd_cfg80211_extscan_start(struct wiphy *wiphy,
3103 struct wireless_dev *wdev,
3104 const void *data,
3105 int data_len)
3106{
3107 tpSirWifiScanCmdReqParams pReqMsg = NULL;
3108 struct net_device *dev = wdev->netdev;
3109 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
3110 hdd_context_t *pHddCtx = wiphy_priv(wiphy);
3111 struct nlattr *tb[PARAM_MAX + 1];
3112 struct hdd_ext_scan_context *context;
3113 uint32_t request_id, num_buckets;
3114 CDF_STATUS status;
3115 int retval;
3116 unsigned long rc;
3117
3118 ENTER();
3119
3120 if (CDF_FTM_MODE == hdd_get_conparam()) {
3121 hdd_err("Command not allowed in FTM mode");
3122 return -EPERM;
3123 }
3124
3125 retval = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05303126 if (0 != retval)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003127 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003128
3129 if (nla_parse(tb, PARAM_MAX, data, data_len,
3130 wlan_hdd_extscan_config_policy)) {
3131 hddLog(LOGE, FL("Invalid ATTR"));
3132 return -EINVAL;
3133 }
3134
3135 pReqMsg = cdf_mem_malloc(sizeof(*pReqMsg));
3136 if (!pReqMsg) {
3137 hddLog(LOGE, FL("memory allocation failed"));
3138 return -ENOMEM;
3139 }
3140
3141 /* Parse and fetch request Id */
3142 if (!tb[PARAM_REQUEST_ID]) {
3143 hddLog(LOGE, FL("attr request id failed"));
3144 goto fail;
3145 }
3146
3147 pReqMsg->requestId = nla_get_u32(tb[PARAM_REQUEST_ID]);
3148 pReqMsg->sessionId = pAdapter->sessionId;
3149 hddLog(LOG1, FL("Req Id %d Session Id %d"),
3150 pReqMsg->requestId,
3151 pReqMsg->sessionId);
3152
3153 /* Parse and fetch base period */
3154 if (!tb[PARAM_BASE_PERIOD]) {
3155 hddLog(LOGE, FL("attr base period failed"));
3156 goto fail;
3157 }
3158 pReqMsg->basePeriod = nla_get_u32(tb[PARAM_BASE_PERIOD]);
3159 hddLog(LOG1, FL("Base Period %d"),
3160 pReqMsg->basePeriod);
3161
3162 /* Parse and fetch max AP per scan */
3163 if (!tb[PARAM_MAX_AP_PER_SCAN]) {
3164 hddLog(LOGE, FL("attr max_ap_per_scan failed"));
3165 goto fail;
3166 }
3167 pReqMsg->maxAPperScan = nla_get_u32(tb[PARAM_MAX_AP_PER_SCAN]);
3168 hddLog(LOG1, FL("Max AP per Scan %d"), pReqMsg->maxAPperScan);
3169
3170 /* Parse and fetch report threshold percent */
3171 if (!tb[PARAM_RPT_THRHLD_PERCENT]) {
3172 hddLog(LOGE, FL("attr report_threshold percent failed"));
3173 goto fail;
3174 }
3175 pReqMsg->report_threshold_percent = nla_get_u8(tb[PARAM_RPT_THRHLD_PERCENT]);
3176 hddLog(LOG1, FL("Report Threshold percent %d"),
3177 pReqMsg->report_threshold_percent);
3178
3179 /* Parse and fetch report threshold num scans */
3180 if (!tb[PARAM_RPT_THRHLD_NUM_SCANS]) {
3181 hddLog(LOGE, FL("attr report_threshold num scans failed"));
3182 goto fail;
3183 }
3184 pReqMsg->report_threshold_num_scans = nla_get_u8(tb[PARAM_RPT_THRHLD_NUM_SCANS]);
3185 hddLog(LOG1, FL("Report Threshold num scans %d"),
3186 pReqMsg->report_threshold_num_scans);
3187
3188 /* Parse and fetch number of buckets */
3189 if (!tb[PARAM_NUM_BUCKETS]) {
3190 hddLog(LOGE, FL("attr number of buckets failed"));
3191 goto fail;
3192 }
3193 num_buckets = nla_get_u8(tb[PARAM_NUM_BUCKETS]);
3194 if (num_buckets > WLAN_EXTSCAN_MAX_BUCKETS) {
3195 hdd_warn("Exceeded MAX number of buckets: %d",
3196 WLAN_EXTSCAN_MAX_BUCKETS);
3197 }
3198 hdd_info("Input: Number of Buckets %d", num_buckets);
3199
3200 /* This is optional attribute, if not present set it to 0 */
3201 if (!tb[PARAM_CONFIG_FLAGS])
3202 pReqMsg->configuration_flags = 0;
3203 else
3204 pReqMsg->configuration_flags =
3205 hdd_extscan_map_usr_drv_config_flags(
3206 nla_get_u32(tb[PARAM_CONFIG_FLAGS]));
3207
3208 hddLog(LOG1, FL("Configuration flags: %u"),
3209 pReqMsg->configuration_flags);
3210
3211 if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC]) {
3212 hddLog(LOGE, FL("attr bucket spec failed"));
3213 goto fail;
3214 }
3215
3216 if (hdd_extscan_start_fill_bucket_channel_spec(pHddCtx, pReqMsg, tb))
3217 goto fail;
3218
3219 context = &ext_scan_context;
3220 spin_lock(&context->context_lock);
3221 INIT_COMPLETION(context->response_event);
3222 context->request_id = request_id = pReqMsg->requestId;
3223 spin_unlock(&context->context_lock);
3224
3225 status = sme_ext_scan_start(pHddCtx->hHal, pReqMsg);
3226 if (!CDF_IS_STATUS_SUCCESS(status)) {
3227 hddLog(LOGE,
3228 FL("sme_ext_scan_start failed(err=%d)"), status);
3229 goto fail;
3230 }
3231
3232 pHddCtx->ext_scan_start_since_boot = cdf_get_monotonic_boottime();
3233 hddLog(LOG1, FL("Timestamp since boot: %llu"),
3234 pHddCtx->ext_scan_start_since_boot);
3235
3236 /* request was sent -- wait for the response */
3237 rc = wait_for_completion_timeout(&context->response_event,
3238 msecs_to_jiffies(WLAN_WAIT_TIME_EXTSCAN));
3239
3240 if (!rc) {
3241 hddLog(LOGE, FL("sme_ext_scan_start timed out"));
3242 retval = -ETIMEDOUT;
3243 } else {
3244 spin_lock(&context->context_lock);
3245 if (context->request_id == request_id)
3246 retval = context->response_status;
3247 else
3248 retval = -EINVAL;
3249 spin_unlock(&context->context_lock);
3250 }
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05303251 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003252 return retval;
3253
3254fail:
3255 cdf_mem_free(pReqMsg);
3256 return -EINVAL;
3257}
3258/*
3259 * done with short names for the global vendor params
3260 * used by __wlan_hdd_cfg80211_extscan_start()
3261 */
3262#undef PARAM_MAX
3263#undef PARAM_REQUEST_ID
3264#undef PARAM_BASE_PERIOD
3265#undef PARAMS_MAX_AP_PER_SCAN
3266#undef PARAMS_RPT_THRHLD_PERCENT
3267#undef PARAMS_RPT_THRHLD_NUM_SCANS
3268#undef PARAMS_NUM_BUCKETS
3269#undef PARAM_CONFIG_FLAGS
3270
3271/**
3272 * wlan_hdd_cfg80211_extscan_start() - start extscan
3273 * @wiphy: Pointer to wireless phy.
3274 * @wdev: Pointer to wireless device.
3275 * @data: Pointer to input data.
3276 * @data_len: Length of @data.
3277 *
3278 * Return: 0 on success, negative errno on failure
3279 */
3280int wlan_hdd_cfg80211_extscan_start(struct wiphy *wiphy,
3281 struct wireless_dev *wdev,
3282 const void *data, int data_len)
3283{
3284 int ret = 0;
3285
3286 cds_ssr_protect(__func__);
3287 ret = __wlan_hdd_cfg80211_extscan_start(wiphy, wdev, data, data_len);
3288 cds_ssr_unprotect(__func__);
3289
3290 return ret;
3291}
3292
3293
3294/*
3295 * define short names for the global vendor params
3296 * used by __wlan_hdd_cfg80211_extscan_stop()
3297 */
3298#define PARAM_MAX \
3299 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX
3300#define PARAM_REQUEST_ID \
3301 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID
3302
3303/**
3304 * __wlan_hdd_cfg80211_extscan_stop() - ext scan stop
3305 * @wiphy: Pointer to wireless phy
3306 * @wdev: Pointer to wireless device
3307 * @data: Pointer to data
3308 * @data_len: Data length
3309 *
3310 * Return: none
3311 */
3312static int
3313__wlan_hdd_cfg80211_extscan_stop(struct wiphy *wiphy,
3314 struct wireless_dev *wdev,
3315 const void *data, int data_len)
3316{
3317 tpSirExtScanStopReqParams pReqMsg = NULL;
3318 struct net_device *dev = wdev->netdev;
3319 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
3320 hdd_context_t *pHddCtx = wiphy_priv(wiphy);
3321 struct nlattr *tb[PARAM_MAX + 1];
3322 struct hdd_ext_scan_context *context;
3323 CDF_STATUS status;
3324 uint32_t request_id;
3325 int retval;
3326 unsigned long rc;
3327
3328 ENTER();
3329
3330 if (CDF_FTM_MODE == hdd_get_conparam()) {
3331 hdd_err("Command not allowed in FTM mode");
3332 return -EPERM;
3333 }
3334
3335 retval = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05303336 if (0 != retval)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003337 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003338
3339 if (nla_parse(tb, PARAM_MAX, data, data_len,
3340 wlan_hdd_extscan_config_policy)) {
3341 hddLog(LOGE, FL("Invalid ATTR"));
3342 return -EINVAL;
3343 }
3344
3345 pReqMsg = cdf_mem_malloc(sizeof(*pReqMsg));
3346 if (!pReqMsg) {
3347 hddLog(LOGE, FL("cdf_mem_malloc failed"));
3348 return -ENOMEM;
3349 }
3350
3351 /* Parse and fetch request Id */
3352 if (!tb[PARAM_REQUEST_ID]) {
3353 hddLog(LOGE, FL("attr request id failed"));
3354 goto fail;
3355 }
3356
3357 pReqMsg->requestId = nla_get_u32(tb[PARAM_REQUEST_ID]);
3358 pReqMsg->sessionId = pAdapter->sessionId;
3359 hddLog(LOG1, FL("Req Id %d Session Id %d"),
3360 pReqMsg->requestId, pReqMsg->sessionId);
3361
3362 context = &ext_scan_context;
3363 spin_lock(&context->context_lock);
3364 INIT_COMPLETION(context->response_event);
3365 context->request_id = request_id = pReqMsg->requestId;
3366 spin_unlock(&context->context_lock);
3367
3368 status = sme_ext_scan_stop(pHddCtx->hHal, pReqMsg);
3369 if (!CDF_IS_STATUS_SUCCESS(status)) {
3370 hddLog(LOGE,
3371 FL("sme_ext_scan_stop failed(err=%d)"), status);
3372 goto fail;
3373 }
3374
3375 /* request was sent -- wait for the response */
3376 rc = wait_for_completion_timeout(&context->response_event,
3377 msecs_to_jiffies(WLAN_WAIT_TIME_EXTSCAN));
3378
3379 if (!rc) {
3380 hddLog(LOGE, FL("sme_ext_scan_stop timed out"));
3381 retval = -ETIMEDOUT;
3382 } else {
3383 spin_lock(&context->context_lock);
3384 if (context->request_id == request_id)
3385 retval = context->response_status;
3386 else
3387 retval = -EINVAL;
3388 spin_unlock(&context->context_lock);
3389 }
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05303390 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003391 return retval;
3392
3393fail:
3394 cdf_mem_free(pReqMsg);
3395 return -EINVAL;
3396}
3397/*
3398 * done with short names for the global vendor params
3399 * used by wlan_hdd_cfg80211_extscan_stop()
3400 */
3401#undef PARAM_MAX
3402#undef PARAM_REQUEST_ID
3403
3404
3405/**
3406 * wlan_hdd_cfg80211_extscan_stop() - stop extscan
3407 * @wiphy: Pointer to wireless phy.
3408 * @wdev: Pointer to wireless device.
3409 * @data: Pointer to input data.
3410 * @data_len: Length of @data.
3411 *
3412 * Return: 0 on success, negative errno on failure
3413 */
3414int wlan_hdd_cfg80211_extscan_stop(struct wiphy *wiphy,
3415 struct wireless_dev *wdev,
3416 const void *data, int data_len)
3417{
3418 int ret = 0;
3419
3420 cds_ssr_protect(__func__);
3421 ret = __wlan_hdd_cfg80211_extscan_stop(wiphy, wdev, data, data_len);
3422 cds_ssr_unprotect(__func__);
3423
3424 return ret;
3425}
3426
3427
3428/**
3429 * __wlan_hdd_cfg80211_extscan_reset_bssid_hotlist() - reset bssid hotlist
3430 * @wiphy: Pointer to wireless phy
3431 * @wdev: Pointer to wireless device
3432 * @data: Pointer to data
3433 * @data_len: Data length
3434 *
3435 * Return: none
3436 */
3437static int
3438__wlan_hdd_cfg80211_extscan_reset_bssid_hotlist(struct wiphy *wiphy,
3439 struct wireless_dev
3440 *wdev, const void *data,
3441 int data_len)
3442{
3443 tpSirExtScanResetBssidHotlistReqParams pReqMsg = NULL;
3444 struct net_device *dev = wdev->netdev;
3445 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
3446 hdd_context_t *pHddCtx = wiphy_priv(wiphy);
3447 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX +
3448 1];
3449 struct hdd_ext_scan_context *context;
3450 uint32_t request_id;
3451 CDF_STATUS status;
3452 int retval;
3453 unsigned long rc;
3454
3455 ENTER();
3456
3457 if (CDF_FTM_MODE == hdd_get_conparam()) {
3458 hdd_err("Command not allowed in FTM mode");
3459 return -EPERM;
3460 }
3461
3462 retval = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05303463 if (0 != retval)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003464 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003465
3466 if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX,
3467 data, data_len, wlan_hdd_extscan_config_policy)) {
3468 hddLog(LOGE, FL("Invalid ATTR"));
3469 return -EINVAL;
3470 }
3471
3472 pReqMsg = cdf_mem_malloc(sizeof(*pReqMsg));
3473 if (!pReqMsg) {
3474 hddLog(LOGE, FL("cdf_mem_malloc failed"));
3475 return -ENOMEM;
3476 }
3477
3478 /* Parse and fetch request Id */
3479 if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]) {
3480 hddLog(LOGE, FL("attr request id failed"));
3481 goto fail;
3482 }
3483
3484 pReqMsg->requestId =
3485 nla_get_u32(tb
3486 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]);
3487 pReqMsg->sessionId = pAdapter->sessionId;
3488 hddLog(LOG1, FL("Req Id %d Session Id %d"),
3489 pReqMsg->requestId, pReqMsg->sessionId);
3490
3491 context = &ext_scan_context;
3492 spin_lock(&context->context_lock);
3493 INIT_COMPLETION(context->response_event);
3494 context->request_id = request_id = pReqMsg->requestId;
3495 spin_unlock(&context->context_lock);
3496
3497 status = sme_reset_bss_hotlist(pHddCtx->hHal, pReqMsg);
3498 if (!CDF_IS_STATUS_SUCCESS(status)) {
3499 hddLog(LOGE,
3500 FL("sme_reset_bss_hotlist failed(err=%d)"), status);
3501 goto fail;
3502 }
3503
3504 /* request was sent -- wait for the response */
3505 rc = wait_for_completion_timeout
3506 (&context->response_event,
3507 msecs_to_jiffies(WLAN_WAIT_TIME_EXTSCAN));
3508 if (!rc) {
3509 hddLog(LOGE, FL("sme_reset_bss_hotlist timed out"));
3510 retval = -ETIMEDOUT;
3511 } else {
3512 spin_lock(&context->context_lock);
3513 if (context->request_id == request_id)
3514 retval = context->response_status;
3515 else
3516 retval = -EINVAL;
3517 spin_unlock(&context->context_lock);
3518 }
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05303519 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003520 return retval;
3521
3522fail:
3523 cdf_mem_free(pReqMsg);
3524 return -EINVAL;
3525}
3526
3527/**
3528 * wlan_hdd_cfg80211_extscan_reset_bssid_hotlist() - reset bssid hot list
3529 * @wiphy: Pointer to wireless phy
3530 * @wdev: Pointer to wireless device
3531 * @data: Pointer to data
3532 * @data_len: Data length
3533 *
3534 * Return: 0 on success, negative errno on failure
3535 */
3536int wlan_hdd_cfg80211_extscan_reset_bssid_hotlist(struct wiphy *wiphy,
3537 struct wireless_dev *wdev,
3538 const void *data, int data_len)
3539{
3540 int ret = 0;
3541
3542 cds_ssr_protect(__func__);
3543 ret = __wlan_hdd_cfg80211_extscan_reset_bssid_hotlist(wiphy, wdev,
3544 data, data_len);
3545 cds_ssr_unprotect(__func__);
3546
3547 return ret;
3548}
3549
3550/**
3551 * __wlan_hdd_cfg80211_extscan_reset_significant_change() -
3552 * reset significant change
3553 * @wiphy: Pointer to wireless phy
3554 * @wdev: Pointer to wireless device
3555 * @data: Pointer to data
3556 * @data_len: Data length
3557 *
3558 * Return: none
3559 */
3560static int
3561__wlan_hdd_cfg80211_extscan_reset_significant_change(struct wiphy
3562 *wiphy,
3563 struct
3564 wireless_dev
3565 *wdev, const void *data,
3566 int data_len)
3567{
3568 tpSirExtScanResetSignificantChangeReqParams pReqMsg = NULL;
3569 struct net_device *dev = wdev->netdev;
3570 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
3571 hdd_context_t *pHddCtx = wiphy_priv(wiphy);
3572 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX +
3573 1];
3574 struct hdd_ext_scan_context *context;
3575 uint32_t request_id;
3576 CDF_STATUS status;
3577 int retval;
3578 unsigned long rc;
3579
3580 ENTER();
3581
3582 if (CDF_FTM_MODE == hdd_get_conparam()) {
3583 hdd_err("Command not allowed in FTM mode");
3584 return -EPERM;
3585 }
3586
3587 retval = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05303588 if (0 != retval)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003589 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003590
3591 if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX,
3592 data, data_len, wlan_hdd_extscan_config_policy)) {
3593 hddLog(LOGE, FL("Invalid ATTR"));
3594 return -EINVAL;
3595 }
3596
3597 pReqMsg = cdf_mem_malloc(sizeof(*pReqMsg));
3598 if (!pReqMsg) {
3599 hddLog(LOGE, FL("cdf_mem_malloc failed"));
3600 return -ENOMEM;
3601 }
3602
3603 /* Parse and fetch request Id */
3604 if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]) {
3605 hddLog(LOGE, FL("attr request id failed"));
3606 goto fail;
3607 }
3608
3609 pReqMsg->requestId =
3610 nla_get_u32(tb
3611 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]);
3612 pReqMsg->sessionId = pAdapter->sessionId;
3613 hddLog(LOG1, FL("Req Id %d Session Id %d"),
3614 pReqMsg->requestId, pReqMsg->sessionId);
3615
3616 context = &ext_scan_context;
3617 spin_lock(&context->context_lock);
3618 INIT_COMPLETION(context->response_event);
3619 context->request_id = request_id = pReqMsg->requestId;
3620 spin_unlock(&context->context_lock);
3621
3622 status = sme_reset_significant_change(pHddCtx->hHal, pReqMsg);
3623 if (!CDF_IS_STATUS_SUCCESS(status)) {
3624 hddLog(LOGE, FL("sme_reset_significant_change failed(err=%d)"),
3625 status);
3626 cdf_mem_free(pReqMsg);
3627 return -EINVAL;
3628 }
3629
3630 /* request was sent -- wait for the response */
3631 rc = wait_for_completion_timeout(&context->response_event,
3632 msecs_to_jiffies(WLAN_WAIT_TIME_EXTSCAN));
3633
3634 if (!rc) {
3635 hddLog(LOGE, FL("sme_ResetSignificantChange timed out"));
3636 retval = -ETIMEDOUT;
3637 } else {
3638 spin_lock(&context->context_lock);
3639 if (context->request_id == request_id)
3640 retval = context->response_status;
3641 else
3642 retval = -EINVAL;
3643 spin_unlock(&context->context_lock);
3644 }
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05303645 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003646 return retval;
3647
3648fail:
3649 cdf_mem_free(pReqMsg);
3650 return -EINVAL;
3651}
3652
3653/**
3654 * wlan_hdd_cfg80211_extscan_reset_significant_change() - reset significant
3655 * change
3656 * @wiphy: Pointer to wireless phy
3657 * @wdev: Pointer to wireless device
3658 * @data: Pointer to data
3659 * @data_len: Data length
3660 *
3661 * Return: 0 on success, negative errno on failure
3662 */
3663int wlan_hdd_cfg80211_extscan_reset_significant_change(struct wiphy *wiphy,
3664 struct wireless_dev *wdev,
3665 const void *data, int data_len)
3666{
3667 int ret = 0;
3668
3669 cds_ssr_protect(__func__);
3670 ret = __wlan_hdd_cfg80211_extscan_reset_significant_change(wiphy, wdev,
3671 data, data_len);
3672 cds_ssr_unprotect(__func__);
3673
3674 return ret;
3675}
3676
3677
3678/**
3679 * hdd_extscan_epno_fill_network_list() - epno fill network list
3680 * @hddctx: HDD context
3681 * @req_msg: request message
3682 * @tb: vendor attribute table
3683 *
3684 * This function reads the network block NL vendor attributes from %tb and
3685 * fill in the epno request message.
3686 *
3687 * Return: 0 on success, error number otherwise
3688 */
3689static int hdd_extscan_epno_fill_network_list(
3690 hdd_context_t *hddctx,
3691 struct wifi_epno_params *req_msg,
3692 struct nlattr **tb)
3693{
3694 struct nlattr *network[
3695 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX + 1];
3696 struct nlattr *networks;
3697 int rem1, ssid_len;
3698 uint8_t index, *ssid;
3699
3700 index = 0;
3701 nla_for_each_nested(networks,
3702 tb[QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORKS_LIST],
3703 rem1) {
3704 if (nla_parse(network,
3705 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX,
3706 nla_data(networks), nla_len(networks), NULL)) {
3707 hddLog(LOGE, FL("nla_parse failed"));
3708 return -EINVAL;
3709 }
3710
3711 /* Parse and fetch ssid */
3712 if (!network[QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_SSID]) {
3713 hddLog(LOGE, FL("attr network ssid failed"));
3714 return -EINVAL;
3715 }
3716 ssid_len = nla_len(
3717 network[QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_SSID]);
3718
3719 /* Decrement by 1, don't count null character */
3720 ssid_len--;
3721
3722 req_msg->networks[index].ssid.length = ssid_len;
3723 hddLog(LOG1, FL("network ssid length %d"), ssid_len);
3724 ssid = nla_data(network[QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_SSID]);
3725 cdf_mem_copy(req_msg->networks[index].ssid.ssId,
3726 ssid, ssid_len);
3727 hddLog(LOG1, FL("Ssid (%.*s)"),
3728 req_msg->networks[index].ssid.length,
3729 req_msg->networks[index].ssid.ssId);
3730
3731 /* Parse and fetch rssi threshold */
3732 if (!network[QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_RSSI_THRESHOLD]) {
3733 hddLog(LOGE, FL("attr rssi threshold failed"));
3734 return -EINVAL;
3735 }
3736 req_msg->networks[index].rssi_threshold = nla_get_s8(
3737 network[QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_RSSI_THRESHOLD]);
3738 hddLog(LOG1, FL("rssi threshold %d"),
3739 req_msg->networks[index].rssi_threshold);
3740
3741 /* Parse and fetch epno flags */
3742 if (!network[QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_FLAGS]) {
3743 hddLog(LOGE, FL("attr epno flags failed"));
3744 return -EINVAL;
3745 }
3746 req_msg->networks[index].flags = nla_get_u8(
3747 network[QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_FLAGS]);
3748 hddLog(LOG1, FL("flags %u"), req_msg->networks[index].flags);
3749
3750 /* Parse and fetch auth bit */
3751 if (!network[QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_AUTH_BIT]) {
3752 hddLog(LOGE, FL("attr auth bit failed"));
3753 return -EINVAL;
3754 }
3755 req_msg->networks[index].auth_bit_field = nla_get_u8(
3756 network[QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_AUTH_BIT]);
3757 hddLog(LOG1, FL("auth bit %u"),
3758 req_msg->networks[index].auth_bit_field);
3759
3760 index++;
3761 }
3762 return 0;
3763}
3764
3765/**
3766 * __wlan_hdd_cfg80211_set_epno_list() - epno set network list
3767 * @wiphy: wiphy
3768 * @wdev: pointer to wireless dev
3769 * @data: data pointer
3770 * @data_len: data length
3771 *
3772 * This function reads the NL vendor attributes from %tb and
3773 * fill in the epno request message.
3774 *
3775 * Return: 0 on success, error number otherwise
3776 */
3777static int __wlan_hdd_cfg80211_set_epno_list(struct wiphy *wiphy,
3778 struct wireless_dev *wdev,
3779 const void *data,
3780 int data_len)
3781{
3782 struct wifi_epno_params *req_msg = NULL;
3783 struct net_device *dev = wdev->netdev;
3784 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
3785 hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
3786 struct nlattr *tb[
3787 QCA_WLAN_VENDOR_ATTR_PNO_MAX + 1];
3788 CDF_STATUS status;
3789 uint32_t num_networks, len;
3790 int ret_val;
3791
3792 ENTER();
3793
3794 ret_val = wlan_hdd_validate_context(hdd_ctx);
3795 if (ret_val)
3796 return ret_val;
3797
3798 if (CDF_FTM_MODE == hdd_get_conparam()) {
3799 hdd_err("Command not allowed in FTM mode");
3800 return -EPERM;
3801 }
3802
3803 if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_PNO_MAX,
3804 data, data_len,
3805 wlan_hdd_extscan_config_policy)) {
3806 hddLog(LOGE, FL("Invalid ATTR"));
3807 return -EINVAL;
3808 }
3809
3810 /* Parse and fetch number of networks */
3811 if (!tb[QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_NUM_NETWORKS]) {
3812 hddLog(LOGE, FL("attr num networks failed"));
3813 return -EINVAL;
3814 }
3815 num_networks = nla_get_u32(
3816 tb[QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_NUM_NETWORKS]);
3817 hddLog(LOG1, FL("num networks %u"), num_networks);
3818
3819 len = sizeof(*req_msg) +
3820 (num_networks * sizeof(struct wifi_epno_network));
3821 req_msg = cdf_mem_malloc(len);
3822 if (!req_msg) {
3823 hddLog(LOGE, FL("cdf_mem_malloc failed"));
3824 return -ENOMEM;
3825 }
3826 cdf_mem_zero(req_msg, len);
3827 req_msg->num_networks = num_networks;
3828
3829 /* Parse and fetch request Id */
3830 if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]) {
3831 hddLog(LOGE, FL("attr request id failed"));
3832 goto fail;
3833 }
3834 req_msg->request_id = nla_get_u32(
3835 tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]);
3836 hddLog(LOG1, FL("Req Id %u"), req_msg->request_id);
3837
3838 req_msg->session_id = adapter->sessionId;
3839 hddLog(LOG1, FL("Session Id %d"), req_msg->session_id);
3840
3841 if (hdd_extscan_epno_fill_network_list(hdd_ctx, req_msg, tb))
3842 goto fail;
3843
3844 status = sme_set_epno_list(hdd_ctx->hHal, req_msg);
3845 if (!CDF_IS_STATUS_SUCCESS(status)) {
3846 hddLog(LOGE, FL("sme_set_epno_list failed(err=%d)"), status);
3847 goto fail;
3848 }
3849
3850 EXIT();
3851 cdf_mem_free(req_msg);
3852 return 0;
3853
3854fail:
3855 cdf_mem_free(req_msg);
3856 return -EINVAL;
3857}
3858
3859 /**
3860 * wlan_hdd_cfg80211_set_epno_list() - epno set network list
3861 * @wiphy: wiphy
3862 * @wdev: pointer to wireless dev
3863 * @data: data pointer
3864 * @data_len: data length
3865 *
3866 * This function reads the NL vendor attributes from %tb and
3867 * fill in the epno request message.
3868 *
3869 * Return: 0 on success, error number otherwise
3870 */
3871int wlan_hdd_cfg80211_set_epno_list(struct wiphy *wiphy,
3872 struct wireless_dev *wdev,
3873 const void *data,
3874 int data_len)
3875{
3876 int ret;
3877
3878 cds_ssr_protect(__func__);
3879 ret = __wlan_hdd_cfg80211_set_epno_list(wiphy, wdev,
3880 data, data_len);
3881 cds_ssr_unprotect(__func__);
3882
3883 return ret;
3884}
3885
3886/**
3887 * hdd_extscan_passpoint_fill_network_list() - passpoint fill network list
3888 * @hddctx: HDD context
3889 * @req_msg: request message
3890 * @tb: vendor attribute table
3891 *
3892 * This function reads the network block NL vendor attributes from %tb and
3893 * fill in the passpoint request message.
3894 *
3895 * Return: 0 on success, error number otherwise
3896 */
3897static int hdd_extscan_passpoint_fill_network_list(
3898 hdd_context_t *hddctx,
3899 struct wifi_passpoint_req *req_msg,
3900 struct nlattr **tb)
3901{
3902 struct nlattr *network[QCA_WLAN_VENDOR_ATTR_PNO_MAX + 1];
3903 struct nlattr *networks;
3904 int rem1, len;
3905 uint8_t index;
3906
3907 index = 0;
3908 nla_for_each_nested(networks,
3909 tb[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_LIST_PARAM_NETWORK_ARRAY],
3910 rem1) {
3911 if (nla_parse(network,
3912 QCA_WLAN_VENDOR_ATTR_PNO_MAX,
3913 nla_data(networks), nla_len(networks), NULL)) {
3914 hddLog(LOGE, FL("nla_parse failed"));
3915 return -EINVAL;
3916 }
3917
3918 /* Parse and fetch identifier */
3919 if (!network[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ID]) {
3920 hddLog(LOGE, FL("attr passpoint id failed"));
3921 return -EINVAL;
3922 }
3923 req_msg->networks[index].id = nla_get_u32(
3924 network[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ID]);
3925 hddLog(LOG1, FL("Id %u"), req_msg->networks[index].id);
3926
3927 /* Parse and fetch realm */
3928 if (!network[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_REALM]) {
3929 hddLog(LOGE, FL("attr realm failed"));
3930 return -EINVAL;
3931 }
3932 len = nla_len(
3933 network[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_REALM]);
3934 if (len < 0 || len > SIR_PASSPOINT_REALM_LEN) {
3935 hddLog(LOGE, FL("Invalid realm size %d"), len);
3936 return -EINVAL;
3937 }
3938 cdf_mem_copy(req_msg->networks[index].realm,
3939 nla_data(network[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_REALM]),
3940 len);
3941 hddLog(LOG1, FL("realm len %d"), len);
3942 hddLog(LOG1, FL("realm: %s"), req_msg->networks[index].realm);
3943
3944 /* Parse and fetch roaming consortium ids */
3945 if (!network[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ROAM_CNSRTM_ID]) {
3946 hddLog(LOGE, FL("attr roaming consortium ids failed"));
3947 return -EINVAL;
3948 }
3949 nla_memcpy(&req_msg->networks[index].roaming_consortium_ids,
3950 network[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ROAM_CNSRTM_ID],
3951 sizeof(req_msg->networks[0].roaming_consortium_ids));
3952 hddLog(LOG1, FL("roaming consortium ids"));
3953
3954 /* Parse and fetch plmn */
3955 if (!network[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ROAM_PLMN]) {
3956 hddLog(LOGE, FL("attr plmn failed"));
3957 return -EINVAL;
3958 }
3959 nla_memcpy(&req_msg->networks[index].plmn,
3960 network[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ROAM_PLMN],
3961 SIR_PASSPOINT_PLMN_LEN);
3962 hddLog(LOG1, FL("plmn %02x:%02x:%02x)"),
3963 req_msg->networks[index].plmn[0],
3964 req_msg->networks[index].plmn[1],
3965 req_msg->networks[index].plmn[2]);
3966
3967 index++;
3968 }
3969 return 0;
3970}
3971
3972/**
3973 * __wlan_hdd_cfg80211_set_passpoint_list() - set passpoint network list
3974 * @wiphy: wiphy
3975 * @wdev: pointer to wireless dev
3976 * @data: data pointer
3977 * @data_len: data length
3978 *
3979 * This function reads the NL vendor attributes from %tb and
3980 * fill in the passpoint request message.
3981 *
3982 * Return: 0 on success, error number otherwise
3983 */
3984static int __wlan_hdd_cfg80211_set_passpoint_list(struct wiphy *wiphy,
3985 struct wireless_dev *wdev,
3986 const void *data,
3987 int data_len)
3988{
3989 struct wifi_passpoint_req *req_msg = NULL;
3990 struct net_device *dev = wdev->netdev;
3991 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
3992 hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
3993 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_PNO_MAX + 1];
3994 CDF_STATUS status;
3995 uint32_t num_networks = 0;
3996 int ret;
3997
3998 ENTER();
3999
4000 ret = wlan_hdd_validate_context(hdd_ctx);
4001 if (ret)
4002 return ret;
4003
4004 if (CDF_FTM_MODE == hdd_get_conparam()) {
4005 hdd_err("Command not allowed in FTM mode");
4006 return -EPERM;
4007 }
4008
4009 if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_PNO_MAX, data, data_len,
4010 wlan_hdd_extscan_config_policy)) {
4011 hddLog(LOGE, FL("Invalid ATTR"));
4012 return -EINVAL;
4013 }
4014
4015 /* Parse and fetch number of networks */
4016 if (!tb[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_LIST_PARAM_NUM]) {
4017 hddLog(LOGE, FL("attr num networks failed"));
4018 return -EINVAL;
4019 }
4020 num_networks = nla_get_u32(
4021 tb[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_LIST_PARAM_NUM]);
4022 hddLog(LOG1, FL("num networks %u"), num_networks);
4023
4024 req_msg = cdf_mem_malloc(sizeof(*req_msg) +
4025 (num_networks * sizeof(req_msg->networks[0])));
4026 if (!req_msg) {
4027 hddLog(LOGE, FL("cdf_mem_malloc failed"));
4028 return -ENOMEM;
4029 }
4030 req_msg->num_networks = num_networks;
4031
4032 /* Parse and fetch request Id */
4033 if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]) {
4034 hddLog(LOGE, FL("attr request id failed"));
4035 goto fail;
4036 }
4037 req_msg->request_id = nla_get_u32(
4038 tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]);
4039
4040 req_msg->session_id = adapter->sessionId;
4041 hddLog(LOG1, FL("Req Id %u Session Id %d"), req_msg->request_id,
4042 req_msg->session_id);
4043
4044 if (hdd_extscan_passpoint_fill_network_list(hdd_ctx, req_msg, tb))
4045 goto fail;
4046
4047 status = sme_set_passpoint_list(hdd_ctx->hHal, req_msg);
4048 if (!CDF_IS_STATUS_SUCCESS(status)) {
4049 hddLog(LOGE,
4050 FL("sme_set_passpoint_list failed(err=%d)"), status);
4051 goto fail;
4052 }
4053
4054 EXIT();
4055 cdf_mem_free(req_msg);
4056 return 0;
4057
4058fail:
4059 cdf_mem_free(req_msg);
4060 return -EINVAL;
4061}
4062
4063/**
4064 * wlan_hdd_cfg80211_set_passpoint_list() - set passpoint network list
4065 * @wiphy: wiphy
4066 * @wdev: pointer to wireless dev
4067 * @data: data pointer
4068 * @data_len: data length
4069 *
4070 * This function reads the NL vendor attributes from %tb and
4071 * fill in the passpoint request message.
4072 *
4073 * Return: 0 on success, error number otherwise
4074 */
4075int wlan_hdd_cfg80211_set_passpoint_list(struct wiphy *wiphy,
4076 struct wireless_dev *wdev,
4077 const void *data,
4078 int data_len)
4079{
4080 int ret;
4081
4082 cds_ssr_protect(__func__);
4083 ret = __wlan_hdd_cfg80211_set_passpoint_list(wiphy, wdev,
4084 data, data_len);
4085 cds_ssr_unprotect(__func__);
4086
4087 return ret;
4088}
4089
4090/**
4091 * __wlan_hdd_cfg80211_reset_passpoint_list() - reset 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 resets passpoint networks list
4098 *
4099 * Return: 0 on success, error number otherwise
4100 */
4101static int __wlan_hdd_cfg80211_reset_passpoint_list(struct wiphy *wiphy,
4102 struct wireless_dev *wdev,
4103 const void *data,
4104 int data_len)
4105{
4106 struct wifi_passpoint_req *req_msg = NULL;
4107 struct net_device *dev = wdev->netdev;
4108 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
4109 hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
4110 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_PNO_MAX + 1];
4111 CDF_STATUS status;
4112 int ret;
4113
4114 ENTER();
4115
4116 ret = wlan_hdd_validate_context(hdd_ctx);
4117 if (ret)
4118 return ret;
4119
4120 if (CDF_FTM_MODE == hdd_get_conparam()) {
4121 hdd_err("Command not allowed in FTM mode");
4122 return -EPERM;
4123 }
4124
4125 if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_PNO_MAX, data, data_len,
4126 wlan_hdd_extscan_config_policy)) {
4127 hddLog(LOGE, FL("Invalid ATTR"));
4128 return -EINVAL;
4129 }
4130
4131 req_msg = cdf_mem_malloc(sizeof(*req_msg));
4132 if (!req_msg) {
4133 hddLog(LOGE, FL("cdf_mem_malloc failed"));
4134 return -ENOMEM;
4135 }
4136
4137 /* Parse and fetch request Id */
4138 if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]) {
4139 hddLog(LOGE, FL("attr request id failed"));
4140 goto fail;
4141 }
4142 req_msg->request_id = nla_get_u32(
4143 tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]);
4144
4145 req_msg->session_id = adapter->sessionId;
4146 hddLog(LOG1, FL("Req Id %u Session Id %d"),
4147 req_msg->request_id, req_msg->session_id);
4148
4149 status = sme_reset_passpoint_list(hdd_ctx->hHal, req_msg);
4150 if (!CDF_IS_STATUS_SUCCESS(status)) {
4151 hddLog(LOGE,
4152 FL("sme_reset_passpoint_list failed(err=%d)"), status);
4153 goto fail;
4154 }
4155
4156 EXIT();
4157 cdf_mem_free(req_msg);
4158 return 0;
4159
4160fail:
4161 cdf_mem_free(req_msg);
4162 return -EINVAL;
4163}
4164
4165/**
4166 * wlan_hdd_cfg80211_reset_passpoint_list() - reset passpoint network list
4167 * @wiphy: wiphy
4168 * @wdev: pointer to wireless dev
4169 * @data: data pointer
4170 * @data_len: data length
4171 *
4172 * This function resets passpoint networks list
4173 *
4174 * Return: 0 on success, error number otherwise
4175 */
4176int wlan_hdd_cfg80211_reset_passpoint_list(struct wiphy *wiphy,
4177 struct wireless_dev *wdev,
4178 const void *data,
4179 int data_len)
4180{
4181 int ret;
4182
4183 cds_ssr_protect(__func__);
4184 ret = __wlan_hdd_cfg80211_reset_passpoint_list(wiphy, wdev,
4185 data, data_len);
4186 cds_ssr_unprotect(__func__);
4187
4188 return ret;
4189}
4190
4191/*
4192 * define short names for the global vendor params
4193 * used by __wlan_hdd_cfg80211_extscan_set_ssid_hotlist()
4194 */
4195#define PARAM_MAX \
4196 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX
4197#define PARAM_REQUEST_ID \
4198 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID
4199#define PARAMS_LOST_SSID_SAMPLE_SIZE \
4200 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_HOTLIST_PARAMS_LOST_SSID_SAMPLE_SIZE
4201#define PARAMS_NUM_SSID \
4202 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_HOTLIST_PARAMS_NUM_SSID
4203#define THRESHOLD_PARAM \
4204 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM
4205#define PARAM_SSID \
4206 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM_SSID
4207#define PARAM_BAND \
4208 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM_BAND
4209#define PARAM_RSSI_LOW \
4210 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM_RSSI_LOW
4211#define PARAM_RSSI_HIGH \
4212 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM_RSSI_HIGH
4213
4214/**
4215 * __wlan_hdd_cfg80211_extscan_set_ssid_hotlist() - set ssid hot list
4216 * @wiphy: Pointer to wireless phy
4217 * @wdev: Pointer to wireless device
4218 * @data: Pointer to data
4219 * @data_len: Data length
4220 *
4221 * Return: 0 on success, negative errno on failure
4222 */
4223static int
4224__wlan_hdd_cfg80211_extscan_set_ssid_hotlist(struct wiphy *wiphy,
4225 struct wireless_dev *wdev,
4226 const void *data,
4227 int data_len)
4228{
4229 struct sir_set_ssid_hotlist_request *request;
4230 struct net_device *dev = wdev->netdev;
4231 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
4232 hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
4233 struct nlattr *tb[PARAM_MAX + 1];
4234 struct nlattr *tb2[PARAM_MAX + 1];
4235 struct nlattr *ssids;
4236 struct hdd_ext_scan_context *context;
4237 uint32_t request_id;
4238 char ssid_string[SIR_MAC_MAX_SSID_LENGTH + 1];
4239 int ssid_len, i, rem;
4240 CDF_STATUS status;
4241 int retval;
4242 unsigned long rc;
4243
4244 ENTER();
4245
4246 if (CDF_FTM_MODE == hdd_get_conparam()) {
4247 hdd_err("Command not allowed in FTM mode");
4248 return -EPERM;
4249 }
4250
4251 retval = wlan_hdd_validate_context(hdd_ctx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05304252 if (0 != retval)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004253 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004254
4255 if (nla_parse(tb, PARAM_MAX,
4256 data, data_len,
4257 wlan_hdd_extscan_config_policy)) {
4258 hddLog(LOGE, FL("Invalid ATTR"));
4259 return -EINVAL;
4260 }
4261
4262 request = cdf_mem_malloc(sizeof(*request));
4263 if (!request) {
4264 hddLog(LOGE, FL("cdf_mem_malloc failed"));
4265 return -ENOMEM;
4266 }
4267
4268 /* Parse and fetch request Id */
4269 if (!tb[PARAM_REQUEST_ID]) {
4270 hddLog(LOGE, FL("attr request id failed"));
4271 goto fail;
4272 }
4273
4274 request->request_id = nla_get_u32(tb[PARAM_REQUEST_ID]);
4275 hddLog(LOG1, FL("Request Id %d"), request->request_id);
4276
4277 /* Parse and fetch lost SSID sample size */
4278 if (!tb[PARAMS_LOST_SSID_SAMPLE_SIZE]) {
4279 hddLog(LOGE, FL("attr number of Ssid failed"));
4280 goto fail;
4281 }
4282 request->lost_ssid_sample_size =
4283 nla_get_u32(tb[PARAMS_LOST_SSID_SAMPLE_SIZE]);
4284 hddLog(LOG1, FL("Lost SSID Sample Size %d"),
4285 request->lost_ssid_sample_size);
4286
4287 /* Parse and fetch number of hotlist SSID */
4288 if (!tb[PARAMS_NUM_SSID]) {
4289 hddLog(LOGE, FL("attr number of Ssid failed"));
4290 goto fail;
4291 }
4292 request->ssid_count = nla_get_u32(tb[PARAMS_NUM_SSID]);
4293 hddLog(LOG1, FL("Number of SSID %d"), request->ssid_count);
4294
4295 request->session_id = adapter->sessionId;
4296 hddLog(LOG1, FL("Session Id %d"), request->session_id);
4297
4298 i = 0;
4299 nla_for_each_nested(ssids, tb[THRESHOLD_PARAM], rem) {
4300 if (i >= WLAN_EXTSCAN_MAX_HOTLIST_SSIDS) {
4301 hddLog(LOGE,
4302 FL("Too Many SSIDs, %d exceeds %d"),
4303 i, WLAN_EXTSCAN_MAX_HOTLIST_SSIDS);
4304 break;
4305 }
4306 if (nla_parse(tb2, PARAM_MAX,
4307 nla_data(ssids), nla_len(ssids),
4308 wlan_hdd_extscan_config_policy)) {
4309 hddLog(LOGE, FL("nla_parse failed"));
4310 goto fail;
4311 }
4312
4313 /* Parse and fetch SSID */
4314 if (!tb2[PARAM_SSID]) {
4315 hddLog(LOGE, FL("attr ssid failed"));
4316 goto fail;
4317 }
4318 nla_memcpy(ssid_string,
4319 tb2[PARAM_SSID],
4320 sizeof(ssid_string));
4321 hddLog(LOG1, FL("SSID %s"),
4322 ssid_string);
4323 ssid_len = strlen(ssid_string);
4324 memcpy(request->ssids[i].ssid.ssId, ssid_string, ssid_len);
4325 request->ssids[i].ssid.length = ssid_len;
4326
4327 /* Parse and fetch low RSSI */
4328 if (!tb2[PARAM_BAND]) {
4329 hddLog(LOGE, FL("attr band failed"));
4330 goto fail;
4331 }
4332 request->ssids[i].band = nla_get_u8(tb2[PARAM_BAND]);
4333 hddLog(LOG1, FL("band %d"), request->ssids[i].band);
4334
4335 /* Parse and fetch low RSSI */
4336 if (!tb2[PARAM_RSSI_LOW]) {
4337 hddLog(LOGE, FL("attr low RSSI failed"));
4338 goto fail;
4339 }
4340 request->ssids[i].rssi_low = nla_get_s32(tb2[PARAM_RSSI_LOW]);
4341 hddLog(LOG1, FL("RSSI low %d"), request->ssids[i].rssi_low);
4342
4343 /* Parse and fetch high RSSI */
4344 if (!tb2[PARAM_RSSI_HIGH]) {
4345 hddLog(LOGE, FL("attr high RSSI failed"));
4346 goto fail;
4347 }
4348 request->ssids[i].rssi_high = nla_get_u32(tb2[PARAM_RSSI_HIGH]);
4349 hddLog(LOG1, FL("RSSI high %d"), request->ssids[i].rssi_high);
4350 i++;
4351 }
4352
4353 context = &ext_scan_context;
4354 spin_lock(&context->context_lock);
4355 INIT_COMPLETION(context->response_event);
4356 context->request_id = request_id = request->request_id;
4357 spin_unlock(&context->context_lock);
4358
4359 status = sme_set_ssid_hotlist(hdd_ctx->hHal, request);
4360 if (!CDF_IS_STATUS_SUCCESS(status)) {
4361 hddLog(LOGE,
4362 FL("sme_set_ssid_hotlist failed(err=%d)"), status);
4363 goto fail;
4364 }
4365
4366 cdf_mem_free(request);
4367
4368 /* request was sent -- wait for the response */
4369 rc = wait_for_completion_timeout(&context->response_event,
4370 msecs_to_jiffies
4371 (WLAN_WAIT_TIME_EXTSCAN));
4372 if (!rc) {
4373 hddLog(LOGE, FL("sme_set_ssid_hotlist timed out"));
4374 retval = -ETIMEDOUT;
4375 } else {
4376 spin_lock(&context->context_lock);
4377 if (context->request_id == request_id)
4378 retval = context->response_status;
4379 else
4380 retval = -EINVAL;
4381 spin_unlock(&context->context_lock);
4382 }
4383
4384 return retval;
4385
4386fail:
4387 cdf_mem_free(request);
4388 return -EINVAL;
4389}
4390
4391/*
4392 * done with short names for the global vendor params
4393 * used by wlan_hdd_cfg80211_extscan_set_ssid_hotlist()
4394 */
4395#undef PARAM_MAX
4396#undef PARAM_REQUEST_ID
4397#undef PARAMS_NUM_SSID
4398#undef THRESHOLD_PARAM
4399#undef PARAM_SSID
4400#undef PARAM_BAND
4401#undef PARAM_RSSI_LOW
4402#undef PARAM_RSSI_HIGH
4403
4404/**
4405 * wlan_hdd_cfg80211_extscan_set_ssid_hotlist() - set ssid hot list
4406 * @wiphy: Pointer to wireless phy
4407 * @wdev: Pointer to wireless device
4408 * @data: Pointer to data
4409 * @data_len: Data length
4410 *
4411 * Return: 0 on success, negative errno on failure
4412 */
4413int
4414wlan_hdd_cfg80211_extscan_set_ssid_hotlist(struct wiphy *wiphy,
4415 struct wireless_dev *wdev,
4416 const void *data,
4417 int data_len)
4418{
4419 int ret;
4420
4421 cds_ssr_protect(__func__);
4422 ret = __wlan_hdd_cfg80211_extscan_set_ssid_hotlist(wiphy, wdev, data,
4423 data_len);
4424 cds_ssr_unprotect(__func__);
4425
4426 return ret;
4427}
4428
4429/*
4430 * define short names for the global vendor params
4431 * used by __wlan_hdd_cfg80211_extscan_reset_ssid_hotlist()
4432 */
4433#define PARAM_MAX \
4434 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX
4435#define PARAM_REQUEST_ID \
4436 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID
4437
4438/**
4439 * __wlan_hdd_cfg80211_extscan_reset_ssid_hotlist() - reset ssid hot list
4440 * @wiphy: Pointer to wireless phy
4441 * @wdev: Pointer to wireless device
4442 * @data: Pointer to data
4443 * @data_len: Data length
4444 *
4445 * Return: 0 on success, negative errno on failure
4446 */
4447static int
4448__wlan_hdd_cfg80211_extscan_reset_ssid_hotlist(struct wiphy *wiphy,
4449 struct wireless_dev *wdev,
4450 const void *data,
4451 int data_len)
4452{
4453 struct sir_set_ssid_hotlist_request *request;
4454 struct net_device *dev = wdev->netdev;
4455 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
4456 hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
4457 struct nlattr *tb[PARAM_MAX + 1];
4458 struct hdd_ext_scan_context *context;
4459 uint32_t request_id;
4460 CDF_STATUS status;
4461 int retval;
4462 unsigned long rc;
4463
4464 ENTER();
4465
4466 if (CDF_FTM_MODE == hdd_get_conparam()) {
4467 hdd_err("Command not allowed in FTM mode");
4468 return -EPERM;
4469 }
4470
4471 retval = wlan_hdd_validate_context(hdd_ctx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05304472 if (0 != retval)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004473 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004474
4475 if (nla_parse(tb, PARAM_MAX,
4476 data, data_len,
4477 wlan_hdd_extscan_config_policy)) {
4478 hddLog(LOGE, FL("Invalid ATTR"));
4479 return -EINVAL;
4480 }
4481
4482 request = cdf_mem_malloc(sizeof(*request));
4483 if (!request) {
4484 hddLog(LOGE, FL("cdf_mem_malloc failed"));
4485 return -ENOMEM;
4486 }
4487
4488 /* Parse and fetch request Id */
4489 if (!tb[PARAM_REQUEST_ID]) {
4490 hddLog(LOGE, FL("attr request id failed"));
4491 goto fail;
4492 }
4493
4494 request->request_id = nla_get_u32(tb[PARAM_REQUEST_ID]);
4495 hddLog(LOG1, FL("Request Id %d"), request->request_id);
4496
4497 request->session_id = adapter->sessionId;
4498 hddLog(LOG1, FL("Session Id %d"), request->session_id);
4499
4500 request->lost_ssid_sample_size = 0;
4501 request->ssid_count = 0;
4502
4503 context = &ext_scan_context;
4504 spin_lock(&context->context_lock);
4505 INIT_COMPLETION(context->response_event);
4506 context->request_id = request_id = request->request_id;
4507 spin_unlock(&context->context_lock);
4508
4509 status = sme_set_ssid_hotlist(hdd_ctx->hHal, request);
4510 if (!CDF_IS_STATUS_SUCCESS(status)) {
4511 hddLog(LOGE,
4512 FL("sme_reset_ssid_hotlist failed(err=%d)"), status);
4513 goto fail;
4514 }
4515
4516 cdf_mem_free(request);
4517
4518 /* request was sent -- wait for the response */
4519 rc = wait_for_completion_timeout(&context->response_event,
4520 msecs_to_jiffies
4521 (WLAN_WAIT_TIME_EXTSCAN));
4522 if (!rc) {
4523 hddLog(LOGE, FL("sme_reset_ssid_hotlist timed out"));
4524 retval = -ETIMEDOUT;
4525 } else {
4526 spin_lock(&context->context_lock);
4527 if (context->request_id == request_id)
4528 retval = context->response_status;
4529 else
4530 retval = -EINVAL;
4531 spin_unlock(&context->context_lock);
4532 }
4533
4534 return retval;
4535
4536fail:
4537 cdf_mem_free(request);
4538 return -EINVAL;
4539}
4540
4541/*
4542 * done with short names for the global vendor params
4543 * used by wlan_hdd_cfg80211_extscan_reset_ssid_hotlist()
4544 */
4545#undef PARAM_MAX
4546#undef PARAM_REQUEST_ID
4547
4548/**
4549 * wlan_hdd_cfg80211_extscan_reset_ssid_hotlist() - reset ssid hot list
4550 * @wiphy: Pointer to wireless phy
4551 * @wdev: Pointer to wireless device
4552 * @data: Pointer to data
4553 * @data_len: Data length
4554 *
4555 * Return: 0 on success, negative errno on failure
4556 */
4557int
4558wlan_hdd_cfg80211_extscan_reset_ssid_hotlist(struct wiphy *wiphy,
4559 struct wireless_dev *wdev,
4560 const void *data,
4561 int data_len)
4562{
4563 int ret;
4564
4565 cds_ssr_protect(__func__);
4566 ret = __wlan_hdd_cfg80211_extscan_reset_ssid_hotlist(wiphy, wdev,
4567 data, data_len);
4568 cds_ssr_unprotect(__func__);
4569
4570 return ret;
4571}
4572
4573/**
4574 * wlan_hdd_init_completion_extwow() - Initialize ext wow variable
4575 * @hdd_ctx: Global HDD context
4576 *
4577 * Return: none
4578 */
4579#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
4580static inline void wlan_hdd_init_completion_extwow(hdd_context_t *pHddCtx)
4581{
4582 init_completion(&pHddCtx->ready_to_extwow);
4583}
4584#else
4585static inline void wlan_hdd_init_completion_extwow(hdd_context_t *pHddCtx)
4586{
4587 return;
4588}
4589#endif
4590
4591/**
4592 * wlan_hdd_cfg80211_extscan_init() - Initialize the ExtScan feature
4593 * @hdd_ctx: Global HDD context
4594 *
4595 * Return: none
4596 */
4597void wlan_hdd_cfg80211_extscan_init(hdd_context_t *hdd_ctx)
4598{
4599 wlan_hdd_init_completion_extwow(hdd_ctx);
4600 init_completion(&ext_scan_context.response_event);
4601 spin_lock_init(&ext_scan_context.context_lock);
4602}
4603
4604#endif /* FEATURE_WLAN_EXTSCAN */