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