1 /*
2 * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved.
3 * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
4 *
5 * Permission to use, copy, modify, and/or distribute this software for
6 * any purpose with or without fee is hereby granted, provided that the
7 * above copyright notice and this permission notice appear in all
8 * copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
18 */
19
20 /**
21 * DOC: wlan_hdd_ext_scan.c
22 *
23 * WLAN Host Device Driver EXT SCAN feature implementation
24 *
25 */
26
27 #ifdef FEATURE_WLAN_EXTSCAN
28
29 #include "osif_sync.h"
30 #include "wlan_hdd_ext_scan.h"
31 #include "wlan_hdd_regulatory.h"
32 #include "cds_utils.h"
33 #include "cds_sched.h"
34 #include <qca_vendor.h>
35 #include "wlan_extscan_ucfg_api.h"
36 #include "wlan_hdd_scan.h"
37
38 /* amount of time to wait for a synchronous request/response operation */
39 #define WLAN_WAIT_TIME_EXTSCAN 1000
40
41 /**
42 * struct hdd_ext_scan_context - hdd ext scan context
43 * @request_id: userspace-assigned ID associated with the request
44 * @response_event: Ext scan wait event
45 * @response_status: Status returned by FW in response to a request
46 * @ignore_cached_results: Flag to ignore cached results or not
47 * @context_lock: Spinlock to serialize all context accesses
48 * @capability_response: Ext scan capability response data from target
49 * @buckets_scanned: bitmask of buckets scanned in extscan cycle
50 */
51 struct hdd_ext_scan_context {
52 uint32_t request_id;
53 int response_status;
54 bool ignore_cached_results;
55 struct completion response_event;
56 spinlock_t context_lock;
57 struct ext_scan_capabilities_response capability_response;
58 uint32_t buckets_scanned;
59 };
60 static struct hdd_ext_scan_context ext_scan_context;
61
62 const struct nla_policy
63 wlan_hdd_extscan_config_policy[EXTSCAN_PARAM_MAX + 1] = {
64 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID] = {
65 .type = NLA_U32},
66 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_CHANNEL] = {.type = NLA_U32},
67 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_DWELL_TIME] = {
68 .type = NLA_U32},
69 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_PASSIVE] = {.type = NLA_U8},
70 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_CLASS] = {.type = NLA_U8},
71
72 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_INDEX] = {.type = NLA_U8},
73 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_BAND] = {.type = NLA_U8},
74 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_PERIOD] = {.type = NLA_U32},
75 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_REPORT_EVENTS] = {
76 .type = NLA_U8},
77 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_NUM_CHANNEL_SPECS] = {
78 .type = NLA_U32},
79 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_BASE_PERIOD] = {
80 .type = NLA_U32},
81 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_MAX_AP_PER_SCAN] = {
82 .type = NLA_U32},
83 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_REPORT_THRESHOLD_PERCENT] = {
84 .type = NLA_U8},
85 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_REPORT_THRESHOLD_NUM_SCANS] = {
86 .type = NLA_U8 },
87 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_NUM_BUCKETS] = {
88 .type = NLA_U8},
89 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_GET_CACHED_SCAN_RESULTS_CONFIG_PARAM_FLUSH] = {
90 .type = NLA_U8},
91
92 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_GET_CACHED_SCAN_RESULTS_CONFIG_PARAM_MAX] = {
93 .type = NLA_U32},
94 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_BSSID] =
95 VENDOR_NLA_POLICY_MAC_ADDR,
96 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_RSSI_LOW] = {
97 .type = NLA_S32},
98 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_RSSI_HIGH] = {
99 .type = NLA_S32},
100 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_CHANNEL] = {
101 .type = NLA_U32},
102 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_BSSID_HOTLIST_PARAMS_NUM_AP] = {
103 .type = NLA_U32},
104 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_RSSI_SAMPLE_SIZE] = {
105 .type = NLA_U32},
106 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_LOST_AP_SAMPLE_SIZE] = {
107 .type = NLA_U32},
108 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_MIN_BREACHING] = {
109 .type = NLA_U32},
110 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_NUM_AP] = {
111 .type = NLA_U32},
112 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_MAX_PERIOD] = {
113 .type = NLA_U32},
114 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_BASE] = {
115 .type = NLA_U32},
116 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_STEP_COUNT] = {
117 .type = NLA_U32},
118 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM_SSID] = {
119 .type = NLA_BINARY,
120 .len = IEEE80211_MAX_SSID_LEN + 1 },
121 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_HOTLIST_PARAMS_LOST_SSID_SAMPLE_SIZE] = {
122 .type = NLA_U32 },
123 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_HOTLIST_PARAMS_NUM_SSID] = {
124 .type = NLA_U32 },
125 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM_BAND] = {
126 .type = NLA_U8 },
127 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM_RSSI_LOW] = {
128 .type = NLA_S32 },
129 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM_RSSI_HIGH] = {
130 .type = NLA_S32 },
131 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_CONFIGURATION_FLAGS] = {
132 .type = NLA_U32 },
133 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_BSSID_HOTLIST_PARAMS_LOST_AP_SAMPLE_SIZE] = {
134 .type = NLA_U32},
135 };
136
137 const struct nla_policy
138 wlan_hdd_pno_config_policy[QCA_WLAN_VENDOR_ATTR_PNO_MAX + 1] = {
139 [QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_LIST_PARAM_NUM] = {
140 .type = NLA_U32
141 },
142 [QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ID] = {
143 .type = NLA_U32
144 },
145 [QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_NUM_NETWORKS] = {
146 .type = NLA_U32
147 },
148 [QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_SSID] = {
149 .type = NLA_BINARY,
150 .len = IEEE80211_MAX_SSID_LEN + 1
151 },
152 [QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_FLAGS] = {
153 .type = NLA_U8
154 },
155 [QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_AUTH_BIT] = {
156 .type = NLA_U8
157 },
158 [QCA_WLAN_VENDOR_ATTR_EPNO_MIN5GHZ_RSSI] = {
159 .type = NLA_U32
160 },
161 [QCA_WLAN_VENDOR_ATTR_EPNO_MIN24GHZ_RSSI] = {
162 .type = NLA_U32
163 },
164 [QCA_WLAN_VENDOR_ATTR_EPNO_INITIAL_SCORE_MAX] = {
165 .type = NLA_U32
166 },
167 [QCA_WLAN_VENDOR_ATTR_EPNO_CURRENT_CONNECTION_BONUS] = {
168 .type = NLA_U32
169 },
170 [QCA_WLAN_VENDOR_ATTR_EPNO_SAME_NETWORK_BONUS] = {
171 .type = NLA_U32
172 },
173 [QCA_WLAN_VENDOR_ATTR_EPNO_SECURE_BONUS] = {
174 .type = NLA_U32
175 },
176 [QCA_WLAN_VENDOR_ATTR_EPNO_BAND5GHZ_BONUS] = {
177 .type = NLA_U32
178 },
179 [QCA_WLAN_VENDOR_ATTR_PNO_CONFIG_REQUEST_ID] = {
180 .type = NLA_U32
181 },
182 };
183
184 /**
185 * wlan_hdd_cfg80211_extscan_get_capabilities_rsp() - response from target
186 * @hdd_ctx: Pointer to hdd context
187 * @data: Pointer to ext scan capabilities response from fw
188 *
189 * Return: None
190 */
191 static void
wlan_hdd_cfg80211_extscan_get_capabilities_rsp(struct hdd_context * hdd_ctx,struct ext_scan_capabilities_response * data)192 wlan_hdd_cfg80211_extscan_get_capabilities_rsp(struct hdd_context *hdd_ctx,
193 struct ext_scan_capabilities_response *data)
194 {
195 struct hdd_ext_scan_context *context;
196
197 hdd_enter();
198
199 if (wlan_hdd_validate_context(hdd_ctx))
200 return;
201 if (!data) {
202 hdd_err("data is null");
203 return;
204 }
205
206 context = &ext_scan_context;
207
208 spin_lock(&context->context_lock);
209 /* validate response received from target*/
210 if (context->request_id != data->requestId) {
211 spin_unlock(&context->context_lock);
212 hdd_err("Target response id did not match. request_id: %d response_id: %d",
213 context->request_id, data->requestId);
214 return;
215 }
216
217 context->capability_response = *data;
218 complete(&context->response_event);
219 spin_unlock(&context->context_lock);
220 }
221
222 /*
223 * define short names for the global vendor params
224 * used by hdd_extscan_nl_fill_bss()
225 */
226 #define PARAM_TIME_STAMP \
227 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_TIME_STAMP
228 #define PARAM_SSID \
229 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_SSID
230 #define PARAM_BSSID \
231 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_BSSID
232 #define PARAM_CHANNEL \
233 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_CHANNEL
234 #define PARAM_RSSI \
235 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RSSI
236 #define PARAM_RTT \
237 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RTT
238 #define PARAM_RTT_SD \
239 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RTT_SD
240 #define PARAM_BEACON_PERIOD \
241 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_BEACON_PERIOD
242 #define PARAM_CAPABILITY \
243 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_CAPABILITY
244 #define PARAM_IE_LENGTH \
245 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_IE_LENGTH
246 #define PARAM_IE_DATA \
247 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_IE_DATA
248
249 /** hdd_extscan_nl_fill_bss() - extscan nl fill bss
250 * @skb: socket buffer
251 * @ap: bss information
252 * @idx: nesting index
253 *
254 * Return: 0 on success; error number otherwise
255 */
hdd_extscan_nl_fill_bss(struct sk_buff * skb,tSirWifiScanResult * ap,int idx)256 static int hdd_extscan_nl_fill_bss(struct sk_buff *skb, tSirWifiScanResult *ap,
257 int idx)
258 {
259 struct nlattr *nla_ap;
260
261 nla_ap = nla_nest_start(skb, idx);
262 if (!nla_ap)
263 return -EINVAL;
264
265 if (hdd_wlan_nla_put_u64(skb, PARAM_TIME_STAMP, ap->ts) ||
266 nla_put(skb, PARAM_SSID, sizeof(ap->ssid), ap->ssid) ||
267 nla_put(skb, PARAM_BSSID, sizeof(ap->bssid), ap->bssid.bytes) ||
268 nla_put_u32(skb, PARAM_CHANNEL, ap->channel) ||
269 nla_put_s32(skb, PARAM_RSSI, ap->rssi) ||
270 nla_put_u32(skb, PARAM_RTT, ap->rtt) ||
271 nla_put_u32(skb, PARAM_RTT_SD, ap->rtt_sd) ||
272 nla_put_u16(skb, PARAM_BEACON_PERIOD, ap->beaconPeriod) ||
273 nla_put_u16(skb, PARAM_CAPABILITY, ap->capability) ||
274 nla_put_u16(skb, PARAM_IE_LENGTH, ap->ieLength)) {
275 hdd_err("put fail");
276 return -EINVAL;
277 }
278
279 if (ap->ieLength)
280 if (nla_put(skb, PARAM_IE_DATA, ap->ieLength, ap->ieData)) {
281 hdd_err("put fail");
282 return -EINVAL;
283 }
284
285 nla_nest_end(skb, nla_ap);
286
287 return 0;
288 }
289 /*
290 * done with short names for the global vendor params
291 * used by hdd_extscan_nl_fill_bss()
292 */
293 #undef PARAM_TIME_STAMP
294 #undef PARAM_SSID
295 #undef PARAM_BSSID
296 #undef PARAM_CHANNEL
297 #undef PARAM_RSSI
298 #undef PARAM_RTT
299 #undef PARAM_RTT_SD
300 #undef PARAM_BEACON_PERIOD
301 #undef PARAM_CAPABILITY
302 #undef PARAM_IE_LENGTH
303 #undef PARAM_IE_DATA
304
305 /**
306 * wlan_hdd_cfg80211_extscan_cached_results_ind() - get cached results
307 * @hdd_ctx: hdd global context
308 * @data: cached results
309 *
310 * This function reads the cached results %data, populated the NL
311 * attributes and sends the NL event to the upper layer.
312 *
313 * Return: none
314 */
315 static void
wlan_hdd_cfg80211_extscan_cached_results_ind(struct hdd_context * hdd_ctx,struct extscan_cached_scan_results * data)316 wlan_hdd_cfg80211_extscan_cached_results_ind(struct hdd_context *hdd_ctx,
317 struct extscan_cached_scan_results *data)
318 {
319 struct sk_buff *skb = NULL;
320 struct hdd_ext_scan_context *context;
321 struct extscan_cached_scan_result *result;
322 tSirWifiScanResult *ap;
323 uint32_t i, j, nl_buf_len;
324 bool ignore_cached_results = false;
325
326 /* ENTER() intentionally not used in a frequently invoked API */
327
328 if (wlan_hdd_validate_context(hdd_ctx))
329 return;
330 if (!data) {
331 hdd_err("data is null");
332 return;
333 }
334
335 context = &ext_scan_context;
336 spin_lock(&context->context_lock);
337 ignore_cached_results = context->ignore_cached_results;
338 spin_unlock(&context->context_lock);
339
340 if (ignore_cached_results) {
341 hdd_err("Ignore the cached results received after timeout");
342 return;
343 }
344
345 #define EXTSCAN_CACHED_NEST_HDRLEN NLA_HDRLEN
346 #define EXTSCAN_CACHED_NL_FIXED_TLV \
347 ((sizeof(data->request_id) + NLA_HDRLEN) + \
348 (sizeof(data->num_scan_ids) + NLA_HDRLEN) + \
349 (sizeof(data->more_data) + NLA_HDRLEN))
350 #define EXTSCAN_CACHED_NL_SCAN_ID_TLV \
351 ((sizeof(result->scan_id) + NLA_HDRLEN) + \
352 (sizeof(result->flags) + NLA_HDRLEN) + \
353 (sizeof(result->num_results) + NLA_HDRLEN))+ \
354 (sizeof(result->buckets_scanned) + NLA_HDRLEN)
355 #define EXTSCAN_CACHED_NL_SCAN_RESULTS_TLV \
356 ((sizeof(ap->ts) + NLA_HDRLEN) + \
357 (sizeof(ap->ssid) + NLA_HDRLEN) + \
358 (sizeof(ap->bssid) + NLA_HDRLEN) + \
359 (sizeof(ap->channel) + NLA_HDRLEN) + \
360 (sizeof(ap->rssi) + NLA_HDRLEN) + \
361 (sizeof(ap->rtt) + NLA_HDRLEN) + \
362 (sizeof(ap->rtt_sd) + NLA_HDRLEN) + \
363 (sizeof(ap->beaconPeriod) + NLA_HDRLEN) + \
364 (sizeof(ap->capability) + NLA_HDRLEN) + \
365 (sizeof(ap->ieLength) + NLA_HDRLEN))
366 #define EXTSCAN_CACHED_NL_SCAN_RESULTS_IE_DATA_TLV \
367 (ap->ieLength + NLA_HDRLEN)
368
369 nl_buf_len = NLMSG_HDRLEN;
370 nl_buf_len += EXTSCAN_CACHED_NL_FIXED_TLV;
371 if (data->num_scan_ids) {
372 nl_buf_len += sizeof(result->scan_id) + NLA_HDRLEN;
373 nl_buf_len += EXTSCAN_CACHED_NEST_HDRLEN;
374 result = &data->result[0];
375 for (i = 0; i < data->num_scan_ids; i++) {
376 nl_buf_len += EXTSCAN_CACHED_NEST_HDRLEN;
377 nl_buf_len += EXTSCAN_CACHED_NL_SCAN_ID_TLV;
378 nl_buf_len += EXTSCAN_CACHED_NEST_HDRLEN;
379
380 ap = &result->ap[0];
381 for (j = 0; j < result->num_results; j++) {
382 nl_buf_len += EXTSCAN_CACHED_NEST_HDRLEN;
383 nl_buf_len +=
384 EXTSCAN_CACHED_NL_SCAN_RESULTS_TLV;
385 if (ap->ieLength)
386 nl_buf_len +=
387 EXTSCAN_CACHED_NL_SCAN_RESULTS_IE_DATA_TLV;
388 ap++;
389 }
390 result++;
391 }
392 }
393
394 skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy,
395 nl_buf_len);
396 if (!skb) {
397 hdd_err("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed");
398 goto fail;
399 }
400 hdd_debug("Req Id %u Num_scan_ids %u More Data %u",
401 data->request_id, data->num_scan_ids, data->more_data);
402
403 result = &data->result[0];
404 for (i = 0; i < data->num_scan_ids; i++) {
405 hdd_debug("[i=%d] scan_id %u flags %u num_results %u buckets scanned %u",
406 i, result->scan_id, result->flags, result->num_results,
407 result->buckets_scanned);
408
409 ap = &result->ap[0];
410 for (j = 0; j < result->num_results; j++) {
411 /*
412 * Firmware returns timestamp from ext scan start till
413 * BSSID was cached (in micro seconds). Add this with
414 * time gap between system boot up to ext scan start
415 * to derive the time since boot when the
416 * BSSID was cached.
417 */
418 ap->ts += hdd_ctx->ext_scan_start_since_boot;
419 hdd_debug("Timestamp %llu Ssid: " QDF_SSID_FMT " Bssid (" QDF_MAC_ADDR_FMT ") Channel %u Rssi %d RTT %u RTT_SD %u Beacon Period %u Capability 0x%x Ie length %d",
420 ap->ts,
421 QDF_SSID_REF(WLAN_SSID_MAX_LEN, ap->ssid),
422 QDF_MAC_ADDR_REF(ap->bssid.bytes),
423 ap->channel, ap->rssi, ap->rtt, ap->rtt_sd,
424 ap->beaconPeriod, ap->capability,
425 ap->ieLength);
426 ap++;
427 }
428 result++;
429 }
430
431 if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID,
432 data->request_id) ||
433 nla_put_u32(skb,
434 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_NUM_RESULTS_AVAILABLE,
435 data->num_scan_ids) ||
436 nla_put_u8(skb,
437 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_MORE_DATA,
438 data->more_data)) {
439 hdd_err("put fail");
440 goto fail;
441 }
442
443 if (data->num_scan_ids) {
444 struct nlattr *nla_results;
445
446 result = &data->result[0];
447
448 if (nla_put_u32(skb,
449 QCA_WLAN_VENDOR_ATTR_EXTSCAN_CACHED_RESULTS_SCAN_ID,
450 result->scan_id)) {
451 hdd_err("put fail");
452 goto fail;
453 }
454 nla_results = nla_nest_start(skb,
455 QCA_WLAN_VENDOR_ATTR_EXTSCAN_CACHED_RESULTS_LIST);
456 if (!nla_results)
457 goto fail;
458
459 for (i = 0; i < data->num_scan_ids; i++) {
460 struct nlattr *nla_result;
461 struct nlattr *nla_aps;
462
463 nla_result = nla_nest_start(skb, i);
464 if (!nla_result)
465 goto fail;
466
467 if (nla_put_u32(skb,
468 QCA_WLAN_VENDOR_ATTR_EXTSCAN_CACHED_RESULTS_SCAN_ID,
469 result->scan_id) ||
470 nla_put_u32(skb,
471 QCA_WLAN_VENDOR_ATTR_EXTSCAN_CACHED_RESULTS_FLAGS,
472 result->flags) ||
473 nla_put_u32(skb,
474 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_BUCKETS_SCANNED,
475 result->buckets_scanned) ||
476 nla_put_u32(skb,
477 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_NUM_RESULTS_AVAILABLE,
478 result->num_results)) {
479 hdd_err("put fail");
480 goto fail;
481 }
482
483 nla_aps = nla_nest_start(skb,
484 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_LIST);
485 if (!nla_aps)
486 goto fail;
487
488 ap = &result->ap[0];
489 for (j = 0; j < result->num_results; j++) {
490 if (hdd_extscan_nl_fill_bss(skb, ap, j))
491 goto fail;
492
493 ap++;
494 }
495 nla_nest_end(skb, nla_aps);
496 nla_nest_end(skb, nla_result);
497 result++;
498 }
499 nla_nest_end(skb, nla_results);
500 }
501
502 wlan_cfg80211_vendor_cmd_reply(skb);
503
504 if (!data->more_data) {
505 spin_lock(&context->context_lock);
506 context->response_status = 0;
507 complete(&context->response_event);
508 spin_unlock(&context->context_lock);
509 }
510 return;
511
512 fail:
513 wlan_cfg80211_vendor_free_skb(skb);
514 spin_lock(&context->context_lock);
515 context->response_status = -EINVAL;
516 spin_unlock(&context->context_lock);
517 }
518
519 /**
520 * wlan_hdd_cfg80211_extscan_hotlist_match_ind() - hot list match ind
521 * @hdd_ctx: Pointer to hdd context
522 * @data: Pointer to ext scan result event
523 *
524 * This callback execute in atomic context and must not invoke any
525 * blocking calls.
526 *
527 * Return: none
528 */
529 static void
wlan_hdd_cfg80211_extscan_hotlist_match_ind(struct hdd_context * hdd_ctx,struct extscan_hotlist_match * data)530 wlan_hdd_cfg80211_extscan_hotlist_match_ind(struct hdd_context *hdd_ctx,
531 struct extscan_hotlist_match *data)
532 {
533 struct sk_buff *skb = NULL;
534 uint32_t i, index;
535 int flags = cds_get_gfp_flags();
536
537 hdd_enter();
538
539 if (wlan_hdd_validate_context(hdd_ctx))
540 return;
541 if (!data) {
542 hdd_err("data is null");
543 return;
544 }
545
546 if (data->ap_found)
547 index = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_AP_FOUND_INDEX;
548 else
549 index = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_AP_LOST_INDEX;
550
551 skb = wlan_cfg80211_vendor_event_alloc(
552 hdd_ctx->wiphy,
553 NULL,
554 EXTSCAN_EVENT_BUF_SIZE + NLMSG_HDRLEN,
555 index, flags);
556
557 if (!skb) {
558 hdd_err("wlan_cfg80211_vendor_event_alloc failed");
559 return;
560 }
561 hdd_debug("Req Id: %u Num_APs: %u MoreData: %u ap_found: %u",
562 data->requestId, data->numOfAps, data->moreData,
563 data->ap_found);
564
565 for (i = 0; i < data->numOfAps; i++) {
566 data->ap[i].ts = qdf_get_monotonic_boottime();
567 hdd_debug("[i=%d] Timestamp %llu Ssid: " QDF_SSID_FMT " Bssid (" QDF_MAC_ADDR_FMT ") Channel %u Rssi %d RTT %u RTT_SD %u",
568 i, data->ap[i].ts,
569 QDF_SSID_REF(WLAN_SSID_MAX_LEN, data->ap[i].ssid),
570 QDF_MAC_ADDR_REF(data->ap[i].bssid.bytes),
571 data->ap[i].channel, data->ap[i].rssi,
572 data->ap[i].rtt, data->ap[i].rtt_sd);
573 }
574
575 if (nla_put_u32(skb,
576 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID,
577 data->requestId) ||
578 nla_put_u32(skb,
579 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_NUM_RESULTS_AVAILABLE,
580 data->numOfAps)) {
581 hdd_err("put fail");
582 goto fail;
583 }
584
585 if (data->numOfAps) {
586 struct nlattr *aps;
587
588 aps = nla_nest_start(skb,
589 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_LIST);
590 if (!aps)
591 goto fail;
592
593 for (i = 0; i < data->numOfAps; i++) {
594 struct nlattr *ap;
595
596 ap = nla_nest_start(skb, i);
597 if (!ap)
598 goto fail;
599
600 if (hdd_wlan_nla_put_u64(skb,
601 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_TIME_STAMP,
602 data->ap[i].ts) ||
603 nla_put(skb,
604 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_SSID,
605 sizeof(data->ap[i].ssid),
606 data->ap[i].ssid) ||
607 nla_put(skb,
608 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_BSSID,
609 sizeof(data->ap[i].bssid),
610 data->ap[i].bssid.bytes) ||
611 nla_put_u32(skb,
612 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_CHANNEL,
613 data->ap[i].channel) ||
614 nla_put_s32(skb,
615 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RSSI,
616 data->ap[i].rssi) ||
617 nla_put_u32(skb,
618 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RTT,
619 data->ap[i].rtt) ||
620 nla_put_u32(skb,
621 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RTT_SD,
622 data->ap[i].rtt_sd))
623 goto fail;
624
625 nla_nest_end(skb, ap);
626 }
627 nla_nest_end(skb, aps);
628
629 if (nla_put_u8(skb,
630 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_MORE_DATA,
631 data->moreData))
632 goto fail;
633 }
634
635 wlan_cfg80211_vendor_event(skb, flags);
636 hdd_exit();
637 return;
638
639 fail:
640 wlan_cfg80211_vendor_free_skb(skb);
641 }
642
643 /**
644 * wlan_hdd_cfg80211_extscan_signif_wifi_change_results_ind() -
645 * significant wifi change results indication
646 * @hdd_ctx: Pointer to hdd context
647 * @data: Pointer to signif wifi change event
648 *
649 * This callback execute in atomic context and must not invoke any
650 * blocking calls.
651 *
652 * Return: none
653 */
654 static void
wlan_hdd_cfg80211_extscan_signif_wifi_change_results_ind(struct hdd_context * hdd_ctx,tpSirWifiSignificantChangeEvent data)655 wlan_hdd_cfg80211_extscan_signif_wifi_change_results_ind(
656 struct hdd_context *hdd_ctx,
657 tpSirWifiSignificantChangeEvent data)
658 {
659 struct sk_buff *skb = NULL;
660 tSirWifiSignificantChange *ap_info;
661 int32_t *rssi;
662 uint32_t i, j;
663 int flags = cds_get_gfp_flags();
664
665 hdd_enter();
666
667 if (wlan_hdd_validate_context(hdd_ctx))
668 return;
669 if (!data) {
670 hdd_err("data is null");
671 return;
672 }
673
674 skb = wlan_cfg80211_vendor_event_alloc(
675 hdd_ctx->wiphy,
676 NULL,
677 EXTSCAN_EVENT_BUF_SIZE + NLMSG_HDRLEN,
678 QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SIGNIFICANT_CHANGE_INDEX,
679 flags);
680
681 if (!skb) {
682 hdd_err("wlan_cfg80211_vendor_event_alloc failed");
683 return;
684 }
685 hdd_debug("Req Id %u Num results %u More Data %u",
686 data->requestId, data->numResults, data->moreData);
687
688 ap_info = &data->ap[0];
689 for (i = 0; i < data->numResults; i++) {
690 hdd_debug("[i=%d] "
691 "Bssid (" QDF_MAC_ADDR_FMT ") "
692 "Channel %u "
693 "numOfRssi %d",
694 i,
695 QDF_MAC_ADDR_REF(ap_info->bssid.bytes),
696 ap_info->channel, ap_info->numOfRssi);
697 rssi = &(ap_info)->rssi[0];
698 for (j = 0; j < ap_info->numOfRssi; j++)
699 hdd_debug("Rssi %d", *rssi++);
700
701 ap_info = (tSirWifiSignificantChange *)((char *)ap_info +
702 ap_info->numOfRssi * sizeof(*rssi) +
703 sizeof(*ap_info));
704 }
705
706 if (nla_put_u32(skb,
707 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID,
708 data->requestId) ||
709 nla_put_u32(skb,
710 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_NUM_RESULTS_AVAILABLE,
711 data->numResults)) {
712 hdd_err("put fail");
713 goto fail;
714 }
715
716 if (data->numResults) {
717 struct nlattr *aps;
718
719 aps = nla_nest_start(skb,
720 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_LIST);
721 if (!aps)
722 goto fail;
723
724 ap_info = &data->ap[0];
725 for (i = 0; i < data->numResults; i++) {
726 struct nlattr *ap;
727
728 ap = nla_nest_start(skb, i);
729 if (!ap)
730 goto fail;
731
732 if (nla_put(skb,
733 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_BSSID,
734 QDF_MAC_ADDR_SIZE, ap_info->bssid.bytes) ||
735 nla_put_u32(skb,
736 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_CHANNEL,
737 ap_info->channel) ||
738 nla_put_u32(skb,
739 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_NUM_RSSI,
740 ap_info->numOfRssi) ||
741 nla_put(skb,
742 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_RSSI_LIST,
743 sizeof(s32) * ap_info->numOfRssi,
744 &(ap_info)->rssi[0]))
745 goto fail;
746
747 nla_nest_end(skb, ap);
748
749 ap_info = (tSirWifiSignificantChange *)((char *)ap_info
750 + ap_info->numOfRssi * sizeof(*rssi) +
751 sizeof(*ap_info));
752 }
753 nla_nest_end(skb, aps);
754
755 if (nla_put_u8(skb,
756 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_MORE_DATA,
757 data->moreData))
758 goto fail;
759 }
760
761 wlan_cfg80211_vendor_event(skb, flags);
762 return;
763
764 fail:
765 wlan_cfg80211_vendor_free_skb(skb);
766 return;
767
768 }
769
770 /**
771 * wlan_hdd_cfg80211_extscan_full_scan_result_event() - full scan result event
772 * @hdd_ctx: Pointer to hdd context
773 * @data: Pointer to full scan result event
774 *
775 * This callback execute in atomic context and must not invoke any
776 * blocking calls.
777 *
778 * Return: none
779 */
780 static void
wlan_hdd_cfg80211_extscan_full_scan_result_event(struct hdd_context * hdd_ctx,tpSirWifiFullScanResultEvent data)781 wlan_hdd_cfg80211_extscan_full_scan_result_event(struct hdd_context *hdd_ctx,
782 tpSirWifiFullScanResultEvent
783 data)
784 {
785 struct sk_buff *skb;
786 struct hdd_ext_scan_context *context;
787
788 int flags = cds_get_gfp_flags();
789
790 /* ENTER() intentionally not used in a frequently invoked API */
791
792 if (wlan_hdd_validate_context(hdd_ctx))
793 return;
794 if (!data) {
795 hdd_err("data is null");
796 return;
797 }
798
799 if ((sizeof(*data) + data->ap.ieLength) >= EXTSCAN_EVENT_BUF_SIZE) {
800 hdd_err("Frame exceeded NL size limitation, drop it!!");
801 return;
802 }
803 skb = wlan_cfg80211_vendor_event_alloc(
804 hdd_ctx->wiphy,
805 NULL,
806 EXTSCAN_EVENT_BUF_SIZE + NLMSG_HDRLEN,
807 QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_FULL_SCAN_RESULT_INDEX,
808 flags);
809
810 if (!skb) {
811 hdd_err("wlan_cfg80211_vendor_event_alloc failed");
812 return;
813 }
814
815 data->ap.channel = cds_chan_to_freq(data->ap.channel);
816
817 /*
818 * Android does not want the time stamp from the frame.
819 * Instead it wants a monotonic increasing value since boot
820 */
821 data->ap.ts = qdf_get_monotonic_boottime();
822
823 hdd_debug("Req Id %u More Data %u", data->requestId, data->moreData);
824 hdd_debug("AP Info: Timestamp %llu Ssid: " QDF_SSID_FMT " Bssid (" QDF_MAC_ADDR_FMT ") Channel %u Rssi %d RTT %u RTT_SD %u Bcn Period %d Capability 0x%X IE Length %d",
825 data->ap.ts,
826 QDF_SSID_REF(WLAN_SSID_MAX_LEN, data->ap.ssid),
827 QDF_MAC_ADDR_REF(data->ap.bssid.bytes),
828 data->ap.channel, data->ap.rssi, data->ap.rtt,
829 data->ap.rtt_sd, data->ap.beaconPeriod,
830 data->ap.capability, data->ap.ieLength);
831
832 if (nla_put_u32(skb,
833 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID,
834 data->requestId) ||
835 hdd_wlan_nla_put_u64(skb,
836 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_TIME_STAMP,
837 data->ap.ts) ||
838 nla_put(skb,
839 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_SSID,
840 sizeof(data->ap.ssid),
841 data->ap.ssid) ||
842 nla_put(skb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_BSSID,
843 sizeof(data->ap.bssid),
844 data->ap.bssid.bytes) ||
845 nla_put_u32(skb,
846 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_CHANNEL,
847 data->ap.channel) ||
848 nla_put_s32(skb,
849 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RSSI,
850 data->ap.rssi) ||
851 nla_put_u32(skb,
852 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RTT,
853 data->ap.rtt) ||
854 nla_put_u32(skb,
855 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RTT_SD,
856 data->ap.rtt_sd) ||
857 nla_put_u16(skb,
858 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_BEACON_PERIOD,
859 data->ap.beaconPeriod) ||
860 nla_put_u16(skb,
861 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_CAPABILITY,
862 data->ap.capability) ||
863 nla_put_u32(skb,
864 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_IE_LENGTH,
865 data->ap.ieLength) ||
866 nla_put_u8(skb,
867 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_MORE_DATA,
868 data->moreData)) {
869 hdd_err("nla put fail");
870 goto nla_put_failure;
871 }
872
873 if (data->ap.ieLength) {
874 if (nla_put(skb,
875 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_IE_DATA,
876 data->ap.ieLength, data->ap.ieData))
877 goto nla_put_failure;
878 }
879
880 context = &ext_scan_context;
881 spin_lock(&context->context_lock);
882 if (nla_put_u32(skb,
883 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_BUCKETS_SCANNED,
884 context->buckets_scanned)) {
885 spin_unlock(&context->context_lock);
886 hdd_debug("Failed to include buckets_scanned");
887 goto nla_put_failure;
888 }
889 spin_unlock(&context->context_lock);
890
891 wlan_cfg80211_vendor_event(skb, flags);
892 return;
893
894 nla_put_failure:
895 wlan_cfg80211_vendor_free_skb(skb);
896 }
897
898 /**
899 * wlan_hdd_cfg80211_extscan_scan_res_available_event() - scan result event
900 * @hdd_ctx: Pointer to hdd context
901 * @data: Pointer to scan results available indication param
902 *
903 * This callback execute in atomic context and must not invoke any
904 * blocking calls.
905 *
906 * Return: none
907 */
908 static void
wlan_hdd_cfg80211_extscan_scan_res_available_event(struct hdd_context * hdd_ctx,tpSirExtScanResultsAvailableIndParams data)909 wlan_hdd_cfg80211_extscan_scan_res_available_event(
910 struct hdd_context *hdd_ctx,
911 tpSirExtScanResultsAvailableIndParams data)
912 {
913 struct sk_buff *skb;
914 int flags = cds_get_gfp_flags();
915
916 hdd_enter();
917
918 if (wlan_hdd_validate_context(hdd_ctx))
919 return;
920 if (!data) {
921 hdd_err("data is null");
922 return;
923 }
924
925 skb = wlan_cfg80211_vendor_event_alloc(
926 hdd_ctx->wiphy,
927 NULL,
928 EXTSCAN_EVENT_BUF_SIZE + NLMSG_HDRLEN,
929 QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SCAN_RESULTS_AVAILABLE_INDEX,
930 flags);
931
932 if (!skb) {
933 hdd_err("wlan_cfg80211_vendor_event_alloc failed");
934 return;
935 }
936
937 hdd_debug("Req Id %u Num results %u",
938 data->requestId, data->numResultsAvailable);
939 if (nla_put_u32(skb,
940 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID,
941 data->requestId) ||
942 nla_put_u32(skb,
943 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_NUM_RESULTS_AVAILABLE,
944 data->numResultsAvailable)) {
945 hdd_err("nla put fail");
946 goto nla_put_failure;
947 }
948
949 wlan_cfg80211_vendor_event(skb, flags);
950 hdd_exit();
951 return;
952
953 nla_put_failure:
954 wlan_cfg80211_vendor_free_skb(skb);
955 }
956
957 /**
958 * wlan_hdd_cfg80211_extscan_scan_progress_event() - scan progress event
959 * @hdd_ctx: Pointer to hdd context
960 * @data: Pointer to scan event indication param
961 *
962 * This callback execute in atomic context and must not invoke any
963 * blocking calls.
964 *
965 * Return: none
966 */
967 static void
wlan_hdd_cfg80211_extscan_scan_progress_event(struct hdd_context * hdd_ctx,tpSirExtScanOnScanEventIndParams data)968 wlan_hdd_cfg80211_extscan_scan_progress_event(struct hdd_context *hdd_ctx,
969 tpSirExtScanOnScanEventIndParams
970 data)
971 {
972 struct sk_buff *skb;
973 int flags = cds_get_gfp_flags();
974 struct hdd_ext_scan_context *context;
975
976 /* ENTER() intentionally not used in a frequently invoked API */
977
978 if (wlan_hdd_validate_context(hdd_ctx))
979 return;
980 if (!data) {
981 hdd_err("data is null");
982 return;
983 }
984
985 skb = wlan_cfg80211_vendor_event_alloc(
986 hdd_ctx->wiphy,
987 NULL,
988 EXTSCAN_EVENT_BUF_SIZE + NLMSG_HDRLEN,
989 QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SCAN_EVENT_INDEX,
990 flags);
991
992 if (!skb) {
993 hdd_err("wlan_cfg80211_vendor_event_alloc failed");
994 return;
995 }
996
997 hdd_debug("Request Id: %u Scan event type: %u Scan event status: %u buckets scanned: %u",
998 data->requestId, data->scanEventType, data->status,
999 data->buckets_scanned);
1000
1001 context = &ext_scan_context;
1002 spin_lock(&context->context_lock);
1003 if (data->scanEventType == WIFI_EXTSCAN_CYCLE_COMPLETED_EVENT) {
1004 context->buckets_scanned = 0;
1005 data->scanEventType = WIFI_EXTSCAN_RESULTS_AVAILABLE;
1006 spin_unlock(&context->context_lock);
1007 } else if (data->scanEventType == WIFI_EXTSCAN_CYCLE_STARTED_EVENT) {
1008 context->buckets_scanned = data->buckets_scanned;
1009 /* No need to report to user space */
1010 spin_unlock(&context->context_lock);
1011 goto nla_put_failure;
1012 } else {
1013 spin_unlock(&context->context_lock);
1014 }
1015
1016 if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID,
1017 data->requestId) ||
1018 nla_put_u8(skb,
1019 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_EVENT_TYPE,
1020 data->scanEventType)) {
1021 hdd_err("nla put fail");
1022 goto nla_put_failure;
1023 }
1024
1025 wlan_cfg80211_vendor_event(skb, flags);
1026 return;
1027
1028 nla_put_failure:
1029 wlan_cfg80211_vendor_free_skb(skb);
1030 }
1031
1032 /**
1033 * wlan_hdd_cfg80211_extscan_epno_match_found() - pno match found
1034 * @hdd_ctx: HDD context
1035 * @data: matched network data
1036 *
1037 * This function reads the matched network data and fills NL vendor attributes
1038 * and send it to upper layer.
1039 * This callback execute in atomic context and must not invoke any
1040 * blocking calls.
1041 *
1042 * Return: 0 on success, error number otherwise
1043 */
1044 static void
wlan_hdd_cfg80211_extscan_epno_match_found(struct hdd_context * hdd_ctx,struct pno_match_found * data)1045 wlan_hdd_cfg80211_extscan_epno_match_found(struct hdd_context *hdd_ctx,
1046 struct pno_match_found *data)
1047 {
1048 struct sk_buff *skb;
1049 uint32_t len, i;
1050 int flags = cds_get_gfp_flags();
1051 enum qca_nl80211_vendor_subcmds_index index =
1052 QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_NETWORK_FOUND_INDEX;
1053
1054 hdd_enter();
1055
1056 if (wlan_hdd_validate_context(hdd_ctx))
1057 return;
1058 if (!data) {
1059 hdd_err("data is null");
1060 return;
1061 }
1062
1063 /*
1064 * If the number of match found APs including IE data exceeds NL 4K size
1065 * limitation, drop that beacon/probe rsp frame.
1066 */
1067 len = sizeof(*data) +
1068 (data->num_results + sizeof(tSirWifiScanResult));
1069 for (i = 0; i < data->num_results; i++)
1070 len += data->ap[i].ieLength;
1071
1072 if (len >= EXTSCAN_EVENT_BUF_SIZE) {
1073 hdd_err("Frame exceeded NL size limitation, drop it!");
1074 return;
1075 }
1076
1077 skb = wlan_cfg80211_vendor_event_alloc(hdd_ctx->wiphy, NULL,
1078 EXTSCAN_EVENT_BUF_SIZE +
1079 NLMSG_HDRLEN,
1080 index, flags);
1081 if (!skb) {
1082 hdd_err("wlan_cfg80211_vendor_event_alloc failed");
1083 return;
1084 }
1085
1086 hdd_debug("Req Id %u More Data %u num_results %d",
1087 data->request_id, data->more_data, data->num_results);
1088 for (i = 0; i < data->num_results; i++) {
1089 data->ap[i].channel = cds_chan_to_freq(data->ap[i].channel);
1090 hdd_debug("AP Info: Timestamp %llu) Ssid: " QDF_SSID_FMT " Bssid (" QDF_MAC_ADDR_FMT ") Channel %u Rssi %d RTT %u RTT_SD %u Bcn Period %d Capability 0x%X IE Length %d",
1091 data->ap[i].ts,
1092 QDF_SSID_REF(WLAN_SSID_MAX_LEN, data->ap[i].ssid),
1093 QDF_MAC_ADDR_REF(data->ap[i].bssid.bytes),
1094 data->ap[i].channel, data->ap[i].rssi,
1095 data->ap[i].rtt, data->ap[i].rtt_sd,
1096 data->ap[i].beaconPeriod, data->ap[i].capability,
1097 data->ap[i].ieLength);
1098 }
1099
1100 if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID,
1101 data->request_id) ||
1102 nla_put_u32(skb,
1103 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_NUM_RESULTS_AVAILABLE,
1104 data->num_results) ||
1105 nla_put_u8(skb,
1106 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_MORE_DATA,
1107 data->more_data)) {
1108 hdd_err("nla put fail");
1109 goto fail;
1110 }
1111
1112 if (data->num_results) {
1113 struct nlattr *nla_aps;
1114
1115 nla_aps = nla_nest_start(skb,
1116 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_LIST);
1117 if (!nla_aps)
1118 goto fail;
1119
1120 for (i = 0; i < data->num_results; i++) {
1121 if (hdd_extscan_nl_fill_bss(skb, &data->ap[i], i))
1122 goto fail;
1123 }
1124 nla_nest_end(skb, nla_aps);
1125 }
1126
1127 wlan_cfg80211_vendor_event(skb, flags);
1128 return;
1129
1130 fail:
1131 wlan_cfg80211_vendor_free_skb(skb);
1132 }
1133
1134 /**
1135 * wlan_hdd_cfg80211_passpoint_match_found() - passpoint match found
1136 * @ctx: HDD context
1137 * @data: matched network data
1138 *
1139 * This function reads the match network %data and fill in the skb with
1140 * NL attributes and send up the NL event
1141 * This callback execute in atomic context and must not invoke any
1142 * blocking calls.
1143 *
1144 * Return: none
1145 */
1146 static void
wlan_hdd_cfg80211_passpoint_match_found(void * ctx,struct wifi_passpoint_match * data)1147 wlan_hdd_cfg80211_passpoint_match_found(void *ctx,
1148 struct wifi_passpoint_match *data)
1149 {
1150 struct hdd_context *hdd_ctx = ctx;
1151 struct sk_buff *skb = NULL;
1152 uint32_t len, i, num_matches = 1, more_data = 0;
1153 struct nlattr *nla_aps, *nla_bss;
1154 int flags = cds_get_gfp_flags();
1155 enum qca_nl80211_vendor_subcmds_index index =
1156 QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_PASSPOINT_NETWORK_FOUND_INDEX;
1157
1158 hdd_enter();
1159
1160 if (wlan_hdd_validate_context(hdd_ctx))
1161 return;
1162 if (!data) {
1163 hdd_err("data is null");
1164 return;
1165 }
1166
1167 len = sizeof(*data) + data->ap.ieLength + data->anqp_len;
1168 if (len >= EXTSCAN_EVENT_BUF_SIZE) {
1169 hdd_err("Result exceeded NL size limitation, drop it");
1170 return;
1171 }
1172
1173 skb = wlan_cfg80211_vendor_event_alloc(hdd_ctx->wiphy, NULL,
1174 EXTSCAN_EVENT_BUF_SIZE +
1175 NLMSG_HDRLEN,
1176 index, flags);
1177 if (!skb) {
1178 hdd_err("wlan_cfg80211_vendor_event_alloc failed");
1179 return;
1180 }
1181
1182 hdd_debug("Req Id %u Id %u ANQP length %u num_matches %u",
1183 data->request_id, data->id, data->anqp_len, num_matches);
1184 for (i = 0; i < num_matches; i++) {
1185 hdd_debug("AP Info: Timestamp %llu Ssid: " QDF_SSID_FMT " Bssid (" QDF_MAC_ADDR_FMT ") Channel %u Rssi %d RTT %u RTT_SD %u Bcn Period %d Capability 0x%X IE Length %d",
1186 data->ap.ts,
1187 QDF_SSID_REF(WLAN_SSID_MAX_LEN, data->ap.ssid),
1188 QDF_MAC_ADDR_REF(data->ap.bssid.bytes),
1189 data->ap.channel, data->ap.rssi, data->ap.rtt,
1190 data->ap.rtt_sd, data->ap.beaconPeriod,
1191 data->ap.capability, data->ap.ieLength);
1192 }
1193
1194 if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID,
1195 data->request_id) ||
1196 nla_put_u32(skb,
1197 QCA_WLAN_VENDOR_ATTR_EXTSCAN_PNO_RESULTS_PASSPOINT_NETWORK_FOUND_NUM_MATCHES,
1198 num_matches) ||
1199 nla_put_u8(skb,
1200 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_MORE_DATA,
1201 more_data)) {
1202 hdd_err("nla put fail");
1203 goto fail;
1204 }
1205
1206 nla_aps = nla_nest_start(skb,
1207 QCA_WLAN_VENDOR_ATTR_EXTSCAN_PNO_RESULTS_PASSPOINT_MATCH_RESULT_LIST);
1208 if (!nla_aps)
1209 goto fail;
1210
1211 for (i = 0; i < num_matches; i++) {
1212 struct nlattr *nla_ap;
1213
1214 nla_ap = nla_nest_start(skb, i);
1215 if (!nla_ap)
1216 goto fail;
1217
1218 if (nla_put_u32(skb,
1219 QCA_WLAN_VENDOR_ATTR_EXTSCAN_PNO_RESULTS_PASSPOINT_MATCH_ID,
1220 data->id) ||
1221 nla_put_u32(skb,
1222 QCA_WLAN_VENDOR_ATTR_EXTSCAN_PNO_RESULTS_PASSPOINT_MATCH_ANQP_LEN,
1223 data->anqp_len)) {
1224 goto fail;
1225 }
1226
1227 if (data->anqp_len)
1228 if (nla_put(skb,
1229 QCA_WLAN_VENDOR_ATTR_EXTSCAN_PNO_RESULTS_PASSPOINT_MATCH_ANQP,
1230 data->anqp_len, data->anqp))
1231 goto fail;
1232
1233 nla_bss = nla_nest_start(skb,
1234 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_LIST);
1235 if (!nla_bss)
1236 goto fail;
1237
1238 if (hdd_extscan_nl_fill_bss(skb, &data->ap, 0))
1239 goto fail;
1240
1241 nla_nest_end(skb, nla_bss);
1242 nla_nest_end(skb, nla_ap);
1243 }
1244 nla_nest_end(skb, nla_aps);
1245
1246 wlan_cfg80211_vendor_event(skb, flags);
1247 return;
1248
1249 fail:
1250 wlan_cfg80211_vendor_free_skb(skb);
1251 }
1252
1253 /**
1254 * wlan_hdd_cfg80211_extscan_generic_rsp() -
1255 * Handle a generic ExtScan Response message
1256 * @hdd_ctx: HDD context registered with SME
1257 * @response: The ExtScan response from firmware
1258 *
1259 * This function will handle a generic ExtScan response message from
1260 * firmware and will communicate the result to the userspace thread
1261 * that is waiting for the response.
1262 *
1263 * Return: none
1264 */
1265 static void
wlan_hdd_cfg80211_extscan_generic_rsp(struct hdd_context * hdd_ctx,struct sir_extscan_generic_response * response)1266 wlan_hdd_cfg80211_extscan_generic_rsp(struct hdd_context *hdd_ctx,
1267 struct sir_extscan_generic_response *response)
1268 {
1269 struct hdd_ext_scan_context *context;
1270
1271 hdd_enter();
1272
1273 if (wlan_hdd_validate_context(hdd_ctx) || !response) {
1274 hdd_err("HDD context is not valid or response(%pK) is null",
1275 response);
1276 return;
1277 }
1278
1279 hdd_debug("request %u status %u",
1280 response->request_id, response->status);
1281
1282 context = &ext_scan_context;
1283 spin_lock(&context->context_lock);
1284 if (context->request_id == response->request_id) {
1285 context->response_status = response->status ? -EINVAL : 0;
1286 complete(&context->response_event);
1287 }
1288 spin_unlock(&context->context_lock);
1289 }
1290
wlan_hdd_cfg80211_extscan_callback(hdd_handle_t hdd_handle,const uint16_t event_id,void * msg)1291 void wlan_hdd_cfg80211_extscan_callback(hdd_handle_t hdd_handle,
1292 const uint16_t event_id, void *msg)
1293 {
1294 struct hdd_context *hdd_ctx = hdd_handle_to_context(hdd_handle);
1295
1296 /* ENTER() intentionally not used in a frequently invoked API */
1297
1298 if (wlan_hdd_validate_context(hdd_ctx))
1299 return;
1300
1301 hdd_debug("Rcvd Event %d", event_id);
1302
1303 switch (event_id) {
1304 case eSIR_EXTSCAN_CACHED_RESULTS_RSP:
1305 /* There is no need to send this response to upper layer
1306 * Just log the message
1307 */
1308 hdd_debug("Rcvd eSIR_EXTSCAN_CACHED_RESULTS_RSP");
1309 break;
1310
1311 case eSIR_EXTSCAN_GET_CAPABILITIES_IND:
1312 wlan_hdd_cfg80211_extscan_get_capabilities_rsp(hdd_ctx, msg);
1313 break;
1314
1315 case eSIR_EXTSCAN_HOTLIST_MATCH_IND:
1316 wlan_hdd_cfg80211_extscan_hotlist_match_ind(hdd_ctx, msg);
1317 break;
1318
1319 case eSIR_EXTSCAN_SIGNIFICANT_WIFI_CHANGE_RESULTS_IND:
1320 wlan_hdd_cfg80211_extscan_signif_wifi_change_results_ind(hdd_ctx,
1321 msg);
1322 break;
1323
1324 case eSIR_EXTSCAN_CACHED_RESULTS_IND:
1325 wlan_hdd_cfg80211_extscan_cached_results_ind(hdd_ctx, msg);
1326 break;
1327
1328 case eSIR_EXTSCAN_SCAN_RES_AVAILABLE_IND:
1329 wlan_hdd_cfg80211_extscan_scan_res_available_event(hdd_ctx,
1330 msg);
1331 break;
1332
1333 case eSIR_EXTSCAN_FULL_SCAN_RESULT_IND:
1334 wlan_hdd_cfg80211_extscan_full_scan_result_event(hdd_ctx, msg);
1335 break;
1336
1337 case eSIR_EPNO_NETWORK_FOUND_IND:
1338 wlan_hdd_cfg80211_extscan_epno_match_found(hdd_ctx, msg);
1339 break;
1340
1341 case eSIR_EXTSCAN_SCAN_PROGRESS_EVENT_IND:
1342 wlan_hdd_cfg80211_extscan_scan_progress_event(hdd_ctx, msg);
1343 break;
1344
1345 case eSIR_PASSPOINT_NETWORK_FOUND_IND:
1346 wlan_hdd_cfg80211_passpoint_match_found(hdd_ctx, msg);
1347 break;
1348
1349 case eSIR_EXTSCAN_START_RSP:
1350 case eSIR_EXTSCAN_STOP_RSP:
1351 case eSIR_EXTSCAN_SET_BSSID_HOTLIST_RSP:
1352 case eSIR_EXTSCAN_RESET_BSSID_HOTLIST_RSP:
1353 case eSIR_EXTSCAN_SET_SIGNIFICANT_WIFI_CHANGE_RSP:
1354 case eSIR_EXTSCAN_RESET_SIGNIFICANT_WIFI_CHANGE_RSP:
1355 case eSIR_EXTSCAN_SET_SSID_HOTLIST_RSP:
1356 case eSIR_EXTSCAN_RESET_SSID_HOTLIST_RSP:
1357 wlan_hdd_cfg80211_extscan_generic_rsp(hdd_ctx, msg);
1358 break;
1359
1360 default:
1361 hdd_err("Unknown event type: %u", event_id);
1362 break;
1363 }
1364 }
1365
1366 /*
1367 * define short names for the global vendor params
1368 * used by wlan_hdd_send_ext_scan_capability()
1369 */
1370 #define PARAM_REQUEST_ID \
1371 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID
1372 #define PARAM_STATUS \
1373 QCA_WLAN_VENDOR_ATTR_EXTSCAN_STATUS
1374 #define MAX_EXTSCAN_CACHE_SIZE \
1375 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_SCAN_CACHE_SIZE
1376 #define MAX_SCAN_BUCKETS \
1377 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_SCAN_BUCKETS
1378 #define MAX_AP_CACHE_PER_SCAN \
1379 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_AP_CACHE_PER_SCAN
1380 #define MAX_RSSI_SAMPLE_SIZE \
1381 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_RSSI_SAMPLE_SIZE
1382 #define MAX_SCAN_RPT_THRHOLD \
1383 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_SCAN_REPORTING_THRESHOLD
1384 #define MAX_HOTLIST_BSSIDS \
1385 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_HOTLIST_BSSIDS
1386 #define MAX_SIGNIFICANT_WIFI_CHANGE_APS \
1387 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_SIGNIFICANT_WIFI_CHANGE_APS
1388 #define MAX_BSSID_HISTORY_ENTRIES \
1389 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_BSSID_HISTORY_ENTRIES
1390 #define MAX_HOTLIST_SSIDS \
1391 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_HOTLIST_SSIDS
1392 #define MAX_NUM_EPNO_NETS \
1393 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_NUM_EPNO_NETS
1394 #define MAX_NUM_EPNO_NETS_BY_SSID \
1395 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_NUM_EPNO_NETS_BY_SSID
1396 #define MAX_NUM_WHITELISTED_SSID \
1397 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_NUM_WHITELISTED_SSID
1398 #define MAX_NUM_BLACKLISTED_BSSID \
1399 QCA_WLAN_VENDOR_ATTR_EXTSCAN_MAX_NUM_BLACKLISTED_BSSID
1400 /**
1401 * wlan_hdd_send_ext_scan_capability - send ext scan capability to user space
1402 * @hdd_ctx: Pointer to hdd context
1403 *
1404 * Return: 0 for success, non-zero for failure
1405 */
wlan_hdd_send_ext_scan_capability(struct hdd_context * hdd_ctx)1406 static int wlan_hdd_send_ext_scan_capability(struct hdd_context *hdd_ctx)
1407 {
1408 int ret;
1409 struct sk_buff *skb;
1410 struct ext_scan_capabilities_response *data;
1411 uint32_t nl_buf_len;
1412
1413 ret = wlan_hdd_validate_context(hdd_ctx);
1414 if (0 != ret)
1415 return ret;
1416
1417 data = &(ext_scan_context.capability_response);
1418 nl_buf_len = NLMSG_HDRLEN;
1419 nl_buf_len += (sizeof(data->requestId) + NLA_HDRLEN) +
1420 (sizeof(data->status) + NLA_HDRLEN) +
1421 (sizeof(data->max_scan_cache_size) + NLA_HDRLEN) +
1422 (sizeof(data->max_scan_buckets) + NLA_HDRLEN) +
1423 (sizeof(data->max_ap_cache_per_scan) + NLA_HDRLEN) +
1424 (sizeof(data->max_rssi_sample_size) + NLA_HDRLEN) +
1425 (sizeof(data->max_scan_reporting_threshold) + NLA_HDRLEN) +
1426 (sizeof(data->max_hotlist_bssids) + NLA_HDRLEN) +
1427 (sizeof(data->max_significant_wifi_change_aps) + NLA_HDRLEN) +
1428 (sizeof(data->max_bssid_history_entries) + NLA_HDRLEN) +
1429 (sizeof(data->max_hotlist_ssids) + NLA_HDRLEN) +
1430 (sizeof(data->max_number_epno_networks) + NLA_HDRLEN) +
1431 (sizeof(data->max_number_epno_networks_by_ssid) + NLA_HDRLEN) +
1432 (sizeof(data->max_number_of_allow_listed_ssid) + NLA_HDRLEN) +
1433 (sizeof(data->max_number_of_deny_listed_bssid) + NLA_HDRLEN);
1434 skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy,
1435 nl_buf_len);
1436 if (!skb) {
1437 hdd_err("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed");
1438 return -ENOMEM;
1439 }
1440
1441
1442 hdd_debug("Req Id %u", data->requestId);
1443 hdd_debug("Status %u", data->status);
1444 hdd_debug("Scan cache size %u",
1445 data->max_scan_cache_size);
1446 hdd_debug("Scan buckets %u", data->max_scan_buckets);
1447 hdd_debug("Max AP per scan %u",
1448 data->max_ap_cache_per_scan);
1449 hdd_debug("max_rssi_sample_size %u",
1450 data->max_rssi_sample_size);
1451 hdd_debug("max_scan_reporting_threshold %u",
1452 data->max_scan_reporting_threshold);
1453 hdd_debug("max_hotlist_bssids %u",
1454 data->max_hotlist_bssids);
1455 hdd_debug("max_significant_wifi_change_aps %u",
1456 data->max_significant_wifi_change_aps);
1457 hdd_debug("max_bssid_history_entries %u",
1458 data->max_bssid_history_entries);
1459 hdd_debug("max_hotlist_ssids %u", data->max_hotlist_ssids);
1460 hdd_debug("max_number_epno_networks %u",
1461 data->max_number_epno_networks);
1462 hdd_debug("max_number_epno_networks_by_ssid %u",
1463 data->max_number_epno_networks_by_ssid);
1464 hdd_debug("max_number_of_allow_listed_ssid %u",
1465 data->max_number_of_allow_listed_ssid);
1466 hdd_debug("max_number_of_deny_listed_bssid (%u)",
1467 data->max_number_of_deny_listed_bssid);
1468
1469 if (nla_put_u32(skb, PARAM_REQUEST_ID, data->requestId) ||
1470 nla_put_u32(skb, PARAM_STATUS, data->status) ||
1471 nla_put_u32(skb, MAX_EXTSCAN_CACHE_SIZE,
1472 data->max_scan_cache_size) ||
1473 nla_put_u32(skb, MAX_SCAN_BUCKETS, data->max_scan_buckets) ||
1474 nla_put_u32(skb, MAX_AP_CACHE_PER_SCAN,
1475 data->max_ap_cache_per_scan) ||
1476 nla_put_u32(skb, MAX_RSSI_SAMPLE_SIZE,
1477 data->max_rssi_sample_size) ||
1478 nla_put_u32(skb, MAX_SCAN_RPT_THRHOLD,
1479 data->max_scan_reporting_threshold) ||
1480 nla_put_u32(skb, MAX_HOTLIST_BSSIDS, data->max_hotlist_bssids) ||
1481 nla_put_u32(skb, MAX_SIGNIFICANT_WIFI_CHANGE_APS,
1482 data->max_significant_wifi_change_aps) ||
1483 nla_put_u32(skb, MAX_BSSID_HISTORY_ENTRIES,
1484 data->max_bssid_history_entries) ||
1485 nla_put_u32(skb, MAX_HOTLIST_SSIDS, data->max_hotlist_ssids) ||
1486 nla_put_u32(skb, MAX_NUM_EPNO_NETS,
1487 data->max_number_epno_networks) ||
1488 nla_put_u32(skb, MAX_NUM_EPNO_NETS_BY_SSID,
1489 data->max_number_epno_networks_by_ssid) ||
1490 nla_put_u32(skb, MAX_NUM_WHITELISTED_SSID,
1491 data->max_number_of_allow_listed_ssid) ||
1492 nla_put_u32(skb, MAX_NUM_BLACKLISTED_BSSID,
1493 data->max_number_of_deny_listed_bssid)) {
1494 hdd_err("nla put fail");
1495 goto nla_put_failure;
1496 }
1497
1498 wlan_cfg80211_vendor_cmd_reply(skb);
1499 return 0;
1500
1501 nla_put_failure:
1502 wlan_cfg80211_vendor_free_skb(skb);
1503 return -EINVAL;
1504 }
1505 /*
1506 * done with short names for the global vendor params
1507 * used by wlan_hdd_send_ext_scan_capability()
1508 */
1509 #undef PARAM_REQUEST_ID
1510 #undef PARAM_STATUS
1511 #undef MAX_EXTSCAN_CACHE_SIZE
1512 #undef MAX_SCAN_BUCKETS
1513 #undef MAX_AP_CACHE_PER_SCAN
1514 #undef MAX_RSSI_SAMPLE_SIZE
1515 #undef MAX_SCAN_RPT_THRHOLD
1516 #undef MAX_HOTLIST_BSSIDS
1517 #undef MAX_SIGNIFICANT_WIFI_CHANGE_APS
1518 #undef MAX_BSSID_HISTORY_ENTRIES
1519 #undef MAX_HOTLIST_SSIDS
1520 #undef MAX_NUM_EPNO_NETS
1521 #undef MAX_NUM_EPNO_NETS_BY_SSID
1522 #undef MAX_NUM_WHITELISTED_SSID
1523 #undef MAX_NUM_BLACKLISTED_BSSID
1524
1525 /**
1526 * __wlan_hdd_cfg80211_extscan_get_capabilities() - get ext scan capabilities
1527 * @wiphy: Pointer to wireless phy
1528 * @wdev: Pointer to wireless device
1529 * @data: Pointer to data
1530 * @data_len: Data length
1531 *
1532 * Return: none
1533 */
1534 static int
__wlan_hdd_cfg80211_extscan_get_capabilities(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)1535 __wlan_hdd_cfg80211_extscan_get_capabilities(struct wiphy *wiphy,
1536 struct wireless_dev *wdev,
1537 const void *data, int data_len)
1538 {
1539 int id, ret;
1540 unsigned long rc;
1541 struct hdd_ext_scan_context *context;
1542 struct extscan_capabilities_params params;
1543 struct net_device *dev = wdev->netdev;
1544 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
1545 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
1546 struct nlattr *tb[EXTSCAN_PARAM_MAX + 1];
1547 QDF_STATUS status;
1548
1549 hdd_enter_dev(dev);
1550
1551 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
1552 hdd_err("Command not allowed in FTM mode");
1553 return -EPERM;
1554 }
1555
1556 ret = wlan_hdd_validate_context(hdd_ctx);
1557 if (0 != ret)
1558 return -EINVAL;
1559
1560 if (hdd_ctx->driver_status == DRIVER_MODULES_CLOSED) {
1561 hdd_err("Driver Modules are closed");
1562 return -EINVAL;
1563 }
1564
1565 if (!ucfg_extscan_get_enable(hdd_ctx->psoc)) {
1566 hdd_err("extscan not supported");
1567 return -ENOTSUPP;
1568 }
1569 if (wlan_cfg80211_nla_parse(tb, EXTSCAN_PARAM_MAX, data, data_len,
1570 wlan_hdd_extscan_config_policy)) {
1571 hdd_err("Invalid ATTR");
1572 return -EINVAL;
1573 }
1574
1575 /* Parse and fetch request Id */
1576 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID;
1577 if (!tb[id]) {
1578 hdd_err("attr request id failed");
1579 return -EINVAL;
1580 }
1581
1582 params.request_id = nla_get_u32(tb[id]);
1583 params.vdev_id = adapter->deflink->vdev_id;
1584 hdd_debug("Req Id %d Vdev Id %d", params.request_id, params.vdev_id);
1585
1586 context = &ext_scan_context;
1587 spin_lock(&context->context_lock);
1588 context->request_id = params.request_id;
1589 INIT_COMPLETION(context->response_event);
1590 spin_unlock(&context->context_lock);
1591
1592 status = sme_ext_scan_get_capabilities(hdd_ctx->mac_handle, ¶ms);
1593 if (!QDF_IS_STATUS_SUCCESS(status)) {
1594 hdd_err("sme_ext_scan_get_capabilities failed(err=%d)",
1595 status);
1596 return -EINVAL;
1597 }
1598
1599 rc = wait_for_completion_timeout(&context->response_event,
1600 msecs_to_jiffies(WLAN_WAIT_TIME_EXTSCAN));
1601 if (!rc) {
1602 hdd_err("Target response timed out");
1603 return -ETIMEDOUT;
1604 }
1605
1606 ret = wlan_hdd_send_ext_scan_capability(hdd_ctx);
1607 if (ret)
1608 hdd_err("Failed to send ext scan capability to user space");
1609 hdd_exit();
1610 return ret;
1611 }
1612
1613 /**
1614 * wlan_hdd_cfg80211_extscan_get_capabilities() - get ext scan capabilities
1615 * @wiphy: Pointer to wiphy
1616 * @wdev: Pointer to wdev
1617 * @data: Pointer to data
1618 * @data_len: Data length
1619 *
1620 * Return: 0 for success, non-zero for failure
1621 */
wlan_hdd_cfg80211_extscan_get_capabilities(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)1622 int wlan_hdd_cfg80211_extscan_get_capabilities(struct wiphy *wiphy,
1623 struct wireless_dev *wdev,
1624 const void *data, int data_len)
1625 {
1626 int errno;
1627 struct osif_vdev_sync *vdev_sync;
1628
1629 errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync);
1630 if (errno)
1631 return errno;
1632
1633 errno = __wlan_hdd_cfg80211_extscan_get_capabilities(wiphy, wdev,
1634 data, data_len);
1635
1636 osif_vdev_sync_op_stop(vdev_sync);
1637
1638 return errno;
1639 }
1640
1641 /**
1642 * __wlan_hdd_cfg80211_extscan_get_cached_results() - extscan get cached results
1643 * @wiphy: wiphy pointer
1644 * @wdev: pointer to struct wireless_dev
1645 * @data: pointer to incoming NL vendor data
1646 * @data_len: length of @data
1647 *
1648 * This function parses the incoming NL vendor command data attributes and
1649 * invokes the SME Api and blocks on a completion variable.
1650 * Each WMI event with cached scan results data chunk results in
1651 * function call wlan_hdd_cfg80211_extscan_cached_results_ind and each
1652 * data chunk is sent up the layer in wlan_cfg80211_vendor_cmd_alloc_reply_skb.
1653 *
1654 * If timeout happens before receiving all of the data, this function sets
1655 * a context variable @ignore_cached_results to %true, all of the next data
1656 * chunks are checked against this variable and dropped.
1657 *
1658 * Return: 0 on success; error number otherwise.
1659 */
1660 static int
__wlan_hdd_cfg80211_extscan_get_cached_results(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)1661 __wlan_hdd_cfg80211_extscan_get_cached_results(struct wiphy *wiphy,
1662 struct wireless_dev *wdev,
1663 const void *data,
1664 int data_len)
1665 {
1666 struct extscan_cached_result_params params;
1667 struct net_device *dev = wdev->netdev;
1668 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
1669 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
1670 struct nlattr *tb[EXTSCAN_PARAM_MAX + 1];
1671 struct hdd_ext_scan_context *context;
1672 QDF_STATUS status;
1673 int id, retval;
1674 unsigned long rc;
1675
1676 /* ENTER_DEV() intentionally not used in a frequently invoked API */
1677
1678 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
1679 hdd_err("Command not allowed in FTM mode");
1680 return -EPERM;
1681 }
1682
1683 retval = wlan_hdd_validate_context(hdd_ctx);
1684 if (0 != retval)
1685 return -EINVAL;
1686
1687 if (!ucfg_extscan_get_enable(hdd_ctx->psoc)) {
1688 hdd_err("extscan not supported");
1689 return -ENOTSUPP;
1690 }
1691 if (wlan_cfg80211_nla_parse(tb, EXTSCAN_PARAM_MAX, data, data_len,
1692 wlan_hdd_extscan_config_policy)) {
1693 hdd_err("Invalid ATTR");
1694 return -EINVAL;
1695 }
1696
1697 /* Parse and fetch request Id */
1698 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID;
1699 if (!tb[id]) {
1700 hdd_err("attr request id failed");
1701 return -EINVAL;
1702 }
1703
1704 params.request_id = nla_get_u32(tb[id]);
1705 params.vdev_id = adapter->deflink->vdev_id;
1706
1707 /* Parse and fetch flush parameter */
1708 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_GET_CACHED_SCAN_RESULTS_CONFIG_PARAM_FLUSH;
1709 if (!tb[id]) {
1710 hdd_err("attr flush failed");
1711 return -EINVAL;
1712 }
1713 params.flush = nla_get_u8(tb[id]);
1714 hdd_debug("Req Id: %u Vdev Id: %d Flush: %d",
1715 params.request_id, params.vdev_id, params.flush);
1716
1717 context = &ext_scan_context;
1718 spin_lock(&context->context_lock);
1719 context->request_id = params.request_id;
1720 context->ignore_cached_results = false;
1721 INIT_COMPLETION(context->response_event);
1722 spin_unlock(&context->context_lock);
1723
1724 status = sme_get_cached_results(hdd_ctx->mac_handle, ¶ms);
1725 if (!QDF_IS_STATUS_SUCCESS(status)) {
1726 hdd_err("sme_get_cached_results failed(err=%d)", status);
1727 return -EINVAL;
1728 }
1729
1730 rc = wait_for_completion_timeout(&context->response_event,
1731 msecs_to_jiffies(WLAN_WAIT_TIME_EXTSCAN));
1732 if (!rc) {
1733 hdd_err("Target response timed out");
1734 retval = -ETIMEDOUT;
1735 spin_lock(&context->context_lock);
1736 context->ignore_cached_results = true;
1737 spin_unlock(&context->context_lock);
1738 } else {
1739 spin_lock(&context->context_lock);
1740 retval = context->response_status;
1741 spin_unlock(&context->context_lock);
1742 }
1743 return retval;
1744 }
1745
1746 /**
1747 * wlan_hdd_cfg80211_extscan_get_cached_results() - extscan get cached results
1748 * @wiphy: wiphy pointer
1749 * @wdev: pointer to struct wireless_dev
1750 * @data: pointer to incoming NL vendor data
1751 * @data_len: length of @data
1752 *
1753 * This function parses the incoming NL vendor command data attributes and
1754 * invokes the SME Api and blocks on a completion variable.
1755 * Each WMI event with cached scan results data chunk results in
1756 * function call wlan_hdd_cfg80211_extscan_cached_results_ind and each
1757 * data chunk is sent up the layer in wlan_cfg80211_vendor_cmd_alloc_reply_skb.
1758 *
1759 * If timeout happens before receiving all of the data, this function sets
1760 * a context variable @ignore_cached_results to %true, all of the next data
1761 * chunks are checked against this variable and dropped.
1762 *
1763 * Return: 0 on success; error number otherwise.
1764 */
wlan_hdd_cfg80211_extscan_get_cached_results(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)1765 int wlan_hdd_cfg80211_extscan_get_cached_results(struct wiphy *wiphy,
1766 struct wireless_dev *wdev,
1767 const void *data, int data_len)
1768 {
1769 int errno;
1770 struct osif_vdev_sync *vdev_sync;
1771
1772 errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync);
1773 if (errno)
1774 return errno;
1775
1776 errno = __wlan_hdd_cfg80211_extscan_get_cached_results(wiphy, wdev,
1777 data, data_len);
1778
1779 osif_vdev_sync_op_stop(vdev_sync);
1780
1781 return errno;
1782 }
1783
1784 /**
1785 * hdd_parse_ap_rssi_threshold() - parse AP RSSI threshold parameters
1786 * @attr: netlink attribute containing the AP RSSI threshold parameters
1787 * @ap: destination buffer for the parsed parameters
1788 *
1789 * This function parses the BSSID, low RSSI and high RSSI values from
1790 * the @attr netlink attribute, storing the parsed values in @ap.
1791 *
1792 * Return: 0 if @attr is parsed and all required attributes are
1793 * present, otherwise a negative errno.
1794 */
hdd_parse_ap_rssi_threshold(struct nlattr * attr,struct ap_threshold_params * ap)1795 static int hdd_parse_ap_rssi_threshold(struct nlattr *attr,
1796 struct ap_threshold_params *ap)
1797 {
1798 struct nlattr *tb[EXTSCAN_PARAM_MAX + 1];
1799 int id;
1800
1801 if (wlan_cfg80211_nla_parse(tb, EXTSCAN_PARAM_MAX,
1802 nla_data(attr), nla_len(attr),
1803 wlan_hdd_extscan_config_policy)) {
1804 hdd_err("nla_parse failed");
1805 return -EINVAL;
1806 }
1807
1808 /* Parse and fetch MAC address */
1809 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_BSSID;
1810 if (!tb[id]) {
1811 hdd_err("attr mac address failed");
1812 return -EINVAL;
1813 }
1814 nla_memcpy(ap->bssid.bytes, tb[id], QDF_MAC_ADDR_SIZE);
1815 hdd_debug("BSSID: " QDF_MAC_ADDR_FMT,
1816 QDF_MAC_ADDR_REF(ap->bssid.bytes));
1817
1818 /* Parse and fetch low RSSI */
1819 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_RSSI_LOW;
1820 if (!tb[id]) {
1821 hdd_err("attr low RSSI failed");
1822 return -EINVAL;
1823 }
1824 ap->low = nla_get_s32(tb[id]);
1825 hdd_debug("RSSI low %d", ap->low);
1826
1827 /* Parse and fetch high RSSI */
1828 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_RSSI_HIGH;
1829 if (!tb[id]) {
1830 hdd_err("attr high RSSI failed");
1831 return -EINVAL;
1832 }
1833 ap->high = nla_get_s32(tb[id]);
1834 hdd_debug("RSSI High %d", ap->high);
1835
1836 return 0;
1837 }
1838
1839 /**
1840 * __wlan_hdd_cfg80211_extscan_set_bssid_hotlist() - set bssid hot list
1841 * @wiphy: Pointer to wireless phy
1842 * @wdev: Pointer to wireless device
1843 * @data: Pointer to data
1844 * @data_len: Data length
1845 *
1846 * Return: none
1847 */
1848 static int
__wlan_hdd_cfg80211_extscan_set_bssid_hotlist(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)1849 __wlan_hdd_cfg80211_extscan_set_bssid_hotlist(struct wiphy *wiphy,
1850 struct wireless_dev *wdev,
1851 const void *data,
1852 int data_len)
1853 {
1854 struct extscan_bssid_hotlist_set_params *params;
1855 struct net_device *dev = wdev->netdev;
1856 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
1857 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
1858 struct nlattr *tb[EXTSCAN_PARAM_MAX + 1];
1859 struct nlattr *apth;
1860 struct hdd_ext_scan_context *context;
1861 QDF_STATUS status;
1862 uint8_t i;
1863 int id, rem, retval;
1864 unsigned long rc;
1865
1866 hdd_enter_dev(dev);
1867
1868 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
1869 hdd_err("Command not allowed in FTM mode");
1870 return -EPERM;
1871 }
1872
1873 retval = wlan_hdd_validate_context(hdd_ctx);
1874 if (0 != retval)
1875 return -EINVAL;
1876
1877 if (!ucfg_extscan_get_enable(hdd_ctx->psoc)) {
1878 hdd_err("extscan not supported");
1879 return -ENOTSUPP;
1880 }
1881
1882 if (wlan_cfg80211_nla_parse(tb, EXTSCAN_PARAM_MAX,
1883 data, data_len,
1884 wlan_hdd_extscan_config_policy)) {
1885 hdd_err("Invalid ATTR");
1886 return -EINVAL;
1887 }
1888
1889 params = qdf_mem_malloc(sizeof(*params));
1890 if (!params)
1891 return -ENOMEM;
1892
1893 /* assume the worst until proven otherwise */
1894 retval = -EINVAL;
1895
1896 /* Parse and fetch request Id */
1897 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID;
1898 if (!tb[id]) {
1899 hdd_err("attr request id failed");
1900 goto fail;
1901 }
1902
1903 params->request_id = nla_get_u32(tb[id]);
1904 hdd_debug("Req Id %d", params->request_id);
1905
1906 /* Parse and fetch number of APs */
1907 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_BSSID_HOTLIST_PARAMS_NUM_AP;
1908 if (!tb[id]) {
1909 hdd_err("attr number of AP failed");
1910 goto fail;
1911 }
1912
1913 params->num_ap = nla_get_u32(tb[id]);
1914 if (params->num_ap > WMI_WLAN_EXTSCAN_MAX_HOTLIST_APS) {
1915 hdd_err("Number of AP: %u exceeds max: %u",
1916 params->num_ap, WMI_WLAN_EXTSCAN_MAX_HOTLIST_APS);
1917 goto fail;
1918 }
1919 params->vdev_id = adapter->deflink->vdev_id;
1920 hdd_debug("Number of AP %d vdev Id %d",
1921 params->num_ap, params->vdev_id);
1922
1923 /* Parse and fetch lost ap sample size */
1924 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_BSSID_HOTLIST_PARAMS_LOST_AP_SAMPLE_SIZE;
1925 if (!tb[id]) {
1926 hdd_err("attr lost ap sample size failed");
1927 goto fail;
1928 }
1929
1930 params->lost_ap_sample_size = nla_get_u32(tb[id]);
1931 hdd_debug("Lost ap sample size %d",
1932 params->lost_ap_sample_size);
1933
1934 /* Parse the AP Threshold array */
1935 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM;
1936 if (!tb[id]) {
1937 hdd_err("attr ap threshold failed");
1938 goto fail;
1939 }
1940
1941 i = 0;
1942 nla_for_each_nested(apth, tb[id], rem) {
1943 if (i == params->num_ap) {
1944 hdd_warn("Ignoring excess AP");
1945 break;
1946 }
1947
1948 retval = hdd_parse_ap_rssi_threshold(apth, ¶ms->ap[i]);
1949 if (retval)
1950 goto fail;
1951
1952 i++;
1953 }
1954
1955 if (i < params->num_ap) {
1956 hdd_warn("Number of AP %u less than expected %u",
1957 i, params->num_ap);
1958 params->num_ap = i;
1959 }
1960
1961 context = &ext_scan_context;
1962 spin_lock(&context->context_lock);
1963 INIT_COMPLETION(context->response_event);
1964 context->request_id = params->request_id;
1965 spin_unlock(&context->context_lock);
1966
1967 status = sme_set_bss_hotlist(hdd_ctx->mac_handle, params);
1968 if (!QDF_IS_STATUS_SUCCESS(status)) {
1969 hdd_err("sme_set_bss_hotlist failed(err=%d)", status);
1970 retval = qdf_status_to_os_return(status);
1971 goto fail;
1972 }
1973
1974 /* request was sent -- wait for the response */
1975 rc = wait_for_completion_timeout
1976 (&context->response_event,
1977 msecs_to_jiffies(WLAN_WAIT_TIME_EXTSCAN));
1978
1979 if (!rc) {
1980 hdd_err("sme_set_bss_hotlist timed out");
1981 retval = -ETIMEDOUT;
1982 } else {
1983 spin_lock(&context->context_lock);
1984 if (context->request_id == params->request_id)
1985 retval = context->response_status;
1986 else
1987 retval = -EINVAL;
1988 spin_unlock(&context->context_lock);
1989 }
1990 hdd_exit();
1991
1992 fail:
1993 qdf_mem_free(params);
1994 return retval;
1995 }
1996
1997 /**
1998 * wlan_hdd_cfg80211_extscan_set_bssid_hotlist() - set ext scan bssid hotlist
1999 * @wiphy: Pointer to wiphy
2000 * @wdev: Pointer to wdev
2001 * @data: Pointer to data
2002 * @data_len: Data length
2003 *
2004 * Return: 0 for success, non-zero for failure
2005 */
wlan_hdd_cfg80211_extscan_set_bssid_hotlist(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)2006 int wlan_hdd_cfg80211_extscan_set_bssid_hotlist(struct wiphy *wiphy,
2007 struct wireless_dev *wdev,
2008 const void *data, int data_len)
2009 {
2010 int errno;
2011 struct osif_vdev_sync *vdev_sync;
2012
2013 errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync);
2014 if (errno)
2015 return errno;
2016
2017 errno = __wlan_hdd_cfg80211_extscan_set_bssid_hotlist(wiphy, wdev,
2018 data, data_len);
2019
2020 osif_vdev_sync_op_stop(vdev_sync);
2021
2022 return errno;
2023 }
2024
2025
2026 /**
2027 * __wlan_hdd_cfg80211_extscan_set_significant_change() - set significant change
2028 * @wiphy: Pointer to wireless phy
2029 * @wdev: Pointer to wireless device
2030 * @data: Pointer to data
2031 * @data_len: Data length
2032 *
2033 * Return: none
2034 */
2035 static int
__wlan_hdd_cfg80211_extscan_set_significant_change(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)2036 __wlan_hdd_cfg80211_extscan_set_significant_change(struct wiphy *wiphy,
2037 struct wireless_dev *wdev,
2038 const void *data,
2039 int data_len)
2040 {
2041 struct extscan_set_sig_changereq_params *params;
2042 struct net_device *dev = wdev->netdev;
2043 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
2044 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
2045 struct nlattr *tb[EXTSCAN_PARAM_MAX + 1];
2046 struct nlattr *apth;
2047 struct hdd_ext_scan_context *context;
2048 QDF_STATUS status;
2049 uint8_t i;
2050 int id, rem, retval;
2051 unsigned long rc;
2052
2053 hdd_enter_dev(dev);
2054
2055 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
2056 hdd_err("Command not allowed in FTM mode");
2057 return -EPERM;
2058 }
2059
2060 retval = wlan_hdd_validate_context(hdd_ctx);
2061 if (0 != retval)
2062 return -EINVAL;
2063
2064 if (wlan_cfg80211_nla_parse(tb, EXTSCAN_PARAM_MAX,
2065 data, data_len,
2066 wlan_hdd_extscan_config_policy)) {
2067 hdd_err("Invalid ATTR");
2068 return -EINVAL;
2069 }
2070
2071 params = qdf_mem_malloc(sizeof(*params));
2072 if (!params)
2073 return -ENOMEM;
2074
2075 /* assume the worst until proven otherwise */
2076 retval = -EINVAL;
2077
2078 /* Parse and fetch request Id */
2079 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID;
2080 if (!tb[id]) {
2081 hdd_err("attr request id failed");
2082 goto fail;
2083 }
2084
2085 params->request_id = nla_get_u32(tb[id]);
2086 hdd_debug("Req Id %d", params->request_id);
2087
2088 /* Parse and fetch RSSI sample size */
2089 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_RSSI_SAMPLE_SIZE;
2090 if (!tb[id]) {
2091 hdd_err("attr RSSI sample size failed");
2092 goto fail;
2093 }
2094 params->rssi_sample_size = nla_get_u32(tb[id]);
2095 hdd_debug("RSSI sample size %u", params->rssi_sample_size);
2096
2097 /* Parse and fetch lost AP sample size */
2098 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_LOST_AP_SAMPLE_SIZE;
2099 if (!tb[id]) {
2100 hdd_err("attr lost AP sample size failed");
2101 goto fail;
2102 }
2103 params->lostap_sample_size = nla_get_u32(tb[id]);
2104 hdd_debug("Lost AP sample size %u", params->lostap_sample_size);
2105
2106 /* Parse and fetch AP min breaching */
2107 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_MIN_BREACHING;
2108 if (!tb[id]) {
2109 hdd_err("attr AP min breaching");
2110 goto fail;
2111 }
2112 params->min_breaching = nla_get_u32(tb[id]);
2113 hdd_debug("AP min breaching %u", params->min_breaching);
2114
2115 /* Parse and fetch number of APs */
2116 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_NUM_AP;
2117 if (!tb[id]) {
2118 hdd_err("attr number of AP failed");
2119 goto fail;
2120 }
2121 params->num_ap = nla_get_u32(tb[id]);
2122 if (params->num_ap > WLAN_EXTSCAN_MAX_SIGNIFICANT_CHANGE_APS) {
2123 hdd_err("Number of AP %u exceeds max %u",
2124 params->num_ap,
2125 WLAN_EXTSCAN_MAX_SIGNIFICANT_CHANGE_APS);
2126 goto fail;
2127 }
2128
2129 params->vdev_id = adapter->deflink->vdev_id;
2130 hdd_debug("Number of AP %d Vdev Id %d",
2131 params->num_ap, params->vdev_id);
2132
2133 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM;
2134 if (!tb[id]) {
2135 hdd_err("attr ap threshold failed");
2136 goto fail;
2137 }
2138 i = 0;
2139 nla_for_each_nested(apth, tb[id], rem) {
2140
2141 if (i == params->num_ap) {
2142 hdd_warn("Ignoring excess AP");
2143 break;
2144 }
2145
2146 retval = hdd_parse_ap_rssi_threshold(apth, ¶ms->ap[i]);
2147 if (retval)
2148 goto fail;
2149
2150 i++;
2151 }
2152 if (i < params->num_ap) {
2153 hdd_warn("Number of AP %u less than expected %u",
2154 i, params->num_ap);
2155 params->num_ap = i;
2156 }
2157
2158 context = &ext_scan_context;
2159 spin_lock(&context->context_lock);
2160 INIT_COMPLETION(context->response_event);
2161 context->request_id = params->request_id;
2162 spin_unlock(&context->context_lock);
2163
2164 status = sme_set_significant_change(hdd_ctx->mac_handle, params);
2165 if (!QDF_IS_STATUS_SUCCESS(status)) {
2166 hdd_err("sme_set_significant_change failed(err=%d)", status);
2167 retval = qdf_status_to_os_return(status);
2168 goto fail;
2169 }
2170
2171 /* request was sent -- wait for the response */
2172 rc = wait_for_completion_timeout(&context->response_event,
2173 msecs_to_jiffies(WLAN_WAIT_TIME_EXTSCAN));
2174
2175 if (!rc) {
2176 hdd_err("sme_set_significant_change timed out");
2177 retval = -ETIMEDOUT;
2178 } else {
2179 spin_lock(&context->context_lock);
2180 if (context->request_id == params->request_id)
2181 retval = context->response_status;
2182 else
2183 retval = -EINVAL;
2184 spin_unlock(&context->context_lock);
2185 }
2186 hdd_exit();
2187
2188 fail:
2189 qdf_mem_free(params);
2190 return retval;
2191 }
2192
2193 /**
2194 * wlan_hdd_cfg80211_extscan_set_significant_change() - set significant change
2195 * @wiphy: Pointer to wireless phy
2196 * @wdev: Pointer to wireless device
2197 * @data: Pointer to data
2198 * @data_len: Data length
2199 *
2200 * Return: 0 on success, negative errno on failure
2201 */
wlan_hdd_cfg80211_extscan_set_significant_change(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)2202 int wlan_hdd_cfg80211_extscan_set_significant_change(struct wiphy *wiphy,
2203 struct wireless_dev *wdev,
2204 const void *data, int data_len)
2205 {
2206 int errno;
2207 struct osif_vdev_sync *vdev_sync;
2208
2209 errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync);
2210 if (errno)
2211 return errno;
2212
2213 errno = __wlan_hdd_cfg80211_extscan_set_significant_change(wiphy, wdev,
2214 data,
2215 data_len);
2216
2217 osif_vdev_sync_op_stop(vdev_sync);
2218
2219 return errno;
2220 }
2221
2222 /**
2223 * hdd_extscan_update_dwell_time_limits() - update dwell times
2224 * @req_msg: Pointer to request message
2225 * @bkt_idx: Index of current bucket being processed
2226 * @active_min: minimum active dwell time
2227 * @active_max: maximum active dwell time
2228 * @passive_min: minimum passive dwell time
2229 * @passive_max: maximum passive dwell time
2230 *
2231 * Return: none
2232 */
2233 static void
hdd_extscan_update_dwell_time_limits(struct wifi_scan_cmd_req_params * req_msg,uint32_t bkt_idx,uint32_t active_min,uint32_t active_max,uint32_t passive_min,uint32_t passive_max)2234 hdd_extscan_update_dwell_time_limits(struct wifi_scan_cmd_req_params *req_msg,
2235 uint32_t bkt_idx, uint32_t active_min,
2236 uint32_t active_max, uint32_t passive_min,
2237 uint32_t passive_max)
2238 {
2239 /* update per-bucket dwell times */
2240 if (req_msg->buckets[bkt_idx].min_dwell_time_active >
2241 active_min) {
2242 req_msg->buckets[bkt_idx].min_dwell_time_active =
2243 active_min;
2244 }
2245 if (req_msg->buckets[bkt_idx].max_dwell_time_active <
2246 active_max) {
2247 req_msg->buckets[bkt_idx].max_dwell_time_active =
2248 active_max;
2249 }
2250 if (req_msg->buckets[bkt_idx].min_dwell_time_passive >
2251 passive_min) {
2252 req_msg->buckets[bkt_idx].min_dwell_time_passive =
2253 passive_min;
2254 }
2255 if (req_msg->buckets[bkt_idx].max_dwell_time_passive <
2256 passive_max) {
2257 req_msg->buckets[bkt_idx].max_dwell_time_passive =
2258 passive_max;
2259 }
2260 /* update dwell-time across all buckets */
2261 if (req_msg->min_dwell_time_active >
2262 req_msg->buckets[bkt_idx].min_dwell_time_active) {
2263 req_msg->min_dwell_time_active =
2264 req_msg->buckets[bkt_idx].min_dwell_time_active;
2265 }
2266 if (req_msg->max_dwell_time_active <
2267 req_msg->buckets[bkt_idx].max_dwell_time_active) {
2268 req_msg->max_dwell_time_active =
2269 req_msg->buckets[bkt_idx].max_dwell_time_active;
2270 }
2271 if (req_msg->min_dwell_time_passive >
2272 req_msg->buckets[bkt_idx].min_dwell_time_passive) {
2273 req_msg->min_dwell_time_passive =
2274 req_msg->buckets[bkt_idx].min_dwell_time_passive;
2275 }
2276 if (req_msg->max_dwell_time_passive >
2277 req_msg->buckets[bkt_idx].max_dwell_time_passive) {
2278 req_msg->max_dwell_time_passive =
2279 req_msg->buckets[bkt_idx].max_dwell_time_passive;
2280 }
2281 }
2282
2283 /**
2284 * hdd_extscan_channel_max_reached() - channel max reached
2285 * @req: extscan request structure
2286 * @total_channels: total number of channels
2287 *
2288 * Return: true if total channels reached max, false otherwise
2289 */
2290 static bool
hdd_extscan_channel_max_reached(struct wifi_scan_cmd_req_params * req,uint8_t total_channels)2291 hdd_extscan_channel_max_reached(struct wifi_scan_cmd_req_params *req,
2292 uint8_t total_channels)
2293 {
2294 if (total_channels == WMI_WLAN_EXTSCAN_MAX_CHANNELS) {
2295 hdd_warn("max #of channels %d reached, take only first %d bucket(s)",
2296 total_channels, req->num_buckets);
2297 return true;
2298 }
2299 return false;
2300 }
2301
2302 /**
2303 * hdd_extscan_start_fill_bucket_channel_spec() - fill bucket channel spec
2304 * @hdd_ctx: HDD global context
2305 * @req_msg: Pointer to request structure
2306 * @bucket_attr: pointer to bucket attribute
2307 *
2308 * Return: 0 on success; error number otherwise
2309 */
hdd_extscan_start_fill_bucket_channel_spec(struct hdd_context * hdd_ctx,struct wifi_scan_cmd_req_params * req_msg,struct nlattr * bucket_attr)2310 static int hdd_extscan_start_fill_bucket_channel_spec(
2311 struct hdd_context *hdd_ctx,
2312 struct wifi_scan_cmd_req_params *req_msg,
2313 struct nlattr *bucket_attr)
2314 {
2315 mac_handle_t mac_handle;
2316 struct nlattr *bucket_tb[EXTSCAN_PARAM_MAX + 1];
2317 struct nlattr *channel_tb[EXTSCAN_PARAM_MAX + 1];
2318 struct nlattr *buckets;
2319 struct nlattr *channels;
2320 int id, rem1, rem2;
2321 QDF_STATUS status;
2322 uint8_t bkt_index, j, num_channels, total_channels = 0;
2323 uint32_t expected_buckets;
2324 uint32_t expected_channels;
2325 uint32_t chan_list[CFG_VALID_CHANNEL_LIST_LEN] = {0};
2326 uint32_t extscan_active_min_chn_time;
2327 uint32_t min_dwell_time_active_bucket;
2328 uint32_t max_dwell_time_active_bucket;
2329 uint32_t min_dwell_time_passive_bucket;
2330 uint32_t max_dwell_time_passive_bucket;
2331 struct wifi_scan_bucket_params *bucket;
2332 struct wifi_scan_channelspec_params *channel;
2333 struct nlattr *channel_attr;
2334
2335 ucfg_extscan_get_active_min_time(hdd_ctx->psoc,
2336 &extscan_active_min_chn_time);
2337 ucfg_extscan_get_active_max_time(hdd_ctx->psoc,
2338 &max_dwell_time_active_bucket);
2339 ucfg_extscan_get_passive_max_time(hdd_ctx->psoc,
2340 &max_dwell_time_passive_bucket);
2341
2342 min_dwell_time_active_bucket = max_dwell_time_active_bucket;
2343 min_dwell_time_passive_bucket = max_dwell_time_passive_bucket;
2344
2345 req_msg->min_dwell_time_active =
2346 req_msg->max_dwell_time_active = max_dwell_time_active_bucket;
2347
2348 req_msg->min_dwell_time_passive =
2349 req_msg->max_dwell_time_passive = max_dwell_time_passive_bucket;
2350
2351 expected_buckets = req_msg->num_buckets;
2352 req_msg->num_buckets = 0;
2353 bkt_index = 0;
2354
2355 mac_handle = hdd_ctx->mac_handle;
2356 nla_for_each_nested(buckets, bucket_attr, rem1) {
2357
2358 if (bkt_index >= expected_buckets) {
2359 hdd_warn("ignoring excess buckets");
2360 break;
2361 }
2362
2363 if (wlan_cfg80211_nla_parse(bucket_tb, EXTSCAN_PARAM_MAX,
2364 nla_data(buckets), nla_len(buckets),
2365 wlan_hdd_extscan_config_policy)) {
2366 hdd_err("nla_parse failed");
2367 return -EINVAL;
2368 }
2369
2370 bucket = &req_msg->buckets[bkt_index];
2371
2372 /* Parse and fetch bucket spec */
2373 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_INDEX;
2374 if (!bucket_tb[id]) {
2375 hdd_err("attr bucket index failed");
2376 return -EINVAL;
2377 }
2378 bucket->bucket = nla_get_u8(bucket_tb[id]);
2379
2380 /* Parse and fetch wifi band */
2381 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_BAND;
2382 if (!bucket_tb[id]) {
2383 hdd_err("attr wifi band failed");
2384 return -EINVAL;
2385 }
2386 bucket->band = nla_get_u8(bucket_tb[id]);
2387
2388 /* Parse and fetch period */
2389 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_PERIOD;
2390 if (!bucket_tb[id]) {
2391 hdd_err("attr period failed");
2392 return -EINVAL;
2393 }
2394 bucket->period = nla_get_u32(bucket_tb[id]);
2395
2396 /* Parse and fetch report events */
2397 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_REPORT_EVENTS;
2398 if (!bucket_tb[id]) {
2399 hdd_err("attr report events failed");
2400 return -EINVAL;
2401 }
2402 bucket->report_events = nla_get_u8(bucket_tb[id]);
2403
2404 /* Parse and fetch max period */
2405 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_MAX_PERIOD;
2406 if (!bucket_tb[id]) {
2407 hdd_err("attr max period failed");
2408 return -EINVAL;
2409 }
2410 bucket->max_period = nla_get_u32(bucket_tb[id]);
2411
2412 /* Parse and fetch base */
2413 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_BASE;
2414 if (!bucket_tb[id]) {
2415 hdd_err("attr base failed");
2416 return -EINVAL;
2417 }
2418 bucket->exponent = nla_get_u32(bucket_tb[id]);
2419
2420 /* Parse and fetch step count */
2421 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_STEP_COUNT;
2422 if (!bucket_tb[id]) {
2423 hdd_err("attr step count failed");
2424 return -EINVAL;
2425 }
2426 bucket->step_count = nla_get_u32(bucket_tb[id]);
2427
2428 hdd_debug("Bucket spec Index: %d Wifi band: %d period: %d report events: %d max period: %u base: %u Step count: %u",
2429 bucket->bucket,
2430 bucket->band,
2431 bucket->period,
2432 bucket->report_events,
2433 bucket->max_period,
2434 bucket->exponent,
2435 bucket->step_count);
2436
2437 /* start with known good values for bucket dwell times */
2438 bucket->min_dwell_time_active = max_dwell_time_active_bucket;
2439 bucket->max_dwell_time_active = max_dwell_time_active_bucket;
2440 bucket->min_dwell_time_passive = max_dwell_time_passive_bucket;
2441 bucket->max_dwell_time_passive = max_dwell_time_passive_bucket;
2442
2443 /* Framework shall pass the channel list if the input
2444 * WiFi band is WMI_WIFI_BAND_UNSPECIFIED. If the
2445 * input WiFi band is specified (any value other than
2446 * WMI_WIFI_BAND_UNSPECIFIED) then driver populates
2447 * the channel list.
2448 */
2449 if (bucket->band != WMI_WIFI_BAND_UNSPECIFIED) {
2450 if (hdd_extscan_channel_max_reached(req_msg,
2451 total_channels))
2452 return 0;
2453
2454 num_channels = 0;
2455 hdd_debug("WiFi band is specified, driver to fill channel list");
2456 status = sme_get_valid_channels_by_band(mac_handle,
2457 bucket->band,
2458 chan_list,
2459 &num_channels);
2460 if (!QDF_IS_STATUS_SUCCESS(status)) {
2461 hdd_err("sme_get_valid_channels_by_band failed (err=%d)",
2462 status);
2463 return -EINVAL;
2464 }
2465 hdd_debug("before trimming, num_channels: %d",
2466 num_channels);
2467
2468 bucket->num_channels =
2469 QDF_MIN(num_channels,
2470 (WMI_WLAN_EXTSCAN_MAX_CHANNELS -
2471 total_channels));
2472 hdd_debug("Adj Num channels/bucket: %d total_channels: %d",
2473 bucket->num_channels, total_channels);
2474 total_channels += bucket->num_channels;
2475
2476 for (j = 0; j < bucket->num_channels; j++) {
2477 channel = &bucket->channels[j];
2478
2479 channel->channel = chan_list[j];
2480 channel->channel_class = 0;
2481 if ((wlan_reg_get_channel_state_for_pwrmode(
2482 hdd_ctx->pdev, chan_list[j],
2483 REG_CURRENT_PWR_MODE)) !=
2484 CHANNEL_STATE_ENABLE) {
2485 channel->passive = 1;
2486 channel->dwell_time_ms =
2487 max_dwell_time_passive_bucket;
2488 /* reconfigure per-bucket dwell time */
2489 if (min_dwell_time_passive_bucket >
2490 channel->dwell_time_ms) {
2491 min_dwell_time_passive_bucket =
2492 channel->dwell_time_ms;
2493 }
2494 if (max_dwell_time_passive_bucket <
2495 channel->dwell_time_ms) {
2496 max_dwell_time_passive_bucket =
2497 channel->dwell_time_ms;
2498 }
2499
2500 } else {
2501 channel->passive = 0;
2502 channel->dwell_time_ms =
2503 max_dwell_time_active_bucket;
2504 /* reconfigure per-bucket dwell times */
2505 if (min_dwell_time_active_bucket >
2506 channel->dwell_time_ms) {
2507 min_dwell_time_active_bucket =
2508 channel->dwell_time_ms;
2509 }
2510 if (max_dwell_time_active_bucket <
2511 channel->dwell_time_ms) {
2512 max_dwell_time_active_bucket =
2513 channel->dwell_time_ms;
2514 }
2515
2516 }
2517
2518 hdd_debug("Channel: %u Passive: %u Dwell time: %u ms Class: %u",
2519 channel->channel,
2520 channel->passive,
2521 channel->dwell_time_ms,
2522 channel->channel_class);
2523 }
2524
2525 hdd_extscan_update_dwell_time_limits(
2526 req_msg, bkt_index,
2527 min_dwell_time_active_bucket,
2528 max_dwell_time_active_bucket,
2529 min_dwell_time_passive_bucket,
2530 max_dwell_time_passive_bucket);
2531
2532 hdd_debug("bkt_index:%d actv_min:%d actv_max:%d pass_min:%d pass_max:%d",
2533 bkt_index,
2534 bucket->min_dwell_time_active,
2535 bucket->max_dwell_time_active,
2536 bucket->min_dwell_time_passive,
2537 bucket->max_dwell_time_passive);
2538
2539 bkt_index++;
2540 req_msg->num_buckets++;
2541 continue;
2542 }
2543
2544 /* Parse and fetch number of channels */
2545 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_NUM_CHANNEL_SPECS;
2546 if (!bucket_tb[id]) {
2547 hdd_err("attr num channels failed");
2548 return -EINVAL;
2549 }
2550 bucket->num_channels = nla_get_u32(bucket_tb[id]);
2551 hdd_debug("before trimming: num channels %d",
2552 bucket->num_channels);
2553
2554 bucket->num_channels =
2555 QDF_MIN(bucket->num_channels,
2556 (WMI_WLAN_EXTSCAN_MAX_CHANNELS -
2557 total_channels));
2558 hdd_debug("Num channels/bucket: %d total_channels: %d",
2559 bucket->num_channels, total_channels);
2560
2561 if (hdd_extscan_channel_max_reached(req_msg, total_channels))
2562 return 0;
2563
2564 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC;
2565 channel_attr = bucket_tb[id];
2566 if (!channel_attr) {
2567 hdd_err("attr channel spec failed");
2568 return -EINVAL;
2569 }
2570
2571 expected_channels = bucket->num_channels;
2572 bucket->num_channels = 0;
2573
2574 nla_for_each_nested(channels, channel_attr, rem2) {
2575 if ((bucket->num_channels >= expected_channels) ||
2576 hdd_extscan_channel_max_reached(req_msg,
2577 total_channels))
2578 break;
2579
2580 if (wlan_cfg80211_nla_parse(channel_tb,
2581 EXTSCAN_PARAM_MAX,
2582 nla_data(channels),
2583 nla_len(channels),
2584 wlan_hdd_extscan_config_policy)) {
2585 hdd_err("nla_parse failed");
2586 return -EINVAL;
2587 }
2588
2589 channel = &bucket->channels[bucket->num_channels];
2590 /* Parse and fetch channel */
2591 if (!channel_tb[
2592 QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_CHANNEL]) {
2593 hdd_err("attr channel failed");
2594 return -EINVAL;
2595 }
2596 channel->channel =
2597 nla_get_u32(channel_tb[
2598 QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_CHANNEL]);
2599 hdd_debug("channel %u",
2600 channel->channel);
2601
2602 /* Parse and fetch dwell time */
2603 if (!channel_tb[
2604 QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_DWELL_TIME]) {
2605 hdd_err("attr dwelltime failed");
2606 return -EINVAL;
2607 }
2608 channel->dwell_time_ms =
2609 nla_get_u32(channel_tb[
2610 QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_DWELL_TIME]);
2611
2612 /* Override dwell time if required */
2613 if (channel->dwell_time_ms <
2614 extscan_active_min_chn_time ||
2615 channel->dwell_time_ms >
2616 max_dwell_time_active_bucket) {
2617 hdd_debug("WiFi band is unspecified, dwellTime:%d",
2618 channel->dwell_time_ms);
2619
2620 if ((wlan_reg_get_channel_state_for_pwrmode(
2621 hdd_ctx->pdev, channel->channel,
2622 REG_CURRENT_PWR_MODE)) !=
2623 CHANNEL_STATE_ENABLE) {
2624 channel->dwell_time_ms =
2625 max_dwell_time_passive_bucket;
2626 } else {
2627 channel->dwell_time_ms =
2628 max_dwell_time_active_bucket;
2629 }
2630 }
2631
2632 hdd_debug("New Dwell time %u ms",
2633 channel->dwell_time_ms);
2634
2635 if ((wlan_reg_get_channel_state_for_pwrmode(
2636 hdd_ctx->pdev, channel->channel,
2637 REG_CURRENT_PWR_MODE)) !=
2638 CHANNEL_STATE_ENABLE) {
2639 if (min_dwell_time_passive_bucket >
2640 channel->dwell_time_ms) {
2641 min_dwell_time_passive_bucket =
2642 channel->dwell_time_ms;
2643 }
2644 if (max_dwell_time_passive_bucket <
2645 channel->dwell_time_ms) {
2646 max_dwell_time_passive_bucket =
2647 channel->dwell_time_ms;
2648 }
2649 } else {
2650 if (min_dwell_time_active_bucket >
2651 channel->dwell_time_ms) {
2652 min_dwell_time_active_bucket =
2653 channel->dwell_time_ms;
2654 }
2655 if (max_dwell_time_active_bucket <
2656 channel->dwell_time_ms) {
2657 max_dwell_time_active_bucket =
2658 channel->dwell_time_ms;
2659 }
2660 }
2661
2662 /* Parse and fetch channel spec passive */
2663 if (!channel_tb[
2664 QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_PASSIVE]) {
2665 hdd_err("attr channel spec passive failed");
2666 return -EINVAL;
2667 }
2668 channel->passive =
2669 nla_get_u8(channel_tb[
2670 QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_PASSIVE]);
2671 hdd_debug("Chnl spec passive %u",
2672 channel->passive);
2673 /* Override scan type if required */
2674 if ((wlan_reg_get_channel_state_for_pwrmode(
2675 hdd_ctx->pdev,
2676 channel->channel,
2677 REG_CURRENT_PWR_MODE))
2678 != CHANNEL_STATE_ENABLE) {
2679 channel->passive = true;
2680 } else {
2681 channel->passive = false;
2682 }
2683 total_channels++;
2684 bucket->num_channels++;
2685 }
2686
2687 if (bucket->num_channels != expected_channels)
2688 hdd_warn("channels: Expected %u got %u",
2689 expected_channels,
2690 bucket->num_channels);
2691
2692 hdd_extscan_update_dwell_time_limits(
2693 req_msg, bkt_index,
2694 min_dwell_time_active_bucket,
2695 max_dwell_time_active_bucket,
2696 min_dwell_time_passive_bucket,
2697 max_dwell_time_passive_bucket);
2698
2699 hdd_debug("bktIndex:%d actv_min:%d actv_max:%d pass_min:%d pass_max:%d",
2700 bkt_index,
2701 bucket->min_dwell_time_active,
2702 bucket->max_dwell_time_active,
2703 bucket->min_dwell_time_passive,
2704 bucket->max_dwell_time_passive);
2705
2706 bkt_index++;
2707 req_msg->num_buckets++;
2708 }
2709
2710 hdd_debug("Global: actv_min:%d actv_max:%d pass_min:%d pass_max:%d",
2711 req_msg->min_dwell_time_active,
2712 req_msg->max_dwell_time_active,
2713 req_msg->min_dwell_time_passive,
2714 req_msg->max_dwell_time_passive);
2715 return 0;
2716 }
2717
2718 /*
2719 * hdd_extscan_map_usr_drv_config_flags() - map userspace to driver config flags
2720 * @config_flags - [input] configuration flags.
2721 *
2722 * This function maps user space received configuration flags to
2723 * driver representation.
2724 *
2725 * Return: configuration flags
2726 */
hdd_extscan_map_usr_drv_config_flags(uint32_t config_flags)2727 static uint32_t hdd_extscan_map_usr_drv_config_flags(uint32_t config_flags)
2728 {
2729 uint32_t configuration_flags = 0;
2730
2731 if (config_flags & EXTSCAN_LP_EXTENDED_BATCHING)
2732 configuration_flags |= EXTSCAN_LP_EXTENDED_BATCHING;
2733
2734 return configuration_flags;
2735 }
2736
2737 /**
2738 * __wlan_hdd_cfg80211_extscan_start() - ext scan start
2739 * @wiphy: Pointer to wireless phy
2740 * @wdev: Pointer to wireless device
2741 * @data: Pointer to data
2742 * @data_len: Length of @data
2743 *
2744 * Return: 0 on success; error number otherwise
2745 */
2746 static int
__wlan_hdd_cfg80211_extscan_start(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)2747 __wlan_hdd_cfg80211_extscan_start(struct wiphy *wiphy,
2748 struct wireless_dev *wdev,
2749 const void *data,
2750 int data_len)
2751 {
2752 struct wifi_scan_cmd_req_params *params;
2753 struct net_device *dev = wdev->netdev;
2754 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
2755 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
2756 struct nlattr *tb[EXTSCAN_PARAM_MAX + 1];
2757 struct hdd_ext_scan_context *context;
2758 uint32_t num_buckets;
2759 QDF_STATUS status;
2760 int retval, id;
2761 unsigned long rc;
2762
2763 hdd_enter_dev(dev);
2764
2765 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
2766 hdd_err("Command not allowed in FTM mode");
2767 return -EPERM;
2768 }
2769
2770 if (QDF_NDI_MODE == adapter->device_mode) {
2771 hdd_err("Command not allowed for NDI interface");
2772 return -EPERM;
2773 }
2774
2775 retval = wlan_hdd_validate_context(hdd_ctx);
2776 if (0 != retval)
2777 return -EINVAL;
2778
2779 if (!ucfg_extscan_get_enable(hdd_ctx->psoc)) {
2780 hdd_err("extscan not supported");
2781 return -ENOTSUPP;
2782 }
2783 if (wlan_cfg80211_nla_parse(tb, EXTSCAN_PARAM_MAX, data, data_len,
2784 wlan_hdd_extscan_config_policy)) {
2785 hdd_err("Invalid ATTR");
2786 return -EINVAL;
2787 }
2788
2789 params = qdf_mem_malloc(sizeof(*params));
2790 if (!params)
2791 return -ENOMEM;
2792
2793 /* assume the worst until proven otherwise */
2794 retval = -EINVAL;
2795
2796 /* Parse and fetch request Id */
2797 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID;
2798 if (!tb[id]) {
2799 hdd_err("attr request id failed");
2800 goto fail;
2801 }
2802
2803 params->request_id = nla_get_u32(tb[id]);
2804 params->vdev_id = adapter->deflink->vdev_id;
2805
2806 /* Parse and fetch base period */
2807 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_BASE_PERIOD;
2808 if (!tb[id]) {
2809 hdd_err("attr base period failed");
2810 goto fail;
2811 }
2812 params->base_period = nla_get_u32(tb[id]);
2813
2814 /* Parse and fetch max AP per scan */
2815 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_MAX_AP_PER_SCAN;
2816 if (!tb[id]) {
2817 hdd_err("attr max_ap_per_scan failed");
2818 goto fail;
2819 }
2820 params->max_ap_per_scan = nla_get_u32(tb[id]);
2821
2822 /* Parse and fetch report threshold percent */
2823 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_REPORT_THRESHOLD_PERCENT;
2824 if (!tb[id]) {
2825 hdd_err("attr report_threshold percent failed");
2826 goto fail;
2827 }
2828 params->report_threshold_percent = nla_get_u8(tb[id]);
2829
2830 /* Parse and fetch report threshold num scans */
2831 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_REPORT_THRESHOLD_NUM_SCANS;
2832 if (!tb[id]) {
2833 hdd_err("attr report_threshold num scans failed");
2834 goto fail;
2835 }
2836 params->report_threshold_num_scans = nla_get_u8(tb[id]);
2837 hdd_debug("Req Id: %d Vdev Id: %d Base Period: %d Max AP per Scan: %d Report Threshold percent: %d Report Threshold num scans: %d",
2838 params->request_id, params->vdev_id,
2839 params->base_period, params->max_ap_per_scan,
2840 params->report_threshold_percent,
2841 params->report_threshold_num_scans);
2842
2843 /* Parse and fetch number of buckets */
2844 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_NUM_BUCKETS;
2845 if (!tb[id]) {
2846 hdd_err("attr number of buckets failed");
2847 goto fail;
2848 }
2849 num_buckets = nla_get_u8(tb[id]);
2850
2851 if (num_buckets > WMI_WLAN_EXTSCAN_MAX_BUCKETS) {
2852 hdd_warn("Exceeded MAX number of buckets: %d",
2853 WMI_WLAN_EXTSCAN_MAX_BUCKETS);
2854 num_buckets = WMI_WLAN_EXTSCAN_MAX_BUCKETS;
2855 }
2856 hdd_debug("Input: Number of Buckets %d", num_buckets);
2857 params->num_buckets = num_buckets;
2858
2859 /* This is optional attribute, if not present set it to 0 */
2860 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_CONFIGURATION_FLAGS;
2861 if (!tb[id])
2862 params->configuration_flags = 0;
2863 else
2864 params->configuration_flags =
2865 hdd_extscan_map_usr_drv_config_flags(
2866 nla_get_u32(tb[id]));
2867
2868 params->extscan_adaptive_dwell_mode =
2869 ucfg_scan_get_extscan_adaptive_dwell_mode(hdd_ctx->psoc);
2870
2871 hdd_debug("Configuration flags: %u",
2872 params->configuration_flags);
2873
2874 /* Parse and fetch number the array of buckets */
2875 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC;
2876 if (!tb[id]) {
2877 hdd_err("attr bucket spec failed");
2878 goto fail;
2879 }
2880 retval = hdd_extscan_start_fill_bucket_channel_spec(hdd_ctx, params,
2881 tb[id]);
2882 if (retval)
2883 goto fail;
2884
2885 context = &ext_scan_context;
2886 spin_lock(&context->context_lock);
2887 INIT_COMPLETION(context->response_event);
2888 context->request_id = params->request_id;
2889 context->buckets_scanned = 0;
2890 spin_unlock(&context->context_lock);
2891
2892 status = sme_ext_scan_start(hdd_ctx->mac_handle, params);
2893 if (!QDF_IS_STATUS_SUCCESS(status)) {
2894 hdd_err("sme_ext_scan_start failed(err=%d)", status);
2895 retval = qdf_status_to_os_return(status);
2896 goto fail;
2897 }
2898
2899 hdd_ctx->ext_scan_start_since_boot = qdf_get_monotonic_boottime();
2900 hdd_debug("Timestamp since boot: %llu",
2901 hdd_ctx->ext_scan_start_since_boot);
2902
2903 /* request was sent -- wait for the response */
2904 rc = wait_for_completion_timeout(&context->response_event,
2905 msecs_to_jiffies(WLAN_WAIT_TIME_EXTSCAN));
2906
2907 if (!rc) {
2908 hdd_err("sme_ext_scan_start timed out");
2909 retval = -ETIMEDOUT;
2910 } else {
2911 spin_lock(&context->context_lock);
2912 if (context->request_id == params->request_id)
2913 retval = context->response_status;
2914 else
2915 retval = -EINVAL;
2916 spin_unlock(&context->context_lock);
2917 }
2918 hdd_exit();
2919
2920 fail:
2921 qdf_mem_free(params);
2922 return retval;
2923 }
2924
2925 /**
2926 * wlan_hdd_cfg80211_extscan_start() - start extscan
2927 * @wiphy: Pointer to wireless phy.
2928 * @wdev: Pointer to wireless device.
2929 * @data: Pointer to input data.
2930 * @data_len: Length of @data.
2931 *
2932 * Return: 0 on success, negative errno on failure
2933 */
wlan_hdd_cfg80211_extscan_start(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)2934 int wlan_hdd_cfg80211_extscan_start(struct wiphy *wiphy,
2935 struct wireless_dev *wdev,
2936 const void *data, int data_len)
2937 {
2938 int errno;
2939 struct osif_vdev_sync *vdev_sync;
2940
2941 errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync);
2942 if (errno)
2943 return errno;
2944
2945 errno = __wlan_hdd_cfg80211_extscan_start(wiphy, wdev, data, data_len);
2946
2947 osif_vdev_sync_op_stop(vdev_sync);
2948
2949 return errno;
2950 }
2951
2952
2953 /**
2954 * __wlan_hdd_cfg80211_extscan_stop() - ext scan stop
2955 * @wiphy: Pointer to wireless phy
2956 * @wdev: Pointer to wireless device
2957 * @data: Pointer to data
2958 * @data_len: Data length
2959 *
2960 * Return: none
2961 */
2962 static int
__wlan_hdd_cfg80211_extscan_stop(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)2963 __wlan_hdd_cfg80211_extscan_stop(struct wiphy *wiphy,
2964 struct wireless_dev *wdev,
2965 const void *data, int data_len)
2966 {
2967 struct extscan_stop_req_params params;
2968 struct net_device *dev = wdev->netdev;
2969 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
2970 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
2971 struct nlattr *tb[EXTSCAN_PARAM_MAX + 1];
2972 struct hdd_ext_scan_context *context;
2973 QDF_STATUS status;
2974 int id, retval;
2975 unsigned long rc;
2976
2977 hdd_enter_dev(dev);
2978
2979 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
2980 hdd_err("Command not allowed in FTM mode");
2981 return -EPERM;
2982 }
2983
2984 retval = wlan_hdd_validate_context(hdd_ctx);
2985 if (0 != retval)
2986 return -EINVAL;
2987
2988 if (!ucfg_extscan_get_enable(hdd_ctx->psoc)) {
2989 hdd_err("extscan not supported");
2990 return -ENOTSUPP;
2991 }
2992
2993 if (wlan_cfg80211_nla_parse(tb, EXTSCAN_PARAM_MAX, data, data_len,
2994 wlan_hdd_extscan_config_policy)) {
2995 hdd_err("Invalid ATTR");
2996 return -EINVAL;
2997 }
2998
2999 /* Parse and fetch request Id */
3000 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID;
3001 if (!tb[id]) {
3002 hdd_err("attr request id failed");
3003 return -EINVAL;
3004 }
3005 params.request_id = nla_get_u32(tb[id]);
3006 params.vdev_id = adapter->deflink->vdev_id;
3007 hdd_debug("Req Id %d Vdev Id %d",
3008 params.request_id, params.vdev_id);
3009
3010 context = &ext_scan_context;
3011 spin_lock(&context->context_lock);
3012 INIT_COMPLETION(context->response_event);
3013 context->request_id = params.request_id;
3014 spin_unlock(&context->context_lock);
3015
3016 status = sme_ext_scan_stop(hdd_ctx->mac_handle, ¶ms);
3017 if (!QDF_IS_STATUS_SUCCESS(status)) {
3018 hdd_err("sme_ext_scan_stop failed(err=%d)", status);
3019 return qdf_status_to_os_return(status);
3020 }
3021
3022 /* request was sent -- wait for the response */
3023 rc = wait_for_completion_timeout(&context->response_event,
3024 msecs_to_jiffies(WLAN_WAIT_TIME_EXTSCAN));
3025
3026 if (!rc) {
3027 hdd_err("sme_ext_scan_stop timed out");
3028 retval = -ETIMEDOUT;
3029 } else {
3030 spin_lock(&context->context_lock);
3031 if (context->request_id == params.request_id)
3032 retval = context->response_status;
3033 else
3034 retval = -EINVAL;
3035 spin_unlock(&context->context_lock);
3036 }
3037 hdd_exit();
3038 return retval;
3039 }
3040
3041 /**
3042 * wlan_hdd_cfg80211_extscan_stop() - stop extscan
3043 * @wiphy: Pointer to wireless phy.
3044 * @wdev: Pointer to wireless device.
3045 * @data: Pointer to input data.
3046 * @data_len: Length of @data.
3047 *
3048 * Return: 0 on success, negative errno on failure
3049 */
wlan_hdd_cfg80211_extscan_stop(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)3050 int wlan_hdd_cfg80211_extscan_stop(struct wiphy *wiphy,
3051 struct wireless_dev *wdev,
3052 const void *data, int data_len)
3053 {
3054 int errno;
3055 struct osif_vdev_sync *vdev_sync;
3056
3057 errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync);
3058 if (errno)
3059 return errno;
3060
3061 errno = __wlan_hdd_cfg80211_extscan_stop(wiphy, wdev, data, data_len);
3062
3063 osif_vdev_sync_op_stop(vdev_sync);
3064
3065 return errno;
3066 }
3067
3068 /**
3069 * __wlan_hdd_cfg80211_extscan_reset_bssid_hotlist() - reset bssid hotlist
3070 * @wiphy: Pointer to wireless phy
3071 * @wdev: Pointer to wireless device
3072 * @data: Pointer to data
3073 * @data_len: Data length
3074 *
3075 * Return: none
3076 */
3077 static int
__wlan_hdd_cfg80211_extscan_reset_bssid_hotlist(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)3078 __wlan_hdd_cfg80211_extscan_reset_bssid_hotlist(struct wiphy *wiphy,
3079 struct wireless_dev *wdev,
3080 const void *data,
3081 int data_len)
3082 {
3083 struct extscan_bssid_hotlist_reset_params params;
3084 struct net_device *dev = wdev->netdev;
3085 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
3086 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
3087 struct nlattr *tb[EXTSCAN_PARAM_MAX + 1];
3088 struct hdd_ext_scan_context *context;
3089 QDF_STATUS status;
3090 int id, retval;
3091 unsigned long rc;
3092
3093 hdd_enter_dev(dev);
3094
3095 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
3096 hdd_err("Command not allowed in FTM mode");
3097 return -EPERM;
3098 }
3099
3100 retval = wlan_hdd_validate_context(hdd_ctx);
3101 if (0 != retval)
3102 return -EINVAL;
3103
3104 if (!ucfg_extscan_get_enable(hdd_ctx->psoc)) {
3105 hdd_err("extscan not supported");
3106 return -ENOTSUPP;
3107 }
3108
3109 if (wlan_cfg80211_nla_parse(tb, EXTSCAN_PARAM_MAX,
3110 data, data_len,
3111 wlan_hdd_extscan_config_policy)) {
3112 hdd_err("Invalid ATTR");
3113 return -EINVAL;
3114 }
3115
3116 /* Parse and fetch request Id */
3117 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID;
3118 if (!tb[id]) {
3119 hdd_err("attr request id failed");
3120 return -EINVAL;
3121 }
3122
3123 params.request_id = nla_get_u32(tb[id]);
3124 params.vdev_id = adapter->deflink->vdev_id;
3125 hdd_debug("Req Id %d vdev Id %d", params.request_id, params.vdev_id);
3126
3127 context = &ext_scan_context;
3128 spin_lock(&context->context_lock);
3129 INIT_COMPLETION(context->response_event);
3130 context->request_id = params.request_id;
3131 spin_unlock(&context->context_lock);
3132
3133 status = sme_reset_bss_hotlist(hdd_ctx->mac_handle, ¶ms);
3134 if (!QDF_IS_STATUS_SUCCESS(status)) {
3135 hdd_err("sme_reset_bss_hotlist failed(err=%d)", status);
3136 return qdf_status_to_os_return(status);
3137 }
3138
3139 /* request was sent -- wait for the response */
3140 rc = wait_for_completion_timeout
3141 (&context->response_event,
3142 msecs_to_jiffies(WLAN_WAIT_TIME_EXTSCAN));
3143 if (!rc) {
3144 hdd_err("sme_reset_bss_hotlist timed out");
3145 retval = -ETIMEDOUT;
3146 } else {
3147 spin_lock(&context->context_lock);
3148 if (context->request_id == params.request_id)
3149 retval = context->response_status;
3150 else
3151 retval = -EINVAL;
3152 spin_unlock(&context->context_lock);
3153 }
3154 hdd_exit();
3155 return retval;
3156 }
3157
3158 /**
3159 * wlan_hdd_cfg80211_extscan_reset_bssid_hotlist() - reset bssid hot list
3160 * @wiphy: Pointer to wireless phy
3161 * @wdev: Pointer to wireless device
3162 * @data: Pointer to data
3163 * @data_len: Data length
3164 *
3165 * Return: 0 on success, negative errno on failure
3166 */
wlan_hdd_cfg80211_extscan_reset_bssid_hotlist(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)3167 int wlan_hdd_cfg80211_extscan_reset_bssid_hotlist(struct wiphy *wiphy,
3168 struct wireless_dev *wdev,
3169 const void *data,
3170 int data_len)
3171 {
3172 int errno;
3173 struct osif_vdev_sync *vdev_sync;
3174
3175 errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync);
3176 if (errno)
3177 return errno;
3178
3179 errno = __wlan_hdd_cfg80211_extscan_reset_bssid_hotlist(wiphy, wdev,
3180 data, data_len);
3181
3182 osif_vdev_sync_op_stop(vdev_sync);
3183
3184 return errno;
3185 }
3186
3187 /**
3188 * __wlan_hdd_cfg80211_extscan_reset_significant_change() -
3189 * reset significant change
3190 * @wiphy: Pointer to wireless phy
3191 * @wdev: Pointer to wireless device
3192 * @data: Pointer to data
3193 * @data_len: Data length
3194 *
3195 * Return: none
3196 */
3197 static int
__wlan_hdd_cfg80211_extscan_reset_significant_change(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)3198 __wlan_hdd_cfg80211_extscan_reset_significant_change(struct wiphy *wiphy,
3199 struct wireless_dev *wdev,
3200 const void *data,
3201 int data_len)
3202 {
3203 struct extscan_capabilities_reset_params params;
3204 struct net_device *dev = wdev->netdev;
3205 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
3206 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
3207 struct nlattr *tb[EXTSCAN_PARAM_MAX + 1];
3208 struct hdd_ext_scan_context *context;
3209 QDF_STATUS status;
3210 int id, retval;
3211 unsigned long rc;
3212
3213 hdd_enter_dev(dev);
3214
3215 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
3216 hdd_err("Command not allowed in FTM mode");
3217 return -EPERM;
3218 }
3219
3220 retval = wlan_hdd_validate_context(hdd_ctx);
3221 if (0 != retval)
3222 return -EINVAL;
3223
3224 if (!ucfg_extscan_get_enable(hdd_ctx->psoc)) {
3225 hdd_err("extscan not supported");
3226 return -ENOTSUPP;
3227 }
3228
3229 if (wlan_cfg80211_nla_parse(tb, EXTSCAN_PARAM_MAX, data, data_len,
3230 wlan_hdd_extscan_config_policy)) {
3231 hdd_err("Invalid ATTR");
3232 return -EINVAL;
3233 }
3234
3235 /* Parse and fetch request Id */
3236 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID;
3237 if (!tb[id]) {
3238 hdd_err("attr request id failed");
3239 return -EINVAL;
3240 }
3241
3242 params.request_id = nla_get_u32(tb[id]);
3243 params.vdev_id = adapter->deflink->vdev_id;
3244 hdd_debug("Req Id %d Vdev Id %d", params.request_id, params.vdev_id);
3245
3246 context = &ext_scan_context;
3247 spin_lock(&context->context_lock);
3248 INIT_COMPLETION(context->response_event);
3249 context->request_id = params.request_id;
3250 spin_unlock(&context->context_lock);
3251
3252 status = sme_reset_significant_change(hdd_ctx->mac_handle, ¶ms);
3253 if (!QDF_IS_STATUS_SUCCESS(status)) {
3254 hdd_err("sme_reset_significant_change failed(err=%d)",
3255 status);
3256 return -EINVAL;
3257 }
3258
3259 /* request was sent -- wait for the response */
3260 rc = wait_for_completion_timeout(&context->response_event,
3261 msecs_to_jiffies(WLAN_WAIT_TIME_EXTSCAN));
3262
3263 if (!rc) {
3264 hdd_err("sme_ResetSignificantChange timed out");
3265 retval = -ETIMEDOUT;
3266 } else {
3267 spin_lock(&context->context_lock);
3268 if (context->request_id == params.request_id)
3269 retval = context->response_status;
3270 else
3271 retval = -EINVAL;
3272 spin_unlock(&context->context_lock);
3273 }
3274 hdd_exit();
3275 return retval;
3276 }
3277
3278 /**
3279 * wlan_hdd_cfg80211_extscan_reset_significant_change() - reset significant
3280 * change
3281 * @wiphy: Pointer to wireless phy
3282 * @wdev: Pointer to wireless device
3283 * @data: Pointer to data
3284 * @data_len: Data length
3285 *
3286 * Return: 0 on success, negative errno on failure
3287 */
wlan_hdd_cfg80211_extscan_reset_significant_change(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)3288 int wlan_hdd_cfg80211_extscan_reset_significant_change(struct wiphy *wiphy,
3289 struct wireless_dev *wdev,
3290 const void *data, int data_len)
3291 {
3292 int errno;
3293 struct osif_vdev_sync *vdev_sync;
3294
3295 errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync);
3296 if (errno)
3297 return errno;
3298
3299 errno = __wlan_hdd_cfg80211_extscan_reset_significant_change(wiphy,
3300 wdev,
3301 data,
3302 data_len);
3303
3304 osif_vdev_sync_op_stop(vdev_sync);
3305
3306 return errno;
3307 }
3308
3309
3310 /**
3311 * hdd_extscan_epno_fill_network() - epno fill single network
3312 * @network: aggregate network attribute
3313 * @nw: epno network record to be filled
3314 *
3315 * This function takes a single network block NL vendor attribute from
3316 * @network and decodes it into the internal record @nw.
3317 *
3318 * Return: 0 on success, error number otherwise
3319 */
3320 static int
hdd_extscan_epno_fill_network(struct nlattr * network,struct wifi_epno_network_params * nw)3321 hdd_extscan_epno_fill_network(struct nlattr *network,
3322 struct wifi_epno_network_params *nw)
3323 {
3324 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_PNO_MAX + 1];
3325 int id, ssid_len;
3326 uint8_t *ssid;
3327
3328 if (!network) {
3329 hdd_err("attr network attr failed");
3330 return -EINVAL;
3331 }
3332
3333 if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_PNO_MAX,
3334 nla_data(network),
3335 nla_len(network),
3336 wlan_hdd_pno_config_policy)) {
3337 hdd_err("nla_parse failed");
3338 return -EINVAL;
3339 }
3340
3341 /* Parse and fetch ssid */
3342 id = QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_SSID;
3343 if (!tb[id]) {
3344 hdd_err("attr network ssid failed");
3345 return -EINVAL;
3346 }
3347 ssid_len = nla_len(tb[id]);
3348
3349 /* nla_parse will detect overflow but not underflow */
3350 if (0 == ssid_len) {
3351 hdd_err("zero ssid length");
3352 return -EINVAL;
3353 }
3354
3355 /* Decrement by 1, don't count null character */
3356 ssid_len--;
3357
3358 nw->ssid.length = ssid_len;
3359 hdd_debug("network ssid length %d", ssid_len);
3360 ssid = nla_data(tb[id]);
3361 qdf_mem_copy(nw->ssid.ssid, ssid, ssid_len);
3362 hdd_debug("Ssid (" QDF_SSID_FMT ")",
3363 QDF_SSID_REF(nw->ssid.length, nw->ssid.ssid));
3364
3365 /* Parse and fetch epno flags */
3366 id = QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_FLAGS;
3367 if (!tb[id]) {
3368 hdd_err("attr epno flags failed");
3369 return -EINVAL;
3370 }
3371 nw->flags = nla_get_u8(tb[id]);
3372 hdd_debug("flags %u", nw->flags);
3373
3374 /* Parse and fetch auth bit */
3375 id = QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_AUTH_BIT;
3376 if (!tb[id]) {
3377 hdd_err("attr auth bit failed");
3378 return -EINVAL;
3379 }
3380 nw->auth_bit_field = nla_get_u8(tb[id]);
3381 hdd_debug("auth bit %u", nw->auth_bit_field);
3382
3383 return 0;
3384 }
3385
3386 /**
3387 * hdd_extscan_epno_fill_network_list() - epno fill network list
3388 * @req_msg: request message
3389 * @networks: aggregate network list attribute
3390 *
3391 * This function reads the network block NL vendor attributes from
3392 * @networks and fills in the epno request message @req_msg.
3393 *
3394 * Return: 0 on success, error number otherwise
3395 */
3396 static int
hdd_extscan_epno_fill_network_list(struct wifi_enhanced_pno_params * req_msg,struct nlattr * networks)3397 hdd_extscan_epno_fill_network_list(struct wifi_enhanced_pno_params *req_msg,
3398 struct nlattr *networks)
3399 {
3400 struct nlattr *network;
3401 int rem;
3402 uint32_t index;
3403 uint32_t expected_networks;
3404 struct wifi_epno_network_params *nw;
3405
3406 if (!networks) {
3407 hdd_err("attr networks list failed");
3408 return -EINVAL;
3409 }
3410
3411 expected_networks = req_msg->num_networks;
3412 index = 0;
3413
3414 nla_for_each_nested(network, networks, rem) {
3415 if (index == expected_networks) {
3416 hdd_warn("ignoring excess networks");
3417 break;
3418 }
3419
3420 nw = &req_msg->networks[index++];
3421 if (hdd_extscan_epno_fill_network(network, nw))
3422 return -EINVAL;
3423 }
3424 req_msg->num_networks = index;
3425 return 0;
3426 }
3427
3428 /**
3429 * __wlan_hdd_cfg80211_set_epno_list() - epno set network list
3430 * @wiphy: wiphy
3431 * @wdev: pointer to wireless dev
3432 * @data: data pointer
3433 * @data_len: data length
3434 *
3435 * This function reads the NL vendor attributes from @data and
3436 * fills in the epno request message.
3437 *
3438 * Return: 0 on success, error number otherwise
3439 */
__wlan_hdd_cfg80211_set_epno_list(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)3440 static int __wlan_hdd_cfg80211_set_epno_list(struct wiphy *wiphy,
3441 struct wireless_dev *wdev,
3442 const void *data,
3443 int data_len)
3444 {
3445 struct wifi_enhanced_pno_params *req_msg;
3446 struct net_device *dev = wdev->netdev;
3447 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
3448 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
3449 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_PNO_MAX + 1];
3450 struct nlattr *networks;
3451 QDF_STATUS status;
3452 uint32_t num_networks, len;
3453 int id, ret_val;
3454
3455 hdd_enter_dev(dev);
3456
3457 ret_val = wlan_hdd_validate_context(hdd_ctx);
3458 if (ret_val)
3459 return ret_val;
3460
3461 if (!ucfg_extscan_get_enable(hdd_ctx->psoc)) {
3462 hdd_err("extscan not supported");
3463 return -ENOTSUPP;
3464 }
3465
3466 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
3467 hdd_err("Command not allowed in FTM mode");
3468 return -EPERM;
3469 }
3470
3471 if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_PNO_MAX, data,
3472 data_len, wlan_hdd_pno_config_policy)) {
3473 hdd_err("Invalid ATTR");
3474 return -EINVAL;
3475 }
3476
3477 /* Parse and fetch number of networks */
3478 id = QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_NUM_NETWORKS;
3479 if (!tb[id]) {
3480 hdd_err("attr num networks failed");
3481 return -EINVAL;
3482 }
3483
3484 /*
3485 * num_networks is also used as EPNO SET/RESET request.
3486 * if num_networks is zero then it is treated as RESET.
3487 */
3488 num_networks = nla_get_u32(tb[id]);
3489
3490 if (num_networks > MAX_EPNO_NETWORKS) {
3491 hdd_debug("num of nw: %d exceeded max: %d, resetting to: %d",
3492 num_networks, MAX_EPNO_NETWORKS, MAX_EPNO_NETWORKS);
3493 num_networks = MAX_EPNO_NETWORKS;
3494 }
3495
3496 hdd_debug("num networks %u", num_networks);
3497 len = sizeof(*req_msg) +
3498 (num_networks * sizeof(req_msg->networks[0]));
3499
3500 req_msg = qdf_mem_malloc(len);
3501 if (!req_msg)
3502 return -ENOMEM;
3503
3504 req_msg->num_networks = num_networks;
3505
3506 /* Parse and fetch request Id */
3507 id = QCA_WLAN_VENDOR_ATTR_PNO_CONFIG_REQUEST_ID;
3508 if (!tb[id]) {
3509 hdd_err("attr request id failed");
3510 goto fail;
3511 }
3512 req_msg->request_id = nla_get_u32(tb[id]);
3513 hdd_debug("Req Id %u", req_msg->request_id);
3514
3515 req_msg->vdev_id = adapter->deflink->vdev_id;
3516 hdd_debug("Vdev Id %d", req_msg->vdev_id);
3517
3518 if (num_networks) {
3519 /* Parse and fetch min_5ghz_rssi */
3520 id = QCA_WLAN_VENDOR_ATTR_EPNO_MIN5GHZ_RSSI;
3521 if (!tb[id]) {
3522 hdd_err("min_5ghz_rssi id failed");
3523 goto fail;
3524 }
3525 req_msg->min_5ghz_rssi = nla_get_u32(tb[id]);
3526
3527 /* Parse and fetch min_24ghz_rssi */
3528 id = QCA_WLAN_VENDOR_ATTR_EPNO_MIN24GHZ_RSSI;
3529 if (!tb[id]) {
3530 hdd_err("min_24ghz_rssi id failed");
3531 goto fail;
3532 }
3533 req_msg->min_24ghz_rssi = nla_get_u32(tb[id]);
3534
3535 /* Parse and fetch initial_score_max */
3536 id = QCA_WLAN_VENDOR_ATTR_EPNO_INITIAL_SCORE_MAX;
3537 if (!tb[id]) {
3538 hdd_err("initial_score_max id failed");
3539 goto fail;
3540 }
3541 req_msg->initial_score_max = nla_get_u32(tb[id]);
3542
3543 /* Parse and fetch current_connection_bonus */
3544 id = QCA_WLAN_VENDOR_ATTR_EPNO_CURRENT_CONNECTION_BONUS;
3545 if (!tb[id]) {
3546 hdd_err("current_connection_bonus id failed");
3547 goto fail;
3548 }
3549 req_msg->current_connection_bonus = nla_get_u32(tb[id]);
3550
3551 /* Parse and fetch same_network_bonus */
3552 id = QCA_WLAN_VENDOR_ATTR_EPNO_SAME_NETWORK_BONUS;
3553 if (!tb[id]) {
3554 hdd_err("same_network_bonus id failed");
3555 goto fail;
3556 }
3557 req_msg->same_network_bonus = nla_get_u32(tb[id]);
3558
3559 /* Parse and fetch secure_bonus */
3560 id = QCA_WLAN_VENDOR_ATTR_EPNO_SECURE_BONUS;
3561 if (!tb[id]) {
3562 hdd_err("secure_bonus id failed");
3563 goto fail;
3564 }
3565 req_msg->secure_bonus = nla_get_u32(tb[id]);
3566
3567 /* Parse and fetch band_5ghz_bonus */
3568 id = QCA_WLAN_VENDOR_ATTR_EPNO_BAND5GHZ_BONUS;
3569 if (!tb[id]) {
3570 hdd_err("band_5ghz_bonus id failed");
3571 goto fail;
3572 }
3573 req_msg->band_5ghz_bonus = nla_get_u32(tb[id]);
3574
3575 hdd_debug("min_5ghz_rssi: %d min_24ghz_rssi: %d",
3576 req_msg->min_5ghz_rssi,
3577 req_msg->min_24ghz_rssi);
3578 hdd_debug("initial_score_max: %d current_connection_bonus:%d",
3579 req_msg->initial_score_max,
3580 req_msg->current_connection_bonus);
3581 hdd_debug("Bonuses same_network: %d secure: %d band_5ghz: %d",
3582 req_msg->same_network_bonus,
3583 req_msg->secure_bonus,
3584 req_msg->band_5ghz_bonus);
3585
3586 id = QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORKS_LIST;
3587 networks = tb[id];
3588 if (hdd_extscan_epno_fill_network_list(req_msg, networks))
3589 goto fail;
3590
3591 }
3592
3593 status = sme_set_epno_list(hdd_ctx->mac_handle, req_msg);
3594 if (!QDF_IS_STATUS_SUCCESS(status)) {
3595 hdd_err("sme_set_epno_list failed(err=%d)", status);
3596 goto fail;
3597 }
3598
3599 hdd_exit();
3600 qdf_mem_free(req_msg);
3601 return 0;
3602
3603 fail:
3604 qdf_mem_free(req_msg);
3605 return -EINVAL;
3606 }
3607
3608 /**
3609 * wlan_hdd_cfg80211_set_epno_list() - epno set network list
3610 * @wiphy: wiphy
3611 * @wdev: pointer to wireless dev
3612 * @data: data pointer
3613 * @data_len: data length
3614 *
3615 * This function reads the NL vendor attributes from %tb and
3616 * fill in the epno request message.
3617 *
3618 * Return: 0 on success, error number otherwise
3619 */
wlan_hdd_cfg80211_set_epno_list(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)3620 int wlan_hdd_cfg80211_set_epno_list(struct wiphy *wiphy,
3621 struct wireless_dev *wdev,
3622 const void *data,
3623 int data_len)
3624 {
3625 int errno;
3626 struct osif_vdev_sync *vdev_sync;
3627
3628 errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync);
3629 if (errno)
3630 return errno;
3631
3632 errno = __wlan_hdd_cfg80211_set_epno_list(wiphy, wdev, data, data_len);
3633
3634 osif_vdev_sync_op_stop(vdev_sync);
3635
3636 return errno;
3637 }
3638
3639 /**
3640 * hdd_extscan_passpoint_fill_network() - passpoint fill single network
3641 * @network: aggregate network attribute
3642 * @nw: passpoint network record to be filled
3643 *
3644 * This function takes a single network block NL vendor attribute from
3645 * @network and decodes it into the internal record @nw.
3646 *
3647 * Return: 0 on success, error number otherwise
3648 */
3649 static int
hdd_extscan_passpoint_fill_network(struct nlattr * network,struct wifi_passpoint_network_param * nw)3650 hdd_extscan_passpoint_fill_network(struct nlattr *network,
3651 struct wifi_passpoint_network_param *nw)
3652 {
3653 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_PNO_MAX + 1];
3654 int id;
3655 size_t len;
3656
3657 if (!network) {
3658 hdd_err("attr network attr failed");
3659 return -EINVAL;
3660 }
3661
3662 if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_PNO_MAX,
3663 nla_data(network),
3664 nla_len(network),
3665 wlan_hdd_pno_config_policy)) {
3666 hdd_err("nla_parse failed");
3667 return -EINVAL;
3668 }
3669
3670 /* Parse and fetch identifier */
3671 id = QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ID;
3672 if (!tb[id]) {
3673 hdd_err("attr passpoint id failed");
3674 return -EINVAL;
3675 }
3676 nw->id = nla_get_u32(tb[id]);
3677 hdd_debug("Id %u", nw->id);
3678
3679 /* Parse and fetch realm */
3680 id = QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_REALM;
3681 if (!tb[id]) {
3682 hdd_err("attr realm failed");
3683 return -EINVAL;
3684 }
3685 len = wlan_cfg80211_nla_strscpy(nw->realm, tb[id],
3686 WMI_PASSPOINT_REALM_LEN);
3687 /* Don't send partial realm to firmware */
3688 if (len >= WMI_PASSPOINT_REALM_LEN) {
3689 hdd_err("user passed invalid realm, len:%zu", len);
3690 return -EINVAL;
3691 }
3692
3693 hdd_debug("realm: %s", nw->realm);
3694
3695 /* Parse and fetch roaming consortium ids */
3696 id = QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ROAM_CNSRTM_ID;
3697 if (!tb[id]) {
3698 hdd_err("attr roaming consortium ids failed");
3699 return -EINVAL;
3700 }
3701 nla_memcpy(&nw->roaming_consortium_ids, tb[id],
3702 sizeof(nw->roaming_consortium_ids));
3703 hdd_debug("roaming consortium ids");
3704
3705 /* Parse and fetch plmn */
3706 id = QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ROAM_PLMN;
3707 if (!tb[id]) {
3708 hdd_err("attr plmn failed");
3709 return -EINVAL;
3710 }
3711 nla_memcpy(&nw->plmn, tb[id],
3712 WMI_PASSPOINT_PLMN_LEN);
3713 hdd_debug("plmn %02x:%02x:%02x)",
3714 nw->plmn[0],
3715 nw->plmn[1],
3716 nw->plmn[2]);
3717
3718 return 0;
3719 }
3720
3721 /**
3722 * hdd_extscan_passpoint_fill_networks() - passpoint fill network list
3723 * @req_msg: request message
3724 * @networks: aggregate network list attribute
3725 *
3726 * This function reads the network block NL vendor attributes from
3727 * @networks and fills in the passpoint request message.
3728 *
3729 * Return: 0 on success, error number otherwise
3730 */
3731 static int
hdd_extscan_passpoint_fill_networks(struct wifi_passpoint_req_param * req_msg,struct nlattr * networks)3732 hdd_extscan_passpoint_fill_networks(struct wifi_passpoint_req_param *req_msg,
3733 struct nlattr *networks)
3734 {
3735 struct nlattr *network;
3736 int rem;
3737 uint32_t index;
3738 uint32_t expected_networks;
3739 struct wifi_passpoint_network_param *nw;
3740
3741 if (!networks) {
3742 hdd_err("attr networks list failed");
3743 return -EINVAL;
3744 }
3745
3746 expected_networks = req_msg->num_networks;
3747 index = 0;
3748
3749 nla_for_each_nested(network, networks, rem) {
3750 if (index == expected_networks) {
3751 hdd_warn("ignoring excess networks");
3752 break;
3753 }
3754
3755 nw = &req_msg->networks[index++];
3756 if (hdd_extscan_passpoint_fill_network(network, nw))
3757 return -EINVAL;
3758 }
3759 req_msg->num_networks = index;
3760 return 0;
3761 }
3762
3763 /**
3764 * __wlan_hdd_cfg80211_set_passpoint_list() - set passpoint 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 passpoint request message.
3772 *
3773 * Return: 0 on success, error number otherwise
3774 */
__wlan_hdd_cfg80211_set_passpoint_list(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)3775 static int __wlan_hdd_cfg80211_set_passpoint_list(struct wiphy *wiphy,
3776 struct wireless_dev *wdev,
3777 const void *data,
3778 int data_len)
3779 {
3780 struct wifi_passpoint_req_param *req_msg;
3781 struct net_device *dev = wdev->netdev;
3782 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
3783 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
3784 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_PNO_MAX + 1];
3785 struct nlattr *networks;
3786 uint32_t num_networks;
3787 QDF_STATUS status;
3788 int id, ret;
3789
3790 hdd_enter_dev(dev);
3791
3792 ret = wlan_hdd_validate_context(hdd_ctx);
3793 if (ret)
3794 return ret;
3795
3796 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
3797 hdd_err("Command not allowed in FTM mode");
3798 return -EPERM;
3799 }
3800
3801 if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_PNO_MAX, data,
3802 data_len, wlan_hdd_pno_config_policy)) {
3803 hdd_err("Invalid ATTR");
3804 return -EINVAL;
3805 }
3806
3807 /* Parse and fetch number of networks */
3808 id = QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_LIST_PARAM_NUM;
3809 if (!tb[id]) {
3810 hdd_err("attr num networks failed");
3811 return -EINVAL;
3812 }
3813 num_networks = nla_get_u32(tb[id]);
3814 if (num_networks > SIR_PASSPOINT_LIST_MAX_NETWORKS) {
3815 hdd_err("num networks %u exceeds max %u",
3816 num_networks, SIR_PASSPOINT_LIST_MAX_NETWORKS);
3817 return -EINVAL;
3818 }
3819
3820 hdd_debug("num networks %u", num_networks);
3821
3822 req_msg = qdf_mem_malloc(sizeof(*req_msg) +
3823 (num_networks * sizeof(req_msg->networks[0])));
3824 if (!req_msg)
3825 return -ENOMEM;
3826
3827 req_msg->num_networks = num_networks;
3828
3829 /* Parse and fetch request Id */
3830 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID;
3831 if (!tb[id]) {
3832 hdd_err("attr request id failed");
3833 goto fail;
3834 }
3835 req_msg->request_id = nla_get_u32(tb[id]);
3836
3837 req_msg->vdev_id = adapter->deflink->vdev_id;
3838 hdd_debug("Req Id %u Vdev Id %d",
3839 req_msg->request_id, req_msg->vdev_id);
3840
3841 id = QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_LIST_PARAM_NETWORK_ARRAY;
3842 networks = tb[id];
3843 if (hdd_extscan_passpoint_fill_networks(req_msg, networks))
3844 goto fail;
3845
3846 status = sme_set_passpoint_list(hdd_ctx->mac_handle, req_msg);
3847 if (!QDF_IS_STATUS_SUCCESS(status)) {
3848 hdd_err("sme_set_passpoint_list failed(err=%d)", status);
3849 goto fail;
3850 }
3851
3852 hdd_exit();
3853 qdf_mem_free(req_msg);
3854 return 0;
3855
3856 fail:
3857 qdf_mem_free(req_msg);
3858 return -EINVAL;
3859 }
3860
3861 /**
3862 * wlan_hdd_cfg80211_set_passpoint_list() - set passpoint network list
3863 * @wiphy: wiphy
3864 * @wdev: pointer to wireless dev
3865 * @data: data pointer
3866 * @data_len: data length
3867 *
3868 * This function reads the NL vendor attributes from %tb and
3869 * fill in the passpoint request message.
3870 *
3871 * Return: 0 on success, error number otherwise
3872 */
wlan_hdd_cfg80211_set_passpoint_list(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)3873 int wlan_hdd_cfg80211_set_passpoint_list(struct wiphy *wiphy,
3874 struct wireless_dev *wdev,
3875 const void *data,
3876 int data_len)
3877 {
3878 int errno;
3879 struct osif_vdev_sync *vdev_sync;
3880
3881 errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync);
3882 if (errno)
3883 return errno;
3884
3885 errno = __wlan_hdd_cfg80211_set_passpoint_list(wiphy, wdev,
3886 data, data_len);
3887
3888 osif_vdev_sync_op_stop(vdev_sync);
3889
3890 return errno;
3891 }
3892
3893 /**
3894 * __wlan_hdd_cfg80211_reset_passpoint_list() - reset passpoint network list
3895 * @wiphy: wiphy
3896 * @wdev: pointer to wireless dev
3897 * @data: data pointer
3898 * @data_len: data length
3899 *
3900 * This function resets passpoint networks list
3901 *
3902 * Return: 0 on success, error number otherwise
3903 */
__wlan_hdd_cfg80211_reset_passpoint_list(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)3904 static int __wlan_hdd_cfg80211_reset_passpoint_list(struct wiphy *wiphy,
3905 struct wireless_dev *wdev,
3906 const void *data,
3907 int data_len)
3908 {
3909 struct wifi_passpoint_req_param *req_msg;
3910 struct net_device *dev = wdev->netdev;
3911 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
3912 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
3913 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_PNO_MAX + 1];
3914 QDF_STATUS status;
3915 int id, ret;
3916
3917 hdd_enter_dev(dev);
3918
3919 ret = wlan_hdd_validate_context(hdd_ctx);
3920 if (ret)
3921 return ret;
3922
3923 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
3924 hdd_err("Command not allowed in FTM mode");
3925 return -EPERM;
3926 }
3927
3928 if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_PNO_MAX, data,
3929 data_len, wlan_hdd_extscan_config_policy)) {
3930 hdd_err("Invalid ATTR");
3931 return -EINVAL;
3932 }
3933
3934 req_msg = qdf_mem_malloc(sizeof(*req_msg));
3935 if (!req_msg)
3936 return -ENOMEM;
3937
3938 /* Parse and fetch request Id */
3939 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID;
3940 if (!tb[id]) {
3941 hdd_err("attr request id failed");
3942 goto fail;
3943 }
3944 req_msg->request_id = nla_get_u32(tb[id]);
3945
3946 req_msg->vdev_id = adapter->deflink->vdev_id;
3947 hdd_debug("Req Id %u Vdev Id %d",
3948 req_msg->request_id, req_msg->vdev_id);
3949
3950 status = sme_reset_passpoint_list(hdd_ctx->mac_handle, req_msg);
3951 if (!QDF_IS_STATUS_SUCCESS(status)) {
3952 hdd_err("sme_reset_passpoint_list failed(err=%d)", status);
3953 goto fail;
3954 }
3955
3956 hdd_exit();
3957 qdf_mem_free(req_msg);
3958 return 0;
3959
3960 fail:
3961 qdf_mem_free(req_msg);
3962 return -EINVAL;
3963 }
3964
3965 /**
3966 * wlan_hdd_cfg80211_reset_passpoint_list() - reset passpoint network list
3967 * @wiphy: wiphy
3968 * @wdev: pointer to wireless dev
3969 * @data: data pointer
3970 * @data_len: data length
3971 *
3972 * This function resets passpoint networks list
3973 *
3974 * Return: 0 on success, error number otherwise
3975 */
wlan_hdd_cfg80211_reset_passpoint_list(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)3976 int wlan_hdd_cfg80211_reset_passpoint_list(struct wiphy *wiphy,
3977 struct wireless_dev *wdev,
3978 const void *data,
3979 int data_len)
3980 {
3981 int errno;
3982 struct osif_vdev_sync *vdev_sync;
3983
3984 errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync);
3985 if (errno)
3986 return errno;
3987
3988 errno = __wlan_hdd_cfg80211_reset_passpoint_list(wiphy, wdev,
3989 data, data_len);
3990
3991 osif_vdev_sync_op_stop(vdev_sync);
3992
3993 return errno;
3994 }
3995
3996 /**
3997 * wlan_hdd_cfg80211_extscan_init() - Initialize the ExtScan feature
3998 * @hdd_ctx: Global HDD context
3999 *
4000 * Return: none
4001 */
wlan_hdd_cfg80211_extscan_init(struct hdd_context * hdd_ctx)4002 void wlan_hdd_cfg80211_extscan_init(struct hdd_context *hdd_ctx)
4003 {
4004 init_completion(&ext_scan_context.response_event);
4005 spin_lock_init(&ext_scan_context.context_lock);
4006 }
4007
4008 #endif /* FEATURE_WLAN_EXTSCAN */
4009