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