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