]> git.ipfire.org Git - thirdparty/iw.git/blame - mesh.c
update nl80211.h
[thirdparty/iw.git] / mesh.c
CommitLineData
46c1ad1f 1#include <net/if.h>
2#include <errno.h>
3#include <string.h>
4
5#include <netlink/genl/genl.h>
6#include <netlink/genl/family.h>
7#include <netlink/genl/ctrl.h>
8#include <netlink/msg.h>
9#include <netlink/attr.h>
10
11#include "nl80211.h"
12#include "iw.h"
13
400efd3e
JB
14SECTION(mesh);
15
16
46c1ad1f 17typedef struct _any_t {
18 union {
19 uint32_t as_32;
be97e513 20 int32_t as_s32;
46c1ad1f 21 uint16_t as_16;
22 uint8_t as_8;
23 } u;
24} _any;
25
26/* describes a mesh parameter */
27struct mesh_param_descr {
28 const char *name;
29 enum nl80211_meshconf_params mesh_param_num;
30 int (*nla_put_fn)(struct nl_msg*, int, _any*);
31 uint32_t (*parse_fn)(const char*, _any*);
32 void (*nla_print_fn)(struct nlattr *);
33};
34
35/* utility functions for manipulating and printing u8/u16/u32 values and
36 * timesouts. */
37static int _my_nla_put_u8(struct nl_msg *n, int mesh_param_num, _any *value)
38{
39 return nla_put(n, mesh_param_num, sizeof(uint8_t), &value->u.as_8);
40}
41
42static int _my_nla_put_u16(struct nl_msg *n, int mesh_param_num, _any *value)
43{
44 return nla_put(n, mesh_param_num, sizeof(uint16_t), &value->u.as_16);
45}
46
47static int _my_nla_put_u32(struct nl_msg *n, int mesh_param_num, _any *value)
48{
49 return nla_put(n, mesh_param_num, sizeof(uint32_t), &value->u.as_32);
50}
51
52static uint32_t _parse_u8(const char *str, _any *ret)
53{
54 char *endptr = NULL;
55 unsigned long int v = strtoul(str, &endptr, 10);
56 if (*endptr != '\0')
57 return 0xff;
58 if (v > 0xff)
59 return 0xff;
60 ret->u.as_8 = (uint8_t)v;
61 return 0;
62}
63
64static uint32_t _parse_u8_as_bool(const char *str, _any *ret)
65{
66 char *endptr = NULL;
67 unsigned long int v = strtoul(str, &endptr, 10);
68 if (*endptr != '\0')
69 return 0x1;
70 if (v > 0x1)
71 return 0x1;
72 ret->u.as_8 = (uint8_t)v;
73 return 0;
74}
75
76static uint32_t _parse_u16(const char *str, _any *ret)
77{
78 char *endptr = NULL;
79 long int v = strtol(str, &endptr, 10);
80 if (*endptr != '\0')
81 return 0xffff;
82 if ((v < 0) || (v > 0xffff))
83 return 0xffff;
84 ret->u.as_16 = (uint16_t)v;
85 return 0;
86}
87
88static uint32_t _parse_u32(const char *str, _any *ret)
89{
90 char *endptr = NULL;
91 long long int v = strtoll(str, &endptr, 10);
92 if (*endptr != '\0')
93 return 0xffffffff;
94 if ((v < 0) || (v > 0xffffffff))
95 return 0xffffffff;
96 ret->u.as_32 = (uint32_t)v;
97 return 0;
98}
99
be97e513
AN
100static uint32_t _parse_s32(const char *str, _any *ret)
101{
102 char *endptr = NULL;
103 long int v = strtol(str, &endptr, 10);
104 if (*endptr != '\0')
105 return 0xffffffff;
106 if (v > 0xff)
107 return 0xffffffff;
108 ret->u.as_s32 = (int32_t)v;
109 return 0;
110}
111
46758fa3
MP
112static uint32_t _parse_u32_power_mode(const char *str, _any *ret)
113{
114 unsigned long int v;
115
116 /* Parse attribute for the name of power mode */
117 if (!strcmp(str, "active"))
118 v = NL80211_MESH_POWER_ACTIVE;
119 else if (!strcmp(str, "light"))
120 v = NL80211_MESH_POWER_LIGHT_SLEEP;
121 else if (!strcmp(str, "deep"))
122 v = NL80211_MESH_POWER_DEEP_SLEEP;
123 else
124 return 0xff;
125
126 ret->u.as_32 = (uint32_t)v;
127 return 0;
128}
be97e513 129
656aa246 130static void _print_u8(struct nlattr *a)
46c1ad1f 131{
132 printf("%d", nla_get_u8(a));
133}
134
656aa246 135static void _print_u16(struct nlattr *a)
46c1ad1f 136{
137 printf("%d", nla_get_u16(a));
138}
139
656aa246 140static void _print_u16_timeout(struct nlattr *a)
46c1ad1f 141{
142 printf("%d milliseconds", nla_get_u16(a));
143}
144
656aa246 145static void _print_u16_in_TUs(struct nlattr *a)
46c1ad1f 146{
147 printf("%d TUs", nla_get_u16(a));
148}
149
d9f730c4
AN
150static void _print_u32(struct nlattr *a)
151{
152 printf("%d", nla_get_u32(a));
153}
154
656aa246 155static void _print_u32_timeout(struct nlattr *a)
46c1ad1f 156{
157 printf("%u milliseconds", nla_get_u32(a));
158}
159
656aa246 160static void _print_u32_in_TUs(struct nlattr *a)
46c1ad1f 161{
162 printf("%d TUs", nla_get_u32(a));
163}
164
46758fa3
MP
165static void _print_u32_power_mode(struct nlattr *a)
166{
167 unsigned long v = nla_get_u32(a);
168
169 switch (v) {
170 case NL80211_MESH_POWER_ACTIVE:
171 printf("active");
172 break;
173 case NL80211_MESH_POWER_LIGHT_SLEEP:
174 printf("light");
175 break;
176 case NL80211_MESH_POWER_DEEP_SLEEP:
177 printf("deep");
178 break;
179 default:
180 printf("undefined");
181 break;
182 }
183}
184
be97e513
AN
185static void _print_s32_in_dBm(struct nlattr *a)
186{
187 printf("%d dBm", (int32_t) nla_get_u32(a));
188}
189
190
46c1ad1f 191/* The current mesh parameters */
192const static struct mesh_param_descr _mesh_param_descrs[] =
193{
194 {"mesh_retry_timeout",
195 NL80211_MESHCONF_RETRY_TIMEOUT,
196 _my_nla_put_u16, _parse_u16, _print_u16_timeout},
197 {"mesh_confirm_timeout",
198 NL80211_MESHCONF_CONFIRM_TIMEOUT,
199 _my_nla_put_u16, _parse_u16, _print_u16_timeout},
200 {"mesh_holding_timeout",
201 NL80211_MESHCONF_HOLDING_TIMEOUT,
202 _my_nla_put_u16, _parse_u16, _print_u16_timeout},
203 {"mesh_max_peer_links",
204 NL80211_MESHCONF_MAX_PEER_LINKS,
205 _my_nla_put_u16, _parse_u16, _print_u16},
206 {"mesh_max_retries",
207 NL80211_MESHCONF_MAX_RETRIES,
208 _my_nla_put_u8, _parse_u8, _print_u8},
209 {"mesh_ttl",
210 NL80211_MESHCONF_TTL,
211 _my_nla_put_u8, _parse_u8, _print_u8},
247beb99
JB
212 {"mesh_element_ttl",
213 NL80211_MESHCONF_ELEMENT_TTL,
214 _my_nla_put_u8, _parse_u8, _print_u8},
46c1ad1f 215 {"mesh_auto_open_plinks",
216 NL80211_MESHCONF_AUTO_OPEN_PLINKS,
217 _my_nla_put_u8, _parse_u8_as_bool, _print_u8},
218 {"mesh_hwmp_max_preq_retries",
219 NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES,
220 _my_nla_put_u8, _parse_u8, _print_u8},
221 {"mesh_path_refresh_time",
222 NL80211_MESHCONF_PATH_REFRESH_TIME,
223 _my_nla_put_u32, _parse_u32, _print_u32_timeout},
224 {"mesh_min_discovery_timeout",
225 NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT,
226 _my_nla_put_u16, _parse_u16, _print_u16_timeout},
227 {"mesh_hwmp_active_path_timeout",
228 NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT,
229 _my_nla_put_u32, _parse_u32, _print_u32_in_TUs},
230 {"mesh_hwmp_preq_min_interval",
231 NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL,
232 _my_nla_put_u16, _parse_u16, _print_u16_in_TUs},
233 {"mesh_hwmp_net_diameter_traversal_time",
234 NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
235 _my_nla_put_u16, _parse_u16, _print_u16_in_TUs},
cc37218f
RP
236 {"mesh_hwmp_rootmode", NL80211_MESHCONF_HWMP_ROOTMODE,
237 _my_nla_put_u8, _parse_u8, _print_u8},
b9aa711a 238 {"mesh_hwmp_rann_interval", NL80211_MESHCONF_HWMP_RANN_INTERVAL,
b1b5713b 239 _my_nla_put_u16, _parse_u16, _print_u16_in_TUs},
b9aa711a
JC
240 {"mesh_gate_announcements", NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
241 _my_nla_put_u8, _parse_u8, _print_u8},
accd0d23
CYY
242 {"mesh_fwding", NL80211_MESHCONF_FORWARDING,
243 _my_nla_put_u8, _parse_u8_as_bool, _print_u8},
d9f730c4
AN
244 {"mesh_sync_offset_max_neighor",
245 NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR,
246 _my_nla_put_u32, _parse_u32, _print_u32},
be97e513
AN
247 {"mesh_rssi_threshold", NL80211_MESHCONF_RSSI_THRESHOLD,
248 _my_nla_put_u32, _parse_s32, _print_s32_in_dBm},
b1b5713b
CYY
249 {"mesh_hwmp_active_path_to_root_timeout",
250 NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT,
251 _my_nla_put_u32, _parse_u32, _print_u32_in_TUs},
252 {"mesh_hwmp_root_interval", NL80211_MESHCONF_HWMP_ROOT_INTERVAL,
253 _my_nla_put_u16, _parse_u16, _print_u16_in_TUs},
254 {"mesh_hwmp_confirmation_interval",
255 NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL,
256 _my_nla_put_u16, _parse_u16, _print_u16_in_TUs},
46758fa3
MP
257 {"mesh_power_mode", NL80211_MESHCONF_POWER_MODE,
258 _my_nla_put_u32, _parse_u32_power_mode, _print_u32_power_mode},
259 {"mesh_awake_window", NL80211_MESHCONF_AWAKE_WINDOW,
260 _my_nla_put_u16, _parse_u16, _print_u16_in_TUs},
46c1ad1f 261};
262
263static void print_all_mesh_param_descr(void)
264{
265 int i;
46c1ad1f 266
f089471a
JB
267 printf("Possible mesh parameters are:\n");
268
269 for (i = 0; i < ARRAY_SIZE(_mesh_param_descrs); i++)
270 printf(" - %s\n", _mesh_param_descrs[i].name);
46c1ad1f 271}
272
a34f62cf 273static const struct mesh_param_descr *find_mesh_param(const char *name)
46c1ad1f 274{
275 int i;
46c1ad1f 276
277 /* Find out what mesh parameter we want to change. */
4d0d2ea7 278 for (i = 0; i < ARRAY_SIZE(_mesh_param_descrs); i++) {
83cb979b 279 if (strcmp(_mesh_param_descrs[i].name, name) == 0)
46c1ad1f 280 return _mesh_param_descrs + i;
4d0d2ea7 281 }
46c1ad1f 282
83cb979b
AN
283 print_all_mesh_param_descr();
284 return NULL;
46c1ad1f 285}
286
287/* Setter */
7c37a24d
JB
288static int set_interface_meshparam(struct nl80211_state *state,
289 struct nl_cb *cb,
290 struct nl_msg *msg,
05514f95
JB
291 int argc, char **argv,
292 enum id_input id)
46c1ad1f 293{
46c1ad1f 294 const struct mesh_param_descr *mdescr;
656aa246 295 struct nlattr *container;
a34f62cf
JB
296 uint32_t ret;
297 int err;
46c1ad1f 298
656aa246 299 container = nla_nest_start(msg, NL80211_ATTR_MESH_PARAMS);
46c1ad1f 300 if (!container)
301 return -ENOBUFS;
a34f62cf
JB
302
303 if (!argc)
304 return 1;
305
306 while (argc) {
307 const char *name;
308 char *value;
309 _any any;
310
311 memset(&any, 0, sizeof(_any));
312
313 name = argv[0];
314 value = strchr(name, '=');
315 if (value) {
316 *value = '\0';
317 value++;
318 argc--;
319 argv++;
320 } else {
321 /* backward compat -- accept w/o '=' */
322 if (argc < 2) {
323 printf("Must specify a value for %s.\n", name);
324 return 2;
325 }
326 value = argv[1];
327 argc -= 2;
328 argv += 2;
329 }
330
331 mdescr = find_mesh_param(name);
332 if (!mdescr)
333 return 2;
334
335 /* Parse the new value */
336 ret = mdescr->parse_fn(value, &any);
337 if (ret != 0) {
46758fa3
MP
338 if (mdescr->mesh_param_num
339 == NL80211_MESHCONF_POWER_MODE)
340 printf("%s must be set to active, light or "
341 "deep.\n", mdescr->name);
342 else
343 printf("%s must be set to a number "
344 "between 0 and %u\n",
345 mdescr->name, ret);
346
a34f62cf
JB
347 return 2;
348 }
349
350 err = mdescr->nla_put_fn(msg, mdescr->mesh_param_num, &any);
351 if (err)
352 return err;
353 }
46c1ad1f 354 nla_nest_end(msg, container);
355
356 return err;
357}
358
a34f62cf 359COMMAND(set, mesh_param, "<param>=<value> [<param>=<value>]*",
70cf4544
JB
360 NL80211_CMD_SET_MESH_PARAMS, 0, CIB_NETDEV, set_interface_meshparam,
361 "Set mesh parameter (run command without any to see available ones).");
46c1ad1f 362
363/* Getter */
364static int print_mesh_param_handler(struct nl_msg *msg, void *arg)
365{
366 const struct mesh_param_descr *mdescr = arg;
367 struct nlattr *attrs[NL80211_ATTR_MAX + 1];
368 struct nlattr *parent_attr;
369 struct nlattr *mesh_params[NL80211_MESHCONF_ATTR_MAX + 1];
370 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
371
372 /* locate NL80211_ATTR_MESH_PARAMS */
373 nla_parse(attrs, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
374 genlmsg_attrlen(gnlh, 0), NULL);
375 parent_attr = attrs[NL80211_ATTR_MESH_PARAMS];
376 if (!parent_attr)
377 return -EINVAL;
378
379 /* unpack the mesh parameters */
380 if (nla_parse_nested(mesh_params, NL80211_MESHCONF_ATTR_MAX,
97e21372 381 parent_attr, NULL))
46c1ad1f 382 return -EINVAL;
383
97e21372
JB
384 if (!mdescr) {
385 int i;
386
387 for (i = 0; i < ARRAY_SIZE(_mesh_param_descrs); i++) {
388 mdescr = &_mesh_param_descrs[i];
389 printf("%s = ", mdescr->name);
390 mdescr->nla_print_fn(mesh_params[mdescr->mesh_param_num]);
391 printf("\n");
392 }
393 return NL_SKIP;
394 }
395
46c1ad1f 396 /* print out the mesh parameter */
397 mdescr->nla_print_fn(mesh_params[mdescr->mesh_param_num]);
398 printf("\n");
399 return NL_SKIP;
400}
401
7c37a24d
JB
402static int get_interface_meshparam(struct nl80211_state *state,
403 struct nl_cb *cb,
404 struct nl_msg *msg,
05514f95
JB
405 int argc, char **argv,
406 enum id_input id)
46c1ad1f 407{
97e21372 408 const struct mesh_param_descr *mdescr = NULL;
46c1ad1f 409
97e21372
JB
410 if (argc > 1)
411 return 1;
412
413 if (argc == 1) {
a34f62cf 414 mdescr = find_mesh_param(argv[0]);
97e21372
JB
415 if (!mdescr)
416 return 2;
417 }
46c1ad1f 418
419 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM,
420 print_mesh_param_handler, (void *)mdescr);
421 return 0;
422}
423
97e21372 424COMMAND(get, mesh_param, "[<param>]",
70cf4544
JB
425 NL80211_CMD_GET_MESH_PARAMS, 0, CIB_NETDEV, get_interface_meshparam,
426 "Retrieve mesh parameter (run command without any to see available ones).");
400efd3e
JB
427
428static int join_mesh(struct nl80211_state *state, struct nl_cb *cb,
05514f95
JB
429 struct nl_msg *msg, int argc, char **argv,
430 enum id_input id)
400efd3e 431{
9560e43d 432 struct nlattr *container;
7d01a091 433 float rate;
a8c2e76d 434 int bintval, dtim_period;
7d01a091
CYY
435 char *end;
436
400efd3e
JB
437 if (argc < 1)
438 return 1;
439
440 NLA_PUT(msg, NL80211_ATTR_MESH_ID, strlen(argv[0]), argv[0]);
441 argc--;
442 argv++;
443
7d01a091
CYY
444 if (argc > 1 && strcmp(argv[0], "mcast-rate") == 0) {
445 argv++;
446 argc--;
447
448 rate = strtod(argv[0], &end);
449 if (*end != '\0')
450 return 1;
451
452 NLA_PUT_U32(msg, NL80211_ATTR_MCAST_RATE, (int)(rate * 10));
453 argv++;
454 argc--;
455 }
456
a8c2e76d
MP
457 if (argc > 1 && strcmp(argv[0], "beacon-interval") == 0) {
458 argc--;
459 argv++;
460
461 bintval = strtoul(argv[0], &end, 10);
462 if (*end != '\0')
463 return 1;
464
465 NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, bintval);
466 argv++;
467 argc--;
468 }
469
470 if (argc > 1 && strcmp(argv[0], "dtim-period") == 0) {
471 argc--;
472 argv++;
473
474 dtim_period = strtoul(argv[0], &end, 10);
475 if (*end != '\0')
476 return 1;
477
478 NLA_PUT_U32(msg, NL80211_ATTR_DTIM_PERIOD, dtim_period);
479 argv++;
480 argc--;
481 }
482
9560e43d
AN
483 container = nla_nest_start(msg, NL80211_ATTR_MESH_SETUP);
484 if (!container)
485 return -ENOBUFS;
486
487 if (argc > 1 && strcmp(argv[0], "vendor_sync") == 0) {
488 argv++;
489 argc--;
490 if (strcmp(argv[0], "on") == 0)
491 NLA_PUT_U8(msg,
492 NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC, 1);
493 else
494 NLA_PUT_U8(msg,
495 NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC, 0);
496 argv++;
497 argc--;
498 }
499 /* parse and put other NL80211_ATTR_MESH_SETUP elements here */
500
501 nla_nest_end(msg, container);
502
400efd3e
JB
503 if (!argc)
504 return 0;
05514f95 505 return set_interface_meshparam(state, cb, msg, argc, argv, id);
400efd3e
JB
506 nla_put_failure:
507 return -ENOBUFS;
508}
a8c2e76d
MP
509COMMAND(mesh, join, "<mesh ID> [mcast-rate <rate in Mbps>]"
510 " [beacon-interval <time in TUs>] [dtim-period <value>]"
511 " [vendor_sync on|off] [<param>=<value>]*",
400efd3e 512 NL80211_CMD_JOIN_MESH, 0, CIB_NETDEV, join_mesh,
7d01a091 513 "Join a mesh with the given mesh ID with mcast-rate and mesh parameters.");
400efd3e
JB
514
515static int leave_mesh(struct nl80211_state *state, struct nl_cb *cb,
05514f95
JB
516 struct nl_msg *msg, int argc, char **argv,
517 enum id_input id)
400efd3e
JB
518{
519 if (argc)
520 return 1;
521
522 return 0;
523}
524COMMAND(mesh, leave, NULL, NL80211_CMD_LEAVE_MESH, 0, CIB_NETDEV, leave_mesh,
525 "Leave a mesh.");