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