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