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 da7c4da08765..c4da7a94f2aa 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 @@ 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 diff --git a/umac/scan/core/src/wlan_scan_cache_db.c b/umac/scan/core/src/wlan_scan_cache_db.c index 31a1b001ba8d..ed291718885a 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 @@ 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); diff --git a/umac/scan/core/src/wlan_scan_cache_db.h b/umac/scan/core/src/wlan_scan_cache_db.h index eea3898f14b4..c91a9c5b5f73 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 e013b911803d..a2a4a51b0f88 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_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 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 055bd5681d86..ca2dbab85607 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 @@ 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; +} diff --git a/umac/scan/core/src/wlan_scan_main.h b/umac/scan/core/src/wlan_scan_main.h index 8cf508156853..59ad234440a7 100644 --- a/umac/scan/core/src/wlan_scan_main.h +++ b/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]; diff --git a/umac/scan/dispatcher/inc/wlan_scan_public_structs.h b/umac/scan/dispatcher/inc/wlan_scan_public_structs.h index 41fb834494bd..ae3ccf824d72 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 @@ 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; }; /** diff --git a/umac/scan/dispatcher/inc/wlan_scan_utils_api.h b/umac/scan/dispatcher/inc/wlan_scan_utils_api.h index 545569241d3e..0f9b3e1a8b66 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 @@ 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 diff --git a/umac/scan/dispatcher/src/wlan_scan_ucfg_api.c b/umac/scan/dispatcher/src/wlan_scan_ucfg_api.c index 3e3264a26efb..1e077e52c5df 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 @@ 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, diff --git a/umac/scan/dispatcher/src/wlan_scan_utils_api.c b/umac/scan/dispatcher/src/wlan_scan_utils_api.c index 34742d1f766e..e06ec7c54720 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 @@ 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; }