Browse Source

qcacmn: Select best candidate at first connection

Best candidate at first connection is a mechanism
to select best possible candidate for making Wi-Fi
connection based on the scan results provided.
Driver use Scan results to calculate score for each
BSS and select the best candidate to connect.

This enhances the user experience by connection
to better AP, based on certain parameters.

Change-Id: Iebb4ce009b23cae8ad7cbff83628e01633bbf3fe
CRs-Fixed: 2018585
Abhishek Singh 7 years ago
parent
commit
b80af7e971

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

@@ -327,6 +327,7 @@ enum extn_element_ie {
 	WLAN_EXTN_ELEMID_HECAP       = 35,
 	WLAN_EXTN_ELEMID_HEOP        = 36,
 	WLAN_EXTN_ELEMID_SRP         = 39,
+	WLAN_EXTN_ELEMID_ESP         = 11,
 };
 
 #define WLAN_OUI_SIZE 4
@@ -734,6 +735,65 @@ struct wlan_vendor_ie_htinfo {
 	struct wlan_ie_htinfo_cmn hi_ie;
 } qdf_packed;
 
+/**
+ * struct wlan_ie_vhtcaps - VHT capabilities
+ * @elem_id: VHT caps IE
+ * @elem_len: VHT caps IE len
+ * @max_mpdu_len: MPDU length
+ * @supported_channel_widthset: channel width set
+ * @ldpc_coding: LDPC coding capability
+ * @shortgi80: short GI 80 support
+ * @shortgi160and80plus80: short Gi 160 & 80+80 support
+ * @tx_stbc; Tx STBC cap
+ * @tx_stbc: Rx STBC cap
+ * @su_beam_former: SU beam former cap
+ * @su_beam_formee: SU beam formee cap
+ * @csnof_beamformer_antSup: Antenna support for beamforming
+ * @num_soundingdim: Sound dimensions
+ * @mu_beam_former: MU beam former cap
+ * @mu_beam_formee: MU beam formee cap
+ * @vht_txops: TXOP power save
+ * @htc_vhtcap: HTC VHT capability
+ * @max_ampdu_lenexp: AMPDU length
+ * @vht_link_adapt: VHT link adapatation capable
+ * @rx_antpattern: Rx Antenna pattern
+ * @tx_antpattern: Tx Antenna pattern
+ * @rx_mcs_map: RX MCS map
+ * @rx_high_sup_data_rate : highest RX supported data rate
+ * @tx_mcs_map: TX MCS map
+ * @tx_sup_data_rate: highest TX supported data rate
+ */
+struct wlan_ie_vhtcaps {
+	uint8_t elem_id;
+	uint8_t elem_len;
+	uint32_t max_mpdu_len:2;
+	uint32_t supported_channel_widthset:2;
+	uint32_t ldpc_coding:1;
+	uint32_t shortgi80:1;
+	uint32_t shortgi160and80plus80:1;
+	uint32_t tx_stbc:1;
+	uint32_t rx_stbc:3;
+	uint32_t su_beam_former:1;
+	uint32_t su_beam_formee:1;
+	uint32_t csnof_beamformer_antSup:3;
+	uint32_t num_soundingdim:3;
+	uint32_t mu_beam_former:1;
+	uint32_t mu_beam_formee:1;
+	uint32_t vht_txops:1;
+	uint32_t htc_vhtcap:1;
+	uint32_t max_ampdu_lenexp:3;
+	uint32_t vht_link_adapt:2;
+	uint32_t rx_antpattern:1;
+	uint32_t tx_antpattern:1;
+	uint32_t unused:2;
+	uint16_t rx_mcs_map;
+	uint16_t rx_high_sup_data_rate:13;
+	uint16_t reserved2:3;
+	uint16_t tx_mcs_map;
+	uint16_t tx_sup_data_rate:13;
+	uint16_t reserved3:3;
+} qdf_packed;
+
 /**
  * struct wlan_ie_vhtop: VHT op IE
  * @elem_id: VHT op IE
@@ -764,6 +824,20 @@ struct wlan_country_ie {
 	uint8_t cc[3];
 } qdf_packed;
 
+/**
+ * struct wlan_country_ie: country IE
+ * @ie: QBSS IE
+ * @len: IE len
+ * @qbss_chan_load: qbss channel load
+ * @qbss_load_avail: qbss_load_avail
+ */
+struct qbss_load_ie {
+	uint8_t ie;
+	uint8_t len;
+	uint8_t qbss_chan_load;
+	uint16_t qbss_load_avail;
+} qdf_packed;
+
 /**
  * struct wlan_bcn_frame: beacon frame fixed params
  * @timestamp: the value of sender's TSFTIMER
@@ -843,6 +917,84 @@ struct wlan_srp_ie {
 	};
 } qdf_packed;
 
+#define ESP_INFORMATION_LIST_LENGTH 3
+#define MAX_ESP_INFORMATION_FIELD 4
+/*
+ * enum access_category: tells about access category in ESP paramameter
+ * @ESP_AC_BK: ESP access category for background
+ * @ESP_AC_BE: ESP access category for best effort
+ * @ESP_AC_VI: ESP access category for video
+ * @ESP_AC_VO: ESP access category for Voice
+ */
+enum access_category {
+	ESP_AC_BK,
+	ESP_AC_BE,
+	ESP_AC_VI,
+	ESP_AC_VO,
+
+};
+/*
+ * struct wlan_esp_info: structure for Esp information parameter
+ * @access_category: access category info
+ * @reserved: reserved
+ * @data_format: two bits in length and tells about data format
+ * i.e. 0 = No aggregation is expected to be performed for MSDUs or MPDUs with
+ * the Type subfield equal to Data for the corresponding AC
+ * 1 = A-MSDU aggregation is expected to be performed for MSDUs for the
+ * corresponding AC, but A-MPDU aggregation is not expected to be performed
+ * for MPDUs with the Type subfield equal to Data for the corresponding AC
+ * 2 = A-MPDU aggregation is expected to be performed for MPDUs with the Type
+ * subfield equal to Data for the corresponding AC, but A-MSDU aggregation is
+ * not expected to be performed for MSDUs for the corresponding AC
+ * 3 = A-MSDU aggregation is expected to be performed for MSDUs for the
+ * corresponding AC and A-MPDU aggregation is expected to be performed for
+ * MPDUs with the Type subfield equal to Data for the corresponding AC
+ * @ba_window_size: BA Window Size subfield is three bits in length and
+ * indicates the size of the Block Ack window that is
+ * expected for the corresponding access category
+ * @estimated_air_fraction: Estimated Air Time Fraction subfield is 8 bits in
+ * length and contains an unsigned integer that represents
+ * the predicted percentage of time, linearly scaled with 255 representing
+ * 100%, that a new STA joining the
+ * BSS will be allocated for PPDUs that contain only
+ * MPDUs with the Type
+ * subfield equal to Data of the
+ * corresponding access category for that STA.
+ * @ppdu_duration: Data PPDU Duration Target field
+ * is 8 bits in length and is
+ * an unsigned integer that indicates the
+ * expected target duration of PPDUs that contain only MPDUs with the Type
+ * subfield equal to Data for the
+ * corresponding access category in units of 50 μs
+ */
+struct wlan_esp_info {
+	uint8_t access_category:2;
+	uint8_t reserved:1;
+	uint8_t data_format:2;
+	uint8_t ba_window_size:3;
+	uint8_t estimated_air_fraction;
+	uint8_t ppdu_duration;
+};
+
+/**
+ * struct wlan_esp_ie: struct for ESP information
+ * @esp_id: ESP IE id
+ * @esp_len: ESP IE len
+ * @esp_id_extn: ESP Extension ID
+ * @esp_info_AC_BK: ESP information related to BK category
+ * @esp_info_AC_BE: ESP information related to BE category
+ * @esp_info_AC_VI: ESP information related to VI category
+ * @esp_info_AC_VO: ESP information related to VO category
+ */
+struct wlan_esp_ie {
+	uint8_t esp_id;
+	uint8_t esp_len;
+	uint8_t esp_id_extn;
+	struct wlan_esp_info esp_info_AC_BK;
+	struct wlan_esp_info esp_info_AC_BE;
+	struct wlan_esp_info esp_info_AC_VI;
+	struct wlan_esp_info esp_info_AC_VO;
+} qdf_packed;
 /**
  * is_wpa_oui() - If vendor IE is WPA type
  * @frm: vendor IE pointer

+ 20 - 4
umac/scan/core/src/wlan_scan_cache_db.c

@@ -589,7 +589,6 @@ QDF_STATUS scm_handle_bcn_probe(struct scheduler_msg *msg)
 		status = QDF_STATUS_E_INVAL;
 		goto free_nbuf;
 	}
-
 	scm_info("Received %s from BSSID: %pM tsf_delta = %u Seq Num: %x "
 		"ssid:%.*s, rssi: %d",
 		(bcn->frm_type == MGMT_SUBTYPE_PROBE_RESP) ?
@@ -645,11 +644,29 @@ static void scm_list_insert_sorted(struct wlan_objmgr_psoc *psoc,
 	struct scan_cache_node *cur_node;
 	qdf_list_node_t *cur_lst = NULL, *next_lst = NULL;
 	struct scan_default_params *params;
+	int pcl_chan_weight = 0;
 
 	params = wlan_scan_psoc_get_def_params(psoc);
 
-	scm_calculate_bss_score(params, filter,
-			scan_node->entry);
+	if (filter->num_of_pcl_channels > 0 &&
+			(scan_node->entry->rssi_raw > SCM_PCL_RSSI_THRESHOLD)) {
+		if (scm_get_pcl_weight_of_channel(
+					scan_node->entry->channel.chan_idx,
+					filter, &pcl_chan_weight,
+					filter->pcl_weight_list)) {
+			scm_debug("pcl channel %d pcl_chan_weight %d",
+					scan_node->entry->channel.chan_idx,
+					pcl_chan_weight);
+		}
+	}
+	if (params->is_bssid_hint_priority &&
+	    !qdf_mem_cmp(filter->bssid_hint.bytes,
+			 scan_node->entry->bssid.bytes,
+			 QDF_MAC_ADDR_SIZE))
+		scan_node->entry->bss_score = BEST_CANDIDATE_MAX_BSS_SCORE;
+	else
+		scm_calculate_bss_score(psoc, params,
+					scan_node->entry, pcl_chan_weight);
 
 	if (qdf_list_empty(scan_list)) {
 		qdf_list_insert_front(scan_list, &scan_node->node);
@@ -831,7 +848,6 @@ qdf_list_t *scm_get_scan_result(struct wlan_objmgr_pdev *pdev,
 	}
 	qdf_list_create(tmp_list,
 			MAX_SCAN_CACHE_SIZE);
-
 	scm_age_out_entries(psoc, scan_db);
 	scm_get_results(psoc, scan_db, filter, tmp_list);
 

+ 44 - 0
umac/scan/core/src/wlan_scan_cache_db.h

@@ -33,6 +33,50 @@
 #define SCAN_GET_HASH(addr) \
 	(((const uint8_t *)(addr))[QDF_MAC_ADDR_SIZE - 1] % SCAN_HASH_SIZE)
 
+#define RSSI_THRESHOLD_5GHZ -70
+#define BEST_CANDIDATE_RSSI_WEIGHT 50
+#define MIN_RSSI (-100)
+#define MAX_RSSI 0
+#define ROAM_MAX_CHANNEL_WEIGHT 100
+#define MAX_CHANNEL_UTILIZATION 100
+#define NSS_1X1_WEIGHTAGE 3
+#define MAX_ESTIMATED_AIR_TIME_FRACTION 255
+#define MAX_AP_LOAD 255
+
+#define LOW_CHANNEL_CONGESTION_WEIGHT 500
+#define MODERATE_CHANNEL_CONGESTION_WEIGHT 370
+#define CONSIDERABLE_CHANNEL_CONGESTION_WEIGHT 250
+#define HIGH_CHANNEL_CONGESTION_WEIGHT 120
+
+#define LOW_CHANNEL_CONGESTION 0
+#define MODERATE_CHANNEL_CONGESTION 25
+#define CONSIDERABLE_CHANNEL_CONGESTION 50
+#define HIGH_CHANNEL_CONGESTION 75
+#define EXTREME_CHANNEL_CONGESTION 100
+
+#define RSSI_WEIGHTAGE 25
+#define HT_CAPABILITY_WEIGHTAGE 7
+#define VHT_CAP_WEIGHTAGE 5
+#define CHAN_WIDTH_WEIGHTAGE 10
+#define CHAN_BAND_WEIGHTAGE 5
+#define NSS_WEIGHTAGE 5
+#define BEAMFORMING_CAP_WEIGHTAGE 2
+#define PCL_WEIGHT 10
+#define CHANNEL_CONGESTION_WEIGHTAGE 5
+#define RESERVED_WEIGHT 31
+
+#define EXCELLENT_RSSI -55
+#define BAD_RSSI  -80
+#define EXCELLENT_RSSI_WEIGHT 100
+#define RSSI_BUCKET 5
+#define RSSI_WEIGHT_BUCKET 250
+
+#define BEST_CANDIDATE_MAX_WEIGHT 100
+#define BEST_CANDIDATE_80MHZ 100
+#define BEST_CANDIDATE_40MHZ 70
+#define BEST_CANDIDATE_20MHZ 30
+#define BEST_CANDIDATE_MAX_BSS_SCORE 10000
+
 /**
  * struct scan_dbs - scan cache data base definition
  * @num_entries: number of scan entries

+ 23 - 33
umac/scan/core/src/wlan_scan_cache_db_i.h

@@ -53,35 +53,6 @@ bool scm_filter_match(struct wlan_objmgr_psoc *psoc,
 bool scm_is_better_bss(struct scan_default_params *params,
 	struct scan_cache_entry *bss1,
 	struct scan_cache_entry *bss2);
-
-/**
- * is_channel_found_in_pcl() - to check if channel is present in pcl
- * @channel_id: channel of bss
- * @filter: pointer to filter created through profile
- *
- * to check if provided channel is present in pcl
- *
- * Return: true or false
- */
-static inline bool is_channel_found_in_pcl(int channel_id,
-		struct scan_filter *filter)
-{
-	int i;
-	bool status = false;
-
-	if (!filter)
-		return status;
-
-	for (i = 0; i < filter->num_of_pcl_channels; i++) {
-		if (filter->pcl_channel_list[i] == channel_id) {
-			status = true;
-			break;
-		}
-	}
-
-	return status;
-}
-
 /**
  * scm_derive_prefer_value_from_rssi() - to derive prefer value
  * @params: scan params
@@ -112,15 +83,18 @@ scm_derive_prefer_value_from_rssi(struct scan_default_params *params,
 /**
  * scm_calculate_bss_score() - calculate BSS score used to get
  * the preference
+ * psoc: psoc ptr;
  * @params: scan params
- * @filter: filter to find match from scan result
  * @entry: scan entry for which score needs to be calculated
+ * @pcl_chan_weight: weight for pcl channel
  *
  * Return: scan db for the pdev id
  */
-void scm_calculate_bss_score(struct scan_default_params *params,
-	struct scan_filter *filter,
-	struct scan_cache_entry *entry);
+int scm_calculate_bss_score(
+		struct wlan_objmgr_psoc *psoc,
+		struct scan_default_params *params,
+		struct scan_cache_entry *entry,
+		int pcl_chan_weight);
 
 /**
  * wlan_pdevid_get_scan_db() - private API to get scan db from pdev id
@@ -166,4 +140,20 @@ wlan_pdev_get_scan_db(struct wlan_objmgr_psoc *psoc,
 
 	return wlan_pdevid_get_scan_db(psoc, pdev_id);
 }
+
+/**
+ * scm_get_pcl_weight_of_channel() - Get PCL weight if channel is present in pcl
+ * @channel_id: channel of bss
+ * @filter: filter
+ * @pcl_chan_weight: Get PCL weight for corresponding channel
+ * @weight_list: Weight list for all the pcl channels.
+ *
+ * Get pcl_chan_weight if provided channel is present in pcl list
+ *
+ * Return: true or false
+ */
+bool scm_get_pcl_weight_of_channel(int channel_id,
+		struct scan_filter *filter,
+		int *pcl_chan_weight,
+		uint8_t *weight_list);
 #endif

+ 198 - 239
umac/scan/core/src/wlan_scan_cache_db_ops.c

@@ -26,267 +26,206 @@
 #include "wlan_scan_main.h"
 #include "wlan_scan_cache_db_i.h"
 
-/**
- * scm_get_altered_rssi() - Artificially increase/decrease RSSI
- * @params: scan params
- * @rssi: Actual RSSI of the AP.
- * @channel_id: Channel on which the AP is parked.
- * @bssid: BSSID of the AP to connect to.
- *
- * This routine will apply the boost and penalty parameters
- * if the channel_id is of 5G band and it will also apply
- * the preferred bssid score if there is a match between
- * the bssid and the global preferred bssid list.
- *
- * Return: The modified RSSI Value
- */
-static int scm_get_altered_rssi(struct scan_default_params *params,
-	int rssi, uint8_t channel_id, struct qdf_mac_addr *bssid)
-{
-	int modified_rssi;
-	int boost_factor;
-	int penalty_factor;
-	int i;
-	struct roam_filter_params *roam_params;
-
-	roam_params = &params->roam_params;
-	modified_rssi = rssi;
-
-	/*
-	 * If the 5G pref feature is enabled, apply the roaming
-	 * parameters to boost or penalize the rssi.
-	 * Boost Factor = boost_factor * (Actual RSSI - boost Threshold)
-	 * Penalty Factor = penalty factor * (penalty threshold - Actual RSSI)
-	 */
-	if (roam_params->is_5g_pref_enabled &&
-			WLAN_CHAN_IS_2GHZ(channel_id)) {
-		if (rssi > roam_params->raise_rssi_thresh_5g) {
-			/* Check and boost the threshold*/
-			boost_factor = roam_params->raise_factor_5g *
-				(rssi - roam_params->raise_rssi_thresh_5g);
-			/* Check and penalize the threshold */
-			modified_rssi += QDF_MIN(roam_params->max_raise_rssi_5g,
-				boost_factor);
-		} else if (rssi < roam_params->drop_rssi_thresh_5g) {
-			penalty_factor = roam_params->drop_factor_5g *
-				(roam_params->drop_rssi_thresh_5g - rssi);
-			modified_rssi -= QDF_MIN(roam_params->max_drop_rssi_5g,
-				penalty_factor);
-		}
-	}
-	/*
-	 * Check if there are preferred bssid and then apply the
-	 * preferred score
-	 */
-	if (bssid && roam_params->num_bssid_favored &&
-	   (roam_params->num_bssid_favored <= MAX_FAVORED_BSSID)) {
-		for (i = 0; i < roam_params->num_bssid_favored; i++) {
-			if (!qdf_is_macaddr_equal(
-			   &roam_params->bssid_favored[i], bssid))
-				continue;
-			modified_rssi +=
-				roam_params->bssid_favored_factor[i];
-		}
-	}
-
-	return modified_rssi;
-}
-
-/**
- * scm_is_better_rssi() - Is bss1 better than bss2
- * @params: scan params
- * @bss1: Pointer to the first BSS.
- * @bss2: Pointer to the second BSS.
- *
- * This routine helps in determining the preference value
- * of a particular BSS in the scan result which is further
- * used in the sorting logic of the final candidate AP's.
- *
- * Return: true, if bss1 is better than bss2
- *         false, if bss2 is better than bss1.
- */
-static bool scm_is_better_rssi(struct scan_default_params *params,
-	struct scan_cache_entry *bss1, struct scan_cache_entry *bss2)
-{
-	bool ret;
-	int rssi1, rssi2;
-	struct qdf_mac_addr local_mac;
-
-	rssi1 = bss1->rssi_raw;
-	rssi2 = bss2->rssi_raw;
-	/*
-	 * Apply the boost and penlty logic and check
-	 * which is the best RSSI
-	 */
-	qdf_mem_copy(local_mac.bytes,
-		bss1->bssid.bytes, QDF_MAC_ADDR_SIZE);
-	rssi1 = scm_get_altered_rssi(params, rssi1,
-			bss1->channel.chan_idx,
-			&local_mac);
-	qdf_mem_copy(local_mac.bytes,
-			bss2->bssid.bytes, QDF_MAC_ADDR_SIZE);
-	rssi2 = scm_get_altered_rssi(params, rssi2,
-			bss2->channel.chan_idx,
-			&local_mac);
-	if (rssi1 > rssi2)
-		ret = true;
-	else
-		ret = false;
-
-	return ret;
-}
-
 bool scm_is_better_bss(struct scan_default_params *params,
 	struct scan_cache_entry *bss1,
 	struct scan_cache_entry *bss2)
 {
 	bool ret;
-
-	if (bss1->prefer_value > bss2->prefer_value)
-		return true;
-
-	if (bss1->prefer_value == bss2->prefer_value) {
-		if (bss1->cap_val > bss2->cap_val)
-			ret = true;
-		else if (bss1->cap_val == bss2->cap_val) {
-			if (scm_is_better_rssi(params, bss1, bss2))
-				ret = true;
-			else
-				ret = false;
-		} else {
-			ret = false;
-		}
-	} else {
+	if (bss1->bss_score > bss2->bss_score)
+		ret = true;
+	else
 		ret = false;
-	}
-
 	return ret;
-}
 
-/**
- * scm_get_bss_prefer_value() - Get the preference value for BSS
- * @params: scan params
- * @entry: entry
- *
- * Each entry should be assigned a preference value ranging from
- * 14-0, which will be used as an RSSI bucket score while sorting the
- * scan results.
- *
- * Return: Preference value for the BSSID
- */
-static uint32_t scm_get_bss_prefer_value(struct scan_default_params *params,
-			struct scan_cache_entry *entry)
+}
+int scm_calculate_bss_score(struct wlan_objmgr_psoc *psoc,
+		struct scan_default_params *params,
+		struct scan_cache_entry *entry,
+		int pcl_chan_weight)
 {
-	uint32_t ret = 0;
-	int modified_rssi;
-
+	int32_t score = 0;
+	int32_t ap_load = 0;
+	int32_t normalised_width = BEST_CANDIDATE_20MHZ;
+	int32_t pcl_score = 0;
+	int32_t temp_pcl_chan_weight = 0;
+	int32_t est_air_time_percentage = 0;
+	int32_t congestion = 0;
+	int32_t rssi_diff = 0;
+	int32_t rssi_weight = 0;
+	struct  qbss_load_ie *qbss_load;
+	struct wlan_scan_obj *scan_obj;
+	int32_t ht_score, vht_score, qbss_score = 0;
+
+
+	scan_obj = wlan_psoc_get_scan_obj(psoc);
+	if (!scan_obj) {
+		scm_err("scan_obj is NULL");
+		return 0;
+	}
 	/*
-	 * The RSSI does not get modified in case the 5G
-	 * preference or preferred BSSID is not applicable
+	 * Total weight of a BSSID is calculated on basis of 100 in which
+	 * contribution of every factor is considered like this.
+	 * RSSI: RSSI_WEIGHTAGE : 25
+	 * HT_CAPABILITY_WEIGHTAGE: 7
+	 * VHT_CAP_WEIGHTAGE: 5
+	 * BEAMFORMING_CAP_WEIGHTAGE: 2
+	 * CHAN_WIDTH_WEIGHTAGE:10
+	 * CHAN_BAND_WEIGHTAGE: 5
+	 * NSS: 5
+	 * PCL: 10
+	 * CHANNEL_CONGESTION: 5
+	 * Reserved: 31
 	 */
-	modified_rssi = scm_get_altered_rssi(params,
-		entry->rssi_raw, entry->channel.chan_idx,
-		&entry->bssid);
-	ret = scm_derive_prefer_value_from_rssi(params, modified_rssi);
-
-	return ret;
-}
-
-/**
- * scm_get_bss_cap_value() - get bss capability value
- * @params: def scan params
- * @entry: scan entry entry
- *
- * Return: CapValue base on the capabilities of a BSS
- */
-static uint32_t scm_get_bss_cap_value(struct scan_default_params *params,
-	struct scan_cache_entry *entry)
-{
-	uint32_t ret = SCM_BSS_CAP_VALUE_NONE;
-
-	if (params->prefer_5ghz ||
-	   params->roam_params.is_5g_pref_enabled)
-		if (WLAN_CHAN_IS_5GHZ(entry->channel.chan_idx))
-			ret += SCM_BSS_CAP_VALUE_5GHZ;
 	/*
-	 * if strict select 5GHz is set then ignore
-	 * the capability checking
+	 * Further bucketization of rssi is also done out of 25 score.
+	 * RSSI > -55=> weight = 2500
+	 * RSSI > -60=> weight = 2250
+	 * RSSI >-65 =>weight = 2000
+	 * RSSI > -70=> weight = 1750
+	 * RSSI > -75=> weight = 1500
+	 * RSSI > -80=> weight = 1250
 	 */
-	if (!params->select_5ghz_margin) {
-		/* give weightage in the order 11ax, 11ac, 11n */
-		if (entry->ie_list.hecap)
-			ret += SCM_BSS_CAP_VALUE_HE;
-		else if (entry->ie_list.vhtcap)
-			ret += SCM_BSS_CAP_VALUE_VHT;
-		else if (entry->ie_list.htcap)
-			ret += SCM_BSS_CAP_VALUE_HT;
-		if (entry->ie_list.wmeinfo ||
-		   entry->ie_list.wmeinfo) {
-			ret += SCM_BSS_CAP_VALUE_WMM;
-			/* TO do Give advantage to UAPSD */
+	if (entry->rssi_raw) {
+		/*
+		 * if RSSI of AP is less then -80, driver should ignore that
+		 * candidate.
+		 */
+		if (entry->rssi_raw < BAD_RSSI) {
+			scm_err("Drop this BSS %pM due to low rssi %d",
+					entry->bssid.bytes, entry->rssi_raw);
+			score = 0;
+			return score;
 		}
-	}
-
-	return ret;
-}
+		if (entry->rssi_raw >= EXCELLENT_RSSI) {
+			rssi_weight = EXCELLENT_RSSI_WEIGHT *
+				RSSI_WEIGHTAGE;
+		} else {
+			rssi_diff = EXCELLENT_RSSI - entry->rssi_raw;
+			rssi_diff = rssi_diff/5;
+			rssi_weight = (rssi_diff + 1) * RSSI_WEIGHT_BUCKET;
+			rssi_weight = (EXCELLENT_RSSI_WEIGHT *
+					RSSI_WEIGHTAGE) - rssi_weight;
 
-/**
- * scm_calc_pref_val_by_pcl() - to calculate preferred value
- * @params: scan params
- * @filter: filter to find match from scan result
- * @entry: scan entry for which score needs to be calculated
- *
- * this routine calculates the new preferred value to be given to
- * provided bss if its channel falls under preferred channel list.
- * Thump rule is higer the RSSI better the boost.
- *
- * Return: success or failure
- */
-static QDF_STATUS scm_calc_pref_val_by_pcl(struct scan_default_params *params,
-	struct scan_filter *filter,
-	struct scan_cache_entry *entry)
-{
-	int temp_rssi = 0, new_pref_val = 0;
-	int orig_pref_val = 0;
+		}
+		score += rssi_weight;
+	}
+	if (pcl_chan_weight) {
+		temp_pcl_chan_weight =
+			(SCM_MAX_WEIGHT_OF_PCL_CHANNELS - pcl_chan_weight);
+		do_div(temp_pcl_chan_weight,
+				20);
+		pcl_score = PCL_WEIGHT - temp_pcl_chan_weight;
 
-	if (!entry)
-		return QDF_STATUS_E_FAILURE;
+		if (pcl_score < 0)
+			pcl_score = 0;
 
-	if (filter->num_of_bssid) {
-		scm_info("filter has specific bssid, no point of boosting");
-		return QDF_STATUS_SUCCESS;
+		score += pcl_score * BEST_CANDIDATE_MAX_WEIGHT;
 	}
-
-	if (is_channel_found_in_pcl(entry->channel.chan_idx, filter) &&
-		(entry->rssi_raw > SCM_PCL_RSSI_THRESHOLD)) {
-		orig_pref_val = scm_derive_prefer_value_from_rssi(params,
-					entry->rssi_raw);
-		temp_rssi = entry->rssi_raw +
-				(SCM_PCL_ADVANTAGE/(SCM_NUM_RSSI_CAT -
-							orig_pref_val));
-		if (temp_rssi > 0)
-			temp_rssi = 0;
-		new_pref_val = scm_derive_prefer_value_from_rssi(params,
-					temp_rssi);
-
-		entry->prefer_value =
-			QDF_MAX(new_pref_val, entry->prefer_value);
+	/* If AP supports HT caps, extra 10% score will be added */
+	if (entry->ie_list.htcap) {
+		ht_score = BEST_CANDIDATE_MAX_WEIGHT * HT_CAPABILITY_WEIGHTAGE;
+		score += BEST_CANDIDATE_MAX_WEIGHT * HT_CAPABILITY_WEIGHTAGE;
 	}
 
-	return QDF_STATUS_SUCCESS;
-}
-
-void scm_calculate_bss_score(struct scan_default_params *params,
-	struct scan_filter *filter, struct scan_cache_entry *entry)
-{
-	entry->cap_val =
-		scm_get_bss_cap_value(params, entry);
+	/* If AP supports VHT caps, Extra 6% score will be added to score */
+	if (entry->ie_list.vhtcap) {
+		vht_score = BEST_CANDIDATE_MAX_WEIGHT * VHT_CAP_WEIGHTAGE;
+		score += BEST_CANDIDATE_MAX_WEIGHT * VHT_CAP_WEIGHTAGE;
+	}
 
-	entry->prefer_value =
-		scm_get_bss_prefer_value(params, entry);
+	/*
+	 * Channel width is again calculated on basis of 100.
+	 * Where if AP is
+	 * 80MHZ = 100
+	 * 40MHZ = 70
+	 * 20MHZ = 30 weightage is given out of 100.
+	 * Channel width weightage is given as CHAN_WIDTH_WEIGHTAGE (10%).
+	 */
+	if (entry->phy_mode == WLAN_PHYMODE_11AC_VHT20 ||
+	    entry->phy_mode == WLAN_PHYMODE_11AC_VHT40PLUS ||
+	    entry->phy_mode == WLAN_PHYMODE_11AC_VHT40MINUS ||
+	    entry->phy_mode == WLAN_PHYMODE_11AC_VHT40 ||
+	    entry->phy_mode == WLAN_PHYMODE_11AC_VHT80 ||
+	    entry->phy_mode == WLAN_PHYMODE_11AC_VHT80_80 ||
+	    entry->phy_mode == WLAN_PHYMODE_11AC_VHT160)
+		normalised_width = BEST_CANDIDATE_80MHZ;
+	else if (entry->phy_mode == WLAN_PHYMODE_11NA_HT40PLUS ||
+			entry->phy_mode == WLAN_PHYMODE_11NA_HT40MINUS ||
+			entry->phy_mode == WLAN_PHYMODE_11NG_HT40PLUS ||
+			entry->phy_mode == WLAN_PHYMODE_11NG_HT40MINUS ||
+			entry->phy_mode == WLAN_PHYMODE_11NG_HT40 ||
+			entry->phy_mode == WLAN_PHYMODE_11NA_HT40)
+		normalised_width = BEST_CANDIDATE_40MHZ;
+	else
+		normalised_width = BEST_CANDIDATE_20MHZ;
+	score += normalised_width * CHAN_WIDTH_WEIGHTAGE;
 
-	if (filter->num_of_pcl_channels)
-		scm_calc_pref_val_by_pcl(params, filter, entry);
+	if (util_scan_scm_chan_to_band(
+				entry->channel.chan_idx) == WLAN_BAND_5_GHZ &&
+			entry->rssi_raw > RSSI_THRESHOLD_5GHZ)
+		score += BEST_CANDIDATE_MAX_WEIGHT * CHAN_BAND_WEIGHTAGE;
+	/*
+	 * If ESP is being transmitted by the AP, use the estimated airtime for
+	 * AC_BE from that, Estimated airtime 0-25% = 120, 25-50% = 250, 50-75%
+	 * = 370, 75-100% = 500.
+	 * Else if QBSSLoad is being transmitted and QBSSLoad < 25% = 500
+	 * else assing default weight of 370
+	 */
+	if (entry->air_time_fraction) {
+		est_air_time_percentage =
+			entry->air_time_fraction * ROAM_MAX_CHANNEL_WEIGHT;
+		est_air_time_percentage =
+			est_air_time_percentage/MAX_ESTIMATED_AIR_TIME_FRACTION;
+		/*
+		 * Calculate channel congestion from estimated air time
+		 * fraction.
+		 */
+		congestion = MAX_CHANNEL_UTILIZATION - est_air_time_percentage;
+		if (congestion >= LOW_CHANNEL_CONGESTION &&
+				congestion < MODERATE_CHANNEL_CONGESTION)
+			score += LOW_CHANNEL_CONGESTION_WEIGHT;
+		else if (congestion >= MODERATE_CHANNEL_CONGESTION &&
+				congestion < CONSIDERABLE_CHANNEL_CONGESTION)
+			score += MODERATE_CHANNEL_CONGESTION_WEIGHT;
+		else if (congestion >= CONSIDERABLE_CHANNEL_CONGESTION &&
+				congestion < HIGH_CHANNEL_CONGESTION)
+			score += CONSIDERABLE_CHANNEL_CONGESTION_WEIGHT;
+		else
+			score += HIGH_CHANNEL_CONGESTION_WEIGHT;
+	} else if (entry->ie_list.qbssload) {
+		qbss_load = (struct qbss_load_ie *)
+			util_scan_entry_qbssload(entry);
+		scm_debug("qbss_load is %d", qbss_load->qbss_chan_load);
+		/*
+		 * Calculate ap_load in % from qbss channel load from 0-255
+		 * range
+		 */
+		ap_load = (qbss_load->qbss_chan_load *
+				BEST_CANDIDATE_MAX_WEIGHT);
+		ap_load = ap_load/MAX_AP_LOAD;
+		congestion = ap_load;
+		if (congestion < MODERATE_CHANNEL_CONGESTION) {
+			qbss_score = LOW_CHANNEL_CONGESTION_WEIGHT;
+			score += LOW_CHANNEL_CONGESTION_WEIGHT;
+		} else {
+			qbss_score = HIGH_CHANNEL_CONGESTION_WEIGHT;
+			score += HIGH_CHANNEL_CONGESTION_WEIGHT;
+		}
+	} else {
+		qbss_score = MODERATE_CHANNEL_CONGESTION_WEIGHT;
+		scm_debug("qbss load is not present so qbss_Score is %d",
+				qbss_score);
+		score += MODERATE_CHANNEL_CONGESTION_WEIGHT;
+	}
+	scm_debug(" ht_score %d vht_score %d and qbss_score %d",
+			ht_score, vht_score, qbss_score);
+	scm_debug(" BSS %pM rssi %d channel %d final score %d",
+			entry->bssid.bytes,
+			entry->rssi_raw, entry->channel.chan_idx,
+			score);
+	scm_info("nss %d", entry->nss);
+	entry->bss_score = score;
+	return score;
 }
 
 /**
@@ -1167,3 +1106,23 @@ bool scm_filter_match(struct wlan_objmgr_psoc *psoc,
 
 	return true;
 }
+bool scm_get_pcl_weight_of_channel(int channel_id,
+		struct scan_filter *filter,
+		int *pcl_chan_weight,
+		uint8_t *weight_list)
+{
+	int i;
+	bool found = false;
+
+	if (NULL == filter)
+		return found;
+
+	for (i = 0; i < filter->num_of_pcl_channels; i++) {
+		if (filter->pcl_channel_list[i] == channel_id) {
+			*pcl_chan_weight = filter->pcl_weight_list[i];
+			found = true;
+			break;
+		}
+	}
+	return found;
+}

+ 2 - 0
umac/scan/core/src/wlan_scan_main.h

@@ -227,6 +227,7 @@ struct pno_def_config {
  * @select_5gh_margin: Prefer connecting to 5G AP even if
  *      its RSSI is lower by select_5gh_margin dbm than 2.4G AP.
  *      applicable if prefer_5ghz is set.
+ * @is_bssid_hint_priority: True if bssid_hint is given priority
  * @bss_prefer_val: bss prefer value for the RSSI category
  * @rssi_cat: RSSI category
  * @max_bss_per_pdev: maximum number of bss entries to be maintained per pdev
@@ -293,6 +294,7 @@ struct scan_default_params {
 	uint32_t scan_cache_aging_time;
 	uint32_t prefer_5ghz;
 	uint32_t select_5ghz_margin;
+	bool is_bssid_hint_priority;
 	/* each RSSI category has one value */
 	uint32_t bss_prefer_val[SCM_NUM_RSSI_CAT];
 	int rssi_cat[SCM_NUM_RSSI_CAT];

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

@@ -37,6 +37,7 @@ typedef uint32_t wlan_scan_id;
 
 #define SCM_PCL_ADVANTAGE       30
 #define SCM_PCL_RSSI_THRESHOLD -75
+#define SCM_MAX_WEIGHT_OF_PCL_CHANNELS 255
 
 #define SCM_BSS_CAP_VALUE_NONE  0/* not much value */
 #define SCM_BSS_CAP_VALUE_HT    1
@@ -127,6 +128,7 @@ struct element_info {
  * @txpwrenvlp: pointer to tx power envelop sub ie
  * @srp: pointer to spatial reuse parameter sub extended ie
  * @fils_indication: pointer to FILS indication ie
+ * @esp: pointer to ESP indication ie
  */
 struct ie_list {
 	uint8_t *tim;
@@ -169,6 +171,7 @@ struct ie_list {
 	uint8_t *heop;
 	uint8_t *srp;
 	uint8_t *fils_indication;
+	uint8_t *esp;
 };
 
 /**
@@ -236,6 +239,8 @@ struct security_info {
  * @tsf_info: TSF info
  * @erp: erp info
  * @dtim_period: dtime period
+ * @air_time_fraction: Air time fraction from ESP param
+ * @nss: supported NSS information
  * @is_p2p_ssid: is P2P entry
  * @scan_entry_time: boottime in microsec when last beacon/probe is received
  * @rssi_timestamp: boottime in microsec when RSSI was updated
@@ -247,6 +252,7 @@ struct security_info {
  * @tsf_delta: TSF delta
  * @prefer_value: Preffer value calulated for the AP
  * @cap_value: Capability value calculated for the AP
+ * @bss_score: bss score calculated on basis of RSSI/caps etc.
  * @neg_sec_info: negotiated security info
  * @rrm_parent_tsf: RRM parent tsf
  * @mlme_info: Mlme info, this will be updated by MLME for the scan entry
@@ -271,6 +277,8 @@ struct scan_cache_entry {
 	} tsf_info;
 	uint8_t erp;
 	uint8_t dtim_period;
+	uint8_t air_time_fraction;
+	uint8_t nss;
 	bool is_p2p;
 	qdf_time_t scan_entry_time;
 	qdf_time_t rssi_timestamp;
@@ -281,6 +289,7 @@ struct scan_cache_entry {
 	uint32_t tsf_delta;
 	uint32_t prefer_value;
 	uint32_t cap_val;
+	uint32_t bss_score;
 	struct security_info neg_sec_info;
 	uint32_t rrm_parent_tsf;
 	struct element_info alt_wcn_ie;
@@ -385,6 +394,8 @@ struct fils_filter_info {
  * @mc_enc_type: multicast cast enc type list
  * @pcl_channel_list: PCL channel list
  * @fils_scan_filter: FILS info
+ * @pcl_weight_list: PCL Weight list
+ * @bssid_hint: Mac address of bssid_hint
  */
 struct scan_filter {
 	uint32_t age_threshold;
@@ -415,6 +426,8 @@ struct scan_filter {
 	enum wlan_enc_type mc_enc_type[WLAN_NUM_OF_ENCRYPT_TYPE];
 	uint8_t pcl_channel_list[QDF_MAX_NUM_CHAN];
 	struct fils_filter_info fils_scan_filter;
+	uint8_t pcl_weight_list[QDF_MAX_NUM_CHAN];
+	struct qdf_mac_addr bssid_hint;
 };
 
 
@@ -1048,6 +1061,7 @@ struct pno_user_cfg {
  * @scan_dwell_time_mode: Adaptive dweltime mode
  * @pno_cfg: Pno related config params
  * @ie_whitelist: probe req IE whitelist attrs
+ * @is_bssid_hint_priority: True if bssid_hint is priority
  */
 struct scan_user_cfg {
 	uint32_t active_dwell;
@@ -1066,6 +1080,7 @@ struct scan_user_cfg {
 	enum scan_dwelltime_adaptive_mode scan_dwell_time_mode;
 	struct pno_user_cfg pno_cfg;
 	struct probe_req_whitelist_attr ie_whitelist;
+	bool is_bssid_hint_priority;
 };
 
 /**

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

@@ -651,6 +651,7 @@ util_scan_copy_beacon_data(struct scan_cache_entry *new_entry,
 	ie_lst->heop = conv_ptr(ie_lst->heop, old_ptr, new_ptr);
 	ie_lst->fils_indication = conv_ptr(ie_lst->fils_indication,
 					   old_ptr, new_ptr);
+	ie_lst->esp = conv_ptr(ie_lst->esp, old_ptr, new_ptr);
 
 	return QDF_STATUS_SUCCESS;
 }
@@ -1353,4 +1354,27 @@ util_scan_entry_is_hidden_ap(struct scan_cache_entry *scan_entry)
     return util_scan_is_hidden_ssid(
 			(struct ie_ssid *)scan_entry->ie_list.ssid);
 }
+
+/**
+ * util_scan_entry_espinfo() - function to read ESP info
+ * @scan_entry: scan entry
+ *
+ * API, function to read ESP info
+ *
+ * Return: erp info
+ */
+static inline uint8_t *
+util_scan_entry_esp_info(struct scan_cache_entry *scan_entry)
+{
+	return scan_entry->ie_list.esp;
+}
+
+/**
+ * util_scan_scm_chan_to_band() - function to tell band for channel number
+ * @chan: Channel number
+ *
+ * Return: Band information as per channel
+ */
+enum wlan_band util_scan_scm_chan_to_band(uint32_t chan);
+
 #endif

+ 1 - 0
umac/scan/dispatcher/src/wlan_scan_ucfg_api.c

@@ -1173,6 +1173,7 @@ QDF_STATUS ucfg_scan_update_user_config(struct wlan_objmgr_psoc *psoc,
 	scan_def->adaptive_dwell_time_mode = scan_cfg->scan_dwell_time_mode;
 	scan_def->scan_f_chan_stat_evnt = scan_cfg->is_snr_monitoring_enabled;
 	scan_obj->ie_whitelist = scan_cfg->ie_whitelist;
+	scan_def->is_bssid_hint_priority = scan_cfg->is_bssid_hint_priority;
 
 	ucfg_scan_assign_rssi_category(scan_def,
 			scan_cfg->scan_bucket_threshold,

+ 166 - 3
umac/scan/dispatcher/src/wlan_scan_utils_api.c

@@ -100,7 +100,7 @@ util_get_last_scan_time(struct wlan_objmgr_vdev *vdev)
 	return scan_obj->pdev_info[pdev_id].last_scan_time;
 }
 
-static enum wlan_band scm_chan_to_band(uint32_t chan)
+enum wlan_band util_scan_scm_chan_to_band(uint32_t chan)
 {
 	if (WLAN_CHAN_IS_2GHZ(chan))
 		return WLAN_BAND_2_4_GHZ;
@@ -120,9 +120,9 @@ bool util_is_scan_entry_match(
 	if (entry1->cap_info.wlan_caps.ess &&
 	   !qdf_mem_cmp(entry1->bssid.bytes,
 	   entry2->bssid.bytes, QDF_MAC_ADDR_SIZE) &&
-	   scm_chan_to_band(
+	   util_scan_scm_chan_to_band(
 	   entry1->channel.chan_idx) ==
-	   scm_chan_to_band(entry2->channel.chan_idx)) {
+	   util_scan_scm_chan_to_band(entry2->channel.chan_idx)) {
 		/* Check for BSS */
 		if (util_is_ssid_match(
 		   &entry1->ssid, &entry2->ssid))
@@ -357,6 +357,9 @@ util_scan_parse_extn_ie(struct scan_cache_entry *scan_params,
 	case WLAN_EXTN_ELEMID_HEOP:
 		scan_params->ie_list.heop  = (uint8_t *)ie;
 		break;
+	case WLAN_EXTN_ELEMID_ESP:
+		scan_params->ie_list.esp = (uint8_t *)ie;
+		break;
 	default:
 		break;
 	}
@@ -557,6 +560,163 @@ util_scan_populate_bcn_ie_list(struct scan_cache_entry *scan_params)
 	return QDF_STATUS_SUCCESS;
 }
 
+/**
+ * util_scan_update_esp_data: update ESP params from beacon/probe response
+ * @esp_information: pointer to wlan_esp_information
+ * @scan_entry: new received entry
+ *
+ * The Estimated Service Parameters element is
+ * used by a AP to provide information to another STA which
+ * can then use the information as input to an algorithm to
+ * generate an estimate of throughput between the two STAs.
+ * The ESP Information List field contains from 1 to 4 ESP
+ * Information fields(each field 24 bits), each corresponding
+ * to an access category for which estimated service parameters
+ * information is provided.
+ *
+ * Return: None
+ */
+static void util_scan_update_esp_data(struct wlan_esp_ie *esp_information,
+		struct scan_cache_entry *scan_entry)
+{
+
+	uint8_t *data;
+	int i = 0;
+	int total_elements;
+	struct wlan_esp_info *esp_info;
+	struct wlan_esp_ie *esp_ie;
+
+	esp_ie = (struct wlan_esp_ie *)
+		util_scan_entry_esp_info(scan_entry);
+
+	total_elements  = esp_ie->esp_len;
+	data = (uint8_t *)esp_ie + 3;
+	do_div(total_elements, ESP_INFORMATION_LIST_LENGTH);
+
+	if (total_elements > MAX_ESP_INFORMATION_FIELD) {
+		scm_err("No of Air time fractions are greater than supported");
+		return;
+	}
+
+	for (i = 0; i < total_elements; i++) {
+		esp_info = (struct wlan_esp_info *)data;
+		if (esp_info->access_category == ESP_AC_BK) {
+			qdf_mem_copy(&esp_information->esp_info_AC_BK,
+					data, 3);
+			data = data + ESP_INFORMATION_LIST_LENGTH;
+			continue;
+		}
+		if (esp_info->access_category == ESP_AC_BE) {
+			qdf_mem_copy(&esp_information->esp_info_AC_BE,
+					data, 3);
+			data = data + ESP_INFORMATION_LIST_LENGTH;
+			continue;
+		}
+		if (esp_info->access_category == ESP_AC_VI) {
+			qdf_mem_copy(&esp_information->esp_info_AC_VI,
+					data, 3);
+			data = data + ESP_INFORMATION_LIST_LENGTH;
+			continue;
+		}
+		if (esp_info->access_category == ESP_AC_VO) {
+			qdf_mem_copy(&esp_information->esp_info_AC_VO,
+					data, 3);
+			data = data + ESP_INFORMATION_LIST_LENGTH;
+			break;
+		}
+	}
+}
+
+/**
+ * util_scan_scm_update_bss_with_esp_dataa: calculate estimated air time
+ * fraction
+ * @scan_entry: new received entry
+ *
+ * This function process all Access category ESP params and provide
+ * best effort air time fraction.
+ * If best effort is not available, it will choose VI, VO and BK in sequence
+ *
+ */
+static void util_scan_scm_update_bss_with_esp_data(
+		struct scan_cache_entry *scan_entry)
+{
+	uint8_t air_time_fraction = 0;
+	struct wlan_esp_ie esp_information;
+
+	if (!scan_entry->ie_list.esp)
+		return;
+
+	util_scan_update_esp_data(&esp_information, scan_entry);
+
+	/*
+	 * If the ESP metric is transmitting multiple airtime fractions, then
+	 * follow the sequence AC_BE, AC_VI, AC_VO, AC_BK and pick whichever is
+	 * the first one available
+	 */
+	if (esp_information.esp_info_AC_BE.access_category
+			== ESP_AC_BE)
+		air_time_fraction =
+			esp_information.esp_info_AC_BE.
+			estimated_air_fraction;
+	else if (esp_information.esp_info_AC_VI.access_category
+			== ESP_AC_VI)
+		air_time_fraction =
+			esp_information.esp_info_AC_VI.
+			estimated_air_fraction;
+	else if (esp_information.esp_info_AC_VO.access_category
+			== ESP_AC_VO)
+		air_time_fraction =
+			esp_information.esp_info_AC_VO.
+			estimated_air_fraction;
+	else if (esp_information.esp_info_AC_BK.access_category
+			== ESP_AC_BK)
+		air_time_fraction =
+			esp_information.esp_info_AC_BK.
+				estimated_air_fraction;
+	scan_entry->air_time_fraction = air_time_fraction;
+}
+
+/**
+ * util_scan_scm_calc_nss_supported_by_ap() - finds out nss from AP
+ * @scan_entry: new received entry
+ *
+ * Return: number of nss advertised by AP
+ */
+static int util_scan_scm_calc_nss_supported_by_ap(
+		struct scan_cache_entry *scan_params)
+{
+	struct htcap_cmn_ie *htcap;
+	struct wlan_ie_vhtcaps *vhtcaps;
+	uint8_t rx_mcs_map;
+
+	htcap = (struct htcap_cmn_ie *)
+		util_scan_entry_htcap(scan_params);
+	vhtcaps = (struct wlan_ie_vhtcaps *)
+		util_scan_entry_vhtcap(scan_params);
+	if (vhtcaps) {
+		rx_mcs_map = vhtcaps->rx_mcs_map;
+		if ((rx_mcs_map & 0xC0) != 0xC0)
+			return 4;
+
+		if ((rx_mcs_map & 0x30) != 0x30)
+			return 3;
+
+		if ((rx_mcs_map & 0x0C) != 0x0C)
+			return 2;
+	} else if (htcap) {
+		if (htcap->mcsset[3])
+			return 4;
+
+		if (htcap->mcsset[2])
+			return 3;
+
+		if (htcap->mcsset[1])
+			return 2;
+
+	}
+	return 1;
+}
+
 struct scan_cache_entry *
 util_scan_unpack_beacon_frame(uint8_t *frame,
 	qdf_size_t frame_len, uint32_t frm_subtype,
@@ -670,6 +830,9 @@ util_scan_unpack_beacon_frame(uint8_t *frame,
 	else
 		scan_entry->phy_mode = util_scan_get_phymode_2g(scan_entry);
 
+	scan_entry->nss = util_scan_scm_calc_nss_supported_by_ap(scan_entry);
+	util_scan_scm_update_bss_with_esp_data(scan_entry);
+
 	/* TODO calculate channel struct */
 	return scan_entry;
 }