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