From 25d77b28e7ff2fadfc8fac5afc410cfcc2effea1 Mon Sep 17 00:00:00 2001 From: Srinivas Dasari Date: Wed, 7 Aug 2019 16:21:48 +0530 Subject: [PATCH] qcacld-3.0: Configure preferred freq list as dynamic chan list Configure the preferred channel list received from vendor roam subcmd command ROAMING_SUBCMD_CONTROL_SET as dynamic channel list to firmware. Combine this channel list with the existing occupied channel list and send to firmware. Flush this channel list as part of csr_cleanup Change-Id: Ibc45291f72844331096cb460257cab6f0b0095dc CRs-Fixed: 2507159 --- core/hdd/src/wlan_hdd_cfg80211.c | 139 ++++++++++++++++++++++++++++ core/sme/inc/csr_neighbor_roam.h | 1 + core/sme/inc/sme_api.h | 28 ++++++ core/sme/src/common/sme_api.c | 151 +++++++++++++++++++++++++++++++ core/sme/src/csr/csr_api_roam.c | 68 +++++++++++++- 5 files changed, 386 insertions(+), 1 deletion(-) diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c index eb581c47de3f..2d31d30ee877 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.c +++ b/core/hdd/src/wlan_hdd_cfg80211.c @@ -3730,6 +3730,16 @@ wlan_hdd_cfg80211_get_features(struct wiphy *wiphy, QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_ALERT_ROAM_RSSI_TRIGGER #define PARAM_ROAM_ENABLE \ QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_ENABLE +#define PARAM_ROAM_CONTROL_CONFIG \ + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_CONTROL +#define PARAM_FREQ_LIST_SCHEME \ + QCA_ATTR_ROAM_CONTROL_FREQ_LIST_SCHEME +#define PARAM_FREQ_LIST_SCHEME_MAX \ + QCA_ATTR_ROAM_CONTROL_SCAN_FREQ_LIST_SCHEME_MAX +#define PARAM_SCAN_FREQ_LIST \ + QCA_ATTR_ROAM_CONTROL_SCAN_FREQ_LIST +#define PARAM_SCAN_FREQ_LIST_TYPE \ + QCA_ATTR_ROAM_CONTROL_SCAN_FREQ_LIST_TYPE static const struct nla_policy @@ -3751,6 +3761,7 @@ wlan_hdd_set_roam_param_policy[MAX_ROAMING_PARAM + 1] = { [PARAM_ROAM_BSSID] = {.type = NLA_UNSPEC, .len = QDF_MAC_ADDR_SIZE}, [PARAM_SET_BSSID] = {.type = NLA_UNSPEC, .len = QDF_MAC_ADDR_SIZE}, [PARAM_SET_BSSID_HINT] = {.type = NLA_FLAG}, + [PARAM_ROAM_CONTROL_CONFIG] = {.type = NLA_NESTED}, }; /** @@ -4029,6 +4040,129 @@ fail: return -EINVAL; } +static const struct nla_policy +roam_scan_freq_list_scheme_policy[PARAM_FREQ_LIST_SCHEME_MAX + 1] = { + [PARAM_SCAN_FREQ_LIST_TYPE] = {.type = NLA_U32}, + [PARAM_SCAN_FREQ_LIST] = {.type = NLA_NESTED}, +}; + +/** + * hdd_send_roam_scan_channel_freq_list_to_sme() - Send control roam scan freqs + * @hdd_ctx: HDD context + * @vdev_id: vdev id + * @tb: Nested attribute carrying frequency list scheme + * + * Extracts the frequency list and frequency list type from the frequency + * list scheme and send the frequencies to SME. + * + * Return: QDF_STATUS + */ +static QDF_STATUS +hdd_send_roam_scan_channel_freq_list_to_sme(struct hdd_context *hdd_ctx, + uint8_t vdev_id, struct nlattr *tb) +{ + QDF_STATUS status; + struct nlattr *tb2[PARAM_FREQ_LIST_SCHEME_MAX + 1], *curr_attr; + uint8_t num_chan = 0; + uint32_t freq_list[SIR_MAX_SUPPORTED_CHANNEL_LIST] = {0}; + uint32_t list_type; + mac_handle_t mac_handle = hdd_ctx->mac_handle; + int rem; + + if (wlan_cfg80211_nla_parse_nested(tb2, PARAM_FREQ_LIST_SCHEME_MAX, + tb, + roam_scan_freq_list_scheme_policy)) { + hdd_err("nla_parse failed"); + return QDF_STATUS_E_INVAL; + } + + if (!tb2[PARAM_SCAN_FREQ_LIST] || !tb2[PARAM_SCAN_FREQ_LIST_TYPE]) { + hdd_err("ROAM_CONTROL_SCAN_FREQ_LIST or type are not present"); + return QDF_STATUS_E_INVAL; + } + + list_type = nla_get_u32(tb2[PARAM_SCAN_FREQ_LIST_TYPE]); + if (list_type != QCA_PREFERRED_SCAN_FREQ_LIST && + list_type != QCA_SPECIFIC_SCAN_FREQ_LIST) { + hdd_err("Invalid freq list type received: %u", list_type); + return QDF_STATUS_E_INVAL; + } + + nla_for_each_nested(curr_attr, tb2[PARAM_SCAN_FREQ_LIST], rem) + num_chan++; + if (num_chan > SIR_MAX_SUPPORTED_CHANNEL_LIST) { + hdd_err("number of channels (%d) supported exceeded max (%d)", + num_chan, SIR_MAX_SUPPORTED_CHANNEL_LIST); + return QDF_STATUS_E_INVAL; + } + num_chan = 0; + + nla_for_each_nested(curr_attr, tb2[PARAM_SCAN_FREQ_LIST], rem) + freq_list[num_chan++] = nla_get_u32(curr_attr); + + status = sme_update_roam_scan_freq_list(mac_handle, vdev_id, freq_list, + num_chan, list_type); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("Failed to update channel list information"); + + return status; +} + +static const struct nla_policy +roam_control_policy[QCA_ATTR_ROAM_CONTROL_MAX + 1] = { + [PARAM_FREQ_LIST_SCHEME] = {.type = NLA_NESTED}, +}; + +/** + * hdd_set_roam_with_control_config() - Set roam control configuration + * @hdd_ctx: HDD context + * @tb: List of attributes carrying roam subcmd data + * @vdev_id: vdev id + * + * Extracts the attribute PARAM_ROAM_CONTROL_CONFIG from the attributes list tb + * and sends the corresponding roam control configuration to driver/firmware. + * + * Return: 0 on success; error number on failure + */ +static int +hdd_set_roam_with_control_config(struct hdd_context *hdd_ctx, + struct nlattr **tb, + uint8_t vdev_id) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct nlattr *tb2[QCA_ATTR_ROAM_CONTROL_MAX + 1], *attr; + + /* The command must carry PARAM_ROAM_CONTROL_CONFIG */ + if (!tb[PARAM_ROAM_CONTROL_CONFIG]) { + hdd_err("Attribute CONTROL_CONFIG is not present"); + return -EINVAL; + } + + if (wlan_cfg80211_nla_parse_nested(tb2, QCA_ATTR_ROAM_CONTROL_MAX, + tb[PARAM_ROAM_CONTROL_CONFIG], + roam_control_policy)) { + hdd_err("nla_parse failed"); + return -EINVAL; + } + + attr = tb2[PARAM_FREQ_LIST_SCHEME]; + if (attr) { + status = hdd_send_roam_scan_channel_freq_list_to_sme(hdd_ctx, + vdev_id, + attr); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("failed to config roam control"); + } + + return qdf_status_to_os_return(status); +} + +#undef PARAM_ROAM_CONTROL_CONFIG +#undef PARAM_FREQ_LIST_SCHEME_MAX +#undef PARAM_FREQ_LIST_SCHEME +#undef PARAM_SCAN_FREQ_LIST +#undef PARAM_SCAN_FREQ_LIST_TYPE + /** * hdd_set_ext_roam_params() - parse ext roam params * @hdd_ctx: HDD context @@ -4168,6 +4302,11 @@ static int hdd_set_ext_roam_params(struct hdd_context *hdd_ctx, if (ret) goto fail; break; + case QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_SET: + ret = hdd_set_roam_with_control_config(hdd_ctx, tb, vdev_id); + if (ret) + goto fail; + break; } return 0; diff --git a/core/sme/inc/csr_neighbor_roam.h b/core/sme/inc/csr_neighbor_roam.h index 338f8e7f64b3..c1e3e2e5531c 100644 --- a/core/sme/inc/csr_neighbor_roam.h +++ b/core/sme/inc/csr_neighbor_roam.h @@ -63,6 +63,7 @@ typedef struct sCsrNeighborRoamCfgParams { uint32_t hi_rssi_scan_rssi_delta; uint32_t hi_rssi_scan_delay; int32_t hi_rssi_scan_rssi_ub; + tCsrChannelInfo pref_chan_info; } tCsrNeighborRoamCfgParams, *tpCsrNeighborRoamCfgParams; #define CSR_NEIGHBOR_ROAM_INVALID_CHANNEL_INDEX 255 diff --git a/core/sme/inc/sme_api.h b/core/sme/inc/sme_api.h index 0ce451cc4631..b6e7ad128f80 100644 --- a/core/sme/inc/sme_api.h +++ b/core/sme/inc/sme_api.h @@ -854,6 +854,24 @@ QDF_STATUS sme_change_roam_scan_channel_list(mac_handle_t mac_handle, uint8_t sessionId, uint8_t *pChannelList, uint8_t numChannels); + +/** + * sme_update_roam_scan_freq_list() - Update roam scan freq list + * @mac_handle: Opaque handle to the global MAC context + * @vdev_id: vdev identifier + * @freq_list: List of frequencies to be configured + * @num_channels: Number of frequencies to be configured + * @freq_list_type: Type of frequency list to be configured to + * + * Update the frequencies from freq_list to the corresponding channel list + * in neighborRoamInfo + * + * Return: QDF_STATUS + */ +QDF_STATUS +sme_update_roam_scan_freq_list(mac_handle_t mac_handle, uint8_t vdev_id, + uint32_t *freq_list, uint8_t num_chan, + uint32_t freq_list_type); QDF_STATUS sme_set_ese_roam_scan_channel_list(mac_handle_t mac_handle, uint8_t sessionId, uint8_t *pChannelList, @@ -862,6 +880,16 @@ QDF_STATUS sme_get_roam_scan_channel_list(mac_handle_t mac_handle, uint8_t *pChannelList, uint8_t *pNumChannels, uint8_t sessionId); +/** + * sme_dump_freq_list() - Dump the frequencies from given chan info + * @chan_info: Contains the frequency list and number of frequencies + * + * Extract number of frequencies and frequency list from chan_info and print + * to the logs. + * + * Return: None + */ +void sme_dump_freq_list(tCsrChannelInfo *chan_info); bool sme_get_is_ese_feature_enabled(mac_handle_t mac_handle); bool sme_get_wes_mode(mac_handle_t mac_handle); bool sme_get_roam_scan_control(mac_handle_t mac_handle); diff --git a/core/sme/src/common/sme_api.c b/core/sme/src/common/sme_api.c index e9336d40201a..8fbc0f1bee2c 100644 --- a/core/sme/src/common/sme_api.c +++ b/core/sme/src/common/sme_api.c @@ -7168,6 +7168,114 @@ uint8_t sme_get_roam_rssi_diff(mac_handle_t mac_handle) return mac->mlme_cfg->lfr.roam_rssi_diff; } +void sme_dump_freq_list(tCsrChannelInfo *chan_info) +{ + uint8_t *channel_list; + uint8_t i = 0, j = 0; + uint32_t buflen = CFG_VALID_CHANNEL_LIST_LEN * 4; + + channel_list = qdf_mem_malloc(buflen); + if (!channel_list) + return; + + if (chan_info->freq_list) { + for (i = 0; i < chan_info->numOfChannels; i++) { + if (j < buflen) + j += snprintf(channel_list + j, buflen - j, + "%d ", chan_info->freq_list[i]); + else + break; + } + } + + sme_debug("No.of frequencies: %u, frequency list: %s", i, channel_list); + qdf_mem_free(channel_list); +} + +static bool sme_validate_freq_list(mac_handle_t mac_handle, + uint32_t *freq_list, + uint8_t num_channels) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + uint8_t i = 0, j; + bool found; + struct csr_channel *ch_lst_info = &mac_ctx->scan.base_channels; + + if (!freq_list || !num_channels) { + sme_err("Freq list empty %pK or num_channels is 0", freq_list); + return false; + } + + while (i < num_channels) { + found = false; + for (j = 0; j < ch_lst_info->numChannels; j++) { + if (wlan_reg_chan_to_freq(mac_ctx->pdev, + ch_lst_info->channelList[j]) + == freq_list[i]) { + found = true; + break; + } + } + + if (!found) { + sme_debug("Invalid frequency %u", freq_list[i]); + return false; + } + + i++; + } + + return true; +} + +/** + * sme_update_roam_scan_channel_list() - to update scan channel list + * @mac_handle: Opaque handle to the global MAC context + * @vdev_id: vdev identifier + * @chan_info: Channel information to be updated to. + * @freq_list: Frequency list to be updated from. + * @num_chan: Number of channels + * + * Updates the chan_info by flushing the current frequency list and update + * the same with freq_list. + * + * Return: QDF_STATUS + */ +static QDF_STATUS +sme_update_roam_scan_channel_list(mac_handle_t mac_handle, uint8_t vdev_id, + tCsrChannelInfo *chan_info, + uint32_t *freq_list, uint8_t num_chan) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + uint8_t *channel_list; + + channel_list = qdf_mem_malloc(SIR_MAX_SUPPORTED_CHANNEL_LIST); + if (!channel_list) + return QDF_STATUS_E_NOMEM; + + if (chan_info->numOfChannels) { + sme_debug("Current channels:"); + sme_dump_freq_list(chan_info); + } + csr_flush_cfg_bg_scan_roam_channel_list(chan_info); + sme_freq_to_chan_list(mac->pdev, channel_list, freq_list, num_chan); + csr_create_bg_scan_roam_channel_list(mac, chan_info, channel_list, + num_chan); + sme_debug("New channels:"); + sme_dump_freq_list(chan_info); + sme_debug("Updated roam scan channels - roam state is %d", + mac->roam.neighborRoamInfo[vdev_id].neighborRoamState); + + if (mac->mlme_cfg->lfr.roam_scan_offload_enabled) + status = csr_roam_offload_scan(mac, vdev_id, + ROAM_SCAN_OFFLOAD_UPDATE_CFG, + REASON_CHANNEL_LIST_CHANGED); + qdf_mem_free(channel_list); + + return status; +} + /** * sme_change_roam_scan_channel_list() - to change scan channel list * @mac_handle: Opaque handle to the global MAC context @@ -7247,6 +7355,49 @@ QDF_STATUS sme_change_roam_scan_channel_list(mac_handle_t mac_handle, return status; } +QDF_STATUS +sme_update_roam_scan_freq_list(mac_handle_t mac_handle, uint8_t vdev_id, + uint32_t *freq_list, uint8_t num_chan, + uint32_t freq_list_type) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + QDF_STATUS status; + tpCsrNeighborRoamControlInfo neighbor_roam_info; + tCsrChannelInfo *channel_info; + + if (vdev_id >= WLAN_MAX_VDEVS) { + sme_err("Invalid vdev_id: %d", vdev_id); + return QDF_STATUS_E_INVAL; + } + + if (!sme_validate_freq_list(mac_handle, freq_list, num_chan)) { + sme_err("List contains invalid channel(s)"); + return QDF_STATUS_E_INVAL; + } + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_ERROR(status)) { + sme_err("Failed to acquire SME lock"); + return status; + } + + neighbor_roam_info = &mac->roam.neighborRoamInfo[vdev_id]; + if (freq_list_type == QCA_PREFERRED_SCAN_FREQ_LIST) { + sme_debug("Preferred frequency list: "); + channel_info = &neighbor_roam_info->cfgParams.pref_chan_info; + } else { + goto out; + } + + status = sme_update_roam_scan_channel_list(mac_handle, vdev_id, + channel_info, freq_list, + num_chan); +out: + sme_release_global_lock(&mac->sme); + + return status; +} + /** * sme_get_roam_scan_channel_list() - To get roam scan channel list * @mac_handle: Opaque handle to the global MAC context diff --git a/core/sme/src/csr/csr_api_roam.c b/core/sme/src/csr/csr_api_roam.c index 4f5dcb9ef4ac..3146844fafbc 100644 --- a/core/sme/src/csr/csr_api_roam.c +++ b/core/sme/src/csr/csr_api_roam.c @@ -1599,6 +1599,29 @@ void csr_flush_cfg_bg_scan_roam_channel_list(tCsrChannelInfo *channel_info) } } +/** + * csr_flush_roam_scan_chan_lists() - Flush the roam channel lists + * @mac: Global MAC context + * @vdev_id: vdev id + * + * Flush the roam channel lists pref_chan_info and specific_chan_info. + * + * Return: None + */ +static void +csr_flush_roam_scan_chan_lists(struct mac_context *mac, uint8_t vdev_id) +{ + tCsrChannelInfo *chan_info; + + chan_info = + &mac->roam.neighborRoamInfo[vdev_id].cfgParams.pref_chan_info; + csr_flush_cfg_bg_scan_roam_channel_list(chan_info); + + chan_info = + &mac->roam.neighborRoamInfo[vdev_id].cfgParams.specific_chan_info; + csr_flush_cfg_bg_scan_roam_channel_list(chan_info); +} + QDF_STATUS csr_create_bg_scan_roam_channel_list(struct mac_context *mac, tCsrChannelInfo *channel_info, const uint8_t *chan_list, @@ -17156,6 +17179,7 @@ void csr_cleanup_session(struct mac_context *mac, uint8_t vdev_id) csr_free_connect_bss_desc(mac, vdev_id); sme_reset_key(MAC_HANDLE(mac), vdev_id); csr_reset_cfg_privacy(mac); + csr_flush_roam_scan_chan_lists(mac, vdev_id); csr_roam_free_connect_profile(&pSession->connectedProfile); csr_roam_free_connected_info(mac, &pSession->connectedInfo); csr_roam_free_connected_info(mac, @@ -17971,6 +17995,40 @@ csr_fetch_valid_ch_lst(struct mac_context *mac_ctx, return status; } +/** + * csr_add_ch_lst_from_roam_scan_list() - channel from roam scan chan list + * parameters + * @mac_ctx: Global mac ctx + * @req_buf: out param, roam offload scan request packet + * @roam_info: roam info struct + * + * Return: QDF_STATUS + */ +static QDF_STATUS +csr_add_ch_lst_from_roam_scan_list(struct mac_context *mac_ctx, + struct roam_offload_scan_req *req_buf, + tpCsrNeighborRoamControlInfo roam_info) +{ + QDF_STATUS status; + tCsrChannelInfo *pref_chan_info = &roam_info->cfgParams.pref_chan_info; + + if (!pref_chan_info->numOfChannels) + return QDF_STATUS_SUCCESS; + + status = csr_populate_roam_chan_list(mac_ctx, + &req_buf->ConnectedNetwork, + pref_chan_info); + if (status != QDF_STATUS_SUCCESS) { + sme_err("Failed to copy channels to roam list"); + return status; + } + sme_debug("Added to roam chan list:"); + sme_dump_freq_list(pref_chan_info); + req_buf->ChannelCacheType = CHANNEL_LIST_DYNAMIC; + + return QDF_STATUS_SUCCESS; +} + /** * csr_create_roam_scan_offload_request() - init roam offload scan request * @@ -18136,7 +18194,8 @@ csr_create_roam_scan_offload_request(struct mac_context *mac_ctx, curr_ch_lst_info->numOfChannels == 0) { /* * Retrieve the Channel Cache either from ini or from - * the occupied channels list. + * the occupied channels list along with preferred + * channel list configured by the client. * Give Preference to INI Channels */ if (specific_chan_info->numOfChannels) { @@ -18154,6 +18213,13 @@ csr_create_roam_scan_offload_request(struct mac_context *mac_ctx, csr_fetch_ch_lst_from_occupied_lst(mac_ctx, session_id, reason, req_buf, roam_info); + /* Add the preferred channel list configured by + * client to the roam channel list along with + * occupied channel list. + */ + csr_add_ch_lst_from_roam_scan_list(mac_ctx, + req_buf, + roam_info); } } #ifdef FEATURE_WLAN_ESE