blob: f77aba7faafaa90cf09a329d4be56dd8bb040d3c [file] [log] [blame]
Om Prakash Tripathi7e3f45d2016-12-28 16:58:54 +05301/*
Nandha Kishore Easwaran89583512019-01-10 12:46:46 +05302 * Copyright (c) 2017-2019 The Linux Foundation. All rights reserved.
Om Prakash Tripathi7e3f45d2016-12-28 16:58:54 +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: contains scan cache api and functionality
Abhishek Singhd4e600f2017-02-21 15:16:28 +053021 * The Scan entries are protected by scan_db_lock. Holding the lock
22 * for whole scan operation during get/flush scan results may take
23 * more than 5 ms and thus ref count is used along with scan_db_lock.
24 * Below are the operation on scan cache entry:
25 * - While adding new node to the entry scan_db_lock is taken and ref_cnt
Abhishek Singhc176a522018-04-06 11:14:57 +053026 * is initialized and incremented. Also the cookie will be set to valid value.
27 * - The ref count incremented during adding new node should be decremented only
28 * by a delete operation on the node. But there can be multiple concurrent
29 * delete operations on a node from different threads which may lead to ref
30 * count being decremented multiple time and freeing the node even if node
31 * is in use. So to maintain atomicity between multiple delete operations
32 * on a same node from different threads, a cookie is used to check if node is
33 * logically deleted or not. A delete operation will set the cookie to 0
34 * making it invalid. So if the 2nd thread find the cookie as invalid it will
35 * not try to delete and decrement the ref count of the node again.
36 * - This Cookie is also used to check if node is valid while iterating through
37 * the scan cache to avoid duplicate entries.
38 * - Once ref_cnt become 0, i.e. it is logically deleted and no thread is using
39 * it the node is physically deleted from the scan cache.
40 * - While reading the node the ref_cnt should be incremented. Once reading
41 * operation is done ref_cnt is decremented.
Om Prakash Tripathi7e3f45d2016-12-28 16:58:54 +053042 */
Sandeep Puligilla2e1088d2016-12-27 19:58:17 -080043#include <qdf_status.h>
Abhishek Singh4caf1a92017-02-21 15:01:08 +053044#include <wlan_objmgr_psoc_obj.h>
45#include <wlan_objmgr_pdev_obj.h>
46#include <wlan_objmgr_vdev_obj.h>
47#include <wlan_scan_public_structs.h>
48#include <wlan_scan_utils_api.h>
49#include "wlan_scan_main.h"
50#include "wlan_scan_cache_db_i.h"
Paul Zhangca615212018-02-02 17:43:37 +080051#include "wlan_reg_services_api.h"
52#include "wlan_reg_ucfg_api.h"
Shashikala Prabhu7517a8d2018-12-13 18:02:45 +053053#include <wlan_objmgr_vdev_obj.h>
Basamma Yakkanahalliab48ce32018-07-06 18:49:19 +053054#include <wlan_dfs_utils_api.h>
Abhishek Singh4caf1a92017-02-21 15:01:08 +053055
Sandeep Puligillad763fee2019-11-08 14:00:10 -080056/* MAX RNR entries per channel*/
57#define WLAN_MAX_RNR_COUNT 15
58struct channel_list_db rnr_channel_db;
59
60#ifdef FEATURE_6G_SCAN_CHAN_SORT_ALGO
61struct meta_rnr_channel *scm_get_chan_meta(uint32_t chan_freq)
62{
63 int i;
64
65 for (i = 0; i <= MAX_6GHZ_CHANNEL; i++)
66 if (rnr_channel_db.channel[i].chan_freq == chan_freq)
67 return &rnr_channel_db.channel[i];
68
69 return NULL;
70}
71
72static void scm_add_rnr_channel_db(struct scan_cache_entry *entry)
73{
74 uint32_t chan_freq;
75 uint8_t is_6g_bss, i;
76 struct meta_rnr_channel *channel;
77 struct rnr_bss_info *rnr_bss;
78 struct scan_rnr_node *rnr_node;
79
80 chan_freq = entry->channel.chan_freq;
81 is_6g_bss = wlan_reg_is_6ghz_chan_freq(chan_freq);
82
83 /* Return if the BSS is not 6G and RNR IE is not present */
84 if (!(is_6g_bss || entry->ie_list.rnrie))
85 return;
86
87 scm_debug("scan entry channel freq %d", chan_freq);
88 if (is_6g_bss) {
89 channel = scm_get_chan_meta(chan_freq);
90 if (channel) {
91 scm_debug("Failed to get chan Meta freq %d", chan_freq);
92 return;
93 }
94 channel->bss_beacon_probe_count++;
95 channel->beacon_probe_last_time_found = entry->scan_entry_time;
96 }
97
98 /*
99 * If scan entry got RNR IE then loop through all
100 * entries and increase the BSS count in respective channels
101 */
102 if (!entry->ie_list.rnrie)
103 return;
104
105 for (i = 0; i < MAX_RNR_BSS; i++) {
106 rnr_bss = &entry->rnr.bss_info[i];
107 channel->bss_beacon_probe_count++;
108 /* Don't add RNR entry if list is full */
109 if (qdf_list_size(&channel->rnr_list) >= WLAN_MAX_RNR_COUNT)
110 continue;
111 /* Skip if entry is not valid */
112 if (!rnr_bss->channel_number)
113 continue;
114 rnr_node = qdf_mem_malloc(sizeof(struct scan_rnr_node));
115 if (!rnr_node)
116 return;
117 chan_freq = wlan_reg_chan_opclass_to_freq(rnr_bss->channel_number,
118 rnr_bss->operating_class,
119 false);
120 channel = scm_get_chan_meta(chan_freq);
121 if (!channel) {
122 scm_debug("Failed to get chan Meta freq %d", chan_freq);
123 qdf_mem_free(rnr_node);
124 return;
125 }
126 rnr_node->entry.timestamp = entry->scan_entry_time;
127 if (!qdf_is_macaddr_zero(&rnr_bss->bssid))
128 qdf_mem_copy(&rnr_node->entry.bssid,
129 &rnr_bss->bssid,
130 QDF_MAC_ADDR_SIZE);
131 if (rnr_bss->short_ssid)
132 rnr_node->entry.short_ssid = rnr_bss->short_ssid;
133 qdf_list_insert_back(&channel->rnr_list,
134 &rnr_node->node);
135 }
136}
137
138static void scm_del_rnr_channel_db(struct scan_cache_entry *entry)
139{
140 uint32_t chan_freq;
141 uint8_t is_6g_bss, i;
142 struct meta_rnr_channel *channel;
143 struct rnr_bss_info *rnr_bss;
144 struct scan_rnr_node *rnr_node;
145 qdf_list_node_t *cur_node, *next_node;
146
147 chan_freq = entry->channel.chan_freq;
148 is_6g_bss = wlan_reg_is_6ghz_chan_freq(chan_freq);
149
150 /* Return if the BSS is not 6G and RNR IE is not present*/
151 if (!(is_6g_bss || entry->ie_list.rnrie))
152 return;
153
154 scm_debug("channel freq of scan entry %d", chan_freq);
155 if (is_6g_bss) {
156 channel = scm_get_chan_meta(chan_freq);
157 if (!channel) {
158 scm_debug("Failed to get chan Meta freq %d", chan_freq);
159 return;
160 }
161 channel->bss_beacon_probe_count--;
162 }
163 /*
164 * If scan entry got RNR IE then loop through all
165 * entries and decrease the BSS count in respective channels
166 */
167 if (!entry->ie_list.rnrie)
168 return;
169
170 for (i = 0; i < MAX_RNR_BSS; i++) {
171 rnr_bss = &entry->rnr.bss_info[i];
172 /* Skip if entry is not valid */
173 if (!rnr_bss->channel_number)
174 continue;
175 chan_freq = wlan_reg_chan_opclass_to_freq(rnr_bss->channel_number,
176 rnr_bss->operating_class,
177 false);
178 channel = scm_get_chan_meta(chan_freq);
179 if (!channel) {
180 scm_debug("Failed to get chan Meta freq %d",
181 chan_freq);
182 return;
183 }
184 channel->bss_beacon_probe_count--;
Liangwei Dong7ce41f12019-11-26 16:49:08 +0800185 cur_node = NULL;
Sandeep Puligillad763fee2019-11-08 14:00:10 -0800186 qdf_list_peek_front(&channel->rnr_list, &cur_node);
187 /* Free the Node */
188 while (cur_node) {
Liangwei Dong7ce41f12019-11-26 16:49:08 +0800189 next_node = NULL;
Sandeep Puligillad763fee2019-11-08 14:00:10 -0800190 qdf_list_peek_next(&channel->rnr_list, cur_node,
191 &next_node);
192 rnr_node = qdf_container_of(cur_node,
193 struct scan_rnr_node,
194 node);
195 if (qdf_is_macaddr_equal(&rnr_node->entry.bssid,
196 &rnr_bss->bssid)) {
197 qdf_list_remove_node(&channel->rnr_list,
198 &rnr_node->node);
199 qdf_mem_free(rnr_node);
200 } else if (rnr_node->entry.short_ssid ==
201 rnr_bss->short_ssid) {
202 qdf_list_remove_node(&channel->rnr_list,
203 &rnr_node->node);
204 qdf_mem_free(rnr_node);
205 }
206 cur_node = next_node;
207 next_node = NULL;
208 }
209 }
210}
211#else
212struct meta_rnr_channel *scm_get_chan_meta(uint32_t channel_freq)
213{
214 return NULL;
215}
216
217static void scm_add_rnr_channel_db(struct scan_cache_entry *entry)
218{
219}
220
221static void scm_del_rnr_channel_db(struct scan_cache_entry *entry)
222{
223}
224#endif
225
Abhishek Singhd4e600f2017-02-21 15:16:28 +0530226/**
227 * scm_del_scan_node() - API to remove scan node from the list
228 * @list: hash list
229 * @scan_node: node to be removed
230 *
231 * This should be called while holding scan_db_lock.
232 *
233 * Return: void
234 */
235static void scm_del_scan_node(qdf_list_t *list,
236 struct scan_cache_node *scan_node)
237{
238 QDF_STATUS status;
239
240 status = qdf_list_remove_node(list, &scan_node->node);
241 if (QDF_IS_STATUS_SUCCESS(status)) {
242 util_scan_free_cache_entry(scan_node->entry);
243 qdf_mem_free(scan_node);
244 }
245}
246
247/**
248 * scm_del_scan_node_from_db() - API to del the scan entry
249 * @scan_db: scan database
250 * @scan_entry:entry scan_node
251 *
252 * API to flush the scan entry. This should be called while
253 * holding scan_db_lock.
254 *
255 * Return: QDF status.
256 */
257static QDF_STATUS scm_del_scan_node_from_db(struct scan_dbs *scan_db,
258 struct scan_cache_node *scan_node)
259{
260 QDF_STATUS status = QDF_STATUS_SUCCESS;
261 uint8_t hash_idx;
262
263 if (!scan_node)
264 return QDF_STATUS_E_INVAL;
265
266 hash_idx = SCAN_GET_HASH(scan_node->entry->bssid.bytes);
267 scm_del_scan_node(&scan_db->scan_hash_tbl[hash_idx], scan_node);
268 scan_db->num_entries--;
269
270 return status;
271}
272
273/**
274 * scm_scan_entry_get_ref() - api to increase ref count of scan entry
275 * @scan_node: scan node
276 *
277 * Return: void
278 */
279static void scm_scan_entry_get_ref(struct scan_cache_node *scan_node)
280{
Jeff Johnson82eb2122019-03-20 12:16:13 -0700281 if (!scan_node) {
Abhishek Singhd4e600f2017-02-21 15:16:28 +0530282 scm_err("scan_node is NULL");
283 QDF_ASSERT(0);
284 return;
285 }
286 qdf_atomic_inc(&scan_node->ref_cnt);
287}
288
289/**
290 * scm_scan_entry_put_ref() - Api to decrease ref count of scan entry
291 * and free if it become 0
292 * @scan_db: scan database
293 * @scan_node: scan node
294 * @lock_needed: if scan_db_lock is needed
295 *
296 * Return: void
297 */
298static void scm_scan_entry_put_ref(struct scan_dbs *scan_db,
Amir Patel7c1a52c2018-03-02 16:33:04 +0530299 struct scan_cache_node *scan_node, bool lock_needed)
Abhishek Singhd4e600f2017-02-21 15:16:28 +0530300{
301
302 if (!scan_node) {
303 scm_err("scan_node is NULL");
304 QDF_ASSERT(0);
305 return;
306 }
307
Abhishek Singh3f11bd62017-12-08 14:08:16 +0530308 if (lock_needed)
309 qdf_spin_lock_bh(&scan_db->scan_db_lock);
310
Abhishek Singhd4e600f2017-02-21 15:16:28 +0530311 if (!qdf_atomic_read(&scan_node->ref_cnt)) {
Abhishek Singh3f11bd62017-12-08 14:08:16 +0530312 if (lock_needed)
313 qdf_spin_unlock_bh(&scan_db->scan_db_lock);
Abhishek Singhd4e600f2017-02-21 15:16:28 +0530314 scm_err("scan_node ref cnt is 0");
315 QDF_ASSERT(0);
316 return;
317 }
318
Abhishek Singhd4e600f2017-02-21 15:16:28 +0530319 /* Decrement ref count, free scan_node, if ref count == 0 */
320 if (qdf_atomic_dec_and_test(&scan_node->ref_cnt))
321 scm_del_scan_node_from_db(scan_db, scan_node);
322
323 if (lock_needed)
324 qdf_spin_unlock_bh(&scan_db->scan_db_lock);
325}
326
327/**
Amir Patel7c1a52c2018-03-02 16:33:04 +0530328 * scm_scan_entry_del() - API to delete scan node
329 * @scan_db: data base
330 * @scan_node: node to be deleted
331 *
332 * Call must be protected by scan_db->scan_db_lock
333 *
334 * Return: void
335 */
336
337static void scm_scan_entry_del(struct scan_dbs *scan_db,
338 struct scan_cache_node *scan_node)
339{
340 if (!scan_node) {
341 scm_err("scan node is NULL");
342 QDF_ASSERT(0);
343 return;
344 }
345
Abhishek Singhc176a522018-04-06 11:14:57 +0530346 if (scan_node->cookie != SCAN_NODE_ACTIVE_COOKIE) {
347 scm_debug("node is already deleted");
Amir Patel7c1a52c2018-03-02 16:33:04 +0530348 return;
349 }
Amir Patel2b2435e2018-03-20 12:30:27 +0530350 /* Seems node is already deleted */
351 if (!qdf_atomic_read(&scan_node->ref_cnt)) {
Abhishek Singhc176a522018-04-06 11:14:57 +0530352 scm_debug("node is already deleted ref 0");
Amir Patel2b2435e2018-03-20 12:30:27 +0530353 return;
354 }
Abhishek Singhc176a522018-04-06 11:14:57 +0530355 scan_node->cookie = 0;
Sandeep Puligillad763fee2019-11-08 14:00:10 -0800356 scm_del_rnr_channel_db(scan_node->entry);
Amir Patel7c1a52c2018-03-02 16:33:04 +0530357 scm_scan_entry_put_ref(scan_db, scan_node, false);
358}
359
360/**
Abhishek Singhd4e600f2017-02-21 15:16:28 +0530361 * scm_add_scan_node() - API to add scan node
362 * @scan_db: data base
Amir Patel7c1a52c2018-03-02 16:33:04 +0530363 * @scan_node: node to be added
364 * @dup_node: node before which new node to be added
365 * if it's not NULL, otherwise add node to tail
366 *
367 * Call must be protected by scan_db->scan_db_lock
Abhishek Singhd4e600f2017-02-21 15:16:28 +0530368 *
369 * Return: void
370 */
371static void scm_add_scan_node(struct scan_dbs *scan_db,
Amir Patel7c1a52c2018-03-02 16:33:04 +0530372 struct scan_cache_node *scan_node,
373 struct scan_cache_node *dup_node)
Abhishek Singhd4e600f2017-02-21 15:16:28 +0530374{
375 uint8_t hash_idx;
376
377 hash_idx =
378 SCAN_GET_HASH(scan_node->entry->bssid.bytes);
379
Abhishek Singhd4e600f2017-02-21 15:16:28 +0530380 qdf_atomic_init(&scan_node->ref_cnt);
Abhishek Singhc176a522018-04-06 11:14:57 +0530381 scan_node->cookie = SCAN_NODE_ACTIVE_COOKIE;
Abhishek Singhd4e600f2017-02-21 15:16:28 +0530382 scm_scan_entry_get_ref(scan_node);
Amir Patel7c1a52c2018-03-02 16:33:04 +0530383 if (!dup_node)
384 qdf_list_insert_back(&scan_db->scan_hash_tbl[hash_idx],
385 &scan_node->node);
386 else
387 qdf_list_insert_before(&scan_db->scan_hash_tbl[hash_idx],
388 &scan_node->node, &dup_node->node);
389
Sandeep Puligillad763fee2019-11-08 14:00:10 -0800390 scm_add_rnr_channel_db(scan_node->entry);
Abhishek Singhd4e600f2017-02-21 15:16:28 +0530391 scan_db->num_entries++;
Abhishek Singhd4e600f2017-02-21 15:16:28 +0530392}
393
394
395/**
Abhishek Singh3f11bd62017-12-08 14:08:16 +0530396 * scm_get_next_valid_node() - API get the next valid scan node from
Abhishek Singhd4e600f2017-02-21 15:16:28 +0530397 * the list
398 * @list: hash list
Abhishek Singh3f11bd62017-12-08 14:08:16 +0530399 * @cur_node: current node pointer
400 *
401 * API to get next active node from the list. If cur_node is NULL
402 * it will return first node of the list.
403 * Call must be protected by scan_db->scan_db_lock
404 *
405 * Return: next scan node
406 */
407static qdf_list_node_t *
408scm_get_next_valid_node(qdf_list_t *list,
409 qdf_list_node_t *cur_node)
410{
411 qdf_list_node_t *next_node = NULL;
412 qdf_list_node_t *temp_node = NULL;
413 struct scan_cache_node *scan_node;
414
415 if (cur_node)
416 qdf_list_peek_next(list, cur_node, &next_node);
417 else
418 qdf_list_peek_front(list, &next_node);
419
420 while (next_node) {
421 scan_node = qdf_container_of(next_node,
422 struct scan_cache_node, node);
Abhishek Singhc176a522018-04-06 11:14:57 +0530423 if (scan_node->cookie == SCAN_NODE_ACTIVE_COOKIE)
Abhishek Singh3f11bd62017-12-08 14:08:16 +0530424 return next_node;
425 /*
426 * If node is not valid check for next entry
427 * to get next valid node.
428 */
429 qdf_list_peek_next(list, next_node, &temp_node);
430 next_node = temp_node;
431 temp_node = NULL;
432 }
433
434 return next_node;
435}
436
437/**
438 * scm_get_next_node() - API get the next scan node from
439 * the list
440 * @scan_db: scan data base
441 * @list: hash list
442 * @cur_node: current node pointer
Abhishek Singhd4e600f2017-02-21 15:16:28 +0530443 *
444 * API get the next node from the list. If cur_node is NULL
445 * it will return first node of the list
446 *
447 * Return: next scan cache node
448 */
449static struct scan_cache_node *
450scm_get_next_node(struct scan_dbs *scan_db,
Abhishek Singh3f11bd62017-12-08 14:08:16 +0530451 qdf_list_t *list, struct scan_cache_node *cur_node)
Abhishek Singhd4e600f2017-02-21 15:16:28 +0530452{
453 struct scan_cache_node *next_node = NULL;
454 qdf_list_node_t *next_list = NULL;
455
456 qdf_spin_lock_bh(&scan_db->scan_db_lock);
457 if (cur_node) {
Abhishek Singh3f11bd62017-12-08 14:08:16 +0530458 next_list = scm_get_next_valid_node(list, &cur_node->node);
Abhishek Singhd4e600f2017-02-21 15:16:28 +0530459 /* Decrement the ref count of the previous node */
460 scm_scan_entry_put_ref(scan_db,
Amir Patel7c1a52c2018-03-02 16:33:04 +0530461 cur_node, false);
Abhishek Singhd4e600f2017-02-21 15:16:28 +0530462 } else {
Abhishek Singh3f11bd62017-12-08 14:08:16 +0530463 next_list = scm_get_next_valid_node(list, NULL);
Abhishek Singhd4e600f2017-02-21 15:16:28 +0530464 }
465 /* Increase the ref count of the obtained node */
466 if (next_list) {
467 next_node = qdf_container_of(next_list,
468 struct scan_cache_node, node);
469 scm_scan_entry_get_ref(next_node);
470 }
471 qdf_spin_unlock_bh(&scan_db->scan_db_lock);
472
473 return next_node;
474}
475
476/**
477 * scm_check_and_age_out() - check and age out the old entries
478 * @scan_db: scan db
479 * @scan_node: node to check for age out
Abhishek Singh6e7489e2017-03-23 10:54:22 +0530480 * @scan_aging_time: scan cache aging time
Abhishek Singhd4e600f2017-02-21 15:16:28 +0530481 *
482 * Return: void
483 */
484static void scm_check_and_age_out(struct scan_dbs *scan_db,
Abhishek Singh6e7489e2017-03-23 10:54:22 +0530485 struct scan_cache_node *node,
gaurank kathpaliac2dac1c2019-05-07 10:16:53 +0530486 qdf_time_t scan_aging_time)
Abhishek Singhd4e600f2017-02-21 15:16:28 +0530487{
488 if (util_scan_entry_age(node->entry) >=
Abhishek Singh6e7489e2017-03-23 10:54:22 +0530489 scan_aging_time) {
gaurank kathpaliac2dac1c2019-05-07 10:16:53 +0530490 scm_debug("Aging out BSSID: %pM with age %lu ms",
Yeshwanth Sriram Guntukadad6b5b2018-07-17 13:23:46 +0530491 node->entry->bssid.bytes,
492 util_scan_entry_age(node->entry));
Amir Patel7c1a52c2018-03-02 16:33:04 +0530493 qdf_spin_lock_bh(&scan_db->scan_db_lock);
494 scm_scan_entry_del(scan_db, node);
495 qdf_spin_unlock_bh(&scan_db->scan_db_lock);
Abhishek Singh483d9142017-03-06 13:28:13 +0530496 }
Abhishek Singhd4e600f2017-02-21 15:16:28 +0530497}
498
Sandeep Puligillae062e822018-02-28 00:27:10 -0800499static bool scm_bss_is_connected(struct scan_cache_entry *entry)
500{
501 if (entry->mlme_info.assoc_state == SCAN_ENTRY_CON_STATE_ASSOC)
502 return true;
503 return false;
504}
Abhishek Singh6e7489e2017-03-23 10:54:22 +0530505void scm_age_out_entries(struct wlan_objmgr_psoc *psoc,
506 struct scan_dbs *scan_db)
Abhishek Singhd4e600f2017-02-21 15:16:28 +0530507{
508 int i;
509 struct scan_cache_node *cur_node = NULL;
510 struct scan_cache_node *next_node = NULL;
Abhishek Singh6e7489e2017-03-23 10:54:22 +0530511 struct scan_default_params *def_param;
512
513 def_param = wlan_scan_psoc_get_def_params(psoc);
Naveen Rawat6f7ddca2018-01-18 10:53:45 -0800514 if (!def_param) {
515 scm_err("wlan_scan_psoc_get_def_params failed");
516 return;
517 }
Abhishek Singhd4e600f2017-02-21 15:16:28 +0530518
519 for (i = 0 ; i < SCAN_HASH_SIZE; i++) {
520 cur_node = scm_get_next_node(scan_db,
521 &scan_db->scan_hash_tbl[i], NULL);
522 while (cur_node) {
Sandeep Puligillae062e822018-02-28 00:27:10 -0800523 if (!scm_bss_is_connected(cur_node->entry))
524 scm_check_and_age_out(scan_db, cur_node,
Abhishek Singh6e7489e2017-03-23 10:54:22 +0530525 def_param->scan_cache_aging_time);
Abhishek Singhd4e600f2017-02-21 15:16:28 +0530526 next_node = scm_get_next_node(scan_db,
527 &scan_db->scan_hash_tbl[i], cur_node);
528 cur_node = next_node;
529 next_node = NULL;
530 }
531 }
532}
533
534/**
Amir Patel7c1a52c2018-03-02 16:33:04 +0530535 * scm_flush_oldest_entry() - Iterate over scan db and flust out the
536 * oldest entry
537 * @scan_db: scan db from which oldest entry needs to be flushed
Abhishek Singhd4e600f2017-02-21 15:16:28 +0530538 *
539 * Return: QDF_STATUS
540 */
541static QDF_STATUS scm_flush_oldest_entry(struct scan_dbs *scan_db)
542{
543 int i;
544 struct scan_cache_node *oldest_node = NULL;
545 struct scan_cache_node *cur_node;
Abhishek Singhd4e600f2017-02-21 15:16:28 +0530546
Abhishek Singhd4e600f2017-02-21 15:16:28 +0530547 for (i = 0 ; i < SCAN_HASH_SIZE; i++) {
Abhishek Singh3f11bd62017-12-08 14:08:16 +0530548 /* Get the first valid node for the hash */
Amir Patel7c1a52c2018-03-02 16:33:04 +0530549 cur_node = scm_get_next_node(scan_db,
550 &scan_db->scan_hash_tbl[i],
551 NULL);
552 /* Iterate scan db and flush out oldest node
553 * take ref_cnt for oldest_node
554 */
555
556 while (cur_node) {
Abhishek Singhd4e600f2017-02-21 15:16:28 +0530557 if (!oldest_node ||
558 (util_scan_entry_age(oldest_node->entry) <
Amir Patel7c1a52c2018-03-02 16:33:04 +0530559 util_scan_entry_age(cur_node->entry))) {
560 if (oldest_node)
561 scm_scan_entry_put_ref(scan_db,
562 oldest_node,
563 true);
Abhishek Singhd4e600f2017-02-21 15:16:28 +0530564 oldest_node = cur_node;
Amir Patel7c1a52c2018-03-02 16:33:04 +0530565 scm_scan_entry_get_ref(oldest_node);
566 }
567
568 cur_node = scm_get_next_node(scan_db,
569 &scan_db->scan_hash_tbl[i],
570 cur_node);
571 };
Abhishek Singhd4e600f2017-02-21 15:16:28 +0530572 }
Naveen Rawat6f7ddca2018-01-18 10:53:45 -0800573
574 if (oldest_node) {
gaurank kathpaliac2dac1c2019-05-07 10:16:53 +0530575 scm_debug("Flush oldest BSSID: %pM with age %lu ms",
Naveen Rawat6f7ddca2018-01-18 10:53:45 -0800576 oldest_node->entry->bssid.bytes,
577 util_scan_entry_age(oldest_node->entry));
Amir Patel7c1a52c2018-03-02 16:33:04 +0530578 /* Release ref_cnt taken for oldest_node and delete it */
579 qdf_spin_lock_bh(&scan_db->scan_db_lock);
Amir Patel7c1a52c2018-03-02 16:33:04 +0530580 scm_scan_entry_del(scan_db, oldest_node);
Amir Patel2b2435e2018-03-20 12:30:27 +0530581 scm_scan_entry_put_ref(scan_db, oldest_node, false);
Amir Patel7c1a52c2018-03-02 16:33:04 +0530582 qdf_spin_unlock_bh(&scan_db->scan_db_lock);
Naveen Rawat6f7ddca2018-01-18 10:53:45 -0800583 }
Abhishek Singhd4e600f2017-02-21 15:16:28 +0530584
585 return QDF_STATUS_SUCCESS;
586}
587
588/**
589 * scm_update_alt_wcn_ie() - update the alternate WCN IE
590 * @from: copy from
591 * @dst: copy to
592 *
593 * Return: void
594 */
595static void scm_update_alt_wcn_ie(struct scan_cache_entry *from,
596 struct scan_cache_entry *dst)
597{
598 uint32_t alt_wcn_ie_len;
599
600 if (from->frm_subtype == dst->frm_subtype)
601 return;
602
603 if (!from->ie_list.wcn && !dst->ie_list.wcn)
604 return;
605
606 /* Existing WCN IE is empty. */
607 if (!from->ie_list.wcn)
608 return;
609
610 alt_wcn_ie_len = 2 + from->ie_list.wcn[1];
611 if (alt_wcn_ie_len > WLAN_MAX_IE_LEN + 2) {
612 scm_err("invalid IE len");
613 return;
614 }
615
616 if (!dst->alt_wcn_ie.ptr) {
617 /* allocate this additional buffer for alternate WCN IE */
Om Prakash Tripathi9b56f5d2018-05-29 11:42:19 +0530618 dst->alt_wcn_ie.ptr =
619 qdf_mem_malloc_atomic(WLAN_MAX_IE_LEN + 2);
Abhishek Singhd4e600f2017-02-21 15:16:28 +0530620 if (!dst->alt_wcn_ie.ptr) {
621 scm_err("failed to allocate memory");
622 return;
623 }
624 }
625 qdf_mem_copy(dst->alt_wcn_ie.ptr,
626 from->ie_list.wcn, alt_wcn_ie_len);
627 dst->alt_wcn_ie.len = alt_wcn_ie_len;
628}
629
630/**
Om Prakash Tripathic3fcb682017-08-01 18:24:55 +0530631 * scm_update_mlme_info() - update mlme info
632 * @src: source scan entry
633 * @dest: destination scan entry
634 *
635 * Return: void
636 */
637static inline void
638scm_update_mlme_info(struct scan_cache_entry *src,
639 struct scan_cache_entry *dest)
640{
641 qdf_mem_copy(&dest->mlme_info, &src->mlme_info,
642 sizeof(struct mlme_info));
643}
644
645/**
Amir Patel7c1a52c2018-03-02 16:33:04 +0530646 * scm_copy_info_from_dup_entry() - copy duplicate node info
647 * to new scan entry
Abhishek Singh7062efa2019-03-05 15:37:07 +0530648 * @pdev: pdev ptr
649 * @scan_obj: scan obj ptr
Abhishek Singhd4e600f2017-02-21 15:16:28 +0530650 * @scan_db: scan database
651 * @scan_params: new entry to be added
Amir Patel7c1a52c2018-03-02 16:33:04 +0530652 * @scan_node: duplicate entry
Abhishek Singhd4e600f2017-02-21 15:16:28 +0530653 *
Amir Patel7c1a52c2018-03-02 16:33:04 +0530654 * Copy duplicate node info to new entry.
Abhishek Singhd4e600f2017-02-21 15:16:28 +0530655 *
656 * Return: void
657 */
Amir Patel7c1a52c2018-03-02 16:33:04 +0530658static void
Abhishek Singh7062efa2019-03-05 15:37:07 +0530659scm_copy_info_from_dup_entry(struct wlan_objmgr_pdev *pdev,
660 struct wlan_scan_obj *scan_obj,
661 struct scan_dbs *scan_db,
Amir Patel7c1a52c2018-03-02 16:33:04 +0530662 struct scan_cache_entry *scan_params,
663 struct scan_cache_node *scan_node)
Abhishek Singhd4e600f2017-02-21 15:16:28 +0530664{
665 struct scan_cache_entry *scan_entry;
Om Prakash Tripathicdcbb392017-04-18 18:51:20 +0530666 uint64_t time_gap;
Abhishek Singhd4e600f2017-02-21 15:16:28 +0530667
668 scan_entry = scan_node->entry;
Abhishek Singh7062efa2019-03-05 15:37:07 +0530669
670 /* Update probe resp entry as well if AP is in hidden mode */
671 if (scan_params->frm_subtype == MGMT_SUBTYPE_PROBE_RESP &&
672 scan_entry->is_hidden_ssid)
673 scan_params->is_hidden_ssid = true;
674
675 /*
676 * If AP changed its beacon from not having an SSID to showing it the
677 * kernel will drop the entry asumming that something is wrong with AP.
678 * This can result in connection failure while updating the bss during
679 * connection. So flush the hidden entry from kernel before indicating
680 * the new entry.
681 */
682 if (scan_entry->is_hidden_ssid &&
683 scan_params->frm_subtype == MGMT_SUBTYPE_BEACON &&
684 !util_scan_is_null_ssid(&scan_params->ssid)) {
685 if (scan_obj->cb.unlink_bss) {
686 scm_debug("Hidden AP %pM switch to non-hidden SSID, So unlink the entry",
687 scan_entry->bssid.bytes);
688 scan_obj->cb.unlink_bss(pdev, scan_entry);
689 }
690 }
691
Abhishek Singhd4e600f2017-02-21 15:16:28 +0530692 /* If old entry have the ssid but new entry does not */
Yeshwanth Sriram Guntuka294ce112018-10-23 16:49:19 +0530693 if (util_scan_is_null_ssid(&scan_params->ssid) &&
694 scan_entry->ssid.length) {
Abhishek Singhd4e600f2017-02-21 15:16:28 +0530695 /*
696 * New entry has a hidden SSID and old one has the SSID.
697 * Add the entry by using the ssid of the old entry
698 * only if diff of saved SSID time and current time is
699 * less than HIDDEN_SSID_TIME time.
700 * This will avoid issues in case AP changes its SSID
701 * while remain hidden.
702 */
703 time_gap =
704 qdf_mc_timer_get_system_time() -
705 scan_entry->hidden_ssid_timestamp;
706 if (time_gap <= HIDDEN_SSID_TIME) {
707 scan_params->hidden_ssid_timestamp =
708 scan_entry->hidden_ssid_timestamp;
709 scan_params->ssid.length =
710 scan_entry->ssid.length;
711 qdf_mem_copy(scan_params->ssid.ssid,
712 scan_entry->ssid.ssid,
Yeshwanth Sriram Guntuka294ce112018-10-23 16:49:19 +0530713 scan_entry->ssid.length);
Abhishek Singhd4e600f2017-02-21 15:16:28 +0530714 }
715 }
Abhishek Singhc05285d2018-01-12 15:19:32 +0530716
Abhishek Singhd4e600f2017-02-21 15:16:28 +0530717 /*
Abhishek Singhc05285d2018-01-12 15:19:32 +0530718 * Due to Rx sensitivity issue, sometime beacons are seen on adjacent
719 * channel so workaround in software is needed. If DS params or HT info
720 * are present driver can get proper channel info from these IEs and set
721 * channel_mismatch so that the older RSSI values are used in new entry.
722 *
723 * For the cases where DS params and HT info is not present, driver
724 * needs to check below conditions to get proper channel and set
725 * channel_mismatch so that the older RSSI values are used in new entry:
726 * -- The old entry channel and new entry channel are not same
727 * -- RSSI is less than -80, this indicate that the signal has leaked
728 * in adjacent channel.
Abhishek Singhd4e600f2017-02-21 15:16:28 +0530729 */
Abhishek Singhc05285d2018-01-12 15:19:32 +0530730 if ((scan_params->frm_subtype == MGMT_SUBTYPE_BEACON) &&
731 !util_scan_entry_htinfo(scan_params) &&
732 !util_scan_entry_ds_param(scan_params) &&
Ashish Kumar Dhanotiya75ccbd42019-08-29 19:17:44 +0530733 (scan_params->channel.chan_freq != scan_entry->channel.chan_freq) &&
Abhishek Singhc05285d2018-01-12 15:19:32 +0530734 (scan_params->rssi_raw < ADJACENT_CHANNEL_RSSI_THRESHOLD)) {
Ashish Kumar Dhanotiya75ccbd42019-08-29 19:17:44 +0530735 scan_params->channel.chan_freq = scan_entry->channel.chan_freq;
Abhishek Singhc05285d2018-01-12 15:19:32 +0530736 scan_params->channel_mismatch = true;
737 }
738
739 /* Use old value for rssi if beacon was heard on adjacent channel. */
Abhishek Singhd4e600f2017-02-21 15:16:28 +0530740 if (scan_params->channel_mismatch) {
Shashikala Prabhua477ec22019-10-22 09:41:10 +0530741 scan_params->snr = scan_entry->snr;
742 scan_params->avg_snr = scan_entry->avg_snr;
Abhishek Singhd4e600f2017-02-21 15:16:28 +0530743 scan_params->rssi_raw = scan_entry->rssi_raw;
Om Prakash Tripathicdcbb392017-04-18 18:51:20 +0530744 scan_params->avg_rssi = scan_entry->avg_rssi;
Abhishek Singhd4e600f2017-02-21 15:16:28 +0530745 scan_params->rssi_timestamp =
746 scan_entry->rssi_timestamp;
Om Prakash Tripathicdcbb392017-04-18 18:51:20 +0530747 } else {
Shashikala Prabhua477ec22019-10-22 09:41:10 +0530748 /* If elapsed time since last rssi and snr update for this
Om Prakash Tripathicdcbb392017-04-18 18:51:20 +0530749 * entry is smaller than a thresold, calculate a
Shashikala Prabhua477ec22019-10-22 09:41:10 +0530750 * running average of the RSSI and SNR values.
751 * Otherwise new frames RSSI and SNR are more representive
Om Prakash Tripathi6af738b2017-08-22 15:46:38 +0530752 * of the signal strength.
Om Prakash Tripathicdcbb392017-04-18 18:51:20 +0530753 */
754 time_gap =
Om Prakash Tripathi6af738b2017-08-22 15:46:38 +0530755 scan_params->scan_entry_time -
756 scan_entry->rssi_timestamp;
Shashikala Prabhua477ec22019-10-22 09:41:10 +0530757 if (time_gap > WLAN_RSSI_AVERAGING_TIME) {
Om Prakash Tripathicdcbb392017-04-18 18:51:20 +0530758 scan_params->avg_rssi =
759 WLAN_RSSI_IN(scan_params->rssi_raw);
Shashikala Prabhua477ec22019-10-22 09:41:10 +0530760 scan_params->avg_snr =
761 WLAN_SNR_IN(scan_params->snr);
762 }
Om Prakash Tripathi51052df2017-08-04 14:06:41 +0530763 else {
Shashikala Prabhua477ec22019-10-22 09:41:10 +0530764 /* Copy previous average rssi and snr to new entry */
765 scan_params->avg_snr = scan_entry->avg_snr;
Om Prakash Tripathi51052df2017-08-04 14:06:41 +0530766 scan_params->avg_rssi = scan_entry->avg_rssi;
767 /* Average with previous samples */
Om Prakash Tripathicdcbb392017-04-18 18:51:20 +0530768 WLAN_RSSI_LPF(scan_params->avg_rssi,
Shashikala Prabhua477ec22019-10-22 09:41:10 +0530769 scan_params->rssi_raw);
770 WLAN_SNR_LPF(scan_params->avg_snr,
771 scan_params->snr);
Om Prakash Tripathi51052df2017-08-04 14:06:41 +0530772 }
Om Prakash Tripathicdcbb392017-04-18 18:51:20 +0530773
774 scan_params->rssi_timestamp = scan_params->scan_entry_time;
Abhishek Singhd4e600f2017-02-21 15:16:28 +0530775 }
Om Prakash Tripathicdcbb392017-04-18 18:51:20 +0530776
Abhishek Singhd4e600f2017-02-21 15:16:28 +0530777 /* copy wsn ie from scan_entry to scan_params*/
778 scm_update_alt_wcn_ie(scan_entry, scan_params);
779
Om Prakash Tripathic3fcb682017-08-01 18:24:55 +0530780 /* copy mlme info from scan_entry to scan_params*/
781 scm_update_mlme_info(scan_entry, scan_params);
Abhishek Singhd4e600f2017-02-21 15:16:28 +0530782}
783
784/**
Amir Patel7c1a52c2018-03-02 16:33:04 +0530785 * scm_find_duplicate() - find duplicate entry,
786 * if present, add input scan entry before it and delete
787 * duplicate entry. otherwise add entry to tail
Abhishek Singh7062efa2019-03-05 15:37:07 +0530788 * @pdev: pdev ptr
789 * @scan_obj: scan obj ptr
Abhishek Singhd4e600f2017-02-21 15:16:28 +0530790 * @scan_db: scan db
791 * @entry: input scan cache entry
Amir Patel7c1a52c2018-03-02 16:33:04 +0530792 * @dup_node: node before which new entry to be added
Abhishek Singhd4e600f2017-02-21 15:16:28 +0530793 *
Amir Patel7c1a52c2018-03-02 16:33:04 +0530794 * ref_cnt is taken for dup_node, caller should release ref taken
795 * if returns true.
796 *
797 * Return: bool
Abhishek Singhd4e600f2017-02-21 15:16:28 +0530798 */
799static bool
Abhishek Singh7062efa2019-03-05 15:37:07 +0530800scm_find_duplicate(struct wlan_objmgr_pdev *pdev,
801 struct wlan_scan_obj *scan_obj,
802 struct scan_dbs *scan_db,
Amir Patel7c1a52c2018-03-02 16:33:04 +0530803 struct scan_cache_entry *entry,
804 struct scan_cache_node **dup_node)
Abhishek Singhd4e600f2017-02-21 15:16:28 +0530805{
806 uint8_t hash_idx;
807 struct scan_cache_node *cur_node;
808 struct scan_cache_node *next_node = NULL;
809
810 hash_idx = SCAN_GET_HASH(entry->bssid.bytes);
811
812 cur_node = scm_get_next_node(scan_db,
Amir Patel7c1a52c2018-03-02 16:33:04 +0530813 &scan_db->scan_hash_tbl[hash_idx],
814 NULL);
Abhishek Singhd4e600f2017-02-21 15:16:28 +0530815
816 while (cur_node) {
817 if (util_is_scan_entry_match(entry,
818 cur_node->entry)) {
Abhishek Singh7062efa2019-03-05 15:37:07 +0530819 scm_copy_info_from_dup_entry(pdev, scan_obj, scan_db,
820 entry, cur_node);
Amir Patel7c1a52c2018-03-02 16:33:04 +0530821 *dup_node = cur_node;
Abhishek Singhd4e600f2017-02-21 15:16:28 +0530822 return true;
823 }
824 next_node = scm_get_next_node(scan_db,
825 &scan_db->scan_hash_tbl[hash_idx], cur_node);
826 cur_node = next_node;
827 next_node = NULL;
828 }
829
830 return false;
831}
832
833/**
834 * scm_add_update_entry() - add or update scan entry
Abhishek Singha6157cf2018-03-01 10:29:34 +0530835 * @psoc: psoc ptr
836 * @pdev: pdev pointer
Abhishek Singhd4e600f2017-02-21 15:16:28 +0530837 * @scan_params: new received entry
838 *
839 * Return: QDF_STATUS
840 */
Abhishek Singha6157cf2018-03-01 10:29:34 +0530841static QDF_STATUS scm_add_update_entry(struct wlan_objmgr_psoc *psoc,
842 struct wlan_objmgr_pdev *pdev, struct scan_cache_entry *scan_params)
Abhishek Singhd4e600f2017-02-21 15:16:28 +0530843{
Amir Patel7c1a52c2018-03-02 16:33:04 +0530844 struct scan_cache_node *dup_node = NULL;
845 struct scan_cache_node *scan_node = NULL;
846 bool is_dup_found = false;
Abhishek Singhd4e600f2017-02-21 15:16:28 +0530847 QDF_STATUS status;
Abhishek Singha6157cf2018-03-01 10:29:34 +0530848 struct scan_dbs *scan_db;
849 struct wlan_scan_obj *scan_obj;
850
851 scan_db = wlan_pdev_get_scan_db(psoc, pdev);
852 if (!scan_db) {
853 scm_err("scan_db is NULL");
854 return QDF_STATUS_E_INVAL;
855 }
856
857 scan_obj = wlan_psoc_get_scan_obj(psoc);
858 if (!scan_obj) {
859 scm_err("scan_obj is NULL");
860 return QDF_STATUS_E_INVAL;
861 }
Abhishek Singhd4e600f2017-02-21 15:16:28 +0530862
Abhishek Singhd4e600f2017-02-21 15:16:28 +0530863 if (scan_params->frm_subtype ==
864 MGMT_SUBTYPE_PROBE_RESP &&
865 !scan_params->ie_list.ssid)
Yeshwanth Sriram Guntukadad6b5b2018-07-17 13:23:46 +0530866 scm_debug("Probe resp doesn't contain SSID");
Abhishek Singhd4e600f2017-02-21 15:16:28 +0530867
Abhishek Singhd9e8b4f2017-04-12 14:58:08 +0530868
Abhishek Singhd4e600f2017-02-21 15:16:28 +0530869 if (scan_params->ie_list.csa ||
870 scan_params->ie_list.xcsa ||
871 scan_params->ie_list.cswrp)
Yeshwanth Sriram Guntukadad6b5b2018-07-17 13:23:46 +0530872 scm_debug("CSA IE present for BSSID: %pM",
873 scan_params->bssid.bytes);
Abhishek Singhd4e600f2017-02-21 15:16:28 +0530874
Abhishek Singh7062efa2019-03-05 15:37:07 +0530875 is_dup_found = scm_find_duplicate(pdev, scan_obj, scan_db, scan_params,
876 &dup_node);
Abhishek Singha6157cf2018-03-01 10:29:34 +0530877
878 if (scan_obj->cb.inform_beacon)
879 scan_obj->cb.inform_beacon(pdev, scan_params);
880
Amir Patel7c1a52c2018-03-02 16:33:04 +0530881 if (scan_db->num_entries >= MAX_SCAN_CACHE_SIZE) {
882 status = scm_flush_oldest_entry(scan_db);
Amir Patel2b2435e2018-03-20 12:30:27 +0530883 if (QDF_IS_STATUS_ERROR(status)) {
884 /* release ref taken for dup node */
885 if (is_dup_found)
886 scm_scan_entry_put_ref(scan_db, dup_node, true);
Amir Patel7c1a52c2018-03-02 16:33:04 +0530887 return status;
Amir Patel2b2435e2018-03-20 12:30:27 +0530888 }
Amir Patel7c1a52c2018-03-02 16:33:04 +0530889 }
Abhishek Singhd4e600f2017-02-21 15:16:28 +0530890
Amir Patel7c1a52c2018-03-02 16:33:04 +0530891 scan_node = qdf_mem_malloc(sizeof(*scan_node));
Amir Patel2b2435e2018-03-20 12:30:27 +0530892 if (!scan_node) {
893 /* release ref taken for dup node */
894 if (is_dup_found)
895 scm_scan_entry_put_ref(scan_db, dup_node, true);
Amir Patel7c1a52c2018-03-02 16:33:04 +0530896 return QDF_STATUS_E_NOMEM;
Amir Patel2b2435e2018-03-20 12:30:27 +0530897 }
Amir Patel7c1a52c2018-03-02 16:33:04 +0530898
899 scan_node->entry = scan_params;
900 qdf_spin_lock_bh(&scan_db->scan_db_lock);
901 scm_add_scan_node(scan_db, scan_node, dup_node);
902
903 if (is_dup_found) {
904 /* release ref taken for dup node and delete it */
Amir Patel7c1a52c2018-03-02 16:33:04 +0530905 scm_scan_entry_del(scan_db, dup_node);
Amir Patel2b2435e2018-03-20 12:30:27 +0530906 scm_scan_entry_put_ref(scan_db, dup_node, false);
Amir Patel7c1a52c2018-03-02 16:33:04 +0530907 }
908 qdf_spin_unlock_bh(&scan_db->scan_db_lock);
909
910 return QDF_STATUS_SUCCESS;
Abhishek Singhd4e600f2017-02-21 15:16:28 +0530911}
912
Abhishek Singhbd80d5c2019-04-09 15:05:54 +0530913QDF_STATUS __scm_handle_bcn_probe(struct scan_bcn_probe_event *bcn)
Abhishek Singh4caf1a92017-02-21 15:01:08 +0530914{
Abhishek Singh4caf1a92017-02-21 15:01:08 +0530915 struct wlan_objmgr_psoc *psoc;
916 struct wlan_objmgr_pdev *pdev = NULL;
917 struct scan_cache_entry *scan_entry;
918 struct wlan_scan_obj *scan_obj;
Sandeep Puligillac6764592017-12-05 21:01:52 -0800919 qdf_list_t *scan_list = NULL;
920 QDF_STATUS status = QDF_STATUS_SUCCESS;
921 uint32_t list_count, i;
922 qdf_list_node_t *next_node = NULL;
923 struct scan_cache_node *scan_node;
Om Prakash Tripathi628dfd32018-10-18 16:08:28 +0530924 struct wlan_frame_hdr *hdr = NULL;
Abhishek Singh4caf1a92017-02-21 15:01:08 +0530925
Abhishek Singh4caf1a92017-02-21 15:01:08 +0530926 if (!bcn) {
927 scm_err("bcn is NULL");
928 return QDF_STATUS_E_INVAL;
929 }
930 if (!bcn->rx_data) {
931 scm_err("rx_data iS NULL");
932 status = QDF_STATUS_E_INVAL;
933 goto free_nbuf;
934 }
935 if (!bcn->buf) {
936 scm_err("buf is NULL");
937 status = QDF_STATUS_E_INVAL;
938 goto free_nbuf;
939 }
940
Om Prakash Tripathi628dfd32018-10-18 16:08:28 +0530941 hdr = (struct wlan_frame_hdr *)qdf_nbuf_data(bcn->buf);
Abhishek Singh4caf1a92017-02-21 15:01:08 +0530942 psoc = bcn->psoc;
943 pdev = wlan_objmgr_get_pdev_by_id(psoc,
944 bcn->rx_data->pdev_id, WLAN_SCAN_ID);
945 if (!pdev) {
946 scm_err("pdev is NULL");
947 status = QDF_STATUS_E_INVAL;
948 goto free_nbuf;
949 }
950 scan_obj = wlan_psoc_get_scan_obj(psoc);
951 if (!scan_obj) {
952 scm_err("scan_obj is NULL");
953 status = QDF_STATUS_E_INVAL;
954 goto free_nbuf;
955 }
Abhishek Singh4caf1a92017-02-21 15:01:08 +0530956
957 if (qdf_nbuf_len(bcn->buf) <=
958 (sizeof(struct wlan_frame_hdr) +
959 offsetof(struct wlan_bcn_frame, ie))) {
Om Prakash Tripathi8e9beae2018-04-27 14:35:39 +0530960 scm_debug("invalid beacon/probe length");
Abhishek Singh4caf1a92017-02-21 15:01:08 +0530961 status = QDF_STATUS_E_INVAL;
962 goto free_nbuf;
963 }
964
Basamma Yakkanahalliab48ce32018-07-06 18:49:19 +0530965 if (bcn->frm_type == MGMT_SUBTYPE_BEACON &&
Ashish Kumar Dhanotiya75ccbd42019-08-29 19:17:44 +0530966 wlan_reg_is_dfs_for_freq(pdev, bcn->rx_data->chan_freq)) {
Basamma Yakkanahalliab48ce32018-07-06 18:49:19 +0530967 util_scan_add_hidden_ssid(pdev, bcn->buf);
968 }
969
Sandeep Puligillac6764592017-12-05 21:01:52 -0800970 scan_list =
Shashikala Prabhu7edbb052018-04-12 09:55:25 +0530971 util_scan_unpack_beacon_frame(pdev, qdf_nbuf_data(bcn->buf),
Abhishek Singh4caf1a92017-02-21 15:01:08 +0530972 qdf_nbuf_len(bcn->buf), bcn->frm_type,
973 bcn->rx_data);
Sandeep Puligillac6764592017-12-05 21:01:52 -0800974 if (!scan_list || qdf_list_empty(scan_list)) {
Om Prakash Tripathi628dfd32018-10-18 16:08:28 +0530975 scm_debug("failed to unpack %d frame BSSID: %pM",
976 bcn->frm_type, hdr->i_addr3);
Abhishek Singh4caf1a92017-02-21 15:01:08 +0530977 status = QDF_STATUS_E_INVAL;
978 goto free_nbuf;
979 }
Abhishek Singh4caf1a92017-02-21 15:01:08 +0530980
Sandeep Puligillac6764592017-12-05 21:01:52 -0800981 list_count = qdf_list_size(scan_list);
982 for (i = 0; i < list_count; i++) {
983 status = qdf_list_remove_front(scan_list, &next_node);
Jeff Johnson82eb2122019-03-20 12:16:13 -0700984 if (QDF_IS_STATUS_ERROR(status) || !next_node) {
Om Prakash Tripathi628dfd32018-10-18 16:08:28 +0530985 scm_debug("list remove failure i:%d, lsize:%d, BSSID: %pM",
986 i, list_count, hdr->i_addr3);
Sandeep Puligillac6764592017-12-05 21:01:52 -0800987 status = QDF_STATUS_E_INVAL;
988 goto free_nbuf;
989 }
Abhishek Singh4caf1a92017-02-21 15:01:08 +0530990
Sandeep Puligillac6764592017-12-05 21:01:52 -0800991 scan_node = qdf_container_of(next_node,
992 struct scan_cache_node, node);
Abhishek Singh4caf1a92017-02-21 15:01:08 +0530993
Sandeep Puligillac6764592017-12-05 21:01:52 -0800994 scan_entry = scan_node->entry;
Abhishek Singhc05285d2018-01-12 15:19:32 +0530995
Om Prakash Tripathi5e47d432018-02-23 16:56:09 +0530996 if (scan_obj->drop_bcn_on_chan_mismatch &&
997 scan_entry->channel_mismatch) {
Abhishek Singhe88c0e82018-12-20 13:48:39 +0530998 scm_debug("Drop frame, as channel mismatch Received for from BSSID: %pM Seq Num: %d",
999 scan_entry->bssid.bytes,
1000 scan_entry->seq_num);
Om Prakash Tripathi5e47d432018-02-23 16:56:09 +05301001 util_scan_free_cache_entry(scan_entry);
1002 qdf_mem_free(scan_node);
1003 continue;
1004 }
1005
Abhishek Ambure986f5c92019-10-21 14:52:59 +05301006 scm_nofl_debug("Received %s from BSSID: %pM tsf_delta = %u Seq Num: %d ssid:%.*s, rssi: %d snr = %d frequency %d phy_mode %d pdev_id = %d",
Abhishek Singhb337ebb2019-01-18 15:21:35 +05301007 (bcn->frm_type == MGMT_SUBTYPE_PROBE_RESP) ?
1008 "Probe Rsp" : "Beacon", scan_entry->bssid.bytes,
1009 scan_entry->tsf_delta, scan_entry->seq_num,
1010 scan_entry->ssid.length, scan_entry->ssid.ssid,
1011 scan_entry->rssi_raw,
Shashikala Prabhua477ec22019-10-22 09:41:10 +05301012 scan_entry->snr,
Ashish Kumar Dhanotiya75ccbd42019-08-29 19:17:44 +05301013 scan_entry->channel.chan_freq,
Abhishek Ambure986f5c92019-10-21 14:52:59 +05301014 scan_entry->phy_mode,
Abhishek Singhb337ebb2019-01-18 15:21:35 +05301015 wlan_objmgr_pdev_get_pdev_id(pdev));
1016
Om Prakash Tripathifdaf38b2018-02-21 14:13:32 +05301017 if (scan_obj->cb.update_beacon)
1018 scan_obj->cb.update_beacon(pdev, scan_entry);
1019
Paul Zhangca615212018-02-02 17:43:37 +08001020 if (wlan_reg_11d_enabled_on_host(psoc))
1021 scm_11d_handle_country_info(psoc, pdev, scan_entry);
1022
Abhishek Singha6157cf2018-03-01 10:29:34 +05301023 status = scm_add_update_entry(psoc, pdev, scan_entry);
Abhishek Singhc05285d2018-01-12 15:19:32 +05301024 if (QDF_IS_STATUS_ERROR(status)) {
Abhishek Singhe88c0e82018-12-20 13:48:39 +05301025 scm_debug("failed to add entry for BSSID: %pM Seq Num: %d",
1026 scan_entry->bssid.bytes,
1027 scan_entry->seq_num);
Abhishek Singhc05285d2018-01-12 15:19:32 +05301028 util_scan_free_cache_entry(scan_entry);
1029 qdf_mem_free(scan_node);
Abhishek Singhc05285d2018-01-12 15:19:32 +05301030 continue;
1031 }
Sandeep Puligillac6764592017-12-05 21:01:52 -08001032
Sandeep Puligillac6764592017-12-05 21:01:52 -08001033 qdf_mem_free(scan_node);
Abhishek Singhd4e600f2017-02-21 15:16:28 +05301034 }
1035
Abhishek Singh4caf1a92017-02-21 15:01:08 +05301036free_nbuf:
Sandeep Puligillac6764592017-12-05 21:01:52 -08001037 if (scan_list)
1038 qdf_mem_free(scan_list);
Om Prakash Tripathif527f162017-04-11 17:52:12 +05301039 if (bcn->psoc)
1040 wlan_objmgr_psoc_release_ref(bcn->psoc, WLAN_SCAN_ID);
Abhishek Singh4caf1a92017-02-21 15:01:08 +05301041 if (pdev)
1042 wlan_objmgr_pdev_release_ref(pdev, WLAN_SCAN_ID);
1043 if (bcn->rx_data)
1044 qdf_mem_free(bcn->rx_data);
1045 if (bcn->buf)
1046 qdf_nbuf_free(bcn->buf);
1047 qdf_mem_free(bcn);
1048
1049 return status;
1050}
1051
Abhishek Singhbd80d5c2019-04-09 15:05:54 +05301052QDF_STATUS scm_handle_bcn_probe(struct scheduler_msg *msg)
1053{
1054 if (!msg) {
1055 scm_err("msg is NULL");
1056 return QDF_STATUS_E_NULL_VALUE;
1057 }
1058
1059 return __scm_handle_bcn_probe(msg->bodyptr);
1060}
1061
Abhishek Singh37bf2e02017-02-21 15:19:55 +05301062/**
1063 * scm_list_insert_sorted() - add the entries in scan_list in sorted way
Abhishek Singh6e7489e2017-03-23 10:54:22 +05301064 * @psoc: psoc ptr
Abhishek Singh37bf2e02017-02-21 15:19:55 +05301065 * @filter: scan filter
1066 * @scan_node: node entry to be inserted
1067 * @scan_list: Temp scan list
1068 *
1069 * Add the entries in scan_list in sorted way considering
1070 * cap_val and prefer val. The node is copy of original scan entry and
1071 * thus no lock is required.
1072 *
1073 * Return: void
1074 */
Abhishek Singh6e7489e2017-03-23 10:54:22 +05301075static void scm_list_insert_sorted(struct wlan_objmgr_psoc *psoc,
1076 struct scan_filter *filter,
Abhishek Singh37bf2e02017-02-21 15:19:55 +05301077 struct scan_cache_node *scan_node,
1078 qdf_list_t *scan_list)
1079{
1080 struct scan_cache_node *cur_node;
1081 qdf_list_node_t *cur_lst = NULL, *next_lst = NULL;
Abhishek Singh6e7489e2017-03-23 10:54:22 +05301082 struct scan_default_params *params;
Abhishek Singhb80af7e2017-07-19 18:48:42 +05301083 int pcl_chan_weight = 0;
Abhishek Singh37bf2e02017-02-21 15:19:55 +05301084
Abhishek Singh6e7489e2017-03-23 10:54:22 +05301085 params = wlan_scan_psoc_get_def_params(psoc);
Naveen Rawat6f7ddca2018-01-18 10:53:45 -08001086 if (!params) {
1087 scm_err("wlan_scan_psoc_get_def_params failed");
1088 return;
1089 }
Abhishek Singhb80af7e2017-07-19 18:48:42 +05301090 if (filter->num_of_pcl_channels > 0 &&
1091 (scan_node->entry->rssi_raw > SCM_PCL_RSSI_THRESHOLD)) {
1092 if (scm_get_pcl_weight_of_channel(
Jianmin Zhu69560e32019-11-07 19:48:16 +08001093 scan_node->entry->channel.chan_freq,
Abhishek Singhb80af7e2017-07-19 18:48:42 +05301094 filter, &pcl_chan_weight,
1095 filter->pcl_weight_list)) {
Ashish Kumar Dhanotiya75ccbd42019-08-29 19:17:44 +05301096 scm_debug("pcl freq %d pcl_chan_weight %d",
1097 scan_node->entry->channel.chan_freq,
1098 pcl_chan_weight);
Abhishek Singhb80af7e2017-07-19 18:48:42 +05301099 }
1100 }
1101 if (params->is_bssid_hint_priority &&
1102 !qdf_mem_cmp(filter->bssid_hint.bytes,
1103 scan_node->entry->bssid.bytes,
1104 QDF_MAC_ADDR_SIZE))
1105 scan_node->entry->bss_score = BEST_CANDIDATE_MAX_BSS_SCORE;
1106 else
1107 scm_calculate_bss_score(psoc, params,
1108 scan_node->entry, pcl_chan_weight);
Abhishek Singh37bf2e02017-02-21 15:19:55 +05301109
1110 if (qdf_list_empty(scan_list)) {
1111 qdf_list_insert_front(scan_list, &scan_node->node);
1112 return;
1113 }
1114
1115 qdf_list_peek_front(scan_list, &cur_lst);
1116
1117 while (cur_lst) {
1118 cur_node = qdf_container_of(cur_lst,
1119 struct scan_cache_node, node);
Abhishek Singh6e7489e2017-03-23 10:54:22 +05301120 if (scm_is_better_bss(params,
Abhishek Singh37bf2e02017-02-21 15:19:55 +05301121 scan_node->entry, cur_node->entry)) {
1122 qdf_list_insert_before(scan_list,
1123 &scan_node->node,
1124 &cur_node->node);
1125 break;
1126 }
1127 qdf_list_peek_next(scan_list,
1128 cur_lst, &next_lst);
Sandeep Puligillac4e05fd2017-04-21 01:16:24 -07001129 cur_lst = next_lst;
Abhishek Singh37bf2e02017-02-21 15:19:55 +05301130 next_lst = NULL;
1131 }
1132
1133 if (!cur_lst)
1134 qdf_list_insert_back(scan_list,
1135 &scan_node->node);
Abhishek Singh37bf2e02017-02-21 15:19:55 +05301136}
1137
1138/**
1139 * scm_scan_apply_filter_get_entry() - apply filter and get the
1140 * scan entry
Abhishek Singh6e7489e2017-03-23 10:54:22 +05301141 * @psoc: psoc pointer
Abhishek Singh37bf2e02017-02-21 15:19:55 +05301142 * @db_entry: scan entry
1143 * @filter: filter to be applied
1144 * @scan_list: scan list to which entry is added
1145 *
1146 * Return: QDF_STATUS
1147 */
1148static QDF_STATUS
Abhishek Singh6e7489e2017-03-23 10:54:22 +05301149scm_scan_apply_filter_get_entry(struct wlan_objmgr_psoc *psoc,
1150 struct scan_cache_entry *db_entry,
Abhishek Singh37bf2e02017-02-21 15:19:55 +05301151 struct scan_filter *filter,
1152 qdf_list_t *scan_list)
1153{
1154 struct scan_cache_node *scan_node = NULL;
1155 struct security_info security = {0};
1156 bool match;
1157
1158 if (!filter)
1159 match = true;
1160 else
Abhishek Singh6e7489e2017-03-23 10:54:22 +05301161 match = scm_filter_match(psoc, db_entry,
1162 filter, &security);
Abhishek Singh37bf2e02017-02-21 15:19:55 +05301163
1164 if (!match)
1165 return QDF_STATUS_SUCCESS;
1166
Om Prakash Tripathi9b56f5d2018-05-29 11:42:19 +05301167 scan_node = qdf_mem_malloc_atomic(sizeof(*scan_node));
Abhishek Singh37bf2e02017-02-21 15:19:55 +05301168 if (!scan_node)
1169 return QDF_STATUS_E_NOMEM;
1170
1171 scan_node->entry =
1172 util_scan_copy_cache_entry(db_entry);
1173
1174 if (!scan_node->entry) {
1175 qdf_mem_free(scan_node);
1176 return QDF_STATUS_E_NOMEM;
1177 }
1178
1179 qdf_mem_copy(&scan_node->entry->neg_sec_info,
1180 &security, sizeof(scan_node->entry->neg_sec_info));
1181
gaurank kathpalia7c6b8032017-12-29 11:42:02 +05301182 if (!filter || !filter->bss_scoring_required)
Abhishek Singh37bf2e02017-02-21 15:19:55 +05301183 qdf_list_insert_front(scan_list,
1184 &scan_node->node);
1185 else
Abhishek Singh6e7489e2017-03-23 10:54:22 +05301186 scm_list_insert_sorted(psoc, filter, scan_node, scan_list);
Abhishek Singh37bf2e02017-02-21 15:19:55 +05301187
1188 return QDF_STATUS_SUCCESS;
1189}
1190
1191/**
1192 * scm_get_results() - Iterate and get scan results
Abhishek Singh6e7489e2017-03-23 10:54:22 +05301193 * @psoc: psoc ptr
Abhishek Singh37bf2e02017-02-21 15:19:55 +05301194 * @scan_db: scan db
1195 * @filter: filter to be applied
1196 * @scan_list: scan list to which entry is added
1197 *
1198 * Return: void
1199 */
Abhishek Singh6e7489e2017-03-23 10:54:22 +05301200static void scm_get_results(struct wlan_objmgr_psoc *psoc,
1201 struct scan_dbs *scan_db, struct scan_filter *filter,
Abhishek Singh37bf2e02017-02-21 15:19:55 +05301202 qdf_list_t *scan_list)
1203{
Sandeep Puligillac4e05fd2017-04-21 01:16:24 -07001204 int i, count;
Abhishek Singh37bf2e02017-02-21 15:19:55 +05301205 struct scan_cache_node *cur_node;
1206 struct scan_cache_node *next_node = NULL;
1207
1208 for (i = 0 ; i < SCAN_HASH_SIZE; i++) {
1209 cur_node = scm_get_next_node(scan_db,
1210 &scan_db->scan_hash_tbl[i], NULL);
Sandeep Puligillac4e05fd2017-04-21 01:16:24 -07001211 count = qdf_list_size(&scan_db->scan_hash_tbl[i]);
1212 if (!count)
1213 continue;
Abhishek Singh37bf2e02017-02-21 15:19:55 +05301214 while (cur_node) {
Abhishek Singh6e7489e2017-03-23 10:54:22 +05301215 scm_scan_apply_filter_get_entry(psoc,
Abhishek Singh37bf2e02017-02-21 15:19:55 +05301216 cur_node->entry, filter, scan_list);
1217 next_node = scm_get_next_node(scan_db,
1218 &scan_db->scan_hash_tbl[i], cur_node);
1219 cur_node = next_node;
1220 }
1221 }
1222}
1223
1224QDF_STATUS scm_purge_scan_results(qdf_list_t *scan_list)
1225{
1226 QDF_STATUS status;
1227 struct scan_cache_node *cur_node;
1228 qdf_list_node_t *cur_lst = NULL, *next_lst = NULL;
1229
1230 if (!scan_list) {
1231 scm_err("scan_result is NULL");
1232 return QDF_STATUS_E_INVAL;
1233 }
1234
1235 status = qdf_list_peek_front(scan_list, &cur_lst);
1236
1237 while (cur_lst) {
1238 qdf_list_peek_next(
1239 scan_list, cur_lst, &next_lst);
1240 cur_node = qdf_container_of(cur_lst,
1241 struct scan_cache_node, node);
1242 status = qdf_list_remove_node(scan_list,
1243 cur_lst);
1244 if (QDF_IS_STATUS_SUCCESS(status)) {
1245 util_scan_free_cache_entry(cur_node->entry);
1246 qdf_mem_free(cur_node);
1247 }
1248 cur_lst = next_lst;
1249 next_lst = NULL;
1250 }
1251
1252 qdf_list_destroy(scan_list);
1253 qdf_mem_free(scan_list);
1254
1255 return status;
1256}
1257
1258qdf_list_t *scm_get_scan_result(struct wlan_objmgr_pdev *pdev,
1259 struct scan_filter *filter)
1260{
1261 struct wlan_objmgr_psoc *psoc;
1262 struct scan_dbs *scan_db;
1263 qdf_list_t *tmp_list;
1264
1265 if (!pdev) {
1266 scm_err("pdev is NULL");
1267 return NULL;
1268 }
1269
1270 psoc = wlan_pdev_get_psoc(pdev);
1271 if (!psoc) {
1272 scm_err("psoc is NULL");
1273 return NULL;
1274 }
Abhishek Singh6e7489e2017-03-23 10:54:22 +05301275
Abhishek Singh37bf2e02017-02-21 15:19:55 +05301276 scan_db = wlan_pdev_get_scan_db(psoc, pdev);
1277 if (!scan_db) {
1278 scm_err("scan_db is NULL");
1279 return NULL;
1280 }
1281
Om Prakash Tripathi9b56f5d2018-05-29 11:42:19 +05301282 tmp_list = qdf_mem_malloc_atomic(sizeof(*tmp_list));
Abhishek Singh37bf2e02017-02-21 15:19:55 +05301283 if (!tmp_list) {
1284 scm_err("failed tp allocate scan_result");
1285 return NULL;
1286 }
1287 qdf_list_create(tmp_list,
1288 MAX_SCAN_CACHE_SIZE);
Abhishek Singh6e7489e2017-03-23 10:54:22 +05301289 scm_age_out_entries(psoc, scan_db);
1290 scm_get_results(psoc, scan_db, filter, tmp_list);
Abhishek Singh37bf2e02017-02-21 15:19:55 +05301291
1292 return tmp_list;
1293}
1294
1295/**
1296 * scm_iterate_db_and_call_func() - iterate and call the func
1297 * @scan_db: scan db
1298 * @func: func to be called
1299 * @arg: func arg
1300 *
1301 * Return: QDF_STATUS
1302 */
1303static QDF_STATUS
1304scm_iterate_db_and_call_func(struct scan_dbs *scan_db,
1305 scan_iterator_func func, void *arg)
1306{
1307 int i;
1308 QDF_STATUS status = QDF_STATUS_SUCCESS;
1309 struct scan_cache_node *cur_node;
1310 struct scan_cache_node *next_node = NULL;
1311
1312 if (!func)
1313 return QDF_STATUS_E_INVAL;
1314
1315 for (i = 0 ; i < SCAN_HASH_SIZE; i++) {
1316 cur_node = scm_get_next_node(scan_db,
1317 &scan_db->scan_hash_tbl[i], NULL);
1318 while (cur_node) {
1319 status = func(arg, cur_node->entry);
1320 if (QDF_IS_STATUS_ERROR(status)) {
1321 scm_scan_entry_put_ref(scan_db,
Amir Patel7c1a52c2018-03-02 16:33:04 +05301322 cur_node, true);
Abhishek Singh37bf2e02017-02-21 15:19:55 +05301323 return status;
1324 }
1325 next_node = scm_get_next_node(scan_db,
1326 &scan_db->scan_hash_tbl[i], cur_node);
1327 cur_node = next_node;
1328 }
1329 }
1330
1331 return status;
1332}
1333
1334QDF_STATUS
1335scm_iterate_scan_db(struct wlan_objmgr_pdev *pdev,
1336 scan_iterator_func func, void *arg)
1337{
1338 struct wlan_objmgr_psoc *psoc;
1339 struct scan_dbs *scan_db;
1340 QDF_STATUS status;
1341
1342 if (!func) {
1343 scm_err("func is NULL");
1344 return QDF_STATUS_E_INVAL;
1345 }
1346
1347 if (!pdev) {
1348 scm_err("pdev is NULL");
1349 return QDF_STATUS_E_INVAL;
1350 }
1351
1352 psoc = wlan_pdev_get_psoc(pdev);
1353 if (!psoc) {
1354 scm_err("psoc is NULL");
1355 return QDF_STATUS_E_INVAL;
1356 }
1357 scan_db = wlan_pdev_get_scan_db(psoc, pdev);
1358 if (!scan_db) {
1359 scm_err("scan_db is NULL");
1360 return QDF_STATUS_E_INVAL;
1361 }
1362
Abhishek Singh6e7489e2017-03-23 10:54:22 +05301363 scm_age_out_entries(psoc, scan_db);
Abhishek Singh37bf2e02017-02-21 15:19:55 +05301364 status = scm_iterate_db_and_call_func(scan_db, func, arg);
1365
1366 return status;
1367}
1368
1369/**
1370 * scm_scan_apply_filter_flush_entry() -flush scan entries depending
1371 * on filter
Abhishek Singh6e7489e2017-03-23 10:54:22 +05301372 * @psoc: psoc ptr
Abhishek Singh37bf2e02017-02-21 15:19:55 +05301373 * @scan_db: scan db
1374 * @db_node: node on which filters are applied
1375 * @filter: filter to be applied
1376 *
1377 * Return: QDF_STATUS
1378 */
1379static QDF_STATUS
Abhishek Singh6e7489e2017-03-23 10:54:22 +05301380scm_scan_apply_filter_flush_entry(struct wlan_objmgr_psoc *psoc,
1381 struct scan_dbs *scan_db,
Abhishek Singh37bf2e02017-02-21 15:19:55 +05301382 struct scan_cache_node *db_node,
1383 struct scan_filter *filter)
1384{
1385 struct security_info security = {0};
1386 bool match;
1387
1388 if (!filter)
1389 match = true;
1390 else
Abhishek Singh6e7489e2017-03-23 10:54:22 +05301391 match = scm_filter_match(psoc, db_node->entry,
1392 filter, &security);
Abhishek Singh37bf2e02017-02-21 15:19:55 +05301393
1394 if (!match)
1395 return QDF_STATUS_SUCCESS;
1396
Amir Patel7c1a52c2018-03-02 16:33:04 +05301397 qdf_spin_lock_bh(&scan_db->scan_db_lock);
1398 scm_scan_entry_del(scan_db, db_node);
1399 qdf_spin_unlock_bh(&scan_db->scan_db_lock);
Abhishek Singh37bf2e02017-02-21 15:19:55 +05301400
1401 return QDF_STATUS_SUCCESS;
1402}
1403
1404/**
1405 * scm_flush_scan_entries() - API to flush scan entries depending on filters
Abhishek Singh6e7489e2017-03-23 10:54:22 +05301406 * @psoc: psoc ptr
Abhishek Singh37bf2e02017-02-21 15:19:55 +05301407 * @scan_db: scan db
1408 * @filter: filter
1409 *
1410 * Return: void
1411 */
Abhishek Singh6e7489e2017-03-23 10:54:22 +05301412static void scm_flush_scan_entries(struct wlan_objmgr_psoc *psoc,
1413 struct scan_dbs *scan_db,
Abhishek Singh37bf2e02017-02-21 15:19:55 +05301414 struct scan_filter *filter)
1415{
1416 int i;
1417 struct scan_cache_node *cur_node;
1418 struct scan_cache_node *next_node = NULL;
1419
1420 for (i = 0 ; i < SCAN_HASH_SIZE; i++) {
1421 cur_node = scm_get_next_node(scan_db,
1422 &scan_db->scan_hash_tbl[i], NULL);
1423 while (cur_node) {
Abhishek Singh6e7489e2017-03-23 10:54:22 +05301424 scm_scan_apply_filter_flush_entry(psoc, scan_db,
Abhishek Singh37bf2e02017-02-21 15:19:55 +05301425 cur_node, filter);
1426 next_node = scm_get_next_node(scan_db,
1427 &scan_db->scan_hash_tbl[i], cur_node);
1428 cur_node = next_node;
1429 }
1430 }
1431}
1432
1433QDF_STATUS scm_flush_results(struct wlan_objmgr_pdev *pdev,
1434 struct scan_filter *filter)
1435{
1436 struct wlan_objmgr_psoc *psoc;
1437 struct scan_dbs *scan_db;
1438 QDF_STATUS status = QDF_STATUS_SUCCESS;
1439
1440 if (!pdev) {
1441 scm_err("pdev is NULL");
1442 return QDF_STATUS_E_INVAL;
1443 }
1444
1445 psoc = wlan_pdev_get_psoc(pdev);
1446 if (!psoc) {
1447 scm_err("psoc is NULL");
1448 return QDF_STATUS_E_INVAL;
1449 }
1450
1451 scan_db = wlan_pdev_get_scan_db(psoc, pdev);
1452 if (!scan_db) {
1453 scm_err("scan_db is NULL");
1454 return QDF_STATUS_E_INVAL;
1455 }
1456
Abhishek Singh6e7489e2017-03-23 10:54:22 +05301457 scm_flush_scan_entries(psoc, scan_db, filter);
Abhishek Singh37bf2e02017-02-21 15:19:55 +05301458
1459 return status;
1460}
1461
1462/**
1463 * scm_filter_channels() - Remove entries not belonging to channel list
1464 * @scan_db: scan db
1465 * @db_node: node on which filters are applied
hque131d312019-11-21 17:55:27 +08001466 * @chan_freq_list: valid channel frequency (in MHz) list
Abhishek Singh37bf2e02017-02-21 15:19:55 +05301467 * @num_chan: number of channels
1468 *
1469 * Return: QDF_STATUS
1470 */
Ashish Kumar Dhanotiya75ccbd42019-08-29 19:17:44 +05301471static void scm_filter_channels(struct wlan_objmgr_pdev *pdev,
1472 struct scan_dbs *scan_db,
1473 struct scan_cache_node *db_node,
hque131d312019-11-21 17:55:27 +08001474 uint32_t *chan_freq_list, uint32_t num_chan)
Abhishek Singh37bf2e02017-02-21 15:19:55 +05301475{
1476 int i;
1477 bool match = false;
1478
1479 for (i = 0; i < num_chan; i++) {
hque131d312019-11-21 17:55:27 +08001480 if (chan_freq_list[i] == util_scan_entry_channel_frequency(
1481 db_node->entry)) {
Abhishek Singh37bf2e02017-02-21 15:19:55 +05301482 match = true;
1483 break;
1484 }
1485 }
1486
Amir Patel7c1a52c2018-03-02 16:33:04 +05301487 if (!match) {
1488 qdf_spin_lock_bh(&scan_db->scan_db_lock);
1489 scm_scan_entry_del(scan_db, db_node);
1490 qdf_spin_unlock_bh(&scan_db->scan_db_lock);
1491 }
Abhishek Singh37bf2e02017-02-21 15:19:55 +05301492}
1493
1494void scm_filter_valid_channel(struct wlan_objmgr_pdev *pdev,
hque131d312019-11-21 17:55:27 +08001495 uint32_t *chan_freq_list, uint32_t num_chan)
Abhishek Singh37bf2e02017-02-21 15:19:55 +05301496{
1497 int i;
1498 struct wlan_objmgr_psoc *psoc;
1499 struct scan_dbs *scan_db;
1500 struct scan_cache_node *cur_node;
1501 struct scan_cache_node *next_node = NULL;
1502
Yeshwanth Sriram Guntukadad6b5b2018-07-17 13:23:46 +05301503 scm_debug("num_chan = %d", num_chan);
Abhishek Singh37bf2e02017-02-21 15:19:55 +05301504
1505 if (!pdev) {
1506 scm_err("pdev is NULL");
1507 return;
1508 }
1509
1510 psoc = wlan_pdev_get_psoc(pdev);
1511 if (!psoc) {
1512 scm_err("psoc is NULL");
1513 return;
1514 }
1515
1516 scan_db = wlan_pdev_get_scan_db(psoc, pdev);
1517 if (!scan_db) {
1518 scm_err("scan_db is NULL");
1519 return;
1520 }
1521
1522 for (i = 0 ; i < SCAN_HASH_SIZE; i++) {
1523 cur_node = scm_get_next_node(scan_db,
1524 &scan_db->scan_hash_tbl[i], NULL);
1525 while (cur_node) {
Ashish Kumar Dhanotiya75ccbd42019-08-29 19:17:44 +05301526 scm_filter_channels(pdev, scan_db,
hque131d312019-11-21 17:55:27 +08001527 cur_node, chan_freq_list, num_chan);
Abhishek Singh37bf2e02017-02-21 15:19:55 +05301528 next_node = scm_get_next_node(scan_db,
1529 &scan_db->scan_hash_tbl[i], cur_node);
1530 cur_node = next_node;
1531 }
1532 }
1533}
1534
Abhishek Singh4caf1a92017-02-21 15:01:08 +05301535QDF_STATUS scm_scan_register_bcn_cb(struct wlan_objmgr_psoc *psoc,
1536 update_beacon_cb cb, enum scan_cb_type type)
1537{
1538 struct wlan_scan_obj *scan_obj;
1539
1540 scan_obj = wlan_psoc_get_scan_obj(psoc);
1541 if (!scan_obj) {
1542 scm_err("scan obj is NULL");
1543 return QDF_STATUS_E_INVAL;
1544 }
1545 switch (type) {
1546 case SCAN_CB_TYPE_INFORM_BCN:
1547 scan_obj->cb.inform_beacon = cb;
1548 break;
1549 case SCAN_CB_TYPE_UPDATE_BCN:
1550 scan_obj->cb.update_beacon = cb;
1551 break;
Abhishek Singh7062efa2019-03-05 15:37:07 +05301552 case SCAN_CB_TYPE_UNLINK_BSS:
1553 scan_obj->cb.unlink_bss = cb;
1554 break;
Abhishek Singh4caf1a92017-02-21 15:01:08 +05301555 default:
1556 scm_err("invalid cb type %d", type);
1557 }
1558
1559 return QDF_STATUS_SUCCESS;
1560}
Om Prakash Tripathi7e3f45d2016-12-28 16:58:54 +05301561
Sandeep Puligilla2e1088d2016-12-27 19:58:17 -08001562QDF_STATUS scm_db_init(struct wlan_objmgr_psoc *psoc)
1563{
Abhishek Singh4caf1a92017-02-21 15:01:08 +05301564 int i, j;
1565 struct scan_dbs *scan_db;
1566
1567 if (!psoc) {
1568 scm_err("psoc is NULL");
1569 return QDF_STATUS_E_INVAL;
1570 }
1571
1572 /* Initialize the scan database per pdev */
1573 for (i = 0; i < WLAN_UMAC_MAX_PDEVS; i++) {
1574 scan_db = wlan_pdevid_get_scan_db(psoc, i);
1575 if (!scan_db) {
1576 scm_err("scan_db is NULL %d", i);
1577 continue;
1578 }
1579 scan_db->num_entries = 0;
1580 qdf_spinlock_create(&scan_db->scan_db_lock);
1581 for (j = 0; j < SCAN_HASH_SIZE; j++)
1582 qdf_list_create(&scan_db->scan_hash_tbl[j],
1583 MAX_SCAN_CACHE_SIZE);
1584 }
Sandeep Puligilla2e1088d2016-12-27 19:58:17 -08001585 return QDF_STATUS_SUCCESS;
1586}
1587
1588QDF_STATUS scm_db_deinit(struct wlan_objmgr_psoc *psoc)
1589{
Abhishek Singh4caf1a92017-02-21 15:01:08 +05301590 int i, j;
1591 struct scan_dbs *scan_db;
1592
1593 if (!psoc) {
1594 scm_err("scan obj is NULL");
1595 return QDF_STATUS_E_INVAL;
1596 }
1597
1598 /* Initialize the scan database per pdev */
1599 for (i = 0; i < WLAN_UMAC_MAX_PDEVS; i++) {
1600 scan_db = wlan_pdevid_get_scan_db(psoc, i);
1601 if (!scan_db) {
1602 scm_err("scan_db is NULL %d", i);
1603 continue;
1604 }
1605
Abhishek Singh6e7489e2017-03-23 10:54:22 +05301606 scm_flush_scan_entries(psoc, scan_db, NULL);
Abhishek Singh4caf1a92017-02-21 15:01:08 +05301607 for (j = 0; j < SCAN_HASH_SIZE; j++)
1608 qdf_list_destroy(&scan_db->scan_hash_tbl[j]);
1609 qdf_spinlock_destroy(&scan_db->scan_db_lock);
1610 }
1611
Sandeep Puligilla2e1088d2016-12-27 19:58:17 -08001612 return QDF_STATUS_SUCCESS;
1613}
Om Prakash Tripathic3fcb682017-08-01 18:24:55 +05301614
Sandeep Puligillad763fee2019-11-08 14:00:10 -08001615#ifdef FEATURE_6G_SCAN_CHAN_SORT_ALGO
1616QDF_STATUS scm_channel_list_db_init(struct wlan_objmgr_psoc *psoc)
1617{
Liangwei Dong7ce41f12019-11-26 16:49:08 +08001618 uint32_t i, j;
Sandeep Puligillad763fee2019-11-08 14:00:10 -08001619 uint32_t min_freq, max_freq;
1620
1621 min_freq = wlan_reg_min_6ghz_chan_freq();
1622 max_freq = wlan_reg_max_6ghz_chan_freq();
1623
1624 scm_debug("min_freq %d max_freq %d", min_freq, max_freq);
Liangwei Dong7ce41f12019-11-26 16:49:08 +08001625 i = min_freq;
1626 for (j = 0; j < NUM_6GHZ_CHANNELS; j++) {
1627 if (i >= min_freq && i <= max_freq)
1628 rnr_channel_db.channel[j].chan_freq = i;
Sandeep Puligillad763fee2019-11-08 14:00:10 -08001629 qdf_list_create(&rnr_channel_db.channel[j].rnr_list,
1630 WLAN_MAX_RNR_COUNT);
1631 scm_debug("freq %d", i);
Liangwei Dong7ce41f12019-11-26 16:49:08 +08001632 i += 20;
Sandeep Puligillad763fee2019-11-08 14:00:10 -08001633 }
Sandeep Puligillad763fee2019-11-08 14:00:10 -08001634 return QDF_STATUS_SUCCESS;
1635}
1636
1637QDF_STATUS scm_channel_list_db_deinit(struct wlan_objmgr_psoc *psoc)
1638{
1639 int i;
1640 qdf_list_node_t *cur_node, *next_node;
1641 struct meta_rnr_channel *channel;
1642 struct scan_rnr_node *rnr_node;
1643
Liangwei Dong7ce41f12019-11-26 16:49:08 +08001644 for (i = 0; i < NUM_6GHZ_CHANNELS; i++) {
Sandeep Puligillad763fee2019-11-08 14:00:10 -08001645 channel = &rnr_channel_db.channel[i];
1646 channel->chan_freq = 0;
Liangwei Dong7ce41f12019-11-26 16:49:08 +08001647 cur_node = NULL;
Sandeep Puligillad763fee2019-11-08 14:00:10 -08001648 qdf_list_peek_front(&channel->rnr_list, &cur_node);
1649 while (cur_node) {
Liangwei Dong7ce41f12019-11-26 16:49:08 +08001650 next_node = NULL;
Sandeep Puligillad763fee2019-11-08 14:00:10 -08001651 qdf_list_peek_next(&channel->rnr_list, cur_node,
1652 &next_node);
1653 rnr_node = qdf_container_of(cur_node,
1654 struct scan_rnr_node,
1655 node);
1656 qdf_list_remove_node(&channel->rnr_list,
1657 &rnr_node->node);
1658 qdf_mem_free(rnr_node);
1659 cur_node = next_node;
1660 next_node = NULL;
1661 }
1662 }
1663
1664 return QDF_STATUS_SUCCESS;
1665}
1666#else
1667QDF_STATUS scm_channel_list_db_init(struct wlan_objmgr_psoc *psoc)
1668{
1669 return QDF_STATUS_SUCCESS;
1670}
1671
1672QDF_STATUS scm_channel_list_db_deinit(struct wlan_objmgr_psoc *psoc)
1673{
1674 return QDF_STATUS_SUCCESS;
1675}
1676#endif
1677
Om Prakash Tripathic3fcb682017-08-01 18:24:55 +05301678QDF_STATUS scm_update_scan_mlme_info(struct wlan_objmgr_pdev *pdev,
1679 struct scan_cache_entry *entry)
1680{
1681 uint8_t hash_idx;
1682 struct scan_dbs *scan_db;
1683 struct scan_cache_node *cur_node;
1684 struct scan_cache_node *next_node = NULL;
1685 struct wlan_objmgr_psoc *psoc;
1686
1687 psoc = wlan_pdev_get_psoc(pdev);
1688 if (!psoc) {
1689 scm_err("psoc is NULL");
1690 return QDF_STATUS_E_INVAL;
1691 }
1692 scan_db = wlan_pdev_get_scan_db(psoc, pdev);
1693 if (!scan_db) {
1694 scm_err("scan_db is NULL");
1695 return QDF_STATUS_E_INVAL;
1696 }
1697
1698 hash_idx = SCAN_GET_HASH(entry->bssid.bytes);
1699
1700 cur_node = scm_get_next_node(scan_db,
1701 &scan_db->scan_hash_tbl[hash_idx], NULL);
1702
1703 while (cur_node) {
1704 if (util_is_scan_entry_match(entry,
1705 cur_node->entry)) {
1706 /* Acquire db lock to prevent simultaneous update */
1707 qdf_spin_lock_bh(&scan_db->scan_db_lock);
1708 scm_update_mlme_info(entry, cur_node->entry);
1709 qdf_spin_unlock_bh(&scan_db->scan_db_lock);
1710 scm_scan_entry_put_ref(scan_db,
Amir Patel7c1a52c2018-03-02 16:33:04 +05301711 cur_node, true);
Om Prakash Tripathic3fcb682017-08-01 18:24:55 +05301712 return QDF_STATUS_SUCCESS;
1713 }
1714 next_node = scm_get_next_node(scan_db,
1715 &scan_db->scan_hash_tbl[hash_idx], cur_node);
1716 cur_node = next_node;
1717 }
1718
1719 return QDF_STATUS_E_INVAL;
1720}
Sandeep Puligillae062e822018-02-28 00:27:10 -08001721
1722QDF_STATUS scm_scan_update_mlme_by_bssinfo(struct wlan_objmgr_pdev *pdev,
1723 struct bss_info *bss_info, struct mlme_info *mlme)
1724{
1725 uint8_t hash_idx;
1726 struct scan_dbs *scan_db;
1727 struct scan_cache_node *cur_node;
1728 struct scan_cache_node *next_node = NULL;
1729 struct wlan_objmgr_psoc *psoc;
1730 struct scan_cache_entry *entry;
1731
1732 psoc = wlan_pdev_get_psoc(pdev);
1733 if (!psoc) {
1734 scm_err("psoc is NULL");
1735 return QDF_STATUS_E_INVAL;
1736 }
1737 scan_db = wlan_pdev_get_scan_db(psoc, pdev);
1738 if (!scan_db) {
1739 scm_err("scan_db is NULL");
1740 return QDF_STATUS_E_INVAL;
1741 }
1742
1743 hash_idx = SCAN_GET_HASH(bss_info->bssid.bytes);
1744 cur_node = scm_get_next_node(scan_db,
1745 &scan_db->scan_hash_tbl[hash_idx], NULL);
1746 while (cur_node) {
1747 entry = cur_node->entry;
1748 if (qdf_is_macaddr_equal(&bss_info->bssid, &entry->bssid) &&
1749 (util_is_ssid_match(&bss_info->ssid, &entry->ssid)) &&
tinlinaae613c2019-11-12 10:46:04 +08001750 (bss_info->freq == entry->channel.chan_freq)) {
Sandeep Puligillae062e822018-02-28 00:27:10 -08001751 /* Acquire db lock to prevent simultaneous update */
1752 qdf_spin_lock_bh(&scan_db->scan_db_lock);
1753 qdf_mem_copy(&entry->mlme_info, mlme,
1754 sizeof(struct mlme_info));
1755 scm_scan_entry_put_ref(scan_db,
1756 cur_node, false);
1757 qdf_spin_unlock_bh(&scan_db->scan_db_lock);
1758 return QDF_STATUS_SUCCESS;
1759 }
1760 next_node = scm_get_next_node(scan_db,
1761 &scan_db->scan_hash_tbl[hash_idx], cur_node);
1762 cur_node = next_node;
1763 }
1764
1765 return QDF_STATUS_E_INVAL;
1766}