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