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