Merge 85f79a60c6e6429f9ee6550d2894e050dc052c2d on remote branch
Change-Id: I38b542b53e12ce6715e951ff7eb04f1c7ab9a145
diff --git a/qcwcn/wpa_supplicant_8_lib/driver_cmd_nl80211.c b/qcwcn/wpa_supplicant_8_lib/driver_cmd_nl80211.c
index e599c80..f95a8fb 100644
--- a/qcwcn/wpa_supplicant_8_lib/driver_cmd_nl80211.c
+++ b/qcwcn/wpa_supplicant_8_lib/driver_cmd_nl80211.c
@@ -182,6 +182,10 @@
#define TWT_RESUME_RESP_LEN strlen(TWT_RESUME_RESP)
#define TWT_NOTIFY_RESP_LEN strlen(TWT_NOTIFY_RESP)
+#define OPM_MODE_DISABLE 0
+#define OPM_MODE_ENABLE 1
+#define OPM_MODE_USER_DEFINED 2
+
static int twt_async_support = -1;
struct twt_setup_parameters {
@@ -2689,31 +2693,35 @@
static u64 get_u64_from_string(char *cmd_string, int *ret)
{
- u64 val = 0;
+ long long val = 0;
+ char *endptr = NULL;
*ret = 0;
errno = 0;
- val = strtoll(cmd_string, NULL, 10);
- if (errno == ERANGE || (errno != 0 && val == 0)) {
+ val = strtoll(cmd_string, &endptr, 10);
+ if (errno == ERANGE || (errno != 0 && val == 0) ||
+ *cmd_string == *endptr || val < 0) {
wpa_printf(MSG_ERROR, "invalid value");
*ret = -EINVAL;
- }
- return val;
+ }
+ return (u64)val;
}
static u32 get_u32_from_string(char *cmd_string, int *ret)
{
- u32 val = 0;
+ long val = 0;
+ char *endptr = NULL;
*ret = 0;
errno = 0;
- val = strtol(cmd_string, NULL, 10);
- if (errno == ERANGE || (errno != 0 && val == 0)) {
+ val = strtol(cmd_string, &endptr, 10);
+ if (errno == ERANGE || (errno != 0 && val == 0) ||
+ *cmd_string == *endptr || val < 0) {
wpa_printf(MSG_ERROR, "invalid value");
*ret = -EINVAL;
- }
- return val;
+ }
+ return (u32)val;
}
static s32 get_s32_from_string(char *cmd_string, int *ret)
@@ -2739,16 +2747,34 @@
static u8 get_u8_from_string(char *cmd_string, int *ret)
{
- u8 val = 0;
+ long val = 0;
+ char *endptr = NULL;
*ret = 0;
errno = 0;
- val = strtol(cmd_string, NULL, 10) & 0xFF;
- if (errno == ERANGE || (errno != 0 && val == 0)) {
+ val = strtol(cmd_string, &endptr, 10);
+ if (errno == ERANGE || (errno != 0 && val == 0) ||
+ *cmd_string == *endptr || val < 0) {
wpa_printf(MSG_ERROR, "invalid value");
*ret = -EINVAL;
- }
- return val;
+ }
+ return (u8)(val & 0xFF);
+}
+
+static u16 get_u16_from_string(char *cmd_string, int *ret)
+{
+ long val = 0;
+ char *endptr = NULL;
+
+ *ret = 0;
+ errno = 0;
+ val = strtol(cmd_string, &endptr, 10);
+ if (errno == ERANGE || (errno != 0 && val == 0) ||
+ *cmd_string == *endptr || val < 0) {
+ wpa_printf(MSG_ERROR, "Invalid input to get u16 value");
+ *ret = -EINVAL;
+ }
+ return (u16)(val & 0xFFFF);
}
char *move_to_next_str(char *cmd)
@@ -6401,6 +6427,116 @@
return ret;
}
+static uint8_t wpa_driver_convert_opm_mode(uint8_t opm_mode)
+{
+ switch (opm_mode) {
+ case 0:
+ return QCA_WLAN_VENDOR_OPM_MODE_DISABLE;
+ case 1:
+ return QCA_WLAN_VENDOR_OPM_MODE_ENABLE;
+ case 2:
+ return QCA_WLAN_VENDOR_OPM_MODE_USER_DEFINED;
+ default:
+ return opm_mode;
+ }
+}
+
+static int wpa_driver_ps_config_cmd(struct i802_bss *bss, char *cmd)
+{
+ struct wpa_driver_nl80211_data *drv;
+ struct nl_msg *nlmsg;
+ struct nlattr *attr;
+ u8 opm_mode;
+ u16 ps_ito, spec_wake;
+ int ret;
+
+ drv = bss->drv;
+ cmd = skip_white_space(cmd);
+ if (*cmd == '\0') {
+ wpa_printf(MSG_ERROR, "mode and config values are missing");
+ return -EINVAL;
+ }
+ opm_mode = get_u8_from_string(cmd, &ret);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR, "ps_config: Invalid opm_mode");
+ return -EINVAL;
+ }
+
+ if (opm_mode == OPM_MODE_USER_DEFINED) {
+ cmd = move_to_next_str(cmd);
+ if (*cmd == '\0') {
+ wpa_printf(MSG_ERROR, "ps_ito is missing in command");
+ return -EINVAL;
+ }
+ ps_ito = get_u16_from_string(cmd, &ret);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR, "Invalid ps_ito value");
+ return -EINVAL;
+ }
+ cmd = move_to_next_str(cmd);
+ if (*cmd == '\0') {
+ wpa_printf(MSG_ERROR,
+ "spec_wake is missing in command");
+ return -EINVAL;
+ }
+ spec_wake = get_u16_from_string(cmd, &ret);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR, "Invalid spec_wake value");
+ return -EINVAL;
+ }
+ }
+
+ nlmsg = prepare_vendor_nlmsg(drv, bss->ifname,
+ QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION);
+ if (!nlmsg) {
+ wpa_printf(MSG_ERROR,
+ "Failed to allocate nlmsg for set_opm_mode cmd");
+ return -ENOMEM;
+ }
+
+ attr = nla_nest_start(nlmsg, NL80211_ATTR_VENDOR_DATA);
+ if (!attr) {
+ ret = -ENOMEM;
+ wpa_printf(MSG_ERROR,
+ "Failed to create nl attr for set_opm_mode cmd");
+ goto nlmsg_fail;
+ }
+ if (nla_put_u8(nlmsg,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_OPTIMIZED_POWER_MANAGEMENT,
+ wpa_driver_convert_opm_mode(opm_mode))) {
+ ret = -ENOMEM;
+ wpa_printf(MSG_ERROR, "Failed to put power_save_mode value");
+ goto nlmsg_fail;
+ }
+ if (opm_mode == OPM_MODE_USER_DEFINED) {
+ if (nla_put_u16(nlmsg, QCA_WLAN_VENDOR_ATTR_CONFIG_OPM_ITO,
+ ps_ito)) {
+ ret = -ENOMEM;
+ wpa_printf(MSG_ERROR, "Failed to put ps_ito value");
+ goto nlmsg_fail;
+ }
+ if (nla_put_u16(nlmsg,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_OPM_SPEC_WAKE_INTERVAL,
+ spec_wake)) {
+ ret = -ENOMEM;
+ wpa_printf(MSG_ERROR, "Failed to put spec_wake value");
+ goto nlmsg_fail;
+ }
+ }
+ nla_nest_end(nlmsg, attr);
+
+ ret = send_nlmsg((struct nl_sock *)drv->global->nl, nlmsg, NULL, NULL);
+ if (ret) {
+ wpa_printf(MSG_ERROR,
+ "Failed to send set_opm_mode nlmsg, error:%d", ret);
+ return ret;
+ }
+ return 0;
+nlmsg_fail:
+ nlmsg_free(nlmsg);
+ return ret;
+}
+
int wpa_driver_nl80211_driver_cmd(void *priv, char *cmd, char *buf,
size_t buf_len )
{
@@ -6750,6 +6886,17 @@
*/
cmd += 17;
return wpa_driver_set_ul_mu_cfg(bss, cmd);
+ } else if (os_strncasecmp(cmd, "SET_PS_CONFIG ", 14) == 0) {
+ /* DRIVER SET_PS_CONFIG <opm_mode> <ps_ito> <spec_wake>
+ * opm_mode - Optimized power management Mode
+ * value 0 - Disable OPM
+ * value 1 - Enable OPM
+ * value 2 - User defined OPM
+ * ps_ito - Power save inactivity timeout
+ * spec_wake - Speculative wake interval
+ */
+ cmd += 14;
+ return wpa_driver_ps_config_cmd(bss, cmd);
} else { /* Use private command */
memset(&ifr, 0, sizeof(ifr));
memset(&priv_cmd, 0, sizeof(priv_cmd));
diff --git a/qcwcn/wpa_supplicant_8_lib/qca-vendor_copy.h b/qcwcn/wpa_supplicant_8_lib/qca-vendor_copy.h
index b776082..aade3ae 100644
--- a/qcwcn/wpa_supplicant_8_lib/qca-vendor_copy.h
+++ b/qcwcn/wpa_supplicant_8_lib/qca-vendor_copy.h
@@ -2833,8 +2833,13 @@
* configure the asymmetric NSS configuration (such as 1X2).
*/
QCA_WLAN_VENDOR_ATTR_CONFIG_NSS = 70,
- /* 8-bit unsigned value to trigger Optimized Power Management:
- * 1-Enable, 0-Disable
+ /* 8-bit unsigned value to configure Optimized Power Management mode:
+ * Modes are defined by enum qca_wlan_vendor_opm_mode.
+ *
+ * This attribute shall be configured along with
+ * %QCA_WLAN_VENDOR_ATTR_CONFIG_OPM_ITO and
+ * %QCA_WLAN_VENDOR_ATTR_CONFIG_OPM_SPEC_WAKE_INTERVAL attributes
+ * when its value is set to %QCA_WLAN_VENDOR_OPM_MODE_USER_DEFINED.
*/
QCA_WLAN_VENDOR_ATTR_CONFIG_OPTIMIZED_POWER_MANAGEMENT = 71,
@@ -3202,6 +3207,34 @@
*/
QCA_WLAN_VENDOR_ATTR_CONFIG_MLO_LINKS = 100,
+ /* 16-bit unsigned value to configure power save inactivity timeout in
+ * milliseconds.
+ *
+ * STA enters into power save mode (PM=1) after TX/RX inactivity of time
+ * duration specified by %QCA_WLAN_VENDOR_ATTR_CONFIG_OPM_ITO.
+ *
+ * This attribute shall be configured along with
+ * %QCA_WLAN_VENDOR_ATTR_CONFIG_OPM_SPEC_WAKE_INTERVAL when
+ * %QCA_WLAN_VENDOR_ATTR_CONFIG_OPTIMIZED_POWER_MANAGEMENT
+ * is set to %QCA_WLAN_VENDOR_OPM_MODE_USER_DEFINED mode.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_OPM_ITO = 101,
+
+ /* 16-bit unsigned value to configure speculative wake interval in
+ * milliseconds.
+ *
+ * STA speculatively wakes up to look for buffered data by AP at
+ * %QCA_WLAN_VENDOR_ATTR_CONFIG_OPM_SPEC_WAKE_INTERVAL interval after
+ * entering into power save. If configured zero, STA wakes up at
+ * upcoming DTIM beacon.
+ *
+ * This attribute shall be configured along with
+ * %QCA_WLAN_VENDOR_ATTR_CONFIG_OPM_ITO and
+ * %QCA_WLAN_VENDOR_ATTR_CONFIG_OPTIMIZED_POWER_MANAGEMENT
+ * to %QCA_WLAN_VENDOR_OPM_MODE_USER_DEFINED mode.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_OPM_SPEC_WAKE_INTERVAL = 102,
+
/* keep last */
QCA_WLAN_VENDOR_ATTR_CONFIG_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_CONFIG_MAX =
@@ -15997,4 +16030,22 @@
QCA_WLAN_VENDOR_ATTR_TDLS_STATE_AFTER_LAST - 1,
};
+/*
+ * enum qca_wlan_vendor_opm_mode - Modes supported by
+ * %QCA_WLAN_VENDOR_ATTR_CONFIG_OPTIMIZED_POWER_MANAGEMENT vendor attribute.
+ *
+ * @QCA_WLAN_VENDOR_OPM_MODE_DISABLE: OPM Disabled
+ * @QCA_WLAN_VENDOR_OPM_MODE_ENABLE: OPM Enabled
+ * @QCA_WLAN_VENDOR_OPM_MODE_USER_DEFINED: User defined mode which allows user
+ * to configure power save inactivity timeout and speculative wake up
+ * interval through %QCA_WLAN_VENDOR_ATTR_CONFIG_OPM_ITO and
+ * %QCA_WLAN_VENDOR_ATTR_CONFIG_OPM_SPEC_WAKE_INTERVAL attributes.
+ */
+
+enum qca_wlan_vendor_opm_mode {
+ QCA_WLAN_VENDOR_OPM_MODE_DISABLE = 0,
+ QCA_WLAN_VENDOR_OPM_MODE_ENABLE = 1,
+ QCA_WLAN_VENDOR_OPM_MODE_USER_DEFINED = 2,
+};
+
#endif /* QCA_VENDOR_H */