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