1 /*
2 * Copyright (c) 2011-2021 The Linux Foundation. All rights reserved.
3 * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
4 *
5 * Permission to use, copy, modify, and/or distribute this software for
6 * any purpose with or without fee is hereby granted, provided that the
7 * above copyright notice and this permission notice appear in all
8 * copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
18 */
19 /**
20 * DOC: declare internal APIs related to the denylist component
21 */
22
23 #include <wlan_objmgr_pdev_obj.h>
24 #include <wlan_dlm_core.h>
25 #include <qdf_mc_timer.h>
26 #include <wlan_scan_public_structs.h>
27 #include <wlan_scan_utils_api.h>
28 #include "wlan_dlm_tgt_api.h"
29 #include <wlan_cm_bss_score_param.h>
30 #include <wlan_dlm_public_struct.h>
31
32 #define SECONDS_TO_MS(params) ((params) * 1000)
33 #define MINUTES_TO_MS(params) (SECONDS_TO_MS(params) * 60)
34 #define RSSI_TIMEOUT_VALUE 60
35
36 static void
dlm_update_ap_info(struct dlm_reject_ap * dlm_entry,struct dlm_config * cfg,struct scan_cache_entry * scan_entry)37 dlm_update_ap_info(struct dlm_reject_ap *dlm_entry, struct dlm_config *cfg,
38 struct scan_cache_entry *scan_entry)
39 {
40 qdf_time_t cur_timestamp = qdf_mc_timer_get_system_time();
41 qdf_time_t entry_add_time = 0;
42 bool update_done = false;
43 uint8_t old_reject_ap_type;
44
45 old_reject_ap_type = dlm_entry->reject_ap_type;
46
47 if (DLM_IS_AP_AVOIDED_BY_USERSPACE(dlm_entry)) {
48 entry_add_time =
49 dlm_entry->ap_timestamp.userspace_avoid_timestamp;
50
51 if ((cur_timestamp - entry_add_time) >=
52 MINUTES_TO_MS(cfg->avoid_list_exipry_time)) {
53 /* Move AP to monitor list as avoid list time is over */
54 dlm_entry->userspace_avoidlist = false;
55 dlm_entry->avoid_userspace = false;
56 dlm_entry->driver_monitorlist = true;
57
58 dlm_entry->ap_timestamp.driver_monitor_timestamp =
59 cur_timestamp;
60 dlm_debug("Userspace avoid list timer expired, moved to monitor list");
61 update_done = true;
62 }
63 }
64
65 if (DLM_IS_AP_AVOIDED_BY_DRIVER(dlm_entry)) {
66 entry_add_time = dlm_entry->ap_timestamp.driver_avoid_timestamp;
67
68 if ((cur_timestamp - entry_add_time) >=
69 MINUTES_TO_MS(cfg->avoid_list_exipry_time)) {
70 /* Move AP to monitor list as avoid list time is over */
71 dlm_entry->driver_avoidlist = false;
72 dlm_entry->nud_fail = false;
73 dlm_entry->sta_kickout = false;
74 dlm_entry->ho_fail = false;
75 dlm_entry->driver_monitorlist = true;
76
77 dlm_entry->ap_timestamp.driver_monitor_timestamp =
78 cur_timestamp;
79 dlm_debug("Driver avoid list timer expired, moved to monitor list");
80 update_done = true;
81 }
82 }
83
84 if (DLM_IS_AP_DENYLISTED_BY_DRIVER(dlm_entry)) {
85 entry_add_time =
86 dlm_entry->ap_timestamp.driver_denylist_timestamp;
87
88 if ((cur_timestamp - entry_add_time) >=
89 MINUTES_TO_MS(cfg->deny_list_exipry_time)) {
90 /* Move AP to monitor list as deny list time is over */
91 dlm_entry->driver_denylist = false;
92 dlm_entry->driver_monitorlist = true;
93 dlm_entry->nud_fail = false;
94 dlm_entry->sta_kickout = false;
95 dlm_entry->ho_fail = false;
96 dlm_entry->ap_timestamp.driver_monitor_timestamp =
97 cur_timestamp;
98 dlm_debug("Driver denylist timer expired, moved to monitor list");
99 update_done = true;
100 }
101 }
102
103 if (DLM_IS_AP_IN_RSSI_REJECT_LIST(dlm_entry)) {
104 qdf_time_t entry_age = cur_timestamp -
105 dlm_entry->ap_timestamp.rssi_reject_timestamp;
106
107 if ((dlm_entry->rssi_reject_params.retry_delay &&
108 entry_age >= dlm_entry->rssi_reject_params.retry_delay) ||
109 (scan_entry && scan_entry->rssi_raw >=
110 dlm_entry->rssi_reject_params.expected_rssi)) {
111 /*
112 * Remove from the rssi reject list as:-
113 * 1. In case of OCE reject, both the time, and RSSI
114 * param are present, and one of them have improved
115 * now, so the STA can now connect to the AP.
116 *
117 * 2. In case of BTM message received from the FW,
118 * the STA just needs to wait for a certain time,
119 * hence RSSI is not a restriction (MIN RSSI needed
120 * in that case is filled as 0).
121 * Hence the above check will still pass, if BTM
122 * delay is over, and will fail is not. RSSI check
123 * for BTM message will fail (expected), as BTM does
124 * not care about the same.
125 */
126 dlm_entry->poor_rssi = false;
127 dlm_entry->oce_assoc_reject = false;
128 dlm_entry->btm_bss_termination = false;
129 dlm_entry->btm_disassoc_imminent = false;
130 dlm_entry->btm_mbo_retry = false;
131 dlm_entry->no_more_stas = false;
132 dlm_entry->reassoc_rssi_reject = false;
133 dlm_entry->rssi_reject_list = false;
134 dlm_debug("Remove BSSID from rssi reject expected RSSI = %d, current RSSI = %d, retry delay required = %d ms, delay = %lu ms",
135 dlm_entry->rssi_reject_params.expected_rssi,
136 scan_entry ? scan_entry->rssi_raw : 0,
137 dlm_entry->rssi_reject_params.retry_delay,
138 entry_age);
139 update_done = true;
140 }
141 }
142
143 if (!update_done)
144 return;
145
146 dlm_debug(QDF_MAC_ADDR_FMT " Old %d Updated reject ap type = %x",
147 QDF_MAC_ADDR_REF(dlm_entry->bssid.bytes),
148 old_reject_ap_type,
149 dlm_entry->reject_ap_type);
150 }
151
152 #define MAX_BL_TIME 255000
153
154 static enum cm_denylist_action
dlm_prune_old_entries_and_get_action(struct dlm_reject_ap * dlm_entry,struct dlm_config * cfg,struct scan_cache_entry * entry,qdf_list_t * reject_ap_list)155 dlm_prune_old_entries_and_get_action(struct dlm_reject_ap *dlm_entry,
156 struct dlm_config *cfg,
157 struct scan_cache_entry *entry,
158 qdf_list_t *reject_ap_list)
159 {
160 dlm_update_ap_info(dlm_entry, cfg, entry);
161
162 /*
163 * If all entities have cleared the bits of reject ap type, then
164 * the AP is not needed in the database,(reject_ap_type should be 0),
165 * then remove the entry from the reject ap list.
166 */
167 if (!dlm_entry->reject_ap_type) {
168 dlm_debug(QDF_MAC_ADDR_FMT " cleared from list",
169 QDF_MAC_ADDR_REF(dlm_entry->bssid.bytes));
170 qdf_list_remove_node(reject_ap_list, &dlm_entry->node);
171 qdf_mem_free(dlm_entry);
172 return CM_DLM_NO_ACTION;
173 }
174
175 if (DLM_IS_AP_IN_RSSI_REJECT_LIST(dlm_entry) &&
176 !dlm_entry->userspace_denylist && !dlm_entry->driver_denylist &&
177 dlm_entry->rssi_reject_params.original_timeout > MAX_BL_TIME) {
178 dlm_info("Allow BSSID " QDF_MAC_ADDR_FMT " as the retry delay is greater than %u ms, expected RSSI = %d, current RSSI = %d, retry delay = %u ms original timeout %u time added %lu source %d reason %d",
179 QDF_MAC_ADDR_REF(dlm_entry->bssid.bytes), MAX_BL_TIME,
180 dlm_entry->rssi_reject_params.expected_rssi,
181 entry ? entry->rssi_raw : 0,
182 dlm_entry->rssi_reject_params.retry_delay,
183 dlm_entry->rssi_reject_params.original_timeout,
184 dlm_entry->rssi_reject_params.received_time,
185 dlm_entry->source, dlm_entry->reject_ap_reason);
186
187 if (DLM_IS_AP_IN_AVOIDLIST(dlm_entry)) {
188 dlm_debug(QDF_MAC_ADDR_FMT " in avoid list, deprioritize it",
189 QDF_MAC_ADDR_REF(dlm_entry->bssid.bytes));
190 return CM_DLM_AVOID;
191 }
192
193 return CM_DLM_NO_ACTION;
194 }
195 if (DLM_IS_AP_IN_DENYLIST(dlm_entry)) {
196 dlm_debug(QDF_MAC_ADDR_FMT " in denylist list, reject ap type %d removing from candidate list",
197 QDF_MAC_ADDR_REF(dlm_entry->bssid.bytes),
198 dlm_entry->reject_ap_type);
199
200 if (DLM_IS_AP_DENYLISTED_BY_USERSPACE(dlm_entry) ||
201 DLM_IS_AP_IN_RSSI_REJECT_LIST(dlm_entry)) {
202 if (dlm_entry->reject_ap_reason == REASON_UNKNOWN ||
203 dlm_entry->reject_ap_reason == REASON_NUD_FAILURE ||
204 dlm_entry->reject_ap_reason == REASON_STA_KICKOUT ||
205 dlm_entry->reject_ap_reason == REASON_ROAM_HO_FAILURE)
206 return CM_DLM_REMOVE;
207 else
208 return CM_DLM_FORCE_REMOVE;
209 }
210
211 return CM_DLM_REMOVE;
212 }
213
214 if (DLM_IS_AP_IN_AVOIDLIST(dlm_entry)) {
215 dlm_debug(QDF_MAC_ADDR_FMT " in avoid list, deprioritize it",
216 QDF_MAC_ADDR_REF(dlm_entry->bssid.bytes));
217 return CM_DLM_AVOID;
218 }
219
220 return CM_DLM_NO_ACTION;
221 }
222
223 static enum cm_denylist_action
dlm_action_on_bssid(struct wlan_objmgr_pdev * pdev,struct scan_cache_entry * entry)224 dlm_action_on_bssid(struct wlan_objmgr_pdev *pdev,
225 struct scan_cache_entry *entry)
226 {
227 struct dlm_pdev_priv_obj *dlm_ctx;
228 struct dlm_psoc_priv_obj *dlm_psoc_obj;
229 struct dlm_config *cfg;
230 struct dlm_reject_ap *dlm_entry = NULL;
231 qdf_list_node_t *cur_node = NULL, *next_node = NULL;
232 QDF_STATUS status;
233 enum cm_denylist_action action = CM_DLM_NO_ACTION;
234
235 dlm_ctx = dlm_get_pdev_obj(pdev);
236 dlm_psoc_obj = dlm_get_psoc_obj(wlan_pdev_get_psoc(pdev));
237 if (!dlm_ctx || !dlm_psoc_obj) {
238 dlm_err("dlm_ctx or dlm_psoc_obj is NULL");
239 return CM_DLM_NO_ACTION;
240 }
241
242 status = qdf_mutex_acquire(&dlm_ctx->reject_ap_list_lock);
243 if (QDF_IS_STATUS_ERROR(status)) {
244 dlm_err("failed to acquire reject_ap_list_lock");
245 return CM_DLM_NO_ACTION;
246 }
247
248 cfg = &dlm_psoc_obj->dlm_cfg;
249
250 qdf_list_peek_front(&dlm_ctx->reject_ap_list, &cur_node);
251
252 while (cur_node) {
253 qdf_list_peek_next(&dlm_ctx->reject_ap_list, cur_node,
254 &next_node);
255
256 dlm_entry = qdf_container_of(cur_node, struct dlm_reject_ap,
257 node);
258
259 if (qdf_is_macaddr_equal(&dlm_entry->bssid, &entry->bssid)) {
260 action = dlm_prune_old_entries_and_get_action(dlm_entry,
261 cfg, entry, &dlm_ctx->reject_ap_list);
262 qdf_mutex_release(&dlm_ctx->reject_ap_list_lock);
263 return action;
264 }
265 cur_node = next_node;
266 next_node = NULL;
267 }
268 qdf_mutex_release(&dlm_ctx->reject_ap_list_lock);
269
270 return CM_DLM_NO_ACTION;
271 }
272
273 enum cm_denylist_action
wlan_denylist_action_on_bssid(struct wlan_objmgr_pdev * pdev,struct scan_cache_entry * entry)274 wlan_denylist_action_on_bssid(struct wlan_objmgr_pdev *pdev,
275 struct scan_cache_entry *entry)
276 {
277 return dlm_action_on_bssid(pdev, entry);
278 }
279
280 static void
dlm_update_avoidlist_reject_reason(struct dlm_reject_ap * entry,enum dlm_reject_ap_reason reject_reason)281 dlm_update_avoidlist_reject_reason(struct dlm_reject_ap *entry,
282 enum dlm_reject_ap_reason reject_reason)
283 {
284 entry->nud_fail = false;
285 entry->sta_kickout = false;
286 entry->ho_fail = false;
287
288 switch (reject_reason) {
289 case REASON_NUD_FAILURE:
290 entry->nud_fail = true;
291 break;
292 case REASON_STA_KICKOUT:
293 entry->sta_kickout = true;
294 break;
295 case REASON_ROAM_HO_FAILURE:
296 entry->ho_fail = true;
297 break;
298 default:
299 dlm_err("Invalid reason passed %d", reject_reason);
300 }
301 }
302
303 static void
dlm_handle_avoid_list(struct dlm_reject_ap * entry,struct dlm_config * cfg,struct reject_ap_info * ap_info)304 dlm_handle_avoid_list(struct dlm_reject_ap *entry,
305 struct dlm_config *cfg,
306 struct reject_ap_info *ap_info)
307 {
308 qdf_time_t cur_timestamp = qdf_mc_timer_get_system_time();
309
310 if (ap_info->reject_ap_type == USERSPACE_AVOID_TYPE) {
311 entry->userspace_avoidlist = true;
312 entry->avoid_userspace = true;
313 entry->ap_timestamp.userspace_avoid_timestamp = cur_timestamp;
314 } else if (ap_info->reject_ap_type == DRIVER_AVOID_TYPE) {
315 entry->driver_avoidlist = true;
316 dlm_update_avoidlist_reject_reason(entry,
317 ap_info->reject_reason);
318 entry->ap_timestamp.driver_avoid_timestamp = cur_timestamp;
319 } else {
320 return;
321 }
322 entry->source = ap_info->source;
323 /* Update bssid info for new entry */
324 entry->bssid = ap_info->bssid;
325
326 /* Clear the monitor list bit if the AP was present in monitor list */
327 entry->driver_monitorlist = false;
328
329 /* Increment bad bssid counter as NUD failure happenend with this ap */
330 entry->bad_bssid_counter++;
331
332 /* If bad bssid counter has reached threshold, move it to denylist */
333 if (entry->bad_bssid_counter >= cfg->bad_bssid_counter_thresh) {
334 if (ap_info->reject_ap_type == USERSPACE_AVOID_TYPE)
335 entry->userspace_avoidlist = false;
336 else if (ap_info->reject_ap_type == DRIVER_AVOID_TYPE)
337 entry->driver_avoidlist = false;
338
339 /* Move AP to denylist list */
340 entry->driver_denylist = true;
341 entry->ap_timestamp.driver_denylist_timestamp = cur_timestamp;
342
343 dlm_debug(QDF_MAC_ADDR_FMT " moved to deny list with counter %d",
344 QDF_MAC_ADDR_REF(entry->bssid.bytes),
345 entry->bad_bssid_counter);
346 return;
347 }
348 dlm_debug("Added " QDF_MAC_ADDR_FMT " to avoid list type %d, counter %d reason %d updated reject reason %d source %d",
349 QDF_MAC_ADDR_REF(entry->bssid.bytes), ap_info->reject_ap_type,
350 entry->bad_bssid_counter, ap_info->reject_reason,
351 entry->reject_ap_reason, entry->source);
352
353 entry->connect_timestamp = qdf_mc_timer_get_system_time();
354 }
355
356 static void
dlm_handle_denylist(struct dlm_reject_ap * entry,struct reject_ap_info * ap_info)357 dlm_handle_denylist(struct dlm_reject_ap *entry,
358 struct reject_ap_info *ap_info)
359 {
360 /*
361 * No entity will denylist an AP internal to driver, so only
362 * userspace denylist is the case to be taken care. Driver denylist
363 * will only happen when the bad bssid counter has reached the max
364 * threshold.
365 */
366 entry->bssid = ap_info->bssid;
367 entry->userspace_denylist = true;
368 entry->ap_timestamp.userspace_denylist_timestamp =
369 qdf_mc_timer_get_system_time();
370
371 entry->source = ADDED_BY_DRIVER;
372 entry->denylist_userspace = true;
373 dlm_debug(QDF_MAC_ADDR_FMT " added to userspace denylist",
374 QDF_MAC_ADDR_REF(entry->bssid.bytes));
375 }
376
377 static void
dlm_update_rssi_reject_reason(struct dlm_reject_ap * entry,enum dlm_reject_ap_reason reject_reason)378 dlm_update_rssi_reject_reason(struct dlm_reject_ap *entry,
379 enum dlm_reject_ap_reason reject_reason)
380 {
381 entry->poor_rssi = false;
382 entry->oce_assoc_reject = false;
383 entry->btm_bss_termination = false;
384 entry->btm_disassoc_imminent = false;
385 entry->btm_mbo_retry = false;
386 entry->no_more_stas = false;
387 entry->reassoc_rssi_reject = false;
388
389 switch (reject_reason) {
390 case REASON_ASSOC_REJECT_POOR_RSSI:
391 entry->poor_rssi = true;
392 break;
393 case REASON_ASSOC_REJECT_OCE:
394 entry->oce_assoc_reject = true;
395 break;
396 case REASON_BTM_DISASSOC_IMMINENT:
397 entry->btm_disassoc_imminent = true;
398 break;
399 case REASON_BTM_BSS_TERMINATION:
400 entry->btm_bss_termination = true;
401 break;
402 case REASON_BTM_MBO_RETRY:
403 entry->btm_mbo_retry = true;
404 break;
405 case REASON_REASSOC_RSSI_REJECT:
406 entry->reassoc_rssi_reject = true;
407 break;
408 case REASON_REASSOC_NO_MORE_STAS:
409 entry->no_more_stas = true;
410 break;
411 default:
412 dlm_err("Invalid reason passed %d", reject_reason);
413 }
414 }
415
416 static void
dlm_handle_rssi_reject_list(struct dlm_reject_ap * entry,struct reject_ap_info * ap_info)417 dlm_handle_rssi_reject_list(struct dlm_reject_ap *entry,
418 struct reject_ap_info *ap_info)
419 {
420 bool bssid_newly_added;
421
422 if (entry->rssi_reject_list) {
423 bssid_newly_added = false;
424 } else {
425 entry->rssi_reject_params.source = ap_info->source;
426 entry->bssid = ap_info->bssid;
427 entry->rssi_reject_list = true;
428 bssid_newly_added = true;
429 }
430
431 entry->ap_timestamp.rssi_reject_timestamp =
432 qdf_mc_timer_get_system_time();
433 entry->rssi_reject_params = ap_info->rssi_reject_params;
434 dlm_update_rssi_reject_reason(entry, ap_info->reject_reason);
435 dlm_info(QDF_MAC_ADDR_FMT " %s to rssi reject list, expected RSSI %d retry delay %u source %d original timeout %u received time %lu reject reason %d updated reason %d",
436 QDF_MAC_ADDR_REF(entry->bssid.bytes),
437 bssid_newly_added ? "ADDED" : "UPDATED",
438 entry->rssi_reject_params.expected_rssi,
439 entry->rssi_reject_params.retry_delay,
440 entry->rssi_reject_params.source,
441 entry->rssi_reject_params.original_timeout,
442 entry->rssi_reject_params.received_time,
443 ap_info->reject_reason, entry->reject_ap_reason);
444 }
445
446 static void
dlm_modify_entry(struct dlm_reject_ap * entry,struct dlm_config * cfg,struct reject_ap_info * ap_info)447 dlm_modify_entry(struct dlm_reject_ap *entry, struct dlm_config *cfg,
448 struct reject_ap_info *ap_info)
449 {
450 /* Modify the entry according to the ap_info */
451 switch (ap_info->reject_ap_type) {
452 case USERSPACE_AVOID_TYPE:
453 case DRIVER_AVOID_TYPE:
454 dlm_handle_avoid_list(entry, cfg, ap_info);
455 break;
456 case USERSPACE_DENYLIST_TYPE:
457 dlm_handle_denylist(entry, ap_info);
458 break;
459 case DRIVER_RSSI_REJECT_TYPE:
460 dlm_handle_rssi_reject_list(entry, ap_info);
461 break;
462 default:
463 dlm_debug("Invalid input of ap type %d",
464 ap_info->reject_ap_type);
465 }
466 }
467
468 static bool
dlm_is_bssid_present_only_in_list_type(enum dlm_reject_ap_type list_type,struct dlm_reject_ap * dlm_entry)469 dlm_is_bssid_present_only_in_list_type(enum dlm_reject_ap_type list_type,
470 struct dlm_reject_ap *dlm_entry)
471 {
472 switch (list_type) {
473 case USERSPACE_AVOID_TYPE:
474 return IS_AP_IN_USERSPACE_AVOID_LIST_ONLY(dlm_entry);
475 case USERSPACE_DENYLIST_TYPE:
476 return IS_AP_IN_USERSPACE_DENYLIST_ONLY(dlm_entry);
477 case DRIVER_AVOID_TYPE:
478 return IS_AP_IN_DRIVER_AVOID_LIST_ONLY(dlm_entry);
479 case DRIVER_DENYLIST_TYPE:
480 return IS_AP_IN_DRIVER_DENYLIST_ONLY(dlm_entry);
481 case DRIVER_RSSI_REJECT_TYPE:
482 return IS_AP_IN_RSSI_REJECT_LIST_ONLY(dlm_entry);
483 case DRIVER_MONITOR_TYPE:
484 return IS_AP_IN_MONITOR_LIST_ONLY(dlm_entry);
485 default:
486 dlm_debug("Wrong list type %d passed", list_type);
487 return false;
488 }
489 }
490
491 static bool
dlm_is_bssid_of_type(enum dlm_reject_ap_type reject_ap_type,struct dlm_reject_ap * dlm_entry)492 dlm_is_bssid_of_type(enum dlm_reject_ap_type reject_ap_type,
493 struct dlm_reject_ap *dlm_entry)
494 {
495 switch (reject_ap_type) {
496 case USERSPACE_AVOID_TYPE:
497 return DLM_IS_AP_AVOIDED_BY_USERSPACE(dlm_entry);
498 case USERSPACE_DENYLIST_TYPE:
499 return DLM_IS_AP_DENYLISTED_BY_USERSPACE(dlm_entry);
500 case DRIVER_AVOID_TYPE:
501 return DLM_IS_AP_AVOIDED_BY_DRIVER(dlm_entry);
502 case DRIVER_DENYLIST_TYPE:
503 return DLM_IS_AP_DENYLISTED_BY_DRIVER(dlm_entry);
504 case DRIVER_RSSI_REJECT_TYPE:
505 return DLM_IS_AP_IN_RSSI_REJECT_LIST(dlm_entry);
506 case DRIVER_MONITOR_TYPE:
507 return DLM_IS_AP_IN_MONITOR_LIST(dlm_entry);
508 default:
509 dlm_err("Wrong list type %d passed", reject_ap_type);
510 return false;
511 }
512 }
513
514 static qdf_time_t
dlm_get_delta_of_bssid(enum dlm_reject_ap_type list_type,struct dlm_reject_ap * dlm_entry,struct dlm_config * cfg)515 dlm_get_delta_of_bssid(enum dlm_reject_ap_type list_type,
516 struct dlm_reject_ap *dlm_entry,
517 struct dlm_config *cfg)
518 {
519 qdf_time_t cur_timestamp = qdf_mc_timer_get_system_time();
520 int32_t disallowed_time;
521 /*
522 * For all the list types, delta would be the entry age only. Hence the
523 * oldest entry would be removed first in case of list is full, and the
524 * driver needs to make space for newer entries.
525 */
526
527 switch (list_type) {
528 case USERSPACE_AVOID_TYPE:
529 return MINUTES_TO_MS(cfg->avoid_list_exipry_time) -
530 (cur_timestamp -
531 dlm_entry->ap_timestamp.userspace_avoid_timestamp);
532 case USERSPACE_DENYLIST_TYPE:
533 return cur_timestamp -
534 dlm_entry->ap_timestamp.userspace_denylist_timestamp;
535 case DRIVER_AVOID_TYPE:
536 return MINUTES_TO_MS(cfg->avoid_list_exipry_time) -
537 (cur_timestamp -
538 dlm_entry->ap_timestamp.driver_avoid_timestamp);
539 case DRIVER_DENYLIST_TYPE:
540 return MINUTES_TO_MS(cfg->deny_list_exipry_time) -
541 (cur_timestamp -
542 dlm_entry->ap_timestamp.driver_denylist_timestamp);
543
544 /*
545 * For RSSI reject lowest delta would be the BSSID whose retry delay
546 * is about to expire, hence the delta would be remaining duration for
547 * de-denylisting the AP from rssi reject list.
548 */
549 case DRIVER_RSSI_REJECT_TYPE:
550 if (dlm_entry->rssi_reject_params.retry_delay)
551 disallowed_time =
552 dlm_entry->rssi_reject_params.retry_delay -
553 (cur_timestamp -
554 dlm_entry->ap_timestamp.rssi_reject_timestamp);
555 else
556 disallowed_time =
557 (int32_t)(MINUTES_TO_MS(RSSI_TIMEOUT_VALUE) -
558 (cur_timestamp -
559 dlm_entry->ap_timestamp.rssi_reject_timestamp)
560 );
561 return ((disallowed_time < 0) ? 0 : disallowed_time);
562 case DRIVER_MONITOR_TYPE:
563 return cur_timestamp -
564 dlm_entry->ap_timestamp.driver_monitor_timestamp;
565 default:
566 dlm_debug("Wrong list type %d passed", list_type);
567 return 0;
568 }
569 }
570
571 static bool
dlm_is_oldest_entry(enum dlm_reject_ap_type list_type,qdf_time_t cur_node_delta,qdf_time_t oldest_node_delta)572 dlm_is_oldest_entry(enum dlm_reject_ap_type list_type,
573 qdf_time_t cur_node_delta,
574 qdf_time_t oldest_node_delta)
575 {
576 switch (list_type) {
577 /*
578 * For RSSI reject, userspace avoid, driver avoid/denylist type the
579 * lowest retry delay has to be found out hence if oldest_node_delta is
580 * 0, mean this is the first entry and thus return true, If
581 * oldest_node_delta is non zero, compare the delta and return true if
582 * the cur entry has lower retry delta.
583 */
584 case DRIVER_RSSI_REJECT_TYPE:
585 case USERSPACE_AVOID_TYPE:
586 case DRIVER_AVOID_TYPE:
587 case DRIVER_DENYLIST_TYPE:
588 if (!oldest_node_delta || cur_node_delta < oldest_node_delta)
589 return true;
590 break;
591 case USERSPACE_DENYLIST_TYPE:
592 case DRIVER_MONITOR_TYPE:
593 if (cur_node_delta > oldest_node_delta)
594 return true;
595 break;
596 default:
597 dlm_debug("Wrong list type passed %d", list_type);
598 return false;
599 }
600
601 return false;
602 }
603
604 static QDF_STATUS
dlm_try_delete_bssid_in_list(qdf_list_t * reject_ap_list,enum dlm_reject_ap_type list_type,struct dlm_config * cfg)605 dlm_try_delete_bssid_in_list(qdf_list_t *reject_ap_list,
606 enum dlm_reject_ap_type list_type,
607 struct dlm_config *cfg)
608 {
609 struct dlm_reject_ap *dlm_entry = NULL;
610 qdf_list_node_t *cur_node = NULL, *next_node = NULL;
611 struct dlm_reject_ap *oldest_dlm_entry = NULL;
612 qdf_time_t oldest_node_delta = 0;
613 qdf_time_t cur_node_delta = 0;
614
615 qdf_list_peek_front(reject_ap_list, &cur_node);
616
617 while (cur_node) {
618 qdf_list_peek_next(reject_ap_list, cur_node, &next_node);
619
620 dlm_entry = qdf_container_of(cur_node, struct dlm_reject_ap,
621 node);
622
623 if (dlm_is_bssid_present_only_in_list_type(list_type,
624 dlm_entry)) {
625 cur_node_delta = dlm_get_delta_of_bssid(list_type,
626 dlm_entry, cfg);
627
628 if (dlm_is_oldest_entry(list_type, cur_node_delta,
629 oldest_node_delta)) {
630 /* now this is the oldest entry*/
631 oldest_dlm_entry = dlm_entry;
632 oldest_node_delta = cur_node_delta;
633 }
634 }
635 cur_node = next_node;
636 next_node = NULL;
637 }
638
639 if (oldest_dlm_entry) {
640 /* Remove this entry to make space for the next entry */
641 dlm_debug("Removed " QDF_MAC_ADDR_FMT ", type = %d",
642 QDF_MAC_ADDR_REF(oldest_dlm_entry->bssid.bytes),
643 list_type);
644 qdf_list_remove_node(reject_ap_list, &oldest_dlm_entry->node);
645 qdf_mem_free(oldest_dlm_entry);
646 return QDF_STATUS_SUCCESS;
647 }
648 /* If the flow has reached here, that means no entry could be removed */
649
650 return QDF_STATUS_E_FAILURE;
651 }
652
653 static QDF_STATUS
dlm_remove_lowest_delta_entry(qdf_list_t * reject_ap_list,struct dlm_config * cfg)654 dlm_remove_lowest_delta_entry(qdf_list_t *reject_ap_list,
655 struct dlm_config *cfg)
656 {
657 QDF_STATUS status;
658
659 /*
660 * According to the Priority, the driver will try to remove the entries,
661 * as the least priority list, that is monitor list would not penalize
662 * the BSSIDs for connection. The priority order for the removal is:-
663 * 1. Monitor list
664 * 2. Driver avoid list
665 * 3. Userspace avoid list.
666 * 4. RSSI reject list.
667 * 5. Driver Denylist.
668 * 6. Userspace Denylist.
669 */
670
671 status = dlm_try_delete_bssid_in_list(reject_ap_list,
672 DRIVER_MONITOR_TYPE, cfg);
673 if (QDF_IS_STATUS_SUCCESS(status))
674 return QDF_STATUS_SUCCESS;
675
676 status = dlm_try_delete_bssid_in_list(reject_ap_list,
677 DRIVER_AVOID_TYPE, cfg);
678 if (QDF_IS_STATUS_SUCCESS(status))
679 return QDF_STATUS_SUCCESS;
680
681 status = dlm_try_delete_bssid_in_list(reject_ap_list,
682 USERSPACE_AVOID_TYPE, cfg);
683 if (QDF_IS_STATUS_SUCCESS(status))
684 return QDF_STATUS_SUCCESS;
685
686 status = dlm_try_delete_bssid_in_list(reject_ap_list,
687 DRIVER_RSSI_REJECT_TYPE, cfg);
688 if (QDF_IS_STATUS_SUCCESS(status))
689 return QDF_STATUS_SUCCESS;
690
691 status = dlm_try_delete_bssid_in_list(reject_ap_list,
692 DRIVER_DENYLIST_TYPE, cfg);
693 if (QDF_IS_STATUS_SUCCESS(status))
694 return QDF_STATUS_SUCCESS;
695
696 status = dlm_try_delete_bssid_in_list(reject_ap_list,
697 USERSPACE_DENYLIST_TYPE, cfg);
698 if (QDF_IS_STATUS_SUCCESS(status))
699 return QDF_STATUS_SUCCESS;
700
701 dlm_debug("Failed to remove AP from denylist manager");
702
703 return QDF_STATUS_E_FAILURE;
704 }
705
706 static enum dlm_reject_ap_reason
dlm_get_rssi_reject_reason(struct dlm_reject_ap * dlm_entry)707 dlm_get_rssi_reject_reason(struct dlm_reject_ap *dlm_entry)
708 {
709 if (dlm_entry->poor_rssi)
710 return REASON_ASSOC_REJECT_POOR_RSSI;
711 else if (dlm_entry->oce_assoc_reject)
712 return REASON_ASSOC_REJECT_OCE;
713 else if (dlm_entry->btm_bss_termination)
714 return REASON_BTM_BSS_TERMINATION;
715 else if (dlm_entry->btm_disassoc_imminent)
716 return REASON_BTM_DISASSOC_IMMINENT;
717 else if (dlm_entry->btm_mbo_retry)
718 return REASON_BTM_MBO_RETRY;
719 else if (dlm_entry->no_more_stas)
720 return REASON_REASSOC_NO_MORE_STAS;
721 else if (dlm_entry->reassoc_rssi_reject)
722 return REASON_REASSOC_RSSI_REJECT;
723
724 return REASON_UNKNOWN;
725 }
726
727 static void
dlm_fill_rssi_reject_params(struct dlm_reject_ap * dlm_entry,enum dlm_reject_ap_type reject_ap_type,struct reject_ap_config_params * dlm_reject_list)728 dlm_fill_rssi_reject_params(struct dlm_reject_ap *dlm_entry,
729 enum dlm_reject_ap_type reject_ap_type,
730 struct reject_ap_config_params *dlm_reject_list)
731 {
732 if (reject_ap_type != DRIVER_RSSI_REJECT_TYPE)
733 return;
734
735 dlm_reject_list->source = dlm_entry->rssi_reject_params.source;
736 dlm_reject_list->original_timeout =
737 dlm_entry->rssi_reject_params.original_timeout;
738 dlm_reject_list->received_time =
739 dlm_entry->rssi_reject_params.received_time;
740 dlm_reject_list->reject_reason = dlm_get_rssi_reject_reason(dlm_entry);
741 dlm_debug(QDF_MAC_ADDR_FMT " source %d original timeout %u received time %lu reject reason %d",
742 QDF_MAC_ADDR_REF(dlm_entry->bssid.bytes),
743 dlm_reject_list->source,
744 dlm_reject_list->original_timeout,
745 dlm_reject_list->received_time,
746 dlm_reject_list->reject_reason);
747 }
748
749 /**
750 * dlm_find_reject_type_string() - Function to convert int to string
751 * @reject_ap_type: dlm_reject_ap_type
752 *
753 * This function is used to convert int value of enum dlm_reject_ap_type
754 * to string format.
755 *
756 * Return: String
757 *
758 */
759 static const char *
dlm_find_reject_type_string(enum dlm_reject_ap_type reject_ap_type)760 dlm_find_reject_type_string(enum dlm_reject_ap_type reject_ap_type)
761 {
762 switch (reject_ap_type) {
763 CASE_RETURN_STRING(USERSPACE_AVOID_TYPE);
764 CASE_RETURN_STRING(USERSPACE_DENYLIST_TYPE);
765 CASE_RETURN_STRING(DRIVER_AVOID_TYPE);
766 CASE_RETURN_STRING(DRIVER_DENYLIST_TYPE);
767 CASE_RETURN_STRING(DRIVER_RSSI_REJECT_TYPE);
768 CASE_RETURN_STRING(DRIVER_MONITOR_TYPE);
769 default:
770 return "REJECT_REASON_UNKNOWN";
771 }
772 }
773
774 /**
775 * dlm_get_reject_ap_type() - Function to find reject ap type
776 * @dlm_entry: dlm_reject_ap
777 *
778 * This function is used to get reject ap type.
779 *
780 * Return: dlm_reject_ap_type
781 *
782 */
783 static enum dlm_reject_ap_type
dlm_get_reject_ap_type(struct dlm_reject_ap * dlm_entry)784 dlm_get_reject_ap_type(struct dlm_reject_ap *dlm_entry)
785 {
786 if (DLM_IS_AP_AVOIDED_BY_USERSPACE(dlm_entry))
787 return USERSPACE_AVOID_TYPE;
788 if (DLM_IS_AP_DENYLISTED_BY_USERSPACE(dlm_entry))
789 return USERSPACE_DENYLIST_TYPE;
790 if (DLM_IS_AP_AVOIDED_BY_DRIVER(dlm_entry))
791 return DRIVER_AVOID_TYPE;
792 if (DLM_IS_AP_DENYLISTED_BY_DRIVER(dlm_entry))
793 return DRIVER_DENYLIST_TYPE;
794 if (DLM_IS_AP_IN_RSSI_REJECT_LIST(dlm_entry))
795 return DRIVER_RSSI_REJECT_TYPE;
796 if (DLM_IS_AP_IN_MONITOR_LIST(dlm_entry))
797 return DRIVER_MONITOR_TYPE;
798
799 return REJECT_REASON_UNKNOWN;
800 }
801
dlm_is_bssid_in_reject_list(struct wlan_objmgr_pdev * pdev,struct qdf_mac_addr * bssid)802 bool dlm_is_bssid_in_reject_list(struct wlan_objmgr_pdev *pdev,
803 struct qdf_mac_addr *bssid)
804 {
805 struct dlm_pdev_priv_obj *dlm_ctx;
806 struct dlm_psoc_priv_obj *dlm_psoc_obj;
807 struct dlm_reject_ap *dlm_entry = NULL;
808 qdf_list_node_t *cur_node = NULL, *next_node = NULL;
809 QDF_STATUS status;
810
811 dlm_ctx = dlm_get_pdev_obj(pdev);
812 if (!dlm_ctx) {
813 dlm_err("dlm_ctx is NULL");
814 return false;
815 }
816 dlm_psoc_obj = dlm_get_psoc_obj(wlan_pdev_get_psoc(pdev));
817 if (!dlm_psoc_obj) {
818 dlm_err("dlm_ctx or dlm_psoc_obj is NULL");
819 return false;
820 }
821
822 status = qdf_mutex_acquire(&dlm_ctx->reject_ap_list_lock);
823 if (QDF_IS_STATUS_ERROR(status)) {
824 dlm_err("failed to acquire reject_ap_list_lock");
825 return false;
826 }
827
828 qdf_list_peek_front(&dlm_ctx->reject_ap_list, &cur_node);
829 while (cur_node) {
830 qdf_list_peek_next(&dlm_ctx->reject_ap_list, cur_node,
831 &next_node);
832 dlm_entry =
833 qdf_container_of(cur_node, struct dlm_reject_ap, node);
834 /* Update the AP info to the latest list first */
835 dlm_update_ap_info(dlm_entry, &dlm_psoc_obj->dlm_cfg, NULL);
836 if (!dlm_entry->reject_ap_type) {
837 dlm_debug(QDF_MAC_ADDR_FMT " cleared from list",
838 QDF_MAC_ADDR_REF(dlm_entry->bssid.bytes));
839 qdf_list_remove_node(&dlm_ctx->reject_ap_list,
840 &dlm_entry->node);
841 qdf_mem_free(dlm_entry);
842 cur_node = next_node;
843 next_node = NULL;
844 continue;
845 }
846
847 if (qdf_is_macaddr_equal(&dlm_entry->bssid, bssid)) {
848 dlm_debug("BSSID reject_ap_type 0x%x",
849 dlm_entry->reject_ap_type);
850 if (DLM_IS_AP_IN_DENYLIST(dlm_entry)) {
851 dlm_debug("BSSID is present in deny list");
852 qdf_mutex_release(
853 &dlm_ctx->reject_ap_list_lock);
854 return true;
855 }
856 qdf_mutex_release(
857 &dlm_ctx->reject_ap_list_lock);
858 return false;
859 }
860 cur_node = next_node;
861 next_node = NULL;
862 }
863
864 qdf_mutex_release(&dlm_ctx->reject_ap_list_lock);
865
866 return false;
867 }
868
869 /**
870 * dlm_dump_denylist_bssid() - Function to dump denylisted bssid
871 * @pdev: pdev object
872 *
873 * This function is used to dump denylisted bssid along with reject
874 * ap type, source, delay and required rssi
875 *
876 * Return: None
877 *
878 */
dlm_dump_denylist_bssid(struct wlan_objmgr_pdev * pdev)879 void dlm_dump_denylist_bssid(struct wlan_objmgr_pdev *pdev)
880 {
881 struct dlm_reject_ap *dlm_entry = NULL;
882 qdf_list_node_t *cur_node = NULL, *next_node = NULL;
883 struct dlm_pdev_priv_obj *dlm_ctx;
884 struct dlm_psoc_priv_obj *dlm_psoc_obj;
885 uint32_t reject_duration;
886 enum dlm_reject_ap_type reject_ap_type;
887 qdf_list_t *reject_db_list;
888 QDF_STATUS status;
889
890 dlm_ctx = dlm_get_pdev_obj(pdev);
891 dlm_psoc_obj = dlm_get_psoc_obj(wlan_pdev_get_psoc(pdev));
892
893 if (!dlm_ctx || !dlm_psoc_obj) {
894 dlm_err("dlm_ctx or dlm_psoc_obj is NULL");
895 return;
896 }
897
898 status = qdf_mutex_acquire(&dlm_ctx->reject_ap_list_lock);
899 if (QDF_IS_STATUS_ERROR(status)) {
900 dlm_err("failed to acquire reject_ap_list_lock");
901 return;
902 }
903
904 reject_db_list = &dlm_ctx->reject_ap_list;
905 qdf_list_peek_front(reject_db_list, &cur_node);
906 while (cur_node) {
907 qdf_list_peek_next(reject_db_list, cur_node, &next_node);
908
909 dlm_entry = qdf_container_of(cur_node, struct dlm_reject_ap,
910 node);
911
912 reject_ap_type = dlm_get_reject_ap_type(dlm_entry);
913
914 reject_duration = dlm_get_delta_of_bssid(reject_ap_type,
915 dlm_entry,
916 &dlm_psoc_obj->dlm_cfg);
917
918 dlm_nofl_debug("DENYLIST BSSID " QDF_MAC_ADDR_FMT " type %s retry delay %dms expected RSSI %d reject reason %d rejection source %d",
919 QDF_MAC_ADDR_REF(dlm_entry->bssid.bytes),
920 dlm_find_reject_type_string(reject_ap_type),
921 reject_duration,
922 dlm_entry->rssi_reject_params.expected_rssi,
923 dlm_entry->reject_ap_reason,
924 dlm_entry->rssi_reject_params.source);
925 cur_node = next_node;
926 next_node = NULL;
927 }
928
929 qdf_mutex_release(&dlm_ctx->reject_ap_list_lock);
930 }
931
dlm_fill_reject_list(qdf_list_t * reject_db_list,struct reject_ap_config_params * reject_list,uint8_t * num_of_reject_bssid,enum dlm_reject_ap_type reject_ap_type,uint8_t max_bssid_to_be_filled,struct dlm_config * cfg)932 static void dlm_fill_reject_list(qdf_list_t *reject_db_list,
933 struct reject_ap_config_params *reject_list,
934 uint8_t *num_of_reject_bssid,
935 enum dlm_reject_ap_type reject_ap_type,
936 uint8_t max_bssid_to_be_filled,
937 struct dlm_config *cfg)
938 {
939 struct dlm_reject_ap *dlm_entry = NULL;
940 qdf_list_node_t *cur_node = NULL, *next_node = NULL;
941
942 qdf_list_peek_front(reject_db_list, &cur_node);
943 while (cur_node) {
944 if (*num_of_reject_bssid == max_bssid_to_be_filled) {
945 dlm_debug("Max size reached in list, reject_ap_type %d",
946 reject_ap_type);
947 return;
948 }
949 qdf_list_peek_next(reject_db_list, cur_node, &next_node);
950
951 dlm_entry = qdf_container_of(cur_node, struct dlm_reject_ap,
952 node);
953
954 dlm_update_ap_info(dlm_entry, cfg, NULL);
955 if (!dlm_entry->reject_ap_type) {
956 dlm_debug(QDF_MAC_ADDR_FMT " cleared from list",
957 QDF_MAC_ADDR_REF(dlm_entry->bssid.bytes));
958 qdf_list_remove_node(reject_db_list, &dlm_entry->node);
959 qdf_mem_free(dlm_entry);
960 cur_node = next_node;
961 next_node = NULL;
962 continue;
963 }
964
965 if (dlm_is_bssid_of_type(reject_ap_type, dlm_entry)) {
966 struct reject_ap_config_params *dlm_reject_list;
967
968 dlm_reject_list = &reject_list[*num_of_reject_bssid];
969 dlm_reject_list->expected_rssi =
970 dlm_entry->rssi_reject_params.expected_rssi;
971 dlm_reject_list->reject_duration =
972 dlm_get_delta_of_bssid(reject_ap_type, dlm_entry,
973 cfg);
974
975 dlm_fill_rssi_reject_params(dlm_entry, reject_ap_type,
976 dlm_reject_list);
977 dlm_reject_list->reject_ap_type = reject_ap_type;
978 dlm_reject_list->bssid = dlm_entry->bssid;
979 (*num_of_reject_bssid)++;
980 dlm_debug("Adding BSSID " QDF_MAC_ADDR_FMT " of type %d retry delay %d expected RSSI %d, entries added = %d reject reason %d",
981 QDF_MAC_ADDR_REF(dlm_entry->bssid.bytes),
982 reject_ap_type,
983 reject_list[*num_of_reject_bssid - 1].reject_duration,
984 dlm_entry->rssi_reject_params.expected_rssi,
985 *num_of_reject_bssid,
986 dlm_entry->reject_ap_reason);
987 }
988 cur_node = next_node;
989 next_node = NULL;
990 }
991 }
992
993 #if defined(WLAN_FEATURE_ROAM_OFFLOAD)
dlm_update_reject_ap_list_to_fw(struct wlan_objmgr_psoc * psoc)994 void dlm_update_reject_ap_list_to_fw(struct wlan_objmgr_psoc *psoc)
995 {
996 struct dlm_config *cfg;
997 struct wlan_objmgr_pdev *pdev;
998 struct dlm_pdev_priv_obj *dlm_ctx;
999 struct dlm_psoc_priv_obj *dlm_psoc_obj;
1000 QDF_STATUS status;
1001
1002 dlm_psoc_obj = dlm_get_psoc_obj(psoc);
1003 if (!dlm_psoc_obj) {
1004 dlm_err("DLM psoc obj NULL");
1005 return;
1006 }
1007
1008 pdev = wlan_objmgr_get_pdev_by_id(psoc, dlm_psoc_obj->pdev_id,
1009 WLAN_MLME_CM_ID);
1010 if (!pdev) {
1011 dlm_err("pdev obj NULL");
1012 return;
1013 }
1014
1015 dlm_ctx = dlm_get_pdev_obj(pdev);
1016 if (!dlm_ctx) {
1017 dlm_err("DLM pdev obj NULL");
1018 goto end;
1019 }
1020
1021 status = qdf_mutex_acquire(&dlm_ctx->reject_ap_list_lock);
1022 if (QDF_IS_STATUS_ERROR(status)) {
1023 dlm_err("failed to acquire reject_ap_list_lock");
1024 goto end;
1025 }
1026
1027 cfg = &dlm_psoc_obj->dlm_cfg;
1028 dlm_send_reject_ap_list_to_fw(pdev, &dlm_ctx->reject_ap_list, cfg);
1029 qdf_mutex_release(&dlm_ctx->reject_ap_list_lock);
1030
1031 end:
1032 wlan_objmgr_pdev_release_ref(pdev, WLAN_MLME_CM_ID);
1033 }
1034
dlm_store_pdevid_in_dlm_psocpriv(struct wlan_objmgr_pdev * pdev)1035 static void dlm_store_pdevid_in_dlm_psocpriv(struct wlan_objmgr_pdev *pdev)
1036 {
1037 struct dlm_psoc_priv_obj *dlm_psoc_obj;
1038
1039 dlm_psoc_obj = dlm_get_psoc_obj(wlan_pdev_get_psoc(pdev));
1040
1041 if (!dlm_psoc_obj) {
1042 dlm_err("DLM psoc obj NULL");
1043 return;
1044 }
1045
1046 dlm_psoc_obj->pdev_id = pdev->pdev_objmgr.wlan_pdev_id;
1047 }
1048
1049 void
dlm_send_reject_ap_list_to_fw(struct wlan_objmgr_pdev * pdev,qdf_list_t * reject_db_list,struct dlm_config * cfg)1050 dlm_send_reject_ap_list_to_fw(struct wlan_objmgr_pdev *pdev,
1051 qdf_list_t *reject_db_list,
1052 struct dlm_config *cfg)
1053 {
1054 QDF_STATUS status;
1055 bool is_dlm_suspended;
1056 struct reject_ap_params reject_params = {0};
1057
1058 ucfg_dlm_psoc_get_suspended(wlan_pdev_get_psoc(pdev),
1059 &is_dlm_suspended);
1060 if (is_dlm_suspended) {
1061 dlm_store_pdevid_in_dlm_psocpriv(pdev);
1062 dlm_debug("Failed to send reject AP list to FW as DLM is suspended");
1063 return;
1064 }
1065
1066 reject_params.bssid_list =
1067 qdf_mem_malloc(sizeof(*reject_params.bssid_list) *
1068 PDEV_MAX_NUM_BSSID_DISALLOW_LIST);
1069 if (!reject_params.bssid_list)
1070 return;
1071
1072 /* The priority for filling is as below */
1073 dlm_fill_reject_list(reject_db_list, reject_params.bssid_list,
1074 &reject_params.num_of_reject_bssid,
1075 USERSPACE_DENYLIST_TYPE,
1076 PDEV_MAX_NUM_BSSID_DISALLOW_LIST, cfg);
1077 dlm_fill_reject_list(reject_db_list, reject_params.bssid_list,
1078 &reject_params.num_of_reject_bssid,
1079 DRIVER_DENYLIST_TYPE,
1080 PDEV_MAX_NUM_BSSID_DISALLOW_LIST, cfg);
1081 dlm_fill_reject_list(reject_db_list, reject_params.bssid_list,
1082 &reject_params.num_of_reject_bssid,
1083 DRIVER_RSSI_REJECT_TYPE,
1084 PDEV_MAX_NUM_BSSID_DISALLOW_LIST, cfg);
1085 dlm_fill_reject_list(reject_db_list, reject_params.bssid_list,
1086 &reject_params.num_of_reject_bssid,
1087 USERSPACE_AVOID_TYPE,
1088 PDEV_MAX_NUM_BSSID_DISALLOW_LIST, cfg);
1089 dlm_fill_reject_list(reject_db_list, reject_params.bssid_list,
1090 &reject_params.num_of_reject_bssid,
1091 DRIVER_AVOID_TYPE,
1092 PDEV_MAX_NUM_BSSID_DISALLOW_LIST, cfg);
1093
1094 status = tgt_dlm_send_reject_list_to_fw(pdev, &reject_params);
1095
1096 if (QDF_IS_STATUS_ERROR(status))
1097 dlm_err("failed to send the reject Ap list to FW");
1098
1099 qdf_mem_free(reject_params.bssid_list);
1100 }
1101 #endif
1102
1103 QDF_STATUS
dlm_add_bssid_to_reject_list(struct wlan_objmgr_pdev * pdev,struct reject_ap_info * ap_info)1104 dlm_add_bssid_to_reject_list(struct wlan_objmgr_pdev *pdev,
1105 struct reject_ap_info *ap_info)
1106 {
1107 struct dlm_pdev_priv_obj *dlm_ctx;
1108 struct dlm_psoc_priv_obj *dlm_psoc_obj;
1109 struct dlm_config *cfg;
1110 struct dlm_reject_ap *dlm_entry;
1111 qdf_list_node_t *cur_node = NULL, *next_node = NULL;
1112 QDF_STATUS status;
1113
1114 dlm_ctx = dlm_get_pdev_obj(pdev);
1115 dlm_psoc_obj = dlm_get_psoc_obj(wlan_pdev_get_psoc(pdev));
1116
1117 if (!dlm_ctx || !dlm_psoc_obj) {
1118 dlm_err("dlm_ctx or dlm_psoc_obj is NULL");
1119 return QDF_STATUS_E_INVAL;
1120 }
1121
1122 if (qdf_is_macaddr_zero(&ap_info->bssid) ||
1123 qdf_is_macaddr_group(&ap_info->bssid)) {
1124 dlm_err("Zero/Broadcast BSSID received, entry not added");
1125 return QDF_STATUS_E_INVAL;
1126 }
1127
1128 status = qdf_mutex_acquire(&dlm_ctx->reject_ap_list_lock);
1129 if (QDF_IS_STATUS_ERROR(status)) {
1130 dlm_err("failed to acquire reject_ap_list_lock");
1131 return status;
1132 }
1133
1134 cfg = &dlm_psoc_obj->dlm_cfg;
1135
1136 qdf_list_peek_front(&dlm_ctx->reject_ap_list, &cur_node);
1137
1138 while (cur_node) {
1139 qdf_list_peek_next(&dlm_ctx->reject_ap_list,
1140 cur_node, &next_node);
1141
1142 dlm_entry = qdf_container_of(cur_node, struct dlm_reject_ap,
1143 node);
1144
1145 /* Update the AP info to the latest list first */
1146 dlm_update_ap_info(dlm_entry, cfg, NULL);
1147 if (!dlm_entry->reject_ap_type) {
1148 dlm_debug(QDF_MAC_ADDR_FMT " cleared from list",
1149 QDF_MAC_ADDR_REF(dlm_entry->bssid.bytes));
1150 qdf_list_remove_node(&dlm_ctx->reject_ap_list,
1151 &dlm_entry->node);
1152 qdf_mem_free(dlm_entry);
1153 cur_node = next_node;
1154 next_node = NULL;
1155 continue;
1156 }
1157
1158 if (qdf_is_macaddr_equal(&dlm_entry->bssid, &ap_info->bssid)) {
1159 dlm_modify_entry(dlm_entry, cfg, ap_info);
1160 goto end;
1161 }
1162
1163 cur_node = next_node;
1164 next_node = NULL;
1165 }
1166
1167 if (qdf_list_size(&dlm_ctx->reject_ap_list) == MAX_BAD_AP_LIST_SIZE) {
1168 /* List is FULL, need to delete entries */
1169 status =
1170 dlm_remove_lowest_delta_entry(&dlm_ctx->reject_ap_list,
1171 cfg);
1172
1173 if (QDF_IS_STATUS_ERROR(status)) {
1174 qdf_mutex_release(&dlm_ctx->reject_ap_list_lock);
1175 return status;
1176 }
1177 }
1178
1179 dlm_entry = qdf_mem_malloc(sizeof(*dlm_entry));
1180 if (!dlm_entry) {
1181 qdf_mutex_release(&dlm_ctx->reject_ap_list_lock);
1182 return QDF_STATUS_E_FAILURE;
1183 }
1184
1185 qdf_list_insert_back(&dlm_ctx->reject_ap_list, &dlm_entry->node);
1186 dlm_modify_entry(dlm_entry, cfg, ap_info);
1187
1188 end:
1189 dlm_send_reject_ap_list_to_fw(pdev, &dlm_ctx->reject_ap_list, cfg);
1190 qdf_mutex_release(&dlm_ctx->reject_ap_list_lock);
1191
1192 return QDF_STATUS_SUCCESS;
1193 }
1194
1195 static QDF_STATUS
dlm_clear_userspace_denylist_info(struct wlan_objmgr_pdev * pdev)1196 dlm_clear_userspace_denylist_info(struct wlan_objmgr_pdev *pdev)
1197 {
1198 struct dlm_pdev_priv_obj *dlm_ctx;
1199 struct dlm_reject_ap *dlm_entry;
1200 QDF_STATUS status;
1201 qdf_list_node_t *cur_node = NULL, *next_node = NULL;
1202
1203 dlm_ctx = dlm_get_pdev_obj(pdev);
1204 if (!dlm_ctx) {
1205 dlm_err("dlm_ctx is NULL");
1206 return QDF_STATUS_E_INVAL;
1207 }
1208
1209 status = qdf_mutex_acquire(&dlm_ctx->reject_ap_list_lock);
1210 if (QDF_IS_STATUS_ERROR(status)) {
1211 dlm_err("failed to acquire reject_ap_list_lock");
1212 return QDF_STATUS_E_RESOURCES;
1213 }
1214
1215 qdf_list_peek_front(&dlm_ctx->reject_ap_list, &cur_node);
1216
1217 while (cur_node) {
1218 qdf_list_peek_next(&dlm_ctx->reject_ap_list, cur_node,
1219 &next_node);
1220 dlm_entry = qdf_container_of(cur_node, struct dlm_reject_ap,
1221 node);
1222
1223 if (IS_AP_IN_USERSPACE_DENYLIST_ONLY(dlm_entry)) {
1224 dlm_debug("removing bssid: " QDF_MAC_ADDR_FMT,
1225 QDF_MAC_ADDR_REF(dlm_entry->bssid.bytes));
1226 qdf_list_remove_node(&dlm_ctx->reject_ap_list,
1227 &dlm_entry->node);
1228 qdf_mem_free(dlm_entry);
1229 } else if (DLM_IS_AP_DENYLISTED_BY_USERSPACE(dlm_entry)) {
1230 dlm_debug("Clearing userspace denylist bit for "
1231 QDF_MAC_ADDR_FMT,
1232 QDF_MAC_ADDR_REF(dlm_entry->bssid.bytes));
1233 dlm_entry->userspace_denylist = false;
1234 dlm_entry->denylist_userspace = false;
1235 }
1236 cur_node = next_node;
1237 next_node = NULL;
1238 }
1239 qdf_mutex_release(&dlm_ctx->reject_ap_list_lock);
1240
1241 return QDF_STATUS_SUCCESS;
1242 }
1243
1244 QDF_STATUS
dlm_add_userspace_deny_list(struct wlan_objmgr_pdev * pdev,struct qdf_mac_addr * bssid_deny_list,uint8_t num_of_bssid)1245 dlm_add_userspace_deny_list(struct wlan_objmgr_pdev *pdev,
1246 struct qdf_mac_addr *bssid_deny_list,
1247 uint8_t num_of_bssid)
1248 {
1249 uint8_t i = 0;
1250 struct reject_ap_info ap_info;
1251 QDF_STATUS status;
1252 struct dlm_pdev_priv_obj *dlm_ctx;
1253 struct dlm_psoc_priv_obj *dlm_psoc_obj;
1254 struct dlm_config *cfg;
1255
1256 dlm_ctx = dlm_get_pdev_obj(pdev);
1257 dlm_psoc_obj = dlm_get_psoc_obj(wlan_pdev_get_psoc(pdev));
1258
1259 if (!dlm_ctx || !dlm_psoc_obj) {
1260 dlm_err("dlm_ctx or dlm_psoc_obj is NULL");
1261 return QDF_STATUS_E_INVAL;
1262 }
1263
1264 /* Clear all the info of APs already existing in DLM first */
1265 dlm_clear_userspace_denylist_info(pdev);
1266 cfg = &dlm_psoc_obj->dlm_cfg;
1267
1268 status = qdf_mutex_acquire(&dlm_ctx->reject_ap_list_lock);
1269 if (QDF_IS_STATUS_ERROR(status)) {
1270 dlm_err("failed to acquire reject_ap_list_lock");
1271 return status;
1272 }
1273
1274 dlm_send_reject_ap_list_to_fw(pdev, &dlm_ctx->reject_ap_list, cfg);
1275 qdf_mutex_release(&dlm_ctx->reject_ap_list_lock);
1276
1277 if (!bssid_deny_list || !num_of_bssid) {
1278 dlm_debug("Userspace denylist/num of denylist NULL");
1279 return QDF_STATUS_SUCCESS;
1280 }
1281
1282 for (i = 0; i < num_of_bssid; i++) {
1283 qdf_mem_zero(&ap_info, sizeof(struct reject_ap_info));
1284 ap_info.bssid = bssid_deny_list[i];
1285 ap_info.reject_ap_type = USERSPACE_DENYLIST_TYPE;
1286 ap_info.source = ADDED_BY_DRIVER;
1287 ap_info.reject_reason = REASON_USERSPACE_BL;
1288 status = dlm_add_bssid_to_reject_list(pdev, &ap_info);
1289 if (QDF_IS_STATUS_ERROR(status)) {
1290 dlm_err("Failed to add bssid to userspace denylist");
1291 return QDF_STATUS_E_FAILURE;
1292 }
1293 }
1294
1295 return QDF_STATUS_SUCCESS;
1296 }
1297
1298 void
dlm_flush_reject_ap_list(struct dlm_pdev_priv_obj * dlm_ctx)1299 dlm_flush_reject_ap_list(struct dlm_pdev_priv_obj *dlm_ctx)
1300 {
1301 struct dlm_reject_ap *dlm_entry = NULL;
1302 QDF_STATUS status;
1303 qdf_list_node_t *cur_node = NULL, *next_node = NULL;
1304
1305 status = qdf_mutex_acquire(&dlm_ctx->reject_ap_list_lock);
1306 if (QDF_IS_STATUS_ERROR(status)) {
1307 dlm_err("failed to acquire reject_ap_list_lock");
1308 return;
1309 }
1310
1311 qdf_list_peek_front(&dlm_ctx->reject_ap_list, &cur_node);
1312
1313 while (cur_node) {
1314 qdf_list_peek_next(&dlm_ctx->reject_ap_list, cur_node,
1315 &next_node);
1316 dlm_entry = qdf_container_of(cur_node, struct dlm_reject_ap,
1317 node);
1318 qdf_list_remove_node(&dlm_ctx->reject_ap_list,
1319 &dlm_entry->node);
1320 qdf_mem_free(dlm_entry);
1321 cur_node = next_node;
1322 next_node = NULL;
1323 }
1324
1325 dlm_debug("DLM reject ap list flushed");
1326 qdf_mutex_release(&dlm_ctx->reject_ap_list_lock);
1327 }
1328
1329 uint8_t
dlm_get_bssid_reject_list(struct wlan_objmgr_pdev * pdev,struct reject_ap_config_params * reject_list,uint8_t max_bssid_to_be_filled,enum dlm_reject_ap_type reject_ap_type)1330 dlm_get_bssid_reject_list(struct wlan_objmgr_pdev *pdev,
1331 struct reject_ap_config_params *reject_list,
1332 uint8_t max_bssid_to_be_filled,
1333 enum dlm_reject_ap_type reject_ap_type)
1334 {
1335 struct dlm_pdev_priv_obj *dlm_ctx;
1336 struct dlm_psoc_priv_obj *dlm_psoc_obj;
1337 uint8_t num_of_reject_bssid = 0;
1338 QDF_STATUS status;
1339
1340 dlm_ctx = dlm_get_pdev_obj(pdev);
1341 dlm_psoc_obj = dlm_get_psoc_obj(wlan_pdev_get_psoc(pdev));
1342
1343 if (!dlm_ctx || !dlm_psoc_obj) {
1344 dlm_err("dlm_ctx or dlm_psoc_obj is NULL");
1345 return 0;
1346 }
1347
1348 status = qdf_mutex_acquire(&dlm_ctx->reject_ap_list_lock);
1349 if (QDF_IS_STATUS_ERROR(status)) {
1350 dlm_err("failed to acquire reject_ap_list_lock");
1351 return 0;
1352 }
1353
1354 dlm_fill_reject_list(&dlm_ctx->reject_ap_list, reject_list,
1355 &num_of_reject_bssid, reject_ap_type,
1356 max_bssid_to_be_filled, &dlm_psoc_obj->dlm_cfg);
1357
1358 qdf_mutex_release(&dlm_ctx->reject_ap_list_lock);
1359
1360 return num_of_reject_bssid;
1361 }
1362
1363 void
dlm_update_bssid_connect_params(struct wlan_objmgr_pdev * pdev,struct qdf_mac_addr bssid,enum dlm_connection_state con_state)1364 dlm_update_bssid_connect_params(struct wlan_objmgr_pdev *pdev,
1365 struct qdf_mac_addr bssid,
1366 enum dlm_connection_state con_state)
1367 {
1368 struct dlm_pdev_priv_obj *dlm_ctx;
1369 struct dlm_psoc_priv_obj *dlm_psoc_obj;
1370 qdf_list_node_t *cur_node = NULL, *next_node = NULL;
1371 QDF_STATUS status;
1372 struct dlm_reject_ap *dlm_entry = NULL;
1373 qdf_time_t connection_age = 0;
1374 bool entry_found = false;
1375 qdf_time_t max_entry_time;
1376 qdf_time_t bad_bssid_reset_time;
1377
1378 dlm_ctx = dlm_get_pdev_obj(pdev);
1379 dlm_psoc_obj = dlm_get_psoc_obj(wlan_pdev_get_psoc(pdev));
1380
1381 if (!dlm_ctx || !dlm_psoc_obj) {
1382 dlm_err("dlm_ctx or dlm_psoc_obj is NULL");
1383 return;
1384 }
1385
1386 status = qdf_mutex_acquire(&dlm_ctx->reject_ap_list_lock);
1387 if (QDF_IS_STATUS_ERROR(status)) {
1388 dlm_err("failed to acquire reject_ap_list_lock");
1389 return;
1390 }
1391
1392 qdf_list_peek_front(&dlm_ctx->reject_ap_list, &cur_node);
1393
1394 while (cur_node) {
1395 qdf_list_peek_next(&dlm_ctx->reject_ap_list, cur_node,
1396 &next_node);
1397 dlm_entry = qdf_container_of(cur_node, struct dlm_reject_ap,
1398 node);
1399 if (!dlm_entry && next_node) {
1400 cur_node = next_node;
1401 next_node = NULL;
1402 continue;
1403 }
1404
1405 if (!qdf_mem_cmp(dlm_entry->bssid.bytes, bssid.bytes,
1406 QDF_MAC_ADDR_SIZE)) {
1407 dlm_debug(QDF_MAC_ADDR_FMT " present in DLM reject list, updating connect info con_state = %d",
1408 QDF_MAC_ADDR_REF(dlm_entry->bssid.bytes),
1409 con_state);
1410 entry_found = true;
1411 break;
1412 }
1413 cur_node = next_node;
1414 next_node = NULL;
1415 }
1416
1417 /* This means that the BSSID was not added in the reject list of DLM */
1418 if (!entry_found || !dlm_entry) {
1419 qdf_mutex_release(&dlm_ctx->reject_ap_list_lock);
1420 return;
1421 }
1422 switch (con_state) {
1423 case DLM_AP_CONNECTED:
1424 dlm_entry->connect_timestamp = qdf_mc_timer_get_system_time();
1425 break;
1426 case DLM_AP_DISCONNECTED:
1427 /* Update the dlm info first */
1428 dlm_update_ap_info(dlm_entry, &dlm_psoc_obj->dlm_cfg, NULL);
1429
1430 max_entry_time = dlm_entry->connect_timestamp;
1431 if (dlm_entry->driver_denylist) {
1432 max_entry_time =
1433 dlm_entry->ap_timestamp.driver_denylist_timestamp;
1434 } else if (dlm_entry->driver_avoidlist) {
1435 max_entry_time =
1436 QDF_MAX(dlm_entry->ap_timestamp.driver_avoid_timestamp,
1437 dlm_entry->connect_timestamp);
1438 }
1439 connection_age = qdf_mc_timer_get_system_time() -
1440 max_entry_time;
1441 bad_bssid_reset_time =
1442 dlm_psoc_obj->dlm_cfg.bad_bssid_counter_reset_time;
1443 if (connection_age > SECONDS_TO_MS(bad_bssid_reset_time)) {
1444 dlm_entry->driver_avoidlist = false;
1445 dlm_entry->driver_denylist = false;
1446 dlm_entry->driver_monitorlist = false;
1447 dlm_entry->userspace_avoidlist = false;
1448 dlm_debug("updated reject ap type %d ",
1449 dlm_entry->reject_ap_type);
1450 if (!dlm_entry->reject_ap_type) {
1451 dlm_debug("Bad Bssid timer expired/AP cleared from all denylisting, removed " QDF_MAC_ADDR_FMT " from list",
1452 QDF_MAC_ADDR_REF(dlm_entry->bssid.bytes));
1453 qdf_list_remove_node(&dlm_ctx->reject_ap_list,
1454 &dlm_entry->node);
1455 qdf_mem_free(dlm_entry);
1456 dlm_send_reject_ap_list_to_fw(pdev,
1457 &dlm_ctx->reject_ap_list,
1458 &dlm_psoc_obj->dlm_cfg);
1459 }
1460 }
1461 break;
1462 default:
1463 dlm_debug("Invalid AP connection state received %d", con_state);
1464 };
1465
1466 qdf_mutex_release(&dlm_ctx->reject_ap_list_lock);
1467 }
1468
dlm_get_rssi_denylist_threshold(struct wlan_objmgr_pdev * pdev)1469 int32_t dlm_get_rssi_denylist_threshold(struct wlan_objmgr_pdev *pdev)
1470 {
1471 struct dlm_pdev_priv_obj *dlm_ctx;
1472 struct dlm_psoc_priv_obj *dlm_psoc_obj;
1473 struct dlm_config *cfg;
1474
1475 dlm_ctx = dlm_get_pdev_obj(pdev);
1476 dlm_psoc_obj = dlm_get_psoc_obj(wlan_pdev_get_psoc(pdev));
1477
1478 if (!dlm_ctx || !dlm_psoc_obj) {
1479 dlm_err("dlm_ctx or dlm_psoc_obj is NULL");
1480 return 0;
1481 }
1482
1483 cfg = &dlm_psoc_obj->dlm_cfg;
1484 return cfg->delta_rssi;
1485 }
1486
1487