[PATCH] wpa_supplicant, nl80211: ieee80211 power save support
Janusz.Dziedzic at tieto.com
Janusz.Dziedzic
Wed Jul 20 00:54:27 PDT 2011
Support for enabling/disabling/monitoring
current mode of ieee80211 power save.
Change-Id: Ie7bd2679ac5c4b87d6bdbda05cfde88d8ee2be6b
---
src/drivers/driver.h | 22 ++++++++++++
src/drivers/driver_nl80211.c | 78 ++++++++++++++++++++++++++++++++++++++++++
wpa_supplicant/ctrl_iface.c | 36 +++++++++++++++++++
wpa_supplicant/driver_i.h | 15 ++++++++
wpa_supplicant/wpa_cli.c | 24 +++++++++++++
5 files changed, 175 insertions(+), 0 deletions(-)
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 92951ae..3e73f47 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -2274,6 +2274,28 @@ struct wpa_driver_ops {
*/
void (*set_rekey_info)(void *priv, const u8 *kek, const u8 *kck,
const u8 *replay_ctr);
+
+ /**
+ * set_powersave - set IEEE80211 power save
+ * @priv: Private driver interface data
+ * @enable: 1=enable, 0=disable
+ * Returns: 0 on success, -1 on failure
+ *
+ * This fuction can be used to enable/disable IEEE80211 power
+ * save for the driver/firmware.
+ */
+ int (*set_powersave)(void *priv, int enable);
+
+ /**
+ * get_powersave - get actual IEEE80211 power save settings
+ * @priv: Private driver interface data
+ * @enabled: output param, result: 1=enabled, 0=disabled
+ * Returns: 0 on success, -1 on failure
+ *
+ * This fuction get current IEEE80211 power save mode used
+ * by driver/firmware.
+ */
+ int (*get_powersave)(void *priv, int *enabled);
};
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 87d474e..663e388 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -6786,6 +6786,82 @@ static void nl80211_set_rekey_info(void *priv, const u8 *kek, const u8 *kck,
}
+static int get_powersave_handler(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ enum nl80211_ps_state ps_state;
+ int *state = (int *) arg;
+ *state = -1;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+
+ if (tb[NL80211_ATTR_PS_STATE]) {
+ ps_state = nla_get_u32(tb[NL80211_ATTR_PS_STATE]);
+ if (ps_state == NL80211_PS_ENABLED)
+ *state = 1;
+ else
+ *state = 0;
+ }
+
+ return NL_SKIP;
+}
+
+static int nl80211_get_powersave(void *priv, int *enabled)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int ret;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -ENOMEM;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
+ NL80211_CMD_GET_POWER_SAVE, 0);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+
+ ret = send_and_recv_msgs(bss->drv, msg, get_powersave_handler, enabled);
+ if (ret == 0) {
+ wpa_printf(MSG_DEBUG, "%s enabled: %d\n", __func__, *enabled);
+ if (*enabled == -1)
+ ret = -1;
+ }
+
+ return ret;
+nla_put_failure:
+ nlmsg_free(msg);
+ return -ENOBUFS;
+}
+
+static int nl80211_set_powersave(void *priv, int enable)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ enum nl80211_ps_state ps_state = NL80211_PS_DISABLED;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -ENOMEM;
+
+ if (enable)
+ ps_state = NL80211_PS_ENABLED;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
+ NL80211_CMD_SET_POWER_SAVE, 0);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+ NLA_PUT_U32(msg, NL80211_ATTR_PS_STATE, ps_state);
+
+ return send_and_recv_msgs(bss->drv, msg, NULL, NULL);
+nla_put_failure:
+ nlmsg_free(msg);
+ return -ENOBUFS;
+}
+
const struct wpa_driver_ops wpa_driver_nl80211_ops = {
.name = "nl80211",
.desc = "Linux nl80211/cfg80211",
@@ -6859,4 +6935,6 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
.remove_pmkid = nl80211_remove_pmkid,
.flush_pmkid = nl80211_flush_pmkid,
.set_rekey_info = nl80211_set_rekey_info,
+ .get_powersave = nl80211_get_powersave,
+ .set_powersave = nl80211_set_powersave,
};
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 730e607..45afba5 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -2103,6 +2103,39 @@ static int wpa_supplicant_ctrl_iface_roam(struct wpa_supplicant *wpa_s,
return 0;
}
+static int wpa_supplicant_ieee80211_ps(struct wpa_supplicant *wpa_s, char *input,
+ char *buf, size_t buflen)
+{
+ int ret = 0;
+
+ ret = os_snprintf(buf, buflen, "OK\n");
+ if (ret < 0 || (unsigned int) ret > buflen)
+ ret = -1;
+
+ if (os_strcasecmp(input, "enable") == 0) {
+ /* Enable ieee80211 power save */
+ if (wpa_drv_set_powersave(wpa_s, 1))
+ ret = -1;
+ } else if (os_strcasecmp(input, "disable") == 0) {
+ /* Disable ieee80211 power save */
+ if (wpa_drv_set_powersave(wpa_s, 0))
+ ret = -1;
+ } else if (os_strcasecmp(input, "show") == 0) {
+ /* Get current ieee80211 power save mode */
+ int enabled;
+ if (wpa_drv_get_powersave(wpa_s, &enabled)){
+ ret = -1;
+ } else {
+ ret = os_snprintf(buf, buflen, "%s\nOK",
+ enabled == 0 ? "disabled":"enabled");
+ if (ret < 0 || (unsigned int) ret > buflen)
+ ret = -1;
+ }
+ } else
+ ret = -1;
+
+ return ret;
+}
#ifdef CONFIG_P2P
static int p2p_ctrl_find(struct wpa_supplicant *wpa_s, char *cmd)
@@ -3294,6 +3327,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
} else if (os_strncmp(buf, "SIGNAL_POLL", 11) == 0) {
reply_len = wpa_supplicant_signal_poll(wpa_s, reply,
reply_size);
+ } else if (os_strncmp(buf, "IEEE80211_PS", 12) == 0) {
+ reply_len = wpa_supplicant_ieee80211_ps(wpa_s, buf + 13, reply,
+ reply_size);
} else {
os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
reply_len = 16;
diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h
index 8637754..9dd880d 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -713,4 +713,19 @@ static inline void wpa_drv_set_rekey_info(struct wpa_supplicant *wpa_s,
wpa_s->driver->set_rekey_info(wpa_s->drv_priv, kek, kck, replay_ctr);
}
+static inline int wpa_drv_get_powersave(struct wpa_supplicant *wpa_s,
+ int *enabled)
+{
+ if (!wpa_s->driver->get_powersave)
+ return -1;
+ return wpa_s->driver->get_powersave(wpa_s->drv_priv, enabled);
+}
+
+static inline int wpa_drv_set_powersave(struct wpa_supplicant *wpa_s,
+ int enable)
+{
+ if (!wpa_s->driver->set_powersave)
+ return -1;
+ return wpa_s->driver->set_powersave(wpa_s->drv_priv, enable);
+}
#endif /* DRIVER_I_H */
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index 9439856..4679c7f 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -1678,6 +1678,27 @@ static int wpa_cli_cmd_roam(struct wpa_ctrl *ctrl, int argc, char *argv[])
}
+static int wpa_cli_ieee80211_ps(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ char cmd[128];
+ int res;
+
+ if (argc != 1) {
+ printf("Invalid IEEE80211_PS command: needs one argument: "
+ "<enable|disable|show>\n");
+ return -1;
+ }
+
+ res = os_snprintf(cmd, sizeof(cmd), "IEEE80211_PS %s", argv[0]);
+
+ if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+ printf("Too long IEEE80211_PS command.\n");
+ return -1;
+ }
+
+ return wpa_ctrl_command(ctrl, cmd);
+}
+
#ifdef CONFIG_P2P
static int wpa_cli_cmd_p2p_find(struct wpa_ctrl *ctrl, int argc, char *argv[])
@@ -2540,6 +2561,9 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
{ "roam", wpa_cli_cmd_roam,
cli_cmd_flag_none,
"<addr> = roam to the specified BSS" },
+ { "ieee80211_ps", wpa_cli_ieee80211_ps,
+ cli_cmd_flag_none,
+ "<enable|disable|show>" },
#ifdef CONFIG_P2P
{ "p2p_find", wpa_cli_cmd_p2p_find, cli_cmd_flag_none,
"[timeout] [type=*] = find P2P Devices for up-to timeout seconds" },
--
1.7.0.4
More information about the Hostap
mailing list