]> git.proxmox.com Git - mirror_iproute2.git/blame - tipc/bearer.c
ll_map: Add function to remove link cache entry by index
[mirror_iproute2.git] / tipc / bearer.c
CommitLineData
f043759d
RA
1/*
2 * bearer.c TIPC bearer functionality.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 *
9 * Authors: Richard Alpe <richard.alpe@ericsson.com>
10 */
11
12#include <stdio.h>
13#include <stdlib.h>
14#include <string.h>
15#include <netdb.h>
16#include <errno.h>
ed81deab 17#include <arpa/inet.h>
f043759d
RA
18
19#include <linux/tipc_netlink.h>
20#include <linux/tipc.h>
21#include <linux/genetlink.h>
22
23#include <libmnl/libmnl.h>
24#include <sys/socket.h>
25
26#include "cmdl.h"
27#include "msg.h"
28#include "bearer.h"
29
ed81deab
RA
30#define UDP_PROP_IP 1
31#define UDP_PROP_PORT 2
32
33struct cb_data {
34 int attr;
35 int prop;
36 struct nlmsghdr *nlh;
37};
38
f043759d
RA
39static void _print_bearer_opts(void)
40{
41 fprintf(stderr,
50afc4db 42 "OPTIONS\n"
f043759d
RA
43 " priority - Bearer link priority\n"
44 " tolerance - Bearer link tolerance\n"
7d40bdbc
GM
45 " window - Bearer link window\n"
46 " mtu - Bearer link mtu\n");
f043759d
RA
47}
48
d2ba0b0b 49void print_bearer_media(void)
f043759d
RA
50{
51 fprintf(stderr,
52 "\nMEDIA\n"
53 " udp - User Datagram Protocol\n"
54 " ib - Infiniband\n"
55 " eth - Ethernet\n");
56}
57
50afc4db 58static void cmd_bearer_enable_l2_help(struct cmdl *cmdl, char *media)
f043759d
RA
59{
60 fprintf(stderr,
50afc4db 61 "Usage: %s bearer enable media %s device DEVICE [OPTIONS]\n"
f043759d
RA
62 "\nOPTIONS\n"
63 " domain DOMAIN - Discovery domain\n"
64 " priority PRIORITY - Bearer priority\n",
50afc4db 65 cmdl->argv[0], media);
f043759d
RA
66}
67
50afc4db 68static void cmd_bearer_enable_udp_help(struct cmdl *cmdl, char *media)
f043759d
RA
69{
70 fprintf(stderr,
ed81deab
RA
71 "Usage: %s bearer enable [OPTIONS] media %s name NAME localip IP [UDP OPTIONS]\n\n",
72 cmdl->argv[0], media);
73 fprintf(stderr,
74 "OPTIONS\n"
f043759d 75 " domain DOMAIN - Discovery domain\n"
ed81deab
RA
76 " priority PRIORITY - Bearer priority\n\n");
77 fprintf(stderr,
78 "UDP OPTIONS\n"
f043759d
RA
79 " localport PORT - Local UDP port (default 6118)\n"
80 " remoteip IP - Remote IP address\n"
ed81deab 81 " remoteport PORT - Remote UDP port (default 6118)\n");
f043759d
RA
82}
83
84static int get_netid_cb(const struct nlmsghdr *nlh, void *data)
85{
86 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
87 struct nlattr *info[TIPC_NLA_MAX + 1] = {};
88 struct nlattr *attrs[TIPC_NLA_NET_MAX + 1] = {};
89 int *netid = (int*)data;
90
91 mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, info);
92 if (!info[TIPC_NLA_NET])
93 return MNL_CB_ERROR;
94 mnl_attr_parse_nested(info[TIPC_NLA_NET], parse_attrs, attrs);
95 if (!attrs[TIPC_NLA_NET_ID])
96 return MNL_CB_ERROR;
97 *netid = mnl_attr_get_u32(attrs[TIPC_NLA_NET_ID]);
98
99 return MNL_CB_OK;
100}
101
102static int generate_multicast(short af, char *buf, int bufsize)
103{
104 int netid;
105 char mnl_msg[MNL_SOCKET_BUFFER_SIZE];
106 struct nlmsghdr *nlh;
107
108 if (!(nlh = msg_init(mnl_msg, TIPC_NL_NET_GET))) {
109 fprintf(stderr, "error, message initialization failed\n");
110 return -1;
111 }
112 if (msg_dumpit(nlh, get_netid_cb, &netid)) {
113 fprintf(stderr, "error, failed to fetch TIPC network id from kernel\n");
114 return -EINVAL;
115 }
116 if (af == AF_INET)
117 snprintf(buf, bufsize, "228.0.%u.%u", (netid>>8) & 0xFF, netid & 0xFF);
118 else
119 snprintf(buf, bufsize, "ff02::%u", netid);
120
121 return 0;
122}
123
50afc4db
RA
124static int nl_add_udp_enable_opts(struct nlmsghdr *nlh, struct opt *opts,
125 struct cmdl *cmdl)
f043759d
RA
126{
127 int err;
128 struct opt *opt;
129 struct nlattr *nest;
130 char buf[INET6_ADDRSTRLEN];
131 char *locport = "6118";
132 char *remport = "6118";
133 char *locip = NULL;
134 char *remip = NULL;
f043759d
RA
135 struct addrinfo *loc = NULL;
136 struct addrinfo *rem = NULL;
137 struct addrinfo hints = {
138 .ai_family = AF_UNSPEC,
139 .ai_socktype = SOCK_DGRAM
140 };
141
f043759d
RA
142 if (!(opt = get_opt(opts, "localip"))) {
143 fprintf(stderr, "error, udp bearer localip missing\n");
50afc4db 144 cmd_bearer_enable_udp_help(cmdl, "udp");
f043759d
RA
145 return -EINVAL;
146 }
147 locip = opt->val;
148
149 if ((opt = get_opt(opts, "remoteip")))
150 remip = opt->val;
151
152 if ((opt = get_opt(opts, "localport")))
153 locport = opt->val;
154
155 if ((opt = get_opt(opts, "remoteport")))
156 remport = opt->val;
157
158 if ((err = getaddrinfo(locip, locport, &hints, &loc))) {
159 fprintf(stderr, "UDP local address error: %s\n",
160 gai_strerror(err));
161 return err;
162 }
163
164 if (!remip) {
165 if (generate_multicast(loc->ai_family, buf, sizeof(buf))) {
166 fprintf(stderr, "Failed to generate multicast address\n");
be55416a 167 freeaddrinfo(loc);
f043759d
RA
168 return -EINVAL;
169 }
170 remip = buf;
171 }
172
173 if ((err = getaddrinfo(remip, remport, &hints, &rem))) {
174 fprintf(stderr, "UDP remote address error: %s\n",
175 gai_strerror(err));
176 freeaddrinfo(loc);
177 return err;
178 }
179
180 if (rem->ai_family != loc->ai_family) {
181 fprintf(stderr, "UDP local and remote AF mismatch\n");
be55416a
PS
182 freeaddrinfo(rem);
183 freeaddrinfo(loc);
f043759d
RA
184 return -EINVAL;
185 }
186
f043759d
RA
187 nest = mnl_attr_nest_start(nlh, TIPC_NLA_BEARER_UDP_OPTS);
188 mnl_attr_put(nlh, TIPC_NLA_UDP_LOCAL, loc->ai_addrlen, loc->ai_addr);
189 mnl_attr_put(nlh, TIPC_NLA_UDP_REMOTE, rem->ai_addrlen, rem->ai_addr);
190 mnl_attr_nest_end(nlh, nest);
191
192 freeaddrinfo(rem);
193 freeaddrinfo(loc);
194
195 return 0;
196}
197
7d40bdbc
GM
198static char *cmd_get_media_type(const struct cmd *cmd, struct cmdl *cmdl,
199 struct opt *opts)
200{
201 struct opt *opt = get_opt(opts, "media");
202
203 if (!opt) {
204 if (help_flag)
205 (cmd->help)(cmdl);
206 else
207 fprintf(stderr, "error, missing bearer media\n");
208 return NULL;
209 }
210 return opt->val;
211}
212
50afc4db 213static int nl_add_bearer_name(struct nlmsghdr *nlh, const struct cmd *cmd,
d2ba0b0b
PB
214 struct cmdl *cmdl, struct opt *opts,
215 const struct tipc_sup_media *sup_media)
216{
217 char bname[TIPC_MAX_BEARER_NAME];
218 int err;
219
220 if ((err = cmd_get_unique_bearer_name(cmd, cmdl, opts, bname, sup_media)))
221 return err;
222
223 mnl_attr_put_strz(nlh, TIPC_NLA_BEARER_NAME, bname);
224 return 0;
225}
226
227int cmd_get_unique_bearer_name(const struct cmd *cmd, struct cmdl *cmdl,
228 struct opt *opts, char *bname,
229 const struct tipc_sup_media *sup_media)
50afc4db 230{
50afc4db
RA
231 char *media;
232 char *identifier;
233 struct opt *opt;
d2ba0b0b
PB
234 const struct tipc_sup_media *entry;
235
7d40bdbc 236 if (!(media = cmd_get_media_type(cmd, cmdl, opts)))
50afc4db 237 return -EINVAL;
50afc4db
RA
238
239 for (entry = sup_media; entry->media; entry++) {
240 if (strcmp(entry->media, media))
241 continue;
242
243 if (!(opt = get_opt(opts, entry->identifier))) {
244 if (help_flag)
245 (entry->help)(cmdl, media);
246 else
247 fprintf(stderr, "error, missing bearer %s\n",
d2ba0b0b 248 entry->identifier);
50afc4db
RA
249 return -EINVAL;
250 }
251
252 identifier = opt->val;
d2ba0b0b 253 snprintf(bname, TIPC_MAX_BEARER_NAME, "%s:%s", media, identifier);
50afc4db
RA
254
255 return 0;
256 }
257
258 fprintf(stderr, "error, invalid media type %s\n", media);
259
260 return -EINVAL;
261}
262
f1f40cf7
RA
263static void cmd_bearer_add_udp_help(struct cmdl *cmdl, char *media)
264{
265 fprintf(stderr, "Usage: %s bearer add media %s name NAME remoteip REMOTEIP\n\n",
266 cmdl->argv[0], media);
267}
268
269static void cmd_bearer_add_help(struct cmdl *cmdl)
270{
271 fprintf(stderr, "Usage: %s bearer add media udp name NAME remoteip REMOTEIP\n",
272 cmdl->argv[0]);
273}
274
275static int udp_bearer_add(struct nlmsghdr *nlh, struct opt *opts,
276 struct cmdl *cmdl)
277{
278 int err;
279 struct opt *opt;
280 struct nlattr *opts_nest;
281 char *remport = "6118";
282
283 opts_nest = mnl_attr_nest_start(nlh, TIPC_NLA_BEARER_UDP_OPTS);
284
285 if ((opt = get_opt(opts, "remoteport")))
286 remport = opt->val;
287
288 if ((opt = get_opt(opts, "remoteip"))) {
289 char *ip = opt->val;
290 struct addrinfo *addr = NULL;
291 struct addrinfo hints = {
292 .ai_family = AF_UNSPEC,
293 .ai_socktype = SOCK_DGRAM
294 };
295
296 if ((err = getaddrinfo(ip, remport, &hints, &addr))) {
297 fprintf(stderr, "UDP address error: %s\n",
d2ba0b0b 298 gai_strerror(err));
f1f40cf7
RA
299 freeaddrinfo(addr);
300 return err;
301 }
302
303 mnl_attr_put(nlh, TIPC_NLA_UDP_REMOTE, addr->ai_addrlen,
d2ba0b0b 304 addr->ai_addr);
f1f40cf7
RA
305 freeaddrinfo(addr);
306 } else {
307 fprintf(stderr, "error, missing remoteip\n");
308 return -EINVAL;
309 }
310 mnl_attr_nest_end(nlh, opts_nest);
311
312 return 0;
313}
314
315static int cmd_bearer_add_media(struct nlmsghdr *nlh, const struct cmd *cmd,
316 struct cmdl *cmdl, void *data)
317{
318 int err;
319 char *media;
320 char buf[MNL_SOCKET_BUFFER_SIZE];
321 struct opt *opt;
322 struct nlattr *attrs;
323 struct opt opts[] = {
ed81deab
RA
324 { "remoteip", OPT_KEYVAL, NULL },
325 { "remoteport", OPT_KEYVAL, NULL },
326 { "name", OPT_KEYVAL, NULL },
327 { "media", OPT_KEYVAL, NULL },
f1f40cf7
RA
328 { NULL }
329 };
d2ba0b0b 330 const struct tipc_sup_media sup_media[] = {
f1f40cf7
RA
331 { "udp", "name", cmd_bearer_add_udp_help},
332 { NULL, },
333 };
334
335 /* Rewind optind to include media in the option list */
336 cmdl->optind--;
337 if (parse_opts(opts, cmdl) < 0)
338 return -EINVAL;
339
340 if (!(opt = get_opt(opts, "media"))) {
341 fprintf(stderr, "error, missing media value\n");
342 return -EINVAL;
343 }
344 media = opt->val;
345
346 if (strcmp(media, "udp") != 0) {
347 fprintf(stderr, "error, no \"%s\" media specific options available\n",
348 media);
349 return -EINVAL;
350 }
351 if (!(opt = get_opt(opts, "name"))) {
352 fprintf(stderr, "error, missing media name\n");
353 return -EINVAL;
354 }
355
356 if (!(nlh = msg_init(buf, TIPC_NL_BEARER_ADD))) {
357 fprintf(stderr, "error, message initialisation failed\n");
358 return -1;
359 }
360
361 attrs = mnl_attr_nest_start(nlh, TIPC_NLA_BEARER);
362 err = nl_add_bearer_name(nlh, cmd, cmdl, opts, sup_media);
363 if (err)
364 return err;
365
366 err = udp_bearer_add(nlh, opts, cmdl);
367 if (err)
368 return err;
369
370 mnl_attr_nest_end(nlh, attrs);
371
372 return msg_doit(nlh, NULL, NULL);
373}
374
375static int cmd_bearer_add(struct nlmsghdr *nlh, const struct cmd *cmd,
376 struct cmdl *cmdl, void *data)
377{
378 const struct cmd cmds[] = {
379 { "media", cmd_bearer_add_media, cmd_bearer_add_help },
380 { NULL }
381 };
382
383 return run_cmd(nlh, cmd, cmds, cmdl, NULL);
384}
385
f043759d
RA
386static void cmd_bearer_enable_help(struct cmdl *cmdl)
387{
388 fprintf(stderr,
389 "Usage: %s bearer enable [OPTIONS] media MEDIA ARGS...\n\n"
390 "OPTIONS\n"
391 " domain DOMAIN - Discovery domain\n"
392 " priority PRIORITY - Bearer priority\n",
393 cmdl->argv[0]);
d2ba0b0b 394 print_bearer_media();
f043759d
RA
395}
396
397static int cmd_bearer_enable(struct nlmsghdr *nlh, const struct cmd *cmd,
398 struct cmdl *cmdl, void *data)
399{
400 int err;
401 struct opt *opt;
402 struct nlattr *nest;
403 char buf[MNL_SOCKET_BUFFER_SIZE];
f043759d 404 struct opt opts[] = {
ed81deab
RA
405 { "device", OPT_KEYVAL, NULL },
406 { "domain", OPT_KEYVAL, NULL },
407 { "localip", OPT_KEYVAL, NULL },
408 { "localport", OPT_KEYVAL, NULL },
409 { "media", OPT_KEYVAL, NULL },
410 { "name", OPT_KEYVAL, NULL },
411 { "priority", OPT_KEYVAL, NULL },
412 { "remoteip", OPT_KEYVAL, NULL },
413 { "remoteport", OPT_KEYVAL, NULL },
f043759d
RA
414 { NULL }
415 };
50afc4db 416 struct tipc_sup_media sup_media[] = {
d2ba0b0b
PB
417 { "udp", "name", cmd_bearer_enable_udp_help},
418 { "eth", "device", cmd_bearer_enable_l2_help },
419 { "ib", "device", cmd_bearer_enable_l2_help },
50afc4db
RA
420 { NULL, },
421 };
f043759d
RA
422
423 if (parse_opts(opts, cmdl) < 0) {
424 if (help_flag)
425 (cmd->help)(cmdl);
426 return -EINVAL;
427 }
428
f043759d
RA
429 if (!(nlh = msg_init(buf, TIPC_NL_BEARER_ENABLE))) {
430 fprintf(stderr, "error: message initialisation failed\n");
431 return -1;
432 }
433 nest = mnl_attr_nest_start(nlh, TIPC_NLA_BEARER);
434
435 if ((opt = get_opt(opts, "domain")))
436 mnl_attr_put_u32(nlh, TIPC_NLA_BEARER_DOMAIN, atoi(opt->val));
437
438 if ((opt = get_opt(opts, "priority"))) {
439 struct nlattr *props;
440
441 props = mnl_attr_nest_start(nlh, TIPC_NLA_BEARER_PROP);
442 mnl_attr_put_u32(nlh, TIPC_NLA_PROP_PRIO, atoi(opt->val));
443 mnl_attr_nest_end(nlh, props);
444 }
445
50afc4db
RA
446 err = nl_add_bearer_name(nlh, cmd, cmdl, opts, sup_media);
447 if (err)
448 return err;
449
450 opt = get_opt(opts, "media");
70a6df39 451 if (opt && strcmp(opt->val, "udp") == 0) {
50afc4db
RA
452 err = nl_add_udp_enable_opts(nlh, opts, cmdl);
453 if (err)
f043759d 454 return err;
f043759d 455 }
f043759d
RA
456 mnl_attr_nest_end(nlh, nest);
457
458 return msg_doit(nlh, NULL, NULL);
459}
460
50afc4db 461static void cmd_bearer_disable_l2_help(struct cmdl *cmdl, char *media)
f043759d 462{
50afc4db
RA
463 fprintf(stderr, "Usage: %s bearer disable media %s device DEVICE\n",
464 cmdl->argv[0], media);
f043759d
RA
465}
466
50afc4db 467static void cmd_bearer_disable_udp_help(struct cmdl *cmdl, char *media)
f043759d 468{
50afc4db
RA
469 fprintf(stderr, "Usage: %s bearer disable media %s name NAME\n",
470 cmdl->argv[0], media);
f043759d
RA
471}
472
473static void cmd_bearer_disable_help(struct cmdl *cmdl)
474{
475 fprintf(stderr, "Usage: %s bearer disable media MEDIA ARGS...\n",
476 cmdl->argv[0]);
d2ba0b0b 477 print_bearer_media();
f043759d
RA
478}
479
480static int cmd_bearer_disable(struct nlmsghdr *nlh, const struct cmd *cmd,
481 struct cmdl *cmdl, void *data)
482{
483 int err;
f043759d
RA
484 char buf[MNL_SOCKET_BUFFER_SIZE];
485 struct nlattr *nest;
f043759d 486 struct opt opts[] = {
ed81deab
RA
487 { "device", OPT_KEYVAL, NULL },
488 { "name", OPT_KEYVAL, NULL },
489 { "media", OPT_KEYVAL, NULL },
f043759d
RA
490 { NULL }
491 };
50afc4db 492 struct tipc_sup_media sup_media[] = {
d2ba0b0b
PB
493 { "udp", "name", cmd_bearer_disable_udp_help},
494 { "eth", "device", cmd_bearer_disable_l2_help },
495 { "ib", "device", cmd_bearer_disable_l2_help },
50afc4db
RA
496 { NULL, },
497 };
f043759d
RA
498
499 if (parse_opts(opts, cmdl) < 0) {
500 if (help_flag)
501 (cmd->help)(cmdl);
502 return -EINVAL;
503 }
504
f043759d
RA
505 if (!(nlh = msg_init(buf, TIPC_NL_BEARER_DISABLE))) {
506 fprintf(stderr, "error, message initialisation failed\n");
507 return -1;
508 }
509
510 nest = mnl_attr_nest_start(nlh, TIPC_NLA_BEARER);
50afc4db
RA
511 err = nl_add_bearer_name(nlh, cmd, cmdl, opts, sup_media);
512 if (err)
513 return err;
f043759d
RA
514 mnl_attr_nest_end(nlh, nest);
515
516 return msg_doit(nlh, NULL, NULL);
517
518}
519
520static void cmd_bearer_set_help(struct cmdl *cmdl)
521{
ee262ed2 522 fprintf(stderr, "Usage: %s bearer set OPTION media MEDIA ARGS...\n",
f043759d
RA
523 cmdl->argv[0]);
524 _print_bearer_opts();
d2ba0b0b 525 print_bearer_media();
f043759d
RA
526}
527
50afc4db 528static void cmd_bearer_set_udp_help(struct cmdl *cmdl, char *media)
f043759d 529{
50afc4db
RA
530 fprintf(stderr, "Usage: %s bearer set OPTION media %s name NAME\n\n",
531 cmdl->argv[0], media);
f043759d
RA
532 _print_bearer_opts();
533}
534
535static void cmd_bearer_set_l2_help(struct cmdl *cmdl, char *media)
536{
537 fprintf(stderr,
538 "Usage: %s bearer set [OPTION]... media %s device DEVICE\n",
539 cmdl->argv[0], media);
540 _print_bearer_opts();
541}
542
543static int cmd_bearer_set_prop(struct nlmsghdr *nlh, const struct cmd *cmd,
d2ba0b0b 544 struct cmdl *cmdl, void *data)
f043759d
RA
545{
546 int err;
547 int val;
548 int prop;
f043759d
RA
549 char buf[MNL_SOCKET_BUFFER_SIZE];
550 struct nlattr *props;
551 struct nlattr *attrs;
f043759d 552 struct opt opts[] = {
ed81deab
RA
553 { "device", OPT_KEYVAL, NULL },
554 { "media", OPT_KEYVAL, NULL },
555 { "name", OPT_KEYVAL, NULL },
f043759d
RA
556 { NULL }
557 };
50afc4db 558 struct tipc_sup_media sup_media[] = {
d2ba0b0b
PB
559 { "udp", "name", cmd_bearer_set_udp_help},
560 { "eth", "device", cmd_bearer_set_l2_help },
561 { "ib", "device", cmd_bearer_set_l2_help },
50afc4db
RA
562 { NULL, },
563 };
f043759d
RA
564
565 if (strcmp(cmd->cmd, "priority") == 0)
566 prop = TIPC_NLA_PROP_PRIO;
567 else if ((strcmp(cmd->cmd, "tolerance") == 0))
568 prop = TIPC_NLA_PROP_TOL;
569 else if ((strcmp(cmd->cmd, "window") == 0))
570 prop = TIPC_NLA_PROP_WIN;
7d40bdbc
GM
571 else if ((strcmp(cmd->cmd, "mtu") == 0))
572 prop = TIPC_NLA_PROP_MTU;
f043759d
RA
573 else
574 return -EINVAL;
575
f043759d
RA
576 if (cmdl->optind >= cmdl->argc) {
577 fprintf(stderr, "error, missing value\n");
578 return -EINVAL;
579 }
580 val = atoi(shift_cmdl(cmdl));
581
582 if (parse_opts(opts, cmdl) < 0)
583 return -EINVAL;
584
7d40bdbc
GM
585 if (prop == TIPC_NLA_PROP_MTU) {
586 char *media = cmd_get_media_type(cmd, cmdl, opts);
587
588 if (!media)
589 return -EINVAL;
590 else if (strcmp(media, "udp")) {
591 fprintf(stderr, "error, not supported for media\n");
592 return -EINVAL;
593 }
594 }
595
f043759d
RA
596 if (!(nlh = msg_init(buf, TIPC_NL_BEARER_SET))) {
597 fprintf(stderr, "error, message initialisation failed\n");
598 return -1;
599 }
600 attrs = mnl_attr_nest_start(nlh, TIPC_NLA_BEARER);
601
602 props = mnl_attr_nest_start(nlh, TIPC_NLA_BEARER_PROP);
603 mnl_attr_put_u32(nlh, prop, val);
604 mnl_attr_nest_end(nlh, props);
605
50afc4db
RA
606 err = nl_add_bearer_name(nlh, cmd, cmdl, opts, sup_media);
607 if (err)
608 return err;
f043759d 609
f043759d
RA
610 mnl_attr_nest_end(nlh, attrs);
611
612 return msg_doit(nlh, NULL, NULL);
613}
614
615static int cmd_bearer_set(struct nlmsghdr *nlh, const struct cmd *cmd,
616 struct cmdl *cmdl, void *data)
617{
618 const struct cmd cmds[] = {
619 { "priority", cmd_bearer_set_prop, cmd_bearer_set_help },
620 { "tolerance", cmd_bearer_set_prop, cmd_bearer_set_help },
621 { "window", cmd_bearer_set_prop, cmd_bearer_set_help },
7d40bdbc 622 { "mtu", cmd_bearer_set_prop, cmd_bearer_set_help },
f043759d
RA
623 { NULL }
624 };
625
626 return run_cmd(nlh, cmd, cmds, cmdl, NULL);
627}
628
629static void cmd_bearer_get_help(struct cmdl *cmdl)
630{
ed81deab 631 fprintf(stderr, "Usage: %s bearer get [OPTION] media MEDIA ARGS...\n",
f043759d
RA
632 cmdl->argv[0]);
633 _print_bearer_opts();
d2ba0b0b 634 print_bearer_media();
f043759d
RA
635}
636
50afc4db 637static void cmd_bearer_get_udp_help(struct cmdl *cmdl, char *media)
f043759d 638{
ed81deab 639 fprintf(stderr, "Usage: %s bearer get [OPTION] media %s name NAME [UDP OPTIONS]\n\n",
50afc4db 640 cmdl->argv[0], media);
ed81deab
RA
641 fprintf(stderr,
642 "UDP OPTIONS\n"
643 " remoteip - Remote ip address\n"
644 " remoteport - Remote port\n"
645 " localip - Local ip address\n"
646 " localport - Local port\n\n");
f043759d
RA
647 _print_bearer_opts();
648}
649
650static void cmd_bearer_get_l2_help(struct cmdl *cmdl, char *media)
651{
652 fprintf(stderr,
50afc4db 653 "Usage: %s bearer get OPTION media %s device DEVICE\n",
f043759d
RA
654 cmdl->argv[0], media);
655 _print_bearer_opts();
656}
657
ed81deab
RA
658
659static int bearer_dump_udp_cb(const struct nlmsghdr *nlh, void *data)
660{
661 struct sockaddr_storage *addr;
662 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
663 struct nlattr *info[TIPC_NLA_UDP_MAX + 1] = {};
664
665 mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, info);
666
667 if (!info[TIPC_NLA_UDP_REMOTE])
668 return MNL_CB_ERROR;
669
670 addr = mnl_attr_get_payload(info[TIPC_NLA_UDP_REMOTE]);
671
672 if (addr->ss_family == AF_INET) {
673 struct sockaddr_in *ipv4 = (struct sockaddr_in *) addr;
674
675 printf("%s\n", inet_ntoa(ipv4->sin_addr));
676 } else if (addr->ss_family == AF_INET6) {
677 char straddr[INET6_ADDRSTRLEN];
678 struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *) addr;
679
680 if (!inet_ntop(AF_INET6, &ipv6->sin6_addr, straddr,
d2ba0b0b 681 sizeof(straddr))) {
ed81deab
RA
682 fprintf(stderr, "error, parsing IPv6 addr\n");
683 return MNL_CB_ERROR;
684 }
685 printf("%s\n", straddr);
686
687 } else {
688 return MNL_CB_ERROR;
689 }
690
691 return MNL_CB_OK;
692}
693
694static int bearer_get_udp_cb(const struct nlmsghdr *nlh, void *data)
695{
696 struct cb_data *cb_data = (struct cb_data *) data;
697 struct sockaddr_storage *addr;
698 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
699 struct nlattr *info[TIPC_NLA_MAX + 1] = {};
700 struct nlattr *attrs[TIPC_NLA_BEARER_MAX + 1] = {};
701 struct nlattr *opts[TIPC_NLA_UDP_MAX + 1] = {};
702
703 mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, info);
704 if (!info[TIPC_NLA_BEARER])
705 return MNL_CB_ERROR;
706
707 mnl_attr_parse_nested(info[TIPC_NLA_BEARER], parse_attrs, attrs);
708 if (!attrs[TIPC_NLA_BEARER_UDP_OPTS])
709 return MNL_CB_ERROR;
710
711 mnl_attr_parse_nested(attrs[TIPC_NLA_BEARER_UDP_OPTS], parse_attrs, opts);
712 if (!opts[TIPC_NLA_UDP_LOCAL])
713 return MNL_CB_ERROR;
714
715 if ((cb_data->attr == TIPC_NLA_UDP_REMOTE) &&
716 (cb_data->prop == UDP_PROP_IP) &&
717 opts[TIPC_NLA_UDP_MULTI_REMOTEIP]) {
718 struct genlmsghdr *genl = mnl_nlmsg_get_payload(cb_data->nlh);
719
720 genl->cmd = TIPC_NL_UDP_GET_REMOTEIP;
721 return msg_dumpit(cb_data->nlh, bearer_dump_udp_cb, NULL);
722 }
723
724 addr = mnl_attr_get_payload(opts[cb_data->attr]);
725
726 if (addr->ss_family == AF_INET) {
727 struct sockaddr_in *ipv4 = (struct sockaddr_in *) addr;
728
729 switch (cb_data->prop) {
730 case UDP_PROP_IP:
731 printf("%s\n", inet_ntoa(ipv4->sin_addr));
732 break;
733 case UDP_PROP_PORT:
734 printf("%u\n", ntohs(ipv4->sin_port));
735 break;
736 default:
737 return MNL_CB_ERROR;
738 }
739
740 } else if (addr->ss_family == AF_INET6) {
741 char straddr[INET6_ADDRSTRLEN];
742 struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *) addr;
743
744 switch (cb_data->prop) {
745 case UDP_PROP_IP:
746 if (!inet_ntop(AF_INET6, &ipv6->sin6_addr, straddr,
d2ba0b0b 747 sizeof(straddr))) {
ed81deab
RA
748 fprintf(stderr, "error, parsing IPv6 addr\n");
749 return MNL_CB_ERROR;
750 }
751 printf("%s\n", straddr);
752 break;
753 case UDP_PROP_PORT:
754 printf("%u\n", ntohs(ipv6->sin6_port));
755 break;
756 default:
757 return MNL_CB_ERROR;
758 }
759
760 } else {
761 return MNL_CB_ERROR;
762 }
763
764 return MNL_CB_OK;
765}
766
f043759d
RA
767static int bearer_get_cb(const struct nlmsghdr *nlh, void *data)
768{
769 int *prop = data;
770 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
771 struct nlattr *info[TIPC_NLA_MAX + 1] = {};
772 struct nlattr *attrs[TIPC_NLA_BEARER_MAX + 1] = {};
773 struct nlattr *props[TIPC_NLA_PROP_MAX + 1] = {};
774
775 mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, info);
776 if (!info[TIPC_NLA_BEARER])
777 return MNL_CB_ERROR;
778
779 mnl_attr_parse_nested(info[TIPC_NLA_BEARER], parse_attrs, attrs);
780 if (!attrs[TIPC_NLA_BEARER_PROP])
781 return MNL_CB_ERROR;
782
783 mnl_attr_parse_nested(attrs[TIPC_NLA_BEARER_PROP], parse_attrs, props);
784 if (!props[*prop])
785 return MNL_CB_ERROR;
786
787 printf("%u\n", mnl_attr_get_u32(props[*prop]));
788
789 return MNL_CB_OK;
790}
791
ed81deab
RA
792static int cmd_bearer_get_media(struct nlmsghdr *nlh, const struct cmd *cmd,
793 struct cmdl *cmdl, void *data)
794{
795 int err;
796 char *media;
797 char buf[MNL_SOCKET_BUFFER_SIZE];
798 struct opt *opt;
799 struct cb_data cb_data = {0};
800 struct nlattr *attrs;
801 struct opt opts[] = {
802 { "localip", OPT_KEY, NULL },
803 { "localport", OPT_KEY, NULL },
804 { "remoteip", OPT_KEY, NULL },
805 { "remoteport", OPT_KEY, NULL },
806 { "name", OPT_KEYVAL, NULL },
807 { "media", OPT_KEYVAL, NULL },
808 { NULL }
809 };
810 struct tipc_sup_media sup_media[] = {
d2ba0b0b 811 { "udp", "name", cmd_bearer_get_udp_help},
ed81deab
RA
812 { NULL, },
813 };
814
815 /* Rewind optind to include media in the option list */
816 cmdl->optind--;
817 if (parse_opts(opts, cmdl) < 0)
818 return -EINVAL;
819
820 if (!(opt = get_opt(opts, "media"))) {
821 fprintf(stderr, "error, missing media value\n");
822 return -EINVAL;
823 }
824 media = opt->val;
825
826 if (help_flag) {
827 cmd_bearer_get_udp_help(cmdl, media);
828 return -EINVAL;
829 }
830 if (strcmp(media, "udp") != 0) {
831 fprintf(stderr, "error, no \"%s\" media specific options\n", media);
832 return -EINVAL;
833 }
834 if (!(opt = get_opt(opts, "name"))) {
835 fprintf(stderr, "error, missing media name\n");
836 return -EINVAL;
837 }
838
839 if (!(nlh = msg_init(buf, TIPC_NL_BEARER_GET))) {
840 fprintf(stderr, "error, message initialisation failed\n");
841 return -1;
842 }
843
844 attrs = mnl_attr_nest_start(nlh, TIPC_NLA_BEARER);
845 err = nl_add_bearer_name(nlh, cmd, cmdl, opts, sup_media);
846 if (err)
847 return err;
848 mnl_attr_nest_end(nlh, attrs);
849 cb_data.nlh = nlh;
850
851 if (has_opt(opts, "localip")) {
852 cb_data.attr = TIPC_NLA_UDP_LOCAL;
853 cb_data.prop = UDP_PROP_IP;
854 return msg_doit(nlh, bearer_get_udp_cb, &cb_data);
855 } else if (has_opt(opts, "localport")) {
856 cb_data.attr = TIPC_NLA_UDP_LOCAL;
857 cb_data.prop = UDP_PROP_PORT;
858 return msg_doit(nlh, bearer_get_udp_cb, &cb_data);
859 } else if (has_opt(opts, "remoteip")) {
860 cb_data.attr = TIPC_NLA_UDP_REMOTE;
861 cb_data.prop = UDP_PROP_IP;
862 return msg_doit(nlh, bearer_get_udp_cb, &cb_data);
863 } else if (has_opt(opts, "remoteport")) {
864 cb_data.attr = TIPC_NLA_UDP_REMOTE;
865 cb_data.prop = UDP_PROP_PORT;
866 return msg_doit(nlh, bearer_get_udp_cb, &cb_data);
867 }
868 fprintf(stderr, "error, missing UDP option\n");
869 return -EINVAL;
870}
871
f043759d
RA
872static int cmd_bearer_get_prop(struct nlmsghdr *nlh, const struct cmd *cmd,
873 struct cmdl *cmdl, void *data)
874{
875 int err;
876 int prop;
f043759d
RA
877 char buf[MNL_SOCKET_BUFFER_SIZE];
878 struct nlattr *attrs;
f043759d 879 struct opt opts[] = {
ed81deab
RA
880 { "device", OPT_KEYVAL, NULL },
881 { "media", OPT_KEYVAL, NULL },
882 { "name", OPT_KEYVAL, NULL },
f043759d
RA
883 { NULL }
884 };
50afc4db 885 struct tipc_sup_media sup_media[] = {
d2ba0b0b
PB
886 { "udp", "name", cmd_bearer_get_udp_help},
887 { "eth", "device", cmd_bearer_get_l2_help },
888 { "ib", "device", cmd_bearer_get_l2_help },
50afc4db
RA
889 { NULL, },
890 };
f043759d 891
ed81deab
RA
892 if (help_flag) {
893 (cmd->help)(cmdl);
894 return -EINVAL;
895 }
896
f043759d
RA
897 if (strcmp(cmd->cmd, "priority") == 0)
898 prop = TIPC_NLA_PROP_PRIO;
899 else if ((strcmp(cmd->cmd, "tolerance") == 0))
900 prop = TIPC_NLA_PROP_TOL;
901 else if ((strcmp(cmd->cmd, "window") == 0))
902 prop = TIPC_NLA_PROP_WIN;
7d40bdbc
GM
903 else if ((strcmp(cmd->cmd, "mtu") == 0))
904 prop = TIPC_NLA_PROP_MTU;
f043759d
RA
905 else
906 return -EINVAL;
907
f043759d
RA
908 if (parse_opts(opts, cmdl) < 0)
909 return -EINVAL;
910
7d40bdbc
GM
911 if (prop == TIPC_NLA_PROP_MTU) {
912 char *media = cmd_get_media_type(cmd, cmdl, opts);
913
914 if (!media)
915 return -EINVAL;
916 else if (strcmp(media, "udp")) {
917 fprintf(stderr, "error, not supported for media\n");
918 return -EINVAL;
919 }
920 }
921
f043759d
RA
922 if (!(nlh = msg_init(buf, TIPC_NL_BEARER_GET))) {
923 fprintf(stderr, "error, message initialisation failed\n");
924 return -1;
925 }
926
f043759d 927 attrs = mnl_attr_nest_start(nlh, TIPC_NLA_BEARER);
50afc4db
RA
928 err = nl_add_bearer_name(nlh, cmd, cmdl, opts, sup_media);
929 if (err)
930 return err;
f043759d
RA
931 mnl_attr_nest_end(nlh, attrs);
932
933 return msg_doit(nlh, bearer_get_cb, &prop);
934}
935
936static int cmd_bearer_get(struct nlmsghdr *nlh, const struct cmd *cmd,
937 struct cmdl *cmdl, void *data)
938{
939 const struct cmd cmds[] = {
940 { "priority", cmd_bearer_get_prop, cmd_bearer_get_help },
941 { "tolerance", cmd_bearer_get_prop, cmd_bearer_get_help },
942 { "window", cmd_bearer_get_prop, cmd_bearer_get_help },
7d40bdbc 943 { "mtu", cmd_bearer_get_prop, cmd_bearer_get_help },
ed81deab 944 { "media", cmd_bearer_get_media, cmd_bearer_get_help },
f043759d
RA
945 { NULL }
946 };
947
948 return run_cmd(nlh, cmd, cmds, cmdl, NULL);
949}
950
951static int bearer_list_cb(const struct nlmsghdr *nlh, void *data)
952{
953 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
954 struct nlattr *info[TIPC_NLA_MAX + 1] = {};
955 struct nlattr *attrs[TIPC_NLA_BEARER_MAX + 1] = {};
956
957 mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, info);
958 if (!info[TIPC_NLA_BEARER]) {
959 fprintf(stderr, "No bearer in netlink response\n");
960 return MNL_CB_ERROR;
961 }
962
963 mnl_attr_parse_nested(info[TIPC_NLA_BEARER], parse_attrs, attrs);
964 if (!attrs[TIPC_NLA_BEARER_NAME]) {
965 fprintf(stderr, "Bearer name missing in netlink response\n");
966 return MNL_CB_ERROR;
967 }
968
969 printf("%s\n", mnl_attr_get_str(attrs[TIPC_NLA_BEARER_NAME]));
970
971 return MNL_CB_OK;
972}
973
974static int cmd_bearer_list(struct nlmsghdr *nlh, const struct cmd *cmd,
975 struct cmdl *cmdl, void *data)
976{
977 char buf[MNL_SOCKET_BUFFER_SIZE];
978
979 if (help_flag) {
980 fprintf(stderr, "Usage: %s bearer list\n", cmdl->argv[0]);
981 return -EINVAL;
982 }
983
984 if (!(nlh = msg_init(buf, TIPC_NL_BEARER_GET))) {
985 fprintf(stderr, "error, message initialisation failed\n");
986 return -1;
987 }
988
989 return msg_dumpit(nlh, bearer_list_cb, NULL);
990}
991
992void cmd_bearer_help(struct cmdl *cmdl)
993{
994 fprintf(stderr,
995 "Usage: %s bearer COMMAND [ARGS] ...\n"
996 "\n"
997 "COMMANDS\n"
f1f40cf7 998 " add - Add data to existing bearer\n"
f043759d
RA
999 " enable - Enable a bearer\n"
1000 " disable - Disable a bearer\n"
1001 " set - Set various bearer properties\n"
1002 " get - Get various bearer properties\n"
1003 " list - List bearers\n", cmdl->argv[0]);
1004}
1005
1006int cmd_bearer(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl,
1007 void *data)
1008{
1009 const struct cmd cmds[] = {
f1f40cf7 1010 { "add", cmd_bearer_add, cmd_bearer_add_help },
f043759d
RA
1011 { "disable", cmd_bearer_disable, cmd_bearer_disable_help },
1012 { "enable", cmd_bearer_enable, cmd_bearer_enable_help },
1013 { "get", cmd_bearer_get, cmd_bearer_get_help },
1014 { "list", cmd_bearer_list, NULL },
1015 { "set", cmd_bearer_set, cmd_bearer_set_help },
1016 { NULL }
1017 };
1018
1019 return run_cmd(nlh, cmd, cmds, cmdl, NULL);
1020}