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