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