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