#include "nl80211.h"
#include "iw.h"
+SECTION(mesh);
+
+
typedef struct _any_t {
union {
uint32_t as_32;
+ int32_t as_s32;
uint16_t as_16;
uint8_t as_8;
} u;
return 0;
}
+static uint32_t _parse_s32(const char *str, _any *ret)
+{
+ char *endptr = NULL;
+ long int v = strtol(str, &endptr, 10);
+ if (*endptr != '\0')
+ return 0xffffffff;
+ if (v > 0xff)
+ return 0xffffffff;
+ ret->u.as_s32 = (int32_t)v;
+ return 0;
+}
+
+static uint32_t _parse_u32_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_32 = (uint32_t)v;
+ return 0;
+}
+
static void _print_u8(struct nlattr *a)
{
printf("%d", nla_get_u8(a));
printf("%d TUs", nla_get_u16(a));
}
+static void _print_u32(struct nlattr *a)
+{
+ printf("%d", nla_get_u32(a));
+}
+
static void _print_u32_timeout(struct nlattr *a)
{
printf("%u milliseconds", nla_get_u32(a));
}
+static void _print_u32_in_seconds(struct nlattr *a)
+{
+ printf("%d seconds", nla_get_u32(a));
+}
+
static void _print_u32_in_TUs(struct nlattr *a)
{
printf("%d TUs", nla_get_u32(a));
}
+static void _print_u32_power_mode(struct nlattr *a)
+{
+ unsigned long v = nla_get_u32(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_s32_in_dBm(struct nlattr *a)
+{
+ printf("%d dBm", (int32_t) nla_get_u32(a));
+}
+
+
/* The current mesh parameters */
const static struct mesh_param_descr _mesh_param_descrs[] =
{
{"mesh_ttl",
NL80211_MESHCONF_TTL,
_my_nla_put_u8, _parse_u8, _print_u8},
+ {"mesh_element_ttl",
+ NL80211_MESHCONF_ELEMENT_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_net_diameter_traversal_time",
NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
_my_nla_put_u16, _parse_u16, _print_u16_in_TUs},
+ {"mesh_hwmp_rootmode", NL80211_MESHCONF_HWMP_ROOTMODE,
+ _my_nla_put_u8, _parse_u8, _print_u8},
+ {"mesh_hwmp_rann_interval", NL80211_MESHCONF_HWMP_RANN_INTERVAL,
+ _my_nla_put_u16, _parse_u16, _print_u16_in_TUs},
+ {"mesh_gate_announcements", NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
+ _my_nla_put_u8, _parse_u8, _print_u8},
+ {"mesh_fwding", NL80211_MESHCONF_FORWARDING,
+ _my_nla_put_u8, _parse_u8_as_bool, _print_u8},
+ {"mesh_sync_offset_max_neighor",
+ NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR,
+ _my_nla_put_u32, _parse_u32, _print_u32},
+ {"mesh_rssi_threshold", NL80211_MESHCONF_RSSI_THRESHOLD,
+ _my_nla_put_u32, _parse_s32, _print_s32_in_dBm},
+ {"mesh_hwmp_active_path_to_root_timeout",
+ NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT,
+ _my_nla_put_u32, _parse_u32, _print_u32_in_TUs},
+ {"mesh_hwmp_root_interval", NL80211_MESHCONF_HWMP_ROOT_INTERVAL,
+ _my_nla_put_u16, _parse_u16, _print_u16_in_TUs},
+ {"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_u32, _parse_u32_power_mode, _print_u32_power_mode},
+ {"mesh_awake_window", NL80211_MESHCONF_AWAKE_WINDOW,
+ _my_nla_put_u16, _parse_u16, _print_u16_in_TUs},
+ {"mesh_plink_timeout", NL80211_MESHCONF_PLINK_TIMEOUT,
+ _my_nla_put_u32, _parse_u32, _print_u32_in_seconds},
};
static void print_all_mesh_param_descr(void)
printf(" - %s\n", _mesh_param_descrs[i].name);
}
-static const struct mesh_param_descr* find_mesh_param(int argc, char **argv,
- const char *action_name)
+static const struct mesh_param_descr *find_mesh_param(const char *name)
{
int i;
- const struct mesh_param_descr *mdescr;
-
- if (argc < 1) {
- printf("You must specify which mesh parameter to %s.\n",
- action_name);
- print_all_mesh_param_descr();
- return NULL;
- }
/* Find out what mesh parameter we want to change. */
- mdescr = NULL;
for (i = 0; i < ARRAY_SIZE(_mesh_param_descrs); i++) {
- if (!strcmp(_mesh_param_descrs[i].name, argv[0]))
+ if (strcmp(_mesh_param_descrs[i].name, name) == 0)
return _mesh_param_descrs + i;
}
- if (!mdescr) {
- print_all_mesh_param_descr();
- return NULL;
- }
- return mdescr;
+ print_all_mesh_param_descr();
+ return NULL;
}
/* Setter */
static int set_interface_meshparam(struct nl80211_state *state,
- struct nl_cb *cb,
struct nl_msg *msg,
- int argc, char **argv)
+ int argc, char **argv,
+ enum id_input id)
{
- int err;
- uint32_t ret;
const struct mesh_param_descr *mdescr;
struct nlattr *container;
- _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;
- }
+ uint32_t ret;
+ int err;
- /* Construct a netlink message */
container = nla_nest_start(msg, NL80211_ATTR_MESH_PARAMS);
if (!container)
return -ENOBUFS;
- err = mdescr->nla_put_fn(msg, mdescr->mesh_param_num, &any);
+
+ if (!argc)
+ return 1;
+
+ while (argc) {
+ const char *name;
+ char *value;
+ _any any;
+
+ memset(&any, 0, sizeof(_any));
+
+ name = argv[0];
+ value = strchr(name, '=');
+ if (value) {
+ *value = '\0';
+ value++;
+ argc--;
+ argv++;
+ } else {
+ /* backward compat -- accept w/o '=' */
+ if (argc < 2) {
+ printf("Must specify a value for %s.\n", name);
+ return 2;
+ }
+ value = argv[1];
+ argc -= 2;
+ argv += 2;
+ }
+
+ mdescr = find_mesh_param(name);
+ if (!mdescr)
+ return 2;
+
+ /* Parse the new value */
+ ret = mdescr->parse_fn(value, &any);
+ if (ret != 0) {
+ 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;
+ }
+
+ err = mdescr->nla_put_fn(msg, mdescr->mesh_param_num, &any);
+ if (err)
+ return err;
+ }
nla_nest_end(msg, container);
return err;
}
-COMMAND(set, mesh_param, "<param> <value>",
- NL80211_CMD_SET_MESH_PARAMS, 0, CIB_NETDEV, set_interface_meshparam);
+COMMAND(set, mesh_param, "<param>=<value> [<param>=<value>]*",
+ NL80211_CMD_SET_MESH_PARAMS, 0, CIB_NETDEV, set_interface_meshparam,
+ "Set mesh parameter (run command without any to see available ones).");
/* Getter */
static int print_mesh_param_handler(struct nl_msg *msg, void *arg)
/* unpack the mesh parameters */
if (nla_parse_nested(mesh_params, NL80211_MESHCONF_ATTR_MAX,
- parent_attr, NULL))
+ parent_attr, NULL))
return -EINVAL;
+ if (!mdescr) {
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(_mesh_param_descrs); i++) {
+ mdescr = &_mesh_param_descrs[i];
+ printf("%s = ", mdescr->name);
+ mdescr->nla_print_fn(mesh_params[mdescr->mesh_param_num]);
+ printf("\n");
+ }
+ return NL_SKIP;
+ }
+
/* print out the mesh parameter */
mdescr->nla_print_fn(mesh_params[mdescr->mesh_param_num]);
printf("\n");
}
static int get_interface_meshparam(struct nl80211_state *state,
- struct nl_cb *cb,
struct nl_msg *msg,
- int argc, char **argv)
+ int argc, char **argv,
+ enum id_input id)
{
- const struct mesh_param_descr *mdescr;
+ const struct mesh_param_descr *mdescr = NULL;
- mdescr = find_mesh_param(argc, argv, "get");
- if (!mdescr)
- return 2;
+ if (argc > 1)
+ return 1;
- nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM,
- print_mesh_param_handler, (void *)mdescr);
+ if (argc == 1) {
+ mdescr = find_mesh_param(argv[0]);
+ if (!mdescr)
+ return 2;
+ }
+
+ register_handler(print_mesh_param_handler, (void *)mdescr);
return 0;
}
-COMMAND(get, mesh_param, "<param>",
- NL80211_CMD_GET_MESH_PARAMS, 0, CIB_NETDEV, get_interface_meshparam);
+COMMAND(get, mesh_param, "[<param>]",
+ NL80211_CMD_GET_MESH_PARAMS, 0, CIB_NETDEV, get_interface_meshparam,
+ "Retrieve mesh parameter (run command without any to see available ones).");
+
+static int join_mesh(struct nl80211_state *state,
+ struct nl_msg *msg, int argc, char **argv,
+ enum id_input id)
+{
+ struct nlattr *container;
+ float rate;
+ unsigned char rates[NL80211_MAX_SUPP_RATES];
+ int bintval, dtim_period, i, n_rates = 0;
+ char *end, *value = NULL, *sptr = NULL;
+ unsigned long freq = 0;
+ static const struct {
+ const char *name;
+ unsigned int width;
+ int freq1_diff;
+ int chantype; /* for older kernel */
+ } *chanmode_selected = NULL, chanmode[] = {
+ { .name = "HT20",
+ .width = NL80211_CHAN_WIDTH_20,
+ .freq1_diff = 0,
+ .chantype = NL80211_CHAN_HT20 },
+ { .name = "HT40+",
+ .width = NL80211_CHAN_WIDTH_40,
+ .freq1_diff = 10,
+ .chantype = NL80211_CHAN_HT40PLUS },
+ { .name = "HT40-",
+ .width = NL80211_CHAN_WIDTH_40,
+ .freq1_diff = -10,
+ .chantype = NL80211_CHAN_HT40MINUS },
+ { .name = "NOHT",
+ .width = NL80211_CHAN_WIDTH_20_NOHT,
+ .freq1_diff = 0,
+ .chantype = NL80211_CHAN_NO_HT },
+ };
+
+ if (argc < 1)
+ return 1;
+
+ NLA_PUT(msg, NL80211_ATTR_MESH_ID, strlen(argv[0]), argv[0]);
+ argc--;
+ argv++;
+
+ /* freq */
+ if (argc > 1 && strcmp(argv[0], "freq") == 0) {
+ argv++;
+ argc--;
+
+ freq = strtoul(argv[0], &end, 10);
+ if (*end != '\0')
+ return 1;
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
+
+ argv++;
+ argc--;
+ }
+
+ /* channel type */
+ if (argc) {
+ for (i = 0; i < ARRAY_SIZE(chanmode); i++) {
+ if (strcasecmp(chanmode[i].name, argv[0]) == 0) {
+ chanmode_selected = &chanmode[i];
+ break;
+ }
+ }
+
+ if (chanmode_selected) {
+ NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
+ chanmode_selected->width);
+ NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ1,
+ freq + chanmode_selected->freq1_diff);
+ if (chanmode_selected->chantype != -1)
+ NLA_PUT_U32(msg,
+ NL80211_ATTR_WIPHY_CHANNEL_TYPE,
+ chanmode_selected->chantype);
+
+ argv++;
+ argc--;
+ }
+ }
+
+ /* basic rates */
+ if (argc > 1 && strcmp(argv[0], "basic-rates") == 0) {
+ argv++;
+ argc--;
+
+ value = strtok_r(argv[0], ",", &sptr);
+
+ while (value && n_rates < NL80211_MAX_SUPP_RATES) {
+ rate = strtod(value, &end);
+ rates[n_rates] = rate * 2;
+
+ /* filter out suspicious values */
+ if (*end != '\0' || !rates[n_rates] ||
+ rate*2 != rates[n_rates])
+ return 1;
+
+ n_rates++;
+ value = strtok_r(NULL, ",", &sptr);
+ }
+
+ NLA_PUT(msg, NL80211_ATTR_BSS_BASIC_RATES, n_rates, rates);
+ argv++;
+ argc--;
+ }
+
+ /* multicast rate */
+ if (argc > 1 && strcmp(argv[0], "mcast-rate") == 0) {
+ argv++;
+ argc--;
+
+ rate = strtod(argv[0], &end);
+ if (*end != '\0')
+ return 1;
+
+ NLA_PUT_U32(msg, NL80211_ATTR_MCAST_RATE, (int)(rate * 10));
+ argv++;
+ 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;
+
+ if (argc > 1 && strcmp(argv[0], "vendor_sync") == 0) {
+ argv++;
+ argc--;
+ if (strcmp(argv[0], "on") == 0)
+ NLA_PUT_U8(msg,
+ NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC, 1);
+ else
+ NLA_PUT_U8(msg,
+ NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC, 0);
+ argv++;
+ argc--;
+ }
+ /* parse and put other NL80211_ATTR_MESH_SETUP elements here */
+
+ nla_nest_end(msg, container);
+
+ if (!argc)
+ return 0;
+ return set_interface_meshparam(state, msg, argc, argv, id);
+ nla_put_failure:
+ return -ENOBUFS;
+}
+COMMAND(mesh, join, "<mesh ID> [[freq <freq in MHz> <HT20|HT40+|HT40-|NOHT>]"
+ " [basic-rates <rate in Mbps,rate2,...>]], [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 frequency, basic-rates,\n"
+ "mcast-rate and mesh parameters. Basic-rates are applied only if\n"
+ "frequency is provided.");
+
+static int leave_mesh(struct nl80211_state *state,
+ struct nl_msg *msg, int argc, char **argv,
+ enum id_input id)
+{
+ if (argc)
+ return 1;
+
+ return 0;
+}
+COMMAND(mesh, leave, NULL, NL80211_CMD_LEAVE_MESH, 0, CIB_NETDEV, leave_mesh,
+ "Leave a mesh.");