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