xref: /wlan-dirver/qcacld-3.0/components/denylist_mgr/core/src/wlan_dlm_core.c (revision 052b823b104069786af246cd479c40fb8474d8d7)
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 *
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
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 
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  */
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 
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)
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 
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
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
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
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
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
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
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
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 
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