]> git.ipfire.org Git - thirdparty/iw.git/blame - mesh.c
update nl80211.h
[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 13SECTION(mesh);
d59e9086 14SECTION(mesh_param);
400efd3e
JB
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
770f80c9
CT
160static void _print_u32_in_seconds(struct nlattr *a)
161{
162 printf("%d seconds", nla_get_u32(a));
163}
164
656aa246 165static void _print_u32_in_TUs(struct nlattr *a)
46c1ad1f 166{
167 printf("%d TUs", nla_get_u32(a));
168}
169
46758fa3
MP
170static void _print_u32_power_mode(struct nlattr *a)
171{
172 unsigned long v = nla_get_u32(a);
173
174 switch (v) {
175 case NL80211_MESH_POWER_ACTIVE:
176 printf("active");
177 break;
178 case NL80211_MESH_POWER_LIGHT_SLEEP:
179 printf("light");
180 break;
181 case NL80211_MESH_POWER_DEEP_SLEEP:
182 printf("deep");
183 break;
184 default:
185 printf("undefined");
186 break;
187 }
188}
189
be97e513
AN
190static void _print_s32_in_dBm(struct nlattr *a)
191{
192 printf("%d dBm", (int32_t) nla_get_u32(a));
193}
194
195
46c1ad1f 196/* The current mesh parameters */
6ab936f0 197static const struct mesh_param_descr _mesh_param_descrs[] =
46c1ad1f 198{
199 {"mesh_retry_timeout",
200 NL80211_MESHCONF_RETRY_TIMEOUT,
201 _my_nla_put_u16, _parse_u16, _print_u16_timeout},
202 {"mesh_confirm_timeout",
203 NL80211_MESHCONF_CONFIRM_TIMEOUT,
204 _my_nla_put_u16, _parse_u16, _print_u16_timeout},
205 {"mesh_holding_timeout",
206 NL80211_MESHCONF_HOLDING_TIMEOUT,
207 _my_nla_put_u16, _parse_u16, _print_u16_timeout},
208 {"mesh_max_peer_links",
209 NL80211_MESHCONF_MAX_PEER_LINKS,
210 _my_nla_put_u16, _parse_u16, _print_u16},
211 {"mesh_max_retries",
212 NL80211_MESHCONF_MAX_RETRIES,
213 _my_nla_put_u8, _parse_u8, _print_u8},
214 {"mesh_ttl",
215 NL80211_MESHCONF_TTL,
216 _my_nla_put_u8, _parse_u8, _print_u8},
247beb99
JB
217 {"mesh_element_ttl",
218 NL80211_MESHCONF_ELEMENT_TTL,
219 _my_nla_put_u8, _parse_u8, _print_u8},
46c1ad1f 220 {"mesh_auto_open_plinks",
221 NL80211_MESHCONF_AUTO_OPEN_PLINKS,
222 _my_nla_put_u8, _parse_u8_as_bool, _print_u8},
223 {"mesh_hwmp_max_preq_retries",
224 NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES,
225 _my_nla_put_u8, _parse_u8, _print_u8},
226 {"mesh_path_refresh_time",
227 NL80211_MESHCONF_PATH_REFRESH_TIME,
228 _my_nla_put_u32, _parse_u32, _print_u32_timeout},
229 {"mesh_min_discovery_timeout",
230 NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT,
231 _my_nla_put_u16, _parse_u16, _print_u16_timeout},
232 {"mesh_hwmp_active_path_timeout",
233 NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT,
234 _my_nla_put_u32, _parse_u32, _print_u32_in_TUs},
235 {"mesh_hwmp_preq_min_interval",
236 NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL,
237 _my_nla_put_u16, _parse_u16, _print_u16_in_TUs},
238 {"mesh_hwmp_net_diameter_traversal_time",
239 NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
240 _my_nla_put_u16, _parse_u16, _print_u16_in_TUs},
cc37218f
RP
241 {"mesh_hwmp_rootmode", NL80211_MESHCONF_HWMP_ROOTMODE,
242 _my_nla_put_u8, _parse_u8, _print_u8},
b9aa711a 243 {"mesh_hwmp_rann_interval", NL80211_MESHCONF_HWMP_RANN_INTERVAL,
b1b5713b 244 _my_nla_put_u16, _parse_u16, _print_u16_in_TUs},
b9aa711a
JC
245 {"mesh_gate_announcements", NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
246 _my_nla_put_u8, _parse_u8, _print_u8},
accd0d23
CYY
247 {"mesh_fwding", NL80211_MESHCONF_FORWARDING,
248 _my_nla_put_u8, _parse_u8_as_bool, _print_u8},
d9f730c4
AN
249 {"mesh_sync_offset_max_neighor",
250 NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR,
251 _my_nla_put_u32, _parse_u32, _print_u32},
be97e513
AN
252 {"mesh_rssi_threshold", NL80211_MESHCONF_RSSI_THRESHOLD,
253 _my_nla_put_u32, _parse_s32, _print_s32_in_dBm},
b1b5713b
CYY
254 {"mesh_hwmp_active_path_to_root_timeout",
255 NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT,
256 _my_nla_put_u32, _parse_u32, _print_u32_in_TUs},
257 {"mesh_hwmp_root_interval", NL80211_MESHCONF_HWMP_ROOT_INTERVAL,
258 _my_nla_put_u16, _parse_u16, _print_u16_in_TUs},
259 {"mesh_hwmp_confirmation_interval",
260 NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL,
261 _my_nla_put_u16, _parse_u16, _print_u16_in_TUs},
46758fa3
MP
262 {"mesh_power_mode", NL80211_MESHCONF_POWER_MODE,
263 _my_nla_put_u32, _parse_u32_power_mode, _print_u32_power_mode},
264 {"mesh_awake_window", NL80211_MESHCONF_AWAKE_WINDOW,
265 _my_nla_put_u16, _parse_u16, _print_u16_in_TUs},
770f80c9
CT
266 {"mesh_plink_timeout", NL80211_MESHCONF_PLINK_TIMEOUT,
267 _my_nla_put_u32, _parse_u32, _print_u32_in_seconds},
0789fd27
MT
268 {"mesh_connected_to_gate", NL80211_MESHCONF_CONNECTED_TO_GATE,
269 _my_nla_put_u8, _parse_u8_as_bool, _print_u8},
94ded888
LL
270 {"mesh_nolearn", NL80211_MESHCONF_NOLEARN,
271 _my_nla_put_u8, _parse_u8_as_bool, _print_u8},
0789fd27
MT
272 {"mesh_connected_to_as", NL80211_MESHCONF_CONNECTED_TO_AS,
273 _my_nla_put_u8, _parse_u8_as_bool, _print_u8},
46c1ad1f 274};
275
276static void print_all_mesh_param_descr(void)
277{
0ee571d5 278 unsigned int i;
46c1ad1f 279
f089471a
JB
280 printf("Possible mesh parameters are:\n");
281
282 for (i = 0; i < ARRAY_SIZE(_mesh_param_descrs); i++)
283 printf(" - %s\n", _mesh_param_descrs[i].name);
46c1ad1f 284}
285
a34f62cf 286static const struct mesh_param_descr *find_mesh_param(const char *name)
46c1ad1f 287{
0ee571d5 288 unsigned int i;
46c1ad1f 289
290 /* Find out what mesh parameter we want to change. */
4d0d2ea7 291 for (i = 0; i < ARRAY_SIZE(_mesh_param_descrs); i++) {
83cb979b 292 if (strcmp(_mesh_param_descrs[i].name, name) == 0)
46c1ad1f 293 return _mesh_param_descrs + i;
4d0d2ea7 294 }
46c1ad1f 295
83cb979b 296 return NULL;
46c1ad1f 297}
298
299/* Setter */
7c37a24d 300static int set_interface_meshparam(struct nl80211_state *state,
7c37a24d 301 struct nl_msg *msg,
05514f95
JB
302 int argc, char **argv,
303 enum id_input id)
46c1ad1f 304{
46c1ad1f 305 const struct mesh_param_descr *mdescr;
656aa246 306 struct nlattr *container;
a34f62cf 307 uint32_t ret;
1ea6085c 308 int err = 2;
46c1ad1f 309
656aa246 310 container = nla_nest_start(msg, NL80211_ATTR_MESH_PARAMS);
46c1ad1f 311 if (!container)
312 return -ENOBUFS;
a34f62cf 313
33cbe6cd
OO
314 if (!argc) {
315 print_all_mesh_param_descr();
a34f62cf 316 return 1;
33cbe6cd 317 }
a34f62cf
JB
318
319 while (argc) {
320 const char *name;
321 char *value;
322 _any any;
323
324 memset(&any, 0, sizeof(_any));
325
326 name = argv[0];
327 value = strchr(name, '=');
328 if (value) {
329 *value = '\0';
330 value++;
331 argc--;
332 argv++;
333 } else {
334 /* backward compat -- accept w/o '=' */
335 if (argc < 2) {
336 printf("Must specify a value for %s.\n", name);
337 return 2;
338 }
339 value = argv[1];
340 argc -= 2;
341 argv += 2;
342 }
343
344 mdescr = find_mesh_param(name);
33cbe6cd
OO
345 if (!mdescr) {
346 printf("Could not find the parameter %s.\n", name);
347 print_all_mesh_param_descr();
a34f62cf 348 return 2;
33cbe6cd 349 }
a34f62cf
JB
350
351 /* Parse the new value */
352 ret = mdescr->parse_fn(value, &any);
353 if (ret != 0) {
46758fa3
MP
354 if (mdescr->mesh_param_num
355 == NL80211_MESHCONF_POWER_MODE)
356 printf("%s must be set to active, light or "
357 "deep.\n", mdescr->name);
358 else
359 printf("%s must be set to a number "
360 "between 0 and %u\n",
361 mdescr->name, ret);
362
a34f62cf
JB
363 return 2;
364 }
365
366 err = mdescr->nla_put_fn(msg, mdescr->mesh_param_num, &any);
367 if (err)
368 return err;
369 }
46c1ad1f 370 nla_nest_end(msg, container);
371
372 return err;
373}
374
a34f62cf 375COMMAND(set, mesh_param, "<param>=<value> [<param>=<value>]*",
70cf4544
JB
376 NL80211_CMD_SET_MESH_PARAMS, 0, CIB_NETDEV, set_interface_meshparam,
377 "Set mesh parameter (run command without any to see available ones).");
46c1ad1f 378
379/* Getter */
380static int print_mesh_param_handler(struct nl_msg *msg, void *arg)
381{
382 const struct mesh_param_descr *mdescr = arg;
383 struct nlattr *attrs[NL80211_ATTR_MAX + 1];
384 struct nlattr *parent_attr;
385 struct nlattr *mesh_params[NL80211_MESHCONF_ATTR_MAX + 1];
386 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
387
388 /* locate NL80211_ATTR_MESH_PARAMS */
389 nla_parse(attrs, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
390 genlmsg_attrlen(gnlh, 0), NULL);
391 parent_attr = attrs[NL80211_ATTR_MESH_PARAMS];
392 if (!parent_attr)
393 return -EINVAL;
394
395 /* unpack the mesh parameters */
396 if (nla_parse_nested(mesh_params, NL80211_MESHCONF_ATTR_MAX,
97e21372 397 parent_attr, NULL))
46c1ad1f 398 return -EINVAL;
399
97e21372 400 if (!mdescr) {
0ee571d5 401 unsigned int i;
97e21372 402
5a291261 403 /* print out all the supported mesh parameters */
97e21372
JB
404 for (i = 0; i < ARRAY_SIZE(_mesh_param_descrs); i++) {
405 mdescr = &_mesh_param_descrs[i];
87728dfc
GS
406 if (mesh_params[mdescr->mesh_param_num]) {
407 printf("%s = ", mdescr->name);
408 mdescr->nla_print_fn(mesh_params[mdescr->mesh_param_num]);
409 printf("\n");
410 }
97e21372
JB
411 }
412 return NL_SKIP;
413 }
414
5a291261 415 /* print out the requested mesh parameter */
87728dfc
GS
416 if (mesh_params[mdescr->mesh_param_num]) {
417 mdescr->nla_print_fn(mesh_params[mdescr->mesh_param_num]);
418 printf("\n");
419 }
46c1ad1f 420 return NL_SKIP;
421}
422
7c37a24d 423static int get_interface_meshparam(struct nl80211_state *state,
7c37a24d 424 struct nl_msg *msg,
05514f95
JB
425 int argc, char **argv,
426 enum id_input id)
46c1ad1f 427{
97e21372 428 const struct mesh_param_descr *mdescr = NULL;
46c1ad1f 429
33cbe6cd
OO
430 if (argc == 0) {
431 print_all_mesh_param_descr();
97e21372 432 return 1;
33cbe6cd 433 } else if (argc == 1) {
a34f62cf 434 mdescr = find_mesh_param(argv[0]);
33cbe6cd
OO
435 if (!mdescr) {
436 printf("Could not find the parameter %s.\n", argv[0]);
437 print_all_mesh_param_descr();
97e21372 438 return 2;
33cbe6cd
OO
439 }
440 } else {
441 return 1;
97e21372 442 }
46c1ad1f 443
34b23014 444 register_handler(print_mesh_param_handler, (void *)mdescr);
46c1ad1f 445 return 0;
446}
447
97e21372 448COMMAND(get, mesh_param, "[<param>]",
70cf4544
JB
449 NL80211_CMD_GET_MESH_PARAMS, 0, CIB_NETDEV, get_interface_meshparam,
450 "Retrieve mesh parameter (run command without any to see available ones).");
400efd3e 451
d59e9086
GS
452static int dump_interface_meshparam(struct nl80211_state *state,
453 struct nl_msg *msg,
454 int argc, char **argv,
455 enum id_input id)
456{
457 register_handler(print_mesh_param_handler, NULL);
458 return 0;
459}
460
461COMMAND(mesh_param, dump, "",
462 NL80211_CMD_GET_MESH_PARAMS, 0, CIB_NETDEV, dump_interface_meshparam,
463 "List all supported mesh parameters");
464
34b23014 465static int join_mesh(struct nl80211_state *state,
05514f95
JB
466 struct nl_msg *msg, int argc, char **argv,
467 enum id_input id)
400efd3e 468{
9560e43d 469 struct nlattr *container;
7d01a091 470 float rate;
c8473cb1 471 unsigned char rates[NL80211_MAX_SUPP_RATES];
0ee571d5 472 int bintval, dtim_period, n_rates = 0;
c8473cb1 473 char *end, *value = NULL, *sptr = NULL;
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) {
3e1debef
BB
484 struct chandef chandef;
485 int err, parsed;
957baf81 486
3e1debef 487 err = parse_freqchan(&chandef, false, argc - 1, argv + 1,
a32046bc 488 &parsed, false);
3e1debef
BB
489 if (err)
490 return err;
957baf81 491
3e1debef
BB
492 argv += parsed + 1;
493 argc -= parsed + 1;
957baf81 494
bcdceae1 495 err = put_chandef(msg, &chandef);
3e1debef
BB
496 if (err)
497 return err;
957baf81
CYY
498 }
499
c8473cb1
CYY
500 /* basic rates */
501 if (argc > 1 && strcmp(argv[0], "basic-rates") == 0) {
502 argv++;
503 argc--;
504
505 value = strtok_r(argv[0], ",", &sptr);
506
507 while (value && n_rates < NL80211_MAX_SUPP_RATES) {
508 rate = strtod(value, &end);
509 rates[n_rates] = rate * 2;
510
511 /* filter out suspicious values */
512 if (*end != '\0' || !rates[n_rates] ||
513 rate*2 != rates[n_rates])
514 return 1;
515
516 n_rates++;
517 value = strtok_r(NULL, ",", &sptr);
518 }
519
520 NLA_PUT(msg, NL80211_ATTR_BSS_BASIC_RATES, n_rates, rates);
521 argv++;
522 argc--;
523 }
524
525 /* multicast rate */
7d01a091
CYY
526 if (argc > 1 && strcmp(argv[0], "mcast-rate") == 0) {
527 argv++;
528 argc--;
529
530 rate = strtod(argv[0], &end);
531 if (*end != '\0')
532 return 1;
533
534 NLA_PUT_U32(msg, NL80211_ATTR_MCAST_RATE, (int)(rate * 10));
535 argv++;
536 argc--;
537 }
538
a8c2e76d
MP
539 if (argc > 1 && strcmp(argv[0], "beacon-interval") == 0) {
540 argc--;
541 argv++;
542
543 bintval = strtoul(argv[0], &end, 10);
544 if (*end != '\0')
545 return 1;
546
547 NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, bintval);
548 argv++;
549 argc--;
550 }
551
552 if (argc > 1 && strcmp(argv[0], "dtim-period") == 0) {
553 argc--;
554 argv++;
555
556 dtim_period = strtoul(argv[0], &end, 10);
557 if (*end != '\0')
558 return 1;
559
560 NLA_PUT_U32(msg, NL80211_ATTR_DTIM_PERIOD, dtim_period);
561 argv++;
562 argc--;
563 }
564
9560e43d
AN
565 container = nla_nest_start(msg, NL80211_ATTR_MESH_SETUP);
566 if (!container)
567 return -ENOBUFS;
568
569 if (argc > 1 && strcmp(argv[0], "vendor_sync") == 0) {
570 argv++;
571 argc--;
572 if (strcmp(argv[0], "on") == 0)
573 NLA_PUT_U8(msg,
574 NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC, 1);
575 else
576 NLA_PUT_U8(msg,
577 NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC, 0);
578 argv++;
579 argc--;
580 }
581 /* parse and put other NL80211_ATTR_MESH_SETUP elements here */
582
583 nla_nest_end(msg, container);
584
400efd3e
JB
585 if (!argc)
586 return 0;
34b23014 587 return set_interface_meshparam(state, msg, argc, argv, id);
400efd3e
JB
588 nla_put_failure:
589 return -ENOBUFS;
590}
8366d195 591COMMAND(mesh, join, "<mesh ID> [[freq <freq in MHz> <NOHT|HT20|HT40+|HT40-|80MHz>]"
c8473cb1 592 " [basic-rates <rate in Mbps,rate2,...>]], [mcast-rate <rate in Mbps>]"
a8c2e76d
MP
593 " [beacon-interval <time in TUs>] [dtim-period <value>]"
594 " [vendor_sync on|off] [<param>=<value>]*",
400efd3e 595 NL80211_CMD_JOIN_MESH, 0, CIB_NETDEV, join_mesh,
c8473cb1
CYY
596 "Join a mesh with the given mesh ID with frequency, basic-rates,\n"
597 "mcast-rate and mesh parameters. Basic-rates are applied only if\n"
598 "frequency is provided.");
400efd3e 599
34b23014 600static int leave_mesh(struct nl80211_state *state,
05514f95
JB
601 struct nl_msg *msg, int argc, char **argv,
602 enum id_input id)
400efd3e
JB
603{
604 if (argc)
605 return 1;
606
607 return 0;
608}
609COMMAND(mesh, leave, NULL, NL80211_CMD_LEAVE_MESH, 0, CIB_NETDEV, leave_mesh,
610 "Leave a mesh.");