-#include <net/if.h>
#include <errno.h>
#include <string.h>
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("%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));
{"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},
+ _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_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)
static const struct mesh_param_descr *find_mesh_param(const char *name)
{
int i;
- const struct mesh_param_descr *mdescr = NULL;
/* 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;
+ 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)
{
const struct mesh_param_descr *mdescr;
struct nlattr *container;
/* 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;
}
}
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;
return 2;
}
- 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;
}
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_cb *cb,
- struct nl_msg *msg, int argc, char **argv)
+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;
- char *end;
+ 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;
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--;
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)
return 0;
- return set_interface_meshparam(state, cb, msg, argc, argv);
+ return set_interface_meshparam(state, msg, argc, argv, id);
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> [[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 mcast-rate and mesh parameters.");
+ "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_cb *cb,
- struct nl_msg *msg, int argc, char **argv)
+static int leave_mesh(struct nl80211_state *state,
+ struct nl_msg *msg, int argc, char **argv,
+ enum id_input id)
{
if (argc)
return 1;