diff options
| -rw-r--r-- | core/cds/inc/cds_ieee80211_defines.h | 17 | ||||
| -rw-r--r-- | core/hdd/src/wlan_hdd_cfg80211.c | 481 | ||||
| -rw-r--r-- | core/hdd/src/wlan_hdd_cfg80211.h | 72 | ||||
| -rw-r--r-- | core/sme/inc/sme_api.h | 10 | ||||
| -rw-r--r-- | core/sme/src/common/sme_api.c | 16 | ||||
| -rw-r--r-- | core/sme/src/csr/csr_api_scan.c | 52 | ||||
| -rw-r--r-- | core/sme/src/csr/csr_inside_api.h | 11 |
7 files changed, 657 insertions, 2 deletions
diff --git a/core/cds/inc/cds_ieee80211_defines.h b/core/cds/inc/cds_ieee80211_defines.h index 037ad4295050..6845838b32b0 100644 --- a/core/cds/inc/cds_ieee80211_defines.h +++ b/core/cds/inc/cds_ieee80211_defines.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2014-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2011, 2014-2015, 2017 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -1371,4 +1371,19 @@ enum { IEEE80211_MACCMD_POLICY_RADIUS = 5, /* set policy: RADIUS managed ACLs */ }; +/* + * MBO transition reason codes + */ +enum { + MBO_TRANSITION_REASON_UNSPECIFIED, + MBO_TRANSITION_REASON_EXCESSIVE_FRAME_LOSS_RATE, + MBO_TRANSITION_REASON_EXCESSIVE_DELAY_FOR_CURRENT_TRAFFIC, + MBO_TRANSITION_REASON_INSUFFICIENT_BANDWIDTH_FOR_CURRENT_TRAFFIC, + MBO_TRANSITION_REASON_LOAD_BALANCING, + MBO_TRANSITION_REASON_LOW_RSSI, + MBO_TRANSITION_REASON_RECEIVED_EXCESSIVE_RETRANSMISSIONS, + MBO_TRANSITION_REASON_HIGH_INTERFERENCE, + MBO_TRANSITION_REASON_GRAY_ZONE, + MBO_TRANSITION_REASON_TRANSITIONING_TO_PREMIUM_AP, +}; #endif diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c index 10eefe7c3ae2..7c8bc6cd581c 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.c +++ b/core/hdd/src/wlan_hdd_cfg80211.c @@ -8908,6 +8908,478 @@ static inline bool wlan_hdd_is_bt_in_progress(hdd_context_t *hdd_ctx) return false; } +#ifdef FEATURE_WLAN_CH_AVOID +/** + * wlan_hdd_is_channel_to_avoid() - Check channel to avoid + * @hdd_ctx : HDD contex + * @channel_id : channel to check + * + * This fuction checks if channel is unsafe to use. Unsafe channel here are + * LTE-Coex channels. + * + * Return : true if channel is unsafe to use else false. + */ +static bool wlan_hdd_is_channel_to_avoid(hdd_context_t *hdd_ctx, + uint16_t channel_id) +{ + uint16_t cnt; + + for (cnt = 0; cnt < hdd_ctx->unsafe_channel_count; cnt++) + if (channel_id == hdd_ctx->unsafe_channel_list[cnt]) + return true; + + /* No matching channel */ + return false; +} +#else +static bool wlan_hdd_is_channel_to_avoid(hdd_context_t *hdd_ctx, + uint16_t channel_id) +{ + return false; +} +#endif + +/** + * wlan_hdd_is_mcc_channel() - check if using the channel results into MCC + * @adapter : pointer to adapter + * @channel : channel number to check for MCC scenario + * + * Return : true if channel causes MCC, else false + */ +static bool wlan_hdd_is_mcc_channel(hdd_adapter_t *adapter, uint8_t channel) +{ + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + hdd_adapter_list_node_t *adapter_node = NULL, *next = NULL; + hdd_adapter_t *p_adapter; + hdd_station_ctx_t *sta_ctx; + hdd_ap_ctx_t *ap_ctx; + hdd_hostapd_state_t *hostapd_state; + QDF_STATUS status; + uint8_t oper_channel = 0; + + if (channel == 0) + return false; + + status = hdd_get_front_adapter(hdd_ctx, &adapter_node); + while (QDF_STATUS_SUCCESS == status && NULL != adapter_node) { + p_adapter = adapter_node->pAdapter; + + if (p_adapter && p_adapter != adapter) { + if (QDF_STA_MODE == p_adapter->device_mode || + QDF_P2P_CLIENT_MODE == p_adapter->device_mode) { + sta_ctx = + WLAN_HDD_GET_STATION_CTX_PTR(p_adapter); + if (eConnectionState_Associated == + sta_ctx->conn_info.connState) + oper_channel = + sta_ctx->conn_info.operationChannel; + } else if (QDF_P2P_GO_MODE == p_adapter->device_mode || + QDF_SAP_MODE == p_adapter->device_mode) { + ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(p_adapter); + hostapd_state = + WLAN_HDD_GET_HOSTAP_STATE_PTR(p_adapter); + if (hostapd_state->bssState == BSS_START && + hostapd_state->qdf_status == + QDF_STATUS_SUCCESS) + oper_channel = ap_ctx->operatingChannel; + } + + if (oper_channel && channel != oper_channel && + (!wma_is_hw_dbs_capable() || + CDS_IS_SAME_BAND_CHANNELS(channel, oper_channel))) + return true; + } + + status = hdd_get_next_adapter(hdd_ctx, adapter_node, &next); + adapter_node = next; + } + + return false; +} + +/** + * wlan_hdd_get_status_for_candidate() - Get bss transition status for candidate + * @adapter : pointer to adapter + * @conn_bss_desc : connected bss descriptor + * @bss_desc : candidate bss descriptor + * @info : candiadate bss information + * @trans_reason : transition reason code + * + * Return : true if candidate is rejected and reject reason is filled + * @info->status. Otherwise returns false. + */ +static bool wlan_hdd_get_status_for_candidate(hdd_adapter_t *adapter, + tSirBssDescription *conn_bss_desc, + tSirBssDescription *bss_desc, + struct bss_candidate_info *info, + uint8_t trans_reason) +{ + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + /* Low RSSI based rejection + * If candidate rssi is less than mbo_candidate_rssi_thres and connected + * bss rssi is greater than mbo_current_rssi_thres, then reject the + * candidate with MBO reason code 4. + */ + if (bss_desc->rssi < hdd_ctx->config->mbo_candidate_rssi_thres && + conn_bss_desc->rssi > hdd_ctx->config->mbo_current_rssi_thres) { + hdd_err("Candidate BSS "MAC_ADDRESS_STR" has LOW RSSI(%d), hence reject", + MAC_ADDR_ARRAY(bss_desc->bssId), bss_desc->rssi); + info->status = QCA_STATUS_REJECT_LOW_RSSI; + return true; + } + + if (trans_reason == MBO_TRANSITION_REASON_LOAD_BALANCING || + trans_reason == MBO_TRANSITION_REASON_TRANSITIONING_TO_PREMIUM_AP) { + /* MCC rejection + * If moving to candidate's channel will result in MCC scenario + * and the rssi of connected bss is greater than + * mbo_current_rssi_mss_thres, then reject the candidate with + * MBO reason code 3. + */ + if ((conn_bss_desc->rssi > + hdd_ctx->config->mbo_current_rssi_mcc_thres) && + wlan_hdd_is_mcc_channel(adapter, bss_desc->channelId)) { + hdd_err("Candidate BSS "MAC_ADDRESS_STR" causes MCC, hence reject", + MAC_ADDR_ARRAY(bss_desc->bssId)); + info->status = + QCA_STATUS_REJECT_INSUFFICIENT_QOS_CAPACITY; + return true; + } + + /* BT coex rejection + * If AP is trying to move the client from 5G to 2.4G and moving + * to 2.4G will result in BT coex and candidate channel rssi is + * less than mbo_candidate_rssi_btc_thres, then reject the + * candidate with MBO reason code 2. + */ + if (CDS_IS_CHANNEL_5GHZ(conn_bss_desc->channelId) && + CDS_IS_CHANNEL_24GHZ(bss_desc->channelId) && + wlan_hdd_is_bt_in_progress(hdd_ctx) && + (bss_desc->rssi < + hdd_ctx->config->mbo_candidate_rssi_btc_thres)) { + hdd_err("Candidate BSS "MAC_ADDRESS_STR" causes BT coex, hence reject", + MAC_ADDR_ARRAY(bss_desc->bssId)); + info->status = + QCA_STATUS_REJECT_EXCESSIVE_DELAY_EXPECTED; + return true; + } + + /* LTE coex rejection + * If moving to candidate's channel can cause LTE coex, then + * reject the candidate with MBO reason code 5. + */ + if (!wlan_hdd_is_channel_to_avoid(hdd_ctx, + conn_bss_desc->channelId) && + wlan_hdd_is_channel_to_avoid(hdd_ctx, + bss_desc->channelId)) { + hdd_err("High interference expected if transitioned to BSS " + MAC_ADDRESS_STR" hence reject", + MAC_ADDR_ARRAY(bss_desc->bssId)); + info->status = + QCA_STATUS_REJECT_HIGH_INTERFERENCE; + return true; + } + } + + return false; +} + +/** + * wlan_hdd_get_bss_transition_status() - get bss transition status all + * cadidates + * @adapter : Pointer to adapter + * @transition_reason : Transition reason + * @info : bss candidate information + * @n_candidates : number of candidates + * + * Return : 0 on success otherwise errno + */ +static int wlan_hdd_get_bss_transition_status(hdd_adapter_t *adapter, + uint8_t transition_reason, + struct bss_candidate_info *info, + uint16_t n_candidates) +{ + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + hdd_station_ctx_t *hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + tSirBssDescription *bss_desc, *conn_bss_desc; + tCsrScanResultInfo *res, *conn_res; + uint16_t i; + + if (!n_candidates || !info) { + hdd_err("No candidate info available"); + return -EINVAL; + } + + /* Get the connected BSS descriptor */ + conn_res = sme_scan_get_result_for_bssid(hdd_ctx->hHal, + &hdd_sta_ctx->conn_info.bssId); + if (!conn_res) { + hdd_err("Failed to find connected BSS in scan list"); + return -EINVAL; + } + conn_bss_desc = &conn_res->BssDescriptor; + + for (i = 0; i < n_candidates; i++) { + /* Get candidate BSS descriptors */ + res = sme_scan_get_result_for_bssid(hdd_ctx->hHal, + &info[i].bssid); + if (!res) { + hdd_err("BSS "MAC_ADDRESS_STR" not present in scan list", + MAC_ADDR_ARRAY(info[i].bssid.bytes)); + info[i].status = QCA_STATUS_REJECT_UNKNOWN; + continue; + } + + bss_desc = &res->BssDescriptor; + + if (!wlan_hdd_get_status_for_candidate(adapter, conn_bss_desc, + bss_desc, &info[i], + transition_reason)) { + /* If status is not over written, it means it is a + * candidate for accept. + */ + info[i].status = QCA_STATUS_ACCEPT; + } + + qdf_mem_free(res->pvIes); + qdf_mem_free(res); + } + + /* free allocated memory */ + qdf_mem_free(conn_res->pvIes); + qdf_mem_free(conn_res); + + /* success */ + return 0; +} + +/** + * wlan_hdd_fill_btm_resp() - Fill bss candidate response buffer + * @reply_skb : pointer to reply_skb + * @info : bss candidate information + * @index : attribute type index for nla_next_start() + * + * Return : 0 on success and errno on failure + */ +static int wlan_hdd_fill_btm_resp(struct sk_buff *reply_skb, + struct bss_candidate_info *info, + int index) +{ + struct nlattr *attr; + + attr = nla_nest_start(reply_skb, index); + if (!attr) { + hdd_err("nla_nest_start failed"); + kfree_skb(reply_skb); + return -EINVAL; + } + + if (nla_put(reply_skb, + QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_BSSID, + ETH_ALEN, info->bssid.bytes) || + nla_put_u32(reply_skb, + QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_STATUS, + info->status)) { + hdd_err("nla_put failed"); + kfree_skb(reply_skb); + return -EINVAL; + } + + nla_nest_end(reply_skb, attr); + + return 0; +} + +/** + * __wlan_hdd_cfg80211_fetch_bss_transition_status () - fetch bss transition + * status + * @wiphy : WIPHY structure pointer + * @wdev : Wireless device structure pointer + * @data : Pointer to the data received + * @data_len : Length of the data received + * + * This fuction is used to fetch transition status for candidate bss. The + * transition status is either accept or reason for reject. + * + * Return : 0 on success and errno on failure + */ +static int __wlan_hdd_cfg80211_fetch_bss_transition_status(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_MAX + 1]; + struct nlattr *tb_msg[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_MAX + 1]; + uint8_t transition_reason; + struct nlattr *attr; + struct sk_buff *reply_skb; + int rem, j; + int ret; + struct bss_candidate_info candidate_info[MAX_CANDIDATE_INFO]; + uint16_t nof_candidates, i = 0; + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_station_ctx_t *hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + const struct nla_policy + btm_params_policy[QCA_WLAN_VENDOR_ATTR_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_BTM_MBO_TRANSITION_REASON] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO] = { + .type = NLA_NESTED}, + }; + const struct nla_policy + btm_cand_list_policy[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_MAX + 1] + = {[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_BSSID] = { + .len = QDF_MAC_ADDR_SIZE}, + [QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_STATUS] = { + .type = NLA_U32}, + }; + + ENTER(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + if (adapter->device_mode != QDF_STA_MODE || + hdd_sta_ctx->conn_info.connState != eConnectionState_Associated) { + hdd_err("Command is either not invoked for STA mode (device mode: %d)" + "or STA is not associated (Connection state: %d)", + adapter->device_mode, hdd_sta_ctx->conn_info.connState); + return -EINVAL; + } + + ret = nla_parse(tb, QCA_WLAN_VENDOR_ATTR_MAX, data, + data_len, btm_params_policy); + if (ret) { + hdd_err("Attribute parse failed"); + return -EINVAL; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_BTM_MBO_TRANSITION_REASON] || + !tb[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO]) { + hdd_err("Missing attributes"); + return -EINVAL; + } + + transition_reason = nla_get_u8( + tb[QCA_WLAN_VENDOR_ATTR_BTM_MBO_TRANSITION_REASON]); + + nla_for_each_nested(attr, + tb[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO], + rem) { + ret = nla_parse_nested( + tb_msg, + QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_MAX, + attr, btm_cand_list_policy); + if (ret) { + hdd_err("Attribute parse failed"); + return -EINVAL; + } + + if (!tb_msg[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_BSSID]) { + hdd_err("Missing BSSID attribute"); + return -EINVAL; + } + + qdf_mem_copy((void *)candidate_info[i].bssid.bytes, + nla_data(tb_msg[ + QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_BSSID]), + QDF_MAC_ADDR_SIZE); + i++; + if (i == MAX_CANDIDATE_INFO) + break; + } + + /* Determine status for each candidate and fill in the status field. + * Also arrange the candidates in the order of preference. + */ + nof_candidates = i; + + ret = wlan_hdd_get_bss_transition_status(adapter, transition_reason, + candidate_info, + nof_candidates); + if (ret) + return -EINVAL; + + /* Prepare the reply and send it to userspace */ + reply_skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, + ((QDF_MAC_ADDR_SIZE + sizeof(uint32_t)) * + nof_candidates) + NLMSG_HDRLEN); + if (!reply_skb) { + hdd_err("reply buffer alloc failed"); + return -ENOMEM; + } + + attr = nla_nest_start(reply_skb, + QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO); + if (!attr) { + hdd_err("nla_nest_start failed"); + kfree_skb(reply_skb); + return -EINVAL; + } + + /* Order candidates as - accepted candidate list followed by rejected + * candidate list + */ + for (i = 0, j = 0; i < nof_candidates; i++) { + /* copy accepted candidate list */ + if (candidate_info[i].status == QCA_STATUS_ACCEPT) { + if (wlan_hdd_fill_btm_resp(reply_skb, + &candidate_info[i], j)) + return -EINVAL; + j++; + } + } + for (i = 0; i < nof_candidates; i++) { + /* copy rejected candidate list */ + if (candidate_info[i].status != QCA_STATUS_ACCEPT) { + if (wlan_hdd_fill_btm_resp(reply_skb, + &candidate_info[i], j)) + return -EINVAL; + j++; + } + } + nla_nest_end(reply_skb, attr); + + EXIT(); + + return cfg80211_vendor_cmd_reply(reply_skb); +} + +/** + * __wlan_hdd_cfg80211_fetch_bss_transition_status () - fetch bss transition + * status + * @wiphy : WIPHY structure pointer + * @wdev : Wireless device structure pointer + * @data : Pointer to the data received + * @data_len : Length of the data received + * + * This fuction is used to fetch transition status for candidate bss. The + * transition status is either accept or reason for reject. + * + * Return : 0 on success and errno on failure + */ +static int wlan_hdd_cfg80211_fetch_bss_transition_status(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_fetch_bss_transition_status(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + const struct wiphy_vendor_command hdd_wiphy_vendor_commands[] = { { .info.vendor_id = QCA_NL80211_VENDOR_ID, @@ -9545,6 +10017,15 @@ const struct wiphy_vendor_command hdd_wiphy_vendor_commands[] = { WIPHY_VENDOR_CMD_NEED_RUNNING, .doit = wlan_hdd_cfg80211_get_nud_stats }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = + QCA_NL80211_VENDOR_SUBCMD_FETCH_BSS_TRANSITION_STATUS, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_fetch_bss_transition_status + }, }; /** diff --git a/core/hdd/src/wlan_hdd_cfg80211.h b/core/hdd/src/wlan_hdd_cfg80211.h index fac6d1df84a2..11da3be12dec 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.h +++ b/core/hdd/src/wlan_hdd_cfg80211.h @@ -148,6 +148,18 @@ static inline void wlan_hdd_clear_link_layer_stats(hdd_adapter_t *adapter) {} #define USE_CFG80211_DEL_STA_V2 #endif +#define MAX_CANDIDATE_INFO 10 +/** + * struct bss_candidate_info - Candidate bss information + * + * @bssid : BSSID of candidate bss + * @status : status code for candidate bss + */ +struct bss_candidate_info { + struct qdf_mac_addr bssid; + uint32_t status; +}; + /** * enum eDFS_CAC_STATUS: CAC status * @@ -308,6 +320,18 @@ typedef enum { * Start / Stop the NUD stats collections * @QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_GET * Get the NUD stats, represented by the enum qca_attr_nud_stats_get + * @QCA_NL80211_VENDOR_SUBCMD_FETCH_BSS_TRANSITION_STATUS: Sub-command to fetch + * the BSS transition status, whether accept or reject, for a list of + * candidate BSSIDs provided by the userspace. This uses the vendor + * attributes QCA_WLAN_VENDOR_ATTR_BTM_MBO_TRANSITION_REASON and + * QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO. The userspace shall specify + * the attributes QCA_WLAN_VENDOR_ATTR_BTM_MBO_TRANSITION_REASON and an + * array of QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_BSSID nested in + * QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO in the request. In the response + * the driver shall specify array of + * QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_BSSID and + * QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_STATUS pairs nested in + * QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO. */ enum qca_nl80211_vendor_subcmds { @@ -466,6 +490,9 @@ enum qca_nl80211_vendor_subcmds { QCA_NL80211_VENDOR_SUBCMD_SET_SAR_LIMITS = 146, QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_SET = 149, QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_GET = 150, + + /* Fetch BSS transition status */ + QCA_NL80211_VENDOR_SUBCMD_FETCH_BSS_TRANSITION_STATUS = 151, }; /** @@ -943,6 +970,18 @@ enum qca_wlan_vendor_attr_get_tdls_capabilities { * @QCA_WLAN_VENDOR_ATTR_FEATURE_FLAGS: Supported Features *@QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE: setband attribute which is used by * QCA_NL80211_VENDOR_SUBCMD_SETBAND + * @QCA_WLAN_VENDOR_ATTR_BTM_MBO_TRANSITION_REASON : Unsigned 8-bit value + * representing MBO transition reason code as provided by the AP used by + * subcommand QCA_NL80211_VENDOR_SUBCMD_FETCH_BSS_TRANSITION_STATUS. + * This is specified by the userspace in the request to the driver. + *@QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO : Array of nested attributes, BSSID + * and status code, used by subcommand + * QCA_NL80211_VENDOR_SUBCMD_FETCH_BSS_TRANSITION_STATUS, where each entry + * is taken from enum qca_wlan_vendor_attr_btm_candidate_info. The + * userspace space specifies the list/array of candidate BSSIDs in the + * order of preference in the request. The driver specifies the status + * code, for each BSSID in the list, in the response. The acceptable + * candidates are listed in the order preferred by the driver. * @QCA_WLAN_VENDOR_ATTR_AFTER_LAST: After last * @QCA_WLAN_VENDOR_ATTR_MAX: Max value */ @@ -960,6 +999,9 @@ enum qca_wlan_vendor_attr { QCA_WLAN_VENDOR_ATTR_MAX_CONCURRENT_CHANNELS_5_0_BAND = 11, QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE = 12, + QCA_WLAN_VENDOR_ATTR_BTM_MBO_TRANSITION_REASON = 36, + QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO = 37, + /* keep last */ QCA_WLAN_VENDOR_ATTR_AFTER_LAST, QCA_WLAN_VENDOR_ATTR_MAX = QCA_WLAN_VENDOR_ATTR_AFTER_LAST - 1 @@ -3419,6 +3461,36 @@ enum qca_wlan_vendor_attr_ll_stats_ext { QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_LAST - 1 }; +enum qca_wlan_btm_candidate_status { + QCA_STATUS_ACCEPT, + QCA_STATUS_REJECT_EXCESSIVE_FRAME_LOSS_EXPECTED, + QCA_STATUS_REJECT_EXCESSIVE_DELAY_EXPECTED, + QCA_STATUS_REJECT_INSUFFICIENT_QOS_CAPACITY, + QCA_STATUS_REJECT_LOW_RSSI, + QCA_STATUS_REJECT_HIGH_INTERFERENCE, + QCA_STATUS_REJECT_UNKNOWN, +}; + +enum qca_wlan_vendor_attr_btm_candidate_info { + QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_INVALID = 0, + + /* 6-byte MAC address representing the bssid of transition candidate */ + QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_BSSID = 1, + /* Unsigned 32-bit value from enum qca_wlan_btm_candidate_status + * returned by the driver. It says whether the bssid provided in + * QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_BSSID is acceptable by + * the driver, if not it specifies the reason for rejection. + * Note that the user-space can overwrite the transition reject reason + * codes provided by driver based on more information. + */ + QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_STATUS = 2, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_MAX = + QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_AFTER_LAST - 1, +}; + struct cfg80211_bss *wlan_hdd_cfg80211_update_bss_db(hdd_adapter_t *pAdapter, tCsrRoamInfo *pRoamInfo); diff --git a/core/sme/inc/sme_api.h b/core/sme/inc/sme_api.h index 313b3222d5eb..8eeb5aa02fae 100644 --- a/core/sme/inc/sme_api.h +++ b/core/sme/inc/sme_api.h @@ -1523,4 +1523,14 @@ void sme_set_5g_band_pref(tHalHandle hal_handle, QDF_STATUS sme_set_bt_activity_info_cb(tHalHandle hal, void (*cb)(void *, uint32_t profile_info)); +/** + * sme_scan_get_result_for_bssid - gets the scan result from scan cache for the + * bssid specified + * @hal: handle returned by mac_open + * @bssid: bssid to get the scan result for + * + * Return: tCsrScanResultInfo * or NULL if no result + */ +tCsrScanResultInfo *sme_scan_get_result_for_bssid(tHalHandle hal_handle, + struct qdf_mac_addr *bssid); #endif /* #if !defined( __SME_API_H ) */ diff --git a/core/sme/src/common/sme_api.c b/core/sme/src/common/sme_api.c index 10c8d8faa91c..73ff75d5ab78 100644 --- a/core/sme/src/common/sme_api.c +++ b/core/sme/src/common/sme_api.c @@ -3505,6 +3505,22 @@ QDF_STATUS sme_scan_get_result(tHalHandle hHal, uint8_t sessionId, return status; } +tCsrScanResultInfo *sme_scan_get_result_for_bssid(tHalHandle hal_handle, + struct qdf_mac_addr *bssid) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_handle); + QDF_STATUS status; + tCsrScanResultInfo *res = NULL; + + status = sme_acquire_global_lock(&mac_ctx->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + res = csr_scan_get_result_for_bssid(hal_handle, bssid); + sme_release_global_lock(&mac_ctx->sme); + } + + return res; +} + /** * sme_get_ap_channel_from_scan_cache() - a wrapper function to get AP's * channel id from CSR by filtering the diff --git a/core/sme/src/csr/csr_api_scan.c b/core/sme/src/csr/csr_api_scan.c index 6e7d914b762a..d4d05d226c47 100644 --- a/core/sme/src/csr/csr_api_scan.c +++ b/core/sme/src/csr/csr_api_scan.c @@ -2151,7 +2151,7 @@ QDF_STATUS csr_scan_get_result(tpAniSirGlobal pMac, pRetList->pCurEntry = NULL; status = csr_parse_scan_results(pMac, pFilter, pRetList, &count); sms_log(pMac, LOGD, FL("return %d BSS %d"), - csr_ll_count(&pRetList->List), status); + status, csr_ll_count(&pRetList->List)); if (!QDF_IS_STATUS_SUCCESS(status) || (phResult == NULL)) { /* Fail or No one wants the result. */ csr_scan_result_purge(pMac, (tScanResultHandle) pRetList); @@ -2168,6 +2168,56 @@ QDF_STATUS csr_scan_get_result(tpAniSirGlobal pMac, return status; } +tCsrScanResultInfo *csr_scan_get_result_for_bssid(tpAniSirGlobal mac_ctx, + struct qdf_mac_addr *bssid) +{ + tDblLinkList *list = &mac_ctx->scan.scanResultList; + tListElem *entry; + tCsrScanResultInfo *scan_info = NULL; + tCsrScanResult *scan_res; + size_t bss_len, len; + tDot11fBeaconIEs *ies = NULL; + QDF_STATUS status; + + csr_ll_lock(list); + entry = csr_ll_peek_head(list, LL_ACCESS_NOLOCK); + while (entry) { + scan_res = GET_BASE_ADDR(entry, tCsrScanResult, Link); + if (qdf_mem_cmp(scan_res->Result.BssDescriptor.bssId, + bssid->bytes, QDF_MAC_ADDR_SIZE) == 0) { + /* Found matching scan resut for this bssid */ + bss_len = scan_res->Result.BssDescriptor.length + + sizeof(scan_res->Result.BssDescriptor.length); + len = sizeof(*scan_info) + bss_len; + scan_info = qdf_mem_malloc(len); + if (!scan_info) { + sms_log(mac_ctx, LOGE, + FL("Failed to allocate memory for scan info, len = %lu"), + len); + break; + } + scan_info->ssId = scan_res->Result.ssId; + scan_info->timer = scan_res->Result.timer; + qdf_mem_copy(&scan_info->BssDescriptor, + &scan_res->Result.BssDescriptor, bss_len); + status = csr_get_parsed_bss_description_ies( + mac_ctx, + &scan_info->BssDescriptor, + &ies); + if (QDF_IS_STATUS_ERROR(status)) { + qdf_mem_free(scan_info); + scan_info = NULL; + } + scan_info->pvIes = ies; + break; + } + entry = csr_ll_next(list, entry, LL_ACCESS_NOLOCK); + } + csr_ll_unlock(list); + + return scan_info; +} + /* * NOTE: This routine is being added to make * sure that scan results are not being flushed diff --git a/core/sme/src/csr/csr_inside_api.h b/core/sme/src/csr/csr_inside_api.h index d1610e87edbf..fb5c08356dce 100644 --- a/core/sme/src/csr/csr_inside_api.h +++ b/core/sme/src/csr/csr_inside_api.h @@ -539,6 +539,17 @@ QDF_STATUS csrScanAbort(tpAniSirGlobal, uint32_t scanRequestID); QDF_STATUS csr_scan_get_result(tpAniSirGlobal, tCsrScanResultFilter *pFilter, tScanResultHandle *phResult); +/** + * csr_scan_get_result_for_bssid - gets the scan result from scan cache for the + * bssid specified + * @mac_ctx: mac context + * @bssid: bssid to get the scan result for + * + * Return: tCsrScanResultInfo * or NULL if no result + */ +tCsrScanResultInfo *csr_scan_get_result_for_bssid(tpAniSirGlobal mac_ctx, + struct qdf_mac_addr *bssid); + /* --------------------------------------------------------------------------- \fn csr_scan_flush_result \brief Clear scan results. |
