]> git.ipfire.org Git - thirdparty/iw.git/blob - mesh.c
show supported ciphers
[thirdparty/iw.git] / mesh.c
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
14 SECTION(mesh);
15
16
17 typedef struct _any_t {
18 union {
19 uint32_t as_32;
20 uint16_t as_16;
21 uint8_t as_8;
22 } u;
23 } _any;
24
25 /* describes a mesh parameter */
26 struct 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. */
36 static 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
41 static 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
46 static 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
51 static 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
63 static 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
75 static 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
87 static 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
99 static void _print_u8(struct nlattr *a)
100 {
101 printf("%d", nla_get_u8(a));
102 }
103
104 static void _print_u16(struct nlattr *a)
105 {
106 printf("%d", nla_get_u16(a));
107 }
108
109 static void _print_u16_timeout(struct nlattr *a)
110 {
111 printf("%d milliseconds", nla_get_u16(a));
112 }
113
114 static void _print_u16_in_TUs(struct nlattr *a)
115 {
116 printf("%d TUs", nla_get_u16(a));
117 }
118
119 static void _print_u32_timeout(struct nlattr *a)
120 {
121 printf("%u milliseconds", nla_get_u32(a));
122 }
123
124 static void _print_u32_in_TUs(struct nlattr *a)
125 {
126 printf("%d TUs", nla_get_u32(a));
127 }
128
129 /* The current mesh parameters */
130 const static struct mesh_param_descr _mesh_param_descrs[] =
131 {
132 {"mesh_retry_timeout",
133 NL80211_MESHCONF_RETRY_TIMEOUT,
134 _my_nla_put_u16, _parse_u16, _print_u16_timeout},
135 {"mesh_confirm_timeout",
136 NL80211_MESHCONF_CONFIRM_TIMEOUT,
137 _my_nla_put_u16, _parse_u16, _print_u16_timeout},
138 {"mesh_holding_timeout",
139 NL80211_MESHCONF_HOLDING_TIMEOUT,
140 _my_nla_put_u16, _parse_u16, _print_u16_timeout},
141 {"mesh_max_peer_links",
142 NL80211_MESHCONF_MAX_PEER_LINKS,
143 _my_nla_put_u16, _parse_u16, _print_u16},
144 {"mesh_max_retries",
145 NL80211_MESHCONF_MAX_RETRIES,
146 _my_nla_put_u8, _parse_u8, _print_u8},
147 {"mesh_ttl",
148 NL80211_MESHCONF_TTL,
149 _my_nla_put_u8, _parse_u8, _print_u8},
150 {"mesh_element_ttl",
151 NL80211_MESHCONF_ELEMENT_TTL,
152 _my_nla_put_u8, _parse_u8, _print_u8},
153 {"mesh_auto_open_plinks",
154 NL80211_MESHCONF_AUTO_OPEN_PLINKS,
155 _my_nla_put_u8, _parse_u8_as_bool, _print_u8},
156 {"mesh_hwmp_max_preq_retries",
157 NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES,
158 _my_nla_put_u8, _parse_u8, _print_u8},
159 {"mesh_path_refresh_time",
160 NL80211_MESHCONF_PATH_REFRESH_TIME,
161 _my_nla_put_u32, _parse_u32, _print_u32_timeout},
162 {"mesh_min_discovery_timeout",
163 NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT,
164 _my_nla_put_u16, _parse_u16, _print_u16_timeout},
165 {"mesh_hwmp_active_path_timeout",
166 NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT,
167 _my_nla_put_u32, _parse_u32, _print_u32_in_TUs},
168 {"mesh_hwmp_preq_min_interval",
169 NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL,
170 _my_nla_put_u16, _parse_u16, _print_u16_in_TUs},
171 {"mesh_hwmp_net_diameter_traversal_time",
172 NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
173 _my_nla_put_u16, _parse_u16, _print_u16_in_TUs},
174 {"mesh_hwmp_rootmode", NL80211_MESHCONF_HWMP_ROOTMODE,
175 _my_nla_put_u8, _parse_u8, _print_u8},
176 {"mesh_hwmp_rann_interval", NL80211_MESHCONF_HWMP_RANN_INTERVAL,
177 _my_nla_put_u16, _parse_u16, _print_u16},
178 {"mesh_gate_announcements", NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
179 _my_nla_put_u8, _parse_u8, _print_u8},
180 };
181
182 static void print_all_mesh_param_descr(void)
183 {
184 int i;
185
186 printf("Possible mesh parameters are:\n");
187
188 for (i = 0; i < ARRAY_SIZE(_mesh_param_descrs); i++)
189 printf(" - %s\n", _mesh_param_descrs[i].name);
190 }
191
192 static const struct mesh_param_descr *find_mesh_param(const char *name)
193 {
194 int i;
195 const struct mesh_param_descr *mdescr = NULL;
196
197 /* Find out what mesh parameter we want to change. */
198 for (i = 0; i < ARRAY_SIZE(_mesh_param_descrs); i++) {
199 if (!strcmp(_mesh_param_descrs[i].name, name))
200 return _mesh_param_descrs + i;
201 }
202
203 if (!mdescr) {
204 print_all_mesh_param_descr();
205 return NULL;
206 }
207 return mdescr;
208 }
209
210 /* Setter */
211 static int set_interface_meshparam(struct nl80211_state *state,
212 struct nl_cb *cb,
213 struct nl_msg *msg,
214 int argc, char **argv)
215 {
216 const struct mesh_param_descr *mdescr;
217 struct nlattr *container;
218 uint32_t ret;
219 int err;
220
221 container = nla_nest_start(msg, NL80211_ATTR_MESH_PARAMS);
222 if (!container)
223 return -ENOBUFS;
224
225 if (!argc)
226 return 1;
227
228 while (argc) {
229 const char *name;
230 char *value;
231 _any any;
232
233 memset(&any, 0, sizeof(_any));
234
235 name = argv[0];
236 value = strchr(name, '=');
237 if (value) {
238 *value = '\0';
239 value++;
240 argc--;
241 argv++;
242 } else {
243 /* backward compat -- accept w/o '=' */
244 if (argc < 2) {
245 printf("Must specify a value for %s.\n", name);
246 return 2;
247 }
248 value = argv[1];
249 argc -= 2;
250 argv += 2;
251 }
252
253 mdescr = find_mesh_param(name);
254 if (!mdescr)
255 return 2;
256
257 /* Parse the new value */
258 ret = mdescr->parse_fn(value, &any);
259 if (ret != 0) {
260 printf("%s must be set to a number "
261 "between 0 and %u\n", mdescr->name, ret);
262 return 2;
263 }
264
265 err = mdescr->nla_put_fn(msg, mdescr->mesh_param_num, &any);
266 if (err)
267 return err;
268 }
269 nla_nest_end(msg, container);
270
271 return err;
272 }
273
274 COMMAND(set, mesh_param, "<param>=<value> [<param>=<value>]*",
275 NL80211_CMD_SET_MESH_PARAMS, 0, CIB_NETDEV, set_interface_meshparam,
276 "Set mesh parameter (run command without any to see available ones).");
277
278 /* Getter */
279 static int print_mesh_param_handler(struct nl_msg *msg, void *arg)
280 {
281 const struct mesh_param_descr *mdescr = arg;
282 struct nlattr *attrs[NL80211_ATTR_MAX + 1];
283 struct nlattr *parent_attr;
284 struct nlattr *mesh_params[NL80211_MESHCONF_ATTR_MAX + 1];
285 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
286
287 /* locate NL80211_ATTR_MESH_PARAMS */
288 nla_parse(attrs, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
289 genlmsg_attrlen(gnlh, 0), NULL);
290 parent_attr = attrs[NL80211_ATTR_MESH_PARAMS];
291 if (!parent_attr)
292 return -EINVAL;
293
294 /* unpack the mesh parameters */
295 if (nla_parse_nested(mesh_params, NL80211_MESHCONF_ATTR_MAX,
296 parent_attr, NULL))
297 return -EINVAL;
298
299 if (!mdescr) {
300 int i;
301
302 for (i = 0; i < ARRAY_SIZE(_mesh_param_descrs); i++) {
303 mdescr = &_mesh_param_descrs[i];
304 printf("%s = ", mdescr->name);
305 mdescr->nla_print_fn(mesh_params[mdescr->mesh_param_num]);
306 printf("\n");
307 }
308 return NL_SKIP;
309 }
310
311 /* print out the mesh parameter */
312 mdescr->nla_print_fn(mesh_params[mdescr->mesh_param_num]);
313 printf("\n");
314 return NL_SKIP;
315 }
316
317 static int get_interface_meshparam(struct nl80211_state *state,
318 struct nl_cb *cb,
319 struct nl_msg *msg,
320 int argc, char **argv)
321 {
322 const struct mesh_param_descr *mdescr = NULL;
323
324 if (argc > 1)
325 return 1;
326
327 if (argc == 1) {
328 mdescr = find_mesh_param(argv[0]);
329 if (!mdescr)
330 return 2;
331 }
332
333 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM,
334 print_mesh_param_handler, (void *)mdescr);
335 return 0;
336 }
337
338 COMMAND(get, mesh_param, "[<param>]",
339 NL80211_CMD_GET_MESH_PARAMS, 0, CIB_NETDEV, get_interface_meshparam,
340 "Retrieve mesh parameter (run command without any to see available ones).");
341
342 static int join_mesh(struct nl80211_state *state, struct nl_cb *cb,
343 struct nl_msg *msg, int argc, char **argv)
344 {
345 if (argc < 1)
346 return 1;
347
348 NLA_PUT(msg, NL80211_ATTR_MESH_ID, strlen(argv[0]), argv[0]);
349 argc--;
350 argv++;
351
352 if (!argc)
353 return 0;
354 return set_interface_meshparam(state, cb, msg, argc, argv);
355 nla_put_failure:
356 return -ENOBUFS;
357 }
358 COMMAND(mesh, join, "<mesh ID> [<param>=<value>]*",
359 NL80211_CMD_JOIN_MESH, 0, CIB_NETDEV, join_mesh,
360 "Join a mesh with the given mesh ID and mesh parameters.");
361
362 static int leave_mesh(struct nl80211_state *state, struct nl_cb *cb,
363 struct nl_msg *msg, int argc, char **argv)
364 {
365 if (argc)
366 return 1;
367
368 return 0;
369 }
370 COMMAND(mesh, leave, NULL, NL80211_CMD_LEAVE_MESH, 0, CIB_NETDEV, leave_mesh,
371 "Leave a mesh.");