]> git.ipfire.org Git - thirdparty/iw.git/blame - mesh.c
print wdev id in event info
[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
112
656aa246 113static void _print_u8(struct nlattr *a)
46c1ad1f 114{
115 printf("%d", nla_get_u8(a));
116}
117
656aa246 118static void _print_u16(struct nlattr *a)
46c1ad1f 119{
120 printf("%d", nla_get_u16(a));
121}
122
656aa246 123static void _print_u16_timeout(struct nlattr *a)
46c1ad1f 124{
125 printf("%d milliseconds", nla_get_u16(a));
126}
127
656aa246 128static void _print_u16_in_TUs(struct nlattr *a)
46c1ad1f 129{
130 printf("%d TUs", nla_get_u16(a));
131}
132
d9f730c4
AN
133static void _print_u32(struct nlattr *a)
134{
135 printf("%d", nla_get_u32(a));
136}
137
656aa246 138static void _print_u32_timeout(struct nlattr *a)
46c1ad1f 139{
140 printf("%u milliseconds", nla_get_u32(a));
141}
142
656aa246 143static void _print_u32_in_TUs(struct nlattr *a)
46c1ad1f 144{
145 printf("%d TUs", nla_get_u32(a));
146}
147
be97e513
AN
148static void _print_s32_in_dBm(struct nlattr *a)
149{
150 printf("%d dBm", (int32_t) nla_get_u32(a));
151}
152
153
46c1ad1f 154/* The current mesh parameters */
155const static struct mesh_param_descr _mesh_param_descrs[] =
156{
157 {"mesh_retry_timeout",
158 NL80211_MESHCONF_RETRY_TIMEOUT,
159 _my_nla_put_u16, _parse_u16, _print_u16_timeout},
160 {"mesh_confirm_timeout",
161 NL80211_MESHCONF_CONFIRM_TIMEOUT,
162 _my_nla_put_u16, _parse_u16, _print_u16_timeout},
163 {"mesh_holding_timeout",
164 NL80211_MESHCONF_HOLDING_TIMEOUT,
165 _my_nla_put_u16, _parse_u16, _print_u16_timeout},
166 {"mesh_max_peer_links",
167 NL80211_MESHCONF_MAX_PEER_LINKS,
168 _my_nla_put_u16, _parse_u16, _print_u16},
169 {"mesh_max_retries",
170 NL80211_MESHCONF_MAX_RETRIES,
171 _my_nla_put_u8, _parse_u8, _print_u8},
172 {"mesh_ttl",
173 NL80211_MESHCONF_TTL,
174 _my_nla_put_u8, _parse_u8, _print_u8},
247beb99
JB
175 {"mesh_element_ttl",
176 NL80211_MESHCONF_ELEMENT_TTL,
177 _my_nla_put_u8, _parse_u8, _print_u8},
46c1ad1f 178 {"mesh_auto_open_plinks",
179 NL80211_MESHCONF_AUTO_OPEN_PLINKS,
180 _my_nla_put_u8, _parse_u8_as_bool, _print_u8},
181 {"mesh_hwmp_max_preq_retries",
182 NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES,
183 _my_nla_put_u8, _parse_u8, _print_u8},
184 {"mesh_path_refresh_time",
185 NL80211_MESHCONF_PATH_REFRESH_TIME,
186 _my_nla_put_u32, _parse_u32, _print_u32_timeout},
187 {"mesh_min_discovery_timeout",
188 NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT,
189 _my_nla_put_u16, _parse_u16, _print_u16_timeout},
190 {"mesh_hwmp_active_path_timeout",
191 NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT,
192 _my_nla_put_u32, _parse_u32, _print_u32_in_TUs},
193 {"mesh_hwmp_preq_min_interval",
194 NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL,
195 _my_nla_put_u16, _parse_u16, _print_u16_in_TUs},
196 {"mesh_hwmp_net_diameter_traversal_time",
197 NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
198 _my_nla_put_u16, _parse_u16, _print_u16_in_TUs},
cc37218f
RP
199 {"mesh_hwmp_rootmode", NL80211_MESHCONF_HWMP_ROOTMODE,
200 _my_nla_put_u8, _parse_u8, _print_u8},
b9aa711a 201 {"mesh_hwmp_rann_interval", NL80211_MESHCONF_HWMP_RANN_INTERVAL,
b1b5713b 202 _my_nla_put_u16, _parse_u16, _print_u16_in_TUs},
b9aa711a
JC
203 {"mesh_gate_announcements", NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
204 _my_nla_put_u8, _parse_u8, _print_u8},
accd0d23
CYY
205 {"mesh_fwding", NL80211_MESHCONF_FORWARDING,
206 _my_nla_put_u8, _parse_u8_as_bool, _print_u8},
d9f730c4
AN
207 {"mesh_sync_offset_max_neighor",
208 NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR,
209 _my_nla_put_u32, _parse_u32, _print_u32},
be97e513
AN
210 {"mesh_rssi_threshold", NL80211_MESHCONF_RSSI_THRESHOLD,
211 _my_nla_put_u32, _parse_s32, _print_s32_in_dBm},
b1b5713b
CYY
212 {"mesh_hwmp_active_path_to_root_timeout",
213 NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT,
214 _my_nla_put_u32, _parse_u32, _print_u32_in_TUs},
215 {"mesh_hwmp_root_interval", NL80211_MESHCONF_HWMP_ROOT_INTERVAL,
216 _my_nla_put_u16, _parse_u16, _print_u16_in_TUs},
217 {"mesh_hwmp_confirmation_interval",
218 NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL,
219 _my_nla_put_u16, _parse_u16, _print_u16_in_TUs},
46c1ad1f 220};
221
222static void print_all_mesh_param_descr(void)
223{
224 int i;
46c1ad1f 225
f089471a
JB
226 printf("Possible mesh parameters are:\n");
227
228 for (i = 0; i < ARRAY_SIZE(_mesh_param_descrs); i++)
229 printf(" - %s\n", _mesh_param_descrs[i].name);
46c1ad1f 230}
231
a34f62cf 232static const struct mesh_param_descr *find_mesh_param(const char *name)
46c1ad1f 233{
234 int i;
a34f62cf 235 const struct mesh_param_descr *mdescr = NULL;
46c1ad1f 236
237 /* Find out what mesh parameter we want to change. */
4d0d2ea7 238 for (i = 0; i < ARRAY_SIZE(_mesh_param_descrs); i++) {
a34f62cf 239 if (!strcmp(_mesh_param_descrs[i].name, name))
46c1ad1f 240 return _mesh_param_descrs + i;
4d0d2ea7 241 }
46c1ad1f 242
243 if (!mdescr) {
46c1ad1f 244 print_all_mesh_param_descr();
46c1ad1f 245 return NULL;
246 }
247 return mdescr;
248}
249
250/* Setter */
7c37a24d
JB
251static int set_interface_meshparam(struct nl80211_state *state,
252 struct nl_cb *cb,
253 struct nl_msg *msg,
05514f95
JB
254 int argc, char **argv,
255 enum id_input id)
46c1ad1f 256{
46c1ad1f 257 const struct mesh_param_descr *mdescr;
656aa246 258 struct nlattr *container;
a34f62cf
JB
259 uint32_t ret;
260 int err;
46c1ad1f 261
656aa246 262 container = nla_nest_start(msg, NL80211_ATTR_MESH_PARAMS);
46c1ad1f 263 if (!container)
264 return -ENOBUFS;
a34f62cf
JB
265
266 if (!argc)
267 return 1;
268
269 while (argc) {
270 const char *name;
271 char *value;
272 _any any;
273
274 memset(&any, 0, sizeof(_any));
275
276 name = argv[0];
277 value = strchr(name, '=');
278 if (value) {
279 *value = '\0';
280 value++;
281 argc--;
282 argv++;
283 } else {
284 /* backward compat -- accept w/o '=' */
285 if (argc < 2) {
286 printf("Must specify a value for %s.\n", name);
287 return 2;
288 }
289 value = argv[1];
290 argc -= 2;
291 argv += 2;
292 }
293
294 mdescr = find_mesh_param(name);
295 if (!mdescr)
296 return 2;
297
298 /* Parse the new value */
299 ret = mdescr->parse_fn(value, &any);
300 if (ret != 0) {
301 printf("%s must be set to a number "
302 "between 0 and %u\n", mdescr->name, ret);
303 return 2;
304 }
305
306 err = mdescr->nla_put_fn(msg, mdescr->mesh_param_num, &any);
307 if (err)
308 return err;
309 }
46c1ad1f 310 nla_nest_end(msg, container);
311
312 return err;
313}
314
a34f62cf 315COMMAND(set, mesh_param, "<param>=<value> [<param>=<value>]*",
70cf4544
JB
316 NL80211_CMD_SET_MESH_PARAMS, 0, CIB_NETDEV, set_interface_meshparam,
317 "Set mesh parameter (run command without any to see available ones).");
46c1ad1f 318
319/* Getter */
320static int print_mesh_param_handler(struct nl_msg *msg, void *arg)
321{
322 const struct mesh_param_descr *mdescr = arg;
323 struct nlattr *attrs[NL80211_ATTR_MAX + 1];
324 struct nlattr *parent_attr;
325 struct nlattr *mesh_params[NL80211_MESHCONF_ATTR_MAX + 1];
326 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
327
328 /* locate NL80211_ATTR_MESH_PARAMS */
329 nla_parse(attrs, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
330 genlmsg_attrlen(gnlh, 0), NULL);
331 parent_attr = attrs[NL80211_ATTR_MESH_PARAMS];
332 if (!parent_attr)
333 return -EINVAL;
334
335 /* unpack the mesh parameters */
336 if (nla_parse_nested(mesh_params, NL80211_MESHCONF_ATTR_MAX,
97e21372 337 parent_attr, NULL))
46c1ad1f 338 return -EINVAL;
339
97e21372
JB
340 if (!mdescr) {
341 int i;
342
343 for (i = 0; i < ARRAY_SIZE(_mesh_param_descrs); i++) {
344 mdescr = &_mesh_param_descrs[i];
345 printf("%s = ", mdescr->name);
346 mdescr->nla_print_fn(mesh_params[mdescr->mesh_param_num]);
347 printf("\n");
348 }
349 return NL_SKIP;
350 }
351
46c1ad1f 352 /* print out the mesh parameter */
353 mdescr->nla_print_fn(mesh_params[mdescr->mesh_param_num]);
354 printf("\n");
355 return NL_SKIP;
356}
357
7c37a24d
JB
358static int get_interface_meshparam(struct nl80211_state *state,
359 struct nl_cb *cb,
360 struct nl_msg *msg,
05514f95
JB
361 int argc, char **argv,
362 enum id_input id)
46c1ad1f 363{
97e21372 364 const struct mesh_param_descr *mdescr = NULL;
46c1ad1f 365
97e21372
JB
366 if (argc > 1)
367 return 1;
368
369 if (argc == 1) {
a34f62cf 370 mdescr = find_mesh_param(argv[0]);
97e21372
JB
371 if (!mdescr)
372 return 2;
373 }
46c1ad1f 374
375 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM,
376 print_mesh_param_handler, (void *)mdescr);
377 return 0;
378}
379
97e21372 380COMMAND(get, mesh_param, "[<param>]",
70cf4544
JB
381 NL80211_CMD_GET_MESH_PARAMS, 0, CIB_NETDEV, get_interface_meshparam,
382 "Retrieve mesh parameter (run command without any to see available ones).");
400efd3e
JB
383
384static int join_mesh(struct nl80211_state *state, struct nl_cb *cb,
05514f95
JB
385 struct nl_msg *msg, int argc, char **argv,
386 enum id_input id)
400efd3e 387{
9560e43d 388 struct nlattr *container;
7d01a091
CYY
389 float rate;
390 char *end;
391
400efd3e
JB
392 if (argc < 1)
393 return 1;
394
395 NLA_PUT(msg, NL80211_ATTR_MESH_ID, strlen(argv[0]), argv[0]);
396 argc--;
397 argv++;
398
7d01a091
CYY
399 if (argc > 1 && strcmp(argv[0], "mcast-rate") == 0) {
400 argv++;
401 argc--;
402
403 rate = strtod(argv[0], &end);
404 if (*end != '\0')
405 return 1;
406
407 NLA_PUT_U32(msg, NL80211_ATTR_MCAST_RATE, (int)(rate * 10));
408 argv++;
409 argc--;
410 }
411
9560e43d
AN
412 container = nla_nest_start(msg, NL80211_ATTR_MESH_SETUP);
413 if (!container)
414 return -ENOBUFS;
415
416 if (argc > 1 && strcmp(argv[0], "vendor_sync") == 0) {
417 argv++;
418 argc--;
419 if (strcmp(argv[0], "on") == 0)
420 NLA_PUT_U8(msg,
421 NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC, 1);
422 else
423 NLA_PUT_U8(msg,
424 NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC, 0);
425 argv++;
426 argc--;
427 }
428 /* parse and put other NL80211_ATTR_MESH_SETUP elements here */
429
430 nla_nest_end(msg, container);
431
400efd3e
JB
432 if (!argc)
433 return 0;
05514f95 434 return set_interface_meshparam(state, cb, msg, argc, argv, id);
400efd3e
JB
435 nla_put_failure:
436 return -ENOBUFS;
437}
9560e43d
AN
438COMMAND(mesh, join, "<mesh ID> [mcast-rate <rate in Mbps>] [vendor_sync on|off]"
439 " [<param>=<value>]*",
400efd3e 440 NL80211_CMD_JOIN_MESH, 0, CIB_NETDEV, join_mesh,
7d01a091 441 "Join a mesh with the given mesh ID with mcast-rate and mesh parameters.");
400efd3e
JB
442
443static int leave_mesh(struct nl80211_state *state, struct nl_cb *cb,
05514f95
JB
444 struct nl_msg *msg, int argc, char **argv,
445 enum id_input id)
400efd3e
JB
446{
447 if (argc)
448 return 1;
449
450 return 0;
451}
452COMMAND(mesh, leave, NULL, NL80211_CMD_LEAVE_MESH, 0, CIB_NETDEV, leave_mesh,
453 "Leave a mesh.");