On Tue, 2008-10-21 at 10:53 -0700, colin@xxxxxxxxxxx wrote: > Two new top-level commands: iw dev <devname> get mesh_param <param>, and > iw dev <devname> set mesh_param <param> <value>. > These can be used to configure the 802.11s mesh networking stack. > These use the new %NL80211_CMD_GET_MESH_PARAMS and > %NL80211_CMD_SET_MESH_PARAMS netlink commands. > > We check the user input to make sure that the values given fall in the valid > range for each parameter. Thanks. I'll put this in when the other patch gets in, or put it into the not-yet-merged branch tomorrow. > Signed-off-by: Colin McCabe <colin@xxxxxxxxxxx> > --- > Makefile | 2 +- > mesh.c | 297 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > nl80211.h | 86 ++++++++++++++++++ > 3 files changed, 384 insertions(+), 1 deletions(-) > create mode 100644 mesh.c > > diff --git a/Makefile b/Makefile > index 18e89ae..6a9010e 100644 > --- a/Makefile > +++ b/Makefile > @@ -11,7 +11,7 @@ CFLAGS += -O2 -g > LDFLAGS += `pkg-config --libs libnl-1` > NLVERSION = 1.0 > > -OBJS = iw.o info.o phy.o interface.o station.o util.o mpath.o reg.o > +OBJS = iw.o info.o phy.o interface.o station.o util.o mpath.o reg.o mesh.o > ALL = iw > > ifeq ($(V),1) > diff --git a/mesh.c b/mesh.c > new file mode 100644 > index 0000000..741a662 > --- /dev/null > +++ b/mesh.c > @@ -0,0 +1,297 @@ > +#include <net/if.h> > +#include <errno.h> > +#include <string.h> > + > +#include <netlink/genl/genl.h> > +#include <netlink/genl/family.h> > +#include <netlink/genl/ctrl.h> > +#include <netlink/msg.h> > +#include <netlink/attr.h> > + > +#include "nl80211.h" > +#include "iw.h" > + > +typedef struct _any_t { > + union { > + uint32_t as_32; > + uint16_t as_16; > + uint8_t as_8; > + } u; > +} _any; > + > +/* describes a mesh parameter */ > +struct mesh_param_descr { > + const char *name; > + enum nl80211_meshconf_params mesh_param_num; > + int (*nla_put_fn)(struct nl_msg*, int, _any*); > + uint32_t (*parse_fn)(const char*, _any*); > + void (*nla_print_fn)(struct nlattr *); > +}; > + > +/* utility functions for manipulating and printing u8/u16/u32 values and > + * timesouts. */ > +static int _my_nla_put_u8(struct nl_msg *n, int mesh_param_num, _any *value) > +{ > + return nla_put(n, mesh_param_num, sizeof(uint8_t), &value->u.as_8); > +} > + > +static int _my_nla_put_u16(struct nl_msg *n, int mesh_param_num, _any *value) > +{ > + return nla_put(n, mesh_param_num, sizeof(uint16_t), &value->u.as_16); > +} > + > +static int _my_nla_put_u32(struct nl_msg *n, int mesh_param_num, _any *value) > +{ > + return nla_put(n, mesh_param_num, sizeof(uint32_t), &value->u.as_32); > +} > + > +static uint32_t _parse_u8(const char *str, _any *ret) > +{ > + char *endptr = NULL; > + unsigned long int v = strtoul(str, &endptr, 10); > + if (*endptr != '\0') > + return 0xff; > + if (v > 0xff) > + return 0xff; > + ret->u.as_8 = (uint8_t)v; > + return 0; > +} > + > +static uint32_t _parse_u8_as_bool(const char *str, _any *ret) > +{ > + char *endptr = NULL; > + unsigned long int v = strtoul(str, &endptr, 10); > + if (*endptr != '\0') > + return 0x1; > + if (v > 0x1) > + return 0x1; > + ret->u.as_8 = (uint8_t)v; > + return 0; > +} > + > +static uint32_t _parse_u16(const char *str, _any *ret) > +{ > + char *endptr = NULL; > + long int v = strtol(str, &endptr, 10); > + if (*endptr != '\0') > + return 0xffff; > + if ((v < 0) || (v > 0xffff)) > + return 0xffff; > + ret->u.as_16 = (uint16_t)v; > + return 0; > +} > + > +static uint32_t _parse_u32(const char *str, _any *ret) > +{ > + char *endptr = NULL; > + long long int v = strtoll(str, &endptr, 10); > + if (*endptr != '\0') > + return 0xffffffff; > + if ((v < 0) || (v > 0xffffffff)) > + return 0xffffffff; > + ret->u.as_32 = (uint32_t)v; > + return 0; > +} > + > +void _print_u8(struct nlattr *a) > +{ > + printf("%d", nla_get_u8(a)); > +} > + > +void _print_u16(struct nlattr *a) > +{ > + printf("%d", nla_get_u16(a)); > +} > + > +void _print_u16_timeout(struct nlattr *a) > +{ > + printf("%d milliseconds", nla_get_u16(a)); > +} > + > +void _print_u16_in_TUs(struct nlattr *a) > +{ > + printf("%d TUs", nla_get_u16(a)); > +} > + > +void _print_u32_timeout(struct nlattr *a) > +{ > + printf("%u milliseconds", nla_get_u32(a)); > +} > + > +void _print_u32_in_TUs(struct nlattr *a) > +{ > + printf("%d TUs", nla_get_u32(a)); > +} > + > +/* The current mesh parameters */ > +const static struct mesh_param_descr _mesh_param_descrs[] = > +{ > + {"mesh_retry_timeout", > + NL80211_MESHCONF_RETRY_TIMEOUT, > + _my_nla_put_u16, _parse_u16, _print_u16_timeout}, > + {"mesh_confirm_timeout", > + NL80211_MESHCONF_CONFIRM_TIMEOUT, > + _my_nla_put_u16, _parse_u16, _print_u16_timeout}, > + {"mesh_holding_timeout", > + NL80211_MESHCONF_HOLDING_TIMEOUT, > + _my_nla_put_u16, _parse_u16, _print_u16_timeout}, > + {"mesh_max_peer_links", > + NL80211_MESHCONF_MAX_PEER_LINKS, > + _my_nla_put_u16, _parse_u16, _print_u16}, > + {"mesh_max_retries", > + NL80211_MESHCONF_MAX_RETRIES, > + _my_nla_put_u8, _parse_u8, _print_u8}, > + {"mesh_ttl", > + NL80211_MESHCONF_TTL, > + _my_nla_put_u8, _parse_u8, _print_u8}, > + {"mesh_auto_open_plinks", > + NL80211_MESHCONF_AUTO_OPEN_PLINKS, > + _my_nla_put_u8, _parse_u8_as_bool, _print_u8}, > + {"mesh_hwmp_max_preq_retries", > + NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES, > + _my_nla_put_u8, _parse_u8, _print_u8}, > + {"mesh_path_refresh_time", > + NL80211_MESHCONF_PATH_REFRESH_TIME, > + _my_nla_put_u32, _parse_u32, _print_u32_timeout}, > + {"mesh_min_discovery_timeout", > + NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT, > + _my_nla_put_u16, _parse_u16, _print_u16_timeout}, > + {"mesh_hwmp_active_path_timeout", > + NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT, > + _my_nla_put_u32, _parse_u32, _print_u32_in_TUs}, > + {"mesh_hwmp_preq_min_interval", > + NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL, > + _my_nla_put_u16, _parse_u16, _print_u16_in_TUs}, > + {"mesh_hwmp_net_diameter_traversal_time", > + NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME, > + _my_nla_put_u16, _parse_u16, _print_u16_in_TUs}, > +}; > + > +static void print_all_mesh_param_descr(void) > +{ > + int i; > + const char *comma = ""; > + > + for (i = 0; > + i < sizeof(_mesh_param_descrs)/sizeof(_mesh_param_descrs[0]); > + ++i) { > + printf("%s%s", comma, _mesh_param_descrs[i].name); > + comma = ", "; > + } > +} > + > +static const struct mesh_param_descr* find_mesh_param(int argc, char **argv, > + const char *action_name) > +{ > + int i; > + const struct mesh_param_descr *mdescr; > + > + if (argc < 1) { > + printf("You must specify which mesh parameter to %s.\n", > + action_name); > + return NULL; > + } > + > + /* Find out what mesh parameter we want to change. */ > + mdescr = NULL; > + for (i = 0; > + i < sizeof(_mesh_param_descrs)/sizeof(_mesh_param_descrs[0]); > + ++i) { > + if (!strcmp(_mesh_param_descrs[i].name, argv[0])) > + return _mesh_param_descrs + i; > + } > + > + if (!mdescr) { > + printf("Mesh_param must be one of: "); > + print_all_mesh_param_descr(); > + printf("\n"); > + return NULL; > + } > + return mdescr; > +} > + > +/* Setter */ > +static int set_interface_meshparam(struct nl_cb *cb, > + struct nl_msg *msg, > + int argc, char **argv) > +{ > + int err; > + uint32_t ret; > + const struct mesh_param_descr *mdescr; > + _any any; > + > + mdescr = find_mesh_param(argc, argv, "change"); > + if (!mdescr) > + return 2; > + if (argc != 2) { > + printf("Must specify a value for %s.\n", mdescr->name); > + return 2; > + } > + > + /* Parse the new value */ > + memset(&any, 0, sizeof(_any)); > + ret = mdescr->parse_fn(argv[1], &any); > + if (ret != 0) { > + printf("%s must be set to a number " > + "between 0 and %u\n", mdescr->name, ret); > + return 2; > + } > + > + /* Construct a netlink message */ > + struct nlattr *container = > + nla_nest_start(msg, NL80211_ATTR_MESH_PARAMS); > + if (!container) > + return -ENOBUFS; > + err = mdescr->nla_put_fn(msg, mdescr->mesh_param_num, &any); > + nla_nest_end(msg, container); > + > + return err; > +} > + > +COMMAND(set, mesh_param, "<param> <value>", > + NL80211_CMD_SET_MESH_PARAMS, 0, CIB_NETDEV, set_interface_meshparam); > + > +/* Getter */ > +static int print_mesh_param_handler(struct nl_msg *msg, void *arg) > +{ > + const struct mesh_param_descr *mdescr = arg; > + struct nlattr *attrs[NL80211_ATTR_MAX + 1]; > + struct nlattr *parent_attr; > + struct nlattr *mesh_params[NL80211_MESHCONF_ATTR_MAX + 1]; > + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); > + > + /* locate NL80211_ATTR_MESH_PARAMS */ > + nla_parse(attrs, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), > + genlmsg_attrlen(gnlh, 0), NULL); > + parent_attr = attrs[NL80211_ATTR_MESH_PARAMS]; > + if (!parent_attr) > + return -EINVAL; > + > + /* unpack the mesh parameters */ > + if (nla_parse_nested(mesh_params, NL80211_MESHCONF_ATTR_MAX, > + parent_attr, NULL)) > + return -EINVAL; > + > + /* print out the mesh parameter */ > + mdescr->nla_print_fn(mesh_params[mdescr->mesh_param_num]); > + printf("\n"); > + return NL_SKIP; > +} > + > +static int get_interface_meshparam(struct nl_cb *cb, > + struct nl_msg *msg, > + int argc, char **argv) > +{ > + const struct mesh_param_descr *mdescr; > + > + mdescr = find_mesh_param(argc, argv, "get"); > + if (!mdescr) > + return 2; > + > + nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, > + print_mesh_param_handler, (void *)mdescr); > + return 0; > +} > + > +COMMAND(get, mesh_param, "<param>", > + NL80211_CMD_GET_MESH_PARAMS, 0, CIB_NETDEV, get_interface_meshparam); > diff --git a/nl80211.h b/nl80211.h > index 9bad654..40d7b27 100644 > --- a/nl80211.h > +++ b/nl80211.h > @@ -106,6 +106,12 @@ > * to the the specified ISO/IEC 3166-1 alpha2 country code. The core will > * store this as a valid request and then query userspace for it. > * > + * @NL80211_CMD_GET_MESH_PARAMS: Get mesh networking properties for the > + * interface identified by %NL80211_ATTR_IFINDEX > + * > + * @NL80211_CMD_SET_MESH_PARAMS: Set mesh networking properties for the > + * interface identified by %NL80211_ATTR_IFINDEX > + * > * @NL80211_CMD_MAX: highest used command number > * @__NL80211_CMD_AFTER_LAST: internal use > */ > @@ -148,6 +154,9 @@ enum nl80211_commands { > NL80211_CMD_SET_REG, > NL80211_CMD_REQ_SET_REG, > > + NL80211_CMD_GET_MESH_PARAMS, > + NL80211_CMD_SET_MESH_PARAMS, > + > /* add new commands above here */ > > /* used to define NL80211_CMD_MAX below */ > @@ -296,6 +305,8 @@ enum nl80211_attrs { > NL80211_ATTR_REG_ALPHA2, > NL80211_ATTR_REG_RULES, > > + NL80211_ATTR_MESH_PARAMS, > + > /* add attributes here, update the policy in nl80211.c */ > > __NL80211_ATTR_AFTER_LAST, > @@ -594,4 +605,79 @@ enum nl80211_mntr_flags { > NL80211_MNTR_FLAG_MAX = __NL80211_MNTR_FLAG_AFTER_LAST - 1 > }; > > +/** > + * enum nl80211_meshconf_params - mesh configuration parameters > + * > + * Mesh configuration parameters > + * > + * @__NL80211_MESHCONF_INVALID: internal use > + * > + * @NL80211_MESHCONF_RETRY_TIMEOUT: specifies the initial retry timeout in > + * millisecond units, used by the Peer Link Open message > + * > + * @NL80211_MESHCONF_CONFIRM_TIMEOUT: specifies the inital confirm timeout, in > + * millisecond units, used by the peer link management to close a peer link > + * > + * @NL80211_MESHCONF_HOLDING_TIMEOUT: specifies the holding timeout, in > + * millisecond units > + * > + * @NL80211_MESHCONF_MAX_PEER_LINKS: maximum number of peer links allowed > + * on this mesh interface > + * > + * @NL80211_MESHCONF_MAX_RETRIES: specifies the maximum number of peer link > + * open retries that can be sent to establish a new peer link instance in a > + * mesh > + * > + * @NL80211_MESHCONF_TTL: specifies the value of TTL field set at a source mesh > + * point. > + * > + * @NL80211_MESHCONF_AUTO_OPEN_PLINKS: whether we should automatically > + * open peer links when we detect compatible mesh peers. > + * > + * @NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES: the number of action frames > + * containing a PREQ that an MP can send to a particular destination (path > + * target) > + * > + * @NL80211_MESHCONF_PATH_REFRESH_TIME: how frequently to refresh mesh paths > + * (in milliseconds) > + * > + * @NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT: minimum length of time to wait > + * until giving up on a path discovery (in milliseconds) > + * > + * @NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT: The time (in TUs) for which mesh > + * points receiving a PREQ shall consider the forwarding information from the > + * root to be valid. (TU = time unit) > + * > + * @NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL: The minimum interval of time (in > + * TUs) during which an MP can send only one action frame containing a PREQ > + * reference element > + * > + * @NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME: The interval of time (in TUs) > + * that it takes for an HWMP information element to propagate across the mesh > + * > + * @NL80211_MESHCONF_ATTR_MAX: highest possible mesh configuration attribute > + * > + * @__NL80211_MESHCONF_ATTR_AFTER_LAST: internal use > + */ > +enum nl80211_meshconf_params { > + __NL80211_MESHCONF_INVALID, > + NL80211_MESHCONF_RETRY_TIMEOUT, > + NL80211_MESHCONF_CONFIRM_TIMEOUT, > + NL80211_MESHCONF_HOLDING_TIMEOUT, > + NL80211_MESHCONF_MAX_PEER_LINKS, > + NL80211_MESHCONF_MAX_RETRIES, > + NL80211_MESHCONF_TTL, > + NL80211_MESHCONF_AUTO_OPEN_PLINKS, > + NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES, > + NL80211_MESHCONF_PATH_REFRESH_TIME, > + NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT, > + NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT, > + NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL, > + NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME, > + > + /* keep last */ > + __NL80211_MESHCONF_ATTR_AFTER_LAST, > + NL80211_MESHCONF_ATTR_MAX = __NL80211_MESHCONF_ATTR_AFTER_LAST - 1 > +}; > + > #endif /* __LINUX_NL80211_H */
Attachment:
signature.asc
Description: This is a digitally signed message part