diff --git a/components/mlme/dispatcher/inc/wlan_mlme_api.h b/components/mlme/dispatcher/inc/wlan_mlme_api.h index f2ac5dddc3..4ac879d6ad 100644 --- a/components/mlme/dispatcher/inc/wlan_mlme_api.h +++ b/components/mlme/dispatcher/inc/wlan_mlme_api.h @@ -3433,4 +3433,18 @@ wlan_mlme_get_tx_retry_multiplier(struct wlan_objmgr_psoc *psoc, QDF_STATUS wlan_mlme_get_channel_bonding_5ghz(struct wlan_objmgr_psoc *psoc, uint32_t *value); + +/** + * wlan_mlme_update_ratemask_params() - Update ratemask params + * + * @vdev: pointer to vdev object + * @num_ratemask: number of rate masks + * @rate_params: pointer to ratemask structure + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_update_ratemask_params(struct wlan_objmgr_vdev *vdev, + uint8_t num_ratemask, + struct config_ratemask_params *rate_params); #endif /* _WLAN_MLME_API_H_ */ diff --git a/components/mlme/dispatcher/inc/wlan_mlme_ucfg_api.h b/components/mlme/dispatcher/inc/wlan_mlme_ucfg_api.h index 8eafc4ae90..2025a76f5a 100644 --- a/components/mlme/dispatcher/inc/wlan_mlme_ucfg_api.h +++ b/components/mlme/dispatcher/inc/wlan_mlme_ucfg_api.h @@ -4417,4 +4417,22 @@ bool ucfg_mlme_get_coex_unsafe_chan_reg_disable( return false; } #endif + +/** + * ucfg_set_ratemask_params() - Set ratemask config + * @vdev: pointer to vdev object + * @num_ratemask: number of ratemask params + * @rate_params: ratemask params + * + * Return: QDF_STATUS + */ + +static inline QDF_STATUS +ucfg_set_ratemask_params(struct wlan_objmgr_vdev *vdev, + uint8_t num_ratemask, + struct config_ratemask_params *rate_params) +{ + return wlan_mlme_update_ratemask_params(vdev, num_ratemask, + rate_params); +} #endif /* _WLAN_MLME_UCFG_API_H_ */ diff --git a/components/mlme/dispatcher/src/wlan_mlme_api.c b/components/mlme/dispatcher/src/wlan_mlme_api.c index 91e60ad48e..05b743aae8 100644 --- a/components/mlme/dispatcher/src/wlan_mlme_api.c +++ b/components/mlme/dispatcher/src/wlan_mlme_api.c @@ -30,6 +30,7 @@ #include "wlan_crypto_global_api.h" #include "wlan_utility.h" #include "wlan_policy_mgr_ucfg.h" +#include "wlan_vdev_mgr_utils_api.h" /* quota in milliseconds */ #define MCC_DUTY_CYCLE 70 @@ -5389,5 +5390,58 @@ wlan_mlme_get_channel_bonding_5ghz(struct wlan_objmgr_psoc *psoc, } *value = mlme_obj->cfg.feature_flags.channel_bonding_mode_5ghz; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_update_ratemask_params(struct wlan_objmgr_vdev *vdev, + uint8_t num_ratemask, + struct config_ratemask_params *rate_params) +{ + struct vdev_mlme_obj *vdev_mlme; + struct vdev_mlme_rate_info *rate_info; + QDF_STATUS ret; + uint8_t i = 0; + uint8_t index; + + vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev); + if (!vdev_mlme) + return QDF_STATUS_E_FAILURE; + + rate_info = &vdev_mlme->mgmt.rate_info; + while (i < num_ratemask) { + index = rate_params[i].type; + if (index >= WLAN_VDEV_RATEMASK_TYPE_MAX) { + mlme_legacy_err("Invalid ratemask type"); + ++i; + continue; + } + + if (rate_info->ratemask_params[index].lower32 != + rate_params[i].lower32 || + rate_info->ratemask_params[index].lower32_2 != + rate_params[i].lower32_2 || + rate_info->ratemask_params[index].higher32 != + rate_params[i].higher32 || + rate_info->ratemask_params[index].higher32_2 != + rate_params[i].higher32_2) { + rate_info->ratemask_params[index].lower32 = + rate_params[i].lower32; + rate_info->ratemask_params[index].higher32 = + rate_params[i].higher32; + rate_info->ratemask_params[index].lower32_2 = + rate_params[i].lower32_2; + rate_info->ratemask_params[index].higher32_2 = + rate_params[i].higher32_2; + ret = wlan_util_vdev_mlme_set_ratemask_config(vdev_mlme, + index); + if (ret != QDF_STATUS_SUCCESS) + mlme_legacy_err("ratemask config failed"); + } else { + mlme_legacy_debug("Ratemask same as configured mask"); + } + ++i; + } return QDF_STATUS_SUCCESS; } diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c index 9913d678bb..87d4ada4b4 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.c +++ b/core/hdd/src/wlan_hdd_cfg80211.c @@ -6041,6 +6041,189 @@ wlan_hdd_cfg80211_set_ext_roam_params(struct wiphy *wiphy, return errno; } +#define RATEMASK_PARAMS_TYPE_MAX 4 +#define RATEMASK_PARAMS_MAX QCA_WLAN_VENDOR_ATTR_RATEMASK_PARAMS_MAX +const struct nla_policy wlan_hdd_set_ratemask_param_policy[ + RATEMASK_PARAMS_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_RATEMASK_PARAMS_LIST] = + VENDOR_NLA_POLICY_NESTED(wlan_hdd_set_ratemask_param_policy), + [QCA_WLAN_VENDOR_ATTR_RATEMASK_PARAMS_TYPE] = {.type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_RATEMASK_PARAMS_BITMAP] = {.type = NLA_BINARY, + .len = 128}, +}; + +/** + * hdd_set_ratemask_params() - parse ratemask params + * @hdd_ctx: HDD context + * @tb: list of attributes + * @vdev_id: vdev id + * + * Return: 0 on success; error number on failure + */ +static int hdd_set_ratemask_params(struct hdd_context *hdd_ctx, + const void *data, int data_len, + struct wlan_objmgr_vdev *vdev) +{ + struct nlattr *tb[RATEMASK_PARAMS_MAX + 1]; + struct nlattr *tb2[RATEMASK_PARAMS_MAX + 1]; + struct nlattr *curr_attr; + int ret, rem; + struct config_ratemask_params rate_params[RATEMASK_PARAMS_TYPE_MAX]; + uint8_t ratemask_type, num_ratemask = 0, len; + uint32_t bitmap[RATEMASK_PARAMS_TYPE_MAX] = {0}; + + ret = wlan_cfg80211_nla_parse(tb, + RATEMASK_PARAMS_MAX, + data, data_len, + wlan_hdd_set_ratemask_param_policy); + if (ret) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_RATEMASK_PARAMS_LIST]) { + hdd_err("ratemask array attribute not present"); + return -EINVAL; + } + + memset(rate_params, 0, (RATEMASK_PARAMS_TYPE_MAX * + sizeof(struct config_ratemask_params))); + + nla_for_each_nested(curr_attr, + tb[QCA_WLAN_VENDOR_ATTR_RATEMASK_PARAMS_LIST], + rem) { + if (num_ratemask >= RATEMASK_PARAMS_TYPE_MAX) { + hdd_err("Exceeding ratemask_list_param_num value"); + return -EINVAL; + } + + if (wlan_cfg80211_nla_parse( + tb2, RATEMASK_PARAMS_MAX, + nla_data(curr_attr), nla_len(curr_attr), + wlan_hdd_set_ratemask_param_policy)) { + hdd_err("nla_parse failed"); + return -EINVAL; + } + + if (!tb2[QCA_WLAN_VENDOR_ATTR_RATEMASK_PARAMS_TYPE]) { + hdd_err("type attribute not present"); + return -EINVAL; + } + + if (!tb2[QCA_WLAN_VENDOR_ATTR_RATEMASK_PARAMS_BITMAP]) { + hdd_err("bitmap attribute not present"); + return -EINVAL; + } + + ratemask_type = + nla_get_u8(tb2[QCA_WLAN_VENDOR_ATTR_RATEMASK_PARAMS_TYPE]); + if (ratemask_type >= RATEMASK_PARAMS_TYPE_MAX) { + hdd_err("invalid ratemask type"); + return -EINVAL; + } + + len = nla_len(tb2[QCA_WLAN_VENDOR_ATTR_RATEMASK_PARAMS_BITMAP]); + nla_memcpy((void *)bitmap, + tb2[QCA_WLAN_VENDOR_ATTR_RATEMASK_PARAMS_BITMAP], + len); + + hdd_debug("rate_type:%d, lower32 0x%x, lower32_2 0x%x, higher32 0x%x, higher32_2 0x%x", + ratemask_type, bitmap[0], bitmap[1], + bitmap[2], bitmap[3]); + + rate_params[num_ratemask].type = ratemask_type; + rate_params[num_ratemask].lower32 = bitmap[0]; + rate_params[num_ratemask].lower32_2 = bitmap[1]; + rate_params[num_ratemask].higher32 = bitmap[2]; + rate_params[num_ratemask].higher32_2 = bitmap[3]; + + num_ratemask += 1; + } + + ret = ucfg_set_ratemask_params(vdev, num_ratemask, rate_params); + if (ret) + hdd_err("ucfg_set_ratemask_params failed"); + return ret; +} + +/** + * __wlan_hdd_cfg80211_set_ratemask_config() - Ratemask parameters + * @wiphy: The wiphy structure + * @wdev: The wireless device + * @data: Data passed by framework + * @data_len: Parameters to be configured passed as data + * + * The ratemask parameters are configured by the framework + * using this interface. + * + * Return: Return either success or failure code. + */ +static int +__wlan_hdd_cfg80211_set_ratemask_config(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct wlan_objmgr_vdev *vdev; + int ret; + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + if (hdd_ctx->driver_status == DRIVER_MODULES_CLOSED) { + hdd_err("Driver Modules are closed"); + return -EINVAL; + } + + vdev = hdd_objmgr_get_vdev_by_user(adapter, WLAN_OSIF_POWER_ID); + if (!vdev) { + hdd_err("vdev not present"); + return -EINVAL; + } + + ret = hdd_set_ratemask_params(hdd_ctx, data, data_len, vdev); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_POWER_ID); + if (ret) + goto fail; + + return 0; +fail: + return ret; +} + +/** + * wlan_hdd_cfg80211_set_ratemask_config() - set ratemask config + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * + * Return: Return the Success or Failure code. + */ +static int +wlan_hdd_cfg80211_set_ratemask_config(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_set_ratemask_config(wiphy, wdev, + data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + #define PWR_SAVE_FAIL_CMD_INDEX \ QCA_NL80211_VENDOR_SUBCMD_PWR_SAVE_FAIL_DETECTED_INDEX @@ -17121,6 +17304,16 @@ const struct wiphy_vendor_command hdd_wiphy_vendor_commands[] = { vendor_command_policy(wlan_hdd_set_roam_param_policy, QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_MAX) }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_RATEMASK_CONFIG, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_set_ratemask_config, + vendor_command_policy(wlan_hdd_set_ratemask_param_policy, + QCA_WLAN_VENDOR_ATTR_RATEMASK_PARAMS_MAX) + }, { .info.vendor_id = QCA_NL80211_VENDOR_ID, .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_WIFI_LOGGER_START,