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