-#include <net/if.h>
#include <errno.h>
#include <string.h>
#include "nl80211.h"
#include "iw.h"
+SECTION(mesh);
+SECTION(mesh_param);
+
+
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[] =
+static const struct mesh_param_descr _mesh_param_descrs[] =
{
{"mesh_retry_timeout",
NL80211_MESHCONF_RETRY_TIMEOUT,
{"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},
_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},
+ {"mesh_connected_to_gate", NL80211_MESHCONF_CONNECTED_TO_GATE,
+ _my_nla_put_u8, _parse_u8_as_bool, _print_u8},
+ {"mesh_nolearn", NL80211_MESHCONF_NOLEARN,
+ _my_nla_put_u8, _parse_u8_as_bool, _print_u8},
+ {"mesh_connected_to_as", NL80211_MESHCONF_CONNECTED_TO_AS,
+ _my_nla_put_u8, _parse_u8_as_bool, _print_u8},
};
static void print_all_mesh_param_descr(void)
{
- int i;
+ unsigned int i;
printf("Possible mesh parameters are:\n");
static const struct mesh_param_descr *find_mesh_param(const char *name)
{
- int i;
- const struct mesh_param_descr *mdescr = NULL;
+ unsigned int i;
/* Find out what mesh parameter we want to change. */
for (i = 0; i < ARRAY_SIZE(_mesh_param_descrs); i++) {
- if (!strcmp(_mesh_param_descrs[i].name, name))
+ 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;
+ 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)
{
const struct mesh_param_descr *mdescr;
struct nlattr *container;
uint32_t ret;
- int err;
+ int err = 2;
container = nla_nest_start(msg, NL80211_ATTR_MESH_PARAMS);
if (!container)
return -ENOBUFS;
- if (!argc)
+ if (!argc) {
+ print_all_mesh_param_descr();
return 1;
+ }
while (argc) {
const char *name;
}
mdescr = find_mesh_param(name);
- if (!mdescr)
+ if (!mdescr) {
+ printf("Could not find the parameter %s.\n", name);
+ print_all_mesh_param_descr();
return 2;
+ }
/* 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;
}
return -EINVAL;
if (!mdescr) {
- int i;
+ unsigned int i;
+ /* print out all the supported mesh parameters */
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");
+ if (mesh_params[mdescr->mesh_param_num]) {
+ 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");
+ /* print out the requested mesh parameter */
+ if (mesh_params[mdescr->mesh_param_num]) {
+ mdescr->nla_print_fn(mesh_params[mdescr->mesh_param_num]);
+ printf("\n");
+ }
return NL_SKIP;
}
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 = NULL;
- if (argc > 1)
+ if (argc == 0) {
+ print_all_mesh_param_descr();
return 1;
-
- if (argc == 1) {
+ } else if (argc == 1) {
mdescr = find_mesh_param(argv[0]);
- if (!mdescr)
+ if (!mdescr) {
+ printf("Could not find the parameter %s.\n", argv[0]);
+ print_all_mesh_param_descr();
return 2;
+ }
+ } else {
+ return 1;
}
- nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM,
- print_mesh_param_handler, (void *)mdescr);
+ 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,
"Retrieve mesh parameter (run command without any to see available ones).");
+
+static int dump_interface_meshparam(struct nl80211_state *state,
+ struct nl_msg *msg,
+ int argc, char **argv,
+ enum id_input id)
+{
+ register_handler(print_mesh_param_handler, NULL);
+ return 0;
+}
+
+COMMAND(mesh_param, dump, "",
+ NL80211_CMD_GET_MESH_PARAMS, 0, CIB_NETDEV, dump_interface_meshparam,
+ "List all supported mesh parameters");
+
+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, n_rates = 0;
+ char *end, *value = NULL, *sptr = NULL;
+
+ 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) {
+ struct chandef chandef;
+ int err, parsed;
+
+ err = parse_freqchan(&chandef, false, argc - 1, argv + 1,
+ &parsed, false);
+ if (err)
+ return err;
+
+ argv += parsed + 1;
+ argc -= parsed + 1;
+
+ err = put_chandef(msg, &chandef);
+ if (err)
+ return err;
+ }
+
+ /* 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> <NOHT|HT20|HT40+|HT40-|80MHz>]"
+ " [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.");