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