2012-11-23 20:53:24

by Marco Porsch

[permalink] [raw]
Subject: [RFCv2 0/4] iw: mesh power save

The following commits cover neccessary iw commands for mesh power save.
Beacon interval, DTIM period, default power mode and awake window are accessed
as part of the mesh params. The link-specific power modes are station-specific.

v2:
-beacon interval and DTIM period set as part of mesh join -> no change during
mesh runtime anymore

Marco Porsch (4):
iw: add beacon interval and DTIM period parameters to mesh join
iw: add default mesh power mode to mesh config
iw: add support for link-specific mesh power modes
iw: add mesh awake window to mesh config

mesh.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++++++---
station.c | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 170 insertions(+), 4 deletions(-)

--
1.7.9.5



2012-11-23 20:53:25

by Marco Porsch

[permalink] [raw]
Subject: [RFCv2 1/4] iw: add beacon interval and DTIM period parameters to mesh join

Set the beacon interval and DTIM period with the mesh join command:
iw <dev> mesh join <meshid> beacon-interval <time in TUs> dtim-period <value>

Signed-off-by: Marco Porsch <[email protected]>
---
mesh.c | 32 ++++++++++++++++++++++++++++++--
1 file changed, 30 insertions(+), 2 deletions(-)

diff --git a/mesh.c b/mesh.c
index 4fdad6a..958c2c0 100644
--- a/mesh.c
+++ b/mesh.c
@@ -383,6 +383,7 @@ static int join_mesh(struct nl80211_state *state, struct nl_cb *cb,
{
struct nlattr *container;
float rate;
+ int bintval, dtim_period;
char *end;

if (argc < 1)
@@ -405,6 +406,32 @@ static int join_mesh(struct nl80211_state *state, struct nl_cb *cb,
argc--;
}

+ if (argc > 1 && strcmp(argv[0], "beacon-interval") == 0) {
+ argc--;
+ argv++;
+
+ bintval = strtoul(argv[0], &end, 10);
+ if (*end != '\0')
+ return 1;
+
+ NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, bintval);
+ argv++;
+ argc--;
+ }
+
+ if (argc > 1 && strcmp(argv[0], "dtim-period") == 0) {
+ argc--;
+ argv++;
+
+ dtim_period = strtoul(argv[0], &end, 10);
+ if (*end != '\0')
+ return 1;
+
+ NLA_PUT_U32(msg, NL80211_ATTR_DTIM_PERIOD, dtim_period);
+ argv++;
+ argc--;
+ }
+
container = nla_nest_start(msg, NL80211_ATTR_MESH_SETUP);
if (!container)
return -ENOBUFS;
@@ -431,8 +458,9 @@ static int join_mesh(struct nl80211_state *state, struct nl_cb *cb,
nla_put_failure:
return -ENOBUFS;
}
-COMMAND(mesh, join, "<mesh ID> [mcast-rate <rate in Mbps>] [vendor_sync on|off]"
- " [<param>=<value>]*",
+COMMAND(mesh, join, "<mesh ID> [mcast-rate <rate in Mbps>]"
+ " [beacon-interval <time in TUs>] [dtim-period <value>]"
+ " [vendor_sync on|off] [<param>=<value>]*",
NL80211_CMD_JOIN_MESH, 0, CIB_NETDEV, join_mesh,
"Join a mesh with the given mesh ID with mcast-rate and mesh parameters.");

--
1.7.9.5


2012-11-23 20:53:29

by Marco Porsch

[permalink] [raw]
Subject: [RFCv2 3/4] iw: add support for link-specific mesh power modes

The different power modes of links towards neighbor STA can be read using
iw <dev> station get
-or-
iw <dev> station dump

The different power modes shown are:
- mesh local PS mode
- mesh peer PS mode
- mesh non-peer PS mode
where the local PS mode is "our" mode towards the neighbor, the peer PS mode
is the neighbor's mode towards us, and the non-peer PS mode is the neighbor's
non-peer PS mode as indicated in beacons and management frames.

The local PS mode can be modified for each neighbor using
iw <dev> station set <mac-addr> mesh_power_mode <active|light|deep>

Signed-off-by: Marco Porsch <[email protected]>
Signed-off-by: Ivan Bezyazychnyy <[email protected]>
---
station.c | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 89 insertions(+)

diff --git a/station.c b/station.c
index 247f445..09ccb8f 100644
--- a/station.c
+++ b/station.c
@@ -29,6 +29,25 @@ enum plink_actions {
PLINK_ACTION_BLOCK,
};

+static void print_power_mode(struct nlattr *a)
+{
+ enum nl80211_mesh_power_mode pm = nla_get_u8(a);
+
+ switch (pm) {
+ case NL80211_MESH_POWER_ACTIVE:
+ printf("ACTIVE");
+ break;
+ case NL80211_MESH_POWER_LIGHT_SLEEP:
+ printf("LIGHT SLEEP");
+ break;
+ case NL80211_MESH_POWER_DEEP_SLEEP:
+ printf("DEEP SLEEP");
+ break;
+ default:
+ printf("UNKNOWN");
+ break;
+ }
+}

static int print_sta_handler(struct nl_msg *msg, void *arg)
{
@@ -54,6 +73,9 @@ static int print_sta_handler(struct nl_msg *msg, void *arg)
[NL80211_STA_INFO_TX_FAILED] = { .type = NLA_U32 },
[NL80211_STA_INFO_STA_FLAGS] =
{ .minlen = sizeof(struct nl80211_sta_flag_update) },
+ [NL80211_STA_INFO_LOCAL_MESH_PS_MODE] = { .type = NLA_U8},
+ [NL80211_STA_INFO_PEER_MESH_PS_MODE] = { .type = NLA_U8},
+ [NL80211_STA_INFO_NONPEER_MESH_PS_MODE] = { .type = NLA_U8},
};

static struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = {
@@ -177,6 +199,18 @@ static int print_sta_handler(struct nl_msg *msg, void *arg)
}
printf("\n\tmesh plink:\t%s", state_name);
}
+ if (sinfo[NL80211_STA_INFO_LOCAL_MESH_PS_MODE]) {
+ printf("\n\tmesh local PS mode:\t");
+ print_power_mode(sinfo[NL80211_STA_INFO_LOCAL_MESH_PS_MODE]);
+ }
+ if (sinfo[NL80211_STA_INFO_PEER_MESH_PS_MODE]) {
+ printf("\n\tmesh peer PS mode:\t");
+ print_power_mode(sinfo[NL80211_STA_INFO_PEER_MESH_PS_MODE]);
+ }
+ if (sinfo[NL80211_STA_INFO_NONPEER_MESH_PS_MODE]) {
+ printf("\n\tmesh non-peer PS mode:\t");
+ print_power_mode(sinfo[NL80211_STA_INFO_NONPEER_MESH_PS_MODE]);
+ }

if (sinfo[NL80211_STA_INFO_STA_FLAGS]) {
sta_flags = (struct nl80211_sta_flag_update *)
@@ -274,6 +308,7 @@ COMMAND(station, del, "<MAC address>",

static const struct cmd *station_set_plink;
static const struct cmd *station_set_vlan;
+static const struct cmd *station_set_mesh_power_mode;

static const struct cmd *select_station_cmd(int argc, char **argv)
{
@@ -283,6 +318,8 @@ static const struct cmd *select_station_cmd(int argc, char **argv)
return station_set_plink;
if (strcmp(argv[1], "vlan") == 0)
return station_set_vlan;
+ if (strcmp(argv[1], "mesh_power_mode") == 0)
+ return station_set_mesh_power_mode;
return NULL;
}

@@ -384,6 +421,58 @@ COMMAND_ALIAS(station, set, "<MAC address> vlan <ifindex>",
"Set an AP VLAN for this station.",
select_station_cmd, station_set_vlan);

+static int handle_station_set_mesh_power_mode(struct nl80211_state *state,
+ struct nl_cb *cb,
+ struct nl_msg *msg,
+ int argc, char **argv,
+ enum id_input id)
+{
+ unsigned char mesh_power_mode;
+ unsigned char mac_addr[ETH_ALEN];
+
+ if (argc < 3)
+ return 1;
+
+ if (mac_addr_a2n(mac_addr, argv[0])) {
+ fprintf(stderr, "invalid mac address\n");
+ return 2;
+ }
+ argc--;
+ argv++;
+
+ if (strcmp("mesh_power_mode", argv[0]) != 0)
+ return 1;
+ argc--;
+ argv++;
+
+ if (strcmp("active", argv[0]) == 0)
+ mesh_power_mode = NL80211_MESH_POWER_ACTIVE;
+ else if (strcmp("light", argv[0]) == 0)
+ mesh_power_mode = NL80211_MESH_POWER_LIGHT_SLEEP;
+ else if (strcmp("deep", argv[0]) == 0)
+ mesh_power_mode = NL80211_MESH_POWER_DEEP_SLEEP;
+ else {
+ fprintf(stderr, "unknown mesh power mode\n");
+ return 2;
+ }
+ argc--;
+ argv++;
+
+ if (argc)
+ return 1;
+
+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr);
+ NLA_PUT_U8(msg, NL80211_ATTR_LOCAL_MESH_POWER_MODE, mesh_power_mode);
+
+ return 0;
+nla_put_failure:
+ return -ENOBUFS;
+}
+COMMAND_ALIAS(station, set, "<MAC address> mesh_power_mode "
+ "<active|light|deep>", NL80211_CMD_SET_STATION, 0, CIB_NETDEV,
+ handle_station_set_mesh_power_mode,
+ "Set link-specific mesh power mode for this station",
+ select_station_cmd, station_set_mesh_power_mode);

static int handle_station_dump(struct nl80211_state *state,
struct nl_cb *cb,
--
1.7.9.5


2012-11-23 20:53:31

by Marco Porsch

[permalink] [raw]
Subject: [RFCv2 4/4] iw: add mesh awake window to mesh config

The awake window is the duration the local STA will stay awake after sending
its own beacon in PS mode. The value can be modified as part of the mesh
params.

Signed-off-by: Marco Porsch <[email protected]>
---
mesh.c | 2 ++
1 file changed, 2 insertions(+)

diff --git a/mesh.c b/mesh.c
index 94f1012..6119b15 100644
--- a/mesh.c
+++ b/mesh.c
@@ -257,6 +257,8 @@ const static struct mesh_param_descr _mesh_param_descrs[] =
_my_nla_put_u16, _parse_u16, _print_u16_in_TUs},
{"mesh_power_mode", NL80211_MESHCONF_POWER_MODE,
_my_nla_put_u8, _parse_u8_power_mode, _print_u8_power_mode},
+ {"mesh_awake_window", NL80211_MESHCONF_AWAKE_WINDOW,
+ _my_nla_put_u16, _parse_u16, _print_u16_in_TUs},
};

static void print_all_mesh_param_descr(void)
--
1.7.9.5


2012-11-23 20:53:27

by Marco Porsch

[permalink] [raw]
Subject: [RFCv2 2/4] iw: add default mesh power mode to mesh config

The default mesh power mode is the power mode that will be assigned to newly
established peer links.

Signed-off-by: Marco Porsch <[email protected]>
Signed-off-by: Ivan Bezyazychnyy <[email protected]>
---
mesh.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 49 insertions(+), 2 deletions(-)

diff --git a/mesh.c b/mesh.c
index 958c2c0..94f1012 100644
--- a/mesh.c
+++ b/mesh.c
@@ -73,6 +73,24 @@ static uint32_t _parse_u8_as_bool(const char *str, _any *ret)
return 0;
}

+static uint32_t _parse_u8_power_mode(const char *str, _any *ret)
+{
+ unsigned long int v;
+
+ /* Parse attribute for the name of power mode */
+ if (!strcmp(str, "active"))
+ v = NL80211_MESH_POWER_ACTIVE;
+ else if (!strcmp(str, "light"))
+ v = NL80211_MESH_POWER_LIGHT_SLEEP;
+ else if (!strcmp(str, "deep"))
+ v = NL80211_MESH_POWER_DEEP_SLEEP;
+ else
+ return 0xff;
+
+ ret->u.as_8 = (uint8_t)v;
+ return 0;
+}
+
static uint32_t _parse_u16(const char *str, _any *ret)
{
char *endptr = NULL;
@@ -115,6 +133,26 @@ static void _print_u8(struct nlattr *a)
printf("%d", nla_get_u8(a));
}

+static void _print_u8_power_mode(struct nlattr *a)
+{
+ unsigned long v = nla_get_u8(a);
+
+ switch (v) {
+ case NL80211_MESH_POWER_ACTIVE:
+ printf("active");
+ break;
+ case NL80211_MESH_POWER_LIGHT_SLEEP:
+ printf("light");
+ break;
+ case NL80211_MESH_POWER_DEEP_SLEEP:
+ printf("deep");
+ break;
+ default:
+ printf("undefined");
+ break;
+ }
+}
+
static void _print_u16(struct nlattr *a)
{
printf("%d", nla_get_u16(a));
@@ -217,6 +255,8 @@ const static struct mesh_param_descr _mesh_param_descrs[] =
{"mesh_hwmp_confirmation_interval",
NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL,
_my_nla_put_u16, _parse_u16, _print_u16_in_TUs},
+ {"mesh_power_mode", NL80211_MESHCONF_POWER_MODE,
+ _my_nla_put_u8, _parse_u8_power_mode, _print_u8_power_mode},
};

static void print_all_mesh_param_descr(void)
@@ -294,8 +334,15 @@ static int set_interface_meshparam(struct nl80211_state *state,
/* Parse the new value */
ret = mdescr->parse_fn(value, &any);
if (ret != 0) {
- printf("%s must be set to a number "
- "between 0 and %u\n", mdescr->name, ret);
+ if (mdescr->mesh_param_num
+ == NL80211_MESHCONF_POWER_MODE)
+ printf("%s must be set to active, light or "
+ "deep.\n", mdescr->name);
+ else
+ printf("%s must be set to a number "
+ "between 0 and %u\n",
+ mdescr->name, ret);
+
return 2;
}

--
1.7.9.5