]> git.ipfire.org Git - thirdparty/iw.git/blob - mpath.c
clean up includes
[thirdparty/iw.git] / mpath.c
1 #include <linux/nl80211.h>
2 #include <net/if.h>
3 #include <errno.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 "iw.h"
12
13 enum plink_state {
14 LISTEN,
15 OPN_SNT,
16 OPN_RCVD,
17 CNF_RCVD,
18 ESTAB,
19 HOLDING,
20 BLOCKED
21 };
22
23 enum plink_actions {
24 PLINK_ACTION_UNDEFINED,
25 PLINK_ACTION_OPEN,
26 PLINK_ACTION_BLOCK,
27 };
28
29
30 static int wait_handler(struct nl_msg *msg, void *arg)
31 {
32 int *finished = arg;
33
34 *finished = 1;
35 return NL_STOP;
36 }
37
38 static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err,
39 void *arg)
40 {
41 fprintf(stderr, "nl80211 error %d\n", err->error);
42 exit(err->error);
43 }
44
45 static int print_mpath_handler(struct nl_msg *msg, void *arg)
46 {
47 struct nlattr *tb[NL80211_ATTR_MAX + 1];
48 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
49 struct nlattr *pinfo[NL80211_MPATH_INFO_MAX + 1];
50 char dst[20], next_hop[20], dev[20];
51 static struct nla_policy mpath_policy[NL80211_MPATH_INFO_MAX + 1] = {
52 [NL80211_MPATH_INFO_FRAME_QLEN] = { .type = NLA_U32 },
53 [NL80211_MPATH_INFO_DSN] = { .type = NLA_U32 },
54 [NL80211_MPATH_INFO_METRIC] = { .type = NLA_U32 },
55 [NL80211_MPATH_INFO_EXPTIME] = { .type = NLA_U32 },
56 [NL80211_MPATH_INFO_DISCOVERY_TIMEOUT] = { .type = NLA_U32 },
57 [NL80211_MPATH_INFO_DISCOVERY_RETRIES] = { .type = NLA_U8 },
58 [NL80211_MPATH_INFO_FLAGS] = { .type = NLA_U8 },
59 };
60
61 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
62 genlmsg_attrlen(gnlh, 0), NULL);
63
64 /*
65 * TODO: validate the interface and mac address!
66 * Otherwise, there's a race condition as soon as
67 * the kernel starts sending mpath notifications.
68 */
69
70 if (!tb[NL80211_ATTR_MPATH_INFO]) {
71 fprintf(stderr, "mpath info missing!");
72 return NL_SKIP;
73 }
74 if (nla_parse_nested(pinfo, NL80211_MPATH_INFO_MAX,
75 tb[NL80211_ATTR_MPATH_INFO],
76 mpath_policy)) {
77 fprintf(stderr, "failed to parse nested attributes!");
78 return NL_SKIP;
79 }
80
81 mac_addr_n2a(dst, nla_data(tb[NL80211_ATTR_MAC]));
82 mac_addr_n2a(next_hop, nla_data(tb[NL80211_ATTR_MPATH_NEXT_HOP]));
83 if_indextoname(nla_get_u32(tb[NL80211_ATTR_IFINDEX]), dev);
84 printf("%s %s %s", dst, next_hop, dev);
85 if (pinfo[NL80211_MPATH_INFO_DSN])
86 printf("\t%u",
87 nla_get_u32(pinfo[NL80211_MPATH_INFO_DSN]));
88 if (pinfo[NL80211_MPATH_INFO_METRIC])
89 printf("\t%u",
90 nla_get_u32(pinfo[NL80211_MPATH_INFO_METRIC]));
91 if (pinfo[NL80211_MPATH_INFO_FRAME_QLEN])
92 printf("\t%u",
93 nla_get_u32(pinfo[NL80211_MPATH_INFO_FRAME_QLEN]));
94 if (pinfo[NL80211_MPATH_INFO_EXPTIME])
95 printf("\t%u",
96 nla_get_u32(pinfo[NL80211_MPATH_INFO_EXPTIME]));
97 if (pinfo[NL80211_MPATH_INFO_DISCOVERY_TIMEOUT])
98 printf("\t%u",
99 nla_get_u32(pinfo[NL80211_MPATH_INFO_DISCOVERY_TIMEOUT]));
100 if (pinfo[NL80211_MPATH_INFO_DISCOVERY_RETRIES])
101 printf("\t%u",
102 nla_get_u8(pinfo[NL80211_MPATH_INFO_DISCOVERY_RETRIES]));
103 if (pinfo[NL80211_MPATH_INFO_FLAGS])
104 printf("\t0x%x",
105 nla_get_u8(pinfo[NL80211_MPATH_INFO_FLAGS]));
106
107 printf("\n");
108 return NL_SKIP;
109 }
110
111 static int handle_mpath_get(struct nl80211_state *state,
112 char *dev, int argc, char **argv)
113 {
114 struct nl_msg *msg;
115 struct nl_cb *cb = NULL;
116 int ret = -1;
117 int err;
118 int finished = 0;
119 unsigned char dst[ETH_ALEN];
120
121 if (argc < 1) {
122 fprintf(stderr, "not enough arguments\n");
123 return -1;
124 }
125
126 if (mac_addr_a2n(dst, argv[0])) {
127 fprintf(stderr, "invalid mac address\n");
128 return -1;
129 }
130 argc--;
131 argv++;
132
133 if (argc) {
134 fprintf(stderr, "too many arguments\n");
135 return -1;
136 }
137
138 msg = nlmsg_alloc();
139 if (!msg)
140 goto out;
141
142 genlmsg_put(msg, 0, 0, genl_family_get_id(state->nl80211), 0,
143 0, NL80211_CMD_GET_MPATH, 0);
144
145 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, dst);
146 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(dev));
147
148 cb = nl_cb_alloc(NL_CB_CUSTOM);
149 if (!cb)
150 goto out;
151
152 if (nl_send_auto_complete(state->nl_handle, msg) < 0)
153 goto out;
154
155 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_mpath_handler, NULL);
156 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, wait_handler, &finished);
157 nl_cb_err(cb, NL_CB_CUSTOM, error_handler, NULL);
158
159 err = nl_recvmsgs(state->nl_handle, cb);
160
161 if (!finished)
162 err = nl_wait_for_ack(state->nl_handle);
163
164 if (err < 0)
165 goto out;
166
167 ret = 0;
168
169 out:
170 nl_cb_put(cb);
171 nla_put_failure:
172 nlmsg_free(msg);
173 return ret;
174 }
175
176 static int handle_mpath_set(struct nl80211_state *state, int new,
177 char *dev, int argc, char **argv)
178 {
179 struct nl_msg *msg;
180 struct nl_cb *cb = NULL;
181 int ret = -1;
182 int err, command;
183 int finished = 0;
184 unsigned char dst[ETH_ALEN];
185 unsigned char next_hop[ETH_ALEN];
186
187 if (argc < 3) {
188 fprintf(stderr, "not enough arguments\n");
189 return -1;
190 }
191
192 if (mac_addr_a2n(dst, argv[0])) {
193 fprintf(stderr, "invalid destination mac address\n");
194 return -1;
195 }
196 argc--;
197 argv++;
198
199 if (strcmp("next_hop", argv[0]) != 0) {
200 fprintf(stderr, "parameter not supported\n");
201 return -1;
202 }
203 argc--;
204 argv++;
205
206 if (mac_addr_a2n(next_hop, argv[0])) {
207 fprintf(stderr, "invalid next hop mac address\n");
208 return -1;
209 }
210 argc--;
211 argv++;
212
213 if (argc) {
214 fprintf(stderr, "too many arguments\n");
215 return -1;
216 }
217
218 msg = nlmsg_alloc();
219 if (!msg)
220 goto out;
221
222 command = new ? NL80211_CMD_NEW_MPATH : NL80211_CMD_SET_MPATH;
223 genlmsg_put(msg, 0, 0, genl_family_get_id(state->nl80211), 0, 0,
224 command, 0);
225
226 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, dst);
227 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(dev));
228 NLA_PUT(msg, NL80211_ATTR_MPATH_NEXT_HOP, ETH_ALEN, next_hop);
229
230 cb = nl_cb_alloc(NL_CB_CUSTOM);
231 if (!cb)
232 goto out;
233
234 if (nl_send_auto_complete(state->nl_handle, msg) < 0)
235 goto out;
236
237 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_mpath_handler, NULL);
238 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, wait_handler, &finished);
239 nl_cb_err(cb, NL_CB_CUSTOM, error_handler, NULL);
240
241 err = nl_recvmsgs(state->nl_handle, cb);
242
243 if (!finished)
244 err = nl_wait_for_ack(state->nl_handle);
245
246 if (err < 0)
247 goto out;
248
249 ret = 0;
250
251 out:
252 nl_cb_put(cb);
253 nla_put_failure:
254 nlmsg_free(msg);
255 return ret;
256 }
257
258 static int handle_mpath_del(struct nl80211_state *state,
259 char *dev, int argc, char **argv)
260 {
261 struct nl_msg *msg;
262 struct nl_cb *cb = NULL;
263 int ret = -1;
264 int err;
265 int finished = 0;
266 unsigned char dst[ETH_ALEN];
267
268 if (argc > 1) {
269 fprintf(stderr, "too many arguments\n");
270 return -1;
271 }
272
273 if (argc && mac_addr_a2n(dst, argv[0])) {
274 fprintf(stderr, "invalid mac address\n");
275 return -1;
276 }
277
278 msg = nlmsg_alloc();
279 if (!msg)
280 goto out;
281
282 genlmsg_put(msg, 0, 0, genl_family_get_id(state->nl80211), 0, 0,
283 NL80211_CMD_DEL_MPATH, 0);
284
285 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(dev));
286 if (argc)
287 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, dst);
288
289 cb = nl_cb_alloc(NL_CB_CUSTOM);
290 if (!cb)
291 goto out;
292
293 if (nl_send_auto_complete(state->nl_handle, msg) < 0)
294 goto out;
295
296 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_mpath_handler, NULL);
297 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, wait_handler, &finished);
298 nl_cb_err(cb, NL_CB_CUSTOM, error_handler, NULL);
299
300 err = nl_recvmsgs(state->nl_handle, cb);
301
302 if (!finished)
303 err = nl_wait_for_ack(state->nl_handle);
304
305 if (err < 0)
306 goto out;
307
308 ret = 0;
309
310 out:
311 nl_cb_put(cb);
312 nla_put_failure:
313 nlmsg_free(msg);
314 return ret;
315 }
316
317 static int handle_mpath_dump(struct nl80211_state *state,
318 char *dev, int argc, char **argv)
319 {
320 struct nl_msg *msg;
321 struct nl_cb *cb = NULL;
322 int ret = -1;
323 int err;
324 int finished = 0;
325
326 if (argc) {
327 fprintf(stderr, "too many arguments\n");
328 return -1;
329 }
330
331 msg = nlmsg_alloc();
332 if (!msg)
333 goto out;
334
335 genlmsg_put(msg, 0, 0, genl_family_get_id(state->nl80211), 0,
336 NLM_F_DUMP, NL80211_CMD_GET_MPATH, 0);
337
338 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(dev));
339
340 cb = nl_cb_alloc(NL_CB_CUSTOM);
341 if (!cb)
342 goto out;
343
344 if (nl_send_auto_complete(state->nl_handle, msg) < 0)
345 goto out;
346
347 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_mpath_handler, NULL);
348 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, wait_handler, &finished);
349
350 err = nl_recvmsgs(state->nl_handle, cb);
351
352 if (err < 0)
353 goto out;
354
355 ret = 0;
356
357 out:
358 nl_cb_put(cb);
359 nla_put_failure:
360 nlmsg_free(msg);
361 return ret;
362 }
363
364 int handle_mpath(struct nl80211_state *state,
365 char *dev, int argc, char **argv)
366 {
367 char *cmd = argv[0];
368
369 if (argc < 1) {
370 fprintf(stderr, "you must specify an mpath command\n");
371 return -1;
372 }
373
374 argc--;
375 argv++;
376
377 if (strcmp(cmd, "new") == 0)
378 return handle_mpath_set(state, 1, dev, argc, argv);
379 if (strcmp(cmd, "del") == 0)
380 return handle_mpath_del(state, dev, argc, argv);
381 if (strcmp(cmd, "get") == 0)
382 return handle_mpath_get(state, dev, argc, argv);
383 if (strcmp(cmd, "set") == 0)
384 return handle_mpath_set(state, 0, dev, argc, argv);
385 if (strcmp(cmd, "dump") == 0)
386 return handle_mpath_dump(state, dev, argc, argv);
387
388 printf("invalid interface command %s\n", cmd);
389 return -1;
390 }