blob: f14c283e3b4a426bde369588aad5b573fce082d6 [file] [log] [blame]
Vivek3e5a3ba2017-02-20 18:13:57 +05301/*
Jiachao Wua00b71b2018-01-02 16:21:45 +08002 * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved.
Vivek3e5a3ba2017-02-20 18:13:57 +05303 *
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: defines driver functions interfacing with linux kernel
21 */
22
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -080023#include <qdf_list.h>
24#include <qdf_status.h>
Vivek3e5a3ba2017-02-20 18:13:57 +053025#include <linux/wireless.h>
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -080026#include <linux/netdevice.h>
Vivek3e5a3ba2017-02-20 18:13:57 +053027#include <net/cfg80211.h>
Abhishek Singh9eb058a2017-02-17 18:21:13 +053028#include <wlan_scan_utils_api.h>
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -080029#include <wlan_cfg80211.h>
30#include <wlan_cfg80211_scan.h>
31#include <wlan_osif_priv.h>
32#include <wlan_scan_public_structs.h>
33#include <wlan_scan_ucfg_api.h>
34#include <wlan_cfg80211_scan.h>
35#include <qdf_mem.h>
36#include <wlan_utility.h>
Ajit Pal Singh2563e832017-05-04 22:58:42 +053037#ifdef WLAN_POLICY_MGR_ENABLE
Ajit Pal Singhec973b02017-04-17 16:49:01 +053038#include <wlan_policy_mgr_api.h>
Ajit Pal Singh2563e832017-05-04 22:58:42 +053039#endif
Shashikala Prabhu48ecda82018-04-13 01:13:30 +053040#include <wlan_reg_services_api.h>
Vivek3e5a3ba2017-02-20 18:13:57 +053041
Jeff Johnsonf155c672017-06-12 10:42:48 -070042static const
43struct nla_policy scan_policy[QCA_WLAN_VENDOR_ATTR_SCAN_MAX + 1] = {
44 [QCA_WLAN_VENDOR_ATTR_SCAN_FLAGS] = {.type = NLA_U32},
45 [QCA_WLAN_VENDOR_ATTR_SCAN_TX_NO_CCK_RATE] = {.type = NLA_FLAG},
46 [QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE] = {.type = NLA_U64},
47};
48
Arif Hussaind6b24322017-04-25 11:48:19 -070049#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0))
50static uint32_t hdd_config_sched_scan_start_delay(
51 struct cfg80211_sched_scan_request *request)
52{
53 return request->delay;
54}
55#else
56static uint32_t hdd_config_sched_scan_start_delay(
57 struct cfg80211_sched_scan_request *request)
58{
59 return 0;
60}
61#endif
62
Rajeev Kumar Sirasanagandlad8d18f12017-06-08 18:12:50 +053063#if defined(CFG80211_SCAN_RANDOM_MAC_ADDR) || \
64 (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0))
65/**
66 * wlan_fill_scan_rand_attrs() - Populate the scan randomization attrs
67 * @vdev: pointer to objmgr vdev
68 * @flags: cfg80211 scan flags
69 * @mac_addr: random mac addr from cfg80211
70 * @mac_addr_mask: mac addr mask from cfg80211
71 * @randomize: output variable to check scan randomization status
72 * @addr: output variable to hold random addr
73 * @mask: output variable to hold mac mask
74 *
75 * Return: None
76 */
77static void wlan_fill_scan_rand_attrs(struct wlan_objmgr_vdev *vdev,
78 uint32_t flags,
79 uint8_t *mac_addr,
80 uint8_t *mac_addr_mask,
81 bool *randomize,
82 uint8_t *addr,
83 uint8_t *mask)
84{
Kiran Kumar Lokere584e6612017-10-12 17:55:36 -070085 *randomize = false;
Rajeev Kumar Sirasanagandlad8d18f12017-06-08 18:12:50 +053086 if (!(flags & NL80211_SCAN_FLAG_RANDOM_ADDR))
87 return;
88
89 if (wlan_vdev_mlme_get_opmode(vdev) != QDF_STA_MODE)
90 return;
91
92 if (wlan_vdev_is_connected(vdev))
93 return;
94
95 *randomize = true;
96 memcpy(addr, mac_addr, QDF_MAC_ADDR_SIZE);
97 memcpy(mask, mac_addr_mask, QDF_MAC_ADDR_SIZE);
Yeshwanth Sriram Guntukadad6b5b2018-07-17 13:23:46 +053098 cfg80211_debug("Random mac addr: %pM and Random mac mask: %pM",
99 addr, mask);
Rajeev Kumar Sirasanagandlad8d18f12017-06-08 18:12:50 +0530100}
101
102/**
103 * wlan_scan_rand_attrs() - Wrapper function to fill scan random attrs
104 * @vdev: pointer to objmgr vdev
105 * @request: pointer to cfg80211 scan request
106 * @req: pointer to cmn module scan request
107 *
108 * This is a wrapper function which invokes wlan_fill_scan_rand_attrs()
109 * to fill random attributes of internal scan request with cfg80211_scan_request
110 *
111 * Return: None
112 */
113static void wlan_scan_rand_attrs(struct wlan_objmgr_vdev *vdev,
114 struct cfg80211_scan_request *request,
115 struct scan_start_request *req)
116{
117 bool *randomize = &req->scan_req.scan_random.randomize;
118 uint8_t *mac_addr = req->scan_req.scan_random.mac_addr;
119 uint8_t *mac_mask = req->scan_req.scan_random.mac_mask;
120
121 wlan_fill_scan_rand_attrs(vdev, request->flags, request->mac_addr,
122 request->mac_addr_mask, randomize, mac_addr,
123 mac_mask);
124 if (!*randomize)
125 return;
126
127 req->scan_req.scan_f_add_spoofed_mac_in_probe = true;
128 req->scan_req.scan_f_add_rand_seq_in_probe = true;
129}
130#else
131/**
132 * wlan_scan_rand_attrs() - Wrapper function to fill scan random attrs
133 * @vdev: pointer to objmgr vdev
134 * @request: pointer to cfg80211 scan request
135 * @req: pointer to cmn module scan request
136 *
137 * This is a wrapper function which invokes wlan_fill_scan_rand_attrs()
138 * to fill random attributes of internal scan request with cfg80211_scan_request
139 *
140 * Return: None
141 */
142static void wlan_scan_rand_attrs(struct wlan_objmgr_vdev *vdev,
143 struct cfg80211_scan_request *request,
144 struct scan_start_request *req)
145{
146}
147#endif
148
Abhishek Singh8c6e82d2017-03-03 21:57:29 +0530149#ifdef FEATURE_WLAN_SCAN_PNO
150#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) || \
151 defined(CFG80211_MULTI_SCAN_PLAN_BACKPORT))
152
153/**
154 * wlan_config_sched_scan_plan() - configures the sched scan plans
155 * from the framework.
156 * @pno_req: pointer to PNO scan request
157 * @request: pointer to scan request from framework
158 *
159 * Return: None
160 */
161static void wlan_config_sched_scan_plan(struct pno_scan_req_params *pno_req,
162 struct cfg80211_sched_scan_request *request)
163{
Abhishek Singh8c6e82d2017-03-03 21:57:29 +0530164 /*
165 * As of now max 2 scan plans were supported by firmware
166 * if number of scan plan supported by firmware increased below logic
167 * must change.
168 */
169 if (request->n_scan_plans == SCAN_PNO_MAX_PLAN_REQUEST) {
170 pno_req->fast_scan_period =
171 request->scan_plans[0].interval * MSEC_PER_SEC;
172 pno_req->fast_scan_max_cycles =
173 request->scan_plans[0].iterations;
174 pno_req->slow_scan_period =
175 request->scan_plans[1].interval * MSEC_PER_SEC;
176 } else if (request->n_scan_plans == 1) {
177 pno_req->fast_scan_period =
178 request->scan_plans[0].interval * MSEC_PER_SEC;
179 /*
180 * if only one scan plan is configured from framework
181 * then both fast and slow scan should be configured with the
182 * same value that is why fast scan cycles are hardcoded to one
183 */
184 pno_req->fast_scan_max_cycles = 1;
185 pno_req->slow_scan_period =
186 request->scan_plans[0].interval * MSEC_PER_SEC;
187 } else {
188 cfg80211_err("Invalid number of scan plans %d !!",
189 request->n_scan_plans);
190 }
191}
192#else
193static void wlan_config_sched_scan_plan(struct pno_scan_req_params *pno_req,
194 struct cfg80211_sched_scan_request *request)
195{
196 pno_req->fast_scan_period = request->interval;
197 pno_req->fast_scan_max_cycles = SCAN_PNO_DEF_SCAN_TIMER_REPEAT;
198 pno_req->slow_scan_period =
199 SCAN_PNO_DEF_SLOW_SCAN_MULTIPLIER *
200 pno_req->fast_scan_period;
201}
202#endif
203
Dustin Brown9feb2012017-08-11 17:33:19 -0700204#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0)
205static inline void
206wlan_cfg80211_sched_scan_results(struct wiphy *wiphy, uint64_t reqid)
207{
208 cfg80211_sched_scan_results(wiphy);
209}
210#else
211static inline void
212wlan_cfg80211_sched_scan_results(struct wiphy *wiphy, uint64_t reqid)
213{
214 cfg80211_sched_scan_results(wiphy, reqid);
215}
216#endif
217
Abhishek Singh8c6e82d2017-03-03 21:57:29 +0530218/**
219 * wlan_cfg80211_pno_callback() - pno callback function to handle
220 * pno events.
221 * @vdev: vdev ptr
222 * @event: scan events
223 * @args: argument
224 *
225 * Return: void
226 */
227static void wlan_cfg80211_pno_callback(struct wlan_objmgr_vdev *vdev,
228 struct scan_event *event,
229 void *args)
230{
231 struct wlan_objmgr_pdev *pdev;
232 struct pdev_osif_priv *pdev_ospriv;
233
234 if (event->type != SCAN_EVENT_TYPE_NLO_COMPLETE)
235 return;
236
Yeshwanth Sriram Guntukadad6b5b2018-07-17 13:23:46 +0530237 cfg80211_debug("vdev id = %d", event->vdev_id);
Abhishek Singh8c6e82d2017-03-03 21:57:29 +0530238
Abhishek Singh8c6e82d2017-03-03 21:57:29 +0530239 pdev = wlan_vdev_get_pdev(vdev);
Abhishek Singh8c6e82d2017-03-03 21:57:29 +0530240 if (!pdev) {
241 cfg80211_err("pdev is NULL");
242 return;
243 }
244
Abhishek Singh8c6e82d2017-03-03 21:57:29 +0530245 pdev_ospriv = wlan_pdev_get_ospriv(pdev);
Abhishek Singh8c6e82d2017-03-03 21:57:29 +0530246 if (!pdev_ospriv) {
Dustin Brownf3351d92017-04-24 10:47:42 -0700247 cfg80211_err("pdev_ospriv is NULL");
Abhishek Singh8c6e82d2017-03-03 21:57:29 +0530248 return;
249 }
Dustin Brown9feb2012017-08-11 17:33:19 -0700250 wlan_cfg80211_sched_scan_results(pdev_ospriv->wiphy, 0);
Abhishek Singh8c6e82d2017-03-03 21:57:29 +0530251}
252
Ajit Pal Singh890fc8d2017-06-20 19:26:50 +0530253#ifdef WLAN_POLICY_MGR_ENABLE
254static bool wlan_cfg80211_is_ap_go_present(struct wlan_objmgr_psoc *psoc)
255{
256 return policy_mgr_mode_specific_connection_count(psoc,
Tushnim Bhattacharyyaf9409182018-03-28 17:23:55 -0700257 PM_SAP_MODE,
Ajit Pal Singh890fc8d2017-06-20 19:26:50 +0530258 NULL) ||
259 policy_mgr_mode_specific_connection_count(psoc,
Tushnim Bhattacharyyaf9409182018-03-28 17:23:55 -0700260 PM_P2P_GO_MODE,
Ajit Pal Singh890fc8d2017-06-20 19:26:50 +0530261 NULL);
262}
263
264static QDF_STATUS wlan_cfg80211_is_chan_ok_for_dnbs(
265 struct wlan_objmgr_psoc *psoc,
266 u8 channel, bool *ok)
267{
268 QDF_STATUS status = policy_mgr_is_chan_ok_for_dnbs(psoc, channel, ok);
269
270 if (QDF_IS_STATUS_ERROR(status)) {
271 cfg80211_err("DNBS check failed");
272 return status;
273 }
274
275 return QDF_STATUS_SUCCESS;
276}
277#else
278static bool wlan_cfg80211_is_ap_go_present(struct wlan_objmgr_psoc *psoc)
279{
280 return false;
281}
282
283static QDF_STATUS wlan_cfg80211_is_chan_ok_for_dnbs(
284 struct wlan_objmgr_psoc *psoc,
285 u8 channel,
286 bool *ok)
287{
288 if (!ok)
289 return QDF_STATUS_E_INVAL;
290
291 *ok = true;
292 return QDF_STATUS_SUCCESS;
293}
294#endif
295
Rajeev Kumar Sirasanagandlad8d18f12017-06-08 18:12:50 +0530296#if defined(CFG80211_SCAN_RANDOM_MAC_ADDR) || \
297 (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0))
298/**
299 * wlan_pno_scan_rand_attr() - Wrapper function to fill sched scan random attrs
300 * @vdev: pointer to objmgr vdev
301 * @request: pointer to cfg80211 sched scan request
302 * @req: pointer to cmn module pno scan request
303 *
304 * This is a wrapper function which invokes wlan_fill_scan_rand_attrs()
305 * to fill random attributes of internal pno scan
306 * with cfg80211_sched_scan_request
307 *
308 * Return: None
309 */
310static void wlan_pno_scan_rand_attr(struct wlan_objmgr_vdev *vdev,
311 struct cfg80211_sched_scan_request *request,
312 struct pno_scan_req_params *req)
313{
314 bool *randomize = &req->scan_random.randomize;
315 uint8_t *mac_addr = req->scan_random.mac_addr;
316 uint8_t *mac_mask = req->scan_random.mac_mask;
317
318 wlan_fill_scan_rand_attrs(vdev, request->flags, request->mac_addr,
319 request->mac_addr_mask, randomize, mac_addr,
320 mac_mask);
321}
322#else
323/**
324 * wlan_pno_scan_rand_attr() - Wrapper function to fill sched scan random attrs
325 * @vdev: pointer to objmgr vdev
326 * @request: pointer to cfg80211 sched scan request
327 * @req: pointer to cmn module pno scan request
328 *
329 * This is a wrapper function which invokes wlan_fill_scan_rand_attrs()
330 * to fill random attributes of internal pno scan
331 * with cfg80211_sched_scan_request
332 *
333 * Return: None
334 */
335static void wlan_pno_scan_rand_attr(struct wlan_objmgr_vdev *vdev,
336 struct cfg80211_sched_scan_request *request,
337 struct pno_scan_req_params *req)
338{
339}
340#endif
341
Sreelakshmi Konamki77dd1ef2017-07-21 17:37:30 +0530342/**
343 * wlan_hdd_sched_scan_update_relative_rssi() - update CPNO params
344 * @pno_request: pointer to PNO scan request
345 * @request: Pointer to cfg80211 scheduled scan start request
346 *
347 * This function is used to update Connected PNO params sent by kernel
348 *
349 * Return: None
350 */
Arif Hussain083d9da2018-04-26 18:20:24 -0700351#if defined(CFG80211_REPORT_BETTER_BSS_IN_SCHED_SCAN) || \
352 (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0))
Sreelakshmi Konamki77dd1ef2017-07-21 17:37:30 +0530353static inline void wlan_hdd_sched_scan_update_relative_rssi(
354 struct pno_scan_req_params *pno_request,
355 struct cfg80211_sched_scan_request *request)
356{
357 pno_request->relative_rssi_set = request->relative_rssi_set;
358 pno_request->relative_rssi = request->relative_rssi;
359 if (NL80211_BAND_2GHZ == request->rssi_adjust.band)
360 pno_request->band_rssi_pref.band = WLAN_BAND_2_4_GHZ;
361 else if (NL80211_BAND_5GHZ == request->rssi_adjust.band)
362 pno_request->band_rssi_pref.band = WLAN_BAND_5_GHZ;
363 pno_request->band_rssi_pref.rssi = request->rssi_adjust.delta;
364}
365#else
366static inline void wlan_hdd_sched_scan_update_relative_rssi(
367 struct pno_scan_req_params *pno_request,
368 struct cfg80211_sched_scan_request *request)
369{
370}
371#endif
372
Abhishek Singh8c6e82d2017-03-03 21:57:29 +0530373int wlan_cfg80211_sched_scan_start(struct wlan_objmgr_pdev *pdev,
374 struct net_device *dev,
Dustin Brownf3351d92017-04-24 10:47:42 -0700375 struct cfg80211_sched_scan_request *request,
376 uint8_t scan_backoff_multiplier)
Abhishek Singh8c6e82d2017-03-03 21:57:29 +0530377{
378 struct pno_scan_req_params *req;
379 int i, j, ret = 0;
380 QDF_STATUS status;
381 uint8_t num_chan = 0, channel;
382 struct wlan_objmgr_vdev *vdev;
Abhishek Singh5468c572017-04-11 18:20:44 +0530383 struct wlan_objmgr_psoc *psoc;
Abhishek Singh8c6e82d2017-03-03 21:57:29 +0530384 uint32_t valid_ch[SCAN_PNO_MAX_NETW_CHANNELS_EX] = {0};
385
386 vdev = wlan_objmgr_get_vdev_by_macaddr_from_pdev(pdev, dev->dev_addr,
387 WLAN_OSIF_ID);
388 if (!vdev) {
389 cfg80211_err("vdev object is NULL");
390 return -EIO;
391 }
392
Abhishek Singh5468c572017-04-11 18:20:44 +0530393 if (ucfg_scan_get_pno_in_progress(vdev)) {
394 cfg80211_debug("pno is already in progress");
395 wlan_objmgr_vdev_release_ref(vdev, WLAN_OSIF_ID);
396 return -EBUSY;
397 }
398
Abhishek Singh8c6e82d2017-03-03 21:57:29 +0530399 if (ucfg_scan_get_pdev_status(pdev) !=
400 SCAN_NOT_IN_PROGRESS) {
401 status = wlan_abort_scan(pdev,
402 wlan_objmgr_pdev_get_pdev_id(pdev),
Abhishek Singhf95b9e42017-04-25 12:12:01 +0530403 INVAL_VDEV_ID, INVAL_SCAN_ID, true);
Abhishek Singh8c6e82d2017-03-03 21:57:29 +0530404 if (QDF_IS_STATUS_ERROR(status)) {
405 cfg80211_err("aborting the existing scan is unsuccessful");
406 wlan_objmgr_vdev_release_ref(vdev, WLAN_OSIF_ID);
407 return -EBUSY;
408 }
409 }
410
411 req = qdf_mem_malloc(sizeof(*req));
412 if (!req) {
413 cfg80211_err("req malloc failed");
414 wlan_objmgr_vdev_release_ref(vdev, WLAN_OSIF_ID);
415 return -ENOMEM;
416 }
417
Ajit Pal Singh890fc8d2017-06-20 19:26:50 +0530418 wlan_pdev_obj_lock(pdev);
419 psoc = wlan_pdev_get_psoc(pdev);
420 wlan_pdev_obj_unlock(pdev);
421
Abhishek Singh8c6e82d2017-03-03 21:57:29 +0530422 req->networks_cnt = request->n_match_sets;
Abhishek Singh8c6e82d2017-03-03 21:57:29 +0530423 req->vdev_id = wlan_vdev_get_id(vdev);
Abhishek Singh8c6e82d2017-03-03 21:57:29 +0530424
425 if ((!req->networks_cnt) ||
426 (req->networks_cnt > SCAN_PNO_MAX_SUPP_NETWORKS)) {
427 cfg80211_err("Network input is not correct %d",
428 req->networks_cnt);
429 ret = -EINVAL;
430 goto error;
431 }
432
433 if (request->n_channels > SCAN_PNO_MAX_NETW_CHANNELS_EX) {
434 cfg80211_err("Incorrect number of channels %d",
435 request->n_channels);
436 ret = -EINVAL;
437 goto error;
438 }
439
440 if (request->n_channels) {
441 char chl[(request->n_channels * 5) + 1];
442 int len = 0;
Ajit Pal Singh890fc8d2017-06-20 19:26:50 +0530443 bool ap_or_go_present = wlan_cfg80211_is_ap_go_present(psoc);
Abhishek Singh8c6e82d2017-03-03 21:57:29 +0530444
445 for (i = 0; i < request->n_channels; i++) {
446 channel = request->channels[i]->hw_value;
Kiran Kumar Lokereb49263b2018-05-15 15:48:57 -0700447 if (wlan_reg_is_dsrc_chan(pdev, channel))
Abhishek Singh8c6e82d2017-03-03 21:57:29 +0530448 continue;
Ajit Pal Singh890fc8d2017-06-20 19:26:50 +0530449
450 if (ap_or_go_present) {
451 bool ok;
452
453 status =
454 wlan_cfg80211_is_chan_ok_for_dnbs(psoc,
455 channel,
456 &ok);
457 if (QDF_IS_STATUS_ERROR(status)) {
458 cfg80211_err("DNBS check failed");
459 qdf_mem_free(req);
460 ret = -EINVAL;
461 goto error;
462 }
463 if (!ok)
464 continue;
465 }
Abhishek Singh8c6e82d2017-03-03 21:57:29 +0530466 len += snprintf(chl + len, 5, "%d ", channel);
467 valid_ch[num_chan++] = wlan_chan_to_freq(channel);
468 }
469 cfg80211_notice("No. of Scan Channels: %d", num_chan);
470 cfg80211_notice("Channel-List: %s", chl);
471 /* If all channels are DFS and dropped,
472 * then ignore the PNO request
473 */
474 if (!num_chan) {
475 cfg80211_notice("Channel list empty due to filtering of DSRC");
476 ret = -EINVAL;
477 goto error;
478 }
479 }
480
481 /* Filling per profile params */
482 for (i = 0; i < req->networks_cnt; i++) {
483 req->networks_list[i].ssid.length =
484 request->match_sets[i].ssid.ssid_len;
485
486 if ((!req->networks_list[i].ssid.length) ||
487 (req->networks_list[i].ssid.length > WLAN_SSID_MAX_LEN)) {
488 cfg80211_err(" SSID Len %d is not correct for network %d",
489 req->networks_list[i].ssid.length, i);
490 ret = -EINVAL;
491 goto error;
492 }
493
494 qdf_mem_copy(req->networks_list[i].ssid.ssid,
495 request->match_sets[i].ssid.ssid,
496 req->networks_list[i].ssid.length);
497 req->networks_list[i].authentication = 0; /*eAUTH_TYPE_ANY */
498 req->networks_list[i].encryption = 0; /*eED_ANY */
499 req->networks_list[i].bc_new_type = 0; /*eBCAST_UNKNOWN */
500
501 cfg80211_notice("Received ssid:%.*s",
502 req->networks_list[i].ssid.length,
503 req->networks_list[i].ssid.ssid);
504
505 /*Copying list of valid channel into request */
506 qdf_mem_copy(req->networks_list[i].channels, valid_ch,
507 num_chan * sizeof(uint32_t));
508 req->networks_list[i].channel_cnt = num_chan;
509 req->networks_list[i].rssi_thresh =
510 request->match_sets[i].rssi_thold;
511 }
512
Manjeet Singhc73cd7d2016-08-11 15:31:34 +0530513 /* set scan to passive if no SSIDs are specified in the request */
514 if (0 == request->n_ssids)
515 req->do_passive_scan = true;
516 else
517 req->do_passive_scan = false;
518
Abhishek Singh8c6e82d2017-03-03 21:57:29 +0530519 for (i = 0; i < request->n_ssids; i++) {
520 j = 0;
521 while (j < req->networks_cnt) {
522 if ((req->networks_list[j].ssid.length ==
523 request->ssids[i].ssid_len) &&
524 (!qdf_mem_cmp(req->networks_list[j].ssid.ssid,
525 request->ssids[i].ssid,
526 req->networks_list[j].ssid.length))) {
527 req->networks_list[j].bc_new_type =
528 SSID_BC_TYPE_HIDDEN;
529 break;
530 }
531 j++;
532 }
533 }
534 cfg80211_notice("Number of hidden networks being Configured = %d",
535 request->n_ssids);
536
Kiran Kumar Lokere584e6612017-10-12 17:55:36 -0700537 if (req->scan_random.randomize)
538 wlan_pno_scan_rand_attr(vdev, request, req);
Abhishek Singh8c6e82d2017-03-03 21:57:29 +0530539 /*
540 * Before Kernel 4.4
541 * Driver gets only one time interval which is hard coded in
542 * supplicant for 10000ms.
543 *
544 * After Kernel 4.4
545 * User can configure multiple scan_plans, each scan would have
546 * separate scan cycle and interval. (interval is in unit of second.)
547 * For our use case, we would only have supplicant set one scan_plan,
548 * and firmware also support only one as well, so pick up the first
549 * index.
550 *
551 * Taking power consumption into account
552 * firmware after gPNOScanTimerRepeatValue times fast_scan_period
553 * switches slow_scan_period. This is less frequent scans and firmware
554 * shall be in slow_scan_period mode until next PNO Start.
555 */
556 wlan_config_sched_scan_plan(req, request);
Arif Hussaind6b24322017-04-25 11:48:19 -0700557 req->delay_start_time = hdd_config_sched_scan_start_delay(request);
Dustin Brownf3351d92017-04-24 10:47:42 -0700558 req->scan_backoff_multiplier = scan_backoff_multiplier;
Abhishek Singh8c6e82d2017-03-03 21:57:29 +0530559 cfg80211_notice("Base scan interval: %d sec, scan cycles: %d, slow scan interval %d",
560 req->fast_scan_period, req->fast_scan_max_cycles,
561 req->slow_scan_period);
Sreelakshmi Konamki77dd1ef2017-07-21 17:37:30 +0530562 wlan_hdd_sched_scan_update_relative_rssi(req, request);
Abhishek Singh8c6e82d2017-03-03 21:57:29 +0530563
Vivek5ec0bd32017-06-23 21:05:31 +0530564 psoc = wlan_pdev_get_psoc(pdev);
Abhishek Singh5468c572017-04-11 18:20:44 +0530565 ucfg_scan_register_pno_cb(psoc,
566 wlan_cfg80211_pno_callback, NULL);
Abhishek Singh8c6e82d2017-03-03 21:57:29 +0530567 ucfg_scan_get_pno_def_params(vdev, req);
Rajeev Kumar Sirasanagandlaa3f4a292017-06-21 12:01:22 +0530568 if (ucfg_ie_whitelist_enabled(psoc, vdev))
569 ucfg_copy_ie_whitelist_attrs(psoc, &req->ie_whitelist);
Abhishek Singh8c6e82d2017-03-03 21:57:29 +0530570 status = ucfg_scan_pno_start(vdev, req);
571 if (QDF_IS_STATUS_ERROR(status)) {
572 cfg80211_err("Failed to enable PNO");
573 ret = -EINVAL;
574 goto error;
575 }
576
577 cfg80211_info("PNO scan request offloaded");
578
579error:
580 wlan_objmgr_vdev_release_ref(vdev, WLAN_OSIF_ID);
581 qdf_mem_free(req);
582 return ret;
583}
584
585int wlan_cfg80211_sched_scan_stop(struct wlan_objmgr_pdev *pdev,
586 struct net_device *dev)
587{
588 int ret = 0;
589 QDF_STATUS status;
590 struct wlan_objmgr_vdev *vdev;
591
592 vdev = wlan_objmgr_get_vdev_by_macaddr_from_pdev(pdev, dev->dev_addr,
593 WLAN_OSIF_ID);
594 if (!vdev) {
595 cfg80211_err("vdev object is NULL");
596 return -EIO;
597 }
598
599 status = ucfg_scan_pno_stop(vdev);
600 if (QDF_IS_STATUS_ERROR(status)) {
601 cfg80211_err("Failed to disabled PNO");
602 ret = -EINVAL;
603 } else {
604 cfg80211_info("PNO scan disabled");
605 }
606
607 wlan_objmgr_vdev_release_ref(vdev, WLAN_OSIF_ID);
608 return ret;
609}
Abhishek Singh8c6e82d2017-03-03 21:57:29 +0530610#endif /*FEATURE_WLAN_SCAN_PNO */
611
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -0800612/**
Om Prakash Tripathi7d867d62017-04-26 16:52:09 +0530613 * wlan_copy_bssid_scan_request() - API to copy the bssid to Scan request
614 * @scan_req: Pointer to scan_start_request
615 * @request: scan request from Supplicant
616 *
617 * This API copies the BSSID in scan request from Supplicant and copies it to
618 * the scan_start_request
619 *
620 * Return: None
621 */
622#if defined(CFG80211_SCAN_BSSID) || \
623 (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0))
624static inline void
625wlan_copy_bssid_scan_request(struct scan_start_request *scan_req,
626 struct cfg80211_scan_request *request)
627{
628 qdf_mem_copy(scan_req->scan_req.bssid_list[0].bytes,
629 request->bssid, QDF_MAC_ADDR_SIZE);
630}
631#else
632static inline void
633wlan_copy_bssid_scan_request(struct scan_start_request *scan_req,
634 struct cfg80211_scan_request *request)
635{
636
637}
638#endif
639
640/**
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -0800641 * wlan_scan_request_enqueue() - enqueue Scan Request
642 * @pdev: pointer to pdev object
643 * @req: Pointer to the scan request
644 * @source: source of the scan request
645 * @scan_id: scan identifier
646 *
647 * Enqueue scan request in the global scan list.This list
648 * stores the active scan request information.
649 *
650 * Return: 0 on success, error number otherwise
651 */
652static int wlan_scan_request_enqueue(struct wlan_objmgr_pdev *pdev,
653 struct cfg80211_scan_request *req,
654 uint8_t source, uint32_t scan_id)
Vivek3e5a3ba2017-02-20 18:13:57 +0530655{
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -0800656 struct scan_req *scan_req;
657 QDF_STATUS status;
658 struct pdev_osif_priv *osif_ctx;
659 struct osif_scan_pdev *osif_scan;
660
661 scan_req = qdf_mem_malloc(sizeof(*scan_req));
662 if (NULL == scan_req) {
663 cfg80211_alert("malloc failed for Scan req");
664 return -ENOMEM;
665 }
666
667 /* Get NL global context from objmgr*/
668 osif_ctx = wlan_pdev_get_ospriv(pdev);
669 osif_scan = osif_ctx->osif_scan;
670 scan_req->scan_request = req;
671 scan_req->source = source;
672 scan_req->scan_id = scan_id;
Jiachao Wua00b71b2018-01-02 16:21:45 +0800673 scan_req->dev = req->wdev->netdev;
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -0800674
Sandeep Puligilla15677ec2017-06-06 18:31:39 -0700675 qdf_mutex_acquire(&osif_scan->scan_req_q_lock);
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -0800676 status = qdf_list_insert_back(&osif_scan->scan_req_q,
677 &scan_req->node);
Sandeep Puligilla15677ec2017-06-06 18:31:39 -0700678 qdf_mutex_release(&osif_scan->scan_req_q_lock);
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -0800679 if (QDF_STATUS_SUCCESS != status) {
680 cfg80211_err("Failed to enqueue Scan Req");
681 qdf_mem_free(scan_req);
682 return -EINVAL;
683 }
684
685 return 0;
686}
687
688/**
689 * wlan_scan_request_dequeue() - dequeue scan request
690 * @nl_ctx: Global HDD context
691 * @scan_id: scan id
692 * @req: scan request
Jiachao Wua00b71b2018-01-02 16:21:45 +0800693 * @dev: net device
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -0800694 * @source : returns source of the scan request
695 *
696 * Return: QDF_STATUS
697 */
698static QDF_STATUS wlan_scan_request_dequeue(
699 struct wlan_objmgr_pdev *pdev,
Jiachao Wua00b71b2018-01-02 16:21:45 +0800700 uint32_t scan_id, struct cfg80211_scan_request **req,
701 uint8_t *source, struct net_device **dev)
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -0800702{
703 QDF_STATUS status = QDF_STATUS_E_FAILURE;
704 struct scan_req *scan_req;
705 qdf_list_node_t *node = NULL, *next_node = NULL;
706 struct pdev_osif_priv *osif_ctx;
707 struct osif_scan_pdev *scan_priv;
708
Yeshwanth Sriram Guntukadad6b5b2018-07-17 13:23:46 +0530709 cfg80211_debug("Dequeue Scan id: %d", scan_id);
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -0800710
711 if ((source == NULL) || (req == NULL)) {
712 cfg80211_err("source or request is NULL");
713 return QDF_STATUS_E_NULL_VALUE;
714 }
715
716 /* Get NL global context from objmgr*/
717 osif_ctx = wlan_pdev_get_ospriv(pdev);
718 if (!osif_ctx) {
719 cfg80211_err("Failed to retrieve osif context");
720 return status;
721 }
722 scan_priv = osif_ctx->osif_scan;
723
724 if (qdf_list_empty(&scan_priv->scan_req_q)) {
725 cfg80211_info("Scan List is empty");
726 return QDF_STATUS_E_FAILURE;
727 }
728
Sandeep Puligilla15677ec2017-06-06 18:31:39 -0700729 qdf_mutex_acquire(&scan_priv->scan_req_q_lock);
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -0800730 if (QDF_STATUS_SUCCESS !=
731 qdf_list_peek_front(&scan_priv->scan_req_q, &next_node)) {
Sandeep Puligilla15677ec2017-06-06 18:31:39 -0700732 qdf_mutex_release(&scan_priv->scan_req_q_lock);
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -0800733 cfg80211_err("Failed to remove Scan Req from queue");
734 return QDF_STATUS_E_FAILURE;
735 }
736
737 do {
738 node = next_node;
739 scan_req = qdf_container_of(node, struct scan_req,
740 node);
741 if (scan_req->scan_id == scan_id) {
742 status = qdf_list_remove_node(&scan_priv->scan_req_q,
743 node);
744 if (status == QDF_STATUS_SUCCESS) {
745 *req = scan_req->scan_request;
746 *source = scan_req->source;
Jiachao Wua00b71b2018-01-02 16:21:45 +0800747 *dev = scan_req->dev;
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -0800748 qdf_mem_free(scan_req);
Sandeep Puligilla15677ec2017-06-06 18:31:39 -0700749 qdf_mutex_release(&scan_priv->scan_req_q_lock);
Yeshwanth Sriram Guntukadad6b5b2018-07-17 13:23:46 +0530750 cfg80211_debug("removed Scan id: %d, req = %pK, pending scans %d",
751 scan_id, req,
752 qdf_list_size(&scan_priv->
753 scan_req_q));
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -0800754 return QDF_STATUS_SUCCESS;
755 } else {
Sandeep Puligilla15677ec2017-06-06 18:31:39 -0700756 qdf_mutex_release(&scan_priv->scan_req_q_lock);
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -0800757 cfg80211_err("Failed to remove node scan id %d, pending scans %d",
758 scan_id,
759 qdf_list_size(&scan_priv->scan_req_q));
760 return status;
761 }
762 }
763 } while (QDF_STATUS_SUCCESS ==
764 qdf_list_peek_next(&scan_priv->scan_req_q, node, &next_node));
Sandeep Puligilla15677ec2017-06-06 18:31:39 -0700765 qdf_mutex_release(&scan_priv->scan_req_q_lock);
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -0800766 cfg80211_err("Failed to find scan id %d", scan_id);
767
768 return status;
769}
770
771#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0))
772/**
773 * wlan_cfg80211_scan_done() - Scan completed callback to cfg80211
Jiachao Wua00b71b2018-01-02 16:21:45 +0800774 * @netdev: Net device
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -0800775 * @req : Scan request
776 * @aborted : true scan aborted false scan success
777 *
778 * This function notifies scan done to cfg80211
779 *
780 * Return: none
781 */
Jiachao Wua00b71b2018-01-02 16:21:45 +0800782static void wlan_cfg80211_scan_done(struct net_device *netdev,
783 struct cfg80211_scan_request *req,
784 bool aborted)
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -0800785{
786 struct cfg80211_scan_info info = {
787 .aborted = aborted
788 };
789
Jiachao Wua00b71b2018-01-02 16:21:45 +0800790 if (netdev->flags & IFF_UP)
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -0800791 cfg80211_scan_done(req, &info);
792}
793#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
794/**
795 * wlan_cfg80211_scan_done() - Scan completed callback to cfg80211
Jiachao Wua00b71b2018-01-02 16:21:45 +0800796 * @netdev: Net device
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -0800797 * @req : Scan request
798 * @aborted : true scan aborted false scan success
799 *
800 * This function notifies scan done to cfg80211
801 *
802 * Return: none
803 */
Jiachao Wua00b71b2018-01-02 16:21:45 +0800804static void wlan_cfg80211_scan_done(struct net_device *netdev,
805 struct cfg80211_scan_request *req,
806 bool aborted)
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -0800807{
Jiachao Wua00b71b2018-01-02 16:21:45 +0800808 if (netdev->flags & IFF_UP)
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -0800809 cfg80211_scan_done(req, aborted);
810}
811#endif
812
813/**
814 * wlan_vendor_scan_callback() - Scan completed callback event
815 *
816 * @req : Scan request
817 * @aborted : true scan aborted false scan success
818 *
819 * This function sends scan completed callback event to NL.
820 *
821 * Return: none
822 */
823static void wlan_vendor_scan_callback(struct cfg80211_scan_request *req,
824 bool aborted)
825{
826 struct sk_buff *skb;
827 struct nlattr *attr;
828 int i;
829 uint8_t scan_status;
830 uint64_t cookie;
831
832 skb = cfg80211_vendor_event_alloc(req->wdev->wiphy, req->wdev,
833 SCAN_DONE_EVENT_BUF_SIZE + 4 + NLMSG_HDRLEN,
834 QCA_NL80211_VENDOR_SUBCMD_SCAN_DONE_INDEX,
Om Prakash Tripathi9b56f5d2018-05-29 11:42:19 +0530835 GFP_ATOMIC);
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -0800836
837 if (!skb) {
838 cfg80211_err("skb alloc failed");
839 qdf_mem_free(req);
840 return;
841 }
842
843 cookie = (uintptr_t)req;
844
845 attr = nla_nest_start(skb, QCA_WLAN_VENDOR_ATTR_SCAN_SSIDS);
846 if (!attr)
847 goto nla_put_failure;
848 for (i = 0; i < req->n_ssids; i++) {
849 if (nla_put(skb, i, req->ssids[i].ssid_len, req->ssids[i].ssid))
850 goto nla_put_failure;
851 }
852 nla_nest_end(skb, attr);
853
854 attr = nla_nest_start(skb, QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES);
855 if (!attr)
856 goto nla_put_failure;
857 for (i = 0; i < req->n_channels; i++) {
858 if (nla_put_u32(skb, i, req->channels[i]->center_freq))
859 goto nla_put_failure;
860 }
861 nla_nest_end(skb, attr);
862
863 if (req->ie &&
864 nla_put(skb, QCA_WLAN_VENDOR_ATTR_SCAN_IE, req->ie_len,
865 req->ie))
866 goto nla_put_failure;
867
868 if (req->flags &&
869 nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_SCAN_FLAGS, req->flags))
870 goto nla_put_failure;
871
872 if (wlan_cfg80211_nla_put_u64(skb, QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE,
873 cookie))
874 goto nla_put_failure;
875
876 scan_status = (aborted == true) ? VENDOR_SCAN_STATUS_ABORTED :
877 VENDOR_SCAN_STATUS_NEW_RESULTS;
878 if (nla_put_u8(skb, QCA_WLAN_VENDOR_ATTR_SCAN_STATUS, scan_status))
879 goto nla_put_failure;
880
Om Prakash Tripathi9b56f5d2018-05-29 11:42:19 +0530881 cfg80211_vendor_event(skb, GFP_ATOMIC);
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -0800882 qdf_mem_free(req);
883
884 return;
885
886nla_put_failure:
887 kfree_skb(skb);
888 qdf_mem_free(req);
889}
890
891
892/**
893 * wlan_cfg80211_scan_done_callback() - scan done callback function called after
Abhishek Singh483d9142017-03-06 13:28:13 +0530894 * scan is finished
895 * @vdev: vdev ptr
896 * @event: Scan event
897 * @args: Scan cb arg
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -0800898 *
Abhishek Singh483d9142017-03-06 13:28:13 +0530899 * Return: void
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -0800900 */
901static void wlan_cfg80211_scan_done_callback(
902 struct wlan_objmgr_vdev *vdev,
903 struct scan_event *event,
904 void *args)
905{
906 struct cfg80211_scan_request *req = NULL;
Sandeep Puligillaf57464c2017-11-16 23:31:52 -0800907 bool success = false;
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -0800908 uint32_t scan_id = event->scan_id;
909 uint8_t source = NL_SCAN;
910 struct wlan_objmgr_pdev *pdev;
Abhishek Singhac803092017-04-19 12:35:11 +0530911 struct pdev_osif_priv *osif_priv;
Jiachao Wua00b71b2018-01-02 16:21:45 +0800912 struct net_device *netdev = NULL;
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -0800913 QDF_STATUS status;
914
Sandeep Puligillaf57464c2017-11-16 23:31:52 -0800915 if (!util_is_scan_completed(event, &success))
Abhishek Singh483d9142017-03-06 13:28:13 +0530916 return;
917
Yeshwanth Sriram Guntukadad6b5b2018-07-17 13:23:46 +0530918 cfg80211_debug("scan ID = %d vdev id = %d, event type %s(%d) reason = %s(%d)",
919 scan_id, event->vdev_id,
920 util_scan_get_ev_type_name(event->type), event->type,
921 util_scan_get_ev_reason_name(event->reason),
922 event->reason);
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -0800923
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -0800924 pdev = wlan_vdev_get_pdev(vdev);
Jiachao Wua00b71b2018-01-02 16:21:45 +0800925 status = wlan_scan_request_dequeue(
926 pdev, scan_id, &req, &source, &netdev);
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -0800927 if (QDF_IS_STATUS_ERROR(status)) {
928 cfg80211_err("Dequeue of scan request failed ID: %d", scan_id);
Abhishek Singhac803092017-04-19 12:35:11 +0530929 goto allow_suspend;
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -0800930 }
931
Jiachao Wua00b71b2018-01-02 16:21:45 +0800932 if (!netdev) {
Sandeep Puligilla0014f622017-06-06 19:27:17 -0700933 cfg80211_err("net dev is NULL,Drop scan event Id: %d",
934 scan_id);
935 goto allow_suspend;
936 }
937
938 /* Make sure vdev is active */
939 status = wlan_objmgr_vdev_try_get_ref(vdev, WLAN_OSIF_ID);
940 if (QDF_IS_STATUS_ERROR(status)) {
941 cfg80211_err("Failed to get vdev reference: scan Id: %d",
942 scan_id);
943 goto allow_suspend;
944 }
945
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -0800946 /*
947 * Scan can be triggred from NL or vendor scan
948 * - If scan is triggered from NL then cfg80211 scan done should be
949 * called to updated scan completion to NL.
950 * - If scan is triggred through vendor command then
951 * scan done event will be posted
952 */
953 if (NL_SCAN == source)
Sandeep Puligillaf57464c2017-11-16 23:31:52 -0800954 wlan_cfg80211_scan_done(netdev, req, !success);
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -0800955 else
Sandeep Puligillaf57464c2017-11-16 23:31:52 -0800956 wlan_vendor_scan_callback(req, !success);
Abhishek Singhac803092017-04-19 12:35:11 +0530957
Sandeep Puligilla0014f622017-06-06 19:27:17 -0700958 wlan_objmgr_vdev_release_ref(vdev, WLAN_OSIF_ID);
Abhishek Singhac803092017-04-19 12:35:11 +0530959allow_suspend:
960 osif_priv = wlan_pdev_get_ospriv(pdev);
961 if (qdf_list_empty(&osif_priv->osif_scan->scan_req_q))
962 qdf_runtime_pm_allow_suspend(
Prashanth Bhatta65b0eaa2017-01-19 15:33:43 -0800963 &osif_priv->osif_scan->runtime_pm_lock);
Abhishek Singhac803092017-04-19 12:35:11 +0530964
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -0800965}
966
Yue Ma04dfab52017-10-03 15:05:05 -0700967QDF_STATUS wlan_scan_runtime_pm_init(struct wlan_objmgr_pdev *pdev)
968{
969 struct pdev_osif_priv *osif_priv;
970 struct osif_scan_pdev *scan_priv;
971
972 wlan_pdev_obj_lock(pdev);
973 osif_priv = wlan_pdev_get_ospriv(pdev);
974 wlan_pdev_obj_unlock(pdev);
975
976 scan_priv = osif_priv->osif_scan;
977
978 return qdf_runtime_lock_init(&scan_priv->runtime_pm_lock);
979}
980
Abhishek Singhfb9d5ac2017-06-06 12:25:39 +0530981void wlan_scan_runtime_pm_deinit(struct wlan_objmgr_pdev *pdev)
982{
983 struct pdev_osif_priv *osif_priv;
984 struct osif_scan_pdev *scan_priv;
985
986 wlan_pdev_obj_lock(pdev);
987 osif_priv = wlan_pdev_get_ospriv(pdev);
988 wlan_pdev_obj_unlock(pdev);
989
990 scan_priv = osif_priv->osif_scan;
Prashanth Bhatta65b0eaa2017-01-19 15:33:43 -0800991 qdf_runtime_lock_deinit(&scan_priv->runtime_pm_lock);
Abhishek Singhfb9d5ac2017-06-06 12:25:39 +0530992}
993
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -0800994QDF_STATUS wlan_cfg80211_scan_priv_init(struct wlan_objmgr_pdev *pdev)
995{
996 struct pdev_osif_priv *osif_priv;
997 struct osif_scan_pdev *scan_priv;
998 struct wlan_objmgr_psoc *psoc;
999 wlan_scan_requester req_id;
1000
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -08001001 psoc = wlan_pdev_get_psoc(pdev);
Abhishek Singh8c6e82d2017-03-03 21:57:29 +05301002
Om Prakash Tripathi7d867d62017-04-26 16:52:09 +05301003 req_id = ucfg_scan_register_requester(psoc, "CFG",
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -08001004 wlan_cfg80211_scan_done_callback, NULL);
1005
1006 osif_priv = wlan_pdev_get_ospriv(pdev);
1007 scan_priv = qdf_mem_malloc(sizeof(*scan_priv));
1008 if (!scan_priv) {
1009 cfg80211_err("failed to allocate memory");
1010 return QDF_STATUS_E_NOMEM;
1011 }
1012 /* Initialize the scan request queue */
1013 osif_priv->osif_scan = scan_priv;
1014 qdf_list_create(&scan_priv->scan_req_q, WLAN_MAX_SCAN_COUNT);
Sandeep Puligilla15677ec2017-06-06 18:31:39 -07001015 qdf_mutex_create(&scan_priv->scan_req_q_lock);
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -08001016 scan_priv->req_id = req_id;
1017
1018 return QDF_STATUS_SUCCESS;
1019}
1020
Sandeep Puligillaea68a2c2017-04-13 18:07:06 -07001021QDF_STATUS wlan_cfg80211_scan_priv_deinit(struct wlan_objmgr_pdev *pdev)
1022{
1023 struct pdev_osif_priv *osif_priv;
1024 struct osif_scan_pdev *scan_priv;
1025 struct wlan_objmgr_psoc *psoc;
1026
Sandeep Puligillaea68a2c2017-04-13 18:07:06 -07001027 psoc = wlan_pdev_get_psoc(pdev);
1028 osif_priv = wlan_pdev_get_ospriv(pdev);
Sandeep Puligillaea68a2c2017-04-13 18:07:06 -07001029
Soumya Bhat8b2a5352018-02-21 15:57:34 +05301030 wlan_cfg80211_cleanup_scan_queue(pdev, NULL);
Sandeep Puligillaea68a2c2017-04-13 18:07:06 -07001031 scan_priv = osif_priv->osif_scan;
Sandeep Puligillaea68a2c2017-04-13 18:07:06 -07001032 ucfg_scan_unregister_requester(psoc, scan_priv->req_id);
1033 qdf_list_destroy(&scan_priv->scan_req_q);
Sandeep Puligilla15677ec2017-06-06 18:31:39 -07001034 qdf_mutex_destroy(&scan_priv->scan_req_q_lock);
Sandeep Puligillaea68a2c2017-04-13 18:07:06 -07001035 qdf_mem_free(scan_priv);
Sandeep Puligilla4bd7f8c2017-11-01 23:52:23 -07001036 osif_priv->osif_scan = NULL;
Sandeep Puligillaea68a2c2017-04-13 18:07:06 -07001037
1038 return QDF_STATUS_SUCCESS;
1039}
1040
Soumya Bhat8b2a5352018-02-21 15:57:34 +05301041/**
1042 * wlan_cfg80211_enqueue_for_cleanup() - Function to populate scan cleanup queue
1043 * @scan_cleanup_q: Scan cleanup queue to be populated
1044 * @scan_priv: Pointer to scan related data used by cfg80211 scan
1045 * @dev: Netdevice pointer
1046 *
1047 * The function synchrounously iterates through the global scan queue to
1048 * identify entries that have to be cleaned up, copies identified entries
1049 * to another queue(to send scan complete event to NL later) and removes the
1050 * entry from the global scan queue.
1051 *
1052 * Return: None
1053 */
1054static void
1055wlan_cfg80211_enqueue_for_cleanup(qdf_list_t *scan_cleanup_q,
1056 struct osif_scan_pdev *scan_priv,
1057 struct net_device *dev)
1058{
1059 struct scan_req *scan_req, *scan_cleanup;
1060 qdf_list_node_t *node = NULL, *next_node = NULL;
1061
1062 qdf_mutex_acquire(&scan_priv->scan_req_q_lock);
1063 if (QDF_STATUS_SUCCESS !=
1064 qdf_list_peek_front(&scan_priv->scan_req_q,
1065 &node)) {
1066 qdf_mutex_release(&scan_priv->scan_req_q_lock);
1067 return;
1068 }
1069
1070 while (node) {
1071 /*
1072 * Keep track of the next node, to traverse through the list
1073 * in the event of the current node being deleted.
1074 */
1075 qdf_list_peek_next(&scan_priv->scan_req_q,
1076 node, &next_node);
1077 scan_req = qdf_container_of(node, struct scan_req, node);
1078 if (!dev || (dev == scan_req->dev)) {
1079 scan_cleanup = qdf_mem_malloc(sizeof(struct scan_req));
1080 if (!scan_cleanup) {
1081 qdf_mutex_release(&scan_priv->scan_req_q_lock);
1082 cfg80211_err("Failed to allocate memory");
1083 return;
1084 }
1085 scan_cleanup->scan_request = scan_req->scan_request;
1086 scan_cleanup->scan_id = scan_req->scan_id;
1087 scan_cleanup->source = scan_req->source;
1088 scan_cleanup->dev = scan_req->dev;
1089 qdf_list_insert_back(scan_cleanup_q,
1090 &scan_cleanup->node);
1091 if (QDF_STATUS_SUCCESS !=
1092 qdf_list_remove_node(&scan_priv->scan_req_q,
1093 node)) {
1094 qdf_mutex_release(&scan_priv->scan_req_q_lock);
1095 cfg80211_err("Failed to remove scan request");
1096 return;
1097 }
1098 qdf_mem_free(scan_req);
1099 }
1100 node = next_node;
1101 next_node = NULL;
1102 }
1103 qdf_mutex_release(&scan_priv->scan_req_q_lock);
1104}
1105
1106void wlan_cfg80211_cleanup_scan_queue(struct wlan_objmgr_pdev *pdev,
1107 struct net_device *dev)
Sandeep Puligillaea68a2c2017-04-13 18:07:06 -07001108{
1109 struct scan_req *scan_req;
Sandeep Puligillaea68a2c2017-04-13 18:07:06 -07001110 struct cfg80211_scan_request *req;
1111 uint8_t source;
1112 bool aborted = true;
1113 struct pdev_osif_priv *osif_priv;
Soumya Bhat8b2a5352018-02-21 15:57:34 +05301114 qdf_list_t scan_cleanup_q;
1115 qdf_list_node_t *node = NULL;
Sandeep Puligillaea68a2c2017-04-13 18:07:06 -07001116
1117 if (!pdev) {
1118 cfg80211_err("pdev is Null");
1119 return;
1120 }
1121
Sandeep Puligillaea68a2c2017-04-13 18:07:06 -07001122 osif_priv = wlan_pdev_get_ospriv(pdev);
Sandeep Puligillaea68a2c2017-04-13 18:07:06 -07001123
Soumya Bhat8b2a5352018-02-21 15:57:34 +05301124 /*
1125 * To avoid any race conditions, create a local list to copy all the
1126 * scan entries to be removed and then send scan complete for each of
1127 * the identified entries to NL.
1128 */
1129 qdf_list_create(&scan_cleanup_q, WLAN_MAX_SCAN_COUNT);
1130 wlan_cfg80211_enqueue_for_cleanup(&scan_cleanup_q,
1131 osif_priv->osif_scan, dev);
1132
1133 while (!qdf_list_empty(&scan_cleanup_q)) {
1134 if (QDF_STATUS_SUCCESS != qdf_list_remove_front(&scan_cleanup_q,
1135 &node)) {
Sandeep Puligillaea68a2c2017-04-13 18:07:06 -07001136 cfg80211_err("Failed to remove scan request");
1137 return;
1138 }
Sandeep Puligillaea68a2c2017-04-13 18:07:06 -07001139 scan_req = container_of(node, struct scan_req, node);
1140 req = scan_req->scan_request;
1141 source = scan_req->source;
1142 if (NL_SCAN == source)
Soumya Bhat8b2a5352018-02-21 15:57:34 +05301143 wlan_cfg80211_scan_done(scan_req->dev, req,
1144 aborted);
Sandeep Puligillaea68a2c2017-04-13 18:07:06 -07001145 else
1146 wlan_vendor_scan_callback(req, aborted);
Soumya Bhat8b2a5352018-02-21 15:57:34 +05301147
Sandeep Puligillaea68a2c2017-04-13 18:07:06 -07001148 qdf_mem_free(scan_req);
1149 }
Soumya Bhat8b2a5352018-02-21 15:57:34 +05301150 qdf_list_destroy(&scan_cleanup_q);
Sandeep Puligillaea68a2c2017-04-13 18:07:06 -07001151
1152 return;
1153}
1154
gaurank kathpalia74f2a302018-01-31 19:29:48 +05301155/**
1156 * wlan_cfg80211_update_scan_policy_type_flags() - Set scan flags according to
1157 * scan request
1158 * @scan_req: Pointer to csr scan req
1159 *
1160 * Return: None
1161 */
1162#if defined(CFG80211_SCAN_DBS_CONTROL_SUPPORT) || \
1163 (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0))
1164static void wlan_cfg80211_update_scan_policy_type_flags(
1165 struct cfg80211_scan_request *req,
1166 struct scan_req_params *scan_req)
1167{
1168 if (req->flags & NL80211_SCAN_FLAG_HIGH_ACCURACY)
1169 scan_req->scan_policy_high_accuracy = true;
1170 if (req->flags & NL80211_SCAN_FLAG_LOW_SPAN)
1171 scan_req->scan_policy_low_span = true;
1172 if (req->flags & NL80211_SCAN_FLAG_LOW_POWER)
1173 scan_req->scan_policy_low_power = true;
1174}
1175#else
1176static inline void wlan_cfg80211_update_scan_policy_type_flags(
1177 struct cfg80211_scan_request *req,
1178 struct scan_req_params *scan_req)
1179{
1180}
1181#endif
1182
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -08001183int wlan_cfg80211_scan(struct wlan_objmgr_pdev *pdev,
1184 struct cfg80211_scan_request *request,
yeshwanth sriram guntuka074f5e92017-08-24 14:51:05 +05301185 struct scan_params *params)
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -08001186{
1187 struct net_device *dev = request->wdev->netdev;
1188 struct scan_start_request *req;
1189 struct wlan_ssid *pssid;
1190 uint8_t i;
1191 int status;
1192 uint8_t num_chan = 0, channel;
Shashikala Prabhu48ecda82018-04-13 01:13:30 +05301193 uint32_t c_freq;
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -08001194 struct wlan_objmgr_vdev *vdev;
1195 wlan_scan_requester req_id;
1196 struct pdev_osif_priv *osif_priv;
1197 struct wlan_objmgr_psoc *psoc;
1198 wlan_scan_id scan_id;
Abhishek Singhf9297e52017-03-09 12:57:37 +05301199 bool is_p2p_scan = false;
Om Prakash Tripathi7dd49fe2017-12-28 17:22:14 +05301200 enum wlan_band band;
Jiachao Wua00b71b2018-01-02 16:21:45 +08001201 struct net_device *netdev = NULL;
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -08001202
1203 /* Get the vdev object */
1204 vdev = wlan_objmgr_get_vdev_by_macaddr_from_pdev(pdev, dev->dev_addr,
1205 WLAN_OSIF_ID);
1206 if (vdev == NULL) {
1207 cfg80211_err("vdev object is NULL");
1208 return -EIO;
1209 }
1210 psoc = wlan_pdev_get_psoc(pdev);
1211 if (!psoc) {
1212 wlan_objmgr_vdev_release_ref(vdev, WLAN_OSIF_ID);
1213 cfg80211_err("Invalid psoc object");
1214 return -EINVAL;
1215 }
1216 req = qdf_mem_malloc(sizeof(*req));
1217 if (!req) {
1218 wlan_objmgr_vdev_release_ref(vdev, WLAN_OSIF_ID);
1219 cfg80211_err("Failed to allocate scan request memory");
1220 return -EINVAL;
1221 }
1222 /* Initialize the scan global params */
1223 ucfg_scan_init_default_params(vdev, req);
1224
1225 /* Get NL global context from objmgr*/
1226 osif_priv = wlan_pdev_get_ospriv(pdev);
1227 req_id = osif_priv->osif_scan->req_id;
1228 scan_id = ucfg_scan_get_scan_id(psoc);
1229 if (!scan_id) {
1230 wlan_objmgr_vdev_release_ref(vdev, WLAN_OSIF_ID);
1231 cfg80211_err("Invalid scan id");
1232 qdf_mem_free(req);
1233 return -EINVAL;
1234 }
1235 /* fill the scan request structure */
1236 req->vdev = vdev;
Abhishek Singhf9297e52017-03-09 12:57:37 +05301237 req->scan_req.vdev_id = wlan_vdev_get_id(vdev);
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -08001238 req->scan_req.scan_id = scan_id;
1239 req->scan_req.scan_req_id = req_id;
gaurank kathpalia74f2a302018-01-31 19:29:48 +05301240
1241 /* Update scan policy type flags according to cfg scan request */
1242 wlan_cfg80211_update_scan_policy_type_flags(request,
1243 &req->scan_req);
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -08001244 /*
1245 * Even though supplicant doesn't provide any SSIDs, n_ssids is
1246 * set to 1. Because of this, driver is assuming that this is not
1247 * wildcard scan and so is not aging out the scan results.
1248 */
1249 if ((request->ssids) && (request->n_ssids == 1) &&
1250 ('\0' == request->ssids->ssid[0])) {
1251 request->n_ssids = 0;
1252 }
1253
1254 if ((request->ssids) && (0 < request->n_ssids)) {
1255 int j;
1256 req->scan_req.num_ssids = request->n_ssids;
1257
1258 /* copy all the ssid's and their length */
1259 for (j = 0; j < request->n_ssids; j++) {
1260 pssid = &req->scan_req.ssid[j];
1261 /* get the ssid length */
1262 pssid->length = request->ssids[j].ssid_len;
1263 qdf_mem_copy(pssid->ssid,
1264 &request->ssids[j].ssid[0],
1265 pssid->length);
1266 pssid->ssid[pssid->length] = '\0';
1267 cfg80211_notice("SSID number %d: %s", j,
1268 pssid->ssid);
1269 }
1270 }
1271 if (request->ssids ||
1272 (wlan_vdev_mlme_get_opmode(vdev) == QDF_P2P_GO_MODE))
1273 req->scan_req.scan_f_passive = false;
1274
Shashikala Prabhu48ecda82018-04-13 01:13:30 +05301275 if (params->half_rate)
1276 req->scan_req.scan_f_half_rate = true;
1277 else if (params->quarter_rate)
1278 req->scan_req.scan_f_quarter_rate = true;
1279
Abhishek Singhf9297e52017-03-09 12:57:37 +05301280 if ((request->n_ssids == 1) && request->ssids &&
1281 !qdf_mem_cmp(&request->ssids[0], "DIRECT-", 7))
1282 is_p2p_scan = true;
1283
Yeshwanth Sriram Guntukaf70a37b2018-01-18 16:08:25 +05301284 if (is_p2p_scan && request->no_cck)
1285 req->scan_req.p2p_scan_type = SCAN_P2P_SEARCH;
gaurank kathpalia74f2a302018-01-31 19:29:48 +05301286
1287 /* Set dwell time mode according to scan policy type flags */
1288 if (req->scan_req.scan_policy_high_accuracy)
1289 req->scan_req.adaptive_dwell_time_mode =
1290 SCAN_DWELL_MODE_STATIC;
1291 if ((req->scan_req.scan_policy_low_power) ||
1292 (req->scan_req.scan_policy_low_span))
1293 req->scan_req.adaptive_dwell_time_mode =
1294 SCAN_DWELL_MODE_AGGRESSIVE;
1295
Abhishek Singhf9297e52017-03-09 12:57:37 +05301296 /*
1297 * FW require at least 1 MAC to send probe request.
1298 * If MAC is all 0 set it to BC addr as this is the address on
1299 * which fw will send probe req.
1300 */
1301 req->scan_req.num_bssid = 1;
Om Prakash Tripathi7d867d62017-04-26 16:52:09 +05301302 wlan_copy_bssid_scan_request(req, request);
Abhishek Singhf9297e52017-03-09 12:57:37 +05301303 if (qdf_is_macaddr_zero(&req->scan_req.bssid_list[0]))
1304 qdf_set_macaddr_broadcast(&req->scan_req.bssid_list[0]);
1305
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -08001306 if (request->n_channels) {
1307 char chl[(request->n_channels * 5) + 1];
1308 int len = 0;
Ajit Pal Singh2563e832017-05-04 22:58:42 +05301309#ifdef WLAN_POLICY_MGR_ENABLE
Ajit Pal Singhec973b02017-04-17 16:49:01 +05301310 bool ap_or_go_present =
1311 policy_mgr_mode_specific_connection_count(
Tushnim Bhattacharyyaf9409182018-03-28 17:23:55 -07001312 psoc, PM_SAP_MODE, NULL) ||
Ajit Pal Singhec973b02017-04-17 16:49:01 +05301313 policy_mgr_mode_specific_connection_count(
Tushnim Bhattacharyyaf9409182018-03-28 17:23:55 -07001314 psoc, PM_P2P_GO_MODE, NULL);
Ajit Pal Singh2563e832017-05-04 22:58:42 +05301315#endif
Ajit Pal Singhec973b02017-04-17 16:49:01 +05301316
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -08001317 for (i = 0; i < request->n_channels; i++) {
1318 channel = request->channels[i]->hw_value;
Shashikala Prabhu48ecda82018-04-13 01:13:30 +05301319 c_freq = wlan_reg_chan_to_freq(pdev, channel);
Kiran Kumar Lokereb49263b2018-05-15 15:48:57 -07001320 if (wlan_reg_is_dsrc_chan(pdev, channel))
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -08001321 continue;
Ajit Pal Singh2563e832017-05-04 22:58:42 +05301322#ifdef WLAN_POLICY_MGR_ENABLE
Ajit Pal Singhec973b02017-04-17 16:49:01 +05301323 if (ap_or_go_present) {
1324 bool ok;
1325 int ret;
1326
1327 ret = policy_mgr_is_chan_ok_for_dnbs(psoc,
1328 channel,
1329 &ok);
1330
1331 if (QDF_IS_STATUS_ERROR(ret)) {
1332 cfg80211_err("DNBS check failed");
1333 qdf_mem_free(req);
1334 status = -EINVAL;
1335 goto end;
1336 }
1337 if (!ok)
1338 continue;
1339 }
Ajit Pal Singh2563e832017-05-04 22:58:42 +05301340#endif
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -08001341 len += snprintf(chl + len, 5, "%d ", channel);
Shashikala Prabhu48ecda82018-04-13 01:13:30 +05301342 req->scan_req.chan_list.chan[num_chan].freq = c_freq;
1343 band = util_scan_scm_freq_to_band(c_freq);
Om Prakash Tripathi7dd49fe2017-12-28 17:22:14 +05301344 if (band == WLAN_BAND_2_4_GHZ)
1345 req->scan_req.chan_list.chan[num_chan].phymode =
1346 SCAN_PHY_MODE_11G;
1347 else
1348 req->scan_req.chan_list.chan[num_chan].phymode =
1349 SCAN_PHY_MODE_11A;
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -08001350 num_chan++;
1351 }
1352 cfg80211_notice("Channel-List: %s", chl);
1353 cfg80211_notice("No. of Scan Channels: %d", num_chan);
1354 }
1355 if (!num_chan) {
1356 cfg80211_err("Received zero non-dsrc channels");
1357 qdf_mem_free(req);
1358 status = -EINVAL;
1359 goto end;
1360 }
Om Prakash Tripathi3e166ff2017-11-03 16:11:11 +05301361 req->scan_req.chan_list.num_chan = num_chan;
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -08001362
1363 /* P2P increase the scan priority */
Abhishek Singhf9297e52017-03-09 12:57:37 +05301364 if (is_p2p_scan)
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -08001365 req->scan_req.scan_priority = SCAN_PRIORITY_HIGH;
1366 if (request->ie_len) {
1367 req->scan_req.extraie.ptr = qdf_mem_malloc(request->ie_len);
1368 if (!req->scan_req.extraie.ptr) {
1369 cfg80211_err("Failed to allocate memory");
1370 status = -ENOMEM;
1371 qdf_mem_free(req);
1372 goto end;
1373 }
1374 req->scan_req.extraie.len = request->ie_len;
1375 qdf_mem_copy(req->scan_req.extraie.ptr, request->ie,
1376 request->ie_len);
yeshwanth sriram guntuka074f5e92017-08-24 14:51:05 +05301377 } else if (params->default_ie.ptr && params->default_ie.len) {
1378 req->scan_req.extraie.ptr =
1379 qdf_mem_malloc(params->default_ie.len);
1380 if (!req->scan_req.extraie.ptr) {
1381 cfg80211_err("Failed to allocate memory");
1382 status = -ENOMEM;
1383 qdf_mem_free(req);
1384 goto end;
1385 }
1386 req->scan_req.extraie.len = params->default_ie.len;
1387 qdf_mem_copy(req->scan_req.extraie.ptr, params->default_ie.ptr,
1388 params->default_ie.len);
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -08001389 }
Abhishek Singhf9297e52017-03-09 12:57:37 +05301390
Rajeev Kumar Sirasanagandlaa3f4a292017-06-21 12:01:22 +05301391 if (!is_p2p_scan) {
Kiran Kumar Lokere584e6612017-10-12 17:55:36 -07001392 if (req->scan_req.scan_random.randomize)
1393 wlan_scan_rand_attrs(vdev, request, req);
Rajeev Kumar Sirasanagandlaa3f4a292017-06-21 12:01:22 +05301394 if (ucfg_ie_whitelist_enabled(psoc, vdev) &&
1395 ucfg_copy_ie_whitelist_attrs(psoc,
1396 &req->scan_req.ie_whitelist))
1397 req->scan_req.scan_f_en_ie_whitelist_in_probe = true;
1398 }
Rajeev Kumar Sirasanagandlad8d18f12017-06-08 18:12:50 +05301399
Abhishek Singhf9297e52017-03-09 12:57:37 +05301400 if (request->flags & NL80211_SCAN_FLAG_FLUSH)
1401 ucfg_scan_flush_results(pdev, NULL);
1402
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -08001403 /* Enqueue the scan request */
yeshwanth sriram guntuka074f5e92017-08-24 14:51:05 +05301404 wlan_scan_request_enqueue(pdev, request, params->source,
1405 req->scan_req.scan_id);
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -08001406
Abhishek Singhac803092017-04-19 12:35:11 +05301407 qdf_runtime_pm_prevent_suspend(
Prashanth Bhatta65b0eaa2017-01-19 15:33:43 -08001408 &osif_priv->osif_scan->runtime_pm_lock);
Abhishek Singhac803092017-04-19 12:35:11 +05301409
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -08001410 status = ucfg_scan_start(req);
1411 if (QDF_STATUS_SUCCESS != status) {
1412 cfg80211_err("ucfg_scan_start returned error %d", status);
1413 if (QDF_STATUS_E_RESOURCES == status) {
1414 cfg80211_err("HO is in progress.So defer the scan by informing busy");
1415 status = -EBUSY;
1416 } else {
1417 status = -EIO;
1418 }
yeshwanth sriram guntuka074f5e92017-08-24 14:51:05 +05301419 wlan_scan_request_dequeue(pdev, scan_id, &request,
Jiachao Wua00b71b2018-01-02 16:21:45 +08001420 &params->source, &netdev);
Abhishek Singhac803092017-04-19 12:35:11 +05301421 if (qdf_list_empty(&osif_priv->osif_scan->scan_req_q))
1422 qdf_runtime_pm_allow_suspend(
Prashanth Bhatta65b0eaa2017-01-19 15:33:43 -08001423 &osif_priv->osif_scan->runtime_pm_lock);
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -08001424 }
1425
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -08001426end:
1427 wlan_objmgr_vdev_release_ref(vdev, WLAN_OSIF_ID);
1428 return status;
1429}
1430
1431/**
1432 * wlan_get_scanid() - API to get the scan id
1433 * from the scan cookie attribute.
1434 * @pdev: Pointer to pdev object
1435 * @scan_id: Pointer to scan id
1436 * @cookie : Scan cookie attribute
1437 *
1438 * API to get the scan id from the scan cookie attribute
1439 * sent from supplicant by matching scan request.
1440 *
1441 * Return: 0 for success, non zero for failure
1442 */
1443static int wlan_get_scanid(struct wlan_objmgr_pdev *pdev,
1444 uint32_t *scan_id, uint64_t cookie)
1445{
1446 struct scan_req *scan_req;
1447 qdf_list_node_t *node = NULL;
1448 qdf_list_node_t *ptr_node = NULL;
1449 int ret = -EINVAL;
1450 struct pdev_osif_priv *osif_ctx;
1451 struct osif_scan_pdev *scan_priv;
1452
1453 /* Get NL global context from objmgr*/
1454 osif_ctx = wlan_pdev_get_ospriv(pdev);
1455 if (!osif_ctx) {
1456 cfg80211_err("Failed to retrieve osif context");
1457 return ret;
1458 }
1459 scan_priv = osif_ctx->osif_scan;
Sandeep Puligilla15677ec2017-06-06 18:31:39 -07001460 qdf_mutex_acquire(&scan_priv->scan_req_q_lock);
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -08001461 if (qdf_list_empty(&scan_priv->scan_req_q)) {
Sandeep Puligilla15677ec2017-06-06 18:31:39 -07001462 qdf_mutex_release(&scan_priv->scan_req_q_lock);
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -08001463 cfg80211_err("Failed to retrieve scan id");
1464 return ret;
1465 }
1466
1467 if (QDF_STATUS_SUCCESS !=
1468 qdf_list_peek_front(&scan_priv->scan_req_q,
1469 &ptr_node)) {
Sandeep Puligilla15677ec2017-06-06 18:31:39 -07001470 qdf_mutex_release(&scan_priv->scan_req_q_lock);
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -08001471 return ret;
1472 }
1473
1474 do {
1475 node = ptr_node;
1476 scan_req = qdf_container_of(node, struct scan_req, node);
1477 if (cookie ==
1478 (uintptr_t)(scan_req->scan_request)) {
1479 *scan_id = scan_req->scan_id;
1480 ret = 0;
1481 break;
1482 }
1483 } while (QDF_STATUS_SUCCESS ==
1484 qdf_list_peek_next(&scan_priv->scan_req_q,
1485 node, &ptr_node));
1486
Sandeep Puligilla15677ec2017-06-06 18:31:39 -07001487 qdf_mutex_release(&scan_priv->scan_req_q_lock);
1488
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -08001489 return ret;
1490}
1491
1492QDF_STATUS wlan_abort_scan(struct wlan_objmgr_pdev *pdev,
1493 uint32_t pdev_id, uint32_t vdev_id,
Abhishek Singhf95b9e42017-04-25 12:12:01 +05301494 wlan_scan_id scan_id, bool sync)
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -08001495{
1496 struct scan_cancel_request *req;
1497 struct pdev_osif_priv *osif_ctx;
1498 struct osif_scan_pdev *scan_priv;
1499 QDF_STATUS status;
Abhishek Singh54c28cc2017-03-06 13:38:17 +05301500 struct wlan_objmgr_vdev *vdev;
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -08001501
1502 req = qdf_mem_malloc(sizeof(*req));
1503 if (!req) {
1504 cfg80211_err("Failed to allocate memory");
1505 return QDF_STATUS_E_NOMEM;
1506 }
1507
1508 /* Get NL global context from objmgr*/
1509 osif_ctx = wlan_pdev_get_ospriv(pdev);
1510 if (!osif_ctx) {
1511 cfg80211_err("Failed to retrieve osif context");
Abhishek Singh673bd512017-03-14 18:01:43 +05301512 qdf_mem_free(req);
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -08001513 return QDF_STATUS_E_FAILURE;
1514 }
Abhishek Singh54c28cc2017-03-06 13:38:17 +05301515 if (vdev_id == INVAL_VDEV_ID)
1516 vdev = wlan_objmgr_get_vdev_by_id_from_pdev(pdev,
1517 0, WLAN_OSIF_ID);
1518 else
1519 vdev = wlan_objmgr_get_vdev_by_id_from_pdev(pdev,
1520 vdev_id, WLAN_OSIF_ID);
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -08001521
Abhishek Singh673bd512017-03-14 18:01:43 +05301522 if (!vdev) {
1523 cfg80211_err("Failed get vdev");
1524 qdf_mem_free(req);
1525 return QDF_STATUS_E_INVAL;
1526 }
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -08001527 scan_priv = osif_ctx->osif_scan;
1528 req->cancel_req.requester = scan_priv->req_id;
Abhishek Singh54c28cc2017-03-06 13:38:17 +05301529 req->vdev = vdev;
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -08001530 req->cancel_req.scan_id = scan_id;
1531 req->cancel_req.pdev_id = pdev_id;
1532 req->cancel_req.vdev_id = vdev_id;
1533 if (scan_id != INVAL_SCAN_ID)
1534 req->cancel_req.req_type = WLAN_SCAN_CANCEL_SINGLE;
Sandeep Puligilladc89e472018-06-28 18:47:40 -07001535 else if (vdev_id == INVAL_VDEV_ID)
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -08001536 req->cancel_req.req_type = WLAN_SCAN_CANCEL_PDEV_ALL;
1537 else
1538 req->cancel_req.req_type = WLAN_SCAN_CANCEL_VDEV_ALL;
Abhishek Singhf95b9e42017-04-25 12:12:01 +05301539
1540 if (sync)
1541 status = ucfg_scan_cancel_sync(req);
1542 else
1543 status = ucfg_scan_cancel(req);
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -08001544 if (QDF_IS_STATUS_ERROR(status))
1545 cfg80211_err("Cancel scan request failed");
Abhishek Singh673bd512017-03-14 18:01:43 +05301546
Abhishek Singh54c28cc2017-03-06 13:38:17 +05301547 wlan_objmgr_vdev_release_ref(vdev, WLAN_OSIF_ID);
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -08001548
1549 return status;
1550}
1551
1552int wlan_cfg80211_abort_scan(struct wlan_objmgr_pdev *pdev)
1553{
1554 uint8_t pdev_id;
1555
1556 pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev);
Abhishek Singh673bd512017-03-14 18:01:43 +05301557
1558 if (ucfg_scan_get_pdev_status(pdev) !=
1559 SCAN_NOT_IN_PROGRESS)
1560 wlan_abort_scan(pdev, pdev_id,
Abhishek Singhf95b9e42017-04-25 12:12:01 +05301561 INVAL_VDEV_ID, INVAL_SCAN_ID, true);
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -08001562
1563 return 0;
1564}
1565
1566int wlan_vendor_abort_scan(struct wlan_objmgr_pdev *pdev,
1567 const void *data, int data_len)
1568{
1569 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_SCAN_MAX + 1];
1570 int ret = -EINVAL;
1571 wlan_scan_id scan_id;
1572 uint64_t cookie;
1573 uint8_t pdev_id;
1574
1575 pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev);
Dustin Brown1b57dba2017-08-17 17:22:34 -07001576 if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_SCAN_MAX, data,
1577 data_len, scan_policy)) {
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -08001578 cfg80211_err("Invalid ATTR");
1579 return ret;
1580 }
1581
1582 if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE]) {
1583 cookie = nla_get_u64(
1584 tb[QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE]);
1585 ret = wlan_get_scanid(pdev, &scan_id, cookie);
1586 if (ret != 0)
1587 return ret;
Abhishek Singh673bd512017-03-14 18:01:43 +05301588 if (ucfg_scan_get_pdev_status(pdev) !=
1589 SCAN_NOT_IN_PROGRESS)
Sandeep Puligilladc89e472018-06-28 18:47:40 -07001590 wlan_abort_scan(pdev, INVAL_PDEV_ID,
Abhishek Singhf95b9e42017-04-25 12:12:01 +05301591 INVAL_VDEV_ID, scan_id, true);
Sandeep Puligilla7acd31f2017-02-25 16:35:35 -08001592 }
Vivek3e5a3ba2017-02-20 18:13:57 +05301593 return 0;
1594}
Abhishek Singh9eb058a2017-02-17 18:21:13 +05301595
1596static inline struct ieee80211_channel *
Shashikala Prabhu48ecda82018-04-13 01:13:30 +05301597wlan_get_ieee80211_channel(struct wiphy *wiphy,
1598 struct wlan_objmgr_pdev *pdev,
1599 int chan_no)
Abhishek Singh9eb058a2017-02-17 18:21:13 +05301600{
1601 unsigned int freq;
1602 struct ieee80211_channel *chan;
1603
Shashikala Prabhu48ecda82018-04-13 01:13:30 +05301604 freq = wlan_reg_chan_to_freq(pdev, chan_no);
Dustin Brownbbc97262017-08-15 12:31:27 -07001605 chan = ieee80211_get_channel(wiphy, freq);
Abhishek Singh9eb058a2017-02-17 18:21:13 +05301606 if (!chan)
1607 cfg80211_err("chan is NULL, chan_no: %d freq: %d",
1608 chan_no, freq);
1609
1610 return chan;
1611}
1612
1613#ifdef WLAN_ENABLE_AGEIE_ON_SCAN_RESULTS
1614static inline int wlan_get_frame_len(struct scan_cache_entry *scan_params)
1615{
1616 return util_scan_entry_frame_len(scan_params) + sizeof(qcom_ie_age);
1617}
1618
1619static inline void wlan_add_age_ie(uint8_t *mgmt_frame,
1620 struct scan_cache_entry *scan_params)
1621{
1622 qcom_ie_age *qie_age = NULL;
1623
1624 /* GPS Requirement: need age ie per entry. Using vendor specific. */
1625 /* Assuming this is the last IE, copy at the end */
1626 qie_age = (qcom_ie_age *) (mgmt_frame +
1627 util_scan_entry_frame_len(scan_params));
1628 qie_age->element_id = QCOM_VENDOR_IE_ID;
1629 qie_age->len = QCOM_VENDOR_IE_AGE_LEN;
1630 qie_age->oui_1 = QCOM_OUI1;
1631 qie_age->oui_2 = QCOM_OUI2;
1632 qie_age->oui_3 = QCOM_OUI3;
1633 qie_age->type = QCOM_VENDOR_IE_AGE_TYPE;
1634 /*
1635 * Lowi expects the timestamp of bss in units of 1/10 ms. In driver
1636 * all bss related timestamp is in units of ms. Due to this when scan
1637 * results are sent to lowi the scan age is high.To address this,
1638 * send age in units of 1/10 ms.
1639 */
1640 qie_age->age =
1641 (uint32_t)(qdf_mc_timer_get_system_time() -
1642 scan_params->scan_entry_time)/10;
1643 qie_age->tsf_delta = scan_params->tsf_delta;
1644 memcpy(&qie_age->beacon_tsf, scan_params->tsf_info.data,
1645 sizeof(qie_age->beacon_tsf));
1646 memcpy(&qie_age->seq_ctrl, &scan_params->seq_num,
1647 sizeof(qie_age->seq_ctrl));
1648}
1649#else
1650static inline int wlan_get_frame_len(struct scan_cache_entry *scan_params)
1651{
1652 return util_scan_entry_frame_len(scan_params);
1653}
1654
1655static inline void wlan_add_age_ie(uint8_t *mgmt_frame,
1656 struct scan_cache_entry *scan_params)
1657{
1658}
1659#endif /* WLAN_ENABLE_AGEIE_ON_SCAN_RESULTS */
1660
gaurank kathpalia26f98332018-01-29 18:09:06 +05301661#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) || \
1662 defined(CFG80211_INFORM_BSS_FRAME_DATA)
1663/**
1664 * wlan_fill_per_chain_rssi() - fill per chain RSSI in inform bss
1665 * @data: bss data
1666 * @per_chain_snr: per chain RSSI
1667 *
1668 * Return: void
1669 */
1670#if defined(CFG80211_SCAN_PER_CHAIN_RSSI_SUPPORT) || \
1671 (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0))
1672static void wlan_fill_per_chain_rssi(struct cfg80211_inform_bss *data,
1673 struct wlan_cfg80211_inform_bss *bss)
1674{
1675
1676 uint32_t i;
1677
1678 if (!bss || !data) {
1679 cfg80211_err("Received bss is NULL");
1680 return;
1681 }
1682 for (i = 0; i < WLAN_MGMT_TXRX_HOST_MAX_ANTENNA; i++) {
1683 if (!bss->per_chain_snr[i] ||
1684 (bss->per_chain_snr[i] == WLAN_INVALID_PER_CHAIN_RSSI))
1685 continue;
1686 /* Add noise margin to SNR to convert it to RSSI */
1687 data->chain_signal[i] = bss->per_chain_snr[i] +
1688 WLAN_NOISE_FLOOR_DBM_DEFAULT;
1689 data->chains |= BIT(i);
1690 }
1691}
1692#else
1693static inline void
1694wlan_fill_per_chain_rssi(struct cfg80211_inform_bss *data,
1695 struct wlan_cfg80211_inform_bss *bss)
1696{
1697}
1698#endif
1699
1700struct cfg80211_bss *
1701wlan_cfg80211_inform_bss_frame_data(struct wiphy *wiphy,
1702 struct wlan_cfg80211_inform_bss *bss)
1703{
1704 struct cfg80211_inform_bss data = {0};
1705
1706 if (!bss) {
1707 cfg80211_err("bss is null");
1708 return NULL;
1709 }
1710 wlan_fill_per_chain_rssi(&data, bss);
1711
1712 data.chan = bss->chan;
1713 data.boottime_ns = bss->boottime_ns;
1714 data.signal = bss->rssi;
1715 return cfg80211_inform_bss_frame_data(wiphy, &data, bss->mgmt,
Om Prakash Tripathi9b56f5d2018-05-29 11:42:19 +05301716 bss->frame_len, GFP_ATOMIC);
gaurank kathpalia26f98332018-01-29 18:09:06 +05301717}
1718#else
1719struct cfg80211_bss *
1720wlan_cfg80211_inform_bss_frame_data(struct wiphy *wiphy,
1721 struct wlan_cfg80211_inform_bss *bss)
1722
1723{
1724 return cfg80211_inform_bss_frame(wiphy, bss->chan, bss->mgmt,
1725 bss->frame_len,
Om Prakash Tripathi9b56f5d2018-05-29 11:42:19 +05301726 bss->rssi, GFP_ATOMIC);
gaurank kathpalia26f98332018-01-29 18:09:06 +05301727}
1728#endif
1729
Om Prakash Tripathi8a545992018-03-19 14:05:38 +05301730#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
1731static inline void wlan_cfg80211_put_bss(struct wiphy *wiphy,
1732 struct cfg80211_bss *bss)
1733{
1734 cfg80211_put_bss(wiphy, bss);
1735}
1736#else
1737static inline void wlan_cfg80211_put_bss(struct wiphy *wiphy,
1738 struct cfg80211_bss *bss)
1739{
1740 cfg80211_put_bss(bss);
1741}
1742#endif
1743
Abhishek Singh9eb058a2017-02-17 18:21:13 +05301744void wlan_cfg80211_inform_bss_frame(struct wlan_objmgr_pdev *pdev,
1745 struct scan_cache_entry *scan_params)
1746{
1747 struct pdev_osif_priv *pdev_ospriv = wlan_pdev_get_ospriv(pdev);
1748 struct wiphy *wiphy;
Om Prakash Tripathi8a545992018-03-19 14:05:38 +05301749 struct cfg80211_bss *bss = NULL;
gaurank kathpalia26f98332018-01-29 18:09:06 +05301750 struct wlan_cfg80211_inform_bss bss_data = {0};
Abhishek Singh9eb058a2017-02-17 18:21:13 +05301751
1752 if (!pdev_ospriv) {
1753 cfg80211_err("os_priv is NULL");
1754 return;
1755 }
1756
1757 wiphy = pdev_ospriv->wiphy;
1758
gaurank kathpalia26f98332018-01-29 18:09:06 +05301759 bss_data.frame_len = wlan_get_frame_len(scan_params);
Om Prakash Tripathi9b56f5d2018-05-29 11:42:19 +05301760 bss_data.mgmt = qdf_mem_malloc_atomic(bss_data.frame_len);
gaurank kathpalia26f98332018-01-29 18:09:06 +05301761 if (!bss_data.mgmt) {
Abhishek Singh9eb058a2017-02-17 18:21:13 +05301762 cfg80211_err("mem alloc failed");
1763 return;
1764 }
gaurank kathpalia26f98332018-01-29 18:09:06 +05301765 qdf_mem_copy(bss_data.mgmt,
Abhishek Singh9eb058a2017-02-17 18:21:13 +05301766 util_scan_entry_frame_ptr(scan_params),
1767 util_scan_entry_frame_len(scan_params));
1768 /*
1769 * Android does not want the timestamp from the frame.
1770 * Instead it wants a monotonic increasing value
1771 */
gaurank kathpalia26f98332018-01-29 18:09:06 +05301772 bss_data.mgmt->u.probe_resp.timestamp = qdf_get_monotonic_boottime();
1773 wlan_add_age_ie((uint8_t *)bss_data.mgmt, scan_params);
Abhishek Singh9eb058a2017-02-17 18:21:13 +05301774 /*
1775 * Based on .ini configuration, raw rssi can be reported for bss.
1776 * Raw rssi is typically used for estimating power.
1777 */
gaurank kathpalia26f98332018-01-29 18:09:06 +05301778 bss_data.rssi = scan_params->rssi_raw;
Abhishek Singh9eb058a2017-02-17 18:21:13 +05301779
Shashikala Prabhu48ecda82018-04-13 01:13:30 +05301780 bss_data.chan = wlan_get_ieee80211_channel(wiphy, pdev,
Abhishek Singh9eb058a2017-02-17 18:21:13 +05301781 scan_params->channel.chan_idx);
gaurank kathpalia26f98332018-01-29 18:09:06 +05301782 if (!bss_data.chan) {
1783 qdf_mem_free(bss_data.mgmt);
Abhishek Singh9eb058a2017-02-17 18:21:13 +05301784 return;
1785 }
1786
1787 /*
1788 * Supplicant takes the signal strength in terms of
1789 * mBm (1 dBm = 100 mBm).
1790 */
gaurank kathpalia26f98332018-01-29 18:09:06 +05301791 bss_data.rssi = QDF_MIN(bss_data.rssi, 0) * 100;
1792
1793 bss_data.boottime_ns = scan_params->boottime_ns;
1794
1795 qdf_mem_copy(bss_data.per_chain_snr, scan_params->per_chain_snr,
1796 WLAN_MGMT_TXRX_HOST_MAX_ANTENNA);
Abhishek Singh9eb058a2017-02-17 18:21:13 +05301797
Yeshwanth Sriram Guntukadad6b5b2018-07-17 13:23:46 +05301798 cfg80211_debug("BSSID: %pM Channel:%d RSSI:%d", bss_data.mgmt->bssid,
1799 bss_data.chan->center_freq, (int)(bss_data.rssi / 100));
Abhishek Singh9eb058a2017-02-17 18:21:13 +05301800
Om Prakash Tripathi8a545992018-03-19 14:05:38 +05301801 bss = wlan_cfg80211_inform_bss_frame_data(wiphy, &bss_data);
1802 if (!bss)
gaurank kathpalia26f98332018-01-29 18:09:06 +05301803 cfg80211_err("failed to inform bss");
Om Prakash Tripathi8a545992018-03-19 14:05:38 +05301804 else
1805 wlan_cfg80211_put_bss(wiphy, bss);
gaurank kathpalia26f98332018-01-29 18:09:06 +05301806
1807 qdf_mem_free(bss_data.mgmt);
Abhishek Singh9eb058a2017-02-17 18:21:13 +05301808}