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, &params);
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, &params);
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, &params->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, &params->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, &params);
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, &params);
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, &params);
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