Ver código fonte

qcacmn: Support adaptive 11R BSS in scan

Adaptive 11r is a feature by which the network supports 11r
even though the bss doesn't advertise 11r. This is done with the
help of advertising vendor specific adaptive 11r IE and MD IE
in the beacon/probe. When vendor specific adaptive 11r
IE (oui 0x00 40 96 type 0x2C) is present in the beacon/probe,
and 1st bit of the IE data is  set to 1, then the BSS supports
adaptive 11r.

The BSS advertises, non-11r akm in RSN IE and user space will
send the 11r akm in the connect start. So the scan module
shouldn't filter out the candidate adaptive 11r supported BSS
with AKM mismatch reason.

Add changes in scan module to parse the Vendor specific adaptive
11r IE and copy it to the scan_entry ie_list. Check if
negotiated akm is non-11r akm, and the filter akm sent from csr
is a 11r akm (which is received from user space), then mark the
bss as matching.

Change-Id: I65f32c67016ad634f1592a7453e77aaf0c5a327c
CRs-Fixed: 2431074
Pragaspathi Thilagaraj 6 anos atrás
pai
commit
45a8c1e41f

+ 22 - 0
umac/cmn_services/cmn_defs/inc/wlan_cmn_ieee80211.h

@@ -69,6 +69,13 @@
 /* Extender vendor specific IE */
 #define QCA_OUI_EXTENDER_TYPE           0x03
 
+#define ADAPTIVE_11R_OUI      0x964000
+#define ADAPTIVE_11R_OUI_TYPE 0x2C
+
+#define OUI_LENGTH              4
+#define OUI_TYPE_BITS           24
+#define MAX_ADAPTIVE_11R_IE_LEN 8
+
 /* Temporary vendor specific IE for 11n pre-standard interoperability */
 #define VENDOR_HT_OUI       0x00904c
 #define VENDOR_HT_CAP_ID    51
@@ -1434,6 +1441,21 @@ is_extender_oui(uint8_t *frm)
 		((QCA_OUI_EXTENDER_TYPE << 24) | QCA_OUI));
 }
 
+/**
+ * is_adaptive_11r_oui() - Function to check if vendor IE is ADAPTIVE 11R OUI
+ * @frm: vendor IE pointer
+ *
+ * API to check if vendor IE is ADAPTIVE 11R OUI
+ *
+ * Return: true if its ADAPTIVE 11r OUI
+ */
+static inline bool
+is_adaptive_11r_oui(uint8_t *frm)
+{
+	return (frm[1] > OUI_LENGTH) && (LE_READ_4(frm + 2) ==
+		((ADAPTIVE_11R_OUI_TYPE << OUI_TYPE_BITS) | ADAPTIVE_11R_OUI));
+}
+
 /**
  * wlan_parse_rsn_ie() - parse rsn ie
  * @rsn_ie: rsn ie ptr

+ 88 - 61
umac/scan/core/src/wlan_scan_filter.c

@@ -382,16 +382,18 @@ scm_is_rsn_mcast_cipher_match(struct wlan_rsn_ie *rsn,
  * Return: true if RSN security else false
  */
 static bool scm_is_rsn_security(struct scan_filter *filter,
-	struct scan_cache_entry *db_entry,
-	struct security_info *security)
+				struct scan_cache_entry *db_entry,
+				struct security_info *security)
 {
 	int i;
 	uint8_t cipher_type;
 	bool match_any_akm, match = false;
 	enum wlan_auth_type neg_auth = WLAN_NUM_OF_SUPPORT_AUTH_TYPE;
+	enum wlan_auth_type filter_akm;
 	enum wlan_enc_type neg_mccipher = WLAN_ENCRYPT_TYPE_NONE;
 	struct wlan_rsn_ie rsn = {0};
 	QDF_STATUS status;
+	bool is_adaptive_11r;
 
 	if (!security)
 		return false;
@@ -425,11 +427,15 @@ static bool scm_is_rsn_security(struct scan_filter *filter,
 		return false;
 	}
 
+	is_adaptive_11r = (db_entry->adaptive_11r_ap &&
+			   filter->enable_adaptive_11r);
+
 	/* Initializing with false as it has true value already */
 	match = false;
 	for (i = 0; i < filter->num_of_auth; i++) {
 
-		if (filter->auth_type[i] == WLAN_AUTH_TYPE_ANY)
+		filter_akm = filter->auth_type[i];
+		if (filter_akm == WLAN_AUTH_TYPE_ANY)
 			match_any_akm = true;
 		else
 			match_any_akm = false;
@@ -440,8 +446,8 @@ static bool scm_is_rsn_security(struct scan_filter *filter,
 		if (scm_is_cipher_match(rsn.akm_suites,
 		   rsn.akm_suite_count,
 		   WLAN_RSN_SEL(WLAN_AKM_FILS_FT_SHA384))) {
-			if (match_any_akm || (WLAN_AUTH_TYPE_FT_FILS_SHA384 ==
-			    filter->auth_type[i])) {
+			if (match_any_akm ||
+			    (filter_akm == WLAN_AUTH_TYPE_FT_FILS_SHA384)) {
 				neg_auth = WLAN_AUTH_TYPE_FT_FILS_SHA384;
 				match = true;
 				break;
@@ -450,8 +456,8 @@ static bool scm_is_rsn_security(struct scan_filter *filter,
 		if (scm_is_cipher_match(rsn.akm_suites,
 		   rsn.akm_suite_count,
 		   WLAN_RSN_SEL(WLAN_AKM_FILS_FT_SHA256))) {
-			if (match_any_akm || (WLAN_AUTH_TYPE_FT_FILS_SHA256 ==
-			    filter->auth_type[i])) {
+			if (match_any_akm ||
+			    (filter_akm == WLAN_AUTH_TYPE_FT_FILS_SHA256)) {
 				neg_auth = WLAN_AUTH_TYPE_FT_FILS_SHA256;
 				match = true;
 				break;
@@ -460,8 +466,8 @@ static bool scm_is_rsn_security(struct scan_filter *filter,
 		if (scm_is_cipher_match(rsn.akm_suites,
 		   rsn.akm_suite_count,
 		   WLAN_RSN_SEL(WLAN_AKM_FILS_SHA384))) {
-			if (match_any_akm || (WLAN_AUTH_TYPE_FILS_SHA384 ==
-			    filter->auth_type[i])) {
+			if (match_any_akm ||
+			    (filter_akm == WLAN_AUTH_TYPE_FILS_SHA384)) {
 				neg_auth = WLAN_AUTH_TYPE_FILS_SHA384;
 				match = true;
 				break;
@@ -470,8 +476,8 @@ static bool scm_is_rsn_security(struct scan_filter *filter,
 		if (scm_is_cipher_match(rsn.akm_suites,
 		   rsn.akm_suite_count,
 		   WLAN_RSN_SEL(WLAN_AKM_FILS_SHA256))) {
-			if (match_any_akm || (WLAN_AUTH_TYPE_FILS_SHA256 ==
-			    filter->auth_type[i])) {
+			if (match_any_akm ||
+			    (filter_akm == WLAN_AUTH_TYPE_FILS_SHA256)) {
 				neg_auth = WLAN_AUTH_TYPE_FILS_SHA256;
 				match = true;
 				break;
@@ -481,8 +487,8 @@ static bool scm_is_rsn_security(struct scan_filter *filter,
 		if (scm_is_cipher_match(rsn.akm_suites,
 		    rsn.akm_suite_count,
 		   WLAN_RSN_SEL(WLAN_AKM_SAE))) {
-			if (match_any_akm || (WLAN_AUTH_TYPE_SAE ==
-			    filter->auth_type[i])) {
+			if (match_any_akm ||
+			    (filter_akm == WLAN_AUTH_TYPE_SAE)) {
 				neg_auth = WLAN_AUTH_TYPE_SAE;
 				match = true;
 				break;
@@ -491,8 +497,8 @@ static bool scm_is_rsn_security(struct scan_filter *filter,
 
 		if (scm_is_cipher_match(rsn.akm_suites,
 		   rsn.akm_suite_count, WLAN_RSN_DPP_AKM)) {
-			if (match_any_akm || (WLAN_AUTH_TYPE_DPP_RSN ==
-			    filter->auth_type[i])) {
+			if (match_any_akm ||
+			    (filter_akm == WLAN_AUTH_TYPE_DPP_RSN)) {
 				neg_auth = WLAN_AUTH_TYPE_DPP_RSN;
 				match = true;
 				break;
@@ -502,7 +508,7 @@ static bool scm_is_rsn_security(struct scan_filter *filter,
 					rsn.akm_suite_count,
 					WLAN_RSN_OSEN_AKM)) {
 			if (match_any_akm ||
-			    WLAN_AUTH_TYPE_OSEN == filter->auth_type[i]) {
+			    (filter_akm == WLAN_AUTH_TYPE_OSEN)) {
 				neg_auth = WLAN_AUTH_TYPE_OSEN;
 				match = true;
 				break;
@@ -511,8 +517,8 @@ static bool scm_is_rsn_security(struct scan_filter *filter,
 		if (scm_is_cipher_match(rsn.akm_suites,
 		   rsn.akm_suite_count,
 		   WLAN_RSN_SEL(WLAN_AKM_OWE))) {
-			if (match_any_akm || (WLAN_AUTH_TYPE_OWE ==
-			    filter->auth_type[i])) {
+			if (match_any_akm ||
+			    (filter_akm == WLAN_AUTH_TYPE_OWE)) {
 				neg_auth = WLAN_AUTH_TYPE_OWE;
 				match = true;
 				break;
@@ -521,8 +527,8 @@ static bool scm_is_rsn_security(struct scan_filter *filter,
 		if (scm_is_cipher_match(rsn.akm_suites,
 		   rsn.akm_suite_count,
 		   WLAN_RSN_SEL(WLAN_AKM_FT_IEEE8021X))) {
-			if (match_any_akm || (WLAN_AUTH_TYPE_FT_RSN ==
-			    filter->auth_type[i])) {
+			if (match_any_akm ||
+			    (filter_akm == WLAN_AUTH_TYPE_FT_RSN)) {
 				neg_auth = WLAN_AUTH_TYPE_FT_RSN;
 				match = true;
 				break;
@@ -532,8 +538,8 @@ static bool scm_is_rsn_security(struct scan_filter *filter,
 		if (scm_is_cipher_match(rsn.akm_suites,
 		   rsn.akm_suite_count,
 		   WLAN_RSN_SEL(WLAN_AKM_FT_PSK))) {
-			if (match_any_akm || (WLAN_AUTH_TYPE_FT_RSN_PSK ==
-			   filter->auth_type[i])) {
+			if (match_any_akm ||
+			    (filter_akm == WLAN_AUTH_TYPE_FT_RSN_PSK)) {
 				neg_auth = WLAN_AUTH_TYPE_FT_RSN_PSK;
 				match = true;
 				break;
@@ -543,8 +549,8 @@ static bool scm_is_rsn_security(struct scan_filter *filter,
 		if (scm_is_cipher_match(rsn.akm_suites,
 		   rsn.akm_suite_count,
 		   WLAN_RSN_CCKM_AKM)) {
-			if (match_any_akm || (WLAN_AUTH_TYPE_CCKM_RSN ==
-			   filter->auth_type[i])) {
+			if (match_any_akm ||
+			    (filter_akm == WLAN_AUTH_TYPE_CCKM_RSN)) {
 				neg_auth = WLAN_AUTH_TYPE_CCKM_RSN;
 				match = true;
 				break;
@@ -554,8 +560,15 @@ static bool scm_is_rsn_security(struct scan_filter *filter,
 		if (scm_is_cipher_match(rsn.akm_suites,
 		   rsn.akm_suite_count,
 		   WLAN_RSN_SEL(WLAN_AKM_IEEE8021X))) {
-			if (match_any_akm || (WLAN_AUTH_TYPE_RSN ==
-			   filter->auth_type[i])) {
+			if (is_adaptive_11r &&
+			    (filter_akm == WLAN_AUTH_TYPE_FT_RSN)) {
+				neg_auth = WLAN_AUTH_TYPE_FT_RSN;
+				match = true;
+				break;
+			}
+
+			if (match_any_akm ||
+			    (WLAN_AUTH_TYPE_RSN == filter_akm)) {
 				neg_auth = WLAN_AUTH_TYPE_RSN;
 				match = true;
 				break;
@@ -565,8 +578,15 @@ static bool scm_is_rsn_security(struct scan_filter *filter,
 		if (scm_is_cipher_match(rsn.akm_suites,
 		   rsn.akm_suite_count,
 		   WLAN_RSN_SEL(WLAN_AKM_PSK))) {
-			if (match_any_akm || (WLAN_AUTH_TYPE_RSN_PSK ==
-			   filter->auth_type[i])) {
+			if (is_adaptive_11r &&
+			    (filter_akm == WLAN_AUTH_TYPE_FT_RSN_PSK)) {
+				neg_auth = WLAN_AUTH_TYPE_FT_RSN_PSK;
+				match = true;
+				break;
+			}
+
+			if (match_any_akm ||
+			    (filter_akm == WLAN_AUTH_TYPE_RSN_PSK)) {
 				neg_auth = WLAN_AUTH_TYPE_RSN_PSK;
 				match = true;
 				break;
@@ -576,10 +596,16 @@ static bool scm_is_rsn_security(struct scan_filter *filter,
 		if (scm_is_cipher_match(rsn.akm_suites,
 		   rsn.akm_suite_count,
 		   WLAN_RSN_SEL(WLAN_AKM_SHA256_PSK))) {
-			if (match_any_akm || (WLAN_AUTH_TYPE_RSN_PSK_SHA256 ==
-			   filter->auth_type[i])) {
-				neg_auth =
-					WLAN_AUTH_TYPE_RSN_PSK_SHA256;
+			if (is_adaptive_11r &&
+			    (filter_akm == WLAN_AUTH_TYPE_FT_RSN_PSK)) {
+				neg_auth = WLAN_AUTH_TYPE_FT_RSN_PSK;
+				match = true;
+				break;
+			}
+
+			if (match_any_akm ||
+			    (filter_akm == WLAN_AUTH_TYPE_RSN_PSK_SHA256)) {
+				neg_auth = WLAN_AUTH_TYPE_RSN_PSK_SHA256;
 				match = true;
 				break;
 			}
@@ -588,10 +614,16 @@ static bool scm_is_rsn_security(struct scan_filter *filter,
 		if (scm_is_cipher_match(rsn.akm_suites,
 		   rsn.akm_suite_count,
 		   WLAN_RSN_SEL(WLAN_AKM_SHA256_IEEE8021X))) {
-			if (match_any_akm || (WLAN_AUTH_TYPE_RSN_8021X_SHA256 ==
-			   filter->auth_type[i])) {
-				neg_auth =
-					WLAN_AUTH_TYPE_RSN_8021X_SHA256;
+			if (is_adaptive_11r &&
+			    (filter_akm == WLAN_AUTH_TYPE_FT_RSN)) {
+				neg_auth = WLAN_AUTH_TYPE_FT_RSN;
+				match = true;
+				break;
+			}
+
+			if (match_any_akm ||
+			    (filter_akm == WLAN_AUTH_TYPE_RSN_8021X_SHA256)) {
+				neg_auth = WLAN_AUTH_TYPE_RSN_8021X_SHA256;
 				match = true;
 				break;
 			}
@@ -600,8 +632,7 @@ static bool scm_is_rsn_security(struct scan_filter *filter,
 		   rsn.akm_suite_count,
 		   WLAN_RSN_SEL(WLAN_AKM_SUITEB_EAP_SHA256))) {
 			if (match_any_akm ||
-			    (WLAN_AUTH_TYPE_SUITEB_EAP_SHA256 ==
-			     filter->auth_type[i])) {
+			    (filter_akm == WLAN_AUTH_TYPE_SUITEB_EAP_SHA256)) {
 				neg_auth = WLAN_AUTH_TYPE_SUITEB_EAP_SHA256;
 				match = true;
 				break;
@@ -611,8 +642,7 @@ static bool scm_is_rsn_security(struct scan_filter *filter,
 		   rsn.akm_suite_count,
 		   WLAN_RSN_SEL(WLAN_AKM_SUITEB_EAP_SHA384))) {
 			if (match_any_akm ||
-			    (WLAN_AUTH_TYPE_SUITEB_EAP_SHA384 ==
-			     filter->auth_type[i])) {
+			    (filter_akm == WLAN_AUTH_TYPE_SUITEB_EAP_SHA384)) {
 				neg_auth = WLAN_AUTH_TYPE_SUITEB_EAP_SHA384;
 				match = true;
 				break;
@@ -621,8 +651,8 @@ static bool scm_is_rsn_security(struct scan_filter *filter,
 
 		if (scm_is_cipher_match(rsn.akm_suites, rsn.akm_suite_count,
 					WLAN_RSN_SEL(WLAN_AKM_FT_SAE))) {
-			if (match_any_akm || (WLAN_AUTH_TYPE_FT_SAE ==
-					      filter->auth_type[i])) {
+			if (match_any_akm ||
+			    (filter_akm == WLAN_AUTH_TYPE_FT_SAE)) {
 				neg_auth = WLAN_AUTH_TYPE_FT_SAE;
 				match = true;
 				break;
@@ -633,8 +663,8 @@ static bool scm_is_rsn_security(struct scan_filter *filter,
 					WLAN_RSN_SEL(
 					WLAN_AKM_FT_SUITEB_EAP_SHA384))) {
 			if (match_any_akm ||
-			    (WLAN_AUTH_TYPE_FT_SUITEB_EAP_SHA384 ==
-			     filter->auth_type[i])) {
+			    (filter_akm ==
+			     WLAN_AUTH_TYPE_FT_SUITEB_EAP_SHA384)) {
 				neg_auth = WLAN_AUTH_TYPE_FT_SUITEB_EAP_SHA384;
 				match = true;
 				break;
@@ -923,8 +953,8 @@ static bool scm_is_wapi_security(struct scan_filter *filter,
  * Return: true if any security else false
  */
 static bool scm_is_def_security(struct scan_filter *filter,
-	struct scan_cache_entry *db_entry,
-	struct security_info *security)
+				struct scan_cache_entry *db_entry,
+				struct security_info *security)
 {
 
 	/* It is allowed to match anything. Try the more secured ones first. */
@@ -1045,8 +1075,8 @@ static bool scm_is_fils_config_match(struct scan_filter *filter,
  * Return: true if security match else false
  */
 static bool scm_is_security_match(struct scan_filter *filter,
-	struct scan_cache_entry *db_entry,
-	struct security_info *security)
+				  struct scan_cache_entry *db_entry,
+				  struct security_info *security)
 {
 	int i;
 	bool match = false;
@@ -1078,8 +1108,8 @@ static bool scm_is_security_match(struct scan_filter *filter,
 		case WLAN_ENCRYPT_TYPE_AES_GCMP:
 		case WLAN_ENCRYPT_TYPE_AES_GCMP_256:
 			/* First check if there is a RSN match */
-			match = scm_is_rsn_security(filter,
-				    db_entry, &local_security);
+			match = scm_is_rsn_security(filter, db_entry,
+						    &local_security);
 			/* If not RSN, then check WPA match */
 			if (!match)
 				match = scm_is_wpa_security(filter,
@@ -1091,23 +1121,22 @@ static bool scm_is_security_match(struct scan_filter *filter,
 			break;
 		case WLAN_ENCRYPT_TYPE_ANY:
 		default:
-			match  = scm_is_def_security(filter,
-				    db_entry, &local_security);
+			match  = scm_is_def_security(filter, db_entry,
+						     &local_security);
 			break;
 		}
 	}
 
 	if (match && security)
-		qdf_mem_copy(security,
-			&local_security, sizeof(*security));
+		qdf_mem_copy(security, &local_security, sizeof(*security));
 
 	return match;
 }
 
 bool scm_filter_match(struct wlan_objmgr_psoc *psoc,
-	struct scan_cache_entry *db_entry,
-	struct scan_filter *filter,
-	struct security_info *security)
+		      struct scan_cache_entry *db_entry,
+		      struct scan_filter *filter,
+		      struct security_info *security)
 {
 	int i;
 	bool match = false;
@@ -1191,15 +1220,13 @@ bool scm_filter_match(struct wlan_objmgr_psoc *psoc,
 	/* TODO match phyMode */
 
 	if (!filter->ignore_auth_enc_type &&
-	   !scm_is_security_match(filter,
-	   db_entry, security)) {
+	    !scm_is_security_match(filter, db_entry, security)) {
 		scm_debug("%pM : Ignore as security profile didn't match",
 			  db_entry->bssid.bytes);
 		return false;
 	}
 
-	if (!util_is_bss_type_match(filter->bss_type,
-	   db_entry->cap_info)) {
+	if (!util_is_bss_type_match(filter->bss_type, db_entry->cap_info)) {
 		scm_debug("%pM : Ignore as bss type didn't match cap_info %x bss_type %d",
 			  db_entry->bssid.bytes, db_entry->cap_info.value,
 			  filter->bss_type);

+ 6 - 0
umac/scan/dispatcher/inc/wlan_scan_public_structs.h

@@ -158,6 +158,7 @@ struct element_info {
  * @fils_indication: pointer to FILS indication ie
  * @esp: pointer to ESP indication ie
  * @mbo_oce: pointer to mbo/oce indication ie
+ * @adaptive_11r: pointer to adaptive 11r IE
  */
 struct ie_list {
 	uint8_t *tim;
@@ -206,6 +207,7 @@ struct ie_list {
 	uint8_t *mbo_oce;
 	uint8_t *muedca;
 	uint8_t *extender;
+	uint8_t *adaptive_11r;
 };
 
 enum scan_entry_connection_state {
@@ -299,6 +301,7 @@ struct scan_mbssid_info {
  * @qbss_chan_load: Qbss channel load
  * @nss: supported NSS information
  * @is_p2p_ssid: is P2P entry
+ * @adaptive_11r_ap: flag to check if AP supports adaptive 11r
  * @scan_entry_time: boottime in microsec when last beacon/probe is received
  * @rssi_timestamp: boottime in microsec when RSSI was updated
  * @hidden_ssid_timestamp: boottime in microsec when hidden
@@ -340,6 +343,7 @@ struct scan_cache_entry {
 	uint8_t qbss_chan_load;
 	uint8_t nss;
 	bool is_p2p;
+	bool adaptive_11r_ap;
 	qdf_time_t scan_entry_time;
 	qdf_time_t rssi_timestamp;
 	qdf_time_t hidden_ssid_timestamp;
@@ -523,6 +527,7 @@ struct fils_filter_info {
 
 /**
  * @bss_scoring_required :- flag to bypass scoring filtered results
+ * @enable_adaptive_11r:    flag to check if adaptive 11r ini is enabled
  * @age_threshold: If set return entry which are newer than the age_threshold
  * @p2p_results: If only p2p entries is required
  * @rrm_measurement_filter: For measurement reports.if set, only SSID, BSSID
@@ -560,6 +565,7 @@ struct fils_filter_info {
  */
 struct scan_filter {
 	bool bss_scoring_required;
+	bool enable_adaptive_11r;
 	uint32_t age_threshold;
 	uint32_t p2p_results;
 	uint32_t rrm_measurement_filter;

+ 15 - 0
umac/scan/dispatcher/inc/wlan_scan_utils_api.h

@@ -673,6 +673,7 @@ util_scan_copy_beacon_data(struct scan_cache_entry *new_entry,
 	ie_lst->esp = conv_ptr(ie_lst->esp, old_ptr, new_ptr);
 	ie_lst->mbo_oce = conv_ptr(ie_lst->mbo_oce, old_ptr, new_ptr);
 	ie_lst->extender = conv_ptr(ie_lst->extender, old_ptr, new_ptr);
+	ie_lst->adaptive_11r = conv_ptr(ie_lst->adaptive_11r, old_ptr, new_ptr);
 
 	return QDF_STATUS_SUCCESS;
 }
@@ -809,6 +810,20 @@ util_scan_entry_rsn(struct scan_cache_entry *scan_entry)
 	return scan_entry->ie_list.rsn;
 }
 
+/**
+ * util_scan_entry_adaptive_11r()- function to read adaptive 11r Vendor IE
+ * @scan_entry: scan entry
+ *
+ * API, function to read adaptive 11r IE
+ *
+ * Return:  apaptive 11r ie or NULL if ie is not present
+ */
+static inline uint8_t*
+util_scan_entry_adaptive_11r(struct scan_cache_entry *scan_entry)
+{
+	return scan_entry->ie_list.adaptive_11r;
+}
+
 /**
  * util_scan_get_rsn_len()- function to read rsn IE length if present
  * @scan_entry: scan entry

+ 39 - 0
umac/scan/dispatcher/src/wlan_scan_utils_api.c

@@ -471,6 +471,13 @@ util_scan_parse_vendor_ie(struct scan_cache_entry *scan_params,
 		scan_params->ie_list.mbo_oce = (uint8_t *)ie;
 	} else if (is_extender_oui((uint8_t *)ie)) {
 		scan_params->ie_list.extender = (uint8_t *)ie;
+	} else if (is_adaptive_11r_oui((uint8_t *)ie)) {
+		if ((ie->ie_len < OUI_LENGTH) ||
+		    (ie->ie_len > MAX_ADAPTIVE_11R_IE_LEN))
+			return QDF_STATUS_E_INVAL;
+
+		scan_params->ie_list.adaptive_11r = (uint8_t *)ie +
+						sizeof(struct ie_header);
 	}
 	return QDF_STATUS_SUCCESS;
 }
@@ -977,6 +984,36 @@ util_scan_add_hidden_ssid(struct wlan_objmgr_pdev *pdev, qdf_nbuf_t bcnbuf)
 	return QDF_STATUS_SUCCESS;
 }
 #endif /* WLAN_DFS_CHAN_HIDDEN_SSID */
+
+#ifdef WLAN_ADAPTIVE_11R
+/**
+ * scm_fill_adaptive_11r_cap() - Check if the AP supports adaptive 11r
+ * @scan_entry: Pointer to the scan entry
+ *
+ * Return: true if adaptive 11r is advertised else false
+ */
+static void scm_fill_adaptive_11r_cap(struct scan_cache_entry *scan_entry)
+{
+	uint8_t *ie;
+	uint8_t data;
+	bool adaptive_11r;
+
+	ie = util_scan_entry_adaptive_11r(scan_entry);
+	if (!ie)
+		return;
+
+	data = *(ie + OUI_LENGTH);
+	adaptive_11r = (data & 0x1) ? true : false;
+
+	scan_entry->adaptive_11r_ap = adaptive_11r;
+}
+#else
+static void scm_fill_adaptive_11r_cap(struct scan_cache_entry *scan_entry)
+{
+	scan_entry->adaptive_11r_ap = false;
+}
+#endif
+
 static QDF_STATUS
 util_scan_gen_scan_entry(struct wlan_objmgr_pdev *pdev,
 			 uint8_t *frame, qdf_size_t frame_len,
@@ -1114,6 +1151,8 @@ util_scan_gen_scan_entry(struct wlan_objmgr_pdev *pdev,
 		scan_entry->phy_mode = util_scan_get_phymode_2g(scan_entry);
 
 	scan_entry->nss = util_scan_scm_calc_nss_supported_by_ap(scan_entry);
+	scm_fill_adaptive_11r_cap(scan_entry);
+
 	util_scan_scm_update_bss_with_esp_data(scan_entry);
 	qbss_load = (struct qbss_load_ie *)
 			util_scan_entry_qbssload(scan_entry);