xref: /wlan-driver/qcacld-3.0/core/hdd/src/wlan_hdd_scan.c (revision 5113495b16420b49004c444715d2daae2066e7dc)
1*5113495bSYour Name /*
2*5113495bSYour Name  * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved.
3*5113495bSYour Name  * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
4*5113495bSYour Name  *
5*5113495bSYour Name  * Permission to use, copy, modify, and/or distribute this software for
6*5113495bSYour Name  * any purpose with or without fee is hereby granted, provided that the
7*5113495bSYour Name  * above copyright notice and this permission notice appear in all
8*5113495bSYour Name  * copies.
9*5113495bSYour Name  *
10*5113495bSYour Name  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11*5113495bSYour Name  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12*5113495bSYour Name  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13*5113495bSYour Name  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14*5113495bSYour Name  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15*5113495bSYour Name  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16*5113495bSYour Name  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17*5113495bSYour Name  * PERFORMANCE OF THIS SOFTWARE.
18*5113495bSYour Name  */
19*5113495bSYour Name 
20*5113495bSYour Name /**
21*5113495bSYour Name  * DOC: wlan_hdd_scan.c
22*5113495bSYour Name  *
23*5113495bSYour Name  * WLAN Host Device Driver scan implementation
24*5113495bSYour Name  */
25*5113495bSYour Name 
26*5113495bSYour Name #include <linux/wireless.h>
27*5113495bSYour Name #include <net/cfg80211.h>
28*5113495bSYour Name 
29*5113495bSYour Name #include "wlan_hdd_includes.h"
30*5113495bSYour Name #include "cds_api.h"
31*5113495bSYour Name #include "cds_api.h"
32*5113495bSYour Name #include "ani_global.h"
33*5113495bSYour Name #include "dot11f.h"
34*5113495bSYour Name #include "cds_sched.h"
35*5113495bSYour Name #include "osif_sync.h"
36*5113495bSYour Name #include "wlan_hdd_p2p.h"
37*5113495bSYour Name #include "wlan_hdd_trace.h"
38*5113495bSYour Name #include "wlan_hdd_scan.h"
39*5113495bSYour Name #include "wlan_policy_mgr_api.h"
40*5113495bSYour Name #include "wlan_hdd_power.h"
41*5113495bSYour Name #include "wma_api.h"
42*5113495bSYour Name #include "cds_utils.h"
43*5113495bSYour Name #include "wlan_p2p_ucfg_api.h"
44*5113495bSYour Name #include "cfg_ucfg_api.h"
45*5113495bSYour Name 
46*5113495bSYour Name #include <qca_vendor.h>
47*5113495bSYour Name #include <wlan_cfg80211_scan.h>
48*5113495bSYour Name #include "wlan_utility.h"
49*5113495bSYour Name #include "wlan_hdd_object_manager.h"
50*5113495bSYour Name #include "nan_ucfg_api.h"
51*5113495bSYour Name 
52*5113495bSYour Name #define SCAN_DONE_EVENT_BUF_SIZE 4096
53*5113495bSYour Name #define RATE_MASK 0x7f
54*5113495bSYour Name 
55*5113495bSYour Name /**
56*5113495bSYour Name  * hdd_vendor_scan_callback() - Scan completed callback event
57*5113495bSYour Name  * @adapter: HDD adapter
58*5113495bSYour Name  * @req: Scan request
59*5113495bSYour Name  * @aborted: true scan aborted false scan success
60*5113495bSYour Name  *
61*5113495bSYour Name  * This function sends scan completed callback event to NL.
62*5113495bSYour Name  *
63*5113495bSYour Name  * Return: none
64*5113495bSYour Name  */
hdd_vendor_scan_callback(struct hdd_adapter * adapter,struct cfg80211_scan_request * req,bool aborted)65*5113495bSYour Name static void hdd_vendor_scan_callback(struct hdd_adapter *adapter,
66*5113495bSYour Name 					struct cfg80211_scan_request *req,
67*5113495bSYour Name 					bool aborted)
68*5113495bSYour Name {
69*5113495bSYour Name 	struct hdd_context *hddctx = WLAN_HDD_GET_CTX(adapter);
70*5113495bSYour Name 	struct sk_buff *skb;
71*5113495bSYour Name 	struct nlattr *attr;
72*5113495bSYour Name 	int i;
73*5113495bSYour Name 	uint8_t scan_status;
74*5113495bSYour Name 	uint64_t cookie;
75*5113495bSYour Name 	enum qca_nl80211_vendor_subcmds_index index =
76*5113495bSYour Name 		QCA_NL80211_VENDOR_SUBCMD_SCAN_DONE_INDEX;
77*5113495bSYour Name 
78*5113495bSYour Name 	hdd_enter();
79*5113495bSYour Name 
80*5113495bSYour Name 	if (WLAN_HDD_ADAPTER_MAGIC != adapter->magic) {
81*5113495bSYour Name 		hdd_err("Invalid adapter magic");
82*5113495bSYour Name 		qdf_mem_free(req);
83*5113495bSYour Name 		return;
84*5113495bSYour Name 	}
85*5113495bSYour Name 	skb = wlan_cfg80211_vendor_event_alloc(hddctx->wiphy, &adapter->wdev,
86*5113495bSYour Name 					       SCAN_DONE_EVENT_BUF_SIZE +
87*5113495bSYour Name 					       4 + NLMSG_HDRLEN,
88*5113495bSYour Name 					       index, GFP_KERNEL);
89*5113495bSYour Name 	if (!skb) {
90*5113495bSYour Name 		hdd_err("skb alloc failed");
91*5113495bSYour Name 		qdf_mem_free(req);
92*5113495bSYour Name 		return;
93*5113495bSYour Name 	}
94*5113495bSYour Name 
95*5113495bSYour Name 	cookie = (uintptr_t)req;
96*5113495bSYour Name 	attr = nla_nest_start(skb, QCA_WLAN_VENDOR_ATTR_SCAN_SSIDS);
97*5113495bSYour Name 	if (!attr)
98*5113495bSYour Name 		goto nla_put_failure;
99*5113495bSYour Name 	for (i = 0; i < req->n_ssids; i++) {
100*5113495bSYour Name 		if (nla_put(skb, i, req->ssids[i].ssid_len,
101*5113495bSYour Name 			req->ssids[i].ssid)) {
102*5113495bSYour Name 			hdd_err("Failed to add ssid");
103*5113495bSYour Name 			goto nla_put_failure;
104*5113495bSYour Name 		}
105*5113495bSYour Name 	}
106*5113495bSYour Name 	nla_nest_end(skb, attr);
107*5113495bSYour Name 	attr = nla_nest_start(skb, QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES);
108*5113495bSYour Name 	if (!attr)
109*5113495bSYour Name 		goto nla_put_failure;
110*5113495bSYour Name 	for (i = 0; i < req->n_channels; i++) {
111*5113495bSYour Name 		if (nla_put_u32(skb, i, req->channels[i]->center_freq)) {
112*5113495bSYour Name 			hdd_err("Failed to add channel");
113*5113495bSYour Name 			goto nla_put_failure;
114*5113495bSYour Name 		}
115*5113495bSYour Name 	}
116*5113495bSYour Name 	nla_nest_end(skb, attr);
117*5113495bSYour Name 
118*5113495bSYour Name 	if (req->ie &&
119*5113495bSYour Name 		nla_put(skb, QCA_WLAN_VENDOR_ATTR_SCAN_IE, req->ie_len,
120*5113495bSYour Name 			req->ie)) {
121*5113495bSYour Name 		hdd_err("Failed to add scan ie");
122*5113495bSYour Name 		goto nla_put_failure;
123*5113495bSYour Name 	}
124*5113495bSYour Name 	if (req->flags &&
125*5113495bSYour Name 		nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_SCAN_FLAGS, req->flags)) {
126*5113495bSYour Name 		hdd_err("Failed to add scan flags");
127*5113495bSYour Name 		goto nla_put_failure;
128*5113495bSYour Name 	}
129*5113495bSYour Name 	if (hdd_wlan_nla_put_u64(skb,
130*5113495bSYour Name 				  QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE,
131*5113495bSYour Name 				  cookie)) {
132*5113495bSYour Name 		hdd_err("Failed to add scan cookie");
133*5113495bSYour Name 		goto nla_put_failure;
134*5113495bSYour Name 	}
135*5113495bSYour Name 	scan_status = (aborted == true) ? VENDOR_SCAN_STATUS_ABORTED :
136*5113495bSYour Name 		VENDOR_SCAN_STATUS_NEW_RESULTS;
137*5113495bSYour Name 	if (nla_put_u8(skb, QCA_WLAN_VENDOR_ATTR_SCAN_STATUS, scan_status)) {
138*5113495bSYour Name 		hdd_err("Failed to add scan status");
139*5113495bSYour Name 		goto nla_put_failure;
140*5113495bSYour Name 	}
141*5113495bSYour Name 	wlan_cfg80211_vendor_event(skb, GFP_KERNEL);
142*5113495bSYour Name 	hdd_info("scan complete event sent to NL");
143*5113495bSYour Name 	qdf_mem_free(req);
144*5113495bSYour Name 	return;
145*5113495bSYour Name 
146*5113495bSYour Name nla_put_failure:
147*5113495bSYour Name 	wlan_cfg80211_vendor_free_skb(skb);
148*5113495bSYour Name 	qdf_mem_free(req);
149*5113495bSYour Name }
150*5113495bSYour Name 
151*5113495bSYour Name #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0))
152*5113495bSYour Name /**
153*5113495bSYour Name  * hdd_cfg80211_scan_done() - Scan completed callback to cfg80211
154*5113495bSYour Name  * @adapter: Pointer to the adapter
155*5113495bSYour Name  * @req : Scan request
156*5113495bSYour Name  * @aborted : true scan aborted false scan success
157*5113495bSYour Name  *
158*5113495bSYour Name  * This function notifies scan done to cfg80211
159*5113495bSYour Name  *
160*5113495bSYour Name  * Return: none
161*5113495bSYour Name  */
hdd_cfg80211_scan_done(struct hdd_adapter * adapter,struct cfg80211_scan_request * req,bool aborted)162*5113495bSYour Name static void hdd_cfg80211_scan_done(struct hdd_adapter *adapter,
163*5113495bSYour Name 				   struct cfg80211_scan_request *req,
164*5113495bSYour Name 				   bool aborted)
165*5113495bSYour Name {
166*5113495bSYour Name 	struct cfg80211_scan_info info = {
167*5113495bSYour Name 		.aborted = aborted
168*5113495bSYour Name 	};
169*5113495bSYour Name 
170*5113495bSYour Name 	if (adapter->dev->flags & IFF_UP)
171*5113495bSYour Name 		cfg80211_scan_done(req, &info);
172*5113495bSYour Name }
173*5113495bSYour Name #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
174*5113495bSYour Name /**
175*5113495bSYour Name  * hdd_cfg80211_scan_done() - Scan completed callback to cfg80211
176*5113495bSYour Name  * @adapter: Pointer to the adapter
177*5113495bSYour Name  * @req : Scan request
178*5113495bSYour Name  * @aborted : true scan aborted false scan success
179*5113495bSYour Name  *
180*5113495bSYour Name  * This function notifies scan done to cfg80211
181*5113495bSYour Name  *
182*5113495bSYour Name  * Return: none
183*5113495bSYour Name  */
hdd_cfg80211_scan_done(struct hdd_adapter * adapter,struct cfg80211_scan_request * req,bool aborted)184*5113495bSYour Name static void hdd_cfg80211_scan_done(struct hdd_adapter *adapter,
185*5113495bSYour Name 				   struct cfg80211_scan_request *req,
186*5113495bSYour Name 				   bool aborted)
187*5113495bSYour Name {
188*5113495bSYour Name 	if (adapter->dev->flags & IFF_UP)
189*5113495bSYour Name 		cfg80211_scan_done(req, aborted);
190*5113495bSYour Name }
191*5113495bSYour Name #else
192*5113495bSYour Name /**
193*5113495bSYour Name  * hdd_cfg80211_scan_done() - Scan completed callback to cfg80211
194*5113495bSYour Name  * @adapter: Pointer to the adapter
195*5113495bSYour Name  * @req : Scan request
196*5113495bSYour Name  * @aborted : true scan aborted false scan success
197*5113495bSYour Name  *
198*5113495bSYour Name  * This function notifies scan done to cfg80211
199*5113495bSYour Name  *
200*5113495bSYour Name  * Return: none
201*5113495bSYour Name  */
hdd_cfg80211_scan_done(struct hdd_adapter * adapter,struct cfg80211_scan_request * req,bool aborted)202*5113495bSYour Name static void hdd_cfg80211_scan_done(struct hdd_adapter *adapter,
203*5113495bSYour Name 				   struct cfg80211_scan_request *req,
204*5113495bSYour Name 				   bool aborted)
205*5113495bSYour Name {
206*5113495bSYour Name 	cfg80211_scan_done(req, aborted);
207*5113495bSYour Name }
208*5113495bSYour Name #endif
209*5113495bSYour Name 
210*5113495bSYour Name #ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE
211*5113495bSYour Name /**
212*5113495bSYour Name  * wlan_hdd_sap_skip_scan_check() - The function will check OBSS
213*5113495bSYour Name  *         scan skip or not for SAP.
214*5113495bSYour Name  * @hdd_ctx: pointer to hdd context.
215*5113495bSYour Name  * @request: pointer to scan request.
216*5113495bSYour Name  *
217*5113495bSYour Name  * This function will check the scan request's chan list against the
218*5113495bSYour Name  * previous ACS scan chan list. If all the chan are covered by
219*5113495bSYour Name  * previous ACS scan, we can skip the scan and return scan complete
220*5113495bSYour Name  * to save the SAP starting time.
221*5113495bSYour Name  *
222*5113495bSYour Name  * Return: true to skip the scan,
223*5113495bSYour Name  *            false to continue the scan
224*5113495bSYour Name  */
wlan_hdd_sap_skip_scan_check(struct hdd_context * hdd_ctx,struct cfg80211_scan_request * request)225*5113495bSYour Name static bool wlan_hdd_sap_skip_scan_check(struct hdd_context *hdd_ctx,
226*5113495bSYour Name 	struct cfg80211_scan_request *request)
227*5113495bSYour Name {
228*5113495bSYour Name 	int i, j;
229*5113495bSYour Name 	bool skip;
230*5113495bSYour Name 
231*5113495bSYour Name 	hdd_debug("HDD_ACS_SKIP_STATUS = %d",
232*5113495bSYour Name 		hdd_ctx->skip_acs_scan_status);
233*5113495bSYour Name 	if (hdd_ctx->skip_acs_scan_status != eSAP_SKIP_ACS_SCAN)
234*5113495bSYour Name 		return false;
235*5113495bSYour Name 	qdf_spin_lock(&hdd_ctx->acs_skip_lock);
236*5113495bSYour Name 	if (!hdd_ctx->last_acs_freq_list ||
237*5113495bSYour Name 	    hdd_ctx->num_of_channels == 0 ||
238*5113495bSYour Name 	    request->n_channels == 0) {
239*5113495bSYour Name 		qdf_spin_unlock(&hdd_ctx->acs_skip_lock);
240*5113495bSYour Name 		return false;
241*5113495bSYour Name 	}
242*5113495bSYour Name 	skip = true;
243*5113495bSYour Name 	for (i = 0; i < request->n_channels ; i++) {
244*5113495bSYour Name 		bool find = false;
245*5113495bSYour Name 
246*5113495bSYour Name 		for (j = 0; j < hdd_ctx->num_of_channels; j++) {
247*5113495bSYour Name 			if (hdd_ctx->last_acs_freq_list[j] ==
248*5113495bSYour Name 			    request->channels[i]->center_freq) {
249*5113495bSYour Name 				find = true;
250*5113495bSYour Name 				break;
251*5113495bSYour Name 			}
252*5113495bSYour Name 		}
253*5113495bSYour Name 		if (!find) {
254*5113495bSYour Name 			skip = false;
255*5113495bSYour Name 			hdd_debug("Freq %d isn't in ACS freq list",
256*5113495bSYour Name 				  request->channels[i]->center_freq);
257*5113495bSYour Name 			break;
258*5113495bSYour Name 		}
259*5113495bSYour Name 	}
260*5113495bSYour Name 	qdf_spin_unlock(&hdd_ctx->acs_skip_lock);
261*5113495bSYour Name 	return skip;
262*5113495bSYour Name }
263*5113495bSYour Name #else
wlan_hdd_sap_skip_scan_check(struct hdd_context * hdd_ctx,struct cfg80211_scan_request * request)264*5113495bSYour Name static bool wlan_hdd_sap_skip_scan_check(struct hdd_context *hdd_ctx,
265*5113495bSYour Name 	struct cfg80211_scan_request *request)
266*5113495bSYour Name {
267*5113495bSYour Name 	return false;
268*5113495bSYour Name }
269*5113495bSYour Name #endif
270*5113495bSYour Name 
wlan_hdd_cfg80211_scan_block(struct hdd_adapter * adapter)271*5113495bSYour Name void wlan_hdd_cfg80211_scan_block(struct hdd_adapter *adapter)
272*5113495bSYour Name {
273*5113495bSYour Name 	struct cfg80211_scan_request *request;
274*5113495bSYour Name 	struct scan_req *blocked_scan_req;
275*5113495bSYour Name 	qdf_list_node_t *node;
276*5113495bSYour Name 
277*5113495bSYour Name 	if (adapter->magic != WLAN_HDD_ADAPTER_MAGIC) {
278*5113495bSYour Name 		hdd_err("HDD adapter context is invalid");
279*5113495bSYour Name 		return;
280*5113495bSYour Name 	}
281*5113495bSYour Name 
282*5113495bSYour Name 	qdf_mutex_acquire(&adapter->blocked_scan_request_q_lock);
283*5113495bSYour Name 
284*5113495bSYour Name 	while (!qdf_list_empty(&adapter->blocked_scan_request_q)) {
285*5113495bSYour Name 		qdf_list_remove_front(&adapter->blocked_scan_request_q,
286*5113495bSYour Name 				      &node);
287*5113495bSYour Name 		blocked_scan_req = qdf_container_of(node, struct scan_req,
288*5113495bSYour Name 						    node);
289*5113495bSYour Name 		request = blocked_scan_req->scan_request;
290*5113495bSYour Name 		request->n_ssids = 0;
291*5113495bSYour Name 		request->n_channels = 0;
292*5113495bSYour Name 		if (blocked_scan_req->source == NL_SCAN) {
293*5113495bSYour Name 			hdd_err("Scan aborted. Null result sent");
294*5113495bSYour Name 			hdd_cfg80211_scan_done(adapter, request, true);
295*5113495bSYour Name 		} else {
296*5113495bSYour Name 			hdd_err("Vendor scan aborted. Null result sent");
297*5113495bSYour Name 			hdd_vendor_scan_callback(adapter, request, true);
298*5113495bSYour Name 		}
299*5113495bSYour Name 		qdf_mem_free(blocked_scan_req);
300*5113495bSYour Name 	}
301*5113495bSYour Name 
302*5113495bSYour Name 	qdf_mutex_release(&adapter->blocked_scan_request_q_lock);
303*5113495bSYour Name }
304*5113495bSYour Name 
hdd_init_scan_reject_params(struct hdd_context * hdd_ctx)305*5113495bSYour Name void hdd_init_scan_reject_params(struct hdd_context *hdd_ctx)
306*5113495bSYour Name {
307*5113495bSYour Name 	if (hdd_ctx) {
308*5113495bSYour Name 		hdd_ctx->last_scan_reject_timestamp = 0;
309*5113495bSYour Name 		hdd_ctx->last_scan_reject_vdev_id = WLAN_UMAC_VDEV_ID_MAX;
310*5113495bSYour Name 		hdd_ctx->last_scan_reject_reason = 0;
311*5113495bSYour Name 		hdd_ctx->scan_reject_cnt = 0;
312*5113495bSYour Name 	}
313*5113495bSYour Name }
314*5113495bSYour Name 
315*5113495bSYour Name /*
316*5113495bSYour Name  * wlan_hdd_update_scan_ies() - API to update the scan IEs of scan request
317*5113495bSYour Name  * with already stored default scan IEs
318*5113495bSYour Name  *
319*5113495bSYour Name  * @adapter: Pointer to HDD adapter
320*5113495bSYour Name  * @scan_info: Pointer to scan info in HDD adapter
321*5113495bSYour Name  * @scan_ie: Pointer to scan IE in scan request
322*5113495bSYour Name  * @scan_ie_len: Pointer to scan IE length in scan request
323*5113495bSYour Name  *
324*5113495bSYour Name  * Return: 0 on success; error number otherwise
325*5113495bSYour Name  */
wlan_hdd_update_scan_ies(struct hdd_adapter * adapter,struct hdd_scan_info * scan_info,uint8_t * scan_ie,uint16_t * scan_ie_len)326*5113495bSYour Name static int wlan_hdd_update_scan_ies(struct hdd_adapter *adapter,
327*5113495bSYour Name 			struct hdd_scan_info *scan_info, uint8_t *scan_ie,
328*5113495bSYour Name 			uint16_t *scan_ie_len)
329*5113495bSYour Name {
330*5113495bSYour Name 	uint16_t rem_len = scan_info->default_scan_ies_len;
331*5113495bSYour Name 	uint8_t *temp_ie = scan_info->default_scan_ies;
332*5113495bSYour Name 	uint8_t *current_ie;
333*5113495bSYour Name 	const uint8_t *mbo_ie;
334*5113495bSYour Name 	uint8_t elem_id;
335*5113495bSYour Name 	uint16_t elem_len;
336*5113495bSYour Name 	bool add_ie = false;
337*5113495bSYour Name 
338*5113495bSYour Name 	if (!scan_info->default_scan_ies_len || !scan_info->default_scan_ies)
339*5113495bSYour Name 		return 0;
340*5113495bSYour Name 
341*5113495bSYour Name 	mbo_ie = wlan_get_vendor_ie_ptr_from_oui(MBO_OUI_TYPE,
342*5113495bSYour Name 						 MBO_OUI_TYPE_SIZE, scan_ie,
343*5113495bSYour Name 						 *scan_ie_len);
344*5113495bSYour Name 	while (rem_len >= 2) {
345*5113495bSYour Name 		current_ie = temp_ie;
346*5113495bSYour Name 		elem_id = *temp_ie++;
347*5113495bSYour Name 		elem_len = *temp_ie++;
348*5113495bSYour Name 		rem_len -= 2;
349*5113495bSYour Name 
350*5113495bSYour Name 		if (elem_len > rem_len) {
351*5113495bSYour Name 			hdd_err("Invalid element len %d for elem %d", elem_len,
352*5113495bSYour Name 				elem_id);
353*5113495bSYour Name 			return 0;
354*5113495bSYour Name 		}
355*5113495bSYour Name 
356*5113495bSYour Name 		switch (elem_id) {
357*5113495bSYour Name 		case DOT11F_EID_EXTCAP:
358*5113495bSYour Name 			if (!wlan_get_ie_ptr_from_eid(DOT11F_EID_EXTCAP,
359*5113495bSYour Name 						      scan_ie, *scan_ie_len))
360*5113495bSYour Name 				add_ie = true;
361*5113495bSYour Name 			break;
362*5113495bSYour Name 		case WLAN_ELEMID_VENDOR:
363*5113495bSYour Name 			/* Donot add MBO IE if its already present */
364*5113495bSYour Name 			if ((!mbo_ie &&
365*5113495bSYour Name 			     0 == qdf_mem_cmp(&temp_ie[0], MBO_OUI_TYPE,
366*5113495bSYour Name 					      MBO_OUI_TYPE_SIZE)) ||
367*5113495bSYour Name 			    (0 == qdf_mem_cmp(&temp_ie[0], QCN_OUI_TYPE,
368*5113495bSYour Name 					      QCN_OUI_TYPE_SIZE)))
369*5113495bSYour Name 				add_ie = true;
370*5113495bSYour Name 			break;
371*5113495bSYour Name 		}
372*5113495bSYour Name 
373*5113495bSYour Name 		if (add_ie && (((*scan_ie_len) + elem_len) >
374*5113495bSYour Name 					SIR_MAC_MAX_ADD_IE_LENGTH)){
375*5113495bSYour Name 			hdd_err("Not enough buffer to save default scan IE's");
376*5113495bSYour Name 			return 0;
377*5113495bSYour Name 		}
378*5113495bSYour Name 
379*5113495bSYour Name 		if (add_ie) {
380*5113495bSYour Name 			qdf_mem_copy(scan_ie + (*scan_ie_len),
381*5113495bSYour Name 						current_ie, elem_len + 2);
382*5113495bSYour Name 			(*scan_ie_len) += (elem_len + 2);
383*5113495bSYour Name 			add_ie = false;
384*5113495bSYour Name 		}
385*5113495bSYour Name 
386*5113495bSYour Name 		temp_ie += elem_len;
387*5113495bSYour Name 		rem_len -= elem_len;
388*5113495bSYour Name 	}
389*5113495bSYour Name 	return 0;
390*5113495bSYour Name }
391*5113495bSYour Name 
392*5113495bSYour Name static int
wlan_hdd_enqueue_blocked_scan_request(struct net_device * dev,struct cfg80211_scan_request * request,uint8_t source)393*5113495bSYour Name wlan_hdd_enqueue_blocked_scan_request(struct net_device *dev,
394*5113495bSYour Name 				      struct cfg80211_scan_request *request,
395*5113495bSYour Name 				      uint8_t source)
396*5113495bSYour Name {
397*5113495bSYour Name 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
398*5113495bSYour Name 	struct scan_req *blocked_scan_req =
399*5113495bSYour Name 		qdf_mem_malloc(sizeof(*blocked_scan_req));
400*5113495bSYour Name 	int ret = 0;
401*5113495bSYour Name 
402*5113495bSYour Name 	if (!blocked_scan_req)
403*5113495bSYour Name 		return -EINVAL;
404*5113495bSYour Name 
405*5113495bSYour Name 	blocked_scan_req->dev = dev;
406*5113495bSYour Name 	blocked_scan_req->scan_request = request;
407*5113495bSYour Name 	blocked_scan_req->source = source;
408*5113495bSYour Name 	blocked_scan_req->scan_id = 0;
409*5113495bSYour Name 
410*5113495bSYour Name 	qdf_mutex_acquire(&adapter->blocked_scan_request_q_lock);
411*5113495bSYour Name 	if (qdf_list_size(&adapter->blocked_scan_request_q) <
412*5113495bSYour Name 		WLAN_MAX_SCAN_COUNT)
413*5113495bSYour Name 		qdf_list_insert_back(&adapter->blocked_scan_request_q,
414*5113495bSYour Name 				     &blocked_scan_req->node);
415*5113495bSYour Name 	else
416*5113495bSYour Name 		ret = -EINVAL;
417*5113495bSYour Name 	qdf_mutex_release(&adapter->blocked_scan_request_q_lock);
418*5113495bSYour Name 
419*5113495bSYour Name 	if (ret) {
420*5113495bSYour Name 		hdd_err("Maximum number of block scan request reached!");
421*5113495bSYour Name 		qdf_mem_free(blocked_scan_req);
422*5113495bSYour Name 	}
423*5113495bSYour Name 
424*5113495bSYour Name 	return ret;
425*5113495bSYour Name }
426*5113495bSYour Name 
427*5113495bSYour Name /* Define short name to use in cds_trigger_recovery */
428*5113495bSYour Name #define SCAN_FAILURE QDF_SCAN_ATTEMPT_FAILURES
429*5113495bSYour Name 
430*5113495bSYour Name /**
431*5113495bSYour Name  * __wlan_hdd_cfg80211_scan() - API to process cfg80211 scan request
432*5113495bSYour Name  * @wiphy: Pointer to wiphy
433*5113495bSYour Name  * @request: Pointer to scan request
434*5113495bSYour Name  * @source: scan request source(NL/Vendor scan)
435*5113495bSYour Name  *
436*5113495bSYour Name  * This API responds to scan trigger and update cfg80211 scan database
437*5113495bSYour Name  * later, scan dump command can be used to receive scan results
438*5113495bSYour Name  *
439*5113495bSYour Name  * Return: 0 for success, non zero for failure
440*5113495bSYour Name  */
__wlan_hdd_cfg80211_scan(struct wiphy * wiphy,struct cfg80211_scan_request * request,uint8_t source)441*5113495bSYour Name static int __wlan_hdd_cfg80211_scan(struct wiphy *wiphy,
442*5113495bSYour Name 				    struct cfg80211_scan_request *request,
443*5113495bSYour Name 				    uint8_t source)
444*5113495bSYour Name {
445*5113495bSYour Name 	struct net_device *dev = request->wdev->netdev;
446*5113495bSYour Name 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
447*5113495bSYour Name 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
448*5113495bSYour Name 	int status;
449*5113495bSYour Name 	struct hdd_scan_info *scan_info = NULL;
450*5113495bSYour Name 	struct hdd_adapter *con_sap_adapter;
451*5113495bSYour Name 	struct hdd_ap_ctx *ap_ctx;
452*5113495bSYour Name 	qdf_freq_t con_dfs_ch_freq;
453*5113495bSYour Name 	uint8_t curr_vdev_id;
454*5113495bSYour Name 	enum scan_reject_states curr_reason;
455*5113495bSYour Name 	static uint32_t scan_ebusy_cnt;
456*5113495bSYour Name 	struct scan_params params = {0};
457*5113495bSYour Name 	bool self_recovery;
458*5113495bSYour Name 	struct wlan_objmgr_vdev *vdev;
459*5113495bSYour Name 	QDF_STATUS qdf_status;
460*5113495bSYour Name 	bool enable_connected_scan;
461*5113495bSYour Name 	enum phy_ch_width con_dfs_ch_width;
462*5113495bSYour Name 
463*5113495bSYour Name 	if (cds_is_fw_down()) {
464*5113495bSYour Name 		hdd_err("firmware is down, scan cmd cannot be processed");
465*5113495bSYour Name 		return -EINVAL;
466*5113495bSYour Name 	}
467*5113495bSYour Name 
468*5113495bSYour Name 	if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
469*5113495bSYour Name 		hdd_err("Command not allowed in FTM mode");
470*5113495bSYour Name 		return -EINVAL;
471*5113495bSYour Name 	}
472*5113495bSYour Name 
473*5113495bSYour Name 	if (wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id))
474*5113495bSYour Name 		return -EINVAL;
475*5113495bSYour Name 
476*5113495bSYour Name 	status = wlan_hdd_validate_context(hdd_ctx);
477*5113495bSYour Name 	if (0 != status)
478*5113495bSYour Name 		return status;
479*5113495bSYour Name 
480*5113495bSYour Name 	qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
481*5113495bSYour Name 		   TRACE_CODE_HDD_CFG80211_SCAN,
482*5113495bSYour Name 		   adapter->deflink->vdev_id, request->n_channels);
483*5113495bSYour Name 
484*5113495bSYour Name 	if (!sme_is_session_id_valid(hdd_ctx->mac_handle,
485*5113495bSYour Name 				     adapter->deflink->vdev_id))
486*5113495bSYour Name 		return -EINVAL;
487*5113495bSYour Name 
488*5113495bSYour Name 	qdf_status = ucfg_mlme_get_self_recovery(hdd_ctx->psoc, &self_recovery);
489*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(qdf_status)) {
490*5113495bSYour Name 		hdd_err("Failed to get self recovery ini config");
491*5113495bSYour Name 		return -EIO;
492*5113495bSYour Name 	}
493*5113495bSYour Name 
494*5113495bSYour Name 	enable_connected_scan = ucfg_scan_is_connected_scan_enabled(
495*5113495bSYour Name 							hdd_ctx->psoc);
496*5113495bSYour Name 	if (!enable_connected_scan &&
497*5113495bSYour Name 	    hdd_cm_is_vdev_associated(adapter->deflink)) {
498*5113495bSYour Name 		hdd_info("enable_connected_scan is false, Aborting scan");
499*5113495bSYour Name 		if (wlan_hdd_enqueue_blocked_scan_request(dev, request, source))
500*5113495bSYour Name 			return -EAGAIN;
501*5113495bSYour Name 		schedule_work(&adapter->scan_block_work);
502*5113495bSYour Name 		return 0;
503*5113495bSYour Name 	}
504*5113495bSYour Name 
505*5113495bSYour Name 	/*
506*5113495bSYour Name 	 * NDI and monitor mode don't need scan from userspace to establish
507*5113495bSYour Name 	 * connection and it does not support scan request either.
508*5113495bSYour Name 	 */
509*5113495bSYour Name 	if (QDF_NDI_MODE == adapter->device_mode ||
510*5113495bSYour Name 	    QDF_MONITOR_MODE == adapter->device_mode) {
511*5113495bSYour Name 		hdd_err("Scan not supported for %s",
512*5113495bSYour Name 			qdf_opmode_str(adapter->device_mode));
513*5113495bSYour Name 		return -EINVAL;
514*5113495bSYour Name 	}
515*5113495bSYour Name 
516*5113495bSYour Name 	scan_info = &adapter->scan_info;
517*5113495bSYour Name 
518*5113495bSYour Name 	/* Block All Scan during DFS operation and send null scan result */
519*5113495bSYour Name 
520*5113495bSYour Name 	con_sap_adapter = hdd_get_con_sap_adapter(adapter, true);
521*5113495bSYour Name 	if (con_sap_adapter) {
522*5113495bSYour Name 		ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(con_sap_adapter->deflink);
523*5113495bSYour Name 		con_dfs_ch_freq = ap_ctx->sap_config.chan_freq;
524*5113495bSYour Name 		con_dfs_ch_width = ap_ctx->sap_config.ch_params.ch_width;
525*5113495bSYour Name 		if (con_dfs_ch_freq == AUTO_CHANNEL_SELECT)
526*5113495bSYour Name 			con_dfs_ch_freq = ap_ctx->operating_chan_freq;
527*5113495bSYour Name 
528*5113495bSYour Name 		if (!policy_mgr_is_hw_dbs_capable(hdd_ctx->psoc) &&
529*5113495bSYour Name 		    !policy_mgr_is_sta_sap_scc_allowed_on_dfs_chan(
530*5113495bSYour Name 		    hdd_ctx->psoc) &&
531*5113495bSYour Name 		    (wlan_reg_is_dfs_for_freq(hdd_ctx->pdev, con_dfs_ch_freq) ||
532*5113495bSYour Name 		    (wlan_reg_is_5ghz_ch_freq(con_dfs_ch_freq) &&
533*5113495bSYour Name 		     con_dfs_ch_width == CH_WIDTH_160MHZ))) {
534*5113495bSYour Name 			/* Provide empty scan result during DFS operation since
535*5113495bSYour Name 			 * scanning not supported during DFS. Reason is
536*5113495bSYour Name 			 * following case:
537*5113495bSYour Name 			 * DFS is supported only in SCC for MBSSID Mode.
538*5113495bSYour Name 			 * We shall not return EBUSY or ENOTSUPP as when Primary
539*5113495bSYour Name 			 * AP is operating in DFS channel and secondary AP is
540*5113495bSYour Name 			 * started. Though we force SCC in driver, the hostapd
541*5113495bSYour Name 			 * issues obss scan before starting secAP. This results
542*5113495bSYour Name 			 * in MCC in DFS mode. Thus we return null scan result.
543*5113495bSYour Name 			 * If we return scan failure hostapd fails secondary AP
544*5113495bSYour Name 			 * startup.
545*5113495bSYour Name 			 */
546*5113495bSYour Name 			hdd_err("##In DFS Master mode. Scan aborted");
547*5113495bSYour Name 			if (wlan_hdd_enqueue_blocked_scan_request(dev, request,
548*5113495bSYour Name 								  source))
549*5113495bSYour Name 				return -EAGAIN;
550*5113495bSYour Name 			schedule_work(&adapter->scan_block_work);
551*5113495bSYour Name 			return 0;
552*5113495bSYour Name 		}
553*5113495bSYour Name 	}
554*5113495bSYour Name 
555*5113495bSYour Name 	/* Check if scan is allowed at this point of time */
556*5113495bSYour Name 	if (hdd_is_connection_in_progress(&curr_vdev_id, &curr_reason)) {
557*5113495bSYour Name 		scan_ebusy_cnt++;
558*5113495bSYour Name 		hdd_err_rl("Scan not allowed. scan_ebusy_cnt: %d Session %d Reason %d",
559*5113495bSYour Name 			   scan_ebusy_cnt, curr_vdev_id, curr_reason);
560*5113495bSYour Name 		if (hdd_ctx->last_scan_reject_vdev_id != curr_vdev_id ||
561*5113495bSYour Name 		    hdd_ctx->last_scan_reject_reason != curr_reason ||
562*5113495bSYour Name 		    !hdd_ctx->last_scan_reject_timestamp) {
563*5113495bSYour Name 			hdd_ctx->last_scan_reject_vdev_id = curr_vdev_id;
564*5113495bSYour Name 			hdd_ctx->last_scan_reject_reason = curr_reason;
565*5113495bSYour Name 			hdd_ctx->last_scan_reject_timestamp = jiffies +
566*5113495bSYour Name 				msecs_to_jiffies(SCAN_REJECT_THRESHOLD_TIME);
567*5113495bSYour Name 			hdd_ctx->scan_reject_cnt = 0;
568*5113495bSYour Name 		} else {
569*5113495bSYour Name 			hdd_ctx->scan_reject_cnt++;
570*5113495bSYour Name 			if ((hdd_ctx->scan_reject_cnt >=
571*5113495bSYour Name 			   SCAN_REJECT_THRESHOLD) &&
572*5113495bSYour Name 			   qdf_system_time_after(jiffies,
573*5113495bSYour Name 			   hdd_ctx->last_scan_reject_timestamp)) {
574*5113495bSYour Name 				hdd_err("scan reject threshold reached Session %d Reason %d count %d reject timestamp %lu jiffies %lu",
575*5113495bSYour Name 					curr_vdev_id, curr_reason,
576*5113495bSYour Name 					hdd_ctx->scan_reject_cnt,
577*5113495bSYour Name 					hdd_ctx->last_scan_reject_timestamp,
578*5113495bSYour Name 					jiffies);
579*5113495bSYour Name 				hdd_ctx->last_scan_reject_timestamp = 0;
580*5113495bSYour Name 				hdd_ctx->scan_reject_cnt = 0;
581*5113495bSYour Name 				if (cds_is_fatal_event_enabled()) {
582*5113495bSYour Name 					cds_flush_logs(WLAN_LOG_TYPE_FATAL,
583*5113495bSYour Name 					   WLAN_LOG_INDICATOR_HOST_DRIVER,
584*5113495bSYour Name 					   WLAN_LOG_REASON_SCAN_NOT_ALLOWED,
585*5113495bSYour Name 					   false,
586*5113495bSYour Name 					   self_recovery);
587*5113495bSYour Name 				} else {
588*5113495bSYour Name 					hdd_err("Triggering SSR due to scan stuck");
589*5113495bSYour Name 					cds_trigger_recovery(SCAN_FAILURE);
590*5113495bSYour Name 				}
591*5113495bSYour Name 			}
592*5113495bSYour Name 		}
593*5113495bSYour Name 		return -EBUSY;
594*5113495bSYour Name 	}
595*5113495bSYour Name 
596*5113495bSYour Name 	hdd_init_scan_reject_params(hdd_ctx);
597*5113495bSYour Name 
598*5113495bSYour Name 	/* Check whether SAP scan can be skipped or not */
599*5113495bSYour Name 	if (adapter->device_mode == QDF_SAP_MODE &&
600*5113495bSYour Name 	   wlan_hdd_sap_skip_scan_check(hdd_ctx, request)) {
601*5113495bSYour Name 		hdd_debug("sap scan skipped");
602*5113495bSYour Name 		if (wlan_hdd_enqueue_blocked_scan_request(dev, request, source))
603*5113495bSYour Name 			return -EAGAIN;
604*5113495bSYour Name 		schedule_work(&adapter->scan_block_work);
605*5113495bSYour Name 		return 0;
606*5113495bSYour Name 	}
607*5113495bSYour Name 
608*5113495bSYour Name 	params.source = source;
609*5113495bSYour Name 	params.default_ie.len = 0;
610*5113495bSYour Name 	/* Store the Scan IE's in Adapter*/
611*5113495bSYour Name 	if (request->ie_len) {
612*5113495bSYour Name 		if (request->ie_len > SIR_MAC_MAX_ADD_IE_LENGTH) {
613*5113495bSYour Name 			hdd_debug("Invalid ie_len: %zu", request->ie_len);
614*5113495bSYour Name 			return -EINVAL;
615*5113495bSYour Name 		}
616*5113495bSYour Name 
617*5113495bSYour Name 		/* save this for future association (join requires this) */
618*5113495bSYour Name 		memset(&scan_info->scan_add_ie, 0, sizeof(scan_info->scan_add_ie));
619*5113495bSYour Name 		memcpy(scan_info->scan_add_ie.addIEdata, request->ie,
620*5113495bSYour Name 		       request->ie_len);
621*5113495bSYour Name 		scan_info->scan_add_ie.length = request->ie_len;
622*5113495bSYour Name 
623*5113495bSYour Name 		wlan_hdd_update_scan_ies(adapter, scan_info,
624*5113495bSYour Name 				scan_info->scan_add_ie.addIEdata,
625*5113495bSYour Name 				&scan_info->scan_add_ie.length);
626*5113495bSYour Name 	} else {
627*5113495bSYour Name 		if (scan_info->default_scan_ies &&
628*5113495bSYour Name 		    scan_info->default_scan_ies_len) {
629*5113495bSYour Name 			qdf_mem_copy(scan_info->scan_add_ie.addIEdata,
630*5113495bSYour Name 				     scan_info->default_scan_ies,
631*5113495bSYour Name 				     scan_info->default_scan_ies_len);
632*5113495bSYour Name 			scan_info->scan_add_ie.length =
633*5113495bSYour Name 				scan_info->default_scan_ies_len;
634*5113495bSYour Name 			params.default_ie.ptr =
635*5113495bSYour Name 				qdf_mem_malloc(scan_info->default_scan_ies_len);
636*5113495bSYour Name 			if (params.default_ie.ptr) {
637*5113495bSYour Name 				qdf_mem_copy(params.default_ie.ptr,
638*5113495bSYour Name 					     scan_info->default_scan_ies,
639*5113495bSYour Name 					     scan_info->default_scan_ies_len);
640*5113495bSYour Name 				params.default_ie.len =
641*5113495bSYour Name 						scan_info->default_scan_ies_len;
642*5113495bSYour Name 			}
643*5113495bSYour Name 		}
644*5113495bSYour Name 	}
645*5113495bSYour Name 
646*5113495bSYour Name 	if (QDF_P2P_CLIENT_MODE == adapter->device_mode ||
647*5113495bSYour Name 	    QDF_P2P_DEVICE_MODE == adapter->device_mode) {
648*5113495bSYour Name 		/* Disable NAN Discovery if enabled */
649*5113495bSYour Name 		ucfg_nan_disable_concurrency(hdd_ctx->psoc);
650*5113495bSYour Name 	}
651*5113495bSYour Name 
652*5113495bSYour Name 	vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_OSIF_SCAN_ID);
653*5113495bSYour Name 	if (!vdev) {
654*5113495bSYour Name 		status = -EINVAL;
655*5113495bSYour Name 		goto error;
656*5113495bSYour Name 	}
657*5113495bSYour Name 
658*5113495bSYour Name 	if ((request->n_ssids == 1) && (request->ssids) &&
659*5113495bSYour Name 	    (request->ssids[0].ssid_len > 7) &&
660*5113495bSYour Name 	     !qdf_mem_cmp(&request->ssids[0], "DIRECT-", 7))
661*5113495bSYour Name 		ucfg_p2p_status_scan(vdev);
662*5113495bSYour Name 
663*5113495bSYour Name 	/* If this a scan on SAP adapter, use scan priority high */
664*5113495bSYour Name 	if (adapter->device_mode == QDF_SAP_MODE)
665*5113495bSYour Name 		params.priority = SCAN_PRIORITY_HIGH;
666*5113495bSYour Name 	else
667*5113495bSYour Name 		/* Use default scan priority */
668*5113495bSYour Name 		params.priority = SCAN_PRIORITY_COUNT;
669*5113495bSYour Name 
670*5113495bSYour Name 	status = ucfg_mlme_get_scan_probe_unicast_ra(
671*5113495bSYour Name 						hdd_ctx->psoc,
672*5113495bSYour Name 						&params.scan_probe_unicast_ra);
673*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status))
674*5113495bSYour Name 		hdd_err("Failed to get unicast probe req ra cfg");
675*5113495bSYour Name 
676*5113495bSYour Name 	params.mld_id = ucfg_mlme_get_eht_mld_id(hdd_ctx->psoc);
677*5113495bSYour Name 	hdd_debug("MLD ID: %d", params.mld_id);
678*5113495bSYour Name 
679*5113495bSYour Name 	status = wlan_cfg80211_scan(vdev, request, &params);
680*5113495bSYour Name 	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_SCAN_ID);
681*5113495bSYour Name error:
682*5113495bSYour Name 	if (params.default_ie.ptr)
683*5113495bSYour Name 		qdf_mem_free(params.default_ie.ptr);
684*5113495bSYour Name 
685*5113495bSYour Name 	return status;
686*5113495bSYour Name }
687*5113495bSYour Name 
688*5113495bSYour Name #undef SCAN_FAILURE
689*5113495bSYour Name 
690*5113495bSYour Name /**
691*5113495bSYour Name  * wlan_hdd_cfg80211_scan() - API to process cfg80211 scan request
692*5113495bSYour Name  * @wiphy: Pointer to wiphy
693*5113495bSYour Name  * @request: Pointer to scan request
694*5113495bSYour Name  *
695*5113495bSYour Name  * This API responds to scan trigger and update cfg80211 scan database
696*5113495bSYour Name  * later, scan dump command can be used to receive scan results
697*5113495bSYour Name  *
698*5113495bSYour Name  * Return: 0 for success, non zero for failure
699*5113495bSYour Name  */
wlan_hdd_cfg80211_scan(struct wiphy * wiphy,struct cfg80211_scan_request * request)700*5113495bSYour Name int wlan_hdd_cfg80211_scan(struct wiphy *wiphy,
701*5113495bSYour Name 			   struct cfg80211_scan_request *request)
702*5113495bSYour Name {
703*5113495bSYour Name 	int errno;
704*5113495bSYour Name 	struct osif_vdev_sync *vdev_sync;
705*5113495bSYour Name 
706*5113495bSYour Name 	errno = osif_vdev_sync_op_start(request->wdev->netdev, &vdev_sync);
707*5113495bSYour Name 	if (errno)
708*5113495bSYour Name 		return errno;
709*5113495bSYour Name 
710*5113495bSYour Name 	errno = __wlan_hdd_cfg80211_scan(wiphy, request, NL_SCAN);
711*5113495bSYour Name 
712*5113495bSYour Name 	osif_vdev_sync_op_stop(vdev_sync);
713*5113495bSYour Name 
714*5113495bSYour Name 	return errno;
715*5113495bSYour Name }
716*5113495bSYour Name 
717*5113495bSYour Name /**
718*5113495bSYour Name  * wlan_hdd_get_rates() -API to get the rates from scan request
719*5113495bSYour Name  * @wiphy: Pointer to wiphy
720*5113495bSYour Name  * @band: Band
721*5113495bSYour Name  * @rates: array of rates
722*5113495bSYour Name  * @rate_count: number of rates
723*5113495bSYour Name  *
724*5113495bSYour Name  * Return: o for failure, rate bitmap for success
725*5113495bSYour Name  */
wlan_hdd_get_rates(struct wiphy * wiphy,enum nl80211_band band,const u8 * rates,unsigned int rate_count)726*5113495bSYour Name static uint32_t wlan_hdd_get_rates(struct wiphy *wiphy,
727*5113495bSYour Name 	enum nl80211_band band,
728*5113495bSYour Name 	const u8 *rates, unsigned int rate_count)
729*5113495bSYour Name {
730*5113495bSYour Name 	uint32_t j, count, rate_bitmap = 0;
731*5113495bSYour Name 	uint32_t rate;
732*5113495bSYour Name 	bool found;
733*5113495bSYour Name 
734*5113495bSYour Name 	for (count = 0; count < rate_count; count++) {
735*5113495bSYour Name 		rate = ((rates[count]) & RATE_MASK) * 5;
736*5113495bSYour Name 		found = false;
737*5113495bSYour Name 		for (j = 0; j < wiphy->bands[band]->n_bitrates; j++) {
738*5113495bSYour Name 			if (wiphy->bands[band]->bitrates[j].bitrate == rate) {
739*5113495bSYour Name 				found = true;
740*5113495bSYour Name 				rate_bitmap |= (1 << j);
741*5113495bSYour Name 				break;
742*5113495bSYour Name 			}
743*5113495bSYour Name 		}
744*5113495bSYour Name 		if (!found)
745*5113495bSYour Name 			return 0;
746*5113495bSYour Name 	}
747*5113495bSYour Name 	return rate_bitmap;
748*5113495bSYour Name }
749*5113495bSYour Name 
750*5113495bSYour Name /**
751*5113495bSYour Name  * wlan_hdd_send_scan_start_event() -API to send the scan start event
752*5113495bSYour Name  * @wiphy: Pointer to wiphy
753*5113495bSYour Name  * @wdev: Pointer to net device
754*5113495bSYour Name  * @cookie: scan identifier
755*5113495bSYour Name  *
756*5113495bSYour Name  * Return: return 0 on success and negative error code on failure
757*5113495bSYour Name  */
wlan_hdd_send_scan_start_event(struct wiphy * wiphy,struct wireless_dev * wdev,uint64_t cookie)758*5113495bSYour Name static int wlan_hdd_send_scan_start_event(struct wiphy *wiphy,
759*5113495bSYour Name 		struct wireless_dev *wdev, uint64_t cookie)
760*5113495bSYour Name {
761*5113495bSYour Name 	struct sk_buff *skb;
762*5113495bSYour Name 	int ret;
763*5113495bSYour Name 	enum qca_nl80211_vendor_subcmds_index index =
764*5113495bSYour Name 		QCA_NL80211_VENDOR_SUBCMD_SCAN_INDEX;
765*5113495bSYour Name 
766*5113495bSYour Name 	skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(wiphy, sizeof(u64) +
767*5113495bSYour Name 			NLA_HDRLEN + NLMSG_HDRLEN);
768*5113495bSYour Name 	if (!skb) {
769*5113495bSYour Name 		hdd_err(" reply skb alloc failed");
770*5113495bSYour Name 		return -ENOMEM;
771*5113495bSYour Name 	}
772*5113495bSYour Name 
773*5113495bSYour Name 	if (hdd_wlan_nla_put_u64(skb, QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE,
774*5113495bSYour Name 				 cookie)) {
775*5113495bSYour Name 		hdd_err("nla put fail");
776*5113495bSYour Name 		wlan_cfg80211_vendor_free_skb(skb);
777*5113495bSYour Name 		return -EINVAL;
778*5113495bSYour Name 	}
779*5113495bSYour Name 
780*5113495bSYour Name 	ret = wlan_cfg80211_vendor_cmd_reply(skb);
781*5113495bSYour Name 
782*5113495bSYour Name 	/* Send a scan started event to supplicant */
783*5113495bSYour Name 	skb = wlan_cfg80211_vendor_event_alloc(wiphy, wdev,
784*5113495bSYour Name 					       sizeof(u64) + 4 + NLMSG_HDRLEN,
785*5113495bSYour Name 					       index, GFP_KERNEL);
786*5113495bSYour Name 	if (!skb) {
787*5113495bSYour Name 		hdd_err("skb alloc failed");
788*5113495bSYour Name 		return -ENOMEM;
789*5113495bSYour Name 	}
790*5113495bSYour Name 
791*5113495bSYour Name 	if (hdd_wlan_nla_put_u64(skb, QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE,
792*5113495bSYour Name 				 cookie)) {
793*5113495bSYour Name 		wlan_cfg80211_vendor_free_skb(skb);
794*5113495bSYour Name 		return -EINVAL;
795*5113495bSYour Name 	}
796*5113495bSYour Name 
797*5113495bSYour Name 	wlan_cfg80211_vendor_event(skb, GFP_KERNEL);
798*5113495bSYour Name 	return ret;
799*5113495bSYour Name }
800*5113495bSYour Name 
801*5113495bSYour Name /**
802*5113495bSYour Name  * wlan_hdd_copy_bssid() - API to copy the bssid to vendor Scan request
803*5113495bSYour Name  * @request: Pointer to vendor scan request
804*5113495bSYour Name  * @bssid: Pointer to BSSID
805*5113495bSYour Name  *
806*5113495bSYour Name  * This API copies the specific BSSID received from Supplicant and copies it to
807*5113495bSYour Name  * the vendor Scan request
808*5113495bSYour Name  *
809*5113495bSYour Name  * Return: None
810*5113495bSYour Name  */
811*5113495bSYour Name #if defined(CFG80211_SCAN_BSSID) || \
812*5113495bSYour Name 	(LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0))
wlan_hdd_copy_bssid(struct cfg80211_scan_request * request,uint8_t * bssid)813*5113495bSYour Name static inline void wlan_hdd_copy_bssid(struct cfg80211_scan_request *request,
814*5113495bSYour Name 					uint8_t *bssid)
815*5113495bSYour Name {
816*5113495bSYour Name 	qdf_mem_copy(request->bssid, bssid, QDF_MAC_ADDR_SIZE);
817*5113495bSYour Name }
818*5113495bSYour Name #else
wlan_hdd_copy_bssid(struct cfg80211_scan_request * request,uint8_t * bssid)819*5113495bSYour Name static inline void wlan_hdd_copy_bssid(struct cfg80211_scan_request *request,
820*5113495bSYour Name 					uint8_t *bssid)
821*5113495bSYour Name {
822*5113495bSYour Name }
823*5113495bSYour Name #endif
824*5113495bSYour Name 
hdd_process_vendor_acs_response(struct hdd_adapter * adapter)825*5113495bSYour Name static void hdd_process_vendor_acs_response(struct hdd_adapter *adapter)
826*5113495bSYour Name {
827*5113495bSYour Name 	qdf_mc_timer_t *vendor_acs_timer;
828*5113495bSYour Name 
829*5113495bSYour Name 	if (!test_bit(VENDOR_ACS_RESPONSE_PENDING,
830*5113495bSYour Name 		      &adapter->deflink->link_flags)) {
831*5113495bSYour Name 		return;
832*5113495bSYour Name 	}
833*5113495bSYour Name 
834*5113495bSYour Name 	vendor_acs_timer = &adapter->deflink->session.ap.vendor_acs_timer;
835*5113495bSYour Name 	if (QDF_TIMER_STATE_RUNNING ==
836*5113495bSYour Name 	    qdf_mc_timer_get_current_state(vendor_acs_timer)) {
837*5113495bSYour Name 		qdf_mc_timer_stop(vendor_acs_timer);
838*5113495bSYour Name 	}
839*5113495bSYour Name }
840*5113495bSYour Name 
841*5113495bSYour Name #if defined(CFG80211_SCAN_RANDOM_MAC_ADDR) || \
842*5113495bSYour Name 	(LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0))
843*5113495bSYour Name /**
844*5113495bSYour Name  * wlan_hdd_vendor_scan_random_attr() - check and fill scan randomization attrs
845*5113495bSYour Name  * @wiphy: Pointer to wiphy
846*5113495bSYour Name  * @request: Pointer to scan request
847*5113495bSYour Name  * @adapter: Pointer to hdd adapter
848*5113495bSYour Name  * @tb: Pointer to nl attributes
849*5113495bSYour Name  *
850*5113495bSYour Name  * This function is invoked to check whether vendor scan needs
851*5113495bSYour Name  * probe req source addr, if so populates mac_addr and mac_addr_mask
852*5113495bSYour Name  * in scan request with nl attrs.
853*5113495bSYour Name  *
854*5113495bSYour Name  * Return: 0 - on success, negative value on failure
855*5113495bSYour Name  */
wlan_hdd_vendor_scan_random_attr(struct wiphy * wiphy,struct cfg80211_scan_request * request,struct hdd_adapter * adapter,struct nlattr ** tb)856*5113495bSYour Name static int wlan_hdd_vendor_scan_random_attr(struct wiphy *wiphy,
857*5113495bSYour Name 					struct cfg80211_scan_request *request,
858*5113495bSYour Name 					struct hdd_adapter *adapter,
859*5113495bSYour Name 					struct nlattr **tb)
860*5113495bSYour Name {
861*5113495bSYour Name 	uint32_t i;
862*5113495bSYour Name 	int32_t len = QDF_MAC_ADDR_SIZE;
863*5113495bSYour Name 
864*5113495bSYour Name 	if (!(request->flags & NL80211_SCAN_FLAG_RANDOM_ADDR))
865*5113495bSYour Name 		return 0;
866*5113495bSYour Name 
867*5113495bSYour Name 	if (!(wiphy->features & NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR) ||
868*5113495bSYour Name 	    (hdd_cm_is_vdev_connected(adapter->deflink))) {
869*5113495bSYour Name 		hdd_err("SCAN RANDOMIZATION not supported");
870*5113495bSYour Name 		return -EOPNOTSUPP;
871*5113495bSYour Name 	}
872*5113495bSYour Name 
873*5113495bSYour Name 	if (!tb[QCA_WLAN_VENDOR_ATTR_SCAN_MAC] &&
874*5113495bSYour Name 	    !tb[QCA_WLAN_VENDOR_ATTR_SCAN_MAC_MASK]) {
875*5113495bSYour Name 		qdf_mem_zero(request->mac_addr, len);
876*5113495bSYour Name 		qdf_mem_zero(request->mac_addr_mask, len);
877*5113495bSYour Name 		request->mac_addr[0] = 0x2;
878*5113495bSYour Name 		request->mac_addr_mask[0] = 0x3;
879*5113495bSYour Name 
880*5113495bSYour Name 		return 0;
881*5113495bSYour Name 	}
882*5113495bSYour Name 
883*5113495bSYour Name 	if (!tb[QCA_WLAN_VENDOR_ATTR_SCAN_MAC] ||
884*5113495bSYour Name 	    !tb[QCA_WLAN_VENDOR_ATTR_SCAN_MAC_MASK])
885*5113495bSYour Name 		return -EINVAL;
886*5113495bSYour Name 
887*5113495bSYour Name 	if ((nla_len(tb[QCA_WLAN_VENDOR_ATTR_SCAN_MAC]) != len) ||
888*5113495bSYour Name 	    (nla_len(tb[QCA_WLAN_VENDOR_ATTR_SCAN_MAC_MASK]) != len))
889*5113495bSYour Name 		return -EINVAL;
890*5113495bSYour Name 
891*5113495bSYour Name 	qdf_mem_copy(request->mac_addr,
892*5113495bSYour Name 		     nla_data(tb[QCA_WLAN_VENDOR_ATTR_SCAN_MAC]), len);
893*5113495bSYour Name 
894*5113495bSYour Name 	qdf_mem_copy(request->mac_addr_mask,
895*5113495bSYour Name 		     nla_data(tb[QCA_WLAN_VENDOR_ATTR_SCAN_MAC_MASK]), len);
896*5113495bSYour Name 
897*5113495bSYour Name 	/* avoid configure on multicast address */
898*5113495bSYour Name 	if (!cds_is_group_addr(request->mac_addr_mask) ||
899*5113495bSYour Name 	    cds_is_group_addr(request->mac_addr))
900*5113495bSYour Name 		return -EINVAL;
901*5113495bSYour Name 
902*5113495bSYour Name 	for (i = 0; i < ETH_ALEN; i++)
903*5113495bSYour Name 		request->mac_addr[i] &= request->mac_addr_mask[i];
904*5113495bSYour Name 
905*5113495bSYour Name 	return 0;
906*5113495bSYour Name }
907*5113495bSYour Name #else
wlan_hdd_vendor_scan_random_attr(struct wiphy * wiphy,struct cfg80211_scan_request * request,struct hdd_adapter * adapter,struct nlattr ** tb)908*5113495bSYour Name static int wlan_hdd_vendor_scan_random_attr(struct wiphy *wiphy,
909*5113495bSYour Name 					struct cfg80211_scan_request *request,
910*5113495bSYour Name 					struct hdd_adapter *adapter,
911*5113495bSYour Name 					struct nlattr **tb)
912*5113495bSYour Name {
913*5113495bSYour Name 	return 0;
914*5113495bSYour Name }
915*5113495bSYour Name #endif
916*5113495bSYour Name 
917*5113495bSYour Name const
918*5113495bSYour Name struct nla_policy scan_policy[QCA_WLAN_VENDOR_ATTR_SCAN_MAX + 1] = {
919*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_SCAN_FLAGS] = {.type = NLA_U32},
920*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_SCAN_TX_NO_CCK_RATE] = {.type = NLA_FLAG},
921*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE] = {.type = NLA_U64},
922*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_SCAN_IE] = {.type = NLA_BINARY,
923*5113495bSYour Name 					  .len = MAX_DEFAULT_SCAN_IE_LEN},
924*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_SCAN_MAC] = VENDOR_NLA_POLICY_MAC_ADDR,
925*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_SCAN_MAC_MASK] = VENDOR_NLA_POLICY_MAC_ADDR,
926*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES] = {.type = NLA_NESTED},
927*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_SCAN_SSIDS] = {.type = NLA_NESTED},
928*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_SCAN_SUPP_RATES] = {.type = NLA_NESTED},
929*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_SCAN_BSSID] = {.type = NLA_BINARY},
930*5113495bSYour Name };
931*5113495bSYour Name 
932*5113495bSYour Name /**
933*5113495bSYour Name  * __wlan_hdd_cfg80211_vendor_scan() - API to process venor scan request
934*5113495bSYour Name  * @wiphy: Pointer to wiphy
935*5113495bSYour Name  * @wdev: Pointer to net device
936*5113495bSYour Name  * @data : Pointer to the data
937*5113495bSYour Name  * @data_len : length of the data
938*5113495bSYour Name  *
939*5113495bSYour Name  * API to process venor scan request.
940*5113495bSYour Name  *
941*5113495bSYour Name  * Return: return 0 on success and negative error code on failure
942*5113495bSYour Name  */
__wlan_hdd_cfg80211_vendor_scan(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)943*5113495bSYour Name static int __wlan_hdd_cfg80211_vendor_scan(struct wiphy *wiphy,
944*5113495bSYour Name 		struct wireless_dev *wdev, const void *data,
945*5113495bSYour Name 		int data_len)
946*5113495bSYour Name {
947*5113495bSYour Name 	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_SCAN_MAX + 1];
948*5113495bSYour Name 	struct cfg80211_scan_request *request = NULL;
949*5113495bSYour Name 	struct nlattr *attr;
950*5113495bSYour Name 	enum nl80211_band band;
951*5113495bSYour Name 	uint32_t n_channels = 0, n_ssid = 0;
952*5113495bSYour Name 	uint32_t count, j;
953*5113495bSYour Name 	int tmp;
954*5113495bSYour Name 	size_t len, ie_len = 0;
955*5113495bSYour Name 	struct ieee80211_channel *chan;
956*5113495bSYour Name 	struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
957*5113495bSYour Name 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(wdev->netdev);
958*5113495bSYour Name 	int ret;
959*5113495bSYour Name 
960*5113495bSYour Name 	hdd_enter_dev(wdev->netdev);
961*5113495bSYour Name 
962*5113495bSYour Name 	if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
963*5113495bSYour Name 		hdd_err("Command not allowed in FTM mode");
964*5113495bSYour Name 		return -EPERM;
965*5113495bSYour Name 	}
966*5113495bSYour Name 
967*5113495bSYour Name 	ret = wlan_hdd_validate_context(hdd_ctx);
968*5113495bSYour Name 	if (ret) {
969*5113495bSYour Name 		/*
970*5113495bSYour Name 		 * During SSR, if -EBUSY is returned then OBSS vendor scan is
971*5113495bSYour Name 		 * not issued immediately.
972*5113495bSYour Name 		 */
973*5113495bSYour Name 		if (ret == -EAGAIN)
974*5113495bSYour Name 			return -EBUSY;
975*5113495bSYour Name 
976*5113495bSYour Name 		return ret;
977*5113495bSYour Name 	}
978*5113495bSYour Name 
979*5113495bSYour Name 	if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_SCAN_MAX,
980*5113495bSYour Name 				    data, data_len, scan_policy)) {
981*5113495bSYour Name 		hdd_err("Invalid ATTR");
982*5113495bSYour Name 		return -EINVAL;
983*5113495bSYour Name 	}
984*5113495bSYour Name 
985*5113495bSYour Name 	if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES]) {
986*5113495bSYour Name 		nla_for_each_nested(attr,
987*5113495bSYour Name 			tb[QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES], tmp)
988*5113495bSYour Name 			n_channels++;
989*5113495bSYour Name 	} else {
990*5113495bSYour Name 		for (band = 0; band < HDD_NUM_NL80211_BANDS; band++)
991*5113495bSYour Name 			if (wiphy->bands[band])
992*5113495bSYour Name 				n_channels += wiphy->bands[band]->n_channels;
993*5113495bSYour Name 	}
994*5113495bSYour Name 
995*5113495bSYour Name 	if (n_channels > NUM_CHANNELS) {
996*5113495bSYour Name 		hdd_err("Exceed max number of channels: %d", n_channels);
997*5113495bSYour Name 		return -EINVAL;
998*5113495bSYour Name 	}
999*5113495bSYour Name 	if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_SSIDS])
1000*5113495bSYour Name 		nla_for_each_nested(attr,
1001*5113495bSYour Name 			tb[QCA_WLAN_VENDOR_ATTR_SCAN_SSIDS], tmp)
1002*5113495bSYour Name 			n_ssid++;
1003*5113495bSYour Name 
1004*5113495bSYour Name 	if (MAX_SCAN_SSID < n_ssid) {
1005*5113495bSYour Name 		hdd_err("Exceed max number of SSID: %d", n_ssid);
1006*5113495bSYour Name 		return -EINVAL;
1007*5113495bSYour Name 	}
1008*5113495bSYour Name 
1009*5113495bSYour Name 	if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_IE])
1010*5113495bSYour Name 		ie_len = nla_len(tb[QCA_WLAN_VENDOR_ATTR_SCAN_IE]);
1011*5113495bSYour Name 
1012*5113495bSYour Name 	len = sizeof(*request) + (sizeof(*request->ssids) * n_ssid) +
1013*5113495bSYour Name 			(sizeof(*request->channels) * n_channels) + ie_len;
1014*5113495bSYour Name 
1015*5113495bSYour Name 	request = qdf_mem_malloc(len);
1016*5113495bSYour Name 	if (!request)
1017*5113495bSYour Name 		goto error;
1018*5113495bSYour Name 	if (n_ssid)
1019*5113495bSYour Name 		request->ssids = (void *)&request->channels[n_channels];
1020*5113495bSYour Name 	request->n_ssids = n_ssid;
1021*5113495bSYour Name 	if (ie_len) {
1022*5113495bSYour Name 		if (request->ssids)
1023*5113495bSYour Name 			request->ie = (void *)(request->ssids + n_ssid);
1024*5113495bSYour Name 		else
1025*5113495bSYour Name 			request->ie = (void *)(request->channels + n_channels);
1026*5113495bSYour Name 	}
1027*5113495bSYour Name 
1028*5113495bSYour Name 	request->ie_len = ie_len;
1029*5113495bSYour Name 	count = 0;
1030*5113495bSYour Name 	if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES]) {
1031*5113495bSYour Name 		nla_for_each_nested(attr,
1032*5113495bSYour Name 				    tb[QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES],
1033*5113495bSYour Name 				    tmp) {
1034*5113495bSYour Name 			if (nla_len(attr) != sizeof(uint32_t)) {
1035*5113495bSYour Name 				hdd_err("len is not correct for frequency %d",
1036*5113495bSYour Name 					count);
1037*5113495bSYour Name 				goto error;
1038*5113495bSYour Name 			}
1039*5113495bSYour Name 			chan = ieee80211_get_channel(wiphy, nla_get_u32(attr));
1040*5113495bSYour Name 			if (!chan)
1041*5113495bSYour Name 				goto error;
1042*5113495bSYour Name 			if (chan->flags & IEEE80211_CHAN_DISABLED)
1043*5113495bSYour Name 				continue;
1044*5113495bSYour Name 			request->channels[count] = chan;
1045*5113495bSYour Name 			count++;
1046*5113495bSYour Name 		}
1047*5113495bSYour Name 	} else {
1048*5113495bSYour Name 		for (band = 0; band < HDD_NUM_NL80211_BANDS; band++) {
1049*5113495bSYour Name 			if (!wiphy->bands[band])
1050*5113495bSYour Name 				continue;
1051*5113495bSYour Name 			for (j = 0; j < wiphy->bands[band]->n_channels;
1052*5113495bSYour Name 				j++) {
1053*5113495bSYour Name 				chan = &wiphy->bands[band]->channels[j];
1054*5113495bSYour Name 				if (chan->flags & IEEE80211_CHAN_DISABLED)
1055*5113495bSYour Name 					continue;
1056*5113495bSYour Name 				request->channels[count] = chan;
1057*5113495bSYour Name 				count++;
1058*5113495bSYour Name 			}
1059*5113495bSYour Name 		}
1060*5113495bSYour Name 	}
1061*5113495bSYour Name 
1062*5113495bSYour Name 	if (!count)
1063*5113495bSYour Name 		goto error;
1064*5113495bSYour Name 
1065*5113495bSYour Name 	request->n_channels = count;
1066*5113495bSYour Name 	count = 0;
1067*5113495bSYour Name 	if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_SSIDS]) {
1068*5113495bSYour Name 		int ssid_length;
1069*5113495bSYour Name 
1070*5113495bSYour Name 		nla_for_each_nested(attr, tb[QCA_WLAN_VENDOR_ATTR_SCAN_SSIDS],
1071*5113495bSYour Name 				tmp) {
1072*5113495bSYour Name 			ssid_length = nla_len(attr);
1073*5113495bSYour Name 			if ((ssid_length > WLAN_SSID_MAX_LEN) ||
1074*5113495bSYour Name 			    (ssid_length < 0)) {
1075*5113495bSYour Name 				hdd_err("SSID Len %d is not correct for network %d",
1076*5113495bSYour Name 					 ssid_length, count);
1077*5113495bSYour Name 				goto error;
1078*5113495bSYour Name 			}
1079*5113495bSYour Name 
1080*5113495bSYour Name 			request->ssids[count].ssid_len = ssid_length;
1081*5113495bSYour Name 			memcpy(request->ssids[count].ssid, nla_data(attr),
1082*5113495bSYour Name 					ssid_length);
1083*5113495bSYour Name 			count++;
1084*5113495bSYour Name 		}
1085*5113495bSYour Name 	}
1086*5113495bSYour Name 
1087*5113495bSYour Name 	if (ie_len)
1088*5113495bSYour Name 		nla_memcpy((void *)request->ie,
1089*5113495bSYour Name 			   tb[QCA_WLAN_VENDOR_ATTR_SCAN_IE], ie_len);
1090*5113495bSYour Name 
1091*5113495bSYour Name 	for (count = 0; count < HDD_NUM_NL80211_BANDS; count++)
1092*5113495bSYour Name 		if (wiphy->bands[count])
1093*5113495bSYour Name 			request->rates[count] =
1094*5113495bSYour Name 				(1 << wiphy->bands[count]->n_bitrates) - 1;
1095*5113495bSYour Name 
1096*5113495bSYour Name 	if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_SUPP_RATES]) {
1097*5113495bSYour Name 		nla_for_each_nested(attr,
1098*5113495bSYour Name 				    tb[QCA_WLAN_VENDOR_ATTR_SCAN_SUPP_RATES],
1099*5113495bSYour Name 				    tmp) {
1100*5113495bSYour Name 			band = nla_type(attr);
1101*5113495bSYour Name 			if (band >= HDD_NUM_NL80211_BANDS)
1102*5113495bSYour Name 				continue;
1103*5113495bSYour Name 			if (!wiphy->bands[band])
1104*5113495bSYour Name 				continue;
1105*5113495bSYour Name 			request->rates[band] =
1106*5113495bSYour Name 				wlan_hdd_get_rates(wiphy,
1107*5113495bSYour Name 						   band, nla_data(attr),
1108*5113495bSYour Name 						   nla_len(attr));
1109*5113495bSYour Name 		}
1110*5113495bSYour Name 	}
1111*5113495bSYour Name 
1112*5113495bSYour Name 	if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_FLAGS]) {
1113*5113495bSYour Name 		request->flags =
1114*5113495bSYour Name 			nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_SCAN_FLAGS]);
1115*5113495bSYour Name 		if ((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) &&
1116*5113495bSYour Name 		    !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) {
1117*5113495bSYour Name 			hdd_err("LOW PRIORITY SCAN not supported");
1118*5113495bSYour Name 			goto error;
1119*5113495bSYour Name 		}
1120*5113495bSYour Name 
1121*5113495bSYour Name 		if (wlan_hdd_vendor_scan_random_attr(wiphy, request,
1122*5113495bSYour Name 						     adapter, tb))
1123*5113495bSYour Name 			goto error;
1124*5113495bSYour Name 	}
1125*5113495bSYour Name 
1126*5113495bSYour Name 	if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_BSSID]) {
1127*5113495bSYour Name 		if (nla_len(tb[QCA_WLAN_VENDOR_ATTR_SCAN_BSSID]) <
1128*5113495bSYour Name 		    QDF_MAC_ADDR_SIZE) {
1129*5113495bSYour Name 			hdd_err("invalid bssid length");
1130*5113495bSYour Name 			goto error;
1131*5113495bSYour Name 		}
1132*5113495bSYour Name 		wlan_hdd_copy_bssid(request,
1133*5113495bSYour Name 			nla_data(tb[QCA_WLAN_VENDOR_ATTR_SCAN_BSSID]));
1134*5113495bSYour Name 	}
1135*5113495bSYour Name 
1136*5113495bSYour Name 	/* Check if external acs was requested on this adapter */
1137*5113495bSYour Name 	hdd_process_vendor_acs_response(adapter);
1138*5113495bSYour Name 
1139*5113495bSYour Name 	if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_TX_NO_CCK_RATE])
1140*5113495bSYour Name 		request->no_cck =
1141*5113495bSYour Name 		   nla_get_flag(tb[QCA_WLAN_VENDOR_ATTR_SCAN_TX_NO_CCK_RATE]);
1142*5113495bSYour Name 	request->wdev = wdev;
1143*5113495bSYour Name 	request->wiphy = wiphy;
1144*5113495bSYour Name 	request->scan_start = jiffies;
1145*5113495bSYour Name 
1146*5113495bSYour Name 	ret = __wlan_hdd_cfg80211_scan(wiphy, request, VENDOR_SCAN);
1147*5113495bSYour Name 	if (0 != ret) {
1148*5113495bSYour Name 		hdd_err("Scan Failed. Ret = %d", ret);
1149*5113495bSYour Name 		qdf_mem_free(request);
1150*5113495bSYour Name 		return ret;
1151*5113495bSYour Name 	}
1152*5113495bSYour Name 	ret = wlan_hdd_send_scan_start_event(wiphy, wdev, (uintptr_t)request);
1153*5113495bSYour Name 
1154*5113495bSYour Name 	return ret;
1155*5113495bSYour Name error:
1156*5113495bSYour Name 	hdd_err("Scan Request Failed");
1157*5113495bSYour Name 	qdf_mem_free(request);
1158*5113495bSYour Name 	return -EINVAL;
1159*5113495bSYour Name }
1160*5113495bSYour Name 
1161*5113495bSYour Name /**
1162*5113495bSYour Name  * wlan_hdd_cfg80211_vendor_scan() -API to process venor scan request
1163*5113495bSYour Name  * @wiphy: Pointer to wiphy
1164*5113495bSYour Name  * @wdev: Pointer to wireless device
1165*5113495bSYour Name  * @data: Pointer to the data
1166*5113495bSYour Name  * @data_len: length of the data
1167*5113495bSYour Name  *
1168*5113495bSYour Name  * This is called from userspace to request scan.
1169*5113495bSYour Name  *
1170*5113495bSYour Name  * Return: Return the Success or Failure code.
1171*5113495bSYour Name  */
wlan_hdd_cfg80211_vendor_scan(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)1172*5113495bSYour Name int wlan_hdd_cfg80211_vendor_scan(struct wiphy *wiphy,
1173*5113495bSYour Name 		struct wireless_dev *wdev, const void *data,
1174*5113495bSYour Name 		int data_len)
1175*5113495bSYour Name {
1176*5113495bSYour Name 	int errno;
1177*5113495bSYour Name 	struct osif_vdev_sync *vdev_sync;
1178*5113495bSYour Name 
1179*5113495bSYour Name 	errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync);
1180*5113495bSYour Name 	if (errno)
1181*5113495bSYour Name 		return errno;
1182*5113495bSYour Name 
1183*5113495bSYour Name 	errno = __wlan_hdd_cfg80211_vendor_scan(wiphy, wdev, data, data_len);
1184*5113495bSYour Name 
1185*5113495bSYour Name 	osif_vdev_sync_op_stop(vdev_sync);
1186*5113495bSYour Name 
1187*5113495bSYour Name 	return errno;
1188*5113495bSYour Name }
1189*5113495bSYour Name 
1190*5113495bSYour Name /**
1191*5113495bSYour Name  * __wlan_hdd_vendor_abort_scan() - API to process vendor command for
1192*5113495bSYour Name  * abort scan
1193*5113495bSYour Name  * @wiphy: Pointer to wiphy
1194*5113495bSYour Name  * @data: Pointer to the data
1195*5113495bSYour Name  * @data_len: length of the data
1196*5113495bSYour Name  *
1197*5113495bSYour Name  * API to process vendor abort scan
1198*5113495bSYour Name  *
1199*5113495bSYour Name  * Return: zero for success and non zero for failure
1200*5113495bSYour Name  */
__wlan_hdd_vendor_abort_scan(struct wiphy * wiphy,const void * data,int data_len)1201*5113495bSYour Name static int __wlan_hdd_vendor_abort_scan(
1202*5113495bSYour Name 		struct wiphy *wiphy, const void *data,
1203*5113495bSYour Name 		int data_len)
1204*5113495bSYour Name {
1205*5113495bSYour Name 	struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
1206*5113495bSYour Name 	int ret;
1207*5113495bSYour Name 
1208*5113495bSYour Name 	if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
1209*5113495bSYour Name 		hdd_err("Command not allowed in FTM mode");
1210*5113495bSYour Name 		return -EINVAL;
1211*5113495bSYour Name 	}
1212*5113495bSYour Name 
1213*5113495bSYour Name 	ret = wlan_hdd_validate_context(hdd_ctx);
1214*5113495bSYour Name 	if (0 != ret)
1215*5113495bSYour Name 		return ret;
1216*5113495bSYour Name 
1217*5113495bSYour Name 	wlan_vendor_abort_scan(hdd_ctx->pdev, data, data_len);
1218*5113495bSYour Name 
1219*5113495bSYour Name 	return ret;
1220*5113495bSYour Name }
1221*5113495bSYour Name 
1222*5113495bSYour Name /**
1223*5113495bSYour Name  * wlan_hdd_vendor_abort_scan() - API to process vendor command for
1224*5113495bSYour Name  * abort scan
1225*5113495bSYour Name  * @wiphy: Pointer to wiphy
1226*5113495bSYour Name  * @wdev: Pointer to net device
1227*5113495bSYour Name  * @data : Pointer to the data
1228*5113495bSYour Name  * @data_len : length of the data
1229*5113495bSYour Name  *
1230*5113495bSYour Name  * This is called from supplicant to abort scan
1231*5113495bSYour Name  *
1232*5113495bSYour Name  * Return: zero for success and non zero for failure
1233*5113495bSYour Name  */
wlan_hdd_vendor_abort_scan(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)1234*5113495bSYour Name int wlan_hdd_vendor_abort_scan(struct wiphy *wiphy, struct wireless_dev *wdev,
1235*5113495bSYour Name 			       const void *data, int data_len)
1236*5113495bSYour Name {
1237*5113495bSYour Name 	struct osif_vdev_sync *vdev_sync;
1238*5113495bSYour Name 	int errno;
1239*5113495bSYour Name 
1240*5113495bSYour Name 	errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync);
1241*5113495bSYour Name 	if (errno)
1242*5113495bSYour Name 		return errno;
1243*5113495bSYour Name 
1244*5113495bSYour Name 	errno = __wlan_hdd_vendor_abort_scan(wiphy, data, data_len);
1245*5113495bSYour Name 
1246*5113495bSYour Name 	osif_vdev_sync_op_stop(vdev_sync);
1247*5113495bSYour Name 
1248*5113495bSYour Name 	return errno;
1249*5113495bSYour Name }
1250*5113495bSYour Name 
wlan_hdd_scan_abort(struct wlan_hdd_link_info * link_info)1251*5113495bSYour Name int wlan_hdd_scan_abort(struct wlan_hdd_link_info *link_info)
1252*5113495bSYour Name {
1253*5113495bSYour Name 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter);
1254*5113495bSYour Name 
1255*5113495bSYour Name 	wlan_abort_scan(hdd_ctx->pdev, INVAL_PDEV_ID,
1256*5113495bSYour Name 			link_info->vdev_id, INVALID_SCAN_ID, true);
1257*5113495bSYour Name 
1258*5113495bSYour Name 	return 0;
1259*5113495bSYour Name }
1260*5113495bSYour Name 
1261*5113495bSYour Name #ifdef FEATURE_WLAN_SCAN_PNO
1262*5113495bSYour Name /**
1263*5113495bSYour Name  * __wlan_hdd_cfg80211_sched_scan_start() - cfg80211 scheduled scan(pno) start
1264*5113495bSYour Name  * @wiphy: Pointer to wiphy
1265*5113495bSYour Name  * @dev: Pointer network device
1266*5113495bSYour Name  * @request: Pointer to cfg80211 scheduled scan start request
1267*5113495bSYour Name  *
1268*5113495bSYour Name  * Return: 0 for success, non zero for failure
1269*5113495bSYour Name  */
__wlan_hdd_cfg80211_sched_scan_start(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_sched_scan_request * request)1270*5113495bSYour Name static int __wlan_hdd_cfg80211_sched_scan_start(struct wiphy *wiphy,
1271*5113495bSYour Name 						struct net_device *dev,
1272*5113495bSYour Name 						struct
1273*5113495bSYour Name 						cfg80211_sched_scan_request
1274*5113495bSYour Name 						*request)
1275*5113495bSYour Name {
1276*5113495bSYour Name 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
1277*5113495bSYour Name 	struct hdd_context *hdd_ctx;
1278*5113495bSYour Name 	struct wlan_objmgr_vdev *vdev;
1279*5113495bSYour Name 	int ret;
1280*5113495bSYour Name 	bool pno_offload_enabled;
1281*5113495bSYour Name 	uint8_t scan_backoff_multiplier;
1282*5113495bSYour Name 	bool enable_connected_scan;
1283*5113495bSYour Name 	enum QDF_GLOBAL_MODE curr_mode;
1284*5113495bSYour Name 
1285*5113495bSYour Name 	curr_mode = hdd_get_conparam();
1286*5113495bSYour Name 
1287*5113495bSYour Name 	if (QDF_GLOBAL_FTM_MODE == curr_mode ||
1288*5113495bSYour Name 	    QDF_GLOBAL_MONITOR_MODE == curr_mode) {
1289*5113495bSYour Name 		hdd_err_rl("Command not allowed in FTM/Monitor mode");
1290*5113495bSYour Name 		return -EINVAL;
1291*5113495bSYour Name 	}
1292*5113495bSYour Name 
1293*5113495bSYour Name 	if (wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id))
1294*5113495bSYour Name 		return -EINVAL;
1295*5113495bSYour Name 
1296*5113495bSYour Name 	if (adapter->device_mode != QDF_STA_MODE) {
1297*5113495bSYour Name 		hdd_info("Sched scans only supported on STA ifaces");
1298*5113495bSYour Name 		return -EINVAL;
1299*5113495bSYour Name 	}
1300*5113495bSYour Name 
1301*5113495bSYour Name 	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1302*5113495bSYour Name 	ret = wlan_hdd_validate_context(hdd_ctx);
1303*5113495bSYour Name 	if (ret)
1304*5113495bSYour Name 		return ret;
1305*5113495bSYour Name 
1306*5113495bSYour Name 	pno_offload_enabled = ucfg_scan_is_pno_offload_enabled(hdd_ctx->psoc);
1307*5113495bSYour Name 	if (!pno_offload_enabled) {
1308*5113495bSYour Name 		hdd_debug("Pno Offload is not enabled");
1309*5113495bSYour Name 		return -EINVAL;
1310*5113495bSYour Name 	}
1311*5113495bSYour Name 
1312*5113495bSYour Name 	enable_connected_scan = ucfg_scan_is_connected_scan_enabled(
1313*5113495bSYour Name 							hdd_ctx->psoc);
1314*5113495bSYour Name 	if (!enable_connected_scan &&
1315*5113495bSYour Name 	    hdd_cm_is_vdev_associated(adapter->deflink)) {
1316*5113495bSYour Name 		hdd_info("enable_connected_scan is false, Aborting scan");
1317*5113495bSYour Name 		return -EBUSY;
1318*5113495bSYour Name 	}
1319*5113495bSYour Name 
1320*5113495bSYour Name 	vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_OSIF_SCAN_ID);
1321*5113495bSYour Name 	if (!vdev)
1322*5113495bSYour Name 		return -EINVAL;
1323*5113495bSYour Name 
1324*5113495bSYour Name 	scan_backoff_multiplier =
1325*5113495bSYour Name 			ucfg_get_scan_backoff_multiplier(hdd_ctx->psoc);
1326*5113495bSYour Name 	ret = wlan_cfg80211_sched_scan_start(vdev, request,
1327*5113495bSYour Name 					     scan_backoff_multiplier);
1328*5113495bSYour Name 	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_SCAN_ID);
1329*5113495bSYour Name 
1330*5113495bSYour Name 	return ret;
1331*5113495bSYour Name }
1332*5113495bSYour Name 
1333*5113495bSYour Name /**
1334*5113495bSYour Name  * wlan_hdd_cfg80211_sched_scan_start() - cfg80211 scheduled scan(pno) start
1335*5113495bSYour Name  * @wiphy: Pointer to wiphy
1336*5113495bSYour Name  * @dev: Pointer network device
1337*5113495bSYour Name  * @request: Pointer to cfg80211 scheduled scan start request
1338*5113495bSYour Name  *
1339*5113495bSYour Name  * Return: 0 for success, non zero for failure
1340*5113495bSYour Name  */
wlan_hdd_cfg80211_sched_scan_start(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_sched_scan_request * request)1341*5113495bSYour Name int wlan_hdd_cfg80211_sched_scan_start(struct wiphy *wiphy,
1342*5113495bSYour Name 				       struct net_device *dev,
1343*5113495bSYour Name 				       struct cfg80211_sched_scan_request
1344*5113495bSYour Name 				       *request)
1345*5113495bSYour Name {
1346*5113495bSYour Name 	int errno;
1347*5113495bSYour Name 	struct osif_vdev_sync *vdev_sync;
1348*5113495bSYour Name 
1349*5113495bSYour Name 	errno = osif_vdev_sync_op_start(dev, &vdev_sync);
1350*5113495bSYour Name 	if (errno)
1351*5113495bSYour Name 		return errno;
1352*5113495bSYour Name 
1353*5113495bSYour Name 	errno = __wlan_hdd_cfg80211_sched_scan_start(wiphy, dev, request);
1354*5113495bSYour Name 
1355*5113495bSYour Name 	osif_vdev_sync_op_stop(vdev_sync);
1356*5113495bSYour Name 
1357*5113495bSYour Name 	return errno;
1358*5113495bSYour Name }
1359*5113495bSYour Name 
wlan_hdd_sched_scan_stop(struct net_device * dev)1360*5113495bSYour Name int wlan_hdd_sched_scan_stop(struct net_device *dev)
1361*5113495bSYour Name {
1362*5113495bSYour Name 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
1363*5113495bSYour Name 	struct hdd_context *hdd_ctx;
1364*5113495bSYour Name 	struct wlan_objmgr_vdev *vdev;
1365*5113495bSYour Name 	int ret;
1366*5113495bSYour Name 	bool pno_offload_enabled;
1367*5113495bSYour Name 
1368*5113495bSYour Name 	if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
1369*5113495bSYour Name 		hdd_err("Command not allowed in FTM mode");
1370*5113495bSYour Name 		return -EINVAL;
1371*5113495bSYour Name 	}
1372*5113495bSYour Name 
1373*5113495bSYour Name 	if (wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id))
1374*5113495bSYour Name 		return -EINVAL;
1375*5113495bSYour Name 
1376*5113495bSYour Name 	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1377*5113495bSYour Name 	if (!hdd_ctx) {
1378*5113495bSYour Name 		hdd_err("HDD context is Null");
1379*5113495bSYour Name 		return -EINVAL;
1380*5113495bSYour Name 	}
1381*5113495bSYour Name 
1382*5113495bSYour Name 	pno_offload_enabled = ucfg_scan_is_pno_offload_enabled(hdd_ctx->psoc);
1383*5113495bSYour Name 	if (!pno_offload_enabled) {
1384*5113495bSYour Name 		hdd_debug("PnoOffload is not enabled!!!");
1385*5113495bSYour Name 		return -EINVAL;
1386*5113495bSYour Name 	}
1387*5113495bSYour Name 
1388*5113495bSYour Name 	vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_OSIF_SCAN_ID);
1389*5113495bSYour Name 	if (!vdev)
1390*5113495bSYour Name 		return -EINVAL;
1391*5113495bSYour Name 	ret = wlan_cfg80211_sched_scan_stop(vdev);
1392*5113495bSYour Name 	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_SCAN_ID);
1393*5113495bSYour Name 
1394*5113495bSYour Name 	return ret;
1395*5113495bSYour Name }
1396*5113495bSYour Name 
1397*5113495bSYour Name /**
1398*5113495bSYour Name  * __wlan_hdd_cfg80211_sched_scan_stop() - stop cfg80211 scheduled scan(pno)
1399*5113495bSYour Name  * @dev: Pointer network device
1400*5113495bSYour Name  *
1401*5113495bSYour Name  * This is a wrapper around wlan_hdd_sched_scan_stop() that returns success
1402*5113495bSYour Name  * in the event that the driver is currently recovering or unloading. This
1403*5113495bSYour Name  * prevents a race condition where we get a scan stop from kernel during
1404*5113495bSYour Name  * a driver unload from PLD.
1405*5113495bSYour Name  *
1406*5113495bSYour Name  * Return: 0 for success, non zero for failure
1407*5113495bSYour Name  */
__wlan_hdd_cfg80211_sched_scan_stop(struct net_device * dev)1408*5113495bSYour Name static int __wlan_hdd_cfg80211_sched_scan_stop(struct net_device *dev)
1409*5113495bSYour Name {
1410*5113495bSYour Name 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
1411*5113495bSYour Name 	int errno;
1412*5113495bSYour Name 	enum QDF_GLOBAL_MODE curr_mode;
1413*5113495bSYour Name 
1414*5113495bSYour Name 	curr_mode = hdd_get_conparam();
1415*5113495bSYour Name 
1416*5113495bSYour Name 	if (QDF_GLOBAL_FTM_MODE == curr_mode ||
1417*5113495bSYour Name 	    QDF_GLOBAL_MONITOR_MODE == curr_mode) {
1418*5113495bSYour Name 		hdd_err_rl("Command not allowed in FTM/Monitor mode");
1419*5113495bSYour Name 		return -EINVAL;
1420*5113495bSYour Name 	}
1421*5113495bSYour Name 
1422*5113495bSYour Name 	/* The return 0 is intentional when Recovery and Load/Unload in
1423*5113495bSYour Name 	 * progress. We did observe a crash due to a return of
1424*5113495bSYour Name 	 * failure in sched_scan_stop , especially for a case where the unload
1425*5113495bSYour Name 	 * of the happens at the same time. The function
1426*5113495bSYour Name 	 * __cfg80211_stop_sched_scan was clearing rdev->sched_scan_req only
1427*5113495bSYour Name 	 * when the sched_scan_stop returns success. If it returns a failure ,
1428*5113495bSYour Name 	 * then its next invocation due to the clean up of the second interface
1429*5113495bSYour Name 	 * will have the dev pointer corresponding to the first one leading to
1430*5113495bSYour Name 	 * a crash.
1431*5113495bSYour Name 	 */
1432*5113495bSYour Name 	if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) {
1433*5113495bSYour Name 		hdd_info("Recovery in Progress. State: 0x%x Ignore!!!",
1434*5113495bSYour Name 			 cds_get_driver_state());
1435*5113495bSYour Name 		return 0;
1436*5113495bSYour Name 	}
1437*5113495bSYour Name 
1438*5113495bSYour Name 	if (cds_is_load_or_unload_in_progress()) {
1439*5113495bSYour Name 		hdd_info("Unload/Load in Progress, state: 0x%x.  Ignore!!!",
1440*5113495bSYour Name 			cds_get_driver_state());
1441*5113495bSYour Name 		return 0;
1442*5113495bSYour Name 	}
1443*5113495bSYour Name 
1444*5113495bSYour Name 	errno = hdd_validate_adapter(adapter);
1445*5113495bSYour Name 	if (errno)
1446*5113495bSYour Name 		return errno;
1447*5113495bSYour Name 
1448*5113495bSYour Name 	if (adapter->device_mode != QDF_STA_MODE) {
1449*5113495bSYour Name 		hdd_info("Sched scans only supported on STA ifaces");
1450*5113495bSYour Name 		return -EINVAL;
1451*5113495bSYour Name 	}
1452*5113495bSYour Name 
1453*5113495bSYour Name 	errno = wlan_hdd_validate_context(WLAN_HDD_GET_CTX(adapter));
1454*5113495bSYour Name 	if (errno)
1455*5113495bSYour Name 		return errno;
1456*5113495bSYour Name 
1457*5113495bSYour Name 	errno = wlan_hdd_sched_scan_stop(dev);
1458*5113495bSYour Name 
1459*5113495bSYour Name 	return errno;
1460*5113495bSYour Name }
1461*5113495bSYour Name 
1462*5113495bSYour Name #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0)
wlan_hdd_cfg80211_sched_scan_stop(struct wiphy * wiphy,struct net_device * dev)1463*5113495bSYour Name int wlan_hdd_cfg80211_sched_scan_stop(struct wiphy *wiphy,
1464*5113495bSYour Name 				      struct net_device *dev)
1465*5113495bSYour Name {
1466*5113495bSYour Name 	int errno;
1467*5113495bSYour Name 	struct osif_vdev_sync *vdev_sync;
1468*5113495bSYour Name 
1469*5113495bSYour Name 	errno = osif_vdev_sync_op_start(dev, &vdev_sync);
1470*5113495bSYour Name 	if (errno)
1471*5113495bSYour Name 		return errno;
1472*5113495bSYour Name 
1473*5113495bSYour Name 	errno = __wlan_hdd_cfg80211_sched_scan_stop(dev);
1474*5113495bSYour Name 
1475*5113495bSYour Name 	osif_vdev_sync_op_stop(vdev_sync);
1476*5113495bSYour Name 
1477*5113495bSYour Name 	/* The return 0 is intentional. We observed a crash due to a return of
1478*5113495bSYour Name 	 * failure in sched_scan_stop , especially for a case where the unload
1479*5113495bSYour Name 	 * of the happens at the same time. The function
1480*5113495bSYour Name 	 * __cfg80211_stop_sched_scan was clearing rdev->sched_scan_req only
1481*5113495bSYour Name 	 * when the sched_scan_stop returns success. If it returns a failure ,
1482*5113495bSYour Name 	 * then its next invocation due to the clean up of the second interface
1483*5113495bSYour Name 	 * will have the dev pointer corresponding to the first one leading to
1484*5113495bSYour Name 	 * a crash.
1485*5113495bSYour Name 	 */
1486*5113495bSYour Name 	return 0;
1487*5113495bSYour Name }
1488*5113495bSYour Name #else
wlan_hdd_cfg80211_sched_scan_stop(struct wiphy * wiphy,struct net_device * dev,uint64_t reqid)1489*5113495bSYour Name int wlan_hdd_cfg80211_sched_scan_stop(struct wiphy *wiphy,
1490*5113495bSYour Name 				      struct net_device *dev,
1491*5113495bSYour Name 				      uint64_t reqid)
1492*5113495bSYour Name {
1493*5113495bSYour Name 	int errno;
1494*5113495bSYour Name 	struct osif_vdev_sync *vdev_sync;
1495*5113495bSYour Name 
1496*5113495bSYour Name 	errno = osif_vdev_sync_op_start(dev, &vdev_sync);
1497*5113495bSYour Name 	if (errno)
1498*5113495bSYour Name 		return errno;
1499*5113495bSYour Name 
1500*5113495bSYour Name 	errno = __wlan_hdd_cfg80211_sched_scan_stop(dev);
1501*5113495bSYour Name 
1502*5113495bSYour Name 	osif_vdev_sync_op_stop(vdev_sync);
1503*5113495bSYour Name 
1504*5113495bSYour Name 	/* The return 0 is intentional. We observed a crash due to a return of
1505*5113495bSYour Name 	 * failure in sched_scan_stop , especially for a case where the unload
1506*5113495bSYour Name 	 * of the happens at the same time. The function
1507*5113495bSYour Name 	 * __cfg80211_stop_sched_scan was clearing rdev->sched_scan_req only
1508*5113495bSYour Name 	 * when the sched_scan_stop returns success. If it returns a failure ,
1509*5113495bSYour Name 	 * then its next invocation due to the clean up of the second interface
1510*5113495bSYour Name 	 * will have the dev pointer corresponding to the first one leading to
1511*5113495bSYour Name 	 * a crash.
1512*5113495bSYour Name 	 */
1513*5113495bSYour Name 	return 0;
1514*5113495bSYour Name }
1515*5113495bSYour Name #endif /* KERNEL_VERSION(4, 12, 0) */
1516*5113495bSYour Name #endif /*FEATURE_WLAN_SCAN_PNO */
1517*5113495bSYour Name 
1518*5113495bSYour Name #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)) || \
1519*5113495bSYour Name 	defined(CFG80211_ABORT_SCAN)
1520*5113495bSYour Name /**
1521*5113495bSYour Name  * __wlan_hdd_cfg80211_abort_scan() - cfg80211 abort scan api
1522*5113495bSYour Name  * @wiphy: Pointer to wiphy
1523*5113495bSYour Name  * @wdev: Pointer to wireless device structure
1524*5113495bSYour Name  *
1525*5113495bSYour Name  * This function is used to abort an ongoing scan
1526*5113495bSYour Name  *
1527*5113495bSYour Name  * Return: None
1528*5113495bSYour Name  */
__wlan_hdd_cfg80211_abort_scan(struct wiphy * wiphy,struct wireless_dev * wdev)1529*5113495bSYour Name static void __wlan_hdd_cfg80211_abort_scan(struct wiphy *wiphy,
1530*5113495bSYour Name 					   struct wireless_dev *wdev)
1531*5113495bSYour Name {
1532*5113495bSYour Name 	struct net_device *dev = wdev->netdev;
1533*5113495bSYour Name 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
1534*5113495bSYour Name 	struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
1535*5113495bSYour Name 	int ret;
1536*5113495bSYour Name 
1537*5113495bSYour Name 	hdd_enter_dev(dev);
1538*5113495bSYour Name 
1539*5113495bSYour Name 	if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
1540*5113495bSYour Name 		hdd_err("Command not allowed in FTM mode");
1541*5113495bSYour Name 		return;
1542*5113495bSYour Name 	}
1543*5113495bSYour Name 
1544*5113495bSYour Name 	if (wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id))
1545*5113495bSYour Name 		return;
1546*5113495bSYour Name 
1547*5113495bSYour Name 	ret = wlan_hdd_validate_context(hdd_ctx);
1548*5113495bSYour Name 	if (ret)
1549*5113495bSYour Name 		return;
1550*5113495bSYour Name 
1551*5113495bSYour Name 	wlan_cfg80211_abort_scan(hdd_ctx->pdev);
1552*5113495bSYour Name 
1553*5113495bSYour Name 	hdd_exit();
1554*5113495bSYour Name }
1555*5113495bSYour Name 
1556*5113495bSYour Name /**
1557*5113495bSYour Name  * wlan_hdd_cfg80211_abort_scan - cfg80211 abort scan api
1558*5113495bSYour Name  * @wiphy: Pointer to wiphy
1559*5113495bSYour Name  * @wdev: Pointer to wireless device structure
1560*5113495bSYour Name  *
1561*5113495bSYour Name  * Wrapper to __wlan_hdd_cfg80211_abort_scan() -
1562*5113495bSYour Name  * function is used to abort an ongoing scan
1563*5113495bSYour Name  *
1564*5113495bSYour Name  * Return: None
1565*5113495bSYour Name  */
wlan_hdd_cfg80211_abort_scan(struct wiphy * wiphy,struct wireless_dev * wdev)1566*5113495bSYour Name void wlan_hdd_cfg80211_abort_scan(struct wiphy *wiphy,
1567*5113495bSYour Name 				  struct wireless_dev *wdev)
1568*5113495bSYour Name {
1569*5113495bSYour Name 	struct osif_psoc_sync *psoc_sync;
1570*5113495bSYour Name 	int errno;
1571*5113495bSYour Name 
1572*5113495bSYour Name 	errno = osif_psoc_sync_op_start(wiphy_dev(wiphy), &psoc_sync);
1573*5113495bSYour Name 	if (errno)
1574*5113495bSYour Name 		return;
1575*5113495bSYour Name 
1576*5113495bSYour Name 	__wlan_hdd_cfg80211_abort_scan(wiphy, wdev);
1577*5113495bSYour Name 
1578*5113495bSYour Name 	osif_psoc_sync_op_stop(psoc_sync);
1579*5113495bSYour Name }
1580*5113495bSYour Name #endif
1581*5113495bSYour Name 
1582*5113495bSYour Name /**
1583*5113495bSYour Name  * hdd_scan_context_destroy() - Destroy scan context
1584*5113495bSYour Name  * @hdd_ctx:	HDD context.
1585*5113495bSYour Name  *
1586*5113495bSYour Name  * Destroy scan context.
1587*5113495bSYour Name  *
1588*5113495bSYour Name  * Return: None.
1589*5113495bSYour Name  */
hdd_scan_context_destroy(struct hdd_context * hdd_ctx)1590*5113495bSYour Name void hdd_scan_context_destroy(struct hdd_context *hdd_ctx)
1591*5113495bSYour Name {
1592*5113495bSYour Name }
1593*5113495bSYour Name 
1594*5113495bSYour Name /**
1595*5113495bSYour Name  * hdd_scan_context_init() - Initialize scan context
1596*5113495bSYour Name  * @hdd_ctx:	HDD context.
1597*5113495bSYour Name  *
1598*5113495bSYour Name  * Initialize scan related resources like spin lock and lists.
1599*5113495bSYour Name  *
1600*5113495bSYour Name  * Return: 0 on success and errno on failure.
1601*5113495bSYour Name  */
hdd_scan_context_init(struct hdd_context * hdd_ctx)1602*5113495bSYour Name int hdd_scan_context_init(struct hdd_context *hdd_ctx)
1603*5113495bSYour Name {
1604*5113495bSYour Name 	return 0;
1605*5113495bSYour Name }
1606