X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=mesh.c;h=0650d0cf5ccc93f01542f68b007a11c0bd832f02;hb=02b53ea252f51cdab7ec7341ec2477dcc51e3e81;hp=f66336322392673cae451484891d4f42dfe6f350;hpb=148c5e29cec5a19a0c201d035fe97abfa86c1d8f;p=thirdparty%2Fiw.git diff --git a/mesh.c b/mesh.c index f663363..0650d0c 100644 --- a/mesh.c +++ b/mesh.c @@ -1,4 +1,3 @@ -#include #include #include @@ -11,9 +10,13 @@ #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; @@ -93,6 +96,36 @@ static uint32_t _parse_u32(const char *str, _any *ret) 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)); @@ -113,18 +146,54 @@ static void _print_u16_in_TUs(struct nlattr *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, @@ -144,6 +213,9 @@ 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}, @@ -165,87 +237,137 @@ const static struct mesh_param_descr _mesh_param_descrs[] = {"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) { - int i; - const char *comma = ""; + unsigned int i; - for (i = 0; i < ARRAY_SIZE(_mesh_param_descrs); i++) { - printf("%s%s", comma, _mesh_param_descrs[i].name); - comma = ", "; - } + printf("Possible mesh parameters are:\n"); + + for (i = 0; i < ARRAY_SIZE(_mesh_param_descrs); i++) + 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); - return NULL; - } + unsigned int i; /* 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) { - printf("Mesh_param must be one of: "); - print_all_mesh_param_descr(); - printf("\n"); - return NULL; - } - return mdescr; + return NULL; } /* Setter */ -static int set_interface_meshparam(struct nl_cb *cb, - struct nl_msg *msg, - int argc, char **argv) +static int set_interface_meshparam(struct nl80211_state *state, + struct nl_msg *msg, + 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 = 2; - /* 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) { + print_all_mesh_param_descr(); + 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) { + 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) { + 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, " ", - NL80211_CMD_SET_MESH_PARAMS, 0, CIB_NETDEV, set_interface_meshparam); +COMMAND(set, mesh_param, "= [=]*", + 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) @@ -265,29 +387,199 @@ 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) { + unsigned 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"); return NL_SKIP; } -static int get_interface_meshparam(struct nl_cb *cb, - struct nl_msg *msg, - int argc, char **argv) +static int get_interface_meshparam(struct nl80211_state *state, + struct nl_msg *msg, + 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 == 0) { + print_all_mesh_param_descr(); + return 1; + } else if (argc == 1) { + mdescr = find_mesh_param(argv[0]); + 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, "", - NL80211_CMD_GET_MESH_PARAMS, 0, CIB_NETDEV, get_interface_meshparam); +COMMAND(get, mesh_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, 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); + 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, " [[freq ]" + " [basic-rates ]], [mcast-rate ]" + " [beacon-interval