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