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