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