blob: e692ab71f66671aa0490190df6d3423f0c7a8b10 [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) {
Jeff Johnson56951332015-10-29 11:26:02 -07002908 if ((j >= req_msg->buckets[bkt_index].numChannels) ||
2909 hdd_extscan_channel_max_reached(req_msg,
2910 total_channels))
2911 break;
2912
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002913 if (nla_parse(channel,
2914 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX,
2915 nla_data(channels), nla_len(channels),
2916 wlan_hdd_extscan_config_policy)) {
2917 hddLog(LOGE, FL("nla_parse failed"));
2918 return -EINVAL;
2919 }
2920
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002921 /* Parse and fetch channel */
2922 if (!channel[
2923 QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_CHANNEL]) {
2924 hddLog(LOGE, FL("attr channel failed"));
2925 return -EINVAL;
2926 }
2927 req_msg->buckets[bkt_index].channels[j].channel =
2928 nla_get_u32(channel[
2929 QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_CHANNEL]);
2930 hddLog(LOG1, FL("channel %u"),
2931 req_msg->buckets[bkt_index].channels[j].channel);
2932
2933 /* Parse and fetch dwell time */
2934 if (!channel[
2935 QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_DWELL_TIME]) {
2936 hddLog(LOGE, FL("attr dwelltime failed"));
2937 return -EINVAL;
2938 }
2939 req_msg->buckets[bkt_index].channels[j].dwellTimeMs =
2940 nla_get_u32(channel[
2941 QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_DWELL_TIME]);
2942
2943 /* Override dwell time if required */
2944 if (req_msg->buckets[bkt_index].channels[j].dwellTimeMs <
2945 hdd_ctx->config->extscan_active_min_chn_time ||
2946 req_msg->buckets[bkt_index].channels[j].dwellTimeMs >
2947 hdd_ctx->config->extscan_active_max_chn_time) {
2948 hddLog(LOG1, FL("WiFi band is unspecified, dwellTime:%d"),
2949 req_msg->buckets[bkt_index].channels[j].dwellTimeMs);
2950
2951 if (CDS_IS_PASSIVE_OR_DISABLE_CH(
2952 cds_freq_to_chan(
2953 req_msg->buckets[bkt_index].channels[j].channel))) {
2954 req_msg->buckets[bkt_index].channels[j].dwellTimeMs =
2955 hdd_ctx->config->extscan_passive_max_chn_time;
2956 } else {
2957 req_msg->buckets[bkt_index].channels[j].dwellTimeMs =
2958 hdd_ctx->config->extscan_active_max_chn_time;
2959 }
2960 }
2961
2962 hddLog(LOG1, FL("New Dwell time %u ms"),
2963 req_msg->buckets[bkt_index].channels[j].dwellTimeMs);
2964
2965 if (CDS_IS_PASSIVE_OR_DISABLE_CH(
2966 cds_freq_to_chan(
2967 req_msg->buckets[bkt_index].channels[j].channel))) {
2968 if (min_dwell_time_passive_bucket >
2969 req_msg->buckets[bkt_index].channels[j].dwellTimeMs) {
2970 min_dwell_time_passive_bucket =
2971 req_msg->buckets[bkt_index].channels[j].dwellTimeMs;
2972 }
2973 if (max_dwell_time_passive_bucket <
2974 req_msg->buckets[bkt_index].channels[j].dwellTimeMs) {
2975 max_dwell_time_passive_bucket =
2976 req_msg->buckets[bkt_index].channels[j].dwellTimeMs;
2977 }
2978 } else {
2979 if (min_dwell_time_active_bucket >
2980 req_msg->buckets[bkt_index].channels[j].dwellTimeMs) {
2981 min_dwell_time_active_bucket =
2982 req_msg->buckets[bkt_index].channels[j].dwellTimeMs;
2983 }
2984 if (max_dwell_time_active_bucket <
2985 req_msg->buckets[bkt_index].channels[j].dwellTimeMs) {
2986 max_dwell_time_active_bucket =
2987 req_msg->buckets[bkt_index].channels[j].dwellTimeMs;
2988 }
2989 }
2990
2991 /* Parse and fetch channel spec passive */
2992 if (!channel[
2993 QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_PASSIVE]) {
2994 hddLog(LOGE,
2995 FL("attr channel spec passive failed"));
2996 return -EINVAL;
2997 }
2998 req_msg->buckets[bkt_index].channels[j].passive =
2999 nla_get_u8(channel[
3000 QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_PASSIVE]);
3001 hddLog(LOG1, FL("Chnl spec passive %u"),
3002 req_msg->buckets[bkt_index].channels[j].passive);
3003 /* Override scan type if required */
3004 if (CDS_IS_PASSIVE_OR_DISABLE_CH(
3005 cds_freq_to_chan(
3006 req_msg->buckets[bkt_index].channels[j].channel))) {
3007 req_msg->buckets[bkt_index].channels[j].passive = true;
3008 } else {
3009 req_msg->buckets[bkt_index].channels[j].passive = false;
3010 }
3011 j++;
3012 total_channels++;
3013 }
3014
3015 hdd_extscan_update_dwell_time_limits(
3016 req_msg, bkt_index,
3017 min_dwell_time_active_bucket,
3018 max_dwell_time_active_bucket,
3019 min_dwell_time_passive_bucket,
3020 max_dwell_time_passive_bucket);
3021
3022 hddLog(LOG1, FL("bktIndex:%d actv_min:%d actv_max:%d pass_min:%d pass_max:%d"),
3023 bkt_index,
3024 req_msg->buckets[bkt_index].min_dwell_time_active,
3025 req_msg->buckets[bkt_index].max_dwell_time_active,
3026 req_msg->buckets[bkt_index].min_dwell_time_passive,
3027 req_msg->buckets[bkt_index].max_dwell_time_passive);
3028
3029 bkt_index++;
3030 req_msg->numBuckets++;
3031 }
3032
3033 hddLog(LOG1, FL("Global: actv_min:%d actv_max:%d pass_min:%d pass_max:%d"),
3034 req_msg->min_dwell_time_active,
3035 req_msg->max_dwell_time_active,
3036 req_msg->min_dwell_time_passive,
3037 req_msg->max_dwell_time_passive);
3038
3039 return 0;
3040}
3041
3042/*
3043 * hdd_extscan_map_usr_drv_config_flags() - map userspace to driver config flags
3044 * @config_flags - [input] configuration flags.
3045 *
3046 * This function maps user space received configuration flags to
3047 * driver representation.
3048 *
3049 * Return: configuration flags
3050 */
3051static uint32_t hdd_extscan_map_usr_drv_config_flags(uint32_t config_flags)
3052{
3053 uint32_t configuration_flags = 0;
3054
3055 if (config_flags & EXTSCAN_LP_EXTENDED_BATCHING)
3056 configuration_flags |= EXTSCAN_LP_EXTENDED_BATCHING;
3057
3058 return configuration_flags;
3059}
3060
3061/*
3062 * define short names for the global vendor params
3063 * used by __wlan_hdd_cfg80211_extscan_start()
3064 */
3065#define PARAM_MAX \
3066 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX
3067#define PARAM_REQUEST_ID \
3068 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID
3069#define PARAM_BASE_PERIOD \
3070 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_BASE_PERIOD
3071#define PARAM_MAX_AP_PER_SCAN \
3072 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_MAX_AP_PER_SCAN
3073#define PARAM_RPT_THRHLD_PERCENT \
3074 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_REPORT_THRESHOLD_PERCENT
3075#define PARAM_RPT_THRHLD_NUM_SCANS \
3076 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_REPORT_THRESHOLD_NUM_SCANS
3077#define PARAM_NUM_BUCKETS \
3078 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_NUM_BUCKETS
3079#define PARAM_CONFIG_FLAGS \
3080 QCA_WLAN_VENDOR_ATTR_EXTSCAN_CONFIGURATION_FLAGS
3081
3082/**
3083 * __wlan_hdd_cfg80211_extscan_start() - ext scan start
3084 * @wiphy: Pointer to wireless phy
3085 * @wdev: Pointer to wireless device
3086 * @data: Pointer to data
3087 * @data_len: Length of @data
3088 *
3089 * Return: 0 on success; error number otherwise
3090 */
3091static int
3092__wlan_hdd_cfg80211_extscan_start(struct wiphy *wiphy,
3093 struct wireless_dev *wdev,
3094 const void *data,
3095 int data_len)
3096{
3097 tpSirWifiScanCmdReqParams pReqMsg = NULL;
3098 struct net_device *dev = wdev->netdev;
3099 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
3100 hdd_context_t *pHddCtx = wiphy_priv(wiphy);
3101 struct nlattr *tb[PARAM_MAX + 1];
3102 struct hdd_ext_scan_context *context;
3103 uint32_t request_id, num_buckets;
3104 CDF_STATUS status;
3105 int retval;
3106 unsigned long rc;
3107
3108 ENTER();
3109
3110 if (CDF_FTM_MODE == hdd_get_conparam()) {
3111 hdd_err("Command not allowed in FTM mode");
3112 return -EPERM;
3113 }
3114
3115 retval = wlan_hdd_validate_context(pHddCtx);
3116 if (0 != retval) {
3117 hddLog(LOGE, FL("HDD context is not valid"));
3118 return -EINVAL;
3119 }
3120
3121 if (nla_parse(tb, PARAM_MAX, data, data_len,
3122 wlan_hdd_extscan_config_policy)) {
3123 hddLog(LOGE, FL("Invalid ATTR"));
3124 return -EINVAL;
3125 }
3126
3127 pReqMsg = cdf_mem_malloc(sizeof(*pReqMsg));
3128 if (!pReqMsg) {
3129 hddLog(LOGE, FL("memory allocation failed"));
3130 return -ENOMEM;
3131 }
3132
3133 /* Parse and fetch request Id */
3134 if (!tb[PARAM_REQUEST_ID]) {
3135 hddLog(LOGE, FL("attr request id failed"));
3136 goto fail;
3137 }
3138
3139 pReqMsg->requestId = nla_get_u32(tb[PARAM_REQUEST_ID]);
3140 pReqMsg->sessionId = pAdapter->sessionId;
3141 hddLog(LOG1, FL("Req Id %d Session Id %d"),
3142 pReqMsg->requestId,
3143 pReqMsg->sessionId);
3144
3145 /* Parse and fetch base period */
3146 if (!tb[PARAM_BASE_PERIOD]) {
3147 hddLog(LOGE, FL("attr base period failed"));
3148 goto fail;
3149 }
3150 pReqMsg->basePeriod = nla_get_u32(tb[PARAM_BASE_PERIOD]);
3151 hddLog(LOG1, FL("Base Period %d"),
3152 pReqMsg->basePeriod);
3153
3154 /* Parse and fetch max AP per scan */
3155 if (!tb[PARAM_MAX_AP_PER_SCAN]) {
3156 hddLog(LOGE, FL("attr max_ap_per_scan failed"));
3157 goto fail;
3158 }
3159 pReqMsg->maxAPperScan = nla_get_u32(tb[PARAM_MAX_AP_PER_SCAN]);
3160 hddLog(LOG1, FL("Max AP per Scan %d"), pReqMsg->maxAPperScan);
3161
3162 /* Parse and fetch report threshold percent */
3163 if (!tb[PARAM_RPT_THRHLD_PERCENT]) {
3164 hddLog(LOGE, FL("attr report_threshold percent failed"));
3165 goto fail;
3166 }
3167 pReqMsg->report_threshold_percent = nla_get_u8(tb[PARAM_RPT_THRHLD_PERCENT]);
3168 hddLog(LOG1, FL("Report Threshold percent %d"),
3169 pReqMsg->report_threshold_percent);
3170
3171 /* Parse and fetch report threshold num scans */
3172 if (!tb[PARAM_RPT_THRHLD_NUM_SCANS]) {
3173 hddLog(LOGE, FL("attr report_threshold num scans failed"));
3174 goto fail;
3175 }
3176 pReqMsg->report_threshold_num_scans = nla_get_u8(tb[PARAM_RPT_THRHLD_NUM_SCANS]);
3177 hddLog(LOG1, FL("Report Threshold num scans %d"),
3178 pReqMsg->report_threshold_num_scans);
3179
3180 /* Parse and fetch number of buckets */
3181 if (!tb[PARAM_NUM_BUCKETS]) {
3182 hddLog(LOGE, FL("attr number of buckets failed"));
3183 goto fail;
3184 }
3185 num_buckets = nla_get_u8(tb[PARAM_NUM_BUCKETS]);
3186 if (num_buckets > WLAN_EXTSCAN_MAX_BUCKETS) {
3187 hdd_warn("Exceeded MAX number of buckets: %d",
3188 WLAN_EXTSCAN_MAX_BUCKETS);
3189 }
3190 hdd_info("Input: Number of Buckets %d", num_buckets);
3191
3192 /* This is optional attribute, if not present set it to 0 */
3193 if (!tb[PARAM_CONFIG_FLAGS])
3194 pReqMsg->configuration_flags = 0;
3195 else
3196 pReqMsg->configuration_flags =
3197 hdd_extscan_map_usr_drv_config_flags(
3198 nla_get_u32(tb[PARAM_CONFIG_FLAGS]));
3199
3200 hddLog(LOG1, FL("Configuration flags: %u"),
3201 pReqMsg->configuration_flags);
3202
3203 if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC]) {
3204 hddLog(LOGE, FL("attr bucket spec failed"));
3205 goto fail;
3206 }
3207
3208 if (hdd_extscan_start_fill_bucket_channel_spec(pHddCtx, pReqMsg, tb))
3209 goto fail;
3210
3211 context = &ext_scan_context;
3212 spin_lock(&context->context_lock);
3213 INIT_COMPLETION(context->response_event);
3214 context->request_id = request_id = pReqMsg->requestId;
3215 spin_unlock(&context->context_lock);
3216
3217 status = sme_ext_scan_start(pHddCtx->hHal, pReqMsg);
3218 if (!CDF_IS_STATUS_SUCCESS(status)) {
3219 hddLog(LOGE,
3220 FL("sme_ext_scan_start failed(err=%d)"), status);
3221 goto fail;
3222 }
3223
3224 pHddCtx->ext_scan_start_since_boot = cdf_get_monotonic_boottime();
3225 hddLog(LOG1, FL("Timestamp since boot: %llu"),
3226 pHddCtx->ext_scan_start_since_boot);
3227
3228 /* request was sent -- wait for the response */
3229 rc = wait_for_completion_timeout(&context->response_event,
3230 msecs_to_jiffies(WLAN_WAIT_TIME_EXTSCAN));
3231
3232 if (!rc) {
3233 hddLog(LOGE, FL("sme_ext_scan_start timed out"));
3234 retval = -ETIMEDOUT;
3235 } else {
3236 spin_lock(&context->context_lock);
3237 if (context->request_id == request_id)
3238 retval = context->response_status;
3239 else
3240 retval = -EINVAL;
3241 spin_unlock(&context->context_lock);
3242 }
3243
3244 return retval;
3245
3246fail:
3247 cdf_mem_free(pReqMsg);
3248 return -EINVAL;
3249}
3250/*
3251 * done with short names for the global vendor params
3252 * used by __wlan_hdd_cfg80211_extscan_start()
3253 */
3254#undef PARAM_MAX
3255#undef PARAM_REQUEST_ID
3256#undef PARAM_BASE_PERIOD
3257#undef PARAMS_MAX_AP_PER_SCAN
3258#undef PARAMS_RPT_THRHLD_PERCENT
3259#undef PARAMS_RPT_THRHLD_NUM_SCANS
3260#undef PARAMS_NUM_BUCKETS
3261#undef PARAM_CONFIG_FLAGS
3262
3263/**
3264 * wlan_hdd_cfg80211_extscan_start() - start extscan
3265 * @wiphy: Pointer to wireless phy.
3266 * @wdev: Pointer to wireless device.
3267 * @data: Pointer to input data.
3268 * @data_len: Length of @data.
3269 *
3270 * Return: 0 on success, negative errno on failure
3271 */
3272int wlan_hdd_cfg80211_extscan_start(struct wiphy *wiphy,
3273 struct wireless_dev *wdev,
3274 const void *data, int data_len)
3275{
3276 int ret = 0;
3277
3278 cds_ssr_protect(__func__);
3279 ret = __wlan_hdd_cfg80211_extscan_start(wiphy, wdev, data, data_len);
3280 cds_ssr_unprotect(__func__);
3281
3282 return ret;
3283}
3284
3285
3286/*
3287 * define short names for the global vendor params
3288 * used by __wlan_hdd_cfg80211_extscan_stop()
3289 */
3290#define PARAM_MAX \
3291 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX
3292#define PARAM_REQUEST_ID \
3293 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID
3294
3295/**
3296 * __wlan_hdd_cfg80211_extscan_stop() - ext scan stop
3297 * @wiphy: Pointer to wireless phy
3298 * @wdev: Pointer to wireless device
3299 * @data: Pointer to data
3300 * @data_len: Data length
3301 *
3302 * Return: none
3303 */
3304static int
3305__wlan_hdd_cfg80211_extscan_stop(struct wiphy *wiphy,
3306 struct wireless_dev *wdev,
3307 const void *data, int data_len)
3308{
3309 tpSirExtScanStopReqParams pReqMsg = NULL;
3310 struct net_device *dev = wdev->netdev;
3311 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
3312 hdd_context_t *pHddCtx = wiphy_priv(wiphy);
3313 struct nlattr *tb[PARAM_MAX + 1];
3314 struct hdd_ext_scan_context *context;
3315 CDF_STATUS status;
3316 uint32_t request_id;
3317 int retval;
3318 unsigned long rc;
3319
3320 ENTER();
3321
3322 if (CDF_FTM_MODE == hdd_get_conparam()) {
3323 hdd_err("Command not allowed in FTM mode");
3324 return -EPERM;
3325 }
3326
3327 retval = wlan_hdd_validate_context(pHddCtx);
3328 if (0 != retval) {
3329 hddLog(LOGE, FL("HDD context is not valid"));
3330 return -EINVAL;
3331 }
3332
3333 if (nla_parse(tb, PARAM_MAX, data, data_len,
3334 wlan_hdd_extscan_config_policy)) {
3335 hddLog(LOGE, FL("Invalid ATTR"));
3336 return -EINVAL;
3337 }
3338
3339 pReqMsg = cdf_mem_malloc(sizeof(*pReqMsg));
3340 if (!pReqMsg) {
3341 hddLog(LOGE, FL("cdf_mem_malloc failed"));
3342 return -ENOMEM;
3343 }
3344
3345 /* Parse and fetch request Id */
3346 if (!tb[PARAM_REQUEST_ID]) {
3347 hddLog(LOGE, FL("attr request id failed"));
3348 goto fail;
3349 }
3350
3351 pReqMsg->requestId = nla_get_u32(tb[PARAM_REQUEST_ID]);
3352 pReqMsg->sessionId = pAdapter->sessionId;
3353 hddLog(LOG1, FL("Req Id %d Session Id %d"),
3354 pReqMsg->requestId, pReqMsg->sessionId);
3355
3356 context = &ext_scan_context;
3357 spin_lock(&context->context_lock);
3358 INIT_COMPLETION(context->response_event);
3359 context->request_id = request_id = pReqMsg->requestId;
3360 spin_unlock(&context->context_lock);
3361
3362 status = sme_ext_scan_stop(pHddCtx->hHal, pReqMsg);
3363 if (!CDF_IS_STATUS_SUCCESS(status)) {
3364 hddLog(LOGE,
3365 FL("sme_ext_scan_stop failed(err=%d)"), status);
3366 goto fail;
3367 }
3368
3369 /* request was sent -- wait for the response */
3370 rc = wait_for_completion_timeout(&context->response_event,
3371 msecs_to_jiffies(WLAN_WAIT_TIME_EXTSCAN));
3372
3373 if (!rc) {
3374 hddLog(LOGE, FL("sme_ext_scan_stop timed out"));
3375 retval = -ETIMEDOUT;
3376 } else {
3377 spin_lock(&context->context_lock);
3378 if (context->request_id == request_id)
3379 retval = context->response_status;
3380 else
3381 retval = -EINVAL;
3382 spin_unlock(&context->context_lock);
3383 }
3384
3385 return retval;
3386
3387fail:
3388 cdf_mem_free(pReqMsg);
3389 return -EINVAL;
3390}
3391/*
3392 * done with short names for the global vendor params
3393 * used by wlan_hdd_cfg80211_extscan_stop()
3394 */
3395#undef PARAM_MAX
3396#undef PARAM_REQUEST_ID
3397
3398
3399/**
3400 * wlan_hdd_cfg80211_extscan_stop() - stop extscan
3401 * @wiphy: Pointer to wireless phy.
3402 * @wdev: Pointer to wireless device.
3403 * @data: Pointer to input data.
3404 * @data_len: Length of @data.
3405 *
3406 * Return: 0 on success, negative errno on failure
3407 */
3408int wlan_hdd_cfg80211_extscan_stop(struct wiphy *wiphy,
3409 struct wireless_dev *wdev,
3410 const void *data, int data_len)
3411{
3412 int ret = 0;
3413
3414 cds_ssr_protect(__func__);
3415 ret = __wlan_hdd_cfg80211_extscan_stop(wiphy, wdev, data, data_len);
3416 cds_ssr_unprotect(__func__);
3417
3418 return ret;
3419}
3420
3421
3422/**
3423 * __wlan_hdd_cfg80211_extscan_reset_bssid_hotlist() - reset bssid hotlist
3424 * @wiphy: Pointer to wireless phy
3425 * @wdev: Pointer to wireless device
3426 * @data: Pointer to data
3427 * @data_len: Data length
3428 *
3429 * Return: none
3430 */
3431static int
3432__wlan_hdd_cfg80211_extscan_reset_bssid_hotlist(struct wiphy *wiphy,
3433 struct wireless_dev
3434 *wdev, const void *data,
3435 int data_len)
3436{
3437 tpSirExtScanResetBssidHotlistReqParams pReqMsg = NULL;
3438 struct net_device *dev = wdev->netdev;
3439 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
3440 hdd_context_t *pHddCtx = wiphy_priv(wiphy);
3441 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX +
3442 1];
3443 struct hdd_ext_scan_context *context;
3444 uint32_t request_id;
3445 CDF_STATUS status;
3446 int retval;
3447 unsigned long rc;
3448
3449 ENTER();
3450
3451 if (CDF_FTM_MODE == hdd_get_conparam()) {
3452 hdd_err("Command not allowed in FTM mode");
3453 return -EPERM;
3454 }
3455
3456 retval = wlan_hdd_validate_context(pHddCtx);
3457 if (0 != retval) {
3458 hddLog(LOGE, FL("HDD context is not valid"));
3459 return -EINVAL;
3460 }
3461
3462 if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX,
3463 data, data_len, wlan_hdd_extscan_config_policy)) {
3464 hddLog(LOGE, FL("Invalid ATTR"));
3465 return -EINVAL;
3466 }
3467
3468 pReqMsg = cdf_mem_malloc(sizeof(*pReqMsg));
3469 if (!pReqMsg) {
3470 hddLog(LOGE, FL("cdf_mem_malloc failed"));
3471 return -ENOMEM;
3472 }
3473
3474 /* Parse and fetch request Id */
3475 if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]) {
3476 hddLog(LOGE, FL("attr request id failed"));
3477 goto fail;
3478 }
3479
3480 pReqMsg->requestId =
3481 nla_get_u32(tb
3482 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]);
3483 pReqMsg->sessionId = pAdapter->sessionId;
3484 hddLog(LOG1, FL("Req Id %d Session Id %d"),
3485 pReqMsg->requestId, pReqMsg->sessionId);
3486
3487 context = &ext_scan_context;
3488 spin_lock(&context->context_lock);
3489 INIT_COMPLETION(context->response_event);
3490 context->request_id = request_id = pReqMsg->requestId;
3491 spin_unlock(&context->context_lock);
3492
3493 status = sme_reset_bss_hotlist(pHddCtx->hHal, pReqMsg);
3494 if (!CDF_IS_STATUS_SUCCESS(status)) {
3495 hddLog(LOGE,
3496 FL("sme_reset_bss_hotlist failed(err=%d)"), status);
3497 goto fail;
3498 }
3499
3500 /* request was sent -- wait for the response */
3501 rc = wait_for_completion_timeout
3502 (&context->response_event,
3503 msecs_to_jiffies(WLAN_WAIT_TIME_EXTSCAN));
3504 if (!rc) {
3505 hddLog(LOGE, FL("sme_reset_bss_hotlist timed out"));
3506 retval = -ETIMEDOUT;
3507 } else {
3508 spin_lock(&context->context_lock);
3509 if (context->request_id == request_id)
3510 retval = context->response_status;
3511 else
3512 retval = -EINVAL;
3513 spin_unlock(&context->context_lock);
3514 }
3515
3516 return retval;
3517
3518fail:
3519 cdf_mem_free(pReqMsg);
3520 return -EINVAL;
3521}
3522
3523/**
3524 * wlan_hdd_cfg80211_extscan_reset_bssid_hotlist() - reset bssid hot list
3525 * @wiphy: Pointer to wireless phy
3526 * @wdev: Pointer to wireless device
3527 * @data: Pointer to data
3528 * @data_len: Data length
3529 *
3530 * Return: 0 on success, negative errno on failure
3531 */
3532int wlan_hdd_cfg80211_extscan_reset_bssid_hotlist(struct wiphy *wiphy,
3533 struct wireless_dev *wdev,
3534 const void *data, int data_len)
3535{
3536 int ret = 0;
3537
3538 cds_ssr_protect(__func__);
3539 ret = __wlan_hdd_cfg80211_extscan_reset_bssid_hotlist(wiphy, wdev,
3540 data, data_len);
3541 cds_ssr_unprotect(__func__);
3542
3543 return ret;
3544}
3545
3546/**
3547 * __wlan_hdd_cfg80211_extscan_reset_significant_change() -
3548 * reset significant change
3549 * @wiphy: Pointer to wireless phy
3550 * @wdev: Pointer to wireless device
3551 * @data: Pointer to data
3552 * @data_len: Data length
3553 *
3554 * Return: none
3555 */
3556static int
3557__wlan_hdd_cfg80211_extscan_reset_significant_change(struct wiphy
3558 *wiphy,
3559 struct
3560 wireless_dev
3561 *wdev, const void *data,
3562 int data_len)
3563{
3564 tpSirExtScanResetSignificantChangeReqParams pReqMsg = NULL;
3565 struct net_device *dev = wdev->netdev;
3566 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
3567 hdd_context_t *pHddCtx = wiphy_priv(wiphy);
3568 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX +
3569 1];
3570 struct hdd_ext_scan_context *context;
3571 uint32_t request_id;
3572 CDF_STATUS status;
3573 int retval;
3574 unsigned long rc;
3575
3576 ENTER();
3577
3578 if (CDF_FTM_MODE == hdd_get_conparam()) {
3579 hdd_err("Command not allowed in FTM mode");
3580 return -EPERM;
3581 }
3582
3583 retval = wlan_hdd_validate_context(pHddCtx);
3584 if (0 != retval) {
3585 hddLog(LOGE, FL("HDD context is not valid"));
3586 return -EINVAL;
3587 }
3588
3589 if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX,
3590 data, data_len, wlan_hdd_extscan_config_policy)) {
3591 hddLog(LOGE, FL("Invalid ATTR"));
3592 return -EINVAL;
3593 }
3594
3595 pReqMsg = cdf_mem_malloc(sizeof(*pReqMsg));
3596 if (!pReqMsg) {
3597 hddLog(LOGE, FL("cdf_mem_malloc failed"));
3598 return -ENOMEM;
3599 }
3600
3601 /* Parse and fetch request Id */
3602 if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]) {
3603 hddLog(LOGE, FL("attr request id failed"));
3604 goto fail;
3605 }
3606
3607 pReqMsg->requestId =
3608 nla_get_u32(tb
3609 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]);
3610 pReqMsg->sessionId = pAdapter->sessionId;
3611 hddLog(LOG1, FL("Req Id %d Session Id %d"),
3612 pReqMsg->requestId, pReqMsg->sessionId);
3613
3614 context = &ext_scan_context;
3615 spin_lock(&context->context_lock);
3616 INIT_COMPLETION(context->response_event);
3617 context->request_id = request_id = pReqMsg->requestId;
3618 spin_unlock(&context->context_lock);
3619
3620 status = sme_reset_significant_change(pHddCtx->hHal, pReqMsg);
3621 if (!CDF_IS_STATUS_SUCCESS(status)) {
3622 hddLog(LOGE, FL("sme_reset_significant_change failed(err=%d)"),
3623 status);
3624 cdf_mem_free(pReqMsg);
3625 return -EINVAL;
3626 }
3627
3628 /* request was sent -- wait for the response */
3629 rc = wait_for_completion_timeout(&context->response_event,
3630 msecs_to_jiffies(WLAN_WAIT_TIME_EXTSCAN));
3631
3632 if (!rc) {
3633 hddLog(LOGE, FL("sme_ResetSignificantChange timed out"));
3634 retval = -ETIMEDOUT;
3635 } else {
3636 spin_lock(&context->context_lock);
3637 if (context->request_id == request_id)
3638 retval = context->response_status;
3639 else
3640 retval = -EINVAL;
3641 spin_unlock(&context->context_lock);
3642 }
3643
3644 return retval;
3645
3646fail:
3647 cdf_mem_free(pReqMsg);
3648 return -EINVAL;
3649}
3650
3651/**
3652 * wlan_hdd_cfg80211_extscan_reset_significant_change() - reset significant
3653 * change
3654 * @wiphy: Pointer to wireless phy
3655 * @wdev: Pointer to wireless device
3656 * @data: Pointer to data
3657 * @data_len: Data length
3658 *
3659 * Return: 0 on success, negative errno on failure
3660 */
3661int wlan_hdd_cfg80211_extscan_reset_significant_change(struct wiphy *wiphy,
3662 struct wireless_dev *wdev,
3663 const void *data, int data_len)
3664{
3665 int ret = 0;
3666
3667 cds_ssr_protect(__func__);
3668 ret = __wlan_hdd_cfg80211_extscan_reset_significant_change(wiphy, wdev,
3669 data, data_len);
3670 cds_ssr_unprotect(__func__);
3671
3672 return ret;
3673}
3674
3675
3676/**
3677 * hdd_extscan_epno_fill_network_list() - epno fill network list
3678 * @hddctx: HDD context
3679 * @req_msg: request message
3680 * @tb: vendor attribute table
3681 *
3682 * This function reads the network block NL vendor attributes from %tb and
3683 * fill in the epno request message.
3684 *
3685 * Return: 0 on success, error number otherwise
3686 */
3687static int hdd_extscan_epno_fill_network_list(
3688 hdd_context_t *hddctx,
3689 struct wifi_epno_params *req_msg,
3690 struct nlattr **tb)
3691{
3692 struct nlattr *network[
3693 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX + 1];
3694 struct nlattr *networks;
3695 int rem1, ssid_len;
3696 uint8_t index, *ssid;
3697
3698 index = 0;
3699 nla_for_each_nested(networks,
3700 tb[QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORKS_LIST],
3701 rem1) {
3702 if (nla_parse(network,
3703 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX,
3704 nla_data(networks), nla_len(networks), NULL)) {
3705 hddLog(LOGE, FL("nla_parse failed"));
3706 return -EINVAL;
3707 }
3708
3709 /* Parse and fetch ssid */
3710 if (!network[QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_SSID]) {
3711 hddLog(LOGE, FL("attr network ssid failed"));
3712 return -EINVAL;
3713 }
3714 ssid_len = nla_len(
3715 network[QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_SSID]);
3716
3717 /* Decrement by 1, don't count null character */
3718 ssid_len--;
3719
3720 req_msg->networks[index].ssid.length = ssid_len;
3721 hddLog(LOG1, FL("network ssid length %d"), ssid_len);
3722 ssid = nla_data(network[QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_SSID]);
3723 cdf_mem_copy(req_msg->networks[index].ssid.ssId,
3724 ssid, ssid_len);
3725 hddLog(LOG1, FL("Ssid (%.*s)"),
3726 req_msg->networks[index].ssid.length,
3727 req_msg->networks[index].ssid.ssId);
3728
3729 /* Parse and fetch rssi threshold */
3730 if (!network[QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_RSSI_THRESHOLD]) {
3731 hddLog(LOGE, FL("attr rssi threshold failed"));
3732 return -EINVAL;
3733 }
3734 req_msg->networks[index].rssi_threshold = nla_get_s8(
3735 network[QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_RSSI_THRESHOLD]);
3736 hddLog(LOG1, FL("rssi threshold %d"),
3737 req_msg->networks[index].rssi_threshold);
3738
3739 /* Parse and fetch epno flags */
3740 if (!network[QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_FLAGS]) {
3741 hddLog(LOGE, FL("attr epno flags failed"));
3742 return -EINVAL;
3743 }
3744 req_msg->networks[index].flags = nla_get_u8(
3745 network[QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_FLAGS]);
3746 hddLog(LOG1, FL("flags %u"), req_msg->networks[index].flags);
3747
3748 /* Parse and fetch auth bit */
3749 if (!network[QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_AUTH_BIT]) {
3750 hddLog(LOGE, FL("attr auth bit failed"));
3751 return -EINVAL;
3752 }
3753 req_msg->networks[index].auth_bit_field = nla_get_u8(
3754 network[QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_AUTH_BIT]);
3755 hddLog(LOG1, FL("auth bit %u"),
3756 req_msg->networks[index].auth_bit_field);
3757
3758 index++;
3759 }
3760 return 0;
3761}
3762
3763/**
3764 * __wlan_hdd_cfg80211_set_epno_list() - epno set network list
3765 * @wiphy: wiphy
3766 * @wdev: pointer to wireless dev
3767 * @data: data pointer
3768 * @data_len: data length
3769 *
3770 * This function reads the NL vendor attributes from %tb and
3771 * fill in the epno request message.
3772 *
3773 * Return: 0 on success, error number otherwise
3774 */
3775static int __wlan_hdd_cfg80211_set_epno_list(struct wiphy *wiphy,
3776 struct wireless_dev *wdev,
3777 const void *data,
3778 int data_len)
3779{
3780 struct wifi_epno_params *req_msg = NULL;
3781 struct net_device *dev = wdev->netdev;
3782 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
3783 hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
3784 struct nlattr *tb[
3785 QCA_WLAN_VENDOR_ATTR_PNO_MAX + 1];
3786 CDF_STATUS status;
3787 uint32_t num_networks, len;
3788 int ret_val;
3789
3790 ENTER();
3791
3792 ret_val = wlan_hdd_validate_context(hdd_ctx);
3793 if (ret_val)
3794 return ret_val;
3795
3796 if (CDF_FTM_MODE == hdd_get_conparam()) {
3797 hdd_err("Command not allowed in FTM mode");
3798 return -EPERM;
3799 }
3800
3801 if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_PNO_MAX,
3802 data, data_len,
3803 wlan_hdd_extscan_config_policy)) {
3804 hddLog(LOGE, FL("Invalid ATTR"));
3805 return -EINVAL;
3806 }
3807
3808 /* Parse and fetch number of networks */
3809 if (!tb[QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_NUM_NETWORKS]) {
3810 hddLog(LOGE, FL("attr num networks failed"));
3811 return -EINVAL;
3812 }
3813 num_networks = nla_get_u32(
3814 tb[QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_NUM_NETWORKS]);
3815 hddLog(LOG1, FL("num networks %u"), num_networks);
3816
3817 len = sizeof(*req_msg) +
3818 (num_networks * sizeof(struct wifi_epno_network));
3819 req_msg = cdf_mem_malloc(len);
3820 if (!req_msg) {
3821 hddLog(LOGE, FL("cdf_mem_malloc failed"));
3822 return -ENOMEM;
3823 }
3824 cdf_mem_zero(req_msg, len);
3825 req_msg->num_networks = num_networks;
3826
3827 /* Parse and fetch request Id */
3828 if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]) {
3829 hddLog(LOGE, FL("attr request id failed"));
3830 goto fail;
3831 }
3832 req_msg->request_id = nla_get_u32(
3833 tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]);
3834 hddLog(LOG1, FL("Req Id %u"), req_msg->request_id);
3835
3836 req_msg->session_id = adapter->sessionId;
3837 hddLog(LOG1, FL("Session Id %d"), req_msg->session_id);
3838
3839 if (hdd_extscan_epno_fill_network_list(hdd_ctx, req_msg, tb))
3840 goto fail;
3841
3842 status = sme_set_epno_list(hdd_ctx->hHal, req_msg);
3843 if (!CDF_IS_STATUS_SUCCESS(status)) {
3844 hddLog(LOGE, FL("sme_set_epno_list failed(err=%d)"), status);
3845 goto fail;
3846 }
3847
3848 EXIT();
3849 cdf_mem_free(req_msg);
3850 return 0;
3851
3852fail:
3853 cdf_mem_free(req_msg);
3854 return -EINVAL;
3855}
3856
3857 /**
3858 * wlan_hdd_cfg80211_set_epno_list() - epno set network list
3859 * @wiphy: wiphy
3860 * @wdev: pointer to wireless dev
3861 * @data: data pointer
3862 * @data_len: data length
3863 *
3864 * This function reads the NL vendor attributes from %tb and
3865 * fill in the epno request message.
3866 *
3867 * Return: 0 on success, error number otherwise
3868 */
3869int wlan_hdd_cfg80211_set_epno_list(struct wiphy *wiphy,
3870 struct wireless_dev *wdev,
3871 const void *data,
3872 int data_len)
3873{
3874 int ret;
3875
3876 cds_ssr_protect(__func__);
3877 ret = __wlan_hdd_cfg80211_set_epno_list(wiphy, wdev,
3878 data, data_len);
3879 cds_ssr_unprotect(__func__);
3880
3881 return ret;
3882}
3883
3884/**
3885 * hdd_extscan_passpoint_fill_network_list() - passpoint fill network list
3886 * @hddctx: HDD context
3887 * @req_msg: request message
3888 * @tb: vendor attribute table
3889 *
3890 * This function reads the network block NL vendor attributes from %tb and
3891 * fill in the passpoint request message.
3892 *
3893 * Return: 0 on success, error number otherwise
3894 */
3895static int hdd_extscan_passpoint_fill_network_list(
3896 hdd_context_t *hddctx,
3897 struct wifi_passpoint_req *req_msg,
3898 struct nlattr **tb)
3899{
3900 struct nlattr *network[QCA_WLAN_VENDOR_ATTR_PNO_MAX + 1];
3901 struct nlattr *networks;
3902 int rem1, len;
3903 uint8_t index;
3904
3905 index = 0;
3906 nla_for_each_nested(networks,
3907 tb[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_LIST_PARAM_NETWORK_ARRAY],
3908 rem1) {
3909 if (nla_parse(network,
3910 QCA_WLAN_VENDOR_ATTR_PNO_MAX,
3911 nla_data(networks), nla_len(networks), NULL)) {
3912 hddLog(LOGE, FL("nla_parse failed"));
3913 return -EINVAL;
3914 }
3915
3916 /* Parse and fetch identifier */
3917 if (!network[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ID]) {
3918 hddLog(LOGE, FL("attr passpoint id failed"));
3919 return -EINVAL;
3920 }
3921 req_msg->networks[index].id = nla_get_u32(
3922 network[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ID]);
3923 hddLog(LOG1, FL("Id %u"), req_msg->networks[index].id);
3924
3925 /* Parse and fetch realm */
3926 if (!network[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_REALM]) {
3927 hddLog(LOGE, FL("attr realm failed"));
3928 return -EINVAL;
3929 }
3930 len = nla_len(
3931 network[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_REALM]);
3932 if (len < 0 || len > SIR_PASSPOINT_REALM_LEN) {
3933 hddLog(LOGE, FL("Invalid realm size %d"), len);
3934 return -EINVAL;
3935 }
3936 cdf_mem_copy(req_msg->networks[index].realm,
3937 nla_data(network[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_REALM]),
3938 len);
3939 hddLog(LOG1, FL("realm len %d"), len);
3940 hddLog(LOG1, FL("realm: %s"), req_msg->networks[index].realm);
3941
3942 /* Parse and fetch roaming consortium ids */
3943 if (!network[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ROAM_CNSRTM_ID]) {
3944 hddLog(LOGE, FL("attr roaming consortium ids failed"));
3945 return -EINVAL;
3946 }
3947 nla_memcpy(&req_msg->networks[index].roaming_consortium_ids,
3948 network[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ROAM_CNSRTM_ID],
3949 sizeof(req_msg->networks[0].roaming_consortium_ids));
3950 hddLog(LOG1, FL("roaming consortium ids"));
3951
3952 /* Parse and fetch plmn */
3953 if (!network[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ROAM_PLMN]) {
3954 hddLog(LOGE, FL("attr plmn failed"));
3955 return -EINVAL;
3956 }
3957 nla_memcpy(&req_msg->networks[index].plmn,
3958 network[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ROAM_PLMN],
3959 SIR_PASSPOINT_PLMN_LEN);
3960 hddLog(LOG1, FL("plmn %02x:%02x:%02x)"),
3961 req_msg->networks[index].plmn[0],
3962 req_msg->networks[index].plmn[1],
3963 req_msg->networks[index].plmn[2]);
3964
3965 index++;
3966 }
3967 return 0;
3968}
3969
3970/**
3971 * __wlan_hdd_cfg80211_set_passpoint_list() - set passpoint network list
3972 * @wiphy: wiphy
3973 * @wdev: pointer to wireless dev
3974 * @data: data pointer
3975 * @data_len: data length
3976 *
3977 * This function reads the NL vendor attributes from %tb and
3978 * fill in the passpoint request message.
3979 *
3980 * Return: 0 on success, error number otherwise
3981 */
3982static int __wlan_hdd_cfg80211_set_passpoint_list(struct wiphy *wiphy,
3983 struct wireless_dev *wdev,
3984 const void *data,
3985 int data_len)
3986{
3987 struct wifi_passpoint_req *req_msg = NULL;
3988 struct net_device *dev = wdev->netdev;
3989 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
3990 hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
3991 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_PNO_MAX + 1];
3992 CDF_STATUS status;
3993 uint32_t num_networks = 0;
3994 int ret;
3995
3996 ENTER();
3997
3998 ret = wlan_hdd_validate_context(hdd_ctx);
3999 if (ret)
4000 return ret;
4001
4002 if (CDF_FTM_MODE == hdd_get_conparam()) {
4003 hdd_err("Command not allowed in FTM mode");
4004 return -EPERM;
4005 }
4006
4007 if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_PNO_MAX, data, data_len,
4008 wlan_hdd_extscan_config_policy)) {
4009 hddLog(LOGE, FL("Invalid ATTR"));
4010 return -EINVAL;
4011 }
4012
4013 /* Parse and fetch number of networks */
4014 if (!tb[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_LIST_PARAM_NUM]) {
4015 hddLog(LOGE, FL("attr num networks failed"));
4016 return -EINVAL;
4017 }
4018 num_networks = nla_get_u32(
4019 tb[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_LIST_PARAM_NUM]);
4020 hddLog(LOG1, FL("num networks %u"), num_networks);
4021
4022 req_msg = cdf_mem_malloc(sizeof(*req_msg) +
4023 (num_networks * sizeof(req_msg->networks[0])));
4024 if (!req_msg) {
4025 hddLog(LOGE, FL("cdf_mem_malloc failed"));
4026 return -ENOMEM;
4027 }
4028 req_msg->num_networks = num_networks;
4029
4030 /* Parse and fetch request Id */
4031 if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]) {
4032 hddLog(LOGE, FL("attr request id failed"));
4033 goto fail;
4034 }
4035 req_msg->request_id = nla_get_u32(
4036 tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]);
4037
4038 req_msg->session_id = adapter->sessionId;
4039 hddLog(LOG1, FL("Req Id %u Session Id %d"), req_msg->request_id,
4040 req_msg->session_id);
4041
4042 if (hdd_extscan_passpoint_fill_network_list(hdd_ctx, req_msg, tb))
4043 goto fail;
4044
4045 status = sme_set_passpoint_list(hdd_ctx->hHal, req_msg);
4046 if (!CDF_IS_STATUS_SUCCESS(status)) {
4047 hddLog(LOGE,
4048 FL("sme_set_passpoint_list failed(err=%d)"), status);
4049 goto fail;
4050 }
4051
4052 EXIT();
4053 cdf_mem_free(req_msg);
4054 return 0;
4055
4056fail:
4057 cdf_mem_free(req_msg);
4058 return -EINVAL;
4059}
4060
4061/**
4062 * wlan_hdd_cfg80211_set_passpoint_list() - set passpoint network list
4063 * @wiphy: wiphy
4064 * @wdev: pointer to wireless dev
4065 * @data: data pointer
4066 * @data_len: data length
4067 *
4068 * This function reads the NL vendor attributes from %tb and
4069 * fill in the passpoint request message.
4070 *
4071 * Return: 0 on success, error number otherwise
4072 */
4073int wlan_hdd_cfg80211_set_passpoint_list(struct wiphy *wiphy,
4074 struct wireless_dev *wdev,
4075 const void *data,
4076 int data_len)
4077{
4078 int ret;
4079
4080 cds_ssr_protect(__func__);
4081 ret = __wlan_hdd_cfg80211_set_passpoint_list(wiphy, wdev,
4082 data, data_len);
4083 cds_ssr_unprotect(__func__);
4084
4085 return ret;
4086}
4087
4088/**
4089 * __wlan_hdd_cfg80211_reset_passpoint_list() - reset passpoint network list
4090 * @wiphy: wiphy
4091 * @wdev: pointer to wireless dev
4092 * @data: data pointer
4093 * @data_len: data length
4094 *
4095 * This function resets passpoint networks list
4096 *
4097 * Return: 0 on success, error number otherwise
4098 */
4099static int __wlan_hdd_cfg80211_reset_passpoint_list(struct wiphy *wiphy,
4100 struct wireless_dev *wdev,
4101 const void *data,
4102 int data_len)
4103{
4104 struct wifi_passpoint_req *req_msg = NULL;
4105 struct net_device *dev = wdev->netdev;
4106 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
4107 hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
4108 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_PNO_MAX + 1];
4109 CDF_STATUS status;
4110 int ret;
4111
4112 ENTER();
4113
4114 ret = wlan_hdd_validate_context(hdd_ctx);
4115 if (ret)
4116 return ret;
4117
4118 if (CDF_FTM_MODE == hdd_get_conparam()) {
4119 hdd_err("Command not allowed in FTM mode");
4120 return -EPERM;
4121 }
4122
4123 if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_PNO_MAX, data, data_len,
4124 wlan_hdd_extscan_config_policy)) {
4125 hddLog(LOGE, FL("Invalid ATTR"));
4126 return -EINVAL;
4127 }
4128
4129 req_msg = cdf_mem_malloc(sizeof(*req_msg));
4130 if (!req_msg) {
4131 hddLog(LOGE, FL("cdf_mem_malloc failed"));
4132 return -ENOMEM;
4133 }
4134
4135 /* Parse and fetch request Id */
4136 if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]) {
4137 hddLog(LOGE, FL("attr request id failed"));
4138 goto fail;
4139 }
4140 req_msg->request_id = nla_get_u32(
4141 tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]);
4142
4143 req_msg->session_id = adapter->sessionId;
4144 hddLog(LOG1, FL("Req Id %u Session Id %d"),
4145 req_msg->request_id, req_msg->session_id);
4146
4147 status = sme_reset_passpoint_list(hdd_ctx->hHal, req_msg);
4148 if (!CDF_IS_STATUS_SUCCESS(status)) {
4149 hddLog(LOGE,
4150 FL("sme_reset_passpoint_list failed(err=%d)"), status);
4151 goto fail;
4152 }
4153
4154 EXIT();
4155 cdf_mem_free(req_msg);
4156 return 0;
4157
4158fail:
4159 cdf_mem_free(req_msg);
4160 return -EINVAL;
4161}
4162
4163/**
4164 * wlan_hdd_cfg80211_reset_passpoint_list() - reset passpoint network list
4165 * @wiphy: wiphy
4166 * @wdev: pointer to wireless dev
4167 * @data: data pointer
4168 * @data_len: data length
4169 *
4170 * This function resets passpoint networks list
4171 *
4172 * Return: 0 on success, error number otherwise
4173 */
4174int wlan_hdd_cfg80211_reset_passpoint_list(struct wiphy *wiphy,
4175 struct wireless_dev *wdev,
4176 const void *data,
4177 int data_len)
4178{
4179 int ret;
4180
4181 cds_ssr_protect(__func__);
4182 ret = __wlan_hdd_cfg80211_reset_passpoint_list(wiphy, wdev,
4183 data, data_len);
4184 cds_ssr_unprotect(__func__);
4185
4186 return ret;
4187}
4188
4189/*
4190 * define short names for the global vendor params
4191 * used by __wlan_hdd_cfg80211_extscan_set_ssid_hotlist()
4192 */
4193#define PARAM_MAX \
4194 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX
4195#define PARAM_REQUEST_ID \
4196 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID
4197#define PARAMS_LOST_SSID_SAMPLE_SIZE \
4198 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_HOTLIST_PARAMS_LOST_SSID_SAMPLE_SIZE
4199#define PARAMS_NUM_SSID \
4200 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_HOTLIST_PARAMS_NUM_SSID
4201#define THRESHOLD_PARAM \
4202 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM
4203#define PARAM_SSID \
4204 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM_SSID
4205#define PARAM_BAND \
4206 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM_BAND
4207#define PARAM_RSSI_LOW \
4208 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM_RSSI_LOW
4209#define PARAM_RSSI_HIGH \
4210 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM_RSSI_HIGH
4211
4212/**
4213 * __wlan_hdd_cfg80211_extscan_set_ssid_hotlist() - set ssid hot list
4214 * @wiphy: Pointer to wireless phy
4215 * @wdev: Pointer to wireless device
4216 * @data: Pointer to data
4217 * @data_len: Data length
4218 *
4219 * Return: 0 on success, negative errno on failure
4220 */
4221static int
4222__wlan_hdd_cfg80211_extscan_set_ssid_hotlist(struct wiphy *wiphy,
4223 struct wireless_dev *wdev,
4224 const void *data,
4225 int data_len)
4226{
4227 struct sir_set_ssid_hotlist_request *request;
4228 struct net_device *dev = wdev->netdev;
4229 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
4230 hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
4231 struct nlattr *tb[PARAM_MAX + 1];
4232 struct nlattr *tb2[PARAM_MAX + 1];
4233 struct nlattr *ssids;
4234 struct hdd_ext_scan_context *context;
4235 uint32_t request_id;
4236 char ssid_string[SIR_MAC_MAX_SSID_LENGTH + 1];
4237 int ssid_len, i, rem;
4238 CDF_STATUS status;
4239 int retval;
4240 unsigned long rc;
4241
4242 ENTER();
4243
4244 if (CDF_FTM_MODE == hdd_get_conparam()) {
4245 hdd_err("Command not allowed in FTM mode");
4246 return -EPERM;
4247 }
4248
4249 retval = wlan_hdd_validate_context(hdd_ctx);
4250 if (0 != retval) {
4251 hddLog(LOGE, FL("HDD context is not valid"));
4252 return -EINVAL;
4253 }
4254
4255 if (nla_parse(tb, PARAM_MAX,
4256 data, data_len,
4257 wlan_hdd_extscan_config_policy)) {
4258 hddLog(LOGE, FL("Invalid ATTR"));
4259 return -EINVAL;
4260 }
4261
4262 request = cdf_mem_malloc(sizeof(*request));
4263 if (!request) {
4264 hddLog(LOGE, FL("cdf_mem_malloc failed"));
4265 return -ENOMEM;
4266 }
4267
4268 /* Parse and fetch request Id */
4269 if (!tb[PARAM_REQUEST_ID]) {
4270 hddLog(LOGE, FL("attr request id failed"));
4271 goto fail;
4272 }
4273
4274 request->request_id = nla_get_u32(tb[PARAM_REQUEST_ID]);
4275 hddLog(LOG1, FL("Request Id %d"), request->request_id);
4276
4277 /* Parse and fetch lost SSID sample size */
4278 if (!tb[PARAMS_LOST_SSID_SAMPLE_SIZE]) {
4279 hddLog(LOGE, FL("attr number of Ssid failed"));
4280 goto fail;
4281 }
4282 request->lost_ssid_sample_size =
4283 nla_get_u32(tb[PARAMS_LOST_SSID_SAMPLE_SIZE]);
4284 hddLog(LOG1, FL("Lost SSID Sample Size %d"),
4285 request->lost_ssid_sample_size);
4286
4287 /* Parse and fetch number of hotlist SSID */
4288 if (!tb[PARAMS_NUM_SSID]) {
4289 hddLog(LOGE, FL("attr number of Ssid failed"));
4290 goto fail;
4291 }
4292 request->ssid_count = nla_get_u32(tb[PARAMS_NUM_SSID]);
4293 hddLog(LOG1, FL("Number of SSID %d"), request->ssid_count);
4294
4295 request->session_id = adapter->sessionId;
4296 hddLog(LOG1, FL("Session Id %d"), request->session_id);
4297
4298 i = 0;
4299 nla_for_each_nested(ssids, tb[THRESHOLD_PARAM], rem) {
4300 if (i >= WLAN_EXTSCAN_MAX_HOTLIST_SSIDS) {
4301 hddLog(LOGE,
4302 FL("Too Many SSIDs, %d exceeds %d"),
4303 i, WLAN_EXTSCAN_MAX_HOTLIST_SSIDS);
4304 break;
4305 }
4306 if (nla_parse(tb2, PARAM_MAX,
4307 nla_data(ssids), nla_len(ssids),
4308 wlan_hdd_extscan_config_policy)) {
4309 hddLog(LOGE, FL("nla_parse failed"));
4310 goto fail;
4311 }
4312
4313 /* Parse and fetch SSID */
4314 if (!tb2[PARAM_SSID]) {
4315 hddLog(LOGE, FL("attr ssid failed"));
4316 goto fail;
4317 }
4318 nla_memcpy(ssid_string,
4319 tb2[PARAM_SSID],
4320 sizeof(ssid_string));
4321 hddLog(LOG1, FL("SSID %s"),
4322 ssid_string);
4323 ssid_len = strlen(ssid_string);
4324 memcpy(request->ssids[i].ssid.ssId, ssid_string, ssid_len);
4325 request->ssids[i].ssid.length = ssid_len;
4326
4327 /* Parse and fetch low RSSI */
4328 if (!tb2[PARAM_BAND]) {
4329 hddLog(LOGE, FL("attr band failed"));
4330 goto fail;
4331 }
4332 request->ssids[i].band = nla_get_u8(tb2[PARAM_BAND]);
4333 hddLog(LOG1, FL("band %d"), request->ssids[i].band);
4334
4335 /* Parse and fetch low RSSI */
4336 if (!tb2[PARAM_RSSI_LOW]) {
4337 hddLog(LOGE, FL("attr low RSSI failed"));
4338 goto fail;
4339 }
4340 request->ssids[i].rssi_low = nla_get_s32(tb2[PARAM_RSSI_LOW]);
4341 hddLog(LOG1, FL("RSSI low %d"), request->ssids[i].rssi_low);
4342
4343 /* Parse and fetch high RSSI */
4344 if (!tb2[PARAM_RSSI_HIGH]) {
4345 hddLog(LOGE, FL("attr high RSSI failed"));
4346 goto fail;
4347 }
4348 request->ssids[i].rssi_high = nla_get_u32(tb2[PARAM_RSSI_HIGH]);
4349 hddLog(LOG1, FL("RSSI high %d"), request->ssids[i].rssi_high);
4350 i++;
4351 }
4352
4353 context = &ext_scan_context;
4354 spin_lock(&context->context_lock);
4355 INIT_COMPLETION(context->response_event);
4356 context->request_id = request_id = request->request_id;
4357 spin_unlock(&context->context_lock);
4358
4359 status = sme_set_ssid_hotlist(hdd_ctx->hHal, request);
4360 if (!CDF_IS_STATUS_SUCCESS(status)) {
4361 hddLog(LOGE,
4362 FL("sme_set_ssid_hotlist failed(err=%d)"), status);
4363 goto fail;
4364 }
4365
4366 cdf_mem_free(request);
4367
4368 /* request was sent -- wait for the response */
4369 rc = wait_for_completion_timeout(&context->response_event,
4370 msecs_to_jiffies
4371 (WLAN_WAIT_TIME_EXTSCAN));
4372 if (!rc) {
4373 hddLog(LOGE, FL("sme_set_ssid_hotlist timed out"));
4374 retval = -ETIMEDOUT;
4375 } else {
4376 spin_lock(&context->context_lock);
4377 if (context->request_id == request_id)
4378 retval = context->response_status;
4379 else
4380 retval = -EINVAL;
4381 spin_unlock(&context->context_lock);
4382 }
4383
4384 return retval;
4385
4386fail:
4387 cdf_mem_free(request);
4388 return -EINVAL;
4389}
4390
4391/*
4392 * done with short names for the global vendor params
4393 * used by wlan_hdd_cfg80211_extscan_set_ssid_hotlist()
4394 */
4395#undef PARAM_MAX
4396#undef PARAM_REQUEST_ID
4397#undef PARAMS_NUM_SSID
4398#undef THRESHOLD_PARAM
4399#undef PARAM_SSID
4400#undef PARAM_BAND
4401#undef PARAM_RSSI_LOW
4402#undef PARAM_RSSI_HIGH
4403
4404/**
4405 * wlan_hdd_cfg80211_extscan_set_ssid_hotlist() - set ssid hot list
4406 * @wiphy: Pointer to wireless phy
4407 * @wdev: Pointer to wireless device
4408 * @data: Pointer to data
4409 * @data_len: Data length
4410 *
4411 * Return: 0 on success, negative errno on failure
4412 */
4413int
4414wlan_hdd_cfg80211_extscan_set_ssid_hotlist(struct wiphy *wiphy,
4415 struct wireless_dev *wdev,
4416 const void *data,
4417 int data_len)
4418{
4419 int ret;
4420
4421 cds_ssr_protect(__func__);
4422 ret = __wlan_hdd_cfg80211_extscan_set_ssid_hotlist(wiphy, wdev, data,
4423 data_len);
4424 cds_ssr_unprotect(__func__);
4425
4426 return ret;
4427}
4428
4429/*
4430 * define short names for the global vendor params
4431 * used by __wlan_hdd_cfg80211_extscan_reset_ssid_hotlist()
4432 */
4433#define PARAM_MAX \
4434 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX
4435#define PARAM_REQUEST_ID \
4436 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID
4437
4438/**
4439 * __wlan_hdd_cfg80211_extscan_reset_ssid_hotlist() - reset ssid hot list
4440 * @wiphy: Pointer to wireless phy
4441 * @wdev: Pointer to wireless device
4442 * @data: Pointer to data
4443 * @data_len: Data length
4444 *
4445 * Return: 0 on success, negative errno on failure
4446 */
4447static int
4448__wlan_hdd_cfg80211_extscan_reset_ssid_hotlist(struct wiphy *wiphy,
4449 struct wireless_dev *wdev,
4450 const void *data,
4451 int data_len)
4452{
4453 struct sir_set_ssid_hotlist_request *request;
4454 struct net_device *dev = wdev->netdev;
4455 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
4456 hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
4457 struct nlattr *tb[PARAM_MAX + 1];
4458 struct hdd_ext_scan_context *context;
4459 uint32_t request_id;
4460 CDF_STATUS status;
4461 int retval;
4462 unsigned long rc;
4463
4464 ENTER();
4465
4466 if (CDF_FTM_MODE == hdd_get_conparam()) {
4467 hdd_err("Command not allowed in FTM mode");
4468 return -EPERM;
4469 }
4470
4471 retval = wlan_hdd_validate_context(hdd_ctx);
4472 if (0 != retval) {
4473 hddLog(LOGE, FL("HDD context is not valid"));
4474 return -EINVAL;
4475 }
4476
4477 if (nla_parse(tb, PARAM_MAX,
4478 data, data_len,
4479 wlan_hdd_extscan_config_policy)) {
4480 hddLog(LOGE, FL("Invalid ATTR"));
4481 return -EINVAL;
4482 }
4483
4484 request = cdf_mem_malloc(sizeof(*request));
4485 if (!request) {
4486 hddLog(LOGE, FL("cdf_mem_malloc failed"));
4487 return -ENOMEM;
4488 }
4489
4490 /* Parse and fetch request Id */
4491 if (!tb[PARAM_REQUEST_ID]) {
4492 hddLog(LOGE, FL("attr request id failed"));
4493 goto fail;
4494 }
4495
4496 request->request_id = nla_get_u32(tb[PARAM_REQUEST_ID]);
4497 hddLog(LOG1, FL("Request Id %d"), request->request_id);
4498
4499 request->session_id = adapter->sessionId;
4500 hddLog(LOG1, FL("Session Id %d"), request->session_id);
4501
4502 request->lost_ssid_sample_size = 0;
4503 request->ssid_count = 0;
4504
4505 context = &ext_scan_context;
4506 spin_lock(&context->context_lock);
4507 INIT_COMPLETION(context->response_event);
4508 context->request_id = request_id = request->request_id;
4509 spin_unlock(&context->context_lock);
4510
4511 status = sme_set_ssid_hotlist(hdd_ctx->hHal, request);
4512 if (!CDF_IS_STATUS_SUCCESS(status)) {
4513 hddLog(LOGE,
4514 FL("sme_reset_ssid_hotlist failed(err=%d)"), status);
4515 goto fail;
4516 }
4517
4518 cdf_mem_free(request);
4519
4520 /* request was sent -- wait for the response */
4521 rc = wait_for_completion_timeout(&context->response_event,
4522 msecs_to_jiffies
4523 (WLAN_WAIT_TIME_EXTSCAN));
4524 if (!rc) {
4525 hddLog(LOGE, FL("sme_reset_ssid_hotlist timed out"));
4526 retval = -ETIMEDOUT;
4527 } else {
4528 spin_lock(&context->context_lock);
4529 if (context->request_id == request_id)
4530 retval = context->response_status;
4531 else
4532 retval = -EINVAL;
4533 spin_unlock(&context->context_lock);
4534 }
4535
4536 return retval;
4537
4538fail:
4539 cdf_mem_free(request);
4540 return -EINVAL;
4541}
4542
4543/*
4544 * done with short names for the global vendor params
4545 * used by wlan_hdd_cfg80211_extscan_reset_ssid_hotlist()
4546 */
4547#undef PARAM_MAX
4548#undef PARAM_REQUEST_ID
4549
4550/**
4551 * wlan_hdd_cfg80211_extscan_reset_ssid_hotlist() - reset ssid hot list
4552 * @wiphy: Pointer to wireless phy
4553 * @wdev: Pointer to wireless device
4554 * @data: Pointer to data
4555 * @data_len: Data length
4556 *
4557 * Return: 0 on success, negative errno on failure
4558 */
4559int
4560wlan_hdd_cfg80211_extscan_reset_ssid_hotlist(struct wiphy *wiphy,
4561 struct wireless_dev *wdev,
4562 const void *data,
4563 int data_len)
4564{
4565 int ret;
4566
4567 cds_ssr_protect(__func__);
4568 ret = __wlan_hdd_cfg80211_extscan_reset_ssid_hotlist(wiphy, wdev,
4569 data, data_len);
4570 cds_ssr_unprotect(__func__);
4571
4572 return ret;
4573}
4574
4575/**
4576 * wlan_hdd_init_completion_extwow() - Initialize ext wow variable
4577 * @hdd_ctx: Global HDD context
4578 *
4579 * Return: none
4580 */
4581#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
4582static inline void wlan_hdd_init_completion_extwow(hdd_context_t *pHddCtx)
4583{
4584 init_completion(&pHddCtx->ready_to_extwow);
4585}
4586#else
4587static inline void wlan_hdd_init_completion_extwow(hdd_context_t *pHddCtx)
4588{
4589 return;
4590}
4591#endif
4592
4593/**
4594 * wlan_hdd_cfg80211_extscan_init() - Initialize the ExtScan feature
4595 * @hdd_ctx: Global HDD context
4596 *
4597 * Return: none
4598 */
4599void wlan_hdd_cfg80211_extscan_init(hdd_context_t *hdd_ctx)
4600{
4601 wlan_hdd_init_completion_extwow(hdd_ctx);
4602 init_completion(&ext_scan_context.response_event);
4603 spin_lock_init(&ext_scan_context.context_lock);
4604}
4605
4606#endif /* FEATURE_WLAN_EXTSCAN */