Переглянути джерело

qcacmn: Only allow partner links with matching RSN caps

Each link in MLO can have different RSN capabilities with
different AKMs, PMF capability, UC/MC cipher suites and so on.
For any choice of links for MLO connection, the AKMs of the
links should have one common AKM.

Eliminate partner links without overlapping AKMs from MLO
connection.
Modify partner link AKM to match assoc link AKM, so that
only overlapping AKM is chosen even though an AKM with
higher security exists for partner link.

Change-Id: I9573e938789a4b95ae824872845d31008861f6f2
CRs-Fixed: 3693814
Vinod Kumar Pirla 1 рік тому
батько
коміт
c739c3b6cd

+ 12 - 1
umac/cmn_services/crypto/inc/wlan_crypto_global_api.h

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2017-2020 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -888,6 +888,17 @@ enum wlan_crypto_cipher_type
 wlan_crypto_get_cipher(struct wlan_objmgr_vdev *vdev,
 		       bool pairwise, uint8_t key_index);
 
+/**
+ * wlan_crypto_get_secure_akm_available() - Search the AKM bitmap to
+ * find the most secure AKM.
+ * @akm: Bitmap of available AKMs.
+ *
+ * Search in the decreasing order of AKM security and return the
+ * first matching AKM available in @akm bitmap.
+ *
+ * Return: enum wlan_crypto_key_mgmt
+ */
+wlan_crypto_key_mgmt wlan_crypto_get_secure_akm_available(uint32_t akm);
 #ifdef CRYPTO_SET_KEY_CONVERGED
 /**
  * wlan_crypto_update_set_key_peer() - Update the peer for set key

+ 65 - 1
umac/cmn_services/crypto/src/wlan_crypto_global_api.c

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -4245,6 +4245,70 @@ wlan_crypto_get_cipher(struct wlan_objmgr_vdev *vdev,
 		return WLAN_CRYPTO_CIPHER_INVALID;
 }
 
+wlan_crypto_key_mgmt wlan_crypto_get_secure_akm_available(uint32_t akm)
+{
+	if (!akm)
+		return WLAN_CRYPTO_KEY_MGMT_MAX;
+	else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_FILS_SHA384))
+		return WLAN_CRYPTO_KEY_MGMT_FT_FILS_SHA384;
+	else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_FILS_SHA256))
+		return WLAN_CRYPTO_KEY_MGMT_FT_FILS_SHA256;
+	else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FILS_SHA384))
+		return WLAN_CRYPTO_KEY_MGMT_FILS_SHA384;
+	else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FILS_SHA256))
+		return WLAN_CRYPTO_KEY_MGMT_FILS_SHA256;
+	else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_IEEE8021X_SHA384))
+		return WLAN_CRYPTO_KEY_MGMT_FT_IEEE8021X_SHA384;
+	else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SUITE_B_192))
+		return WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SUITE_B_192;
+	else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SUITE_B))
+		return WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SUITE_B;
+	else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_SAE_EXT_KEY))
+		return WLAN_CRYPTO_KEY_MGMT_FT_SAE_EXT_KEY;
+	else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_SAE_EXT_KEY))
+		return WLAN_CRYPTO_KEY_MGMT_SAE_EXT_KEY;
+	else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_SAE))
+		return WLAN_CRYPTO_KEY_MGMT_FT_SAE;
+	else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_SAE))
+		return WLAN_CRYPTO_KEY_MGMT_SAE;
+	else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_OWE))
+		return WLAN_CRYPTO_KEY_MGMT_OWE;
+	else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_DPP))
+		return WLAN_CRYPTO_KEY_MGMT_DPP;
+	else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SHA256))
+		return WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SHA256;
+	else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_IEEE8021X))
+		return WLAN_CRYPTO_KEY_MGMT_FT_IEEE8021X;
+	else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_IEEE8021X))
+		return WLAN_CRYPTO_KEY_MGMT_IEEE8021X;
+	else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_PSK_SHA384))
+		return WLAN_CRYPTO_KEY_MGMT_FT_PSK_SHA384;
+	else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_PSK_SHA384))
+		return WLAN_CRYPTO_KEY_MGMT_PSK_SHA384;
+	else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_PSK_SHA256))
+		return WLAN_CRYPTO_KEY_MGMT_PSK_SHA256;
+	else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_PSK))
+		return WLAN_CRYPTO_KEY_MGMT_FT_PSK;
+	else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_PSK))
+		return WLAN_CRYPTO_KEY_MGMT_PSK;
+	else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_WAPI_PSK))
+		return WLAN_CRYPTO_KEY_MGMT_WAPI_PSK;
+	else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_WAPI_CERT))
+		return WLAN_CRYPTO_KEY_MGMT_WAPI_CERT;
+	else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_CCKM))
+		return WLAN_CRYPTO_KEY_MGMT_CCKM;
+	else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_OSEN))
+		return WLAN_CRYPTO_KEY_MGMT_OSEN;
+	else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_WPS))
+		return WLAN_CRYPTO_KEY_MGMT_WPS;
+	else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_IEEE8021X_NO_WPA))
+		return WLAN_CRYPTO_KEY_MGMT_IEEE8021X_NO_WPA;
+	else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_WPA_NONE))
+		return WLAN_CRYPTO_KEY_MGMT_WPA_NONE;
+	else /* Return MAX if no AKM matches */
+		return WLAN_CRYPTO_KEY_MGMT_MAX;
+}
+
 #ifdef CRYPTO_SET_KEY_CONVERGED
 QDF_STATUS wlan_crypto_validate_key_params(enum wlan_crypto_cipher_type cipher,
 					   uint8_t key_index, uint8_t key_len,

+ 44 - 20
umac/mlme/connection_mgr/core/src/wlan_cm_bss_scoring.c

@@ -3019,6 +3019,41 @@ static void cm_eliminate_common_candidate(qdf_list_t *candidate_list)
 		size--;
 	}
 }
+
+static void cm_validate_partner_links_rsn_cap(struct scan_cache_entry *entry,
+					      qdf_list_t *scan_list)
+{
+	uint8_t idx;
+	struct scan_cache_entry *partner_entry;
+	struct partner_link_info *partner_info;
+
+	if (!entry->ie_list.multi_link_bv || !entry->ml_info.num_links)
+		return;
+
+	for (idx = 0; idx < entry->ml_info.num_links; idx++) {
+		partner_info = &entry->ml_info.link_info[idx];
+		if (!partner_info->is_valid_link)
+			continue;
+
+		/*
+		 * If partner link is not found in the current candidate list
+		 * don't treat it as failure, it can be removed post ML
+		 * probe resp generation time.
+		 */
+		partner_entry = cm_get_entry(scan_list,
+					     &partner_info->link_addr);
+		if (!partner_entry)
+			continue;
+
+		if (wlan_scan_entries_contain_cmn_akm(entry, partner_entry))
+			continue;
+
+		partner_info->is_valid_link = false;
+		mlme_debug(QDF_MAC_ADDR_FMT "link (%d) akm not matching",
+			   QDF_MAC_ADDR_REF(partner_entry->bssid.bytes),
+			   partner_info->freq);
+	}
+}
 #else
 
 static void cm_update_candidate_list_for_vendor(qdf_list_t *candidate_list)
@@ -3028,6 +3063,12 @@ static void cm_update_candidate_list_for_vendor(qdf_list_t *candidate_list)
 static void cm_eliminate_common_candidate(qdf_list_t *candidate_list)
 {
 }
+
+static inline void
+cm_validate_partner_links_rsn_cap(struct scan_cache_entry *entry,
+				  qdf_list_t *scan_list)
+{
+}
 #endif
 void wlan_cm_calculate_bss_score(struct wlan_objmgr_pdev *pdev,
 				 struct pcl_freq_weight_list *pcl_lst,
@@ -3118,6 +3159,8 @@ void wlan_cm_calculate_bss_score(struct wlan_objmgr_pdev *pdev,
 			}
 		}
 
+		/* Check if the partner links RSN caps are matching. */
+		cm_validate_partner_links_rsn_cap(scan_entry->entry, scan_list);
 		if (denylist_action == CM_DLM_NO_ACTION ||
 		    (are_all_candidate_denylisted && denylist_action ==
 		     CM_DLM_REMOVE)) {
@@ -3223,25 +3266,6 @@ void wlan_cm_calculate_bss_score(struct wlan_objmgr_pdev *pdev,
 }
 
 #ifdef CONFIG_BAND_6GHZ
-static bool cm_check_h2e_support(const uint8_t *rsnxe)
-{
-	const uint8_t *rsnxe_cap;
-	uint8_t cap_len;
-
-	rsnxe_cap = wlan_crypto_parse_rsnxe_ie(rsnxe, &cap_len);
-	if (!rsnxe_cap) {
-		mlme_debug("RSNXE caps not present");
-		return false;
-	}
-
-	if (*rsnxe_cap & WLAN_CRYPTO_RSNX_CAP_SAE_H2E)
-		return true;
-
-	mlme_debug("RSNXE caps %x dont have H2E support", *rsnxe_cap);
-
-	return false;
-}
-
 #ifdef CONN_MGR_ADV_FEATURE
 static bool wlan_cm_wfa_get_test_feature_flags(struct wlan_objmgr_psoc *psoc)
 {
@@ -3311,7 +3335,7 @@ bool wlan_cm_6ghz_allowed_for_akm(struct wlan_objmgr_psoc *psoc,
 	    QDF_HAS_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_FT_SAE_EXT_KEY)))
 		return true;
 
-	return (cm_check_h2e_support(rsnxe) ||
+	return (util_is_rsnxe_h2e_capable(rsnxe) ||
 		wlan_cm_wfa_get_test_feature_flags(psoc));
 }
 

+ 54 - 64
umac/mlme/connection_mgr/core/src/wlan_cm_connect.c

@@ -1989,6 +1989,46 @@ cm_connect_req_update_ml_partner_info(struct cnx_mgr *cm_ctx,
 {}
 #endif
 
+#if defined(WLAN_FEATURE_11BE_MLO) && defined(WLAN_FEATURE_11BE_MLO_ADV_FEATURE)
+static void
+cm_override_partner_link_akm(struct cnx_mgr *cm_ctx, struct cm_req *cm_req)
+{
+	struct scan_cache_entry *cur_entry;
+	struct wlan_objmgr_vdev *assoc_vdev;
+
+	if (!cm_req->connect_req.cur_candidate)
+		return;
+
+	assoc_vdev = wlan_mlo_get_assoc_link_vdev(cm_ctx->vdev);
+	if (!assoc_vdev) {
+		mlme_err("Assoc vdev not found");
+		return;
+	}
+
+	/* Partner link might have common AKM with assoc link but that
+	 * AKM might not be the superior AKM of the available AKMs for
+	 * the partner link.
+	 * Override partner link AKM with assoc link chosen AKM so that
+	 * same AKM will be chosen for partner link as well.
+	 *
+	 * Example: Assoc link: WPA2-PSK
+	 *          Partner link: WPA3-SAE and WPA2-PSK
+	 *
+	 * Even WPA2-PSK is matching with assoc link, WPA3-SAE is more secure
+	 * AKM for partner link and in order to avoid selecting WPA3-SAE for
+	 * partner link, override that AKM with the common AKM from assoc link.
+	 */
+	cur_entry = cm_req->connect_req.cur_candidate->entry;
+	cur_entry->neg_sec_info.key_mgmt =
+		wlan_crypto_get_param(assoc_vdev, WLAN_CRYPTO_PARAM_KEY_MGMT);
+}
+#else
+static inline void
+cm_override_partner_link_akm(struct cnx_mgr *cm_ctx, struct cm_req *cm_req)
+{
+}
+#endif
+
 /**
  * cm_get_valid_candidate() - This API will be called to get the next valid
  * candidate
@@ -2134,6 +2174,10 @@ try_same_candidate:
 
 	cm_connect_req_update_ml_partner_info(cm_ctx, cm_req,
 					      use_same_candidate);
+	if (!use_same_candidate &&
+	    wlan_vdev_mlme_is_mlo_link_vdev(cm_ctx->vdev)) {
+		cm_override_partner_link_akm(cm_ctx, cm_req);
+	}
 
 flush_single_pmk:
 	akm = wlan_crypto_get_param(cm_ctx->vdev, WLAN_CRYPTO_PARAM_KEY_MGMT);
@@ -2433,77 +2477,23 @@ static
 void cm_update_per_peer_key_mgmt_crypto_params(struct wlan_objmgr_vdev *vdev,
 					struct security_info *neg_sec_info)
 {
-	int32_t key_mgmt = 0;
-	int32_t neg_akm = neg_sec_info->key_mgmt;
+	wlan_crypto_key_mgmt akm;
+	uint32_t key_mgmt = 0x0;
 
 	/*
 	 * As there can be multiple AKM present select the most secured AKM
 	 * present
 	 */
-	if (QDF_HAS_PARAM(neg_akm, WLAN_CRYPTO_KEY_MGMT_FT_FILS_SHA384))
-		QDF_SET_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_FT_FILS_SHA384);
-	else if (QDF_HAS_PARAM(neg_akm, WLAN_CRYPTO_KEY_MGMT_FT_FILS_SHA256))
-		QDF_SET_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_FT_FILS_SHA256);
-	else if (QDF_HAS_PARAM(neg_akm, WLAN_CRYPTO_KEY_MGMT_FILS_SHA384))
-		QDF_SET_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_FILS_SHA384);
-	else if (QDF_HAS_PARAM(neg_akm, WLAN_CRYPTO_KEY_MGMT_FILS_SHA256))
-		QDF_SET_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_FILS_SHA256);
-	else if (QDF_HAS_PARAM(neg_akm,
-			       WLAN_CRYPTO_KEY_MGMT_FT_IEEE8021X_SHA384))
-		QDF_SET_PARAM(key_mgmt,
-			      WLAN_CRYPTO_KEY_MGMT_FT_IEEE8021X_SHA384);
-	else if (QDF_HAS_PARAM(neg_akm,
-			       WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SUITE_B_192))
-		QDF_SET_PARAM(key_mgmt,
-			      WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SUITE_B_192);
-	else if (QDF_HAS_PARAM(neg_akm, WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SUITE_B))
-		QDF_SET_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SUITE_B);
-	else if (QDF_HAS_PARAM(neg_akm, WLAN_CRYPTO_KEY_MGMT_FT_SAE_EXT_KEY))
-		QDF_SET_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_FT_SAE_EXT_KEY);
-	else if (QDF_HAS_PARAM(neg_akm, WLAN_CRYPTO_KEY_MGMT_FT_SAE))
-		QDF_SET_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_FT_SAE);
-	else if (QDF_HAS_PARAM(neg_akm, WLAN_CRYPTO_KEY_MGMT_SAE_EXT_KEY))
-		QDF_SET_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_SAE_EXT_KEY);
-	else if (QDF_HAS_PARAM(neg_akm, WLAN_CRYPTO_KEY_MGMT_SAE))
-		QDF_SET_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_SAE);
-	else if (QDF_HAS_PARAM(neg_akm, WLAN_CRYPTO_KEY_MGMT_OWE))
-		QDF_SET_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_OWE);
-	else if (QDF_HAS_PARAM(neg_akm, WLAN_CRYPTO_KEY_MGMT_DPP))
-		QDF_SET_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_DPP);
-	else if (QDF_HAS_PARAM(neg_akm, WLAN_CRYPTO_KEY_MGMT_FT_IEEE8021X))
-		QDF_SET_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_FT_IEEE8021X);
-	else if (QDF_HAS_PARAM(neg_akm, WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SHA256))
-		QDF_SET_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SHA256);
-	else if (QDF_HAS_PARAM(neg_akm, WLAN_CRYPTO_KEY_MGMT_IEEE8021X))
-		QDF_SET_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_IEEE8021X);
-	else if (QDF_HAS_PARAM(neg_akm, WLAN_CRYPTO_KEY_MGMT_FT_PSK_SHA384))
-		QDF_SET_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_FT_PSK_SHA384);
-	else if (QDF_HAS_PARAM(neg_akm, WLAN_CRYPTO_KEY_MGMT_PSK_SHA384))
-		QDF_SET_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_PSK_SHA384);
-	else if (QDF_HAS_PARAM(neg_akm, WLAN_CRYPTO_KEY_MGMT_PSK_SHA256))
-		QDF_SET_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_PSK_SHA256);
-	else if (QDF_HAS_PARAM(neg_akm, WLAN_CRYPTO_KEY_MGMT_FT_PSK))
-		QDF_SET_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_FT_PSK);
-	else if (QDF_HAS_PARAM(neg_akm, WLAN_CRYPTO_KEY_MGMT_PSK))
-		QDF_SET_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_PSK);
-	else if (QDF_HAS_PARAM(neg_akm, WLAN_CRYPTO_KEY_MGMT_WAPI_PSK))
-		QDF_SET_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_WAPI_PSK);
-	else if (QDF_HAS_PARAM(neg_akm, WLAN_CRYPTO_KEY_MGMT_WAPI_CERT))
-		QDF_SET_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_WAPI_CERT);
-	else if (QDF_HAS_PARAM(neg_akm, WLAN_CRYPTO_KEY_MGMT_CCKM))
-		QDF_SET_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_CCKM);
-	else if (QDF_HAS_PARAM(neg_akm, WLAN_CRYPTO_KEY_MGMT_OSEN))
-		QDF_SET_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_OSEN);
-	else if (QDF_HAS_PARAM(neg_akm, WLAN_CRYPTO_KEY_MGMT_WPS))
-		QDF_SET_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_WPS);
-	else if (QDF_HAS_PARAM(neg_akm, WLAN_CRYPTO_KEY_MGMT_IEEE8021X_NO_WPA))
-		QDF_SET_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_IEEE8021X_NO_WPA);
-	else if (QDF_HAS_PARAM(neg_akm, WLAN_CRYPTO_KEY_MGMT_WPA_NONE))
-		QDF_SET_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_WPA_NONE);
-	else /* use original if no akm match */
-		key_mgmt = neg_akm;
+
+	akm = wlan_crypto_get_secure_akm_available(neg_sec_info->key_mgmt);
+	/* If not matches any AKM, set to same AKM */
+	if (akm == WLAN_CRYPTO_KEY_MGMT_MAX)
+		key_mgmt = neg_sec_info->key_mgmt;
+	else
+		QDF_SET_PARAM(key_mgmt, akm);
 
 	wlan_crypto_set_vdev_param(vdev, WLAN_CRYPTO_PARAM_KEY_MGMT, key_mgmt);
+
 	/*
 	 * Overwrite the key mgmt with single key_mgmt if multiple are present
 	 */

+ 73 - 2
umac/scan/core/src/wlan_scan_cache_db.c

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -53,7 +53,7 @@
 #include "wlan_reg_ucfg_api.h"
 #include <wlan_objmgr_vdev_obj.h>
 #include <wlan_dfs_utils_api.h>
-#include "wlan_crypto_global_def.h"
+#include "wlan_crypto_def_i.h"
 #include "wlan_crypto_global_api.h"
 #include "wlan_cm_bss_score_param.h"
 
@@ -2350,3 +2350,74 @@ exit:
 
 	return scan_entry;
 }
+
+bool scm_scan_entries_contain_cmn_akm(struct scan_cache_entry *entry1,
+				      struct scan_cache_entry *entry2)
+{
+	wlan_crypto_key_mgmt akm_type;
+	uint32_t key_mgmt;
+	struct security_info *entry1_sec_info, *entry2_sec_info;
+
+	/* For Open security, allow connection */
+	if (!entry1->ie_list.rsn && !entry2->ie_list.rsn)
+		return true;
+
+	/* If only one is open connection, remove the partner link */
+	if (!entry1->ie_list.rsn || !entry2->ie_list.rsn)
+		return false;
+
+	entry1_sec_info = &entry1->neg_sec_info;
+	entry2_sec_info = &entry2->neg_sec_info;
+
+	/* Check if MFPC is equal */
+	if ((entry1_sec_info->rsn_caps & WLAN_CRYPTO_RSN_CAP_MFP_ENABLED) ^
+	    (entry2_sec_info->rsn_caps & WLAN_CRYPTO_RSN_CAP_MFP_ENABLED)) {
+		scm_debug("MFPC capability is not equal 0x%x, 0x%x",
+			  entry1_sec_info->rsn_caps, entry2_sec_info->rsn_caps);
+		return false;
+	}
+
+	/* Check UC cipher suite */
+	if (!UCAST_CIPHER_MATCH(entry1_sec_info, entry2_sec_info)) {
+		scm_debug("Intersected UC cipher bitmap NULL 0x%x, 0x%x",
+			  entry1_sec_info->ucastcipherset,
+			  entry2_sec_info->ucastcipherset);
+		return false;
+	}
+
+	/* Check MC cipher suite */
+	if (!MCAST_CIPHER_MATCH(entry1_sec_info, entry2_sec_info)) {
+		scm_debug("Intersected MC cipher bitmap NULL 0x%x, 0x%x",
+			  entry1_sec_info->mcastcipherset,
+			  entry2_sec_info->mcastcipherset);
+		return false;
+	}
+
+	/* Check AKM suite */
+	key_mgmt = entry1_sec_info->key_mgmt;
+	akm_type = wlan_crypto_get_secure_akm_available(key_mgmt);
+	if (akm_type == WLAN_CRYPTO_KEY_MGMT_MAX) {
+		scm_debug("No matching AKM 0x%x", key_mgmt);
+		return false;
+	} else if (!HAS_KEY_MGMT(entry2_sec_info, akm_type)) {
+		scm_debug("Intersected AKM bitmap NULL 0x%x, 0x%x",
+			  entry1_sec_info->key_mgmt, entry2_sec_info->key_mgmt);
+		return false;
+	} else {
+		key_mgmt = 0x0;
+		QDF_SET_PARAM(key_mgmt, akm_type);
+	}
+
+	/* If not SAE AKM no need to check H2E capability match */
+	if (!WLAN_CRYPTO_IS_AKM_SAE(key_mgmt))
+		return true;
+
+	/* If SAE_H2E capability is not equal then treat as mismatch */
+	if (util_scan_entry_sae_h2e_capable(entry1) ^
+	    util_scan_entry_sae_h2e_capable(entry2)) {
+		scm_debug("SAE-H2E capability mismatch");
+		return false;
+	}
+
+	return true;
+}

+ 15 - 1
umac/scan/core/src/wlan_scan_cache_db.h

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2017-2020 The Linux Foundation. All rights reserved.
- * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -389,4 +389,18 @@ scm_get_mld_addr_by_link_addr(struct wlan_objmgr_pdev *pdev,
 	return QDF_STATUS_E_NOSUPPORT;
 }
 #endif
+
+/**
+ * scm_scan_entries_contain_cmn_akm() - Check if two entries have common
+ * RSN capabilities.
+ * @entry1: Primary scan entry for comparison
+ * @entry2: Secondary scan entry for comparison
+ *
+ * Checks various RSN parameters of two scan entries to determine
+ * whether both have similar capabilities or not.
+ *
+ * Return: bool
+ */
+bool scm_scan_entries_contain_cmn_akm(struct scan_cache_entry *entry1,
+				      struct scan_cache_entry *entry2);
 #endif

+ 7 - 1
umac/scan/dispatcher/inc/wlan_scan_api.h

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -569,4 +569,10 @@ wlan_scan_get_mld_addr_by_link_addr(struct wlan_objmgr_pdev *pdev,
  */
 bool wlan_scan_get_aux_support(struct wlan_objmgr_psoc *psoc);
 
+static inline bool
+wlan_scan_entries_contain_cmn_akm(struct scan_cache_entry *entry1,
+				  struct scan_cache_entry *entry2)
+{
+	return scm_scan_entries_contain_cmn_akm(entry1, entry2);
+}
 #endif

+ 24 - 1
umac/scan/dispatcher/inc/wlan_scan_utils_api.h

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -1804,6 +1804,29 @@ util_scan_entry_rsnxe(struct scan_cache_entry *scan_entry)
 	return scan_entry->ie_list.rsnxe;
 }
 
+/**
+ * util_is_rsnxe_h2e_capable() - API to check whether the RSNXE has
+ * H2E capable or not.
+ * @rsnxe: Pointer to RSNXE IE.
+ *
+ * Returns true if RSNXE caps has H2E capable bit set or else false.
+ *
+ * Return: bool
+ */
+bool util_is_rsnxe_h2e_capable(const uint8_t *rsnxe);
+
+/**
+ * util_scan_entry_sae_h2e_capable() - API to check whether the
+ * current scan entry is SAE-H2E capable
+ * @scan_entry: Scan cache entry
+ *
+ * Returns true if the current scan entry has RSNXE IE with H2E bit
+ * set.
+ *
+ * Return: bool
+ */
+bool util_scan_entry_sae_h2e_capable(struct scan_cache_entry *scan_entry);
+
 /**
  * util_scan_scm_freq_to_band() - API to get band from frequency
  * @freq: Channel frequency

+ 33 - 1
umac/scan/dispatcher/src/wlan_scan_utils_api.c

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -41,6 +41,7 @@
 #include <wlan_action_oui_main.h>
 #include <wlan_action_oui_public_struct.h>
 #endif
+#include <wlan_crypto_global_api.h>
 
 #define MAX_IE_LEN 1024
 #define SHORT_SSID_LEN 4
@@ -125,6 +126,37 @@ util_get_last_scan_time(struct wlan_objmgr_vdev *vdev)
 		return 0;
 }
 
+bool util_is_rsnxe_h2e_capable(const uint8_t *rsnxe)
+{
+	const uint8_t *rsnxe_caps;
+	uint8_t cap_len;
+
+	if (!rsnxe)
+		return false;
+
+	rsnxe_caps = wlan_crypto_parse_rsnxe_ie(rsnxe, &cap_len);
+	if (!rsnxe_caps)
+		return false;
+
+	return *rsnxe_caps & WLAN_CRYPTO_RSNX_CAP_SAE_H2E;
+}
+
+bool util_scan_entry_sae_h2e_capable(struct scan_cache_entry *scan_entry)
+{
+	const uint8_t *rsnxe;
+
+	/* If RSN caps are not there, then return false */
+	if (!util_scan_entry_rsn(scan_entry))
+		return false;
+
+	/* If not SAE AKM no need to check H2E capability */
+	if (!WLAN_CRYPTO_IS_AKM_SAE(scan_entry->neg_sec_info.key_mgmt))
+		return false;
+
+	rsnxe = util_scan_entry_rsnxe(scan_entry);
+	return util_is_rsnxe_h2e_capable(rsnxe);
+}
+
 enum wlan_band util_scan_scm_freq_to_band(uint16_t freq)
 {
 	if (WLAN_REG_IS_24GHZ_CH_FREQ(freq))