wpa_supplicant_8_lib: Add support for OPM mode configuration
Add support to configure OPM mode with SET_PS_CONFIG command
Command: "SET_PS_CONFIG <opm_mode> <ps_ito> <spec_wake>"
opm_mode: Optimized Power Management Mode
ps_ito: Power Save Inactivity Timeout
spec_wake: Speculative wake interval
Examples:
1. Disable OPM: "SET_PS_CONFIG 0"
2. Enable OPM: "SET_PS_CONFIG 1"
3. User defined OPM: "SET_PS_CONFIG 2 50 0"
Change-Id: Idc09fb84bb79785459f73a52bee58a79e831c86d
CRs-Fixed: 3578543
diff --git a/qcwcn/wpa_supplicant_8_lib/driver_cmd_nl80211.c b/qcwcn/wpa_supplicant_8_lib/driver_cmd_nl80211.c
index 970e521..1d02769 100644
--- a/qcwcn/wpa_supplicant_8_lib/driver_cmd_nl80211.c
+++ b/qcwcn/wpa_supplicant_8_lib/driver_cmd_nl80211.c
@@ -179,6 +179,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 {
@@ -2750,6 +2754,20 @@
return val;
}
+static u16 get_u16_from_string(char *cmd_string, int *ret)
+{
+ u16 val = 0;
+
+ *ret = 0;
+ errno = 0;
+ val = strtol(cmd_string, NULL, 10) & 0xFFFF;
+ if (errno == ERANGE || (errno != 0 && val == 0)) {
+ wpa_printf(MSG_ERROR, "Invalid input to get u16 value");
+ *ret = -EINVAL;
+ }
+ return val;
+}
+
char *move_to_next_str(char *cmd)
{
if (*cmd == '\0')
@@ -6402,6 +6420,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 )
{
@@ -6751,6 +6879,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));