1 /* 2 * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. 3 * 4 * Permission to use, copy, modify, and/or distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17 /* 18 * DOC: contains bss scoring logic 19 */ 20 21 #ifdef WLAN_POLICY_MGR_ENABLE 22 #include "wlan_policy_mgr_api.h" 23 #endif 24 #include <include/wlan_psoc_mlme.h> 25 #include "wlan_psoc_mlme_api.h" 26 #include "cfg_ucfg_api.h" 27 #include "wlan_cm_bss_score_param.h" 28 #include "wlan_scan_api.h" 29 #include "wlan_crypto_global_api.h" 30 #include "wlan_mgmt_txrx_utils_api.h" 31 #ifdef CONN_MGR_ADV_FEATURE 32 #include "wlan_mlme_api.h" 33 #endif 34 35 #define CM_20MHZ_BW_INDEX 0 36 #define CM_40MHZ_BW_INDEX 1 37 #define CM_80MHZ_BW_INDEX 2 38 #define CM_160MHZ_BW_INDEX 3 39 #define CM_MAX_BW_INDEX 4 40 41 #define CM_PCL_RSSI_THRESHOLD -75 42 43 #define CM_NSS_1x1_INDEX 0 44 #define CM_NSS_2x2_INDEX 1 45 #define CM_NSS_3x3_INDEX 2 46 #define CM_NSS_4x4_INDEX 3 47 #define CM_MAX_NSS_INDEX 4 48 49 #define CM_BAND_2G_INDEX 0 50 #define CM_BAND_5G_INDEX 1 51 #define CM_BAND_6G_INDEX 2 52 /* 3 is reserved */ 53 #define CM_MAX_BAND_INDEX 4 54 55 #define CM_SCORE_INDEX_0 0 56 #define CM_SCORE_INDEX_3 3 57 #define CM_SCORE_INDEX_7 7 58 #define CM_SCORE_OFFSET_INDEX_7_4 4 59 #define CM_SCORE_INDEX_11 11 60 #define CM_SCORE_OFFSET_INDEX_11_8 8 61 #define CM_SCORE_MAX_INDEX 15 62 #define CM_SCORE_OFFSET_INDEX_15_12 12 63 64 #define CM_MAX_OCE_WAN_DL_CAP 16 65 66 #define CM_MAX_CHANNEL_WEIGHT 100 67 #define CM_MAX_CHANNEL_UTILIZATION 100 68 #define CM_MAX_ESTIMATED_AIR_TIME_FRACTION 255 69 #define CM_MAX_AP_LOAD 255 70 71 #define CM_MAX_WEIGHT_OF_PCL_CHANNELS 255 72 #define CM_PCL_GROUPS_WEIGHT_DIFFERENCE 20 73 74 /* Congestion threshold (channel load %) to consider band and OCE WAN score */ 75 #define CM_CONGESTION_THRSHOLD_FOR_BAND_OCE_SCORE 75 76 77 #define CM_RSSI_WEIGHTAGE 20 78 #define CM_HT_CAPABILITY_WEIGHTAGE 2 79 #define CM_VHT_CAP_WEIGHTAGE 1 80 #define CM_HE_CAP_WEIGHTAGE 2 81 #define CM_CHAN_WIDTH_WEIGHTAGE 12 82 #define CM_CHAN_BAND_WEIGHTAGE 2 83 #define CM_NSS_WEIGHTAGE 16 84 #define CM_BEAMFORMING_CAP_WEIGHTAGE 2 85 #define CM_PCL_WEIGHT 10 86 #define CM_CHANNEL_CONGESTION_WEIGHTAGE 5 87 #define CM_OCE_WAN_WEIGHTAGE 2 88 #define CM_OCE_AP_TX_POWER_WEIGHTAGE 5 89 #define CM_OCE_SUBNET_ID_WEIGHTAGE 3 90 #define CM_SAE_PK_AP_WEIGHTAGE 3 91 #define CM_BEST_CANDIDATE_MAX_WEIGHT 200 92 #define CM_MAX_PCT_SCORE 100 93 #define CM_MAX_INDEX_PER_INI 4 94 95 #define CM_BEST_CANDIDATE_MAX_BSS_SCORE (CM_BEST_CANDIDATE_MAX_WEIGHT * 100) 96 #define CM_AVOID_CANDIDATE_MIN_SCORE 1 97 98 #define CM_GET_SCORE_PERCENTAGE(value32, bw_index) \ 99 QDF_GET_BITS(value32, (8 * (bw_index)), 8) 100 #define CM_SET_SCORE_PERCENTAGE(value32, score_pcnt, bw_index) \ 101 QDF_SET_BITS(value32, (8 * (bw_index)), 8, score_pcnt) 102 103 #ifdef CONN_MGR_ADV_FEATURE 104 /* 3.2 us + 0.8 us(GI) */ 105 #define PPDU_PAYLOAD_SYMBOL_DUR_US 4 106 /* 12.8 us + (0.8 + 1.6)/2 us(GI) */ 107 #define HE_PPDU_PAYLOAD_SYMBOL_DUR_US 14 108 #define MAC_HEADER_LEN 26 109 /* Minimum snrDb supported by LUT */ 110 #define SNR_DB_TO_BIT_PER_TONE_LUT_MIN -10 111 /* Maximum snrDb supported by LUT */ 112 #define SNR_DB_TO_BIT_PER_TONE_LUT_MAX 9 113 #define DB_NUM 20 114 /* 115 * A fudge factor to represent HW implementation margin in dB. 116 * Predicted throughput matches pretty well with OTA throughput with this 117 * fudge factor. 118 */ 119 #define SNR_MARGIN_DB 16 120 #define TWO_IN_DB 3 121 static int32_t 122 SNR_DB_TO_BIT_PER_TONE_LUT[DB_NUM] = {0, 171, 212, 262, 323, 396, 484, 123 586, 706, 844, 1000, 1176, 1370, 1583, 1812, 2058, 2317, 2588, 2870, 3161}; 124 #endif 125 126 static bool cm_is_better_bss(struct scan_cache_entry *bss1, 127 struct scan_cache_entry *bss2) 128 { 129 if (bss1->bss_score > bss2->bss_score) 130 return true; 131 else if (bss1->bss_score == bss2->bss_score) 132 if (bss1->rssi_raw > bss2->rssi_raw) 133 return true; 134 135 return false; 136 } 137 138 /** 139 * cm_get_rssi_pcnt_for_slot() - calculate rssi % score based on the slot 140 * index between the high rssi and low rssi threshold 141 * @high_rssi_threshold: High rssi of the window 142 * @low_rssi_threshold: low rssi of the window 143 * @high_rssi_pcnt: % score for the high rssi 144 * @low_rssi_pcnt: %score for the low rssi 145 * @bucket_size: bucket size of the window 146 * @bss_rssi: Input rssi for which value need to be calculated 147 * 148 * Return: rssi pct to use for the given rssi 149 */ 150 static inline 151 int8_t cm_get_rssi_pcnt_for_slot(int32_t high_rssi_threshold, 152 int32_t low_rssi_threshold, 153 uint32_t high_rssi_pcnt, 154 uint32_t low_rssi_pcnt, 155 uint32_t bucket_size, int8_t bss_rssi) 156 { 157 int8_t slot_index, slot_size, rssi_diff, num_slot, rssi_pcnt; 158 159 num_slot = ((high_rssi_threshold - 160 low_rssi_threshold) / bucket_size) + 1; 161 slot_size = ((high_rssi_pcnt - low_rssi_pcnt) + 162 (num_slot / 2)) / (num_slot); 163 rssi_diff = high_rssi_threshold - bss_rssi; 164 slot_index = (rssi_diff / bucket_size) + 1; 165 rssi_pcnt = high_rssi_pcnt - (slot_size * slot_index); 166 if (rssi_pcnt < low_rssi_pcnt) 167 rssi_pcnt = low_rssi_pcnt; 168 169 mlme_debug("Window %d -> %d pcnt range %d -> %d bucket_size %d bss_rssi %d num_slot %d slot_size %d rssi_diff %d slot_index %d rssi_pcnt %d", 170 high_rssi_threshold, low_rssi_threshold, high_rssi_pcnt, 171 low_rssi_pcnt, bucket_size, bss_rssi, num_slot, slot_size, 172 rssi_diff, slot_index, rssi_pcnt); 173 174 return rssi_pcnt; 175 } 176 177 /** 178 * cm_calculate_rssi_score() - Calculate RSSI score based on AP RSSI 179 * @score_param: rssi score params 180 * @rssi: rssi of the AP 181 * @rssi_weightage: rssi_weightage out of total weightage 182 * 183 * Return: rssi score 184 */ 185 static int32_t cm_calculate_rssi_score(struct rssi_config_score *score_param, 186 int32_t rssi, uint8_t rssi_weightage) 187 { 188 int8_t rssi_pcnt; 189 int32_t total_rssi_score; 190 int32_t best_rssi_threshold; 191 int32_t good_rssi_threshold; 192 int32_t bad_rssi_threshold; 193 uint32_t good_rssi_pcnt; 194 uint32_t bad_rssi_pcnt; 195 uint32_t good_bucket_size; 196 uint32_t bad_bucket_size; 197 198 best_rssi_threshold = score_param->best_rssi_threshold * (-1); 199 good_rssi_threshold = score_param->good_rssi_threshold * (-1); 200 bad_rssi_threshold = score_param->bad_rssi_threshold * (-1); 201 good_rssi_pcnt = score_param->good_rssi_pcnt; 202 bad_rssi_pcnt = score_param->bad_rssi_pcnt; 203 good_bucket_size = score_param->good_rssi_bucket_size; 204 bad_bucket_size = score_param->bad_rssi_bucket_size; 205 206 total_rssi_score = (CM_MAX_PCT_SCORE * rssi_weightage); 207 208 /* 209 * If RSSI is better than the best rssi threshold then it return full 210 * score. 211 */ 212 if (rssi > best_rssi_threshold) 213 return total_rssi_score; 214 /* 215 * If RSSI is less or equal to bad rssi threshold then it return 216 * least score. 217 */ 218 if (rssi <= bad_rssi_threshold) 219 return (total_rssi_score * bad_rssi_pcnt) / 100; 220 221 /* RSSI lies between best to good rssi threshold */ 222 if (rssi > good_rssi_threshold) 223 rssi_pcnt = cm_get_rssi_pcnt_for_slot(best_rssi_threshold, 224 good_rssi_threshold, 100, good_rssi_pcnt, 225 good_bucket_size, rssi); 226 else 227 rssi_pcnt = cm_get_rssi_pcnt_for_slot(good_rssi_threshold, 228 bad_rssi_threshold, good_rssi_pcnt, 229 bad_rssi_pcnt, bad_bucket_size, 230 rssi); 231 232 return (total_rssi_score * rssi_pcnt) / 100; 233 } 234 235 /** 236 * cm_rssi_is_same_bucket() - check if both rssi fall in same bucket 237 * @rssi_top_thresh: high rssi threshold of the the window 238 * @low_rssi_threshold: low rssi of the window 239 * @rssi_ref1: rssi ref one 240 * @rssi_ref2: rssi ref two 241 * @bucket_size: bucket size of the window 242 * 243 * Return: true if both fall in same window 244 */ 245 static inline bool cm_rssi_is_same_bucket(int8_t rssi_top_thresh, 246 int8_t rssi_ref1, int8_t rssi_ref2, 247 int8_t bucket_size) 248 { 249 int8_t rssi_diff1 = 0; 250 int8_t rssi_diff2 = 0; 251 252 rssi_diff1 = rssi_top_thresh - rssi_ref1; 253 rssi_diff2 = rssi_top_thresh - rssi_ref2; 254 255 return (rssi_diff1 / bucket_size) == (rssi_diff2 / bucket_size); 256 } 257 258 /** 259 * cm_roam_calculate_prorated_pcnt_by_rssi() - Calculate prorated RSSI score 260 * based on AP RSSI. This will be used to determine HT VHT score 261 * @score_param: rssi score params 262 * @rssi: bss rssi 263 * @rssi_weightage: rssi_weightage out of total weightage 264 * 265 * If rssi is greater than good threshold return 100, if less than bad return 0, 266 * if between good and bad, return prorated rssi score for the index. 267 * 268 * Return: rssi prorated score 269 */ 270 static int8_t cm_roam_calculate_prorated_pcnt_by_rssi( 271 struct rssi_config_score *score_param, 272 int32_t rssi, uint8_t rssi_weightage) 273 { 274 int32_t good_rssi_threshold; 275 int32_t bad_rssi_threshold; 276 int8_t rssi_pref_5g_rssi_thresh; 277 bool same_bucket; 278 279 good_rssi_threshold = score_param->good_rssi_threshold * (-1); 280 bad_rssi_threshold = score_param->bad_rssi_threshold * (-1); 281 rssi_pref_5g_rssi_thresh = score_param->rssi_pref_5g_rssi_thresh * (-1); 282 283 /* If RSSI is greater than good rssi return full weight */ 284 if (rssi > good_rssi_threshold) 285 return CM_MAX_PCT_SCORE; 286 287 same_bucket = cm_rssi_is_same_bucket(good_rssi_threshold, rssi, 288 rssi_pref_5g_rssi_thresh, 289 score_param->bad_rssi_bucket_size); 290 if (same_bucket || (rssi < rssi_pref_5g_rssi_thresh)) 291 return 0; 292 /* If RSSI is less or equal to bad rssi threshold then it return 0 */ 293 if (rssi <= bad_rssi_threshold) 294 return 0; 295 296 /* If RSSI is between good and bad threshold */ 297 return cm_get_rssi_pcnt_for_slot(good_rssi_threshold, 298 bad_rssi_threshold, 299 score_param->good_rssi_pcnt, 300 score_param->bad_rssi_pcnt, 301 score_param->bad_rssi_bucket_size, 302 rssi); 303 } 304 305 /** 306 * cm_calculate_bandwidth_score() - Calculate BW score 307 * @entry: scan entry 308 * @score_config: scoring config 309 * @phy_config: psoc phy configs 310 * @prorated_pct: prorated % to return dependent on RSSI 311 * 312 * Return: bw score 313 */ 314 static int32_t cm_calculate_bandwidth_score(struct scan_cache_entry *entry, 315 struct scoring_cfg *score_config, 316 struct psoc_phy_config *phy_config, 317 uint8_t prorated_pct) 318 { 319 uint32_t score; 320 int32_t bw_weight_per_idx; 321 uint8_t bw_above_20 = 0; 322 uint8_t ch_width_index; 323 bool is_vht = false; 324 325 bw_weight_per_idx = score_config->bandwidth_weight_per_index; 326 327 if (WLAN_REG_IS_24GHZ_CH_FREQ(entry->channel.chan_freq)) { 328 bw_above_20 = phy_config->bw_above_20_24ghz; 329 if (phy_config->vht_24G_cap) 330 is_vht = true; 331 } else if (phy_config->vht_cap) { 332 is_vht = true; 333 bw_above_20 = phy_config->bw_above_20_5ghz; 334 } 335 336 if (IS_WLAN_PHYMODE_160MHZ(entry->phy_mode)) 337 ch_width_index = CM_160MHZ_BW_INDEX; 338 else if (IS_WLAN_PHYMODE_80MHZ(entry->phy_mode)) 339 ch_width_index = CM_80MHZ_BW_INDEX; 340 else if (IS_WLAN_PHYMODE_40MHZ(entry->phy_mode)) 341 ch_width_index = CM_40MHZ_BW_INDEX; 342 else 343 ch_width_index = CM_20MHZ_BW_INDEX; 344 345 if (!phy_config->ht_cap && 346 ch_width_index > CM_20MHZ_BW_INDEX) 347 ch_width_index = CM_20MHZ_BW_INDEX; 348 349 if (!is_vht && ch_width_index > CM_40MHZ_BW_INDEX) 350 ch_width_index = CM_40MHZ_BW_INDEX; 351 352 if (bw_above_20 && ch_width_index > CM_20MHZ_BW_INDEX) 353 score = CM_GET_SCORE_PERCENTAGE(bw_weight_per_idx, 354 ch_width_index); 355 else 356 score = CM_GET_SCORE_PERCENTAGE(bw_weight_per_idx, 357 CM_20MHZ_BW_INDEX); 358 359 return (prorated_pct * score * 360 score_config->weight_config.chan_width_weightage) / 361 CM_MAX_PCT_SCORE; 362 } 363 364 /** 365 * cm_get_score_for_index() - get score for the given index 366 * @index: index for which we need the score 367 * @weightage: weigtage for the param 368 * @score: per slot score 369 * 370 * Return: score for the index 371 */ 372 static int32_t cm_get_score_for_index(uint8_t index, 373 uint8_t weightage, 374 struct per_slot_score *score) 375 { 376 if (index <= CM_SCORE_INDEX_3) 377 return weightage * CM_GET_SCORE_PERCENTAGE( 378 score->score_pcnt3_to_0, 379 index); 380 else if (index <= CM_SCORE_INDEX_7) 381 return weightage * CM_GET_SCORE_PERCENTAGE( 382 score->score_pcnt7_to_4, 383 index - CM_SCORE_OFFSET_INDEX_7_4); 384 else if (index <= CM_SCORE_INDEX_11) 385 return weightage * CM_GET_SCORE_PERCENTAGE( 386 score->score_pcnt11_to_8, 387 index - CM_SCORE_OFFSET_INDEX_11_8); 388 else 389 return weightage * CM_GET_SCORE_PERCENTAGE( 390 score->score_pcnt15_to_12, 391 index - CM_SCORE_OFFSET_INDEX_15_12); 392 } 393 394 /** 395 * cm_get_congestion_pct() - Calculate congestion pct from esp/qbss load 396 * @entry: bss information 397 * 398 * Return: congestion pct 399 */ 400 static int32_t cm_get_congestion_pct(struct scan_cache_entry *entry) 401 { 402 uint32_t ap_load = 0; 403 uint32_t est_air_time_percentage = 0; 404 uint32_t congestion = 0; 405 406 if (entry->air_time_fraction) { 407 /* Convert 0-255 range to percentage */ 408 est_air_time_percentage = entry->air_time_fraction * 409 CM_MAX_CHANNEL_WEIGHT; 410 est_air_time_percentage = qdf_do_div(est_air_time_percentage, 411 CM_MAX_ESTIMATED_AIR_TIME_FRACTION); 412 /* 413 * Calculate channel congestion from estimated air time 414 * fraction. 415 */ 416 congestion = CM_MAX_CHANNEL_UTILIZATION - 417 est_air_time_percentage; 418 } else if (entry->qbss_chan_load) { 419 ap_load = (entry->qbss_chan_load * CM_MAX_PCT_SCORE); 420 /* 421 * Calculate ap_load in % from qbss channel load from 422 * 0-255 range 423 */ 424 congestion = qdf_do_div(ap_load, CM_MAX_AP_LOAD); 425 if (!congestion) 426 congestion = 1; 427 } 428 429 return congestion; 430 } 431 432 /** 433 * cm_calculate_congestion_score() - Calculate congestion score 434 * @entry: bss information 435 * @score_params: bss score params 436 * @congestion_pct: congestion pct 437 * 438 * Return: congestion score 439 */ 440 static int32_t cm_calculate_congestion_score(struct scan_cache_entry *entry, 441 struct scoring_cfg *score_params, 442 uint32_t *congestion_pct) 443 { 444 uint32_t window_size; 445 uint8_t index; 446 int32_t good_rssi_threshold; 447 uint8_t chan_congestion_weight; 448 449 *congestion_pct = cm_get_congestion_pct(entry); 450 451 if (!score_params->esp_qbss_scoring.num_slot) 452 return 0; 453 454 if (score_params->esp_qbss_scoring.num_slot > 455 CM_SCORE_MAX_INDEX) 456 score_params->esp_qbss_scoring.num_slot = 457 CM_SCORE_MAX_INDEX; 458 459 good_rssi_threshold = 460 score_params->rssi_score.good_rssi_threshold * (-1); 461 462 chan_congestion_weight = 463 score_params->weight_config.channel_congestion_weightage; 464 465 /* For bad zone rssi get score from last index */ 466 if (entry->rssi_raw <= good_rssi_threshold) 467 return cm_get_score_for_index( 468 score_params->esp_qbss_scoring.num_slot, 469 chan_congestion_weight, 470 &score_params->esp_qbss_scoring); 471 472 if (!*congestion_pct) 473 return chan_congestion_weight * 474 CM_GET_SCORE_PERCENTAGE( 475 score_params->esp_qbss_scoring.score_pcnt3_to_0, 476 CM_SCORE_INDEX_0); 477 478 window_size = CM_MAX_PCT_SCORE / 479 score_params->esp_qbss_scoring.num_slot; 480 481 /* Desired values are from 1 to 15, as 0 is for not present. so do +1 */ 482 index = qdf_do_div(*congestion_pct, window_size) + 1; 483 484 if (index > score_params->esp_qbss_scoring.num_slot) 485 index = score_params->esp_qbss_scoring.num_slot; 486 487 return cm_get_score_for_index(index, 488 chan_congestion_weight, 489 &score_params->esp_qbss_scoring); 490 } 491 492 /** 493 * cm_calculate_nss_score() - Calculate congestion score 494 * @psoc: psoc ptr 495 * @score_config: scoring config 496 * @ap_nss: ap nss 497 * @prorated_pct: prorated % to return dependent on RSSI 498 * 499 * Return: nss score 500 */ 501 static int32_t cm_calculate_nss_score(struct wlan_objmgr_psoc *psoc, 502 struct scoring_cfg *score_config, 503 uint8_t ap_nss, uint8_t prorated_pct, 504 uint32_t sta_nss) 505 { 506 uint8_t nss; 507 uint8_t score_pct; 508 509 nss = ap_nss; 510 if (sta_nss < nss) 511 nss = sta_nss; 512 513 /* TODO: enhance for 8x8 */ 514 if (nss == 4) 515 score_pct = CM_GET_SCORE_PERCENTAGE( 516 score_config->nss_weight_per_index, 517 CM_NSS_4x4_INDEX); 518 else if (nss == 3) 519 score_pct = CM_GET_SCORE_PERCENTAGE( 520 score_config->nss_weight_per_index, 521 CM_NSS_3x3_INDEX); 522 else if (nss == 2) 523 score_pct = CM_GET_SCORE_PERCENTAGE( 524 score_config->nss_weight_per_index, 525 CM_NSS_2x2_INDEX); 526 else 527 score_pct = CM_GET_SCORE_PERCENTAGE( 528 score_config->nss_weight_per_index, 529 CM_NSS_1x1_INDEX); 530 531 return (score_config->weight_config.nss_weightage * score_pct * 532 prorated_pct) / CM_MAX_PCT_SCORE; 533 } 534 535 #ifdef WLAN_POLICY_MGR_ENABLE 536 static uint32_t cm_get_sta_nss(struct wlan_objmgr_psoc *psoc, 537 qdf_freq_t bss_channel_freq, 538 uint8_t vdev_nss_2g, uint8_t vdev_nss_5g) 539 { 540 /* 541 * If station support nss as 2*2 but AP support NSS as 1*1, 542 * this AP will be given half weight compare to AP which are having 543 * NSS as 2*2. 544 */ 545 546 if (policy_mgr_is_chnl_in_diff_band( 547 psoc, bss_channel_freq) && 548 policy_mgr_is_hw_dbs_capable(psoc) && 549 !(policy_mgr_is_hw_dbs_2x2_capable(psoc))) 550 return 1; 551 552 return (WLAN_REG_IS_24GHZ_CH_FREQ(bss_channel_freq) ? 553 vdev_nss_2g : 554 vdev_nss_5g); 555 } 556 #else 557 static uint32_t cm_get_sta_nss(struct wlan_objmgr_psoc *psoc, 558 qdf_freq_t bss_channel_freq, 559 uint8_t vdev_nss_2g, uint8_t vdev_nss_5g) 560 { 561 return (WLAN_REG_IS_24GHZ_CH_FREQ(bss_channel_freq) ? 562 vdev_nss_2g : 563 vdev_nss_5g); 564 } 565 #endif 566 567 #ifdef CONN_MGR_ADV_FEATURE 568 static bool 569 cm_get_pcl_weight_of_channel(uint32_t chan_freq, 570 struct pcl_freq_weight_list *pcl_lst, 571 int *pcl_chan_weight) 572 { 573 int i; 574 bool found = false; 575 576 if (!pcl_lst) 577 return found; 578 579 for (i = 0; i < pcl_lst->num_of_pcl_channels; i++) { 580 if (pcl_lst->pcl_freq_list[i] == chan_freq) { 581 *pcl_chan_weight = pcl_lst->pcl_weight_list[i]; 582 found = true; 583 break; 584 } 585 } 586 587 return found; 588 } 589 590 /** 591 * cm_calculate_pcl_score() - Calculate PCL score based on PCL weightage 592 * @pcl_chan_weight: pcl weight of BSS channel 593 * @pcl_weightage: PCL _weightage out of total weightage 594 * 595 * Return: pcl score 596 */ 597 static int32_t cm_calculate_pcl_score(int pcl_chan_weight, 598 uint8_t pcl_weightage) 599 { 600 int32_t pcl_score = 0; 601 int32_t temp_pcl_chan_weight = 0; 602 603 if (pcl_chan_weight) { 604 temp_pcl_chan_weight = 605 (CM_MAX_WEIGHT_OF_PCL_CHANNELS - pcl_chan_weight); 606 temp_pcl_chan_weight = qdf_do_div( 607 temp_pcl_chan_weight, 608 CM_PCL_GROUPS_WEIGHT_DIFFERENCE); 609 pcl_score = pcl_weightage - temp_pcl_chan_weight; 610 if (pcl_score < 0) 611 pcl_score = 0; 612 } 613 614 return pcl_score * CM_MAX_PCT_SCORE; 615 } 616 617 /** 618 * cm_calculate_oce_wan_score() - Calculate oce wan score 619 * @entry: bss information 620 * @score_params: bss score params 621 * 622 * Return: oce wan score 623 */ 624 static int32_t cm_calculate_oce_wan_score( 625 struct scan_cache_entry *entry, 626 struct scoring_cfg *score_params) 627 { 628 uint32_t window_size; 629 uint8_t index; 630 struct oce_reduced_wan_metrics wan_metrics; 631 uint8_t *mbo_oce_ie; 632 633 if (!score_params->oce_wan_scoring.num_slot) 634 return 0; 635 636 if (score_params->oce_wan_scoring.num_slot > 637 CM_SCORE_MAX_INDEX) 638 score_params->oce_wan_scoring.num_slot = 639 CM_SCORE_MAX_INDEX; 640 641 window_size = CM_SCORE_MAX_INDEX / 642 score_params->oce_wan_scoring.num_slot; 643 mbo_oce_ie = util_scan_entry_mbo_oce(entry); 644 if (wlan_parse_oce_reduced_wan_metrics_ie(mbo_oce_ie, &wan_metrics)) { 645 mlme_err("downlink_av_cap %d", wan_metrics.downlink_av_cap); 646 /* if capacity is 0 return 0 score */ 647 if (!wan_metrics.downlink_av_cap) 648 return 0; 649 /* Desired values are from 1 to WLAN_SCORE_MAX_INDEX */ 650 index = qdf_do_div(wan_metrics.downlink_av_cap, 651 window_size); 652 } else { 653 index = CM_SCORE_INDEX_0; 654 } 655 656 if (index > score_params->oce_wan_scoring.num_slot) 657 index = score_params->oce_wan_scoring.num_slot; 658 659 return cm_get_score_for_index(index, 660 score_params->weight_config.oce_wan_weightage, 661 &score_params->oce_wan_scoring); 662 } 663 664 /** 665 * cm_calculate_oce_subnet_id_weightage() - Calculate oce subnet id weightage 666 * @entry: bss entry 667 * @score_params: bss score params 668 * @oce_subnet_id_present: check if subnet id subelement is present in OCE IE 669 * 670 * Return: oce subnet id score 671 */ 672 static uint32_t 673 cm_calculate_oce_subnet_id_weightage(struct scan_cache_entry *entry, 674 struct scoring_cfg *score_params, 675 bool *oce_subnet_id_present) 676 { 677 uint32_t score = 0; 678 uint8_t *mbo_oce_ie; 679 680 mbo_oce_ie = util_scan_entry_mbo_oce(entry); 681 *oce_subnet_id_present = wlan_parse_oce_subnet_id_ie(mbo_oce_ie); 682 683 /* Consider 50% weightage if subnet id sub element is present */ 684 if (*oce_subnet_id_present) 685 score = score_params->weight_config.oce_subnet_id_weightage * 686 (CM_MAX_PCT_SCORE / 2); 687 688 return score; 689 } 690 691 /** 692 * cm_calculate_sae_pk_ap_weightage() - Calculate SAE-PK AP weightage 693 * @entry: bss entry 694 * @score_params: bss score params 695 * @sae_pk_cap_present: sae_pk cap presetn in RSNXE capability field 696 * 697 * Return: SAE-PK AP weightage score 698 */ 699 static uint32_t 700 cm_calculate_sae_pk_ap_weightage(struct scan_cache_entry *entry, 701 struct scoring_cfg *score_params, 702 bool *sae_pk_cap_present) 703 { 704 const uint8_t *rsnxe_ie; 705 const uint8_t *rsnxe_cap; 706 uint8_t cap_len; 707 708 rsnxe_ie = util_scan_entry_rsnxe(entry); 709 710 rsnxe_cap = wlan_crypto_parse_rsnxe_ie(rsnxe_ie, &cap_len); 711 712 if (!rsnxe_cap) 713 return 0; 714 715 *sae_pk_cap_present = *rsnxe_cap & WLAN_CRYPTO_RSNX_CAP_SAE_PK; 716 if (*sae_pk_cap_present) 717 return score_params->weight_config.sae_pk_ap_weightage * 718 CM_MAX_PCT_SCORE; 719 720 return 0; 721 } 722 723 /** 724 * cm_calculate_oce_ap_tx_pwr_weightage() - Calculate oce ap tx pwr weightage 725 * @entry: bss entry 726 * @score_params: bss score params 727 * @ap_tx_pwr_dbm: pointer to hold ap tx power 728 * 729 * Return: oce ap tx power score 730 */ 731 static uint32_t 732 cm_calculate_oce_ap_tx_pwr_weightage(struct scan_cache_entry *entry, 733 struct scoring_cfg *score_params, 734 int8_t *ap_tx_pwr_dbm) 735 { 736 uint8_t *mbo_oce_ie, ap_tx_pwr_factor; 737 struct rssi_config_score *rssi_score_param; 738 int32_t best_rssi_threshold, good_rssi_threshold, bad_rssi_threshold; 739 uint32_t good_rssi_pcnt, bad_rssi_pcnt, good_bucket_size; 740 uint32_t score, normalized_ap_tx_pwr, bad_bucket_size; 741 bool ap_tx_pwr_cap_present = true; 742 743 mbo_oce_ie = util_scan_entry_mbo_oce(entry); 744 if (!wlan_parse_oce_ap_tx_pwr_ie(mbo_oce_ie, ap_tx_pwr_dbm)) { 745 ap_tx_pwr_cap_present = false; 746 /* If no OCE AP TX pwr, consider Uplink RSSI = Downlink RSSI */ 747 normalized_ap_tx_pwr = entry->rssi_raw; 748 } else { 749 /* 750 * Normalized ap_tx_pwr = 751 * Uplink RSSI = (STA TX Power - * (AP TX power - RSSI)) in dBm. 752 * Currently assuming STA Tx Power to be 20dBm, though later it 753 * need to fetched from hal-phy API. 754 */ 755 normalized_ap_tx_pwr = 756 (20 - (*ap_tx_pwr_dbm - entry->rssi_raw)); 757 } 758 759 rssi_score_param = &score_params->rssi_score; 760 761 best_rssi_threshold = rssi_score_param->best_rssi_threshold * (-1); 762 good_rssi_threshold = rssi_score_param->good_rssi_threshold * (-1); 763 bad_rssi_threshold = rssi_score_param->bad_rssi_threshold * (-1); 764 good_rssi_pcnt = rssi_score_param->good_rssi_pcnt; 765 bad_rssi_pcnt = rssi_score_param->bad_rssi_pcnt; 766 good_bucket_size = rssi_score_param->good_rssi_bucket_size; 767 bad_bucket_size = rssi_score_param->bad_rssi_bucket_size; 768 769 /* Uplink RSSI is better than best rssi threshold */ 770 if (normalized_ap_tx_pwr > best_rssi_threshold) { 771 ap_tx_pwr_factor = CM_MAX_PCT_SCORE; 772 } else if (normalized_ap_tx_pwr <= bad_rssi_threshold) { 773 /* Uplink RSSI is less or equal to bad rssi threshold */ 774 ap_tx_pwr_factor = rssi_score_param->bad_rssi_pcnt; 775 } else if (normalized_ap_tx_pwr > good_rssi_threshold) { 776 /* Uplink RSSI lies between best to good rssi threshold */ 777 ap_tx_pwr_factor = 778 cm_get_rssi_pcnt_for_slot( 779 best_rssi_threshold, 780 good_rssi_threshold, 100, 781 good_rssi_pcnt, 782 good_bucket_size, normalized_ap_tx_pwr); 783 } else { 784 /* Uplink RSSI lies between good to best rssi threshold */ 785 ap_tx_pwr_factor = 786 cm_get_rssi_pcnt_for_slot( 787 good_rssi_threshold, 788 bad_rssi_threshold, good_rssi_pcnt, 789 bad_rssi_pcnt, bad_bucket_size, 790 normalized_ap_tx_pwr); 791 } 792 793 score = score_params->weight_config.oce_ap_tx_pwr_weightage * 794 ap_tx_pwr_factor; 795 796 return score; 797 } 798 799 static bool cm_is_assoc_allowed(struct psoc_mlme_obj *mlme_psoc_obj, 800 struct scan_cache_entry *entry) 801 { 802 uint8_t reason; 803 uint8_t *mbo_oce; 804 bool check_assoc_disallowed; 805 806 mbo_oce = util_scan_entry_mbo_oce(entry); 807 808 check_assoc_disallowed = 809 mlme_psoc_obj->psoc_cfg.score_config.check_assoc_disallowed; 810 811 if (check_assoc_disallowed && 812 wlan_parse_oce_assoc_disallowed_ie(mbo_oce, &reason)) { 813 mlme_nofl_debug("Candidate("QDF_MAC_ADDR_FMT" freq %d): rssi %d, assoc disallowed set in MBO/OCE IE reason %d", 814 QDF_MAC_ADDR_REF(entry->bssid.bytes), 815 entry->channel.chan_freq, 816 entry->rssi_raw, reason); 817 return false; 818 } 819 820 return true; 821 } 822 823 void wlan_cm_set_check_assoc_disallowed(struct wlan_objmgr_psoc *psoc, 824 bool value) 825 { 826 struct psoc_mlme_obj *mlme_psoc_obj; 827 828 mlme_psoc_obj = wlan_psoc_mlme_get_cmpt_obj(psoc); 829 if (!mlme_psoc_obj) 830 return; 831 832 mlme_psoc_obj->psoc_cfg.score_config.check_assoc_disallowed = value; 833 } 834 835 void wlan_cm_get_check_assoc_disallowed(struct wlan_objmgr_psoc *psoc, 836 bool *value) 837 { 838 struct psoc_mlme_obj *mlme_psoc_obj; 839 840 mlme_psoc_obj = wlan_psoc_mlme_get_cmpt_obj(psoc); 841 if (!mlme_psoc_obj) { 842 *value = false; 843 return; 844 } 845 846 *value = mlme_psoc_obj->psoc_cfg.score_config.check_assoc_disallowed; 847 } 848 849 static enum phy_ch_width 850 cm_calculate_bandwidth(struct scan_cache_entry *entry, 851 struct psoc_phy_config *phy_config) 852 { 853 uint8_t bw_above_20 = 0; 854 bool is_vht = false; 855 enum phy_ch_width ch_width; 856 857 if (WLAN_REG_IS_24GHZ_CH_FREQ(entry->channel.chan_freq)) { 858 bw_above_20 = phy_config->bw_above_20_24ghz; 859 if (phy_config->vht_24G_cap) 860 is_vht = true; 861 } else if (phy_config->vht_cap) { 862 is_vht = true; 863 bw_above_20 = phy_config->bw_above_20_5ghz; 864 } 865 866 if (IS_WLAN_PHYMODE_160MHZ(entry->phy_mode)) 867 ch_width = CH_WIDTH_160MHZ; 868 else if (IS_WLAN_PHYMODE_80MHZ(entry->phy_mode)) 869 ch_width = CH_WIDTH_80MHZ; 870 else if (IS_WLAN_PHYMODE_40MHZ(entry->phy_mode)) 871 ch_width = CH_WIDTH_40MHZ; 872 else 873 ch_width = CH_WIDTH_20MHZ; 874 875 if (!phy_config->ht_cap && 876 ch_width >= CH_WIDTH_20MHZ) 877 ch_width = CH_WIDTH_20MHZ; 878 879 if (!is_vht && ch_width > CH_WIDTH_40MHZ) 880 ch_width = CH_WIDTH_40MHZ; 881 882 if (!bw_above_20) 883 ch_width = CH_WIDTH_20MHZ; 884 885 return ch_width; 886 } 887 888 static uint8_t cm_etp_get_ba_win_size_from_esp(uint8_t esp_ba_win_size) 889 { 890 /* 891 * BA Window Size subfield is three bits in length and indicates the 892 * size of the Block Ack window that is. 893 * 802.11-2016.pdf Table 9-262 BA Window Size subfield encoding 894 */ 895 switch (esp_ba_win_size) { 896 case 1: return 2; 897 case 2: return 4; 898 case 3: return 6; 899 case 4: return 8; 900 case 5: return 16; 901 case 6: return 32; 902 case 7: return 64; 903 default: return 1; 904 } 905 } 906 907 static uint16_t cm_get_etp_ntone(bool is_ht, bool is_vht, 908 enum phy_ch_width ch_width) 909 { 910 uint16_t n_sd = 52, n_seg = 1; 911 912 if (is_vht) { 913 /* Refer Table 21-5 in IEEE80211-2016 Spec */ 914 if (ch_width == CH_WIDTH_20MHZ) 915 n_sd = 52; 916 else if (ch_width == CH_WIDTH_40MHZ) 917 n_sd = 108; 918 else if (ch_width == CH_WIDTH_80MHZ) 919 n_sd = 234; 920 else if (ch_width == CH_WIDTH_80P80MHZ) 921 n_sd = 234, n_seg = 2; 922 else if (ch_width == CH_WIDTH_160MHZ) 923 n_sd = 468; 924 } else if (is_ht) { 925 /* Refer Table 19-6 in IEEE80211-2016 Spec */ 926 if (ch_width == CH_WIDTH_20MHZ) 927 n_sd = 52; 928 if (ch_width == CH_WIDTH_40MHZ) 929 n_sd = 108; 930 } else { 931 n_sd = 48; 932 } 933 934 return (n_sd * n_seg); 935 } 936 937 /* Refer Table 27-64 etc in Draft P802.11ax_D7.0.txt */ 938 static uint16_t cm_get_etp_he_ntone(enum phy_ch_width ch_width) 939 { 940 uint16_t n_sd = 234, n_seg = 1; 941 942 if (ch_width == CH_WIDTH_20MHZ) 943 n_sd = 234; 944 else if (ch_width == CH_WIDTH_40MHZ) 945 n_sd = 468; 946 else if (ch_width == CH_WIDTH_80MHZ) 947 n_sd = 980; 948 else if (ch_width == CH_WIDTH_80P80MHZ) 949 n_sd = 980, n_seg = 2; 950 else if (ch_width == CH_WIDTH_160MHZ) 951 n_sd = 1960; 952 953 return (n_sd * n_seg); 954 } 955 956 static uint16_t cm_get_etp_phy_header_dur_us(bool is_ht, bool is_vht, 957 uint8_t nss) 958 { 959 uint16_t dur_us = 0; 960 961 if (is_vht) { 962 /* 963 * Refer Figure 21-4 in 80211-2016 Spec 964 * 8 (L-STF) + 8 (L-LTF) + 4 (L-SIG) + 965 * 8 (VHT-SIG-A) + 4 (VHT-STF) + 4 (VHT-SIG-B) 966 */ 967 dur_us = 36; 968 /* (nss * VHT-LTF) = (nss * 4) */ 969 dur_us += (nss << 2); 970 } else if (is_ht) { 971 /* 972 * Refer Figure 19-1 in 80211-2016 Spec 973 * 8 (L-STF) + 8 (L-LTF) + 4 (L-SIG) + 8 (HT-SIG) + 974 * 4 (HT-STF) 975 */ 976 dur_us = 32; 977 /* (nss * HT-LTF = nss * 4) */ 978 dur_us += (nss << 2); 979 } else { 980 /* 981 * non-HT 982 * Refer Figure 19-1 in 80211-2016 Spec 983 * 8 (L-STF) + 8 (L-LTF) + 4 (L-SIG) 984 */ 985 dur_us = 20; 986 } 987 return dur_us; 988 } 989 990 static uint32_t 991 cm_get_etp_max_bits_per_sc_1000x_for_nss(struct wlan_objmgr_psoc *psoc, 992 struct scan_cache_entry *entry, 993 uint8_t nss, 994 struct psoc_phy_config *phy_config) 995 { 996 uint32_t max_bits_per_sc_1000x = 5000; /* 5 * 1000 */ 997 uint8_t mcs_map; 998 struct wlan_ie_vhtcaps *bss_vht_cap; 999 struct wlan_ie_hecaps *bss_he_cap; 1000 uint32_t self_rx_mcs_map; 1001 QDF_STATUS status; 1002 1003 bss_vht_cap = (struct wlan_ie_vhtcaps *)util_scan_entry_vhtcap(entry); 1004 bss_he_cap = (struct wlan_ie_hecaps *)util_scan_entry_hecap(entry); 1005 if (!phy_config->vht_cap || !bss_vht_cap) { 1006 mlme_err("vht unsupported"); 1007 return max_bits_per_sc_1000x; 1008 } 1009 1010 status = wlan_mlme_cfg_get_vht_rx_mcs_map(psoc, &self_rx_mcs_map); 1011 if (QDF_IS_STATUS_ERROR(status)) 1012 return max_bits_per_sc_1000x; 1013 1014 if (nss == 4) { 1015 mcs_map = (self_rx_mcs_map & 0xC0) >> 6; 1016 mcs_map = QDF_MIN(mcs_map, 1017 (bss_vht_cap->rx_mcs_map & 0xC0) >> 6); 1018 } else if (nss == 3) { 1019 mcs_map = (self_rx_mcs_map & 0x30) >> 4; 1020 mcs_map = QDF_MIN(mcs_map, 1021 (bss_vht_cap->rx_mcs_map & 0x30) >> 4); 1022 } else if (nss == 2) { 1023 mcs_map = (self_rx_mcs_map & 0x0C) >> 2; 1024 mcs_map = QDF_MIN(mcs_map, 1025 (bss_vht_cap->rx_mcs_map & 0x0C) >> 2); 1026 } else { 1027 mcs_map = (self_rx_mcs_map & 0x03); 1028 mcs_map = QDF_MIN(mcs_map, (bss_vht_cap->rx_mcs_map & 0x03)); 1029 } 1030 if (bss_he_cap) { 1031 if (mcs_map == 2) 1032 max_bits_per_sc_1000x = 8333; /* 10 *5/6 * 1000 */ 1033 else if (mcs_map == 1) 1034 max_bits_per_sc_1000x = 7500; /* 10 * 3/4 * 1000 */ 1035 } else { 1036 if (mcs_map == 2) 1037 max_bits_per_sc_1000x = 6667; /* 8 * 5/6 * 1000 */ 1038 else if (mcs_map == 1) 1039 max_bits_per_sc_1000x = 6000; /* 8 * 3/4 * 1000 */ 1040 } 1041 return max_bits_per_sc_1000x; 1042 } 1043 1044 /* Refer Table 9-163 in 80211-2016 Spec */ 1045 static uint32_t cm_etp_get_min_mpdu_ss_us_100x(struct htcap_cmn_ie *htcap) 1046 { 1047 tSirMacHTParametersInfo *ampdu_param; 1048 uint8_t ampdu_density; 1049 1050 ampdu_param = (tSirMacHTParametersInfo *)&htcap->ampdu_param; 1051 ampdu_density = ampdu_param->mpduDensity; 1052 1053 if (ampdu_density == 1) 1054 return 25; /* (1/4) * 100 */ 1055 else if (ampdu_density == 2) 1056 return 50; /* (1/2) * 100 */ 1057 else if (ampdu_density == 3) 1058 return 100; /* 1 * 100 */ 1059 else if (ampdu_density == 4) 1060 return 200; /* 2 * 100 */ 1061 else if (ampdu_density == 5) 1062 return 400; /* 4 * 100 */ 1063 else if (ampdu_density == 6) 1064 return 800; /* 8 * 100 */ 1065 else if (ampdu_density == 7) 1066 return 1600; /* 16 * 100 */ 1067 else 1068 return 100; 1069 } 1070 1071 /* Refer Table 9-162 in 80211-2016 Spec */ 1072 static uint32_t cm_etp_get_max_amsdu_len(struct wlan_objmgr_psoc *psoc, 1073 struct htcap_cmn_ie *htcap) 1074 { 1075 uint8_t bss_max_amsdu; 1076 uint32_t bss_max_amsdu_len; 1077 QDF_STATUS status; 1078 1079 status = wlan_mlme_get_max_amsdu_num(psoc, &bss_max_amsdu); 1080 if (QDF_IS_STATUS_ERROR(status)) 1081 bss_max_amsdu_len = 3839; 1082 else if (bss_max_amsdu == 1) 1083 bss_max_amsdu_len = 7935; 1084 else 1085 bss_max_amsdu_len = 3839; 1086 1087 return bss_max_amsdu_len; 1088 } 1089 1090 // Calculate the number of bits per tone based on the input of SNR in dB 1091 // The output is scaled up by BIT_PER_TONE_SCALE for integer representation 1092 static uint32_t 1093 calculate_bit_per_tone(int32_t rssi, enum phy_ch_width ch_width) 1094 { 1095 int32_t noise_floor_db_boost; 1096 int32_t noise_floor_dbm; 1097 int32_t snr_db; 1098 int32_t bit_per_tone; 1099 int32_t lut_in_idx; 1100 1101 noise_floor_db_boost = TWO_IN_DB * ch_width; 1102 noise_floor_dbm = WLAN_NOISE_FLOOR_DBM_DEFAULT + noise_floor_db_boost + 1103 SNR_MARGIN_DB; 1104 snr_db = rssi - noise_floor_dbm; 1105 if (snr_db <= SNR_DB_TO_BIT_PER_TONE_LUT_MAX) { 1106 lut_in_idx = QDF_MAX(snr_db, SNR_DB_TO_BIT_PER_TONE_LUT_MIN) 1107 - SNR_DB_TO_BIT_PER_TONE_LUT_MIN; 1108 lut_in_idx = QDF_MIN(lut_in_idx, DB_NUM - 1); 1109 bit_per_tone = SNR_DB_TO_BIT_PER_TONE_LUT[lut_in_idx]; 1110 } else { 1111 /* 1112 * SNR_tone = 10^(SNR/10) 1113 * log2(1+SNR_tone) ~= log2(SNR_tone) = 1114 * log10(SNR_tone)/log10(2) = log10(10^(SNR/10)) / 0.3 1115 * = (SNR/10) / 0.3 = SNR/3 1116 * So log2(1+SNR_tone) = SNR/3. 1000x for this is SNR*334 1117 */ 1118 bit_per_tone = snr_db * 334; 1119 } 1120 1121 return bit_per_tone; 1122 } 1123 1124 static uint32_t 1125 cm_calculate_etp(struct wlan_objmgr_psoc *psoc, 1126 struct scan_cache_entry *entry, 1127 struct etp_params *etp_param, 1128 uint8_t max_nss, enum phy_ch_width ch_width, 1129 bool is_ht, bool is_vht, bool is_he, 1130 int8_t rssi, 1131 struct psoc_phy_config *phy_config) 1132 { 1133 uint16_t ntone; 1134 uint16_t phy_hdr_dur_us, max_amsdu_len = 1500, min_mpdu_ss_us_100x = 0; 1135 uint32_t max_bits_per_sc_1000x, log_2_snr_tone_1000x; 1136 uint32_t ppdu_payload_dur_us = 0, mpdu_per_ampdu, mpdu_per_ppdu; 1137 uint32_t single_ppdu_dur_us, estimated_throughput_mbps, data_rate_kbps; 1138 struct htcap_cmn_ie *htcap; 1139 1140 htcap = (struct htcap_cmn_ie *)util_scan_entry_htcap(entry); 1141 if (ch_width > CH_WIDTH_160MHZ) 1142 return CM_AVOID_CANDIDATE_MIN_SCORE; 1143 1144 if (is_he) 1145 ntone = cm_get_etp_he_ntone(ch_width); 1146 else 1147 ntone = cm_get_etp_ntone(is_ht, is_vht, ch_width); 1148 phy_hdr_dur_us = cm_get_etp_phy_header_dur_us(is_ht, is_vht, max_nss); 1149 1150 max_bits_per_sc_1000x = 1151 cm_get_etp_max_bits_per_sc_1000x_for_nss(psoc, entry, 1152 max_nss, phy_config); 1153 if (rssi < WLAN_NOISE_FLOOR_DBM_DEFAULT) 1154 return CM_AVOID_CANDIDATE_MIN_SCORE; 1155 1156 log_2_snr_tone_1000x = calculate_bit_per_tone(rssi, ch_width); 1157 1158 /* Eq. R-2 Pg:3508 in 80211-2016 Spec */ 1159 if (is_he) 1160 data_rate_kbps = 1161 QDF_MIN(log_2_snr_tone_1000x, max_bits_per_sc_1000x) * 1162 (max_nss * ntone) / HE_PPDU_PAYLOAD_SYMBOL_DUR_US; 1163 else 1164 data_rate_kbps = 1165 QDF_MIN(log_2_snr_tone_1000x, max_bits_per_sc_1000x) * 1166 (max_nss * ntone) / PPDU_PAYLOAD_SYMBOL_DUR_US; 1167 mlme_debug("data_rate_kbps: %d", data_rate_kbps); 1168 if (data_rate_kbps < 1000) { 1169 /* Return ETP as 1 since datarate is not even 1 Mbps */ 1170 return CM_AVOID_CANDIDATE_MIN_SCORE; 1171 } 1172 /* compute MPDU_p_PPDU */ 1173 if (is_ht) { 1174 min_mpdu_ss_us_100x = 1175 cm_etp_get_min_mpdu_ss_us_100x(htcap); 1176 max_amsdu_len = 1177 cm_etp_get_max_amsdu_len(psoc, htcap); 1178 ppdu_payload_dur_us = 1179 etp_param->data_ppdu_dur_target_us - phy_hdr_dur_us; 1180 mpdu_per_ampdu = 1181 QDF_MIN(qdf_ceil(ppdu_payload_dur_us * 100, 1182 min_mpdu_ss_us_100x), 1183 qdf_ceil(ppdu_payload_dur_us * 1184 (data_rate_kbps / 1000), 1185 (MAC_HEADER_LEN + max_amsdu_len) * 8)); 1186 mpdu_per_ppdu = QDF_MIN(etp_param->ba_window_size, 1187 QDF_MAX(1, mpdu_per_ampdu)); 1188 } else { 1189 mpdu_per_ppdu = 1; 1190 } 1191 1192 /* compute PPDU_Dur */ 1193 single_ppdu_dur_us = 1194 qdf_ceil((MAC_HEADER_LEN + max_amsdu_len) * mpdu_per_ppdu * 8, 1195 (data_rate_kbps / 1000) * PPDU_PAYLOAD_SYMBOL_DUR_US); 1196 single_ppdu_dur_us *= PPDU_PAYLOAD_SYMBOL_DUR_US; 1197 single_ppdu_dur_us += phy_hdr_dur_us; 1198 1199 estimated_throughput_mbps = 1200 qdf_ceil(mpdu_per_ppdu * max_amsdu_len * 8, single_ppdu_dur_us); 1201 estimated_throughput_mbps = 1202 (estimated_throughput_mbps * 1203 etp_param->airtime_fraction) / 1204 CM_MAX_ESTIMATED_AIR_TIME_FRACTION; 1205 1206 if (estimated_throughput_mbps < CM_AVOID_CANDIDATE_MIN_SCORE) 1207 estimated_throughput_mbps = CM_AVOID_CANDIDATE_MIN_SCORE; 1208 if (estimated_throughput_mbps > CM_BEST_CANDIDATE_MAX_BSS_SCORE) 1209 estimated_throughput_mbps = CM_BEST_CANDIDATE_MAX_BSS_SCORE; 1210 1211 mlme_nofl_debug("Candidate("QDF_MAC_ADDR_FMT" freq %d): rssi %d HT %d VHT %d HE %d ATF: %d NSS %d, ch_width: %d", 1212 QDF_MAC_ADDR_REF(entry->bssid.bytes), 1213 entry->channel.chan_freq, 1214 entry->rssi_raw, is_ht, is_vht, is_he, 1215 etp_param->airtime_fraction, 1216 entry->nss, ch_width); 1217 if (is_ht) 1218 mlme_nofl_debug("min_mpdu_ss_us_100x = %d, max_amsdu_len = %d, ppdu_payload_dur_us = %d, mpdu_per_ampdu = %d, mpdu_per_ppdu = %d, ba_window_size = %d", 1219 min_mpdu_ss_us_100x, max_amsdu_len, 1220 ppdu_payload_dur_us, mpdu_per_ampdu, 1221 mpdu_per_ppdu, etp_param->ba_window_size); 1222 mlme_nofl_debug("ETP score params: ntone: %d, phy_hdr_dur_us: %d, max_bits_per_sc_1000x: %d, log_2_snr_tone_1000x: %d mpdu_p_ppdu = %d, max_amsdu_len = %d, ppdu_dur_us = %d, total score = %d", 1223 ntone, phy_hdr_dur_us, max_bits_per_sc_1000x, 1224 log_2_snr_tone_1000x, mpdu_per_ppdu, max_amsdu_len, 1225 single_ppdu_dur_us, estimated_throughput_mbps); 1226 1227 return estimated_throughput_mbps; 1228 } 1229 1230 static uint32_t 1231 cm_calculate_etp_score(struct wlan_objmgr_psoc *psoc, 1232 struct scan_cache_entry *entry, 1233 struct psoc_phy_config *phy_config) 1234 { 1235 enum phy_ch_width ch_width; 1236 uint32_t nss; 1237 bool is_he_intersect = false; 1238 bool is_vht_intersect = false; 1239 bool is_ht_intersect = false; 1240 struct wlan_esp_info *esp; 1241 struct wlan_esp_ie *esp_ie; 1242 struct etp_params etp_param; 1243 1244 if (phy_config->he_cap && entry->ie_list.hecap) 1245 is_he_intersect = true; 1246 if ((phy_config->vht_cap || phy_config->vht_24G_cap) && 1247 (entry->ie_list.vhtcap || 1248 WLAN_REG_IS_6GHZ_CHAN_FREQ(entry->channel.chan_freq))) 1249 is_vht_intersect = true; 1250 if (phy_config->ht_cap && entry->ie_list.htcap) 1251 is_ht_intersect = true; 1252 nss = cm_get_sta_nss(psoc, entry->channel.chan_freq, 1253 phy_config->vdev_nss_24g, 1254 phy_config->vdev_nss_5g); 1255 nss = QDF_MIN(nss, entry->nss); 1256 ch_width = cm_calculate_bandwidth(entry, phy_config); 1257 1258 /* Initialize default ETP params */ 1259 etp_param.airtime_fraction = 255 / 2; 1260 etp_param.ba_window_size = 32; 1261 etp_param.data_ppdu_dur_target_us = 5000; /* 5 msec */ 1262 1263 if (entry->air_time_fraction) { 1264 etp_param.airtime_fraction = entry->air_time_fraction; 1265 esp_ie = (struct wlan_esp_ie *) 1266 util_scan_entry_esp_info(entry); 1267 if (esp_ie) { 1268 esp = &esp_ie->esp_info_AC_BE; 1269 etp_param.ba_window_size = 1270 cm_etp_get_ba_win_size_from_esp(esp->ba_window_size); 1271 etp_param.data_ppdu_dur_target_us = 1272 50 * esp->ppdu_duration; 1273 mlme_debug("esp ba_window_size: %d, ppdu_duration: %d", 1274 esp->ba_window_size, esp->ppdu_duration); 1275 } 1276 } else if (entry->qbss_chan_load) { 1277 mlme_debug("qbss_chan_load: %d", entry->qbss_chan_load); 1278 etp_param.airtime_fraction = 1279 CM_MAX_ESTIMATED_AIR_TIME_FRACTION - 1280 entry->qbss_chan_load; 1281 } 1282 /* If ini vendor_roam_score_algorithm=1, just calculate ETP of all 1283 * bssid of ssid selected by high layer, and try to connect AP by 1284 * order of ETP, legacy algorithm with following Parameters/Weightage 1285 * becomes useless. ETP should be [1Mbps, 20000Mbps],matches score 1286 * range: [1, 20000] 1287 */ 1288 return cm_calculate_etp(psoc, entry, 1289 &etp_param, 1290 nss, 1291 ch_width, 1292 is_ht_intersect, 1293 is_vht_intersect, 1294 is_he_intersect, 1295 entry->rssi_raw, 1296 phy_config); 1297 } 1298 1299 #ifdef CONFIG_BAND_6GHZ 1300 static bool cm_check_h2e_support(const uint8_t *rsnxe, uint8_t sae_pwe) 1301 { 1302 const uint8_t *rsnxe_cap; 1303 uint8_t cap_len; 1304 1305 rsnxe_cap = wlan_crypto_parse_rsnxe_ie(rsnxe, &cap_len); 1306 if (!rsnxe_cap) { 1307 mlme_debug("RSNXE caps not present"); 1308 return false; 1309 } 1310 1311 if (*rsnxe_cap & WLAN_CRYPTO_RSNX_CAP_SAE_H2E) 1312 return true; 1313 1314 mlme_debug("RSNXE caps %x dont have H2E support", *rsnxe_cap); 1315 1316 return false; 1317 } 1318 #endif 1319 #else 1320 static bool 1321 cm_get_pcl_weight_of_channel(uint32_t chan_freq, 1322 struct pcl_freq_weight_list *pcl_lst, 1323 int *pcl_chan_weight) 1324 { 1325 return false; 1326 } 1327 1328 static int32_t cm_calculate_pcl_score(int pcl_chan_weight, 1329 uint8_t pcl_weightage) 1330 { 1331 return 0; 1332 } 1333 1334 static int32_t cm_calculate_oce_wan_score(struct scan_cache_entry *entry, 1335 struct scoring_cfg *score_params) 1336 { 1337 return 0; 1338 } 1339 1340 static uint32_t 1341 cm_calculate_oce_subnet_id_weightage(struct scan_cache_entry *entry, 1342 struct scoring_cfg *score_params, 1343 bool *oce_subnet_id_present) 1344 { 1345 return 0; 1346 } 1347 1348 static uint32_t 1349 cm_calculate_sae_pk_ap_weightage(struct scan_cache_entry *entry, 1350 struct scoring_cfg *score_params, 1351 bool *sae_pk_cap_present) 1352 { 1353 return 0; 1354 } 1355 1356 static uint32_t 1357 cm_calculate_oce_ap_tx_pwr_weightage(struct scan_cache_entry *entry, 1358 struct scoring_cfg *score_params, 1359 int8_t *ap_tx_pwr_dbm) 1360 { 1361 return 0; 1362 } 1363 1364 static inline bool cm_is_assoc_allowed(struct psoc_mlme_obj *mlme_psoc_obj, 1365 struct scan_cache_entry *entry) 1366 { 1367 return true; 1368 } 1369 1370 static uint32_t 1371 cm_calculate_etp_score(struct wlan_objmgr_psoc *psoc, 1372 struct scan_cache_entry *entry, 1373 struct psoc_phy_config *phy_config) 1374 { 1375 return 0; 1376 } 1377 1378 #ifdef CONFIG_BAND_6GHZ 1379 static bool cm_check_h2e_support(const uint8_t *rsnxe, uint8_t sae_pwe) 1380 { 1381 /* limiting to H2E usage only */ 1382 if (sae_pwe == 1) 1383 return true; 1384 1385 mlme_debug("sae_pwe %d is not H2E", sae_pwe); 1386 1387 return false; 1388 } 1389 #endif 1390 #endif 1391 1392 /** 1393 * cm_get_band_score() - Get band prefernce weightage 1394 * freq: Operating frequency of the AP 1395 * @score_config: Score configuration 1396 * 1397 * Return: Band score for AP. 1398 */ 1399 static int 1400 cm_get_band_score(uint32_t freq, struct scoring_cfg *score_config) 1401 { 1402 uint8_t band_index; 1403 struct weight_cfg *weight_config; 1404 1405 weight_config = &score_config->weight_config; 1406 1407 if (WLAN_REG_IS_5GHZ_CH_FREQ(freq)) 1408 band_index = CM_BAND_5G_INDEX; 1409 else if (WLAN_REG_IS_24GHZ_CH_FREQ(freq)) 1410 band_index = CM_BAND_2G_INDEX; 1411 else if (WLAN_REG_IS_6GHZ_CHAN_FREQ(freq)) 1412 band_index = CM_BAND_6G_INDEX; 1413 else 1414 return 0; 1415 1416 return weight_config->chan_band_weightage * 1417 CM_GET_SCORE_PERCENTAGE(score_config->band_weight_per_index, 1418 band_index); 1419 } 1420 1421 static int cm_calculate_bss_score(struct wlan_objmgr_psoc *psoc, 1422 struct scan_cache_entry *entry, 1423 int pcl_chan_weight, 1424 struct qdf_mac_addr *bssid_hint) 1425 { 1426 int32_t score = 0; 1427 int32_t rssi_score = 0; 1428 int32_t pcl_score = 0; 1429 int32_t ht_score = 0; 1430 int32_t vht_score = 0; 1431 int32_t he_score = 0; 1432 int32_t bandwidth_score = 0; 1433 int32_t beamformee_score = 0; 1434 int32_t band_score = 0; 1435 int32_t nss_score = 0; 1436 int32_t congestion_score = 0; 1437 int32_t congestion_pct = 0; 1438 int32_t oce_wan_score = 0; 1439 uint8_t oce_ap_tx_pwr_score = 0; 1440 uint8_t oce_subnet_id_score = 0; 1441 uint32_t sae_pk_score = 0; 1442 bool oce_subnet_id_present = 0; 1443 bool sae_pk_cap_present = 0; 1444 int8_t ap_tx_pwr_dbm = 0; 1445 uint8_t prorated_pcnt; 1446 bool is_vht = false; 1447 int8_t good_rssi_threshold; 1448 int8_t rssi_pref_5g_rssi_thresh; 1449 bool same_bucket = false; 1450 bool ap_su_beam_former = false; 1451 struct wlan_ie_vhtcaps *vht_cap; 1452 struct scoring_cfg *score_config; 1453 struct weight_cfg *weight_config; 1454 uint32_t sta_nss; 1455 struct psoc_mlme_obj *mlme_psoc_obj; 1456 struct psoc_phy_config *phy_config; 1457 1458 mlme_psoc_obj = wlan_psoc_mlme_get_cmpt_obj(psoc); 1459 if (!mlme_psoc_obj) 1460 return 0; 1461 1462 phy_config = &mlme_psoc_obj->psoc_cfg.phy_config; 1463 score_config = &mlme_psoc_obj->psoc_cfg.score_config; 1464 weight_config = &score_config->weight_config; 1465 1466 if (score_config->is_bssid_hint_priority && bssid_hint && 1467 qdf_is_macaddr_equal(bssid_hint, &entry->bssid)) { 1468 entry->bss_score = CM_BEST_CANDIDATE_MAX_BSS_SCORE; 1469 mlme_nofl_debug("Candidate("QDF_MAC_ADDR_FMT" freq %d): rssi %d BSSID hint given, give max score %d", 1470 QDF_MAC_ADDR_REF(entry->bssid.bytes), 1471 entry->channel.chan_freq, 1472 entry->rssi_raw, 1473 CM_BEST_CANDIDATE_MAX_BSS_SCORE); 1474 return CM_BEST_CANDIDATE_MAX_BSS_SCORE; 1475 } 1476 if (score_config->vendor_roam_score_algorithm) { 1477 score = cm_calculate_etp_score(psoc, entry, phy_config); 1478 entry->bss_score = score; 1479 return score; 1480 } 1481 rssi_score = cm_calculate_rssi_score(&score_config->rssi_score, 1482 entry->rssi_raw, 1483 weight_config->rssi_weightage); 1484 score += rssi_score; 1485 1486 pcl_score = cm_calculate_pcl_score(pcl_chan_weight, 1487 weight_config->pcl_weightage); 1488 score += pcl_score; 1489 1490 prorated_pcnt = cm_roam_calculate_prorated_pcnt_by_rssi( 1491 &score_config->rssi_score, entry->rssi_raw, 1492 weight_config->rssi_weightage); 1493 1494 /* 1495 * Add HT weight if HT is supported by the AP. In case 1496 * of 6 GHZ AP, HT and VHT won't be supported so that 1497 * these weightage to the same by default to match 1498 * with 2.4/5 GHZ APs where HT, VHT is supported 1499 */ 1500 if (phy_config->ht_cap && (entry->ie_list.htcap || 1501 WLAN_REG_IS_6GHZ_CHAN_FREQ(entry->channel.chan_freq))) 1502 ht_score = prorated_pcnt * 1503 weight_config->ht_caps_weightage; 1504 score += ht_score; 1505 1506 if (WLAN_REG_IS_24GHZ_CH_FREQ(entry->channel.chan_freq)) { 1507 if (phy_config->vht_24G_cap) 1508 is_vht = true; 1509 } else if (phy_config->vht_cap) { 1510 is_vht = true; 1511 } 1512 1513 /* Add VHT score to 6 GHZ AP to match with 2.4/5 GHZ APs */ 1514 if (is_vht && (entry->ie_list.vhtcap || 1515 WLAN_REG_IS_6GHZ_CHAN_FREQ(entry->channel.chan_freq))) 1516 vht_score = prorated_pcnt * 1517 weight_config->vht_caps_weightage; 1518 score += vht_score; 1519 1520 if (phy_config->he_cap && entry->ie_list.hecap) 1521 he_score = prorated_pcnt * 1522 weight_config->he_caps_weightage; 1523 score += he_score; 1524 1525 bandwidth_score = cm_calculate_bandwidth_score(entry, score_config, 1526 phy_config, 1527 prorated_pcnt); 1528 score += bandwidth_score; 1529 1530 good_rssi_threshold = 1531 score_config->rssi_score.good_rssi_threshold * (-1); 1532 rssi_pref_5g_rssi_thresh = 1533 score_config->rssi_score.rssi_pref_5g_rssi_thresh * (-1); 1534 if (entry->rssi_raw < good_rssi_threshold) 1535 same_bucket = cm_rssi_is_same_bucket(good_rssi_threshold, 1536 entry->rssi_raw, rssi_pref_5g_rssi_thresh, 1537 score_config->rssi_score.bad_rssi_bucket_size); 1538 1539 vht_cap = (struct wlan_ie_vhtcaps *)util_scan_entry_vhtcap(entry); 1540 if (vht_cap && vht_cap->su_beam_former) 1541 ap_su_beam_former = true; 1542 if (phy_config->beamformee_cap && is_vht && 1543 ap_su_beam_former && 1544 (entry->rssi_raw > rssi_pref_5g_rssi_thresh) && !same_bucket) 1545 beamformee_score = CM_MAX_PCT_SCORE * 1546 weight_config->beamforming_cap_weightage; 1547 score += beamformee_score; 1548 1549 congestion_score = cm_calculate_congestion_score(entry, score_config, 1550 &congestion_pct); 1551 score += congestion_score; 1552 /* 1553 * Consider OCE WAN score and band preference score only if 1554 * congestion_pct is greater than CONGESTION_THRSHOLD_FOR_BAND_OCE_SCORE 1555 */ 1556 if (congestion_pct < CM_CONGESTION_THRSHOLD_FOR_BAND_OCE_SCORE) { 1557 /* 1558 * If AP is on 5/6 GHZ channel , extra weigtage is added to BSS 1559 * score. if RSSI is greater tha 5g rssi threshold or fall in 1560 * same bucket else give weigtage to 2.4 GHZ AP. 1561 */ 1562 if ((entry->rssi_raw > rssi_pref_5g_rssi_thresh) && 1563 !same_bucket) { 1564 if (!WLAN_REG_IS_24GHZ_CH_FREQ(entry->channel.chan_freq)) 1565 band_score = cm_get_band_score( 1566 entry->channel.chan_freq, 1567 score_config); 1568 } else if (WLAN_REG_IS_24GHZ_CH_FREQ( 1569 entry->channel.chan_freq)) { 1570 band_score = cm_get_band_score(entry->channel.chan_freq, 1571 score_config); 1572 } 1573 score += band_score; 1574 1575 oce_wan_score = cm_calculate_oce_wan_score(entry, score_config); 1576 score += oce_wan_score; 1577 } 1578 1579 oce_ap_tx_pwr_score = 1580 cm_calculate_oce_ap_tx_pwr_weightage(entry, score_config, 1581 &ap_tx_pwr_dbm); 1582 score += oce_ap_tx_pwr_score; 1583 1584 oce_subnet_id_score = cm_calculate_oce_subnet_id_weightage(entry, 1585 score_config, 1586 &oce_subnet_id_present); 1587 score += oce_subnet_id_score; 1588 1589 sae_pk_score = cm_calculate_sae_pk_ap_weightage(entry, score_config, 1590 &sae_pk_cap_present); 1591 score += sae_pk_score; 1592 1593 sta_nss = cm_get_sta_nss(psoc, entry->channel.chan_freq, 1594 phy_config->vdev_nss_24g, 1595 phy_config->vdev_nss_5g); 1596 1597 /* 1598 * If station support nss as 2*2 but AP support NSS as 1*1, 1599 * this AP will be given half weight compare to AP which are having 1600 * NSS as 2*2. 1601 */ 1602 nss_score = cm_calculate_nss_score(psoc, score_config, entry->nss, 1603 prorated_pcnt, sta_nss); 1604 score += nss_score; 1605 1606 mlme_nofl_debug("Candidate("QDF_MAC_ADDR_FMT" freq %d): rssi %d HT %d VHT %d HE %d su bfer %d phy %d air time frac %d qbss %d cong_pct %d NSS %d ap_tx_pwr_dbm %d oce_subnet_id_present %d sae_pk_cap_present %d prorated_pcnt %d", 1607 QDF_MAC_ADDR_REF(entry->bssid.bytes), 1608 entry->channel.chan_freq, 1609 entry->rssi_raw, util_scan_entry_htcap(entry) ? 1 : 0, 1610 util_scan_entry_vhtcap(entry) ? 1 : 0, 1611 util_scan_entry_hecap(entry) ? 1 : 0, ap_su_beam_former, 1612 entry->phy_mode, entry->air_time_fraction, 1613 entry->qbss_chan_load, congestion_pct, entry->nss, 1614 ap_tx_pwr_dbm, oce_subnet_id_present, 1615 sae_pk_cap_present, prorated_pcnt); 1616 1617 mlme_nofl_debug("Scores: rssi %d pcl %d ht %d vht %d he %d bfee %d bw %d band %d congestion %d nss %d oce wan %d oce ap tx pwr %d subnet %d sae_pk %d TOTAL %d", 1618 rssi_score, pcl_score, ht_score, 1619 vht_score, he_score, beamformee_score, bandwidth_score, 1620 band_score, congestion_score, nss_score, oce_wan_score, 1621 oce_ap_tx_pwr_score, oce_subnet_id_score, 1622 sae_pk_score, score); 1623 1624 entry->bss_score = score; 1625 1626 return score; 1627 } 1628 1629 static void cm_list_insert_sorted(qdf_list_t *scan_list, 1630 struct scan_cache_node *scan_entry) 1631 { 1632 qdf_list_node_t *cur_node = NULL, *next_node = NULL; 1633 struct scan_cache_node *curr_entry; 1634 1635 qdf_list_peek_front(scan_list, &cur_node); 1636 while (cur_node) { 1637 curr_entry = qdf_container_of(cur_node, struct scan_cache_node, 1638 node); 1639 if (cm_is_better_bss(scan_entry->entry, curr_entry->entry)) { 1640 qdf_list_insert_before(scan_list, &scan_entry->node, 1641 &curr_entry->node); 1642 break; 1643 } 1644 qdf_list_peek_next(scan_list, cur_node, &next_node); 1645 cur_node = next_node; 1646 next_node = NULL; 1647 } 1648 1649 if (!cur_node) 1650 qdf_list_insert_back(scan_list, &scan_entry->node); 1651 } 1652 1653 void wlan_cm_calculate_bss_score(struct wlan_objmgr_pdev *pdev, 1654 struct pcl_freq_weight_list *pcl_lst, 1655 qdf_list_t *scan_list, 1656 struct qdf_mac_addr *bssid_hint) 1657 { 1658 struct scan_cache_node *scan_entry; 1659 qdf_list_node_t *cur_node = NULL, *next_node = NULL; 1660 struct psoc_mlme_obj *mlme_psoc_obj; 1661 struct scoring_cfg *score_config; 1662 int pcl_chan_weight; 1663 QDF_STATUS status; 1664 struct psoc_phy_config *config; 1665 enum cm_blacklist_action blacklist_action; 1666 struct wlan_objmgr_psoc *psoc; 1667 bool assoc_allowed; 1668 struct scan_cache_node *force_connect_candidate = NULL; 1669 bool are_all_candidate_blacklisted = true; 1670 1671 psoc = wlan_pdev_get_psoc(pdev); 1672 1673 if (!psoc) { 1674 mlme_err("psoc NULL"); 1675 return; 1676 } 1677 if (!scan_list) { 1678 mlme_err("Scan list NULL"); 1679 return; 1680 } 1681 1682 mlme_psoc_obj = wlan_psoc_mlme_get_cmpt_obj(psoc); 1683 if (!mlme_psoc_obj) 1684 return; 1685 1686 score_config = &mlme_psoc_obj->psoc_cfg.score_config; 1687 config = &mlme_psoc_obj->psoc_cfg.phy_config; 1688 1689 mlme_nofl_debug("Self caps: HT %d VHT %d HE %d VHT_24Ghz %d BF cap %d bw_above_20_24ghz %d bw_above_20_5ghz %d 2.4G NSS %d 5G NSS %d", 1690 config->ht_cap, config->vht_cap, 1691 config->he_cap, config->vht_24G_cap, 1692 config->beamformee_cap, config->bw_above_20_24ghz, 1693 config->bw_above_20_5ghz, config->vdev_nss_24g, 1694 config->vdev_nss_5g); 1695 1696 /* calculate score for each AP */ 1697 if (qdf_list_peek_front(scan_list, &cur_node) != QDF_STATUS_SUCCESS) { 1698 mlme_err("failed to peer front of scan list"); 1699 return; 1700 } 1701 1702 while (cur_node) { 1703 qdf_list_peek_next(scan_list, cur_node, &next_node); 1704 pcl_chan_weight = 0; 1705 scan_entry = qdf_container_of(cur_node, struct scan_cache_node, 1706 node); 1707 1708 assoc_allowed = cm_is_assoc_allowed(mlme_psoc_obj, 1709 scan_entry->entry); 1710 1711 if (assoc_allowed) 1712 blacklist_action = wlan_blacklist_action_on_bssid(pdev, 1713 scan_entry->entry); 1714 else 1715 blacklist_action = CM_BLM_FORCE_REMOVE; 1716 1717 if (blacklist_action == CM_BLM_NO_ACTION || 1718 blacklist_action == CM_BLM_AVOID) 1719 are_all_candidate_blacklisted = false; 1720 1721 if (blacklist_action == CM_BLM_NO_ACTION && 1722 pcl_lst && pcl_lst->num_of_pcl_channels && 1723 scan_entry->entry->rssi_raw > CM_PCL_RSSI_THRESHOLD && 1724 score_config->weight_config.pcl_weightage) { 1725 if (cm_get_pcl_weight_of_channel( 1726 scan_entry->entry->channel.chan_freq, 1727 pcl_lst, &pcl_chan_weight)) { 1728 mlme_debug("pcl freq %d pcl_chan_weight %d", 1729 scan_entry->entry->channel.chan_freq, 1730 pcl_chan_weight); 1731 } 1732 } 1733 1734 if (blacklist_action == CM_BLM_NO_ACTION || 1735 (are_all_candidate_blacklisted && blacklist_action == CM_BLM_REMOVE)) { 1736 cm_calculate_bss_score(psoc, scan_entry->entry, 1737 pcl_chan_weight, bssid_hint); 1738 } else if (blacklist_action == CM_BLM_AVOID) { 1739 /* add min score so that it is added back in the end */ 1740 scan_entry->entry->bss_score = 1741 CM_AVOID_CANDIDATE_MIN_SCORE; 1742 mlme_nofl_debug("Candidate("QDF_MAC_ADDR_FMT" freq %d): rssi %d, is in Avoidlist, give min score %d", 1743 QDF_MAC_ADDR_REF(scan_entry->entry->bssid.bytes), 1744 scan_entry->entry->channel.chan_freq, 1745 scan_entry->entry->rssi_raw, 1746 scan_entry->entry->bss_score); 1747 } 1748 1749 /* 1750 * The below logic is added to select the best candidate 1751 * amongst the blacklisted candidates. This is done to 1752 * handle a case where all the BSSIDs become blacklisted 1753 * and hence there are continuous connection failures. 1754 * With the below logic if the action on BSSID is to remove 1755 * then we keep a backup node and restore the candidate 1756 * list. 1757 */ 1758 if (blacklist_action == CM_BLM_REMOVE && 1759 are_all_candidate_blacklisted) { 1760 if (!force_connect_candidate) { 1761 force_connect_candidate = 1762 qdf_mem_malloc( 1763 sizeof(*force_connect_candidate)); 1764 if (!force_connect_candidate) 1765 return; 1766 force_connect_candidate->entry = 1767 util_scan_copy_cache_entry(scan_entry->entry); 1768 if (!force_connect_candidate->entry) 1769 return; 1770 } else if (cm_is_better_bss( 1771 scan_entry->entry, 1772 force_connect_candidate->entry)) { 1773 util_scan_free_cache_entry( 1774 force_connect_candidate->entry); 1775 force_connect_candidate->entry = 1776 util_scan_copy_cache_entry(scan_entry->entry); 1777 if (!force_connect_candidate->entry) 1778 return; 1779 } 1780 } 1781 1782 /* Remove node from current location to add node back sorted */ 1783 status = qdf_list_remove_node(scan_list, cur_node); 1784 if (QDF_IS_STATUS_ERROR(status)) { 1785 mlme_err("failed to remove node for BSS "QDF_MAC_ADDR_FMT" from scan list", 1786 QDF_MAC_ADDR_REF(scan_entry->entry->bssid.bytes)); 1787 return; 1788 } 1789 1790 /* 1791 * If CM_BLM_REMOVE ie blacklisted or assoc not allowed then 1792 * free the entry else add back to the list sorted 1793 */ 1794 if (blacklist_action == CM_BLM_REMOVE || 1795 blacklist_action == CM_BLM_FORCE_REMOVE) { 1796 if (assoc_allowed) 1797 mlme_nofl_debug("Candidate("QDF_MAC_ADDR_FMT" freq %d): rssi %d, blm action %d is in Blacklist, remove entry", 1798 QDF_MAC_ADDR_REF(scan_entry->entry->bssid.bytes), 1799 scan_entry->entry->channel.chan_freq, 1800 scan_entry->entry->rssi_raw, 1801 blacklist_action); 1802 util_scan_free_cache_entry(scan_entry->entry); 1803 qdf_mem_free(scan_entry); 1804 } else { 1805 cm_list_insert_sorted(scan_list, scan_entry); 1806 } 1807 1808 cur_node = next_node; 1809 next_node = NULL; 1810 } 1811 1812 if (are_all_candidate_blacklisted && force_connect_candidate) { 1813 mlme_nofl_debug("All candidates in blacklist, Candidate("QDF_MAC_ADDR_FMT" freq %d): rssi %d, selected for connection", 1814 QDF_MAC_ADDR_REF(force_connect_candidate->entry->bssid.bytes), 1815 force_connect_candidate->entry->channel.chan_freq, 1816 force_connect_candidate->entry->rssi_raw); 1817 cm_list_insert_sorted(scan_list, force_connect_candidate); 1818 } else if (force_connect_candidate) { 1819 util_scan_free_cache_entry(force_connect_candidate->entry); 1820 qdf_mem_free(force_connect_candidate); 1821 } 1822 } 1823 1824 #ifdef CONFIG_BAND_6GHZ 1825 bool wlan_cm_6ghz_allowed_for_akm(struct wlan_objmgr_psoc *psoc, 1826 uint32_t key_mgmt, uint16_t rsn_caps, 1827 const uint8_t *rsnxe, uint8_t sae_pwe) 1828 { 1829 struct psoc_mlme_obj *mlme_psoc_obj; 1830 struct scoring_cfg *config; 1831 1832 mlme_psoc_obj = wlan_psoc_mlme_get_cmpt_obj(psoc); 1833 if (!mlme_psoc_obj) 1834 return false; 1835 1836 config = &mlme_psoc_obj->psoc_cfg.score_config; 1837 /* 1838 * if check_6ghz_security is not set check if key_mgmt_mask_6ghz is set 1839 * if key_mgmt_mask_6ghz is set check if AKM matches the user configured 1840 * 6Ghz security 1841 */ 1842 if (!config->check_6ghz_security) { 1843 if (!config->key_mgmt_mask_6ghz) 1844 return true; 1845 /* Check if AKM is allowed as per user 6Ghz allowed AKM mask */ 1846 if ((config->key_mgmt_mask_6ghz & key_mgmt) != key_mgmt) { 1847 mlme_debug("user configured mask %x didnt match AKM %x", 1848 config->key_mgmt_mask_6ghz , key_mgmt); 1849 return false; 1850 } 1851 1852 return true; 1853 } 1854 1855 /* Check if the AKM is allowed as per the 6Ghz allowed AKM mask */ 1856 if ((key_mgmt & ALLOWED_KEYMGMT_6G_MASK) != key_mgmt) 1857 return false; 1858 1859 /* if check_6ghz_security is set validate all checks for 6Ghz */ 1860 if (!(rsn_caps & WLAN_CRYPTO_RSN_CAP_MFP_ENABLED)) 1861 return false; 1862 1863 /* for SAE we need to check H2E support */ 1864 if (!(QDF_HAS_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_SAE) || 1865 QDF_HAS_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_FT_SAE))) 1866 return true; 1867 1868 return cm_check_h2e_support(rsnxe, sae_pwe); 1869 } 1870 1871 void wlan_cm_set_check_6ghz_security(struct wlan_objmgr_psoc *psoc, 1872 bool value) 1873 { 1874 struct psoc_mlme_obj *mlme_psoc_obj; 1875 1876 mlme_psoc_obj = wlan_psoc_mlme_get_cmpt_obj(psoc); 1877 if (!mlme_psoc_obj) 1878 return; 1879 1880 mlme_psoc_obj->psoc_cfg.score_config.check_6ghz_security = value; 1881 } 1882 1883 void wlan_cm_reset_check_6ghz_security(struct wlan_objmgr_psoc *psoc) 1884 { 1885 struct psoc_mlme_obj *mlme_psoc_obj; 1886 1887 mlme_psoc_obj = wlan_psoc_mlme_get_cmpt_obj(psoc); 1888 if (!mlme_psoc_obj) 1889 return; 1890 1891 mlme_psoc_obj->psoc_cfg.score_config.check_6ghz_security = 1892 cfg_get(psoc, CFG_CHECK_6GHZ_SECURITY); 1893 } 1894 1895 bool wlan_cm_get_check_6ghz_security(struct wlan_objmgr_psoc *psoc) 1896 { 1897 struct psoc_mlme_obj *mlme_psoc_obj; 1898 1899 mlme_psoc_obj = wlan_psoc_mlme_get_cmpt_obj(psoc); 1900 if (!mlme_psoc_obj) 1901 return false; 1902 1903 return mlme_psoc_obj->psoc_cfg.score_config.check_6ghz_security; 1904 } 1905 1906 void wlan_cm_set_6ghz_key_mgmt_mask(struct wlan_objmgr_psoc *psoc, 1907 uint32_t value) 1908 { 1909 struct psoc_mlme_obj *mlme_psoc_obj; 1910 1911 mlme_psoc_obj = wlan_psoc_mlme_get_cmpt_obj(psoc); 1912 if (!mlme_psoc_obj) 1913 return; 1914 1915 mlme_psoc_obj->psoc_cfg.score_config.key_mgmt_mask_6ghz = value; 1916 } 1917 1918 uint32_t wlan_cm_get_6ghz_key_mgmt_mask(struct wlan_objmgr_psoc *psoc) 1919 { 1920 struct psoc_mlme_obj *mlme_psoc_obj; 1921 1922 mlme_psoc_obj = wlan_psoc_mlme_get_cmpt_obj(psoc); 1923 if (!mlme_psoc_obj) 1924 return DEFAULT_KEYMGMT_6G_MASK; 1925 1926 return mlme_psoc_obj->psoc_cfg.score_config.key_mgmt_mask_6ghz; 1927 } 1928 1929 static void cm_fill_6ghz_params(struct wlan_objmgr_psoc *psoc, 1930 struct scoring_cfg *score_cfg) 1931 { 1932 /* Allow all security in 6Ghz by default */ 1933 score_cfg->check_6ghz_security = cfg_get(psoc, CFG_CHECK_6GHZ_SECURITY); 1934 score_cfg->key_mgmt_mask_6ghz = 1935 cfg_get(psoc, CFG_6GHZ_ALLOWED_AKM_MASK); 1936 } 1937 #else 1938 static inline void cm_fill_6ghz_params(struct wlan_objmgr_psoc *psoc, 1939 struct scoring_cfg *score_cfg) 1940 { 1941 } 1942 #endif 1943 1944 static uint32_t 1945 cm_limit_max_per_index_score(uint32_t per_index_score) 1946 { 1947 uint8_t i, score; 1948 1949 for (i = 0; i < CM_MAX_INDEX_PER_INI; i++) { 1950 score = CM_GET_SCORE_PERCENTAGE(per_index_score, i); 1951 if (score > CM_MAX_PCT_SCORE) 1952 CM_SET_SCORE_PERCENTAGE(per_index_score, 1953 CM_MAX_PCT_SCORE, i); 1954 } 1955 1956 return per_index_score; 1957 } 1958 1959 void wlan_cm_init_score_config(struct wlan_objmgr_psoc *psoc, 1960 struct scoring_cfg *score_cfg) 1961 { 1962 uint32_t total_weight; 1963 1964 score_cfg->weight_config.rssi_weightage = 1965 cfg_get(psoc, CFG_SCORING_RSSI_WEIGHTAGE); 1966 score_cfg->weight_config.ht_caps_weightage = 1967 cfg_get(psoc, CFG_SCORING_HT_CAPS_WEIGHTAGE); 1968 score_cfg->weight_config.vht_caps_weightage = 1969 cfg_get(psoc, CFG_SCORING_VHT_CAPS_WEIGHTAGE); 1970 score_cfg->weight_config.he_caps_weightage = 1971 cfg_get(psoc, CFG_SCORING_HE_CAPS_WEIGHTAGE); 1972 score_cfg->weight_config.chan_width_weightage = 1973 cfg_get(psoc, CFG_SCORING_CHAN_WIDTH_WEIGHTAGE); 1974 score_cfg->weight_config.chan_band_weightage = 1975 cfg_get(psoc, CFG_SCORING_CHAN_BAND_WEIGHTAGE); 1976 score_cfg->weight_config.nss_weightage = 1977 cfg_get(psoc, CFG_SCORING_NSS_WEIGHTAGE); 1978 score_cfg->weight_config.beamforming_cap_weightage = 1979 cfg_get(psoc, CFG_SCORING_BEAMFORM_CAP_WEIGHTAGE); 1980 score_cfg->weight_config.pcl_weightage = 1981 cfg_get(psoc, CFG_SCORING_PCL_WEIGHTAGE); 1982 score_cfg->weight_config.channel_congestion_weightage = 1983 cfg_get(psoc, CFG_SCORING_CHAN_CONGESTION_WEIGHTAGE); 1984 score_cfg->weight_config.oce_wan_weightage = 1985 cfg_get(psoc, CFG_SCORING_OCE_WAN_WEIGHTAGE); 1986 score_cfg->weight_config.oce_ap_tx_pwr_weightage = 1987 cfg_get(psoc, CFG_OCE_AP_TX_PWR_WEIGHTAGE); 1988 score_cfg->weight_config.oce_subnet_id_weightage = 1989 cfg_get(psoc, CFG_OCE_SUBNET_ID_WEIGHTAGE); 1990 score_cfg->weight_config.sae_pk_ap_weightage = 1991 cfg_get(psoc, CFG_SAE_PK_AP_WEIGHTAGE); 1992 1993 total_weight = score_cfg->weight_config.rssi_weightage + 1994 score_cfg->weight_config.ht_caps_weightage + 1995 score_cfg->weight_config.vht_caps_weightage + 1996 score_cfg->weight_config.he_caps_weightage + 1997 score_cfg->weight_config.chan_width_weightage + 1998 score_cfg->weight_config.chan_band_weightage + 1999 score_cfg->weight_config.nss_weightage + 2000 score_cfg->weight_config.beamforming_cap_weightage + 2001 score_cfg->weight_config.pcl_weightage + 2002 score_cfg->weight_config.channel_congestion_weightage + 2003 score_cfg->weight_config.oce_wan_weightage + 2004 score_cfg->weight_config.oce_ap_tx_pwr_weightage + 2005 score_cfg->weight_config.oce_subnet_id_weightage + 2006 score_cfg->weight_config.sae_pk_ap_weightage; 2007 2008 /* 2009 * If configured weights are greater than max weight, 2010 * fallback to default weights 2011 */ 2012 if (total_weight > CM_BEST_CANDIDATE_MAX_WEIGHT) { 2013 mlme_err("Total weight greater than %d, using default weights", 2014 CM_BEST_CANDIDATE_MAX_WEIGHT); 2015 score_cfg->weight_config.rssi_weightage = CM_RSSI_WEIGHTAGE; 2016 score_cfg->weight_config.ht_caps_weightage = 2017 CM_HT_CAPABILITY_WEIGHTAGE; 2018 score_cfg->weight_config.vht_caps_weightage = 2019 CM_VHT_CAP_WEIGHTAGE; 2020 score_cfg->weight_config.he_caps_weightage = 2021 CM_HE_CAP_WEIGHTAGE; 2022 score_cfg->weight_config.chan_width_weightage = 2023 CM_CHAN_WIDTH_WEIGHTAGE; 2024 score_cfg->weight_config.chan_band_weightage = 2025 CM_CHAN_BAND_WEIGHTAGE; 2026 score_cfg->weight_config.nss_weightage = CM_NSS_WEIGHTAGE; 2027 score_cfg->weight_config.beamforming_cap_weightage = 2028 CM_BEAMFORMING_CAP_WEIGHTAGE; 2029 score_cfg->weight_config.pcl_weightage = CM_PCL_WEIGHT; 2030 score_cfg->weight_config.channel_congestion_weightage = 2031 CM_CHANNEL_CONGESTION_WEIGHTAGE; 2032 score_cfg->weight_config.oce_wan_weightage = 2033 CM_OCE_WAN_WEIGHTAGE; 2034 score_cfg->weight_config.oce_ap_tx_pwr_weightage = 2035 CM_OCE_AP_TX_POWER_WEIGHTAGE; 2036 score_cfg->weight_config.oce_subnet_id_weightage = 2037 CM_OCE_SUBNET_ID_WEIGHTAGE; 2038 score_cfg->weight_config.sae_pk_ap_weightage = 2039 CM_SAE_PK_AP_WEIGHTAGE; 2040 } 2041 2042 score_cfg->rssi_score.best_rssi_threshold = 2043 cfg_get(psoc, CFG_SCORING_BEST_RSSI_THRESHOLD); 2044 score_cfg->rssi_score.good_rssi_threshold = 2045 cfg_get(psoc, CFG_SCORING_GOOD_RSSI_THRESHOLD); 2046 score_cfg->rssi_score.bad_rssi_threshold = 2047 cfg_get(psoc, CFG_SCORING_BAD_RSSI_THRESHOLD); 2048 2049 score_cfg->rssi_score.good_rssi_pcnt = 2050 cfg_get(psoc, CFG_SCORING_GOOD_RSSI_PERCENT); 2051 score_cfg->rssi_score.bad_rssi_pcnt = 2052 cfg_get(psoc, CFG_SCORING_BAD_RSSI_PERCENT); 2053 2054 score_cfg->rssi_score.good_rssi_bucket_size = 2055 cfg_get(psoc, CFG_SCORING_GOOD_RSSI_BUCKET_SIZE); 2056 score_cfg->rssi_score.bad_rssi_bucket_size = 2057 cfg_get(psoc, CFG_SCORING_BAD_RSSI_BUCKET_SIZE); 2058 2059 score_cfg->rssi_score.rssi_pref_5g_rssi_thresh = 2060 cfg_get(psoc, CFG_SCORING_RSSI_PREF_5G_THRESHOLD); 2061 2062 score_cfg->esp_qbss_scoring.num_slot = 2063 cfg_get(psoc, CFG_SCORING_NUM_ESP_QBSS_SLOTS); 2064 score_cfg->esp_qbss_scoring.score_pcnt3_to_0 = 2065 cm_limit_max_per_index_score( 2066 cfg_get(psoc, CFG_SCORING_ESP_QBSS_SCORE_IDX_3_TO_0)); 2067 score_cfg->esp_qbss_scoring.score_pcnt7_to_4 = 2068 cm_limit_max_per_index_score( 2069 cfg_get(psoc, CFG_SCORING_ESP_QBSS_SCORE_IDX_7_TO_4)); 2070 score_cfg->esp_qbss_scoring.score_pcnt11_to_8 = 2071 cm_limit_max_per_index_score( 2072 cfg_get(psoc, CFG_SCORING_ESP_QBSS_SCORE_IDX_11_TO_8)); 2073 score_cfg->esp_qbss_scoring.score_pcnt15_to_12 = 2074 cm_limit_max_per_index_score( 2075 cfg_get(psoc, CFG_SCORING_ESP_QBSS_SCORE_IDX_15_TO_12)); 2076 2077 score_cfg->oce_wan_scoring.num_slot = 2078 cfg_get(psoc, CFG_SCORING_NUM_OCE_WAN_SLOTS); 2079 score_cfg->oce_wan_scoring.score_pcnt3_to_0 = 2080 cm_limit_max_per_index_score( 2081 cfg_get(psoc, CFG_SCORING_OCE_WAN_SCORE_IDX_3_TO_0)); 2082 score_cfg->oce_wan_scoring.score_pcnt7_to_4 = 2083 cm_limit_max_per_index_score( 2084 cfg_get(psoc, CFG_SCORING_OCE_WAN_SCORE_IDX_7_TO_4)); 2085 score_cfg->oce_wan_scoring.score_pcnt11_to_8 = 2086 cm_limit_max_per_index_score( 2087 cfg_get(psoc, CFG_SCORING_OCE_WAN_SCORE_IDX_11_TO_8)); 2088 score_cfg->oce_wan_scoring.score_pcnt15_to_12 = 2089 cm_limit_max_per_index_score( 2090 cfg_get(psoc, CFG_SCORING_OCE_WAN_SCORE_IDX_15_TO_12)); 2091 2092 score_cfg->bandwidth_weight_per_index = 2093 cm_limit_max_per_index_score( 2094 cfg_get(psoc, CFG_SCORING_BW_WEIGHT_PER_IDX)); 2095 score_cfg->nss_weight_per_index = 2096 cm_limit_max_per_index_score( 2097 cfg_get(psoc, CFG_SCORING_NSS_WEIGHT_PER_IDX)); 2098 score_cfg->band_weight_per_index = 2099 cm_limit_max_per_index_score( 2100 cfg_get(psoc, CFG_SCORING_BAND_WEIGHT_PER_IDX)); 2101 score_cfg->is_bssid_hint_priority = 2102 cfg_get(psoc, CFG_IS_BSSID_HINT_PRIORITY); 2103 score_cfg->vendor_roam_score_algorithm = 2104 cfg_get(psoc, CFG_VENDOR_ROAM_SCORE_ALGORITHM); 2105 score_cfg->check_assoc_disallowed = true; 2106 cm_fill_6ghz_params(psoc, score_cfg); 2107 } 2108