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
diff --git a/umac/cmn_services/cmn_defs/inc/wlan_cmn_ieee80211.h b/umac/cmn_services/cmn_defs/inc/wlan_cmn_ieee80211.h
index da7c4da..c4da7a9 100644
--- a/umac/cmn_services/cmn_defs/inc/wlan_cmn_ieee80211.h
+++ b/umac/cmn_services/cmn_defs/inc/wlan_cmn_ieee80211.h
@@ -327,6 +327,7 @@
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
@@ -735,6 +736,65 @@
} 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
* @elem_len: VHT op IE len
@@ -765,6 +825,20 @@
} 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
* @beacon_interval: beacon interval
@@ -843,6 +917,84 @@
};
} 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
diff --git a/umac/scan/core/src/wlan_scan_cache_db.c b/umac/scan/core/src/wlan_scan_cache_db.c
index 31a1b00..ed29171 100644
--- a/umac/scan/core/src/wlan_scan_cache_db.c
+++ b/umac/scan/core/src/wlan_scan_cache_db.c
@@ -589,7 +589,6 @@
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 @@
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_create(tmp_list,
MAX_SCAN_CACHE_SIZE);
-
scm_age_out_entries(psoc, scan_db);
scm_get_results(psoc, scan_db, filter, tmp_list);
diff --git a/umac/scan/core/src/wlan_scan_cache_db.h b/umac/scan/core/src/wlan_scan_cache_db.h
index eea3898..c91a9c5 100644
--- a/umac/scan/core/src/wlan_scan_cache_db.h
+++ b/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
diff --git a/umac/scan/core/src/wlan_scan_cache_db_i.h b/umac/scan/core/src/wlan_scan_cache_db_i.h
index e013b91..a2a4a51 100644
--- a/umac/scan/core/src/wlan_scan_cache_db_i.h
+++ b/umac/scan/core/src/wlan_scan_cache_db_i.h
@@ -53,35 +53,6 @@
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_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 @@
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
diff --git a/umac/scan/core/src/wlan_scan_cache_db_ops.c b/umac/scan/core/src/wlan_scan_cache_db_ops.c
index 055bd56..ca2dbab 100644
--- a/umac/scan/core/src/wlan_scan_cache_db_ops.c
+++ b/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 = ¶ms->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->bss_score > bss2->bss_score)
+ ret = true;
+ else
+ ret = false;
+ return ret;
- if (bss1->prefer_value > bss2->prefer_value)
- return true;
+}
+int scm_calculate_bss_score(struct wlan_objmgr_psoc *psoc,
+ struct scan_default_params *params,
+ struct scan_cache_entry *entry,
+ int pcl_chan_weight)
+{
+ 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;
- 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;
+
+ scan_obj = wlan_psoc_get_scan_obj(psoc);
+ if (!scan_obj) {
+ scm_err("scan_obj is NULL");
+ return 0;
+ }
+ /*
+ * 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
+ */
+ /*
+ * 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 (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;
+ }
+ if (entry->rssi_raw >= EXCELLENT_RSSI) {
+ rssi_weight = EXCELLENT_RSSI_WEIGHT *
+ RSSI_WEIGHTAGE;
} else {
- ret = false;
+ 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;
+
+ }
+ 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 (pcl_score < 0)
+ pcl_score = 0;
+
+ score += pcl_score * BEST_CANDIDATE_MAX_WEIGHT;
+ }
+ /* 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;
+ }
+
+ /* 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;
+ }
+
+ /*
+ * 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 (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 {
- ret = false;
+ 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;
}
-
- 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)
-{
- uint32_t ret = 0;
- int modified_rssi;
-
- /*
- * The RSSI does not get modified in case the 5G
- * preference or preferred BSSID is not applicable
- */
- 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
- */
- 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 */
- }
- }
-
- return ret;
-}
-
-/**
- * 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;
-
- if (!entry)
- return QDF_STATUS_E_FAILURE;
-
- if (filter->num_of_bssid) {
- scm_info("filter has specific bssid, no point of boosting");
- return QDF_STATUS_SUCCESS;
- }
-
- 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);
- }
-
- 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);
-
- entry->prefer_value =
- scm_get_bss_prefer_value(params, entry);
-
- if (filter->num_of_pcl_channels)
- scm_calc_pref_val_by_pcl(params, filter, entry);
+ 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 @@
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;
+}
diff --git a/umac/scan/core/src/wlan_scan_main.h b/umac/scan/core/src/wlan_scan_main.h
index 8cf5081..59ad234 100644
--- a/umac/scan/core/src/wlan_scan_main.h
+++ b/umac/scan/core/src/wlan_scan_main.h
@@ -227,6 +227,7 @@
* @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 @@
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];
diff --git a/umac/scan/dispatcher/inc/wlan_scan_public_structs.h b/umac/scan/dispatcher/inc/wlan_scan_public_structs.h
index 41fb834..ae3ccf8 100644
--- a/umac/scan/dispatcher/inc/wlan_scan_public_structs.h
+++ b/umac/scan/dispatcher/inc/wlan_scan_public_structs.h
@@ -37,6 +37,7 @@
#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 @@
* @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 @@
uint8_t *heop;
uint8_t *srp;
uint8_t *fils_indication;
+ uint8_t *esp;
};
/**
@@ -236,6 +239,8 @@
* @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 @@
* @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 @@
} 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 @@
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 @@
* @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 @@
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 @@
* @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 @@
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;
};
/**
diff --git a/umac/scan/dispatcher/inc/wlan_scan_utils_api.h b/umac/scan/dispatcher/inc/wlan_scan_utils_api.h
index 5455692..0f9b3e1 100644
--- a/umac/scan/dispatcher/inc/wlan_scan_utils_api.h
+++ b/umac/scan/dispatcher/inc/wlan_scan_utils_api.h
@@ -651,6 +651,7 @@
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 @@
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
diff --git a/umac/scan/dispatcher/src/wlan_scan_ucfg_api.c b/umac/scan/dispatcher/src/wlan_scan_ucfg_api.c
index 3e3264a..1e077e5 100644
--- a/umac/scan/dispatcher/src/wlan_scan_ucfg_api.c
+++ b/umac/scan/dispatcher/src/wlan_scan_ucfg_api.c
@@ -1173,6 +1173,7 @@
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,
diff --git a/umac/scan/dispatcher/src/wlan_scan_utils_api.c b/umac/scan/dispatcher/src/wlan_scan_utils_api.c
index 34742d1..e06ec7c 100644
--- a/umac/scan/dispatcher/src/wlan_scan_utils_api.c
+++ b/umac/scan/dispatcher/src/wlan_scan_utils_api.c
@@ -100,7 +100,7 @@
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 @@
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 @@
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 @@
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 @@
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;
}