]> git.ipfire.org Git - thirdparty/iw.git/blobdiff - mesh.c
update nl80211.h
[thirdparty/iw.git] / mesh.c
diff --git a/mesh.c b/mesh.c
index 4fdad6a09a76991c73005be575bde5d0a9a9d4a5..40e5e5e8f0da1dbc2f5b8a1a512fba7a342d7b84 100644 (file)
--- a/mesh.c
+++ b/mesh.c
@@ -1,4 +1,3 @@
-#include <net/if.h>
 #include <errno.h>
 #include <string.h>
 
@@ -12,6 +11,7 @@
 #include "iw.h"
 
 SECTION(mesh);
+SECTION(mesh_param);
 
 
 typedef struct _any_t {
@@ -109,6 +109,23 @@ static uint32_t _parse_s32(const char *str, _any *ret)
        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)
 {
@@ -140,11 +157,36 @@ 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));
@@ -152,7 +194,7 @@ static void _print_s32_in_dBm(struct nlattr *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,
@@ -217,11 +259,23 @@ const static struct mesh_param_descr _mesh_param_descrs[] =
        {"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");
 
@@ -231,7 +285,7 @@ static void print_all_mesh_param_descr(void)
 
 static const struct mesh_param_descr *find_mesh_param(const char *name)
 {
-       int i;
+       unsigned int i;
 
        /* Find out what mesh parameter we want to change. */
        for (i = 0; i < ARRAY_SIZE(_mesh_param_descrs); i++) {
@@ -239,13 +293,11 @@ static const struct mesh_param_descr *find_mesh_param(const char *name)
                        return _mesh_param_descrs + i;
        }
 
-       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,
                                   enum id_input id)
@@ -253,14 +305,16 @@ static int set_interface_meshparam(struct nl80211_state *state,
        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;
@@ -288,14 +342,24 @@ static int set_interface_meshparam(struct nl80211_state *state,
                }
 
                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;
                }
 
@@ -334,42 +398,50 @@ static int print_mesh_param_handler(struct nl_msg *msg, void *arg)
                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,
                                   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;
 }
 
@@ -377,13 +449,28 @@ 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_cb *cb,
+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;
-       char *end;
+       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;
@@ -392,6 +479,50 @@ static int join_mesh(struct nl80211_state *state, struct nl_cb *cb,
        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--;
@@ -405,6 +536,32 @@ static int join_mesh(struct nl80211_state *state, struct nl_cb *cb,
                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;
@@ -427,16 +584,20 @@ static int join_mesh(struct nl80211_state *state, struct nl_cb *cb,
 
        if (!argc)
                return 0;
-       return set_interface_meshparam(state, cb, msg, argc, argv, id);
+       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> <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 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,
+static int leave_mesh(struct nl80211_state *state,
                      struct nl_msg *msg, int argc, char **argv,
                      enum id_input id)
 {