1 /* 2 * Copyright (c) 2017-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 any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 /** 19 * DOC: contains bss scoring logic 20 */ 21 22 #ifdef WLAN_POLICY_MGR_ENABLE 23 #include "wlan_policy_mgr_api.h" 24 #endif 25 #include <include/wlan_psoc_mlme.h> 26 #include "wlan_psoc_mlme_api.h" 27 #include "cfg_ucfg_api.h" 28 #include "wlan_cm_bss_score_param.h" 29 #include "wlan_scan_api.h" 30 #include "wlan_crypto_global_api.h" 31 #include "wlan_mgmt_txrx_utils_api.h" 32 #ifdef CONN_MGR_ADV_FEATURE 33 #include "wlan_mlme_api.h" 34 #include "wlan_wfa_tgt_if_tx_api.h" 35 #endif 36 #include "wlan_cm_main_api.h" 37 #include "wlan_cm_public_struct.h" 38 39 #define CM_PCL_RSSI_THRESHOLD -75 40 41 #define TWO_LINK_BOOST 20 42 #define ONE_LINK_MLMR_BOOST 10 43 #define CANDIDATE_DUMP_MAX_LEN 255 44 45 #define LINK_SCORE BIT(0) 46 #define ASSOC_LINK BIT(1) 47 48 #define IS_LINK_SCORE(ml_flag) ml_flag & LINK_SCORE 49 #define IS_ASSOC_LINK(ml_flag) ml_flag & ASSOC_LINK 50 51 #define CM_BAND_2G_INDEX 0 52 #define CM_BAND_5G_INDEX 1 53 #define CM_BAND_6G_INDEX 2 54 /* 3 is reserved */ 55 #define CM_MAX_BAND_INDEX 4 56 57 #define CM_SCORE_INDEX_0 0 58 #define CM_SCORE_INDEX_3 3 59 #define CM_SCORE_INDEX_7 7 60 #define CM_SCORE_OFFSET_INDEX_7_4 4 61 #define CM_SCORE_INDEX_11 11 62 #define CM_SCORE_OFFSET_INDEX_11_8 8 63 #define CM_SCORE_MAX_INDEX 15 64 #define CM_SCORE_OFFSET_INDEX_15_12 12 65 66 #define CM_MAX_OCE_WAN_DL_CAP 16 67 68 #define CM_MAX_CHANNEL_WEIGHT 100 69 #define CM_MAX_CHANNEL_UTILIZATION 100 70 #define CM_MAX_ESTIMATED_AIR_TIME_FRACTION 255 71 #define CM_MAX_AP_LOAD 255 72 73 #define CM_MAX_WEIGHT_OF_PCL_CHANNELS 255 74 #define CM_PCL_GROUPS_WEIGHT_DIFFERENCE 20 75 76 /* Congestion threshold (channel load %) to consider band and OCE WAN score */ 77 #define CM_CONGESTION_THRSHOLD_FOR_BAND_OCE_SCORE 75 78 79 #define CM_RSSI_WEIGHTAGE 20 80 #define CM_HT_CAPABILITY_WEIGHTAGE 2 81 #define CM_VHT_CAP_WEIGHTAGE 1 82 #define CM_HE_CAP_WEIGHTAGE 2 83 #define CM_CHAN_WIDTH_WEIGHTAGE 12 84 #define CM_CHAN_BAND_WEIGHTAGE 2 85 #define CM_NSS_WEIGHTAGE 20 86 #define CM_SECURITY_WEIGHTAGE 4 87 #define CM_BEAMFORMING_CAP_WEIGHTAGE 2 88 #define CM_PCL_WEIGHT 10 89 #define CM_CHANNEL_CONGESTION_WEIGHTAGE 5 90 #define CM_OCE_WAN_WEIGHTAGE 2 91 #define CM_OCE_AP_TX_POWER_WEIGHTAGE 5 92 #define CM_OCE_SUBNET_ID_WEIGHTAGE 3 93 #define CM_SAE_PK_AP_WEIGHTAGE 30 94 #define CM_BEST_CANDIDATE_MAX_WEIGHT 200 95 #define CM_MAX_PCT_SCORE 100 96 #define CM_MAX_INDEX_PER_INI 4 97 #define CM_SLO_CONGESTION_MAX_SCORE 80 98 #define CM_ASSOC_INK_BEST_BOOST 20 99 100 /* 101 * This macro give percentage value of security_weightage to be used as per 102 * security Eg if AP security is WPA 10% will be given for AP. 103 * 104 * Indexes are defined in this way. 105 * 0 Index (BITS 0-7): WPA - Def 25% 106 * 1 Index (BITS 8-15): WPA2- Def 50% 107 * 2 Index (BITS 16-23): WPA3- Def 100% 108 * 3 Index (BITS 24-31): reserved 109 * 110 * if AP security is Open/WEP 0% will be given for AP 111 * These percentage values are stored in HEX. For any index max value, can be 64 112 */ 113 #define CM_SECURITY_INDEX_WEIGHTAGE 0x00643219 114 115 #define CM_BEST_CANDIDATE_MAX_BSS_SCORE (CM_BEST_CANDIDATE_MAX_WEIGHT * 100) 116 #define CM_AVOID_CANDIDATE_MIN_SCORE 1 117 118 #define CM_GET_SCORE_PERCENTAGE(value32, bw_index) \ 119 QDF_GET_BITS(value32, (8 * (bw_index)), 8) 120 #define CM_SET_SCORE_PERCENTAGE(value32, score_pcnt, bw_index) \ 121 QDF_SET_BITS(value32, (8 * (bw_index)), 8, score_pcnt) 122 123 #ifdef CONN_MGR_ADV_FEATURE 124 /* 3.2 us + 0.8 us(GI) */ 125 #define PPDU_PAYLOAD_SYMBOL_DUR_US 4 126 /* 12.8 us + (0.8 + 1.6)/2 us(GI) */ 127 #define HE_PPDU_PAYLOAD_SYMBOL_DUR_US 14 128 #define MAC_HEADER_LEN 26 129 /* Minimum snrDb supported by LUT */ 130 #define SNR_DB_TO_BIT_PER_TONE_LUT_MIN -10 131 /* Maximum snrDb supported by LUT */ 132 #define SNR_DB_TO_BIT_PER_TONE_LUT_MAX 9 133 #define DB_NUM 20 134 /* 135 * A fudge factor to represent HW implementation margin in dB. 136 * Predicted throughput matches pretty well with OTA throughput with this 137 * fudge factor. 138 */ 139 #define SNR_MARGIN_DB 16 140 #define TWO_IN_DB 3 141 static int32_t 142 SNR_DB_TO_BIT_PER_TONE_LUT[DB_NUM] = {0, 171, 212, 262, 323, 396, 484, 143 586, 706, 844, 1000, 1176, 1370, 1583, 1812, 2058, 2317, 2588, 2870, 3161}; 144 #endif 145 146 static bool cm_is_better_bss(struct scan_cache_entry *bss1, 147 struct scan_cache_entry *bss2) 148 { 149 if (bss1->bss_score > bss2->bss_score) 150 return true; 151 else if (bss1->bss_score == bss2->bss_score) 152 if (bss1->rssi_raw > bss2->rssi_raw) 153 return true; 154 155 return false; 156 } 157 158 /** 159 * cm_get_rssi_pcnt_for_slot() - calculate rssi % score based on the slot 160 * index between the high rssi and low rssi threshold 161 * @high_rssi_threshold: High rssi of the window 162 * @low_rssi_threshold: low rssi of the window 163 * @high_rssi_pcnt: % score for the high rssi 164 * @low_rssi_pcnt: %score for the low rssi 165 * @bucket_size: bucket size of the window 166 * @bss_rssi: Input rssi for which value need to be calculated 167 * 168 * Return: rssi pct to use for the given rssi 169 */ 170 static inline 171 int8_t cm_get_rssi_pcnt_for_slot(int32_t high_rssi_threshold, 172 int32_t low_rssi_threshold, 173 uint32_t high_rssi_pcnt, 174 uint32_t low_rssi_pcnt, 175 uint32_t bucket_size, int8_t bss_rssi) 176 { 177 int8_t slot_index, slot_size, rssi_diff, num_slot, rssi_pcnt; 178 179 num_slot = ((high_rssi_threshold - 180 low_rssi_threshold) / bucket_size) + 1; 181 slot_size = ((high_rssi_pcnt - low_rssi_pcnt) + 182 (num_slot / 2)) / (num_slot); 183 rssi_diff = high_rssi_threshold - bss_rssi; 184 slot_index = (rssi_diff / bucket_size) + 1; 185 rssi_pcnt = high_rssi_pcnt - (slot_size * slot_index); 186 if (rssi_pcnt < low_rssi_pcnt) 187 rssi_pcnt = low_rssi_pcnt; 188 189 return rssi_pcnt; 190 } 191 192 /** 193 * cm_calculate_rssi_score() - Calculate RSSI score based on AP RSSI 194 * @score_param: rssi score params 195 * @rssi: rssi of the AP 196 * @rssi_weightage: rssi_weightage out of total weightage 197 * 198 * Return: rssi score 199 */ 200 static int32_t cm_calculate_rssi_score(struct rssi_config_score *score_param, 201 int32_t rssi, uint8_t rssi_weightage) 202 { 203 int8_t rssi_pcnt; 204 int32_t total_rssi_score; 205 int32_t best_rssi_threshold; 206 int32_t good_rssi_threshold; 207 int32_t bad_rssi_threshold; 208 uint32_t good_rssi_pcnt; 209 uint32_t bad_rssi_pcnt; 210 uint32_t good_bucket_size; 211 uint32_t bad_bucket_size; 212 213 best_rssi_threshold = score_param->best_rssi_threshold * (-1); 214 good_rssi_threshold = score_param->good_rssi_threshold * (-1); 215 bad_rssi_threshold = score_param->bad_rssi_threshold * (-1); 216 good_rssi_pcnt = score_param->good_rssi_pcnt; 217 bad_rssi_pcnt = score_param->bad_rssi_pcnt; 218 good_bucket_size = score_param->good_rssi_bucket_size; 219 bad_bucket_size = score_param->bad_rssi_bucket_size; 220 221 total_rssi_score = (CM_MAX_PCT_SCORE * rssi_weightage); 222 223 /* 224 * If RSSI is better than the best rssi threshold then it return full 225 * score. 226 */ 227 if (rssi > best_rssi_threshold) 228 return total_rssi_score; 229 /* 230 * If RSSI is less or equal to bad rssi threshold then it return 231 * least score. 232 */ 233 if (rssi <= bad_rssi_threshold) 234 return (total_rssi_score * bad_rssi_pcnt) / 100; 235 236 /* RSSI lies between best to good rssi threshold */ 237 if (rssi > good_rssi_threshold) 238 rssi_pcnt = cm_get_rssi_pcnt_for_slot(best_rssi_threshold, 239 good_rssi_threshold, 100, good_rssi_pcnt, 240 good_bucket_size, rssi); 241 else 242 rssi_pcnt = cm_get_rssi_pcnt_for_slot(good_rssi_threshold, 243 bad_rssi_threshold, good_rssi_pcnt, 244 bad_rssi_pcnt, bad_bucket_size, 245 rssi); 246 247 return (total_rssi_score * rssi_pcnt) / 100; 248 } 249 250 /** 251 * cm_rssi_is_same_bucket() - check if both rssi fall in same bucket 252 * @rssi_top_thresh: high rssi threshold of the the window 253 * @rssi_ref1: rssi ref one 254 * @rssi_ref2: rssi ref two 255 * @bucket_size: bucket size of the window 256 * 257 * Return: true if both fall in same window 258 */ 259 static inline bool cm_rssi_is_same_bucket(int8_t rssi_top_thresh, 260 int8_t rssi_ref1, int8_t rssi_ref2, 261 int8_t bucket_size) 262 { 263 int8_t rssi_diff1 = 0; 264 int8_t rssi_diff2 = 0; 265 266 rssi_diff1 = rssi_top_thresh - rssi_ref1; 267 rssi_diff2 = rssi_top_thresh - rssi_ref2; 268 269 return (rssi_diff1 / bucket_size) == (rssi_diff2 / bucket_size); 270 } 271 272 /** 273 * cm_get_rssi_prorate_pct() - Calculate prorated RSSI score 274 * based on AP RSSI. This will be used to determine HT VHT score 275 * @score_param: rssi score params 276 * @rssi: bss rssi 277 * @rssi_weightage: rssi_weightage out of total weightage 278 * 279 * If rssi is greater than good threshold return 100, if less than bad return 0, 280 * if between good and bad, return prorated rssi score for the index. 281 * 282 * Return: rssi prorated score 283 */ 284 static int8_t 285 cm_get_rssi_prorate_pct(struct rssi_config_score *score_param, 286 int32_t rssi, uint8_t rssi_weightage) 287 { 288 int32_t good_rssi_threshold; 289 int32_t bad_rssi_threshold; 290 int8_t rssi_pref_5g_rssi_thresh; 291 bool same_bucket; 292 293 good_rssi_threshold = score_param->good_rssi_threshold * (-1); 294 bad_rssi_threshold = score_param->bad_rssi_threshold * (-1); 295 rssi_pref_5g_rssi_thresh = score_param->rssi_pref_5g_rssi_thresh * (-1); 296 297 /* If RSSI is greater than good rssi return full weight */ 298 if (rssi > good_rssi_threshold) 299 return CM_MAX_PCT_SCORE; 300 301 same_bucket = cm_rssi_is_same_bucket(good_rssi_threshold, rssi, 302 rssi_pref_5g_rssi_thresh, 303 score_param->bad_rssi_bucket_size); 304 if (same_bucket || (rssi < rssi_pref_5g_rssi_thresh)) 305 return 0; 306 /* If RSSI is less or equal to bad rssi threshold then it return 0 */ 307 if (rssi <= bad_rssi_threshold) 308 return 0; 309 310 /* If RSSI is between good and bad threshold */ 311 return cm_get_rssi_pcnt_for_slot(good_rssi_threshold, 312 bad_rssi_threshold, 313 score_param->good_rssi_pcnt, 314 score_param->bad_rssi_pcnt, 315 score_param->bad_rssi_bucket_size, 316 rssi); 317 } 318 319 /** 320 * cm_get_score_for_index() - get score for the given index 321 * @index: index for which we need the score 322 * @weightage: weigtage for the param 323 * @score: per slot score 324 * 325 * Return: score for the index 326 */ 327 static int32_t cm_get_score_for_index(uint8_t index, 328 uint8_t weightage, 329 struct per_slot_score *score) 330 { 331 if (index <= CM_SCORE_INDEX_3) 332 return weightage * CM_GET_SCORE_PERCENTAGE( 333 score->score_pcnt3_to_0, 334 index); 335 else if (index <= CM_SCORE_INDEX_7) 336 return weightage * CM_GET_SCORE_PERCENTAGE( 337 score->score_pcnt7_to_4, 338 index - CM_SCORE_OFFSET_INDEX_7_4); 339 else if (index <= CM_SCORE_INDEX_11) 340 return weightage * CM_GET_SCORE_PERCENTAGE( 341 score->score_pcnt11_to_8, 342 index - CM_SCORE_OFFSET_INDEX_11_8); 343 else 344 return weightage * CM_GET_SCORE_PERCENTAGE( 345 score->score_pcnt15_to_12, 346 index - CM_SCORE_OFFSET_INDEX_15_12); 347 } 348 349 /** 350 * cm_get_congestion_pct() - Calculate congestion pct from esp/qbss load 351 * @entry: bss information 352 * 353 * Return: congestion pct 354 */ 355 static int32_t cm_get_congestion_pct(struct scan_cache_entry *entry) 356 { 357 uint32_t ap_load = 0; 358 uint32_t est_air_time_percentage = 0; 359 uint32_t congestion = 0; 360 361 if (entry->air_time_fraction) { 362 /* Convert 0-255 range to percentage */ 363 est_air_time_percentage = entry->air_time_fraction * 364 CM_MAX_CHANNEL_WEIGHT; 365 est_air_time_percentage = qdf_do_div(est_air_time_percentage, 366 CM_MAX_ESTIMATED_AIR_TIME_FRACTION); 367 /* 368 * Calculate channel congestion from estimated air time 369 * fraction. 370 */ 371 congestion = CM_MAX_CHANNEL_UTILIZATION - 372 est_air_time_percentage; 373 if (!congestion) 374 congestion = 1; 375 } else if (util_scan_entry_qbssload(entry)) { 376 ap_load = (entry->qbss_chan_load * CM_MAX_PCT_SCORE); 377 /* 378 * Calculate ap_load in % from qbss channel load from 379 * 0-255 range 380 */ 381 congestion = qdf_do_div(ap_load, CM_MAX_AP_LOAD); 382 if (!congestion) 383 congestion = 1; 384 } 385 386 return congestion; 387 } 388 389 /** 390 * cm_calculate_congestion_score() - Calculate congestion score 391 * @entry: bss information 392 * @score_params: bss score params 393 * @congestion_pct: congestion pct 394 * @rssi_bad_zone: 395 * 396 * Return: congestion score 397 */ 398 static int32_t cm_calculate_congestion_score(struct scan_cache_entry *entry, 399 struct scoring_cfg *score_params, 400 uint32_t *congestion_pct, 401 bool rssi_bad_zone) 402 { 403 uint32_t window_size; 404 uint8_t index; 405 int32_t good_rssi_threshold; 406 uint8_t chan_congestion_weight; 407 408 chan_congestion_weight = 409 score_params->weight_config.channel_congestion_weightage; 410 411 if (!entry) 412 return chan_congestion_weight * 413 CM_GET_SCORE_PERCENTAGE( 414 score_params->esp_qbss_scoring.score_pcnt3_to_0, 415 CM_SCORE_INDEX_0); 416 417 *congestion_pct = cm_get_congestion_pct(entry); 418 419 if (!score_params->esp_qbss_scoring.num_slot) 420 return 0; 421 422 if (score_params->esp_qbss_scoring.num_slot > 423 CM_SCORE_MAX_INDEX) 424 score_params->esp_qbss_scoring.num_slot = 425 CM_SCORE_MAX_INDEX; 426 427 good_rssi_threshold = 428 score_params->rssi_score.good_rssi_threshold * (-1); 429 430 /* For bad zone rssi get score from last index */ 431 if (rssi_bad_zone || entry->rssi_raw <= good_rssi_threshold) 432 return cm_get_score_for_index( 433 score_params->esp_qbss_scoring.num_slot, 434 chan_congestion_weight, 435 &score_params->esp_qbss_scoring); 436 437 if (!*congestion_pct) 438 return chan_congestion_weight * 439 CM_GET_SCORE_PERCENTAGE( 440 score_params->esp_qbss_scoring.score_pcnt3_to_0, 441 CM_SCORE_INDEX_0); 442 443 window_size = CM_MAX_PCT_SCORE / 444 score_params->esp_qbss_scoring.num_slot; 445 446 /* Desired values are from 1 to 15, as 0 is for not present. so do +1 */ 447 index = qdf_do_div(*congestion_pct, window_size) + 1; 448 449 if (index > score_params->esp_qbss_scoring.num_slot) 450 index = score_params->esp_qbss_scoring.num_slot; 451 452 return cm_get_score_for_index(index, 453 chan_congestion_weight, 454 &score_params->esp_qbss_scoring); 455 } 456 457 /** 458 * cm_calculate_nss_score() - Calculate congestion score 459 * @psoc: psoc ptr 460 * @score_config: scoring config 461 * @ap_nss: ap nss 462 * @prorated_pct: prorated % to return dependent on RSSI 463 * @sta_nss: Sta NSS 464 * 465 * Return: nss score 466 */ 467 static int32_t cm_calculate_nss_score(struct wlan_objmgr_psoc *psoc, 468 struct scoring_cfg *score_config, 469 uint8_t ap_nss, uint8_t prorated_pct, 470 uint32_t sta_nss) 471 { 472 uint8_t nss; 473 uint8_t score_pct; 474 475 nss = ap_nss; 476 if (sta_nss < nss) 477 nss = sta_nss; 478 479 if (nss == 8) 480 score_pct = CM_MAX_PCT_SCORE; 481 if (nss == 4) 482 score_pct = CM_GET_SCORE_PERCENTAGE( 483 score_config->nss_weight_per_index[0], 484 CM_NSS_4x4_INDEX); 485 else if (nss == 3) 486 score_pct = CM_GET_SCORE_PERCENTAGE( 487 score_config->nss_weight_per_index[0], 488 CM_NSS_3x3_INDEX); 489 else if (nss == 2) 490 score_pct = CM_GET_SCORE_PERCENTAGE( 491 score_config->nss_weight_per_index[0], 492 CM_NSS_2x2_INDEX); 493 else 494 score_pct = CM_GET_SCORE_PERCENTAGE( 495 score_config->nss_weight_per_index[0], 496 CM_NSS_1x1_INDEX); 497 498 return (score_config->weight_config.nss_weightage * score_pct * 499 prorated_pct) / CM_MAX_PCT_SCORE; 500 } 501 502 static int32_t cm_calculate_security_score(struct scoring_cfg *score_config, 503 struct security_info neg_sec_info) 504 { 505 uint32_t authmode, key_mgmt, ucastcipherset; 506 uint8_t score_pct = 0; 507 508 authmode = neg_sec_info.authmodeset; 509 key_mgmt = neg_sec_info.key_mgmt; 510 ucastcipherset = neg_sec_info.ucastcipherset; 511 512 if (QDF_HAS_PARAM(authmode, WLAN_CRYPTO_AUTH_FILS_SK) || 513 QDF_HAS_PARAM(authmode, WLAN_CRYPTO_AUTH_SAE) || 514 QDF_HAS_PARAM(authmode, WLAN_CRYPTO_AUTH_CCKM) || 515 QDF_HAS_PARAM(authmode, WLAN_CRYPTO_AUTH_RSNA) || 516 QDF_HAS_PARAM(authmode, WLAN_CRYPTO_AUTH_8021X)) { 517 if (QDF_HAS_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_SAE) || 518 QDF_HAS_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_FT_SAE) || 519 QDF_HAS_PARAM(key_mgmt, 520 WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SUITE_B) || 521 QDF_HAS_PARAM(key_mgmt, 522 WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SUITE_B_192) || 523 QDF_HAS_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_FILS_SHA256) || 524 QDF_HAS_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_FILS_SHA384) || 525 QDF_HAS_PARAM(key_mgmt, 526 WLAN_CRYPTO_KEY_MGMT_FT_FILS_SHA256) || 527 QDF_HAS_PARAM(key_mgmt, 528 WLAN_CRYPTO_KEY_MGMT_FT_FILS_SHA384) || 529 QDF_HAS_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_OWE) || 530 QDF_HAS_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_DPP) || 531 QDF_HAS_PARAM(key_mgmt, 532 WLAN_CRYPTO_KEY_MGMT_FT_IEEE8021X_SHA384) || 533 QDF_HAS_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_SAE_EXT_KEY) || 534 QDF_HAS_PARAM(key_mgmt, 535 WLAN_CRYPTO_KEY_MGMT_FT_SAE_EXT_KEY)) { 536 /*If security is WPA3, consider score_pct = 100%*/ 537 score_pct = CM_GET_SCORE_PERCENTAGE( 538 score_config->security_weight_per_index, 539 CM_SECURITY_WPA3_INDEX); 540 } else if (QDF_HAS_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_PSK) || 541 QDF_HAS_PARAM(key_mgmt, 542 WLAN_CRYPTO_KEY_MGMT_FT_IEEE8021X) || 543 QDF_HAS_PARAM(key_mgmt, 544 WLAN_CRYPTO_KEY_MGMT_FT_PSK) || 545 QDF_HAS_PARAM(key_mgmt, 546 WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SHA256) || 547 QDF_HAS_PARAM(key_mgmt, 548 WLAN_CRYPTO_KEY_MGMT_PSK_SHA256)) { 549 /*If security is WPA2, consider score_pct = 50%*/ 550 score_pct = CM_GET_SCORE_PERCENTAGE( 551 score_config->security_weight_per_index, 552 CM_SECURITY_WPA2_INDEX); 553 } 554 } else if (QDF_HAS_PARAM(authmode, WLAN_CRYPTO_AUTH_SHARED) || 555 QDF_HAS_PARAM(authmode, WLAN_CRYPTO_AUTH_WPA) || 556 QDF_HAS_PARAM(authmode, WLAN_CRYPTO_AUTH_WAPI)) { 557 /*If security is WPA, consider score_pct = 25%*/ 558 score_pct = CM_GET_SCORE_PERCENTAGE( 559 score_config->security_weight_per_index, 560 CM_SECURITY_WPA_INDEX); 561 } 562 563 return (score_config->weight_config.security_weightage * score_pct) / 564 CM_MAX_PCT_SCORE; 565 } 566 567 #ifdef WLAN_POLICY_MGR_ENABLE 568 static uint32_t cm_get_sta_nss(struct wlan_objmgr_psoc *psoc, 569 qdf_freq_t bss_channel_freq, 570 uint8_t vdev_nss_2g, uint8_t vdev_nss_5g) 571 { 572 /* 573 * If station support nss as 2*2 but AP support NSS as 1*1, 574 * this AP will be given half weight compare to AP which are having 575 * NSS as 2*2. 576 */ 577 578 if (policy_mgr_is_chnl_in_diff_band( 579 psoc, bss_channel_freq) && 580 policy_mgr_is_hw_dbs_capable(psoc) && 581 !(policy_mgr_is_hw_dbs_2x2_capable(psoc))) 582 return 1; 583 584 return (WLAN_REG_IS_24GHZ_CH_FREQ(bss_channel_freq) ? 585 vdev_nss_2g : 586 vdev_nss_5g); 587 } 588 #else 589 static uint32_t cm_get_sta_nss(struct wlan_objmgr_psoc *psoc, 590 qdf_freq_t bss_channel_freq, 591 uint8_t vdev_nss_2g, uint8_t vdev_nss_5g) 592 { 593 return (WLAN_REG_IS_24GHZ_CH_FREQ(bss_channel_freq) ? 594 vdev_nss_2g : 595 vdev_nss_5g); 596 } 597 #endif 598 599 #ifdef CONN_MGR_ADV_FEATURE 600 static bool 601 cm_get_pcl_weight_of_channel(uint32_t chan_freq, 602 struct pcl_freq_weight_list *pcl_lst, 603 int *pcl_chan_weight) 604 { 605 int i; 606 bool found = false; 607 608 if (!pcl_lst) 609 return found; 610 611 for (i = 0; i < pcl_lst->num_of_pcl_channels; i++) { 612 if (pcl_lst->pcl_freq_list[i] == chan_freq) { 613 *pcl_chan_weight = pcl_lst->pcl_weight_list[i]; 614 found = true; 615 break; 616 } 617 } 618 619 return found; 620 } 621 622 /** 623 * cm_calculate_pcl_score() - Calculate PCL score based on PCL weightage 624 * @psoc: psoc ptr 625 * @pcl_chan_weight: pcl weight of BSS channel 626 * @pcl_weightage: PCL _weightage out of total weightage 627 * 628 * Return: pcl score 629 */ 630 static int32_t cm_calculate_pcl_score(struct wlan_objmgr_psoc *psoc, 631 int pcl_chan_weight, 632 uint8_t pcl_weightage) 633 { 634 int32_t pcl_score = 0; 635 int32_t temp_pcl_chan_weight = 0; 636 637 /* 638 * Don’t consider pcl weightage for STA connection, 639 * if primary interface is configured. 640 */ 641 if (!policy_mgr_is_pcl_weightage_required(psoc)) 642 return 0; 643 644 /* 645 * Always choose the best candidate for non-DBS, 646 * irrespective of the band. 647 */ 648 if (!policy_mgr_is_hw_dbs_capable(psoc)) 649 return 0; 650 651 if (pcl_chan_weight) { 652 temp_pcl_chan_weight = 653 (CM_MAX_WEIGHT_OF_PCL_CHANNELS - pcl_chan_weight); 654 temp_pcl_chan_weight = qdf_do_div( 655 temp_pcl_chan_weight, 656 CM_PCL_GROUPS_WEIGHT_DIFFERENCE); 657 pcl_score = pcl_weightage - temp_pcl_chan_weight; 658 if (pcl_score < 0) 659 pcl_score = 0; 660 } 661 662 return pcl_score * CM_MAX_PCT_SCORE; 663 } 664 665 /** 666 * cm_calculate_oce_wan_score() - Calculate oce wan score 667 * @entry: bss information 668 * @score_params: bss score params 669 * 670 * Return: oce wan score 671 */ 672 static int32_t cm_calculate_oce_wan_score( 673 struct scan_cache_entry *entry, 674 struct scoring_cfg *score_params) 675 { 676 uint32_t window_size; 677 uint8_t index; 678 struct oce_reduced_wan_metrics wan_metrics; 679 uint8_t *mbo_oce_ie; 680 681 if (!score_params->oce_wan_scoring.num_slot) 682 return 0; 683 684 if (score_params->oce_wan_scoring.num_slot > 685 CM_SCORE_MAX_INDEX) 686 score_params->oce_wan_scoring.num_slot = 687 CM_SCORE_MAX_INDEX; 688 689 window_size = CM_SCORE_MAX_INDEX / 690 score_params->oce_wan_scoring.num_slot; 691 mbo_oce_ie = util_scan_entry_mbo_oce(entry); 692 if (wlan_parse_oce_reduced_wan_metrics_ie(mbo_oce_ie, &wan_metrics)) { 693 mlme_err("downlink_av_cap %d", wan_metrics.downlink_av_cap); 694 /* if capacity is 0 return 0 score */ 695 if (!wan_metrics.downlink_av_cap) 696 return 0; 697 /* Desired values are from 1 to WLAN_SCORE_MAX_INDEX */ 698 index = qdf_do_div(wan_metrics.downlink_av_cap, 699 window_size); 700 } else { 701 index = CM_SCORE_INDEX_0; 702 } 703 704 if (index > score_params->oce_wan_scoring.num_slot) 705 index = score_params->oce_wan_scoring.num_slot; 706 707 return cm_get_score_for_index(index, 708 score_params->weight_config.oce_wan_weightage, 709 &score_params->oce_wan_scoring); 710 } 711 712 /** 713 * cm_calculate_oce_subnet_id_weightage() - Calculate oce subnet id weightage 714 * @entry: bss entry 715 * @score_params: bss score params 716 * @oce_subnet_id_present: check if subnet id subelement is present in OCE IE 717 * 718 * Return: oce subnet id score 719 */ 720 static uint32_t 721 cm_calculate_oce_subnet_id_weightage(struct scan_cache_entry *entry, 722 struct scoring_cfg *score_params, 723 bool *oce_subnet_id_present) 724 { 725 uint32_t score = 0; 726 uint8_t *mbo_oce_ie; 727 728 mbo_oce_ie = util_scan_entry_mbo_oce(entry); 729 *oce_subnet_id_present = wlan_parse_oce_subnet_id_ie(mbo_oce_ie); 730 731 /* Consider 50% weightage if subnet id sub element is present */ 732 if (*oce_subnet_id_present) 733 score = score_params->weight_config.oce_subnet_id_weightage * 734 (CM_MAX_PCT_SCORE / 2); 735 736 return score; 737 } 738 739 /** 740 * cm_calculate_sae_pk_ap_weightage() - Calculate SAE-PK AP weightage 741 * @entry: bss entry 742 * @score_params: bss score params 743 * @sae_pk_cap_present: sae_pk cap presetn in RSNXE capability field 744 * 745 * Return: SAE-PK AP weightage score 746 */ 747 static uint32_t 748 cm_calculate_sae_pk_ap_weightage(struct scan_cache_entry *entry, 749 struct scoring_cfg *score_params, 750 bool *sae_pk_cap_present) 751 { 752 const uint8_t *rsnxe_ie; 753 const uint8_t *rsnxe_cap; 754 uint8_t cap_len; 755 756 rsnxe_ie = util_scan_entry_rsnxe(entry); 757 758 rsnxe_cap = wlan_crypto_parse_rsnxe_ie(rsnxe_ie, &cap_len); 759 760 if (!rsnxe_cap) 761 return 0; 762 763 *sae_pk_cap_present = *rsnxe_cap & WLAN_CRYPTO_RSNX_CAP_SAE_PK; 764 if (*sae_pk_cap_present) 765 return score_params->weight_config.sae_pk_ap_weightage * 766 CM_MAX_PCT_SCORE; 767 768 return 0; 769 } 770 771 /** 772 * cm_calculate_oce_ap_tx_pwr_weightage() - Calculate oce ap tx pwr weightage 773 * @entry: bss entry 774 * @score_params: bss score params 775 * @ap_tx_pwr_dbm: pointer to hold ap tx power 776 * 777 * Return: oce ap tx power score 778 */ 779 static uint32_t 780 cm_calculate_oce_ap_tx_pwr_weightage(struct scan_cache_entry *entry, 781 struct scoring_cfg *score_params, 782 int8_t *ap_tx_pwr_dbm) 783 { 784 uint8_t *mbo_oce_ie, ap_tx_pwr_factor; 785 struct rssi_config_score *rssi_score_param; 786 int32_t best_rssi_threshold, good_rssi_threshold, bad_rssi_threshold; 787 uint32_t good_rssi_pcnt, bad_rssi_pcnt, good_bucket_size; 788 uint32_t score, normalized_ap_tx_pwr, bad_bucket_size; 789 bool ap_tx_pwr_cap_present = true; 790 791 mbo_oce_ie = util_scan_entry_mbo_oce(entry); 792 if (!wlan_parse_oce_ap_tx_pwr_ie(mbo_oce_ie, ap_tx_pwr_dbm)) { 793 ap_tx_pwr_cap_present = false; 794 /* If no OCE AP TX pwr, consider Uplink RSSI = Downlink RSSI */ 795 normalized_ap_tx_pwr = entry->rssi_raw; 796 } else { 797 /* 798 * Normalized ap_tx_pwr = 799 * Uplink RSSI = (STA TX Power - * (AP TX power - RSSI)) in dBm. 800 * Currently assuming STA Tx Power to be 20dBm, though later it 801 * need to fetched from hal-phy API. 802 */ 803 normalized_ap_tx_pwr = 804 (20 - (*ap_tx_pwr_dbm - entry->rssi_raw)); 805 } 806 807 rssi_score_param = &score_params->rssi_score; 808 809 best_rssi_threshold = rssi_score_param->best_rssi_threshold * (-1); 810 good_rssi_threshold = rssi_score_param->good_rssi_threshold * (-1); 811 bad_rssi_threshold = rssi_score_param->bad_rssi_threshold * (-1); 812 good_rssi_pcnt = rssi_score_param->good_rssi_pcnt; 813 bad_rssi_pcnt = rssi_score_param->bad_rssi_pcnt; 814 good_bucket_size = rssi_score_param->good_rssi_bucket_size; 815 bad_bucket_size = rssi_score_param->bad_rssi_bucket_size; 816 817 /* Uplink RSSI is better than best rssi threshold */ 818 if (normalized_ap_tx_pwr > best_rssi_threshold) { 819 ap_tx_pwr_factor = CM_MAX_PCT_SCORE; 820 } else if (normalized_ap_tx_pwr <= bad_rssi_threshold) { 821 /* Uplink RSSI is less or equal to bad rssi threshold */ 822 ap_tx_pwr_factor = rssi_score_param->bad_rssi_pcnt; 823 } else if (normalized_ap_tx_pwr > good_rssi_threshold) { 824 /* Uplink RSSI lies between best to good rssi threshold */ 825 ap_tx_pwr_factor = 826 cm_get_rssi_pcnt_for_slot( 827 best_rssi_threshold, 828 good_rssi_threshold, 100, 829 good_rssi_pcnt, 830 good_bucket_size, normalized_ap_tx_pwr); 831 } else { 832 /* Uplink RSSI lies between good to best rssi threshold */ 833 ap_tx_pwr_factor = 834 cm_get_rssi_pcnt_for_slot( 835 good_rssi_threshold, 836 bad_rssi_threshold, good_rssi_pcnt, 837 bad_rssi_pcnt, bad_bucket_size, 838 normalized_ap_tx_pwr); 839 } 840 841 score = score_params->weight_config.oce_ap_tx_pwr_weightage * 842 ap_tx_pwr_factor; 843 844 return score; 845 } 846 847 static bool cm_is_assoc_allowed(struct psoc_mlme_obj *mlme_psoc_obj, 848 struct scan_cache_entry *entry) 849 { 850 uint8_t reason; 851 uint8_t *mbo_oce; 852 bool check_assoc_disallowed; 853 854 mbo_oce = util_scan_entry_mbo_oce(entry); 855 856 check_assoc_disallowed = 857 mlme_psoc_obj->psoc_cfg.score_config.check_assoc_disallowed; 858 859 if (check_assoc_disallowed && 860 wlan_parse_oce_assoc_disallowed_ie(mbo_oce, &reason)) { 861 mlme_nofl_debug("Candidate("QDF_MAC_ADDR_FMT" freq %d): rssi %d, assoc disallowed set in MBO/OCE IE reason %d", 862 QDF_MAC_ADDR_REF(entry->bssid.bytes), 863 entry->channel.chan_freq, 864 entry->rssi_raw, reason); 865 return false; 866 } 867 868 return true; 869 } 870 871 void wlan_cm_set_check_assoc_disallowed(struct wlan_objmgr_psoc *psoc, 872 bool value) 873 { 874 struct psoc_mlme_obj *mlme_psoc_obj; 875 876 mlme_psoc_obj = wlan_psoc_mlme_get_cmpt_obj(psoc); 877 if (!mlme_psoc_obj) 878 return; 879 880 mlme_psoc_obj->psoc_cfg.score_config.check_assoc_disallowed = value; 881 } 882 883 void wlan_cm_get_check_assoc_disallowed(struct wlan_objmgr_psoc *psoc, 884 bool *value) 885 { 886 struct psoc_mlme_obj *mlme_psoc_obj; 887 888 mlme_psoc_obj = wlan_psoc_mlme_get_cmpt_obj(psoc); 889 if (!mlme_psoc_obj) { 890 *value = false; 891 return; 892 } 893 894 *value = mlme_psoc_obj->psoc_cfg.score_config.check_assoc_disallowed; 895 } 896 897 static enum phy_ch_width 898 cm_calculate_bandwidth(struct scan_cache_entry *entry, 899 struct psoc_phy_config *phy_config) 900 { 901 uint8_t bw_above_20 = 0; 902 bool is_vht = false; 903 enum phy_ch_width ch_width; 904 905 if (WLAN_REG_IS_24GHZ_CH_FREQ(entry->channel.chan_freq)) { 906 bw_above_20 = phy_config->bw_above_20_24ghz; 907 if (phy_config->vht_24G_cap) 908 is_vht = true; 909 } else if (phy_config->vht_cap) { 910 is_vht = true; 911 bw_above_20 = phy_config->bw_above_20_5ghz; 912 } 913 914 if (IS_WLAN_PHYMODE_160MHZ(entry->phy_mode)) 915 ch_width = CH_WIDTH_160MHZ; 916 else if (IS_WLAN_PHYMODE_80MHZ(entry->phy_mode)) 917 ch_width = CH_WIDTH_80MHZ; 918 else if (IS_WLAN_PHYMODE_40MHZ(entry->phy_mode)) 919 ch_width = CH_WIDTH_40MHZ; 920 else 921 ch_width = CH_WIDTH_20MHZ; 922 923 if (!phy_config->ht_cap && 924 ch_width >= CH_WIDTH_20MHZ) 925 ch_width = CH_WIDTH_20MHZ; 926 927 if (!is_vht && ch_width > CH_WIDTH_40MHZ) 928 ch_width = CH_WIDTH_40MHZ; 929 930 if (!bw_above_20) 931 ch_width = CH_WIDTH_20MHZ; 932 933 return ch_width; 934 } 935 936 static uint8_t cm_etp_get_ba_win_size_from_esp(uint8_t esp_ba_win_size) 937 { 938 /* 939 * BA Window Size subfield is three bits in length and indicates the 940 * size of the Block Ack window that is. 941 * 802.11-2016.pdf Table 9-262 BA Window Size subfield encoding 942 */ 943 switch (esp_ba_win_size) { 944 case 1: return 2; 945 case 2: return 4; 946 case 3: return 6; 947 case 4: return 8; 948 case 5: return 16; 949 case 6: return 32; 950 case 7: return 64; 951 default: return 1; 952 } 953 } 954 955 static uint16_t cm_get_etp_ntone(bool is_ht, bool is_vht, 956 enum phy_ch_width ch_width) 957 { 958 uint16_t n_sd = 52, n_seg = 1; 959 960 if (is_vht) { 961 /* Refer Table 21-5 in IEEE80211-2016 Spec */ 962 if (ch_width == CH_WIDTH_20MHZ) 963 n_sd = 52; 964 else if (ch_width == CH_WIDTH_40MHZ) 965 n_sd = 108; 966 else if (ch_width == CH_WIDTH_80MHZ) 967 n_sd = 234; 968 else if (ch_width == CH_WIDTH_80P80MHZ) 969 n_sd = 234, n_seg = 2; 970 else if (ch_width == CH_WIDTH_160MHZ) 971 n_sd = 468; 972 } else if (is_ht) { 973 /* Refer Table 19-6 in IEEE80211-2016 Spec */ 974 if (ch_width == CH_WIDTH_20MHZ) 975 n_sd = 52; 976 if (ch_width == CH_WIDTH_40MHZ) 977 n_sd = 108; 978 } else { 979 n_sd = 48; 980 } 981 982 return (n_sd * n_seg); 983 } 984 985 /* Refer Table 27-64 etc in Draft P802.11ax_D7.0.txt */ 986 static uint16_t cm_get_etp_he_ntone(enum phy_ch_width ch_width) 987 { 988 uint16_t n_sd = 234, n_seg = 1; 989 990 if (ch_width == CH_WIDTH_20MHZ) 991 n_sd = 234; 992 else if (ch_width == CH_WIDTH_40MHZ) 993 n_sd = 468; 994 else if (ch_width == CH_WIDTH_80MHZ) 995 n_sd = 980; 996 else if (ch_width == CH_WIDTH_80P80MHZ) 997 n_sd = 980, n_seg = 2; 998 else if (ch_width == CH_WIDTH_160MHZ) 999 n_sd = 1960; 1000 1001 return (n_sd * n_seg); 1002 } 1003 1004 static uint16_t cm_get_etp_phy_header_dur_us(bool is_ht, bool is_vht, 1005 uint8_t nss) 1006 { 1007 uint16_t dur_us = 0; 1008 1009 if (is_vht) { 1010 /* 1011 * Refer Figure 21-4 in 80211-2016 Spec 1012 * 8 (L-STF) + 8 (L-LTF) + 4 (L-SIG) + 1013 * 8 (VHT-SIG-A) + 4 (VHT-STF) + 4 (VHT-SIG-B) 1014 */ 1015 dur_us = 36; 1016 /* (nss * VHT-LTF) = (nss * 4) */ 1017 dur_us += (nss << 2); 1018 } else if (is_ht) { 1019 /* 1020 * Refer Figure 19-1 in 80211-2016 Spec 1021 * 8 (L-STF) + 8 (L-LTF) + 4 (L-SIG) + 8 (HT-SIG) + 1022 * 4 (HT-STF) 1023 */ 1024 dur_us = 32; 1025 /* (nss * HT-LTF = nss * 4) */ 1026 dur_us += (nss << 2); 1027 } else { 1028 /* 1029 * non-HT 1030 * Refer Figure 19-1 in 80211-2016 Spec 1031 * 8 (L-STF) + 8 (L-LTF) + 4 (L-SIG) 1032 */ 1033 dur_us = 20; 1034 } 1035 return dur_us; 1036 } 1037 1038 static uint32_t 1039 cm_get_etp_max_bits_per_sc_1000x_for_nss(struct wlan_objmgr_psoc *psoc, 1040 struct scan_cache_entry *entry, 1041 uint8_t nss, 1042 struct psoc_phy_config *phy_config) 1043 { 1044 uint32_t max_bits_per_sc_1000x = 5000; /* 5 * 1000 */ 1045 uint8_t mcs_map; 1046 struct wlan_ie_vhtcaps *bss_vht_cap; 1047 struct wlan_ie_hecaps *bss_he_cap; 1048 uint32_t self_rx_mcs_map; 1049 QDF_STATUS status; 1050 1051 bss_vht_cap = (struct wlan_ie_vhtcaps *)util_scan_entry_vhtcap(entry); 1052 bss_he_cap = (struct wlan_ie_hecaps *)util_scan_entry_hecap(entry); 1053 if (!phy_config->vht_cap || !bss_vht_cap) 1054 return max_bits_per_sc_1000x; 1055 1056 status = wlan_mlme_cfg_get_vht_rx_mcs_map(psoc, &self_rx_mcs_map); 1057 if (QDF_IS_STATUS_ERROR(status)) 1058 return max_bits_per_sc_1000x; 1059 1060 if (nss == 4) { 1061 mcs_map = (self_rx_mcs_map & 0xC0) >> 6; 1062 mcs_map = QDF_MIN(mcs_map, 1063 (bss_vht_cap->rx_mcs_map & 0xC0) >> 6); 1064 } else if (nss == 3) { 1065 mcs_map = (self_rx_mcs_map & 0x30) >> 4; 1066 mcs_map = QDF_MIN(mcs_map, 1067 (bss_vht_cap->rx_mcs_map & 0x30) >> 4); 1068 } else if (nss == 2) { 1069 mcs_map = (self_rx_mcs_map & 0x0C) >> 2; 1070 mcs_map = QDF_MIN(mcs_map, 1071 (bss_vht_cap->rx_mcs_map & 0x0C) >> 2); 1072 } else { 1073 mcs_map = (self_rx_mcs_map & 0x03); 1074 mcs_map = QDF_MIN(mcs_map, (bss_vht_cap->rx_mcs_map & 0x03)); 1075 } 1076 if (bss_he_cap) { 1077 if (mcs_map == 2) 1078 max_bits_per_sc_1000x = 8333; /* 10 *5/6 * 1000 */ 1079 else if (mcs_map == 1) 1080 max_bits_per_sc_1000x = 7500; /* 10 * 3/4 * 1000 */ 1081 } else { 1082 if (mcs_map == 2) 1083 max_bits_per_sc_1000x = 6667; /* 8 * 5/6 * 1000 */ 1084 else if (mcs_map == 1) 1085 max_bits_per_sc_1000x = 6000; /* 8 * 3/4 * 1000 */ 1086 } 1087 return max_bits_per_sc_1000x; 1088 } 1089 1090 /* Refer Table 9-163 in 80211-2016 Spec */ 1091 static uint32_t cm_etp_get_min_mpdu_ss_us_100x(struct htcap_cmn_ie *htcap) 1092 { 1093 tSirMacHTParametersInfo *ampdu_param; 1094 uint8_t ampdu_density; 1095 1096 ampdu_param = (tSirMacHTParametersInfo *)&htcap->ampdu_param; 1097 ampdu_density = ampdu_param->mpduDensity; 1098 1099 if (ampdu_density == 1) 1100 return 25; /* (1/4) * 100 */ 1101 else if (ampdu_density == 2) 1102 return 50; /* (1/2) * 100 */ 1103 else if (ampdu_density == 3) 1104 return 100; /* 1 * 100 */ 1105 else if (ampdu_density == 4) 1106 return 200; /* 2 * 100 */ 1107 else if (ampdu_density == 5) 1108 return 400; /* 4 * 100 */ 1109 else if (ampdu_density == 6) 1110 return 800; /* 8 * 100 */ 1111 else if (ampdu_density == 7) 1112 return 1600; /* 16 * 100 */ 1113 else 1114 return 100; 1115 } 1116 1117 /* Refer Table 9-162 in 80211-2016 Spec */ 1118 static uint32_t cm_etp_get_max_amsdu_len(struct wlan_objmgr_psoc *psoc, 1119 struct htcap_cmn_ie *htcap) 1120 { 1121 uint8_t bss_max_amsdu; 1122 uint32_t bss_max_amsdu_len; 1123 QDF_STATUS status; 1124 1125 status = wlan_mlme_get_max_amsdu_num(psoc, &bss_max_amsdu); 1126 if (QDF_IS_STATUS_ERROR(status)) 1127 bss_max_amsdu_len = 3839; 1128 else if (bss_max_amsdu == 1) 1129 bss_max_amsdu_len = 7935; 1130 else 1131 bss_max_amsdu_len = 3839; 1132 1133 return bss_max_amsdu_len; 1134 } 1135 1136 // Calculate the number of bits per tone based on the input of SNR in dB 1137 // The output is scaled up by BIT_PER_TONE_SCALE for integer representation 1138 static uint32_t 1139 calculate_bit_per_tone(int32_t rssi, enum phy_ch_width ch_width) 1140 { 1141 int32_t noise_floor_db_boost; 1142 int32_t noise_floor_dbm; 1143 int32_t snr_db; 1144 int32_t bit_per_tone; 1145 int32_t lut_in_idx; 1146 1147 noise_floor_db_boost = TWO_IN_DB * ch_width; 1148 noise_floor_dbm = WLAN_NOISE_FLOOR_DBM_DEFAULT + noise_floor_db_boost + 1149 SNR_MARGIN_DB; 1150 snr_db = rssi - noise_floor_dbm; 1151 if (snr_db <= SNR_DB_TO_BIT_PER_TONE_LUT_MAX) { 1152 lut_in_idx = QDF_MAX(snr_db, SNR_DB_TO_BIT_PER_TONE_LUT_MIN) 1153 - SNR_DB_TO_BIT_PER_TONE_LUT_MIN; 1154 lut_in_idx = QDF_MIN(lut_in_idx, DB_NUM - 1); 1155 bit_per_tone = SNR_DB_TO_BIT_PER_TONE_LUT[lut_in_idx]; 1156 } else { 1157 /* 1158 * SNR_tone = 10^(SNR/10) 1159 * log2(1+SNR_tone) ~= log2(SNR_tone) = 1160 * log10(SNR_tone)/log10(2) = log10(10^(SNR/10)) / 0.3 1161 * = (SNR/10) / 0.3 = SNR/3 1162 * So log2(1+SNR_tone) = SNR/3. 1000x for this is SNR*334 1163 */ 1164 bit_per_tone = snr_db * 334; 1165 } 1166 1167 return bit_per_tone; 1168 } 1169 1170 static uint32_t 1171 cm_calculate_etp(struct wlan_objmgr_psoc *psoc, 1172 struct scan_cache_entry *entry, 1173 struct etp_params *etp_param, 1174 uint8_t max_nss, enum phy_ch_width ch_width, 1175 bool is_ht, bool is_vht, bool is_he, 1176 int8_t rssi, 1177 struct psoc_phy_config *phy_config, uint8_t ml_flag) 1178 { 1179 uint16_t ntone; 1180 uint16_t phy_hdr_dur_us, max_amsdu_len = 1500, min_mpdu_ss_us_100x = 0; 1181 uint32_t max_bits_per_sc_1000x, log_2_snr_tone_1000x; 1182 uint32_t ppdu_payload_dur_us = 0, mpdu_per_ampdu, mpdu_per_ppdu; 1183 uint32_t single_ppdu_dur_us, estimated_throughput_mbps, data_rate_kbps; 1184 struct htcap_cmn_ie *htcap; 1185 1186 htcap = (struct htcap_cmn_ie *)util_scan_entry_htcap(entry); 1187 if (ch_width > CH_WIDTH_160MHZ) 1188 return CM_AVOID_CANDIDATE_MIN_SCORE; 1189 1190 if (is_he) 1191 ntone = cm_get_etp_he_ntone(ch_width); 1192 else 1193 ntone = cm_get_etp_ntone(is_ht, is_vht, ch_width); 1194 phy_hdr_dur_us = cm_get_etp_phy_header_dur_us(is_ht, is_vht, max_nss); 1195 1196 max_bits_per_sc_1000x = 1197 cm_get_etp_max_bits_per_sc_1000x_for_nss(psoc, entry, 1198 max_nss, phy_config); 1199 if (rssi < WLAN_NOISE_FLOOR_DBM_DEFAULT) 1200 return CM_AVOID_CANDIDATE_MIN_SCORE; 1201 1202 log_2_snr_tone_1000x = calculate_bit_per_tone(rssi, ch_width); 1203 1204 /* Eq. R-2 Pg:3508 in 80211-2016 Spec */ 1205 if (is_he) 1206 data_rate_kbps = 1207 QDF_MIN(log_2_snr_tone_1000x, max_bits_per_sc_1000x) * 1208 (max_nss * ntone) / HE_PPDU_PAYLOAD_SYMBOL_DUR_US; 1209 else 1210 data_rate_kbps = 1211 QDF_MIN(log_2_snr_tone_1000x, max_bits_per_sc_1000x) * 1212 (max_nss * ntone) / PPDU_PAYLOAD_SYMBOL_DUR_US; 1213 if (data_rate_kbps < 1000) { 1214 /* Return ETP as 1 since datarate is not even 1 Mbps */ 1215 mlme_nofl_debug("%s("QDF_MAC_ADDR_FMT" freq %d): data_rate_kbps %d is less than 1Mbps, so return score %d", 1216 IS_ASSOC_LINK(ml_flag) ? "Candidate" : "Partner", 1217 QDF_MAC_ADDR_REF(entry->bssid.bytes), 1218 entry->channel.chan_freq, data_rate_kbps, 1219 CM_AVOID_CANDIDATE_MIN_SCORE); 1220 return CM_AVOID_CANDIDATE_MIN_SCORE; 1221 } 1222 /* compute MPDU_p_PPDU */ 1223 if (is_ht) { 1224 min_mpdu_ss_us_100x = 1225 cm_etp_get_min_mpdu_ss_us_100x(htcap); 1226 max_amsdu_len = 1227 cm_etp_get_max_amsdu_len(psoc, htcap); 1228 ppdu_payload_dur_us = 1229 etp_param->data_ppdu_dur_target_us - phy_hdr_dur_us; 1230 mpdu_per_ampdu = 1231 QDF_MIN(qdf_ceil(ppdu_payload_dur_us * 100, 1232 min_mpdu_ss_us_100x), 1233 qdf_ceil(ppdu_payload_dur_us * 1234 (data_rate_kbps / 1000), 1235 (MAC_HEADER_LEN + max_amsdu_len) * 8)); 1236 mpdu_per_ppdu = QDF_MIN(etp_param->ba_window_size, 1237 QDF_MAX(1, mpdu_per_ampdu)); 1238 } else { 1239 mpdu_per_ppdu = 1; 1240 } 1241 1242 /* compute PPDU_Dur */ 1243 single_ppdu_dur_us = 1244 qdf_ceil((MAC_HEADER_LEN + max_amsdu_len) * mpdu_per_ppdu * 8, 1245 (data_rate_kbps / 1000) * PPDU_PAYLOAD_SYMBOL_DUR_US); 1246 single_ppdu_dur_us *= PPDU_PAYLOAD_SYMBOL_DUR_US; 1247 single_ppdu_dur_us += phy_hdr_dur_us; 1248 1249 estimated_throughput_mbps = 1250 qdf_ceil(mpdu_per_ppdu * max_amsdu_len * 8, single_ppdu_dur_us); 1251 estimated_throughput_mbps = 1252 (estimated_throughput_mbps * 1253 etp_param->airtime_fraction) / 1254 CM_MAX_ESTIMATED_AIR_TIME_FRACTION; 1255 1256 if (estimated_throughput_mbps < CM_AVOID_CANDIDATE_MIN_SCORE) 1257 estimated_throughput_mbps = CM_AVOID_CANDIDATE_MIN_SCORE; 1258 if (estimated_throughput_mbps > CM_BEST_CANDIDATE_MAX_BSS_SCORE) 1259 estimated_throughput_mbps = CM_BEST_CANDIDATE_MAX_BSS_SCORE; 1260 1261 mlme_nofl_debug("%s("QDF_MAC_ADDR_FMT" freq %d): rssi %d HT %d VHT %d HE %d ATF %d NSS %d ch_width %d data_rate %d", 1262 IS_ASSOC_LINK(ml_flag) ? "Candidate" : "Partner", 1263 QDF_MAC_ADDR_REF(entry->bssid.bytes), 1264 entry->channel.chan_freq, entry->rssi_raw, is_ht, 1265 is_vht, is_he, etp_param->airtime_fraction, 1266 entry->nss, ch_width, data_rate_kbps); 1267 if (is_ht) 1268 mlme_nofl_debug("min_mpdu_ss_us_100x %d max_amsdu %d ppdu_payload_dur_us %d mpdu_per_ampdu %d mpdu_per_ppdu %d ba_window %d", 1269 min_mpdu_ss_us_100x, max_amsdu_len, 1270 ppdu_payload_dur_us, mpdu_per_ampdu, 1271 mpdu_per_ppdu, etp_param->ba_window_size); 1272 mlme_nofl_debug("ETP score: ntone %d phy_hdr_dur_us %d max_bits_per_sc_1000x %d snr_tone_1000x %d mpdu_p_ppdu %d max_amsdu %d ppdu_dur_us %d TOTAL %d", 1273 ntone, phy_hdr_dur_us, max_bits_per_sc_1000x, 1274 log_2_snr_tone_1000x, mpdu_per_ppdu, max_amsdu_len, 1275 single_ppdu_dur_us, estimated_throughput_mbps); 1276 1277 return estimated_throughput_mbps; 1278 } 1279 1280 static uint32_t 1281 cm_calculate_etp_score(struct wlan_objmgr_psoc *psoc, 1282 struct scan_cache_entry *entry, 1283 struct psoc_phy_config *phy_config, 1284 enum MLO_TYPE bss_mlo_type, uint8_t ml_flag) 1285 { 1286 enum phy_ch_width ch_width; 1287 uint32_t nss; 1288 bool is_he_intersect = false; 1289 bool is_vht_intersect = false; 1290 bool is_ht_intersect = false; 1291 struct wlan_esp_info *esp; 1292 struct wlan_esp_ie *esp_ie; 1293 struct etp_params etp_param; 1294 int8_t mlo_prefer_percentage = 0; 1295 uint32_t score; 1296 int32_t mlo_score = 0; 1297 1298 if (phy_config->he_cap && entry->ie_list.hecap) 1299 is_he_intersect = true; 1300 if ((phy_config->vht_cap || phy_config->vht_24G_cap) && 1301 (entry->ie_list.vhtcap || 1302 WLAN_REG_IS_6GHZ_CHAN_FREQ(entry->channel.chan_freq))) 1303 is_vht_intersect = true; 1304 if (phy_config->ht_cap && entry->ie_list.htcap) 1305 is_ht_intersect = true; 1306 nss = cm_get_sta_nss(psoc, entry->channel.chan_freq, 1307 phy_config->vdev_nss_24g, 1308 phy_config->vdev_nss_5g); 1309 nss = QDF_MIN(nss, entry->nss); 1310 ch_width = cm_calculate_bandwidth(entry, phy_config); 1311 1312 /* Initialize default ETP params */ 1313 etp_param.airtime_fraction = 255 / 2; 1314 etp_param.ba_window_size = 32; 1315 etp_param.data_ppdu_dur_target_us = 5000; /* 5 msec */ 1316 1317 if (entry->air_time_fraction) { 1318 etp_param.airtime_fraction = entry->air_time_fraction; 1319 esp_ie = (struct wlan_esp_ie *) 1320 util_scan_entry_esp_info(entry); 1321 if (esp_ie) { 1322 esp = &esp_ie->esp_info_AC_BE; 1323 etp_param.ba_window_size = 1324 cm_etp_get_ba_win_size_from_esp(esp->ba_window_size); 1325 etp_param.data_ppdu_dur_target_us = 1326 50 * esp->ppdu_duration; 1327 mlme_debug("esp ba_window_size: %d, ppdu_duration: %d", 1328 esp->ba_window_size, esp->ppdu_duration); 1329 } 1330 } else if (entry->qbss_chan_load) { 1331 mlme_debug("qbss_chan_load: %d", entry->qbss_chan_load); 1332 etp_param.airtime_fraction = 1333 CM_MAX_ESTIMATED_AIR_TIME_FRACTION - 1334 entry->qbss_chan_load; 1335 } 1336 /* If ini vendor_roam_score_algorithm=1, just calculate ETP of all 1337 * bssid of ssid selected by high layer, and try to connect AP by 1338 * order of ETP, legacy algorithm with following Parameters/Weightage 1339 * becomes useless. ETP should be [1Mbps, 20000Mbps],matches score 1340 * range: [1, 20000] 1341 */ 1342 score = cm_calculate_etp(psoc, entry, 1343 &etp_param, 1344 nss, 1345 ch_width, 1346 is_ht_intersect, 1347 is_vht_intersect, 1348 is_he_intersect, 1349 entry->rssi_raw, 1350 phy_config, 1351 ml_flag); 1352 if (bss_mlo_type == SLO) 1353 return score; 1354 wlan_mlme_get_mlo_prefer_percentage(psoc, &mlo_prefer_percentage); 1355 if (mlo_prefer_percentage) { 1356 mlo_score = score; 1357 mlo_score = mlo_score + 1358 (mlo_score * mlo_prefer_percentage) / 100; 1359 score = mlo_score; 1360 } 1361 return score; 1362 } 1363 #else 1364 static bool 1365 cm_get_pcl_weight_of_channel(uint32_t chan_freq, 1366 struct pcl_freq_weight_list *pcl_lst, 1367 int *pcl_chan_weight) 1368 { 1369 return false; 1370 } 1371 1372 static int32_t cm_calculate_pcl_score(struct wlan_objmgr_psoc *psoc, 1373 int pcl_chan_weight, 1374 uint8_t pcl_weightage) 1375 { 1376 return 0; 1377 } 1378 1379 static int32_t cm_calculate_oce_wan_score(struct scan_cache_entry *entry, 1380 struct scoring_cfg *score_params) 1381 { 1382 return 0; 1383 } 1384 1385 static uint32_t 1386 cm_calculate_oce_subnet_id_weightage(struct scan_cache_entry *entry, 1387 struct scoring_cfg *score_params, 1388 bool *oce_subnet_id_present) 1389 { 1390 return 0; 1391 } 1392 1393 static uint32_t 1394 cm_calculate_sae_pk_ap_weightage(struct scan_cache_entry *entry, 1395 struct scoring_cfg *score_params, 1396 bool *sae_pk_cap_present) 1397 { 1398 return 0; 1399 } 1400 1401 static uint32_t 1402 cm_calculate_oce_ap_tx_pwr_weightage(struct scan_cache_entry *entry, 1403 struct scoring_cfg *score_params, 1404 int8_t *ap_tx_pwr_dbm) 1405 { 1406 return 0; 1407 } 1408 1409 static inline bool cm_is_assoc_allowed(struct psoc_mlme_obj *mlme_psoc_obj, 1410 struct scan_cache_entry *entry) 1411 { 1412 return true; 1413 } 1414 1415 static uint32_t 1416 cm_calculate_etp_score(struct wlan_objmgr_psoc *psoc, 1417 struct scan_cache_entry *entry, 1418 struct psoc_phy_config *phy_config, 1419 enum MLO_TYPE bss_mlo_type, uint8_t ml_flag) 1420 { 1421 return 0; 1422 } 1423 #endif 1424 1425 /** 1426 * cm_get_band_score() - Get band preference weightage 1427 * @freq: Operating frequency of the AP 1428 * @score_config: Score configuration 1429 * 1430 * Return: Band score for AP. 1431 */ 1432 static int 1433 cm_get_band_score(uint32_t freq, struct scoring_cfg *score_config) 1434 { 1435 uint8_t band_index; 1436 struct weight_cfg *weight_config; 1437 1438 weight_config = &score_config->weight_config; 1439 1440 if (WLAN_REG_IS_5GHZ_CH_FREQ(freq)) 1441 band_index = CM_BAND_5G_INDEX; 1442 else if (WLAN_REG_IS_24GHZ_CH_FREQ(freq)) 1443 band_index = CM_BAND_2G_INDEX; 1444 else if (WLAN_REG_IS_6GHZ_CHAN_FREQ(freq)) 1445 band_index = CM_BAND_6G_INDEX; 1446 else 1447 return 0; 1448 1449 return weight_config->chan_band_weightage * 1450 CM_GET_SCORE_PERCENTAGE(score_config->band_weight_per_index, 1451 band_index); 1452 } 1453 1454 #ifdef WLAN_FEATURE_11BE 1455 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE 1456 #if defined (SAP_MULTI_LINK_EMULATION) 1457 bool wlan_cm_is_eht_allowed_for_current_security(struct wlan_objmgr_psoc *psoc, 1458 struct scan_cache_entry *entry, 1459 bool is_mlo_connect) 1460 { 1461 return true; 1462 } 1463 #else 1464 bool wlan_cm_is_eht_allowed_for_current_security(struct wlan_objmgr_psoc *psoc, 1465 struct scan_cache_entry *entry, 1466 bool is_mlo_connect) 1467 { 1468 bool rf_test_mode = false; 1469 QDF_STATUS status; 1470 struct security_info *neg_sec_info; 1471 uint32_t oem_eht_cfg = 0x0; 1472 bool mlie_present; 1473 1474 status = wlan_mlme_is_rf_test_mode_enabled(psoc, &rf_test_mode); 1475 if (!QDF_IS_STATUS_SUCCESS(status)) { 1476 mlme_err("Get rf test mode failed"); 1477 return false; 1478 } 1479 if (rf_test_mode) { 1480 mlme_debug("rf test mode is enabled, ignore setting"); 1481 return true; 1482 } 1483 1484 if (!entry->ie_list.rsn) { 1485 mlme_debug(QDF_MAC_ADDR_FMT ": RSN IE not present", 1486 QDF_MAC_ADDR_REF(entry->bssid.bytes)); 1487 return false; 1488 } 1489 1490 /* Get the OEM EHT configuration. */ 1491 status = wlan_mlme_get_oem_eht_mlo_config(psoc, &oem_eht_cfg); 1492 if (QDF_IS_STATUS_ERROR(status)) { 1493 mlme_rl_nofl_err("OEM EHT cfg get failed"); 1494 return false; 1495 } 1496 1497 /* Check if the AP is ML capable or not */ 1498 mlie_present = entry->ie_list.multi_link_bv ? true : false; 1499 1500 neg_sec_info = &entry->neg_sec_info; 1501 if (neg_sec_info->rsn_caps & WLAN_CRYPTO_RSN_CAP_MFP_ENABLED) { 1502 /* For entreprise APs, only check if PMF is enabled or not */ 1503 if (WLAN_CRYPTO_IS_AKM_ENTERPRISE(neg_sec_info->key_mgmt)) 1504 return true; 1505 1506 /* For APs which are both WPA3 and WPA2, only check WPA3 as it 1507 * is the more secure AKM. 1508 */ 1509 if (WLAN_CRYPTO_IS_WPA3(neg_sec_info->key_mgmt)) { 1510 if (!WLAN_CRYPTO_IS_AKM_SAE(neg_sec_info->key_mgmt)) 1511 return true; 1512 1513 /* If OEM enables APs with HnP to connect, don't check 1514 * whether RSNXE has H2E bit set or not. It will be 1515 * allowing both HnP and H2E APs. 1516 * 1517 * If the AP is ML capable, return: 1518 * -True, if H2E is not required and not for ML assoc 1519 * -True, if INI bit value for MLO assoc is set. 1520 * 1521 * If AP is not ML capable, return: 1522 * -True, if INI bit value for allowing EHT only 1523 * connection is set. 1524 */ 1525 if (mlie_present) { 1526 if (!is_mlo_connect && 1527 !WLAN_CRYPTO_WPA3_SAE_OEM_EHT_CFG_IS_STRICT_H2E(oem_eht_cfg)) { 1528 return true; 1529 } else if (is_mlo_connect && 1530 (oem_eht_cfg & WLAN_HOST_CRYPTO_WPA3_SAE_ALLOW_MLO_HnP)) { 1531 return true; 1532 } 1533 } else if (!is_mlo_connect && 1534 (oem_eht_cfg & WLAN_HOST_CRYPTO_WPA3_SAE_ALLOW_NON_MLO_EHT_HnP)) { 1535 return true; 1536 } 1537 1538 /* If OEM wants strict H2E mandatory for EHT/MLO, then 1539 * allow only if candidate has H2E capability 1540 */ 1541 return util_scan_entry_sae_h2e_capable(entry); 1542 } else if (WLAN_CRYPTO_IS_WPA2(neg_sec_info->key_mgmt) && 1543 WLAN_CRYPTO_WPA2_OEM_EHT_CFG_PMF_ALLOWED(oem_eht_cfg)) { 1544 /* Only checks whether PMF APs are allowed or not via 1545 * the INI cfg. 1546 * Even if no-PMF APs are allowed to connect, PMF APs 1547 * will not be allowed to connect if the bitmap is not 1548 * set for PMF APs. 1549 * 1550 * If the AP is ML capable, return: 1551 * -True, if not for MLO connection 1552 * -INI BIT value for allowing MLO assoc with PMF 1553 * enabled APs. 1554 * 1555 * If the AP is not ML capable, return: 1556 * -INI BIT value for allowing EHT only connection 1557 * for PMF enabled APS. 1558 * 1559 */ 1560 if (mlie_present) { 1561 if (!is_mlo_connect) 1562 return true; 1563 return (oem_eht_cfg & WLAN_HOST_CRYPTO_WPA2_ALLOW_MLO_MFPC_SET); 1564 } else { 1565 return (oem_eht_cfg & WLAN_HOST_CRYPTO_WPA2_ALLOW_NON_MLO_EHT_MFPC_SET); 1566 } 1567 } else { 1568 return false; 1569 } 1570 } else if (!WLAN_CRYPTO_IS_WPA3(neg_sec_info->key_mgmt) && 1571 WLAN_CRYPTO_IS_WPA2(neg_sec_info->key_mgmt) && 1572 WLAN_CRYPTO_WPA2_OEM_EHT_CFG_NO_PMF_ALLOWED(oem_eht_cfg)) { 1573 /* 1574 * Only checks whether no PMF APs are allowed or not via the INI 1575 * cfg. 1576 * All WPA3 configurations has to be PMF, so only allow 1577 * non-WPA3 WPA2 APs in this condition. 1578 * 1579 * If the AP is ML capable, return: 1580 * -True, if not for MLO connection 1581 * -INI BIT value for allowing MLO assoc with Non-PMF 1582 * capable APs. 1583 * 1584 * If the AP is not ML capable, return: 1585 * -INI BIT value for allowing EHT only connection 1586 * for Non-PMF capable APs. 1587 */ 1588 if (mlie_present) { 1589 if (!is_mlo_connect) 1590 return true; 1591 return (oem_eht_cfg & WLAN_HOST_CRYPTO_WPA2_ALLOW_MLO); 1592 } else { 1593 return (oem_eht_cfg & WLAN_HOST_CRYPTO_WPA2_ALLOW_NON_MLO_EHT); 1594 } 1595 } else { 1596 return false; 1597 } 1598 } 1599 #endif 1600 #endif 1601 1602 static int cm_calculate_eht_score(struct wlan_objmgr_psoc *psoc, 1603 struct scan_cache_entry *entry, 1604 struct scoring_cfg *score_config, 1605 struct psoc_phy_config *phy_config, 1606 uint8_t prorated_pcnt) 1607 { 1608 uint32_t eht_caps_score; 1609 struct weight_cfg *weight_config; 1610 1611 if (!phy_config->eht_cap || !entry->ie_list.ehtcap) 1612 return 0; 1613 1614 if (!wlan_cm_is_eht_allowed_for_current_security(psoc, entry, false)) 1615 return 0; 1616 1617 weight_config = &score_config->weight_config; 1618 eht_caps_score = prorated_pcnt * weight_config->eht_caps_weightage; 1619 1620 return eht_caps_score; 1621 } 1622 1623 /** 1624 * cm_get_puncture_bw() - Get puncture band width 1625 * @entry: Bss scan entry 1626 * 1627 * Return: Total bandwidth of punctured subchannels (unit: MHz) 1628 */ 1629 static uint16_t cm_get_puncture_bw(struct scan_cache_entry *entry) 1630 { 1631 uint16_t puncture_bitmap; 1632 uint8_t num_puncture_bw = 0; 1633 1634 puncture_bitmap = entry->channel.puncture_bitmap; 1635 while (puncture_bitmap) { 1636 if (puncture_bitmap & 1) 1637 ++num_puncture_bw; 1638 puncture_bitmap >>= 1; 1639 } 1640 return num_puncture_bw * 20; 1641 } 1642 1643 static bool cm_get_su_beam_former(struct scan_cache_entry *entry) 1644 { 1645 struct wlan_ie_ehtcaps *eht_cap; 1646 struct wlan_eht_cap_info *eht_cap_info; 1647 1648 eht_cap = (struct wlan_ie_ehtcaps *)util_scan_entry_ehtcap(entry); 1649 if (eht_cap) { 1650 eht_cap_info = (struct wlan_eht_cap_info *)eht_cap->eht_mac_cap; 1651 if (eht_cap_info->su_beamformer) 1652 return true; 1653 } 1654 1655 return false; 1656 } 1657 #else 1658 static int cm_calculate_eht_score(struct wlan_objmgr_psoc *psoc, 1659 struct scan_cache_entry *entry, 1660 struct scoring_cfg *score_config, 1661 struct psoc_phy_config *phy_config, 1662 uint8_t prorated_pcnt) 1663 { 1664 return 0; 1665 } 1666 1667 static uint16_t cm_get_puncture_bw(struct scan_cache_entry *entry) 1668 { 1669 return 0; 1670 } 1671 1672 static bool cm_get_su_beam_former(struct scan_cache_entry *entry) 1673 { 1674 return false; 1675 } 1676 #endif 1677 1678 #define CM_BAND_WIDTH_NUM 16 1679 #define CM_BAND_WIDTH_UNIT 20 1680 uint16_t link_bw_score[CM_BAND_WIDTH_NUM] = { 1681 9, 18, 27, 35, 44, 53, 56, 67, 74, 80, 86, 90, 93, 96, 98, 100}; 1682 1683 static uint32_t cm_get_bw_score(uint8_t bw_weightage, uint16_t bw, 1684 uint8_t prorated_pcnt) 1685 { 1686 uint32_t score; 1687 uint8_t index; 1688 1689 index = bw / CM_BAND_WIDTH_UNIT - 1; 1690 if (index >= CM_BAND_WIDTH_NUM) 1691 index = CM_BAND_WIDTH_NUM - 1; 1692 score = bw_weightage * link_bw_score[index] 1693 * prorated_pcnt / CM_MAX_PCT_SCORE; 1694 1695 return score; 1696 } 1697 1698 /** 1699 * cm_get_ch_width() - Get channel width of bss scan entry 1700 * @entry: Bss scan entry 1701 * @phy_config: Phy config 1702 * 1703 * Return: Channel width (unit: MHz) 1704 */ 1705 static uint16_t cm_get_ch_width(struct scan_cache_entry *entry, 1706 struct psoc_phy_config *phy_config) 1707 { 1708 uint16_t bw, total_bw = 0; 1709 uint8_t bw_above_20 = 0; 1710 bool is_vht = false; 1711 1712 if (WLAN_REG_IS_24GHZ_CH_FREQ(entry->channel.chan_freq)) { 1713 bw_above_20 = phy_config->bw_above_20_24ghz; 1714 if (phy_config->vht_24G_cap) 1715 is_vht = true; 1716 } else if (phy_config->vht_cap) { 1717 is_vht = true; 1718 bw_above_20 = phy_config->bw_above_20_5ghz; 1719 } 1720 if (IS_WLAN_PHYMODE_320MHZ(entry->phy_mode)) 1721 bw = 320; 1722 else if (IS_WLAN_PHYMODE_160MHZ(entry->phy_mode)) 1723 bw = 160; 1724 else if (IS_WLAN_PHYMODE_80MHZ(entry->phy_mode)) 1725 bw = 80; 1726 else if (IS_WLAN_PHYMODE_40MHZ(entry->phy_mode)) 1727 bw = 40; 1728 else 1729 bw = 20; 1730 if (!phy_config->ht_cap && bw > 20) 1731 bw = 20; 1732 1733 if (!is_vht && bw > 40) 1734 bw = 40; 1735 1736 total_bw = bw - cm_get_puncture_bw(entry); 1737 1738 return total_bw; 1739 } 1740 1741 #ifdef WLAN_FEATURE_11BE_MLO 1742 #define CM_MLO_BAD_RSSI_PCT 61 1743 #define CM_MLO_CONGESTION_PCT_BAD_RSSI 6 1744 1745 static uint8_t mlo_boost_pct[MLO_TYPE_MAX] = {0, 10, CM_MAX_PCT_SCORE}; 1746 1747 /** 1748 * struct mlo_rssi_pct: MLO AP rssi joint factor and score percent 1749 * @joint_factor: rssi joint factor (0 - 100) 1750 * @rssi_pcnt: Rssi score percent (0 - 100) 1751 * @prorate_pcnt: RSSI prorated percent 1752 */ 1753 struct mlo_rssi_pct { 1754 uint16_t joint_factor; 1755 uint16_t rssi_pcnt; 1756 uint16_t prorate_pcnt; 1757 }; 1758 1759 #define CM_RSSI_BUCKET_NUM 7 1760 static struct mlo_rssi_pct mlo_rssi_pcnt[CM_RSSI_BUCKET_NUM] = { 1761 {80, 100, 100}, {60, 87, 100}, {44, 74, 100}, {30, 61, 100}, {20, 48, 54}, 1762 {10, 35, 28}, {0, 22, 1} }; 1763 1764 /** 1765 * cm_get_mlo_rssi_score() - Calculate joint rssi score for MLO AP 1766 * @rssi_weightage: rssi weightage 1767 * @link1_rssi: link1 rssi 1768 * @link2_rssi: link2 rssi 1769 * @prorate_pcnt: pointer to store RSSI prorated percent 1770 * 1771 * Return: MLO AP joint rssi score 1772 */ 1773 static uint32_t cm_get_mlo_rssi_score(uint8_t rssi_weightage, int8_t link1_rssi, 1774 int8_t link2_rssi, uint16_t *prorate_pcnt) 1775 { 1776 int8_t link1_factor = 0, link2_factor = 0; 1777 int32_t joint_factor = 0; 1778 int16_t rssi_pcnt = 0; 1779 int8_t i; 1780 1781 /* Calculate RSSI score -- using joint rssi, but limit to 2 links */ 1782 link1_factor = QDF_MAX(QDF_MIN(link1_rssi, -50), -95) + 95; 1783 link2_factor = QDF_MAX(QDF_MIN(link2_rssi, -50), -95) + 95; 1784 joint_factor = QDF_MIN((link1_factor * link1_factor + 1785 link2_factor * link2_factor) * 100 / (2 * 45 * 45), 1786 100); 1787 for (i = 0; i < CM_RSSI_BUCKET_NUM; i++) 1788 if (joint_factor > mlo_rssi_pcnt[i].joint_factor) { 1789 rssi_pcnt = mlo_rssi_pcnt[i].rssi_pcnt; 1790 *prorate_pcnt = mlo_rssi_pcnt[i].prorate_pcnt; 1791 break; 1792 } 1793 1794 return (rssi_weightage * rssi_pcnt); 1795 } 1796 1797 static inline int cm_calculate_emlsr_score(struct weight_cfg *weight_config) 1798 { 1799 return weight_config->emlsr_weightage * mlo_boost_pct[MLSR]; 1800 } 1801 1802 struct scan_cache_entry *cm_get_entry(qdf_list_t *scan_list, 1803 struct qdf_mac_addr *link_addr) 1804 { 1805 qdf_list_node_t *cur_node = NULL, *next_node = NULL; 1806 struct scan_cache_node *curr_entry = NULL; 1807 1808 qdf_list_peek_front(scan_list, &cur_node); 1809 while (cur_node) { 1810 curr_entry = qdf_container_of(cur_node, struct scan_cache_node, 1811 node); 1812 if (!qdf_mem_cmp(&curr_entry->entry->mac_addr, 1813 link_addr, QDF_MAC_ADDR_SIZE)) 1814 return curr_entry->entry; 1815 1816 qdf_list_peek_next(scan_list, cur_node, &next_node); 1817 cur_node = next_node; 1818 next_node = NULL; 1819 } 1820 1821 return NULL; 1822 } 1823 1824 #ifdef CONN_MGR_ADV_FEATURE 1825 static uint8_t cm_get_sta_mlo_conn_max_num(struct wlan_objmgr_psoc *psoc) 1826 { 1827 return wlan_mlme_get_sta_mlo_conn_max_num(psoc); 1828 } 1829 1830 static bool is_freq_dbs_or_sbs(struct wlan_objmgr_psoc *psoc, 1831 qdf_freq_t freq_1, 1832 qdf_freq_t freq_2) 1833 { 1834 return !policy_mgr_2_freq_always_on_same_mac(psoc, freq_1, freq_2); 1835 } 1836 1837 #else 1838 static inline 1839 uint8_t cm_get_sta_mlo_conn_max_num(struct wlan_objmgr_psoc *psoc) 1840 { 1841 return WLAN_UMAC_MLO_MAX_DEV; 1842 } 1843 1844 static inline bool is_freq_dbs_or_sbs(struct wlan_objmgr_psoc *psoc, 1845 qdf_freq_t freq_1, 1846 qdf_freq_t freq_2) 1847 { 1848 return false; 1849 } 1850 #endif 1851 1852 /** 1853 * cm_bss_mlo_type() - Get mlo type of bss scan entry 1854 * @psoc: Pointer of psoc object 1855 * @entry: Bss scan entry 1856 * @scan_list: 1857 * 1858 * Return: MLO AP type: SLO, MLMR or EMLSR. 1859 */ 1860 enum MLO_TYPE cm_bss_mlo_type(struct wlan_objmgr_psoc *psoc, 1861 struct scan_cache_entry *entry, 1862 qdf_list_t *scan_list) 1863 { 1864 uint8_t mlo_link_num; 1865 uint8_t i; 1866 uint32_t freq_entry; 1867 uint32_t freq[MLD_MAX_LINKS - 1]; 1868 struct scan_cache_entry *entry_partner[MLD_MAX_LINKS - 1]; 1869 bool multi_link = false; 1870 1871 mlo_link_num = cm_get_sta_mlo_conn_max_num(psoc); 1872 if (!entry->ie_list.multi_link_bv) 1873 return SLO; 1874 else if (!entry->ml_info.num_links) 1875 return SLO; 1876 else if (mlo_link_num == 1) 1877 return SLO; 1878 1879 for (i = 0; i < entry->ml_info.num_links; i++) { 1880 if (!entry->ml_info.link_info[i].is_valid_link) 1881 continue; 1882 freq_entry = entry->channel.chan_freq; 1883 freq[i] = entry->ml_info.link_info[i].freq; 1884 entry_partner[i] = 1885 cm_get_entry(scan_list, 1886 &entry->ml_info.link_info[i].link_addr); 1887 if (entry_partner[i]) 1888 freq[i] = entry_partner[i]->channel.chan_freq; 1889 if (is_freq_dbs_or_sbs(psoc, freq[i], freq_entry)) { 1890 return MLMR; 1891 } else if (freq[i] == freq_entry) { 1892 mlme_debug("Partner " QDF_MAC_ADDR_FMT 1893 " freq %d same as assoc freq, invalid it", 1894 QDF_MAC_ADDR_REF(entry->ml_info.link_info[i].link_addr.bytes), 1895 freq[i]); 1896 entry->ml_info.link_info[i].is_valid_link = false; 1897 } else { 1898 multi_link = true; 1899 } 1900 } 1901 1902 if (multi_link) 1903 return MLSR; 1904 else 1905 return SLO; 1906 } 1907 1908 /** 1909 * cm_get_mlo_congestion_score() - Get mlo jointer congestion percent 1910 * @bw1: channel width of link1 1911 * @bw2: channel width of link2 1912 * @congestion_score1: congestion score of link1 1913 * @congestion_score2: congestion score of link2 1914 * @score_params: score param 1915 * 1916 * Return: Mlo jointer congestion percent 1917 */ 1918 static uint32_t 1919 cm_get_mlo_congestion_score(uint16_t bw1, 1920 uint16_t bw2, 1921 uint32_t congestion_score1, 1922 uint32_t congestion_score2, 1923 struct scoring_cfg *score_params) 1924 { 1925 uint32_t congestion_best; 1926 uint32_t congestion_worst; 1927 uint32_t congestion_weight; 1928 1929 congestion_weight = 1930 score_params->weight_config.channel_congestion_weightage; 1931 if (congestion_score1 > congestion_score2) { 1932 congestion_best = congestion_score1; 1933 congestion_worst = congestion_score2 * bw1 / (bw1 + bw2); 1934 } else if (congestion_score1 < congestion_score2) { 1935 congestion_best = congestion_score2; 1936 congestion_worst = congestion_score1 * bw2 / (bw1 + bw2); 1937 } else { 1938 congestion_best = congestion_score1; 1939 congestion_worst = congestion_score2 / 2; 1940 } 1941 congestion_best = congestion_best * CM_SLO_CONGESTION_MAX_SCORE / 1942 CM_MAX_PCT_SCORE; 1943 congestion_worst = congestion_worst * CM_SLO_CONGESTION_MAX_SCORE / 1944 CM_MAX_PCT_SCORE; 1945 congestion_worst = QDF_MIN(congestion_worst, 20 * congestion_weight); 1946 1947 return congestion_best + congestion_worst; 1948 } 1949 1950 /** 1951 * cm_estimate_rssi() - Get estimated rssi by frequency 1952 * @rssi_entry: Rssi of bss scan entry 1953 * @freq_entry: Frequency of bss scan entry 1954 * @freq_partner: Frequency of partner link of MLO 1955 * 1956 * Estimated equation: RSSI(2G) = RSSI(5G) + 7 = RSSI(6G) + 8 1957 * 1958 * Return: Estimated rssi of partner link of MLO 1959 */ 1960 static int8_t cm_estimate_rssi(int8_t rssi_entry, uint32_t freq_entry, 1961 uint32_t freq_partner) 1962 { 1963 if (wlan_reg_is_24ghz_ch_freq(freq_entry)) { 1964 if (wlan_reg_is_5ghz_ch_freq(freq_partner)) 1965 return rssi_entry - 7; 1966 else if (wlan_reg_is_6ghz_chan_freq(freq_partner)) 1967 return rssi_entry - 8; 1968 } else if (wlan_reg_is_5ghz_ch_freq(freq_entry)) { 1969 if (wlan_reg_is_24ghz_ch_freq(freq_partner)) 1970 return rssi_entry + 7; 1971 else if (wlan_reg_is_6ghz_chan_freq(freq_partner)) 1972 return rssi_entry - 1; 1973 } else if (wlan_reg_is_6ghz_chan_freq(freq_entry)) { 1974 if (wlan_reg_is_24ghz_ch_freq(freq_partner)) 1975 return rssi_entry + 8; 1976 else if (wlan_reg_is_5ghz_ch_freq(freq_partner)) 1977 return rssi_entry + 1; 1978 } 1979 1980 return rssi_entry; 1981 } 1982 1983 static int cm_calculate_bss_score(struct wlan_objmgr_psoc *psoc, 1984 struct scan_cache_entry *entry, 1985 int pcl_chan_weight, 1986 struct qdf_mac_addr *bssid_hint, 1987 qdf_list_t *scan_list, 1988 uint8_t ml_flag); 1989 1990 /** 1991 * cm_calculate_mlo_bss_score() - Calculate mlo bss score 1992 * @psoc: Pointer to psoc object 1993 * @entry: Bss scan entry 1994 * @score_params: score parameters 1995 * @phy_config: Phy config 1996 * @scan_list: Scan entry list of bss candidates after filtering 1997 * @rssi_prorated_pct: Rssi prorated percent 1998 * @pcl_chan_weight: PCL chan weight 1999 * 2000 * For MLMR case, besides adding MLMR boost score, 2001 * calculate joint RSSI/band width/congestion score for combination of 2002 * scan entry + each partner link, select highest total score as candidate 2003 * combination, only activate that partner link. 2004 * 2005 * Return: MLO AP joint total score 2006 */ 2007 static int cm_calculate_mlo_bss_score(struct wlan_objmgr_psoc *psoc, 2008 struct scan_cache_entry *entry, 2009 struct scoring_cfg *score_params, 2010 struct psoc_phy_config *phy_config, 2011 qdf_list_t *scan_list, 2012 uint8_t *rssi_prorated_pct, 2013 int pcl_chan_weight) 2014 { 2015 struct scan_cache_entry *entry_partner[MLD_MAX_LINKS - 1]; 2016 int32_t rssi[MLD_MAX_LINKS - 1]; 2017 uint32_t rssi_score[MLD_MAX_LINKS - 1] = {}; 2018 uint16_t prorated_pct[MLD_MAX_LINKS - 1] = {}; 2019 uint32_t freq[MLD_MAX_LINKS - 1]; 2020 uint16_t ch_width[MLD_MAX_LINKS - 1]; 2021 uint32_t bandwidth_score[MLD_MAX_LINKS - 1] = {}; 2022 uint32_t congestion_pct[MLD_MAX_LINKS - 1] = {}; 2023 uint32_t congestion_score[MLD_MAX_LINKS - 1] = {}; 2024 uint32_t cong_total_score[MLD_MAX_LINKS - 1] = {}; 2025 uint32_t total_score[MLD_MAX_LINKS - 1] = {}; 2026 uint8_t i, j; 2027 uint16_t chan_width; 2028 uint32_t best_total_score = 0; 2029 uint8_t best_partner_index = 0; 2030 uint32_t cong_pct = 0; 2031 uint32_t cong_score = 0; 2032 uint32_t freq_entry; 2033 struct weight_cfg *weight_config; 2034 struct partner_link_info *link; 2035 struct wlan_objmgr_pdev *pdev; 2036 bool rssi_bad_zone; 2037 bool eht_capab; 2038 struct partner_link_info tmp_link_info; 2039 uint32_t tmp_total_score = 0; 2040 uint32_t assoc_score = 0; 2041 uint32_t link_score[MLD_MAX_LINKS - 1] = {0}; 2042 bool is_assoc_link_best = true; 2043 uint32_t assoc_band_score; 2044 uint32_t link_band_score[MLD_MAX_LINKS - 1] = {0}; 2045 uint32_t total_band_score[MLD_MAX_LINKS - 1] = {0}; 2046 2047 wlan_psoc_mlme_get_11be_capab(psoc, &eht_capab); 2048 if (!eht_capab) 2049 return 0; 2050 2051 weight_config = &score_params->weight_config; 2052 freq_entry = entry->channel.chan_freq; 2053 chan_width = cm_get_ch_width(entry, phy_config); 2054 cong_score = cm_calculate_congestion_score(entry, 2055 score_params, 2056 &cong_pct, false); 2057 2058 assoc_score = 2059 cm_calculate_bss_score(psoc, entry, pcl_chan_weight, 2060 NULL, scan_list, LINK_SCORE | ASSOC_LINK); 2061 entry->ml_info.link_score = assoc_score; 2062 2063 assoc_band_score = cm_get_band_score(entry->channel.chan_freq, 2064 score_params); 2065 2066 link = &entry->ml_info.link_info[0]; 2067 for (i = 0; i < entry->ml_info.num_links; i++) { 2068 if (!link[i].is_valid_link) 2069 continue; 2070 entry_partner[i] = cm_get_entry(scan_list, &link[i].link_addr); 2071 if (entry_partner[i]) 2072 freq[i] = entry_partner[i]->channel.chan_freq; 2073 else 2074 freq[i] = link[i].freq; 2075 if (!is_freq_dbs_or_sbs(psoc, freq[i], freq_entry)) { 2076 mlme_nofl_debug("freq %d and %d can't be MLMR", 2077 freq[i], freq_entry); 2078 continue; 2079 } 2080 2081 if (entry_partner[i]) { 2082 link_score[i] = 2083 cm_calculate_bss_score(psoc, entry_partner[i], 2084 pcl_chan_weight, 2085 NULL, scan_list, LINK_SCORE); 2086 entry_partner[i]->ml_info.link_score = link_score[i]; 2087 2088 rssi[i] = entry_partner[i]->rssi_raw; 2089 ch_width[i] = cm_get_ch_width(entry_partner[i], 2090 phy_config); 2091 } else { 2092 rssi[i] = cm_estimate_rssi(entry->rssi_raw, 2093 freq_entry, 2094 freq[i]); 2095 pdev = psoc->soc_objmgr.wlan_pdev_list[0]; 2096 ch_width[i] = 2097 wlan_reg_get_op_class_width(pdev, 2098 link[i].op_class, 2099 true); 2100 mlme_nofl_debug("No entry for partner, estimate with rnr"); 2101 } 2102 rssi_score[i] = 2103 cm_get_mlo_rssi_score(weight_config->rssi_weightage, 2104 entry->rssi_raw, rssi[i], 2105 &prorated_pct[i]); 2106 2107 bandwidth_score[i] = 2108 cm_get_bw_score(weight_config->chan_width_weightage, 2109 chan_width + ch_width[i], 2110 prorated_pct[i]); 2111 2112 rssi_bad_zone = prorated_pct[i] < CM_MAX_PCT_SCORE; 2113 congestion_score[i] = 2114 cm_calculate_congestion_score(entry_partner[i], 2115 score_params, 2116 &congestion_pct[i], 2117 rssi_bad_zone); 2118 cong_total_score[i] = 2119 cm_get_mlo_congestion_score(chan_width, 2120 ch_width[i], 2121 cong_score, 2122 congestion_score[i], 2123 score_params); 2124 2125 link_band_score[i] = cm_get_band_score(freq[i], score_params); 2126 total_band_score[i] = 2127 (assoc_band_score + link_band_score[i]) / 2; 2128 2129 total_score[i] = rssi_score[i] + bandwidth_score[i] + 2130 cong_total_score[i] + total_band_score[i]; 2131 if (total_score[i] > best_total_score) { 2132 best_total_score = total_score[i]; 2133 best_partner_index = i; 2134 } 2135 2136 mlme_nofl_debug("ML idx %d score: freq (%d + %d) rssi %u pror %u bw %u congest %u %u %u band score: %u %u total %u", 2137 i, freq_entry, freq[i], rssi_score[i], 2138 prorated_pct[i], bandwidth_score[i], cong_score, 2139 congestion_score[i], cong_total_score[i], 2140 assoc_band_score, link_band_score[i], 2141 total_score[i]); 2142 } 2143 2144 *rssi_prorated_pct = prorated_pct[best_partner_index]; 2145 2146 /* reorder the link idx per score */ 2147 for (j = 0; j < entry->ml_info.num_links; j++) { 2148 tmp_total_score = total_score[j]; 2149 best_partner_index = j; 2150 for (i = j + 1; i < entry->ml_info.num_links; i++) { 2151 if (tmp_total_score < total_score[i]) { 2152 tmp_total_score = total_score[i]; 2153 best_partner_index = i; 2154 } 2155 } 2156 2157 if (best_partner_index != j) { 2158 tmp_link_info = entry->ml_info.link_info[j]; 2159 entry->ml_info.link_info[j] = 2160 entry->ml_info.link_info[best_partner_index]; 2161 entry->ml_info.link_info[best_partner_index] = 2162 tmp_link_info; 2163 total_score[best_partner_index] = total_score[j]; 2164 } 2165 total_score[j] = 0; 2166 } 2167 2168 for (i = 0; i < entry->ml_info.num_links; i++) { 2169 if (link_score[i] > assoc_score) { 2170 is_assoc_link_best = false; 2171 break; 2172 } 2173 } 2174 if (is_assoc_link_best) { 2175 mlme_nofl_debug("assoc link (freq %d) is best, boost %d", 2176 freq_entry, CM_ASSOC_INK_BEST_BOOST); 2177 best_total_score += CM_ASSOC_INK_BEST_BOOST; 2178 } 2179 2180 best_total_score += weight_config->mlo_weightage * 2181 mlo_boost_pct[MLMR]; 2182 entry->ml_info.ml_bss_score = best_total_score; 2183 2184 return best_total_score; 2185 } 2186 2187 #else 2188 static inline int cm_calculate_emlsr_score(struct weight_cfg *weight_config) 2189 { 2190 return 0; 2191 } 2192 2193 static int cm_calculate_mlo_bss_score(struct wlan_objmgr_psoc *psoc, 2194 struct scan_cache_entry *entry, 2195 struct scoring_cfg *score_params, 2196 struct psoc_phy_config *phy_config, 2197 qdf_list_t *scan_list, 2198 uint8_t *rssi_prorated_pct, 2199 int pcl_chan_weight) 2200 { 2201 return 0; 2202 } 2203 #endif 2204 2205 #if defined(WLAN_FEATURE_11BE_MLO) && defined(CONN_MGR_ADV_FEATURE) 2206 static void 2207 cm_sort_vendor_algo_mlo_bss_entry(struct wlan_objmgr_psoc *psoc, 2208 struct scan_cache_entry *entry, 2209 struct psoc_phy_config *phy_config, 2210 qdf_list_t *scan_list, 2211 enum MLO_TYPE bss_mlo_type) 2212 { 2213 struct scan_cache_entry *entry_partner[MLD_MAX_LINKS - 1]; 2214 uint32_t freq[MLD_MAX_LINKS - 1]; 2215 uint32_t etp_score[MLD_MAX_LINKS - 1] = {0}; 2216 uint32_t total_score[MLD_MAX_LINKS - 1] = {0}; 2217 uint8_t i, j; 2218 uint32_t best_total_score = 0; 2219 uint8_t best_partner_index = 0; 2220 uint32_t freq_entry; 2221 struct partner_link_info *link; 2222 bool eht_capab; 2223 struct partner_link_info tmp_link_info; 2224 uint32_t tmp_total_score = 0; 2225 uint8_t mlo_support_link_num; 2226 2227 wlan_psoc_mlme_get_11be_capab(psoc, &eht_capab); 2228 if (!eht_capab) 2229 return; 2230 2231 mlo_support_link_num = wlan_mlme_get_sta_mlo_conn_max_num(psoc); 2232 link = &entry->ml_info.link_info[0]; 2233 freq_entry = entry->channel.chan_freq; 2234 for (i = 0; i < entry->ml_info.num_links; i++) { 2235 if (!link[i].is_valid_link) 2236 continue; 2237 2238 entry_partner[i] = cm_get_entry(scan_list, &link[i].link_addr); 2239 if (entry_partner[i]) 2240 freq[i] = entry_partner[i]->channel.chan_freq; 2241 else 2242 freq[i] = link[i].freq; 2243 2244 if (policy_mgr_2_freq_always_on_same_mac(psoc, freq[i], 2245 freq_entry)) { 2246 total_score[i] = 0; 2247 if (!wlan_mlme_is_5gl_5gh_mlsr_supported(psoc)) { 2248 mlme_nofl_debug("Partner(" QDF_MAC_ADDR_FMT " freq %d): assoc freq %d can't be MLMR", 2249 QDF_MAC_ADDR_REF(link[i].link_addr.bytes), 2250 freq[i], freq_entry); 2251 if (mlo_support_link_num <= WLAN_MAX_ML_DEFAULT_LINK || 2252 entry->ml_info.num_links < 2253 WLAN_MAX_ML_DEFAULT_LINK) 2254 link[i].is_valid_link = false; 2255 } 2256 continue; 2257 } 2258 2259 if (!entry_partner[i]) 2260 continue; 2261 2262 etp_score[i] = cm_calculate_etp_score(psoc, entry_partner[i], 2263 phy_config, bss_mlo_type, 2264 0); 2265 2266 total_score[i] = etp_score[i]; 2267 if (total_score[i] > best_total_score) { 2268 best_total_score = total_score[i]; 2269 best_partner_index = i; 2270 } 2271 } 2272 2273 /* reorder the link idx per score */ 2274 for (j = 0; j < entry->ml_info.num_links; j++) { 2275 tmp_total_score = total_score[j]; 2276 best_partner_index = j; 2277 for (i = j + 1; i < entry->ml_info.num_links; i++) { 2278 if (tmp_total_score < total_score[i]) { 2279 tmp_total_score = total_score[i]; 2280 best_partner_index = i; 2281 } 2282 } 2283 2284 if (best_partner_index != j) { 2285 tmp_link_info = entry->ml_info.link_info[j]; 2286 entry->ml_info.link_info[j] = 2287 entry->ml_info.link_info[best_partner_index]; 2288 entry->ml_info.link_info[best_partner_index] = 2289 tmp_link_info; 2290 total_score[best_partner_index] = total_score[j]; 2291 } 2292 total_score[j] = 0; 2293 } 2294 } 2295 #else 2296 static void 2297 cm_sort_vendor_algo_mlo_bss_entry(struct wlan_objmgr_psoc *psoc, 2298 struct scan_cache_entry *entry, 2299 struct psoc_phy_config *phy_config, 2300 qdf_list_t *scan_list, 2301 enum MLO_TYPE bss_mlo_type) 2302 {} 2303 #endif 2304 2305 /** 2306 * cm_calculate_ml_scores() - Calculate mlo score of AP 2307 * @psoc: Pointer to psoc object 2308 * @entry: Bss scan entry 2309 * @score_config: Score config 2310 * @phy_config: Self phy config 2311 * @scan_list: Scan entry list of bss candidates after filtering 2312 * @ml_flag: MLO flag 2313 * @bss_mlo_type: Bss MLO type 2314 * @pcl_chan_weight: PCL channel weight 2315 * @rssi_prorated_pct: RSSI prorated pencentage 2316 * 2317 * For MLO AP, consider partner link to calculate combined score, 2318 * For legacy/SLO AP or link, get total score of RSSI, bandwidth, 2319 * congestion and band. 2320 * 2321 * Return: MLO score of AP 2322 */ 2323 static int cm_calculate_ml_scores(struct wlan_objmgr_psoc *psoc, 2324 struct scan_cache_entry *entry, 2325 struct scoring_cfg *score_config, 2326 struct psoc_phy_config *phy_config, 2327 qdf_list_t *scan_list, uint8_t ml_flag, 2328 enum MLO_TYPE bss_mlo_type, 2329 int pcl_chan_weight, 2330 uint8_t *rssi_prorated_pct) 2331 { 2332 int32_t score = 0; 2333 int32_t rssi_score = 0; 2334 int32_t congestion_pct = 0; 2335 int32_t bandwidth_score = 0; 2336 int32_t congestion_score = 0; 2337 uint8_t prorated_pcnt = 0; 2338 int32_t band_score = 0; 2339 struct weight_cfg *weight_config; 2340 2341 weight_config = &score_config->weight_config; 2342 if (IS_LINK_SCORE(ml_flag) || bss_mlo_type == SLO || 2343 bss_mlo_type == MLSR || 2344 !wlan_cm_is_eht_allowed_for_current_security(psoc, entry, false)) { 2345 rssi_score = 2346 cm_calculate_rssi_score(&score_config->rssi_score, 2347 entry->rssi_raw, 2348 weight_config->rssi_weightage); 2349 prorated_pcnt = 2350 cm_get_rssi_prorate_pct(&score_config->rssi_score, 2351 entry->rssi_raw, 2352 weight_config->rssi_weightage); 2353 score += rssi_score; 2354 bandwidth_score = 2355 cm_get_bw_score(weight_config->chan_width_weightage, 2356 cm_get_ch_width(entry, phy_config), 2357 prorated_pcnt); 2358 score += bandwidth_score; 2359 2360 congestion_score = 2361 cm_calculate_congestion_score(entry, 2362 score_config, 2363 &congestion_pct, 0); 2364 score += congestion_score * CM_SLO_CONGESTION_MAX_SCORE / 2365 CM_MAX_PCT_SCORE; 2366 2367 band_score = cm_get_band_score(entry->channel.chan_freq, 2368 score_config); 2369 score += band_score; 2370 2371 if (bss_mlo_type == MLSR) 2372 score += cm_calculate_emlsr_score(weight_config); 2373 } else { 2374 score += cm_calculate_mlo_bss_score(psoc, entry, score_config, 2375 phy_config, scan_list, 2376 &prorated_pcnt, 2377 pcl_chan_weight); 2378 } 2379 2380 *rssi_prorated_pct = prorated_pcnt; 2381 2382 return score; 2383 } 2384 2385 static bool 2386 cm_check_and_update_bssid_hint_entry_bss_score(struct scan_cache_entry *entry, 2387 struct scoring_cfg *score_config, 2388 struct qdf_mac_addr *bssid_hint, 2389 uint8_t ml_flag) 2390 { 2391 if (!score_config->is_bssid_hint_priority) 2392 return false; 2393 2394 if (!bssid_hint || !qdf_is_macaddr_equal(bssid_hint, &entry->bssid)) 2395 return false; 2396 2397 entry->bss_score = entry->bss_score + CM_BEST_CANDIDATE_MAX_BSS_SCORE; 2398 mlme_nofl_debug("%s("QDF_MAC_ADDR_FMT" freq %d): rssi %d BSSID hint given, give max score %d", 2399 IS_ASSOC_LINK(ml_flag) ? "Candidate" : "Partner", 2400 QDF_MAC_ADDR_REF(entry->bssid.bytes), 2401 entry->channel.chan_freq, entry->rssi_raw, 2402 entry->bss_score); 2403 return true; 2404 } 2405 2406 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE 2407 static void cm_vendor_specific_boost(struct wlan_objmgr_psoc *psoc, 2408 struct scan_cache_entry *entry, 2409 int32_t score) 2410 { 2411 struct partner_link_info *link = NULL; 2412 uint32_t freq = 0; 2413 uint32_t freq_entry = 0; 2414 2415 /* Add boost of 20% for 2 link candidate */ 2416 if (entry->ml_info.num_links == TWO_LINK) 2417 score = score + (score * TWO_LINK_BOOST) / 100; 2418 2419 if (entry->ml_info.num_links == ONE_LINK) { 2420 freq_entry = entry->channel.chan_freq; 2421 link = &entry->ml_info.link_info[0]; 2422 2423 if (!link[0].is_valid_link) 2424 return; 2425 2426 freq = link[0].freq; 2427 2428 /* Add boost of 10% for one link MLMR candidate */ 2429 if (!policy_mgr_are_2_freq_on_same_mac(psoc, 2430 freq, 2431 freq_entry)) 2432 score = score + (score * ONE_LINK_MLMR_BOOST) / 100; 2433 } 2434 2435 entry->bss_score = score; 2436 } 2437 #else 2438 static void cm_vendor_specific_boost(struct wlan_objmgr_psoc *psoc, 2439 struct scan_cache_entry *entry, 2440 int32_t score) 2441 { 2442 } 2443 #endif 2444 2445 /** 2446 * cm_calculate_bss_score() - Calculate score of AP or 1 link of MLO AP 2447 * @psoc: Pointer to psoc object 2448 * @entry: Bss scan entry 2449 * @pcl_chan_weight: pcl chan weight 2450 * @bssid_hint: bssid hint 2451 * @scan_list: Scan entry list of bss candidates after filtering 2452 * @ml_flag: ML related bitmap 2453 * BIT(0): SET, if score is for link. 2454 * BIT(1): SET, if it is for Assoc link. 2455 * 2456 * For MLO AP, consider partner link to calculate combined score, prefer to 2457 * select best link as assoc link. 2458 * For legacy AP or 1 link of MLO AP, just consider single link. 2459 * Prefer to select AP of higher score to connect by sort AP by score. 2460 * 2461 * Return: score of AP or 1 link of MLO AP 2462 */ 2463 static int cm_calculate_bss_score(struct wlan_objmgr_psoc *psoc, 2464 struct scan_cache_entry *entry, 2465 int pcl_chan_weight, 2466 struct qdf_mac_addr *bssid_hint, 2467 qdf_list_t *scan_list, 2468 uint8_t ml_flag) 2469 { 2470 int32_t score = 0; 2471 int32_t rssi_score = 0; 2472 int32_t pcl_score = 0; 2473 int32_t ht_score = 0; 2474 int32_t vht_score = 0; 2475 int32_t he_score = 0; 2476 int32_t bandwidth_score = 0; 2477 int32_t beamformee_score = 0; 2478 int32_t band_score = 0; 2479 int32_t nss_score = 0; 2480 int32_t security_score = 0; 2481 int32_t congestion_score = 0; 2482 int32_t congestion_pct = 0; 2483 int32_t oce_wan_score = 0; 2484 uint8_t oce_ap_tx_pwr_score = 0; 2485 uint8_t oce_subnet_id_score = 0; 2486 uint32_t sae_pk_score = 0; 2487 bool oce_subnet_id_present = 0; 2488 bool sae_pk_cap_present = 0; 2489 int8_t ap_tx_pwr_dbm = 0; 2490 uint8_t prorated_pcnt = 0; 2491 bool is_vht = false; 2492 int8_t good_rssi_threshold; 2493 int8_t rssi_pref_5g_rssi_thresh; 2494 bool same_bucket = false; 2495 bool ap_su_beam_former = false; 2496 struct wlan_ie_vhtcaps *vht_cap; 2497 struct wlan_ie_hecaps *he_cap; 2498 struct scoring_cfg *score_config; 2499 struct weight_cfg *weight_config; 2500 uint32_t sta_nss; 2501 struct psoc_mlme_obj *mlme_psoc_obj; 2502 struct psoc_phy_config *phy_config; 2503 uint32_t eht_score; 2504 enum MLO_TYPE bss_mlo_type; 2505 int ml_score = 0; 2506 2507 mlme_psoc_obj = wlan_psoc_mlme_get_cmpt_obj(psoc); 2508 if (!mlme_psoc_obj) 2509 return 0; 2510 2511 phy_config = &mlme_psoc_obj->psoc_cfg.phy_config; 2512 score_config = &mlme_psoc_obj->psoc_cfg.score_config; 2513 weight_config = &score_config->weight_config; 2514 2515 bss_mlo_type = cm_bss_mlo_type(psoc, entry, scan_list); 2516 if (score_config->vendor_roam_score_algorithm) { 2517 score = cm_calculate_etp_score(psoc, entry, phy_config, 2518 bss_mlo_type, ml_flag); 2519 entry->bss_score = score; 2520 if (bss_mlo_type == MLMR || bss_mlo_type == MLSR) 2521 cm_sort_vendor_algo_mlo_bss_entry(psoc, entry, 2522 phy_config, scan_list, 2523 bss_mlo_type); 2524 /* vendor specific boost */ 2525 cm_vendor_specific_boost(psoc, entry, score); 2526 2527 if (cm_check_and_update_bssid_hint_entry_bss_score(entry, 2528 score_config, 2529 bssid_hint, 2530 ml_flag)) 2531 return CM_BEST_CANDIDATE_MAX_BSS_SCORE; 2532 2533 mlme_nofl_debug("Candidate score("QDF_MAC_ADDR_FMT" freq %d): rssi %d score %d", 2534 QDF_MAC_ADDR_REF(entry->bssid.bytes), 2535 entry->channel.chan_freq, 2536 entry->rssi_raw, entry->bss_score); 2537 2538 return score; 2539 } 2540 2541 ml_score += cm_calculate_ml_scores(psoc, entry, score_config, 2542 phy_config, scan_list, 2543 ml_flag, bss_mlo_type, 2544 pcl_chan_weight, 2545 &prorated_pcnt); 2546 score += ml_score; 2547 2548 /* 2549 * Check if the given entry matches with the BSSID Hint after 2550 * calculating ML Scores as the cm_calculate_ml_scores() also sorts 2551 * the partner links based on hw mode capabilities & link scores 2552 */ 2553 if (cm_check_and_update_bssid_hint_entry_bss_score(entry, score_config, 2554 bssid_hint, ml_flag)) 2555 return CM_BEST_CANDIDATE_MAX_BSS_SCORE; 2556 2557 pcl_score = cm_calculate_pcl_score(psoc, pcl_chan_weight, 2558 weight_config->pcl_weightage); 2559 score += pcl_score; 2560 2561 /* 2562 * Add HT weight if HT is supported by the AP. In case 2563 * of 6 GHZ AP, HT and VHT won't be supported so that 2564 * these weightage to the same by default to match 2565 * with 2.4/5 GHZ APs where HT, VHT is supported 2566 */ 2567 if (phy_config->ht_cap && (entry->ie_list.htcap || 2568 WLAN_REG_IS_6GHZ_CHAN_FREQ(entry->channel.chan_freq))) 2569 ht_score = prorated_pcnt * 2570 weight_config->ht_caps_weightage; 2571 score += ht_score; 2572 2573 if (WLAN_REG_IS_24GHZ_CH_FREQ(entry->channel.chan_freq)) { 2574 if (phy_config->vht_24G_cap) 2575 is_vht = true; 2576 } else if (phy_config->vht_cap) { 2577 is_vht = true; 2578 } 2579 2580 /* Add VHT score to 6 GHZ AP to match with 2.4/5 GHZ APs */ 2581 if (is_vht && (entry->ie_list.vhtcap || 2582 WLAN_REG_IS_6GHZ_CHAN_FREQ(entry->channel.chan_freq))) 2583 vht_score = prorated_pcnt * 2584 weight_config->vht_caps_weightage; 2585 score += vht_score; 2586 2587 if (phy_config->he_cap && entry->ie_list.hecap) 2588 he_score = prorated_pcnt * 2589 weight_config->he_caps_weightage; 2590 score += he_score; 2591 2592 good_rssi_threshold = 2593 score_config->rssi_score.good_rssi_threshold * (-1); 2594 rssi_pref_5g_rssi_thresh = 2595 score_config->rssi_score.rssi_pref_5g_rssi_thresh * (-1); 2596 if (entry->rssi_raw < good_rssi_threshold) 2597 same_bucket = cm_rssi_is_same_bucket(good_rssi_threshold, 2598 entry->rssi_raw, rssi_pref_5g_rssi_thresh, 2599 score_config->rssi_score.bad_rssi_bucket_size); 2600 2601 vht_cap = (struct wlan_ie_vhtcaps *)util_scan_entry_vhtcap(entry); 2602 he_cap = (struct wlan_ie_hecaps *)util_scan_entry_hecap(entry); 2603 2604 if (vht_cap && vht_cap->su_beam_former) { 2605 ap_su_beam_former = true; 2606 } else if (he_cap && QDF_GET_BITS(*(he_cap->he_phy_cap.phy_cap_bytes + 2607 WLAN_HE_PHYCAP_SU_BFER_OFFSET), WLAN_HE_PHYCAP_SU_BFER_IDX, 2608 WLAN_HE_PHYCAP_SU_BFER_BITS)) { 2609 ap_su_beam_former = true; 2610 } else { 2611 ap_su_beam_former = cm_get_su_beam_former(entry); 2612 } 2613 2614 if (phy_config->beamformee_cap && is_vht && 2615 ap_su_beam_former && 2616 (entry->rssi_raw > rssi_pref_5g_rssi_thresh) && !same_bucket) 2617 beamformee_score = CM_MAX_PCT_SCORE * 2618 weight_config->beamforming_cap_weightage; 2619 score += beamformee_score; 2620 2621 /* 2622 * Consider OCE WAN score score only if 2623 * congestion_pct is greater than CONGESTION_THRSHOLD_FOR_BAND_OCE_SCORE 2624 */ 2625 if (congestion_pct < CM_CONGESTION_THRSHOLD_FOR_BAND_OCE_SCORE) { 2626 oce_wan_score = cm_calculate_oce_wan_score(entry, score_config); 2627 score += oce_wan_score; 2628 } 2629 2630 oce_ap_tx_pwr_score = 2631 cm_calculate_oce_ap_tx_pwr_weightage(entry, score_config, 2632 &ap_tx_pwr_dbm); 2633 score += oce_ap_tx_pwr_score; 2634 2635 oce_subnet_id_score = cm_calculate_oce_subnet_id_weightage(entry, 2636 score_config, 2637 &oce_subnet_id_present); 2638 score += oce_subnet_id_score; 2639 2640 sae_pk_score = cm_calculate_sae_pk_ap_weightage(entry, score_config, 2641 &sae_pk_cap_present); 2642 score += sae_pk_score; 2643 2644 sta_nss = cm_get_sta_nss(psoc, entry->channel.chan_freq, 2645 phy_config->vdev_nss_24g, 2646 phy_config->vdev_nss_5g); 2647 2648 /* 2649 * If station support nss as 2*2 but AP support NSS as 1*1, 2650 * this AP will be given half weight compare to AP which are having 2651 * NSS as 2*2. 2652 */ 2653 nss_score = cm_calculate_nss_score(psoc, score_config, entry->nss, 2654 prorated_pcnt, sta_nss); 2655 score += nss_score; 2656 2657 /* 2658 * Since older FW will stick to the single AKM for roaming, 2659 * no need to check the fw capability. 2660 */ 2661 security_score = cm_calculate_security_score(score_config, 2662 entry->neg_sec_info); 2663 score += security_score; 2664 2665 eht_score = cm_calculate_eht_score(psoc, entry, score_config, 2666 phy_config, 2667 prorated_pcnt); 2668 score += eht_score; 2669 2670 if (!(IS_LINK_SCORE(ml_flag))) 2671 entry->bss_score = score; 2672 2673 if (bss_mlo_type == SLO || IS_LINK_SCORE(ml_flag)) 2674 mlme_nofl_debug("%s("QDF_MAC_ADDR_FMT" freq %d): rssi %d HT %d VHT %d HE %d EHT %d su_bfer %d phy %d atf %d qbss %d cong_pct %d NSS %d ap_tx_pwr %d oce_subnet %d sae_pk_cap %d prorated_pcnt %d keymgmt 0x%x mlo type %d", 2675 IS_ASSOC_LINK(ml_flag) ? "Candidate" : "Partner", 2676 QDF_MAC_ADDR_REF(entry->bssid.bytes), 2677 entry->channel.chan_freq, 2678 entry->rssi_raw, 2679 util_scan_entry_htcap(entry) ? 1 : 0, 2680 util_scan_entry_vhtcap(entry) ? 1 : 0, 2681 util_scan_entry_hecap(entry) ? 1 : 0, 2682 util_scan_entry_ehtcap(entry) ? 1 : 0, 2683 ap_su_beam_former, 2684 entry->phy_mode, entry->air_time_fraction, 2685 entry->qbss_chan_load, congestion_pct, 2686 entry->nss, ap_tx_pwr_dbm, 2687 oce_subnet_id_present, sae_pk_cap_present, 2688 prorated_pcnt, entry->neg_sec_info.key_mgmt, 2689 bss_mlo_type); 2690 2691 mlme_nofl_debug("%s score("QDF_MAC_ADDR_FMT" freq %d): rssi %d pcl %d ht %d vht %d he %d bfee %d bw %d band %d cong %d nss %d oce_wan %d oce_ap_pwr %d oce_subnet %d sae_pk %d eht %d security %d ml %d TOTAL %d", 2692 IS_LINK_SCORE(ml_flag) ? "Link" : "Candidate", 2693 QDF_MAC_ADDR_REF(entry->bssid.bytes), 2694 entry->channel.chan_freq, 2695 rssi_score, pcl_score, ht_score, 2696 vht_score, he_score, beamformee_score, bandwidth_score, 2697 band_score, congestion_score, nss_score, oce_wan_score, 2698 oce_ap_tx_pwr_score, oce_subnet_id_score, 2699 sae_pk_score, eht_score, security_score, ml_score, 2700 score); 2701 2702 return score; 2703 } 2704 2705 static void cm_list_insert_sorted(qdf_list_t *scan_list, 2706 struct scan_cache_node *scan_entry) 2707 { 2708 qdf_list_node_t *cur_node = NULL, *next_node = NULL; 2709 struct scan_cache_node *curr_entry; 2710 2711 qdf_list_peek_front(scan_list, &cur_node); 2712 while (cur_node) { 2713 curr_entry = qdf_container_of(cur_node, struct scan_cache_node, 2714 node); 2715 if (cm_is_better_bss(scan_entry->entry, curr_entry->entry)) { 2716 qdf_list_insert_before(scan_list, &scan_entry->node, 2717 &curr_entry->node); 2718 break; 2719 } 2720 qdf_list_peek_next(scan_list, cur_node, &next_node); 2721 cur_node = next_node; 2722 next_node = NULL; 2723 } 2724 2725 if (!cur_node) 2726 qdf_list_insert_back(scan_list, &scan_entry->node); 2727 } 2728 2729 #ifdef CONN_MGR_ADV_FEATURE 2730 /** 2731 * cm_is_bad_rssi_entry() - check the entry have rssi value, if rssi is lower 2732 * than threshold limit, then it is considered ad bad rssi value. 2733 * @scan_entry: pointer to scan cache entry 2734 * @score_config: pointer to score config structure 2735 * @bssid_hint: bssid hint 2736 * 2737 * Return: true if rssi is lower than threshold 2738 */ 2739 static 2740 bool cm_is_bad_rssi_entry(struct scan_cache_entry *scan_entry, 2741 struct scoring_cfg *score_config, 2742 struct qdf_mac_addr *bssid_hint) 2743 { 2744 int8_t rssi_threshold = 2745 score_config->rssi_score.con_non_hint_target_rssi_threshold; 2746 2747 /* do not need to consider BSSID hint if it is invalid entry(zero) */ 2748 if (qdf_is_macaddr_zero(bssid_hint)) 2749 return false; 2750 2751 if (score_config->is_bssid_hint_priority && 2752 !qdf_is_macaddr_equal(bssid_hint, &scan_entry->bssid) && 2753 scan_entry->rssi_raw < rssi_threshold) { 2754 mlme_nofl_debug("Candidate(" QDF_MAC_ADDR_FMT " freq %d): remove entry, rssi %d lower than rssi_threshold %d", 2755 QDF_MAC_ADDR_REF(scan_entry->bssid.bytes), 2756 scan_entry->channel.chan_freq, 2757 scan_entry->rssi_raw, rssi_threshold); 2758 return true; 2759 } 2760 2761 return false; 2762 } 2763 2764 /** 2765 * cm_update_bss_score_for_mac_addr_matching() - boost score based on mac 2766 * address matching 2767 * @scan_entry: pointer to scan cache entry 2768 * @self_mac: pointer to bssid to be matched 2769 * 2770 * Some IOT APs only allow to connect if last 3 bytes of BSSID 2771 * and self MAC is same. They create a new bssid on receiving 2772 * unicast probe/auth req from STA and allow STA to connect to 2773 * this matching BSSID only. So boost the matching BSSID to try 2774 * to connect to this BSSID. 2775 * 2776 * Return: void 2777 */ 2778 static void 2779 cm_update_bss_score_for_mac_addr_matching(struct scan_cache_node *scan_entry, 2780 struct qdf_mac_addr *self_mac) 2781 { 2782 struct qdf_mac_addr *scan_entry_bssid; 2783 2784 if (!self_mac) 2785 return; 2786 scan_entry_bssid = &scan_entry->entry->bssid; 2787 if (QDF_IS_LAST_3_BYTES_OF_MAC_SAME( 2788 self_mac, scan_entry_bssid)) { 2789 mlme_nofl_debug("Candidate("QDF_MAC_ADDR_FMT" freq %d): boost bss score due to same last 3 byte match", 2790 QDF_MAC_ADDR_REF( 2791 scan_entry_bssid->bytes), 2792 scan_entry->entry->channel.chan_freq); 2793 scan_entry->entry->bss_score = 2794 CM_BEST_CANDIDATE_MAX_BSS_SCORE; 2795 } 2796 } 2797 #else 2798 static inline 2799 bool cm_is_bad_rssi_entry(struct scan_cache_entry *scan_entry, 2800 struct scoring_cfg *score_config, 2801 struct qdf_mac_addr *bssid_hint) 2802 2803 { 2804 return false; 2805 } 2806 2807 static void 2808 cm_update_bss_score_for_mac_addr_matching(struct scan_cache_node *scan_entry, 2809 struct qdf_mac_addr *self_mac) 2810 { 2811 } 2812 #endif 2813 2814 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE 2815 void cm_print_candidate_list(qdf_list_t *candidate_list) 2816 { 2817 struct scan_cache_node *scan_entry = NULL; 2818 qdf_list_node_t *cur_node = NULL, *next_node = NULL; 2819 uint32_t freq_entry = 0; 2820 struct partner_link_info *link = NULL; 2821 uint8_t i = 0; 2822 uint32_t len = 0; 2823 char log_str[CANDIDATE_DUMP_MAX_LEN] = {0}; 2824 uint32_t str_len = CANDIDATE_DUMP_MAX_LEN; 2825 2826 if (qdf_list_peek_front(candidate_list, &cur_node) != 2827 QDF_STATUS_SUCCESS) { 2828 mlme_err("failed to get front of candidate_list"); 2829 return; 2830 } 2831 2832 while (cur_node) { 2833 qdf_list_peek_next(candidate_list, cur_node, &next_node); 2834 2835 scan_entry = qdf_container_of(cur_node, struct scan_cache_node, 2836 node); 2837 link = scan_entry->entry->ml_info.link_info; 2838 freq_entry = scan_entry->entry->channel.chan_freq; 2839 2840 if (scan_entry->entry->ml_info.num_links) 2841 len += qdf_scnprintf(log_str + len, str_len - len, "num_link %d partners ", 2842 scan_entry->entry->ml_info.num_links); 2843 for (i = 0; i < scan_entry->entry->ml_info.num_links; i++) 2844 len += qdf_scnprintf(log_str + len, str_len - len, QDF_MAC_ADDR_FMT " freq (%d) link_id %d is_valid_link %d ", 2845 QDF_MAC_ADDR_REF(link[i].link_addr.bytes), 2846 link[i].freq, link[i].link_id, 2847 link[i].is_valid_link); 2848 mlme_debug("Candidate(" QDF_MAC_ADDR_FMT " freq %d self_link_id %d): %s bss_score %d ", 2849 QDF_MAC_ADDR_REF(scan_entry->entry->bssid.bytes), 2850 scan_entry->entry->channel.chan_freq, 2851 scan_entry->entry->ml_info.self_link_id, 2852 log_str, 2853 scan_entry->entry->bss_score); 2854 cur_node = next_node; 2855 next_node = NULL; 2856 memset(log_str, 0, sizeof(*log_str)); 2857 len = 0; 2858 } 2859 } 2860 2861 /** 2862 * cm_find_and_remove_dup_candidate() - remove duplicate candidate 2863 * @bss_entry: bss scan entry 2864 * @next_can: next candidate 2865 * @candidate_list: candidate list 2866 * 2867 * Ex1: 2868 * Single AP1 3 link 6 GHz 2 GHz 5 GHz 2869 * 2870 * All possible combination of candidate[INPUT] 2871 * AP1 6 GHz + 2 GHz + 5 GHz 2872 * AP1 6 GHz + 2 GHz 2873 * AP1 6 GHz + 5 GHz 2874 * AP1 6 GHz 2875 * AP1 2 GHz + 5 GHz + 6 GHz 2876 * AP1 2 GHz + 5 GHz 2877 * AP1 2 GHz + 6 GHz 2878 * AP1 2 GHz 2879 * AP1 5 GHz + 6 GHz + 2 GHz 2880 * AP1 5 GHz + 6 GHz 2881 * AP1 5 GHz + 2 GHz 2882 * AP1 5 GHz 2883 * 2884 * All possible valid unique combination of candidate after applying [OUTPUT] 2885 * filter. 2886 * AP1 6 GHz + 2 GHz + 5 GHz 2887 * AP1 6 GHz + 2 GHz 2888 * AP1 6 GHz + 5 GHz 2889 * AP1 6 GHz 2890 * AP1 5 GHz + 2 GHz 2891 * AP1 5 GHz 2892 * AP1 2 GHz 2893 * 2894 * Return: none 2895 */ 2896 static void cm_find_and_remove_dup_candidate(struct scan_cache_node *bss_entry, 2897 qdf_list_node_t *next_can, 2898 qdf_list_t *candidate_list) 2899 { 2900 qdf_list_node_t *cur_node = NULL, *next_node = NULL; 2901 struct scan_cache_node *scan_node; 2902 uint8_t i = 0, j = 0; 2903 int match = 0; 2904 uint8_t bss_num_link = 0, curr_num_link = 0; 2905 struct partner_link_info *cur_can = NULL, *bss_can = NULL; 2906 uint32_t size = 0; 2907 2908 bss_num_link = bss_entry->entry->ml_info.num_links; 2909 2910 cur_node = next_can; 2911 size = qdf_list_size(candidate_list); 2912 2913 while (cur_node && size > 0) { 2914 qdf_list_peek_next(candidate_list, cur_node, &next_node); 2915 2916 scan_node = qdf_container_of(cur_node, struct scan_cache_node, 2917 node); 2918 curr_num_link = scan_node->entry->ml_info.num_links; 2919 cur_can = scan_node->entry->ml_info.link_info; 2920 bss_can = bss_entry->entry->ml_info.link_info; 2921 2922 if (scan_node->entry->ml_info.num_links != 2923 bss_entry->entry->ml_info.num_links) 2924 goto next; 2925 2926 match = 0; 2927 for (i = 0; i < bss_num_link; i++) 2928 if (qdf_is_macaddr_equal(&bss_entry->entry->bssid, 2929 &scan_node->entry->bssid) || 2930 qdf_is_macaddr_equal(&bss_entry->entry->bssid, 2931 &cur_can[i].link_addr)) 2932 match++; 2933 for (i = 0; i < bss_num_link; i++) { 2934 for (j = 0; j < curr_num_link; j++) { 2935 if (cur_can[j].is_valid_link && 2936 (qdf_is_macaddr_equal( 2937 &cur_can[j].link_addr, 2938 &bss_can[i].link_addr) || 2939 qdf_is_macaddr_equal( 2940 &cur_can[j].link_addr, 2941 &bss_can[i].link_addr) || 2942 qdf_is_macaddr_equal( 2943 &scan_node->entry->bssid, 2944 &bss_can[i].link_addr))) { 2945 match++; 2946 if (match == bss_num_link + 1) { 2947 qdf_list_remove_node( 2948 candidate_list, 2949 cur_node); 2950 util_scan_free_cache_entry( 2951 scan_node->entry); 2952 qdf_mem_free(cur_node); 2953 goto next; 2954 } 2955 } 2956 } 2957 } 2958 next: 2959 cur_node = next_node; 2960 next_node = NULL; 2961 size--; 2962 } 2963 } 2964 2965 /** 2966 * cm_mlo_generate_candidate_list() - generate candidate list 2967 * @candidate_list: candidate list 2968 * 2969 * For any candidate list this api generates all possible unique 2970 * candidates from mlo candidates 2971 * Input candidate list 2972 * c1 6 GHz + 2 GHz + 5 GHz 2973 * c2 2 GHz + 5 GHz + 6 GHz 2974 * c3 5 GHz + 6 GHz + 2 GHz 2975 * 2976 * Output candidate list 2977 * AP1 6 GHz + 2 GHz + 5 GHz 2978 * AP1 6 GHz + 2 GHz 2979 * AP1 6 GHz + 5 GHz 2980 * AP1 6 GHz 2981 * AP1 2 GHz + 5 GHz + 6 GHz 2982 * AP1 2 GHz + 5 GHz 2983 * AP1 2 GHz + 6 GHz 2984 * AP1 2 GHz 2985 * AP1 5 GHz + 6 GHz + 2 GHz 2986 * AP1 5 GHz + 6 GHz 2987 * AP1 5 GHz + 2 GHz 2988 * AP1 5 GHz 2989 * 2990 * Return none 2991 */ 2992 static void cm_mlo_generate_candidate_list(qdf_list_t *candidate_list) 2993 { 2994 struct scan_cache_entry *tmp_scan_entry = NULL; 2995 struct scan_cache_node *scan_entry = NULL, *scan_node = NULL; 2996 qdf_list_node_t *cur_node = NULL, *next_node = NULL; 2997 struct partner_link_info *link = NULL; 2998 struct partner_link_info tmp = {0}; 2999 uint32_t num_link = 0; 3000 uint32_t i = 0; 3001 uint32_t j = 0; 3002 3003 if (qdf_list_peek_front(candidate_list, &cur_node) != 3004 QDF_STATUS_SUCCESS) { 3005 mlme_err("failed to get front of candidate_list"); 3006 return; 3007 } 3008 while (cur_node) { 3009 qdf_list_peek_next(candidate_list, cur_node, &next_node); 3010 3011 scan_entry = qdf_container_of(cur_node, struct scan_cache_node, 3012 node); 3013 num_link = scan_entry->entry->ml_info.num_links; 3014 3015 for (i = 0; i < num_link; i++) { 3016 tmp_scan_entry = util_scan_copy_cache_entry( 3017 scan_entry->entry); 3018 scan_node = qdf_mem_malloc_atomic(sizeof(*scan_node)); 3019 if (!scan_node) { 3020 util_scan_free_cache_entry(tmp_scan_entry); 3021 goto next; 3022 } 3023 3024 scan_node->entry = tmp_scan_entry; 3025 scan_node->entry->ml_info.num_links = i; 3026 link = scan_node->entry->ml_info.link_info; 3027 for (j = i; j < num_link; j++) 3028 link[j].is_valid_link = false; 3029 qdf_list_insert_after(candidate_list, 3030 &scan_node->node, 3031 &scan_entry->node); 3032 3033 if (i == 1) { 3034 tmp_scan_entry = util_scan_copy_cache_entry( 3035 scan_entry->entry); 3036 scan_node = qdf_mem_malloc_atomic( 3037 sizeof(*scan_node)); 3038 if (!scan_node) { 3039 util_scan_free_cache_entry( 3040 tmp_scan_entry); 3041 goto next; 3042 } 3043 3044 scan_node->entry = tmp_scan_entry; 3045 scan_node->entry->ml_info.num_links = i; 3046 link = scan_node->entry->ml_info.link_info; 3047 tmp = link[1]; 3048 link[1] = link[0]; 3049 link[0] = tmp; 3050 for (j = i; j < num_link; j++) 3051 link[j].is_valid_link = false; 3052 qdf_list_insert_after(candidate_list, 3053 &scan_node->node, 3054 &scan_entry->node); 3055 } 3056 } 3057 next: 3058 cur_node = next_node; 3059 next_node = NULL; 3060 } 3061 } 3062 3063 static void cm_eliminate_common_candidate(qdf_list_t *candidate_list) 3064 { 3065 struct scan_cache_node *scan_entry = NULL; 3066 qdf_list_node_t *cur_node = NULL, *next_node = NULL; 3067 uint32_t size = 0; 3068 QDF_STATUS status; 3069 3070 size = qdf_list_size(candidate_list); 3071 3072 if (qdf_list_peek_front(candidate_list, &cur_node) != 3073 QDF_STATUS_SUCCESS) { 3074 mlme_err("failed to get front of candidate_list"); 3075 return; 3076 } 3077 3078 while (cur_node && size > 0) { 3079 qdf_list_peek_next(candidate_list, cur_node, &next_node); 3080 3081 scan_entry = qdf_container_of(cur_node, 3082 struct scan_cache_node, node); 3083 3084 cm_find_and_remove_dup_candidate(scan_entry, 3085 next_node, candidate_list); 3086 3087 /* 3088 * Find next again as next entry might have deleted. 3089 * If reach end of list, next_node won't be updated, may still 3090 * be freed node, but it's next is itself, qdf_list_peek_next 3091 * will return QDF_STATUS_E_EMPTY, need break loop, or double 3092 * free will happen. 3093 */ 3094 status = qdf_list_peek_next(candidate_list, cur_node, 3095 &next_node); 3096 if (QDF_IS_STATUS_ERROR(status)) 3097 break; 3098 3099 cur_node = next_node; 3100 next_node = NULL; 3101 size--; 3102 } 3103 } 3104 3105 static void cm_validate_partner_links(struct wlan_objmgr_psoc *psoc, 3106 struct scan_cache_entry *entry, 3107 qdf_list_t *scan_list) 3108 { 3109 uint8_t idx; 3110 struct scan_cache_entry *partner_entry; 3111 struct partner_link_info *partner_info; 3112 struct wlan_objmgr_peer *peer; 3113 3114 if (!entry->ie_list.multi_link_bv || !entry->ml_info.num_links) 3115 return; 3116 3117 for (idx = 0; idx < entry->ml_info.num_links; idx++) { 3118 partner_info = &entry->ml_info.link_info[idx]; 3119 if (!partner_info->is_valid_link) 3120 continue; 3121 3122 peer = wlan_objmgr_get_peer_by_mac(psoc, 3123 partner_info->link_addr.bytes, 3124 WLAN_MLME_CM_ID); 3125 if (peer) { 3126 mlme_debug(QDF_MAC_ADDR_FMT "link (%d) dup peer existed", 3127 QDF_MAC_ADDR_REF(partner_info->link_addr.bytes), 3128 partner_info->freq); 3129 partner_info->is_valid_link = false; 3130 wlan_objmgr_peer_release_ref(peer, WLAN_MLME_CM_ID); 3131 continue; 3132 } 3133 3134 if (partner_info->link_id == entry->ml_info.self_link_id) { 3135 mlme_err(QDF_MAC_ADDR_FMT " dup link id %d", 3136 QDF_MAC_ADDR_REF(partner_info->link_addr.bytes), 3137 partner_info->link_id); 3138 partner_info->is_valid_link = false; 3139 } 3140 3141 if (qdf_is_macaddr_equal(&partner_info->link_addr, 3142 &entry->bssid)) { 3143 mlme_err(QDF_MAC_ADDR_FMT " link id %d dup mac", 3144 QDF_MAC_ADDR_REF(partner_info->link_addr.bytes), 3145 partner_info->link_id); 3146 partner_info->is_valid_link = false; 3147 } 3148 3149 /* 3150 * If partner link is not found in the current candidate list 3151 * don't treat it as failure, it can be removed post ML 3152 * probe resp generation time. 3153 */ 3154 partner_entry = cm_get_entry(scan_list, 3155 &partner_info->link_addr); 3156 if (!partner_entry) 3157 continue; 3158 3159 if (wlan_scan_entries_contain_cmn_akm(entry, partner_entry) && 3160 wlan_cm_is_eht_allowed_for_current_security(psoc, 3161 partner_entry, 3162 true)) { 3163 continue; 3164 } 3165 3166 partner_info->is_valid_link = false; 3167 mlme_debug(QDF_MAC_ADDR_FMT "link (%d) akm not matching", 3168 QDF_MAC_ADDR_REF(partner_entry->bssid.bytes), 3169 partner_info->freq); 3170 } 3171 } 3172 #else 3173 3174 static void cm_mlo_generate_candidate_list(qdf_list_t *candidate_list) 3175 { 3176 } 3177 3178 static void cm_eliminate_common_candidate(qdf_list_t *candidate_list) 3179 { 3180 } 3181 3182 static inline void 3183 cm_validate_partner_links(struct wlan_objmgr_psoc *psoc, 3184 struct scan_cache_entry *entry, 3185 qdf_list_t *scan_list) 3186 { 3187 } 3188 #endif 3189 void wlan_cm_calculate_bss_score(struct wlan_objmgr_pdev *pdev, 3190 struct pcl_freq_weight_list *pcl_lst, 3191 qdf_list_t *scan_list, 3192 struct qdf_mac_addr *bssid_hint, 3193 struct qdf_mac_addr *self_mac) 3194 { 3195 struct scan_cache_node *scan_entry; 3196 qdf_list_node_t *cur_node = NULL, *next_node = NULL; 3197 struct psoc_mlme_obj *mlme_psoc_obj; 3198 struct scoring_cfg *score_config; 3199 int pcl_chan_weight; 3200 QDF_STATUS status; 3201 struct psoc_phy_config *config; 3202 enum cm_denylist_action denylist_action; 3203 struct wlan_objmgr_psoc *psoc; 3204 bool assoc_allowed; 3205 struct scan_cache_node *force_connect_candidate = NULL; 3206 bool are_all_candidate_denylisted = true; 3207 bool is_rssi_bad = false; 3208 3209 psoc = wlan_pdev_get_psoc(pdev); 3210 3211 if (!psoc) { 3212 mlme_err("psoc NULL"); 3213 return; 3214 } 3215 if (!scan_list) { 3216 mlme_err("Scan list NULL"); 3217 return; 3218 } 3219 3220 mlme_psoc_obj = wlan_psoc_mlme_get_cmpt_obj(psoc); 3221 if (!mlme_psoc_obj) 3222 return; 3223 3224 score_config = &mlme_psoc_obj->psoc_cfg.score_config; 3225 config = &mlme_psoc_obj->psoc_cfg.phy_config; 3226 3227 mlme_nofl_debug("Self caps: HT %d VHT %d HE %d EHT %d VHT_24Ghz %d BF cap %d bw_above_20_24ghz %d bw_above_20_5ghz %d 2.4G NSS %d 5G NSS %d", 3228 config->ht_cap, config->vht_cap, 3229 config->he_cap, config->eht_cap, config->vht_24G_cap, 3230 config->beamformee_cap, config->bw_above_20_24ghz, 3231 config->bw_above_20_5ghz, config->vdev_nss_24g, 3232 config->vdev_nss_5g); 3233 3234 cm_mlo_generate_candidate_list(scan_list); 3235 3236 /* calculate score for each AP */ 3237 if (qdf_list_peek_front(scan_list, &cur_node) != QDF_STATUS_SUCCESS) { 3238 mlme_err("failed to peer front of scan list"); 3239 return; 3240 } 3241 3242 while (cur_node) { 3243 qdf_list_peek_next(scan_list, cur_node, &next_node); 3244 pcl_chan_weight = 0; 3245 scan_entry = qdf_container_of(cur_node, struct scan_cache_node, 3246 node); 3247 3248 is_rssi_bad = cm_is_bad_rssi_entry(scan_entry->entry, 3249 score_config, bssid_hint); 3250 3251 assoc_allowed = cm_is_assoc_allowed(mlme_psoc_obj, 3252 scan_entry->entry); 3253 3254 if (assoc_allowed && !is_rssi_bad) 3255 denylist_action = wlan_denylist_action_on_bssid(pdev, 3256 scan_entry->entry); 3257 else 3258 denylist_action = CM_DLM_FORCE_REMOVE; 3259 3260 if (denylist_action == CM_DLM_NO_ACTION || 3261 denylist_action == CM_DLM_AVOID) 3262 are_all_candidate_denylisted = false; 3263 3264 if (denylist_action == CM_DLM_NO_ACTION && 3265 pcl_lst && pcl_lst->num_of_pcl_channels && 3266 scan_entry->entry->rssi_raw > CM_PCL_RSSI_THRESHOLD && 3267 score_config->weight_config.pcl_weightage) { 3268 if (cm_get_pcl_weight_of_channel( 3269 scan_entry->entry->channel.chan_freq, 3270 pcl_lst, &pcl_chan_weight)) { 3271 mlme_debug("pcl freq %d pcl_chan_weight %d", 3272 scan_entry->entry->channel.chan_freq, 3273 pcl_chan_weight); 3274 } 3275 } 3276 3277 /* Check if the partner links RSN caps are matching. */ 3278 cm_validate_partner_links(psoc, scan_entry->entry, scan_list); 3279 if (denylist_action == CM_DLM_NO_ACTION || 3280 (are_all_candidate_denylisted && denylist_action == 3281 CM_DLM_REMOVE)) { 3282 cm_calculate_bss_score(psoc, scan_entry->entry, 3283 pcl_chan_weight, bssid_hint, 3284 scan_list, ASSOC_LINK); 3285 } else if (denylist_action == CM_DLM_AVOID) { 3286 /* add min score so that it is added back in the end */ 3287 scan_entry->entry->bss_score = 3288 CM_AVOID_CANDIDATE_MIN_SCORE; 3289 mlme_nofl_debug("Candidate("QDF_MAC_ADDR_FMT" freq %d): rssi %d, is in Avoidlist, give min score %d", 3290 QDF_MAC_ADDR_REF(scan_entry->entry->bssid.bytes), 3291 scan_entry->entry->channel.chan_freq, 3292 scan_entry->entry->rssi_raw, 3293 scan_entry->entry->bss_score); 3294 } else { 3295 mlme_nofl_debug("Candidate("QDF_MAC_ADDR_FMT" freq %d): denylist_action %d", 3296 QDF_MAC_ADDR_REF(scan_entry->entry->bssid.bytes), 3297 scan_entry->entry->channel.chan_freq, 3298 denylist_action); 3299 } 3300 3301 cm_update_bss_score_for_mac_addr_matching(scan_entry, self_mac); 3302 /* 3303 * The below logic is added to select the best candidate 3304 * amongst the denylisted candidates. This is done to 3305 * handle a case where all the BSSIDs become denylisted 3306 * and hence there are continuous connection failures. 3307 * With the below logic if the action on BSSID is to remove 3308 * then we keep a backup node and restore the candidate 3309 * list. 3310 */ 3311 if (denylist_action == CM_DLM_REMOVE && 3312 are_all_candidate_denylisted) { 3313 if (!force_connect_candidate) { 3314 force_connect_candidate = 3315 qdf_mem_malloc( 3316 sizeof(*force_connect_candidate)); 3317 if (!force_connect_candidate) 3318 return; 3319 force_connect_candidate->entry = 3320 util_scan_copy_cache_entry(scan_entry->entry); 3321 if (!force_connect_candidate->entry) 3322 return; 3323 } else if (cm_is_better_bss( 3324 scan_entry->entry, 3325 force_connect_candidate->entry)) { 3326 util_scan_free_cache_entry( 3327 force_connect_candidate->entry); 3328 force_connect_candidate->entry = 3329 util_scan_copy_cache_entry(scan_entry->entry); 3330 if (!force_connect_candidate->entry) 3331 return; 3332 } 3333 } 3334 3335 /* Remove node from current location to add node back sorted */ 3336 status = qdf_list_remove_node(scan_list, cur_node); 3337 if (QDF_IS_STATUS_ERROR(status)) { 3338 mlme_err("failed to remove node for BSS "QDF_MAC_ADDR_FMT" from scan list", 3339 QDF_MAC_ADDR_REF(scan_entry->entry->bssid.bytes)); 3340 return; 3341 } 3342 3343 /* 3344 * If CM_DLM_REMOVE ie denylisted or assoc not allowed then 3345 * free the entry else add back to the list sorted 3346 */ 3347 if (denylist_action == CM_DLM_REMOVE || 3348 denylist_action == CM_DLM_FORCE_REMOVE) { 3349 if (assoc_allowed && !is_rssi_bad) 3350 mlme_nofl_debug("Candidate( " QDF_MAC_ADDR_FMT " freq %d): rssi %d, dlm action %d is in Denylist, remove entry", 3351 QDF_MAC_ADDR_REF(scan_entry->entry->bssid.bytes), 3352 scan_entry->entry->channel.chan_freq, 3353 scan_entry->entry->rssi_raw, 3354 denylist_action); 3355 util_scan_free_cache_entry(scan_entry->entry); 3356 qdf_mem_free(scan_entry); 3357 } else { 3358 cm_list_insert_sorted(scan_list, scan_entry); 3359 } 3360 3361 cur_node = next_node; 3362 next_node = NULL; 3363 } 3364 3365 if (are_all_candidate_denylisted && force_connect_candidate) { 3366 mlme_nofl_debug("All candidates in denylist, Candidate( " QDF_MAC_ADDR_FMT " freq %d): rssi %d, selected for connection", 3367 QDF_MAC_ADDR_REF(force_connect_candidate->entry->bssid.bytes), 3368 force_connect_candidate->entry->channel.chan_freq, 3369 force_connect_candidate->entry->rssi_raw); 3370 cm_list_insert_sorted(scan_list, force_connect_candidate); 3371 } else if (force_connect_candidate) { 3372 util_scan_free_cache_entry(force_connect_candidate->entry); 3373 qdf_mem_free(force_connect_candidate); 3374 } 3375 3376 cm_eliminate_common_candidate(scan_list); 3377 /* print all vendor candidates*/ 3378 cm_print_candidate_list(scan_list); 3379 } 3380 3381 #ifdef CONFIG_BAND_6GHZ 3382 #ifdef CONN_MGR_ADV_FEATURE 3383 static bool wlan_cm_wfa_get_test_feature_flags(struct wlan_objmgr_psoc *psoc) 3384 { 3385 return wlan_wfa_get_test_feature_flags(psoc, WFA_TEST_IGNORE_RSNXE); 3386 } 3387 #else 3388 static bool wlan_cm_wfa_get_test_feature_flags(struct wlan_objmgr_psoc *psoc) 3389 { 3390 return false; 3391 } 3392 #endif 3393 3394 bool wlan_cm_6ghz_allowed_for_akm(struct wlan_objmgr_psoc *psoc, 3395 uint32_t key_mgmt, uint16_t rsn_caps, 3396 const uint8_t *rsnxe, uint8_t sae_pwe, 3397 bool is_wps) 3398 { 3399 struct psoc_mlme_obj *mlme_psoc_obj; 3400 struct scoring_cfg *config; 3401 3402 /* Allow connection for WPS security */ 3403 if (is_wps) 3404 return true; 3405 3406 mlme_psoc_obj = wlan_psoc_mlme_get_cmpt_obj(psoc); 3407 if (!mlme_psoc_obj) 3408 return false; 3409 3410 config = &mlme_psoc_obj->psoc_cfg.score_config; 3411 /* 3412 * if check_6ghz_security is not set check if key_mgmt_mask_6ghz is set 3413 * if key_mgmt_mask_6ghz is set check if AKM matches the user configured 3414 * 6Ghz security 3415 */ 3416 if (!config->check_6ghz_security) { 3417 if (!config->key_mgmt_mask_6ghz) 3418 return true; 3419 /* 3420 * Check if any AKM is allowed as per user 6Ghz allowed AKM mask 3421 */ 3422 if (!(config->key_mgmt_mask_6ghz & key_mgmt)) { 3423 mlme_debug("user configured mask %x didn't match AKM %x", 3424 config->key_mgmt_mask_6ghz , key_mgmt); 3425 return false; 3426 } 3427 3428 return true; 3429 } 3430 3431 /* Check if any AKM is allowed as per the 6Ghz allowed AKM mask */ 3432 if (!(key_mgmt & ALLOWED_KEYMGMT_6G_MASK)) { 3433 mlme_debug("AKM 0x%x didn't match with allowed 6ghz AKM 0x%x", 3434 key_mgmt, ALLOWED_KEYMGMT_6G_MASK); 3435 return false; 3436 } 3437 3438 /* if check_6ghz_security is set validate all checks for 6Ghz */ 3439 if (!(rsn_caps & WLAN_CRYPTO_RSN_CAP_MFP_ENABLED)) { 3440 mlme_debug("PMF not enabled for 6GHz AP"); 3441 return false; 3442 } 3443 3444 /* for SAE we need to check H2E support */ 3445 if (!(QDF_HAS_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_SAE) || 3446 QDF_HAS_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_FT_SAE) || 3447 QDF_HAS_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_SAE_EXT_KEY) || 3448 QDF_HAS_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_FT_SAE_EXT_KEY))) 3449 return true; 3450 3451 return (util_is_rsnxe_h2e_capable(rsnxe) || 3452 wlan_cm_wfa_get_test_feature_flags(psoc)); 3453 } 3454 3455 void wlan_cm_set_check_6ghz_security(struct wlan_objmgr_psoc *psoc, 3456 bool value) 3457 { 3458 struct psoc_mlme_obj *mlme_psoc_obj; 3459 3460 mlme_psoc_obj = wlan_psoc_mlme_get_cmpt_obj(psoc); 3461 if (!mlme_psoc_obj) 3462 return; 3463 3464 mlme_debug("6ghz security check val %x", value); 3465 mlme_psoc_obj->psoc_cfg.score_config.check_6ghz_security = value; 3466 } 3467 3468 void wlan_cm_reset_check_6ghz_security(struct wlan_objmgr_psoc *psoc) 3469 { 3470 struct psoc_mlme_obj *mlme_psoc_obj; 3471 3472 mlme_psoc_obj = wlan_psoc_mlme_get_cmpt_obj(psoc); 3473 if (!mlme_psoc_obj) 3474 return; 3475 3476 mlme_psoc_obj->psoc_cfg.score_config.check_6ghz_security = 3477 cfg_get(psoc, CFG_CHECK_6GHZ_SECURITY); 3478 } 3479 #if defined (SAP_MULTI_LINK_EMULATION) 3480 /*Disable security check for 2link SAP emulation */ 3481 bool wlan_cm_get_check_6ghz_security(struct wlan_objmgr_psoc *psoc) 3482 { 3483 return true; 3484 } 3485 #else 3486 bool wlan_cm_get_check_6ghz_security(struct wlan_objmgr_psoc *psoc) 3487 { 3488 struct psoc_mlme_obj *mlme_psoc_obj; 3489 3490 mlme_psoc_obj = wlan_psoc_mlme_get_cmpt_obj(psoc); 3491 if (!mlme_psoc_obj) 3492 return false; 3493 3494 return mlme_psoc_obj->psoc_cfg.score_config.check_6ghz_security; 3495 } 3496 #endif 3497 void wlan_cm_set_standard_6ghz_conn_policy(struct wlan_objmgr_psoc *psoc, 3498 bool value) 3499 { 3500 struct psoc_mlme_obj *mlme_psoc_obj; 3501 3502 mlme_psoc_obj = wlan_psoc_mlme_get_cmpt_obj(psoc); 3503 if (!mlme_psoc_obj) 3504 return; 3505 3506 mlme_debug("6ghz standard connection policy val %x", value); 3507 mlme_psoc_obj->psoc_cfg.score_config.standard_6ghz_conn_policy = value; 3508 } 3509 3510 bool wlan_cm_get_standard_6ghz_conn_policy(struct wlan_objmgr_psoc *psoc) 3511 { 3512 struct psoc_mlme_obj *mlme_psoc_obj; 3513 3514 mlme_psoc_obj = wlan_psoc_mlme_get_cmpt_obj(psoc); 3515 if (!mlme_psoc_obj) 3516 return false; 3517 3518 return mlme_psoc_obj->psoc_cfg.score_config.standard_6ghz_conn_policy; 3519 } 3520 3521 void wlan_cm_set_disable_vlp_sta_conn_to_sp_ap(struct wlan_objmgr_psoc *psoc, 3522 bool value) 3523 { 3524 struct psoc_mlme_obj *mlme_psoc_obj; 3525 3526 mlme_psoc_obj = wlan_psoc_mlme_get_cmpt_obj(psoc); 3527 if (!mlme_psoc_obj) 3528 return; 3529 3530 mlme_debug("disable_vlp_sta_conn_to_sp_ap val %x", value); 3531 mlme_psoc_obj->psoc_cfg.score_config.disable_vlp_sta_conn_to_sp_ap = value; 3532 } 3533 3534 bool wlan_cm_get_disable_vlp_sta_conn_to_sp_ap(struct wlan_objmgr_psoc *psoc) 3535 { 3536 struct psoc_mlme_obj *mlme_psoc_obj; 3537 3538 mlme_psoc_obj = wlan_psoc_mlme_get_cmpt_obj(psoc); 3539 if (!mlme_psoc_obj) 3540 return false; 3541 3542 return mlme_psoc_obj->psoc_cfg.score_config.disable_vlp_sta_conn_to_sp_ap; 3543 } 3544 3545 void wlan_cm_set_6ghz_key_mgmt_mask(struct wlan_objmgr_psoc *psoc, 3546 uint32_t value) 3547 { 3548 struct psoc_mlme_obj *mlme_psoc_obj; 3549 3550 mlme_psoc_obj = wlan_psoc_mlme_get_cmpt_obj(psoc); 3551 if (!mlme_psoc_obj) 3552 return; 3553 3554 mlme_debug("key_mgmt_mask_6ghz %x", value); 3555 mlme_psoc_obj->psoc_cfg.score_config.key_mgmt_mask_6ghz = value; 3556 } 3557 3558 uint32_t wlan_cm_get_6ghz_key_mgmt_mask(struct wlan_objmgr_psoc *psoc) 3559 { 3560 struct psoc_mlme_obj *mlme_psoc_obj; 3561 3562 mlme_psoc_obj = wlan_psoc_mlme_get_cmpt_obj(psoc); 3563 if (!mlme_psoc_obj) 3564 return DEFAULT_KEYMGMT_6G_MASK; 3565 3566 return mlme_psoc_obj->psoc_cfg.score_config.key_mgmt_mask_6ghz; 3567 } 3568 3569 static void cm_fill_6ghz_params(struct wlan_objmgr_psoc *psoc, 3570 struct scoring_cfg *score_cfg) 3571 { 3572 /* Allow all security in 6Ghz by default */ 3573 score_cfg->check_6ghz_security = cfg_get(psoc, CFG_CHECK_6GHZ_SECURITY); 3574 score_cfg->key_mgmt_mask_6ghz = 3575 cfg_get(psoc, CFG_6GHZ_ALLOWED_AKM_MASK); 3576 } 3577 #else 3578 static inline void cm_fill_6ghz_params(struct wlan_objmgr_psoc *psoc, 3579 struct scoring_cfg *score_cfg) 3580 { 3581 } 3582 #endif 3583 3584 static uint32_t 3585 cm_limit_max_per_index_score(uint32_t per_index_score) 3586 { 3587 uint8_t i, score; 3588 3589 for (i = 0; i < CM_MAX_INDEX_PER_INI; i++) { 3590 score = CM_GET_SCORE_PERCENTAGE(per_index_score, i); 3591 if (score > CM_MAX_PCT_SCORE) 3592 CM_SET_SCORE_PERCENTAGE(per_index_score, 3593 CM_MAX_PCT_SCORE, i); 3594 } 3595 3596 return per_index_score; 3597 } 3598 3599 #ifdef WLAN_FEATURE_11BE_MLO 3600 3601 #define CM_EHT_CAP_WEIGHTAGE 2 3602 #define CM_MLO_WEIGHTAGE 3 3603 #define CM_WLM_INDICATION_WEIGHTAGE 2 3604 #define CM_EMLSR_WEIGHTAGE 3 3605 static void cm_init_mlo_score_config(struct wlan_objmgr_psoc *psoc, 3606 struct scoring_cfg *score_cfg, 3607 uint32_t *total_weight) 3608 { 3609 score_cfg->weight_config.eht_caps_weightage = 3610 cfg_get(psoc, CFG_SCORING_EHT_CAPS_WEIGHTAGE); 3611 3612 score_cfg->weight_config.mlo_weightage = 3613 cfg_get(psoc, CFG_SCORING_MLO_WEIGHTAGE); 3614 3615 score_cfg->weight_config.wlm_indication_weightage = 3616 cfg_get(psoc, CFG_SCORING_WLM_INDICATION_WEIGHTAGE); 3617 3618 score_cfg->weight_config.joint_rssi_alpha = 3619 cfg_get(psoc, CFG_SCORING_JOINT_RSSI_ALPHA); 3620 3621 score_cfg->weight_config.low_band_rssi_boost = 3622 cfg_get(psoc, CFG_SCORING_LOW_BAND_RSSI_BOOST); 3623 3624 score_cfg->weight_config.joint_esp_alpha = 3625 cfg_get(psoc, CFG_SCORING_JOINT_ESP_ALPHA); 3626 3627 score_cfg->weight_config.low_band_esp_boost = 3628 cfg_get(psoc, CFG_SCORING_LOW_BAND_ESP_BOOST); 3629 3630 score_cfg->weight_config.joint_oce_alpha = 3631 cfg_get(psoc, CFG_SCORING_JOINT_OCE_ALPHA); 3632 3633 score_cfg->weight_config.low_band_oce_boost = 3634 cfg_get(psoc, CFG_SCORING_LOW_BAND_OCE_BOOST); 3635 3636 score_cfg->weight_config.emlsr_weightage = 3637 cfg_get(psoc, CFG_SCORING_EMLSR_WEIGHTAGE); 3638 3639 score_cfg->mlsr_link_selection = 3640 cfg_get(psoc, CFG_SCORING_MLSR_LINK_SELECTION); 3641 3642 *total_weight += score_cfg->weight_config.eht_caps_weightage + 3643 score_cfg->weight_config.mlo_weightage + 3644 score_cfg->weight_config.wlm_indication_weightage + 3645 score_cfg->weight_config.emlsr_weightage; 3646 } 3647 3648 static void cm_set_default_mlo_weights(struct scoring_cfg *score_cfg) 3649 { 3650 score_cfg->weight_config.eht_caps_weightage = CM_EHT_CAP_WEIGHTAGE; 3651 score_cfg->weight_config.mlo_weightage = CM_MLO_WEIGHTAGE; 3652 score_cfg->weight_config.wlm_indication_weightage = 3653 CM_WLM_INDICATION_WEIGHTAGE; 3654 score_cfg->weight_config.emlsr_weightage = CM_EMLSR_WEIGHTAGE; 3655 } 3656 3657 static void cm_init_bw_weight_per_index(struct wlan_objmgr_psoc *psoc, 3658 struct scoring_cfg *score_cfg) 3659 { 3660 score_cfg->bandwidth_weight_per_index[0] = 3661 cm_limit_max_per_index_score( 3662 cfg_get(psoc, CFG_SCORING_BW_WEIGHT_PER_IDX)); 3663 3664 score_cfg->bandwidth_weight_per_index[1] = 3665 cm_limit_max_per_index_score( 3666 cfg_get(psoc, CFG_SCORING_BW_WEIGHT_PER_IDX_4_TO_7)); 3667 3668 score_cfg->bandwidth_weight_per_index[2] = 3669 cm_limit_max_per_index_score( 3670 cfg_get(psoc, CFG_SCORING_BW_WEIGHT_PER_IDX_8_TO_11)); 3671 3672 score_cfg->bandwidth_weight_per_index[3] = 3673 cm_limit_max_per_index_score( 3674 cfg_get(psoc, CFG_SCORING_BW_WEIGHT_PER_IDX_12_TO_15)); 3675 3676 score_cfg->bandwidth_weight_per_index[4] = 3677 cm_limit_max_per_index_score( 3678 cfg_get(psoc, CFG_SCORING_BW_WEIGHT_PER_IDX_16_TO_19)); 3679 3680 score_cfg->bandwidth_weight_per_index[5] = 3681 cm_limit_max_per_index_score( 3682 cfg_get(psoc, CFG_SCORING_BW_WEIGHT_PER_IDX_20_TO_23)); 3683 3684 score_cfg->bandwidth_weight_per_index[6] = 3685 cm_limit_max_per_index_score( 3686 cfg_get(psoc, CFG_SCORING_BW_WEIGHT_PER_IDX_24_TO_27)); 3687 3688 score_cfg->bandwidth_weight_per_index[7] = 3689 cm_limit_max_per_index_score( 3690 cfg_get(psoc, CFG_SCORING_BW_WEIGHT_PER_IDX_28_TO_31)); 3691 3692 score_cfg->bandwidth_weight_per_index[8] = 3693 cm_limit_max_per_index_score( 3694 cfg_get(psoc, CFG_SCORING_BW_WEIGHT_PER_IDX_32_TO_35)); 3695 } 3696 3697 static void cm_init_nss_weight_per_index(struct wlan_objmgr_psoc *psoc, 3698 struct scoring_cfg *score_cfg) 3699 { 3700 score_cfg->nss_weight_per_index[0] = 3701 cm_limit_max_per_index_score( 3702 cfg_get(psoc, CFG_SCORING_NSS_WEIGHT_PER_IDX)); 3703 3704 score_cfg->nss_weight_per_index[1] = 3705 cm_limit_max_per_index_score( 3706 cfg_get(psoc, CFG_SCORING_ML_NSS_WEIGHT_PER_IDX_4_TO_7)); 3707 } 3708 #else 3709 static void cm_init_mlo_score_config(struct wlan_objmgr_psoc *psoc, 3710 struct scoring_cfg *score_cfg, 3711 uint32_t *total_weight) 3712 { 3713 } 3714 3715 static void cm_set_default_mlo_weights(struct scoring_cfg *score_cfg) 3716 { 3717 } 3718 3719 #ifdef WLAN_FEATURE_11BE 3720 static void cm_init_bw_weight_per_index(struct wlan_objmgr_psoc *psoc, 3721 struct scoring_cfg *score_cfg) 3722 { 3723 score_cfg->bandwidth_weight_per_index[0] = 3724 cm_limit_max_per_index_score( 3725 cfg_get(psoc, CFG_SCORING_BW_WEIGHT_PER_IDX)); 3726 3727 score_cfg->bandwidth_weight_per_index[1] = 3728 cm_limit_max_per_index_score( 3729 cfg_get(psoc, CFG_SCORING_BW_WEIGHT_PER_IDX_4_TO_7)); 3730 3731 score_cfg->bandwidth_weight_per_index[2] = 3732 cm_limit_max_per_index_score( 3733 cfg_get(psoc, CFG_SCORING_BW_WEIGHT_PER_IDX_8_TO_11)); 3734 } 3735 #else 3736 static void cm_init_bw_weight_per_index(struct wlan_objmgr_psoc *psoc, 3737 struct scoring_cfg *score_cfg) 3738 { 3739 score_cfg->bandwidth_weight_per_index[0] = 3740 cm_limit_max_per_index_score( 3741 cfg_get(psoc, CFG_SCORING_BW_WEIGHT_PER_IDX)); 3742 } 3743 #endif 3744 3745 static void cm_init_nss_weight_per_index(struct wlan_objmgr_psoc *psoc, 3746 struct scoring_cfg *score_cfg) 3747 { 3748 score_cfg->nss_weight_per_index[0] = 3749 cm_limit_max_per_index_score( 3750 cfg_get(psoc, CFG_SCORING_NSS_WEIGHT_PER_IDX)); 3751 } 3752 #endif 3753 3754 void wlan_cm_init_score_config(struct wlan_objmgr_psoc *psoc, 3755 struct scoring_cfg *score_cfg) 3756 { 3757 uint32_t total_weight; 3758 3759 score_cfg->weight_config.rssi_weightage = 3760 cfg_get(psoc, CFG_SCORING_RSSI_WEIGHTAGE); 3761 score_cfg->weight_config.ht_caps_weightage = 3762 cfg_get(psoc, CFG_SCORING_HT_CAPS_WEIGHTAGE); 3763 score_cfg->weight_config.vht_caps_weightage = 3764 cfg_get(psoc, CFG_SCORING_VHT_CAPS_WEIGHTAGE); 3765 score_cfg->weight_config.he_caps_weightage = 3766 cfg_get(psoc, CFG_SCORING_HE_CAPS_WEIGHTAGE); 3767 score_cfg->weight_config.chan_width_weightage = 3768 cfg_get(psoc, CFG_SCORING_CHAN_WIDTH_WEIGHTAGE); 3769 score_cfg->weight_config.chan_band_weightage = 3770 cfg_get(psoc, CFG_SCORING_CHAN_BAND_WEIGHTAGE); 3771 score_cfg->weight_config.nss_weightage = 3772 cfg_get(psoc, CFG_SCORING_NSS_WEIGHTAGE); 3773 score_cfg->weight_config.beamforming_cap_weightage = 3774 cfg_get(psoc, CFG_SCORING_BEAMFORM_CAP_WEIGHTAGE); 3775 score_cfg->weight_config.pcl_weightage = 3776 cfg_get(psoc, CFG_SCORING_PCL_WEIGHTAGE); 3777 score_cfg->weight_config.channel_congestion_weightage = 3778 cfg_get(psoc, CFG_SCORING_CHAN_CONGESTION_WEIGHTAGE); 3779 score_cfg->weight_config.oce_wan_weightage = 3780 cfg_get(psoc, CFG_SCORING_OCE_WAN_WEIGHTAGE); 3781 score_cfg->weight_config.oce_ap_tx_pwr_weightage = 3782 cfg_get(psoc, CFG_OCE_AP_TX_PWR_WEIGHTAGE); 3783 score_cfg->weight_config.oce_subnet_id_weightage = 3784 cfg_get(psoc, CFG_OCE_SUBNET_ID_WEIGHTAGE); 3785 score_cfg->weight_config.sae_pk_ap_weightage = 3786 cfg_get(psoc, CFG_SAE_PK_AP_WEIGHTAGE); 3787 score_cfg->weight_config.security_weightage = CM_SECURITY_WEIGHTAGE; 3788 3789 total_weight = score_cfg->weight_config.rssi_weightage + 3790 score_cfg->weight_config.ht_caps_weightage + 3791 score_cfg->weight_config.vht_caps_weightage + 3792 score_cfg->weight_config.he_caps_weightage + 3793 score_cfg->weight_config.chan_width_weightage + 3794 score_cfg->weight_config.chan_band_weightage + 3795 score_cfg->weight_config.nss_weightage + 3796 score_cfg->weight_config.beamforming_cap_weightage + 3797 score_cfg->weight_config.pcl_weightage + 3798 score_cfg->weight_config.channel_congestion_weightage + 3799 score_cfg->weight_config.oce_wan_weightage + 3800 score_cfg->weight_config.oce_ap_tx_pwr_weightage + 3801 score_cfg->weight_config.oce_subnet_id_weightage + 3802 score_cfg->weight_config.sae_pk_ap_weightage + 3803 score_cfg->weight_config.security_weightage; 3804 3805 cm_init_mlo_score_config(psoc, score_cfg, &total_weight); 3806 3807 /* 3808 * If configured weights are greater than max weight, 3809 * fallback to default weights 3810 */ 3811 if (total_weight > CM_BEST_CANDIDATE_MAX_WEIGHT) { 3812 mlme_err("Total weight greater than %d, using default weights", 3813 CM_BEST_CANDIDATE_MAX_WEIGHT); 3814 score_cfg->weight_config.rssi_weightage = CM_RSSI_WEIGHTAGE; 3815 score_cfg->weight_config.ht_caps_weightage = 3816 CM_HT_CAPABILITY_WEIGHTAGE; 3817 score_cfg->weight_config.vht_caps_weightage = 3818 CM_VHT_CAP_WEIGHTAGE; 3819 score_cfg->weight_config.he_caps_weightage = 3820 CM_HE_CAP_WEIGHTAGE; 3821 score_cfg->weight_config.chan_width_weightage = 3822 CM_CHAN_WIDTH_WEIGHTAGE; 3823 score_cfg->weight_config.chan_band_weightage = 3824 CM_CHAN_BAND_WEIGHTAGE; 3825 score_cfg->weight_config.nss_weightage = CM_NSS_WEIGHTAGE; 3826 score_cfg->weight_config.beamforming_cap_weightage = 3827 CM_BEAMFORMING_CAP_WEIGHTAGE; 3828 score_cfg->weight_config.pcl_weightage = CM_PCL_WEIGHT; 3829 score_cfg->weight_config.channel_congestion_weightage = 3830 CM_CHANNEL_CONGESTION_WEIGHTAGE; 3831 score_cfg->weight_config.oce_wan_weightage = 3832 CM_OCE_WAN_WEIGHTAGE; 3833 score_cfg->weight_config.oce_ap_tx_pwr_weightage = 3834 CM_OCE_AP_TX_POWER_WEIGHTAGE; 3835 score_cfg->weight_config.oce_subnet_id_weightage = 3836 CM_OCE_SUBNET_ID_WEIGHTAGE; 3837 score_cfg->weight_config.sae_pk_ap_weightage = 3838 CM_SAE_PK_AP_WEIGHTAGE; 3839 cm_set_default_mlo_weights(score_cfg); 3840 } 3841 3842 score_cfg->rssi_score.best_rssi_threshold = 3843 cfg_get(psoc, CFG_SCORING_BEST_RSSI_THRESHOLD); 3844 score_cfg->rssi_score.good_rssi_threshold = 3845 cfg_get(psoc, CFG_SCORING_GOOD_RSSI_THRESHOLD); 3846 score_cfg->rssi_score.bad_rssi_threshold = 3847 cfg_get(psoc, CFG_SCORING_BAD_RSSI_THRESHOLD); 3848 3849 score_cfg->rssi_score.good_rssi_pcnt = 3850 cfg_get(psoc, CFG_SCORING_GOOD_RSSI_PERCENT); 3851 score_cfg->rssi_score.bad_rssi_pcnt = 3852 cfg_get(psoc, CFG_SCORING_BAD_RSSI_PERCENT); 3853 3854 score_cfg->rssi_score.good_rssi_bucket_size = 3855 cfg_get(psoc, CFG_SCORING_GOOD_RSSI_BUCKET_SIZE); 3856 score_cfg->rssi_score.bad_rssi_bucket_size = 3857 cfg_get(psoc, CFG_SCORING_BAD_RSSI_BUCKET_SIZE); 3858 3859 score_cfg->rssi_score.rssi_pref_5g_rssi_thresh = 3860 cfg_get(psoc, CFG_SCORING_RSSI_PREF_5G_THRESHOLD); 3861 3862 score_cfg->rssi_score.con_non_hint_target_rssi_threshold = 3863 cfg_get(psoc, CFG_CON_NON_HINT_TARGET_MIN_RSSI); 3864 3865 score_cfg->esp_qbss_scoring.num_slot = 3866 cfg_get(psoc, CFG_SCORING_NUM_ESP_QBSS_SLOTS); 3867 score_cfg->esp_qbss_scoring.score_pcnt3_to_0 = 3868 cm_limit_max_per_index_score( 3869 cfg_get(psoc, CFG_SCORING_ESP_QBSS_SCORE_IDX_3_TO_0)); 3870 score_cfg->esp_qbss_scoring.score_pcnt7_to_4 = 3871 cm_limit_max_per_index_score( 3872 cfg_get(psoc, CFG_SCORING_ESP_QBSS_SCORE_IDX_7_TO_4)); 3873 score_cfg->esp_qbss_scoring.score_pcnt11_to_8 = 3874 cm_limit_max_per_index_score( 3875 cfg_get(psoc, CFG_SCORING_ESP_QBSS_SCORE_IDX_11_TO_8)); 3876 score_cfg->esp_qbss_scoring.score_pcnt15_to_12 = 3877 cm_limit_max_per_index_score( 3878 cfg_get(psoc, CFG_SCORING_ESP_QBSS_SCORE_IDX_15_TO_12)); 3879 3880 score_cfg->oce_wan_scoring.num_slot = 3881 cfg_get(psoc, CFG_SCORING_NUM_OCE_WAN_SLOTS); 3882 score_cfg->oce_wan_scoring.score_pcnt3_to_0 = 3883 cm_limit_max_per_index_score( 3884 cfg_get(psoc, CFG_SCORING_OCE_WAN_SCORE_IDX_3_TO_0)); 3885 score_cfg->oce_wan_scoring.score_pcnt7_to_4 = 3886 cm_limit_max_per_index_score( 3887 cfg_get(psoc, CFG_SCORING_OCE_WAN_SCORE_IDX_7_TO_4)); 3888 score_cfg->oce_wan_scoring.score_pcnt11_to_8 = 3889 cm_limit_max_per_index_score( 3890 cfg_get(psoc, CFG_SCORING_OCE_WAN_SCORE_IDX_11_TO_8)); 3891 score_cfg->oce_wan_scoring.score_pcnt15_to_12 = 3892 cm_limit_max_per_index_score( 3893 cfg_get(psoc, CFG_SCORING_OCE_WAN_SCORE_IDX_15_TO_12)); 3894 3895 score_cfg->band_weight_per_index = 3896 cm_limit_max_per_index_score( 3897 cfg_get(psoc, CFG_SCORING_BAND_WEIGHT_PER_IDX)); 3898 score_cfg->is_bssid_hint_priority = 3899 cfg_get(psoc, CFG_IS_BSSID_HINT_PRIORITY); 3900 score_cfg->vendor_roam_score_algorithm = 3901 cfg_get(psoc, CFG_VENDOR_ROAM_SCORE_ALGORITHM); 3902 score_cfg->check_assoc_disallowed = true; 3903 cm_fill_6ghz_params(psoc, score_cfg); 3904 3905 cm_init_bw_weight_per_index(psoc, score_cfg); 3906 cm_init_nss_weight_per_index(psoc, score_cfg); 3907 score_cfg->security_weight_per_index = CM_SECURITY_INDEX_WEIGHTAGE; 3908 } 3909