• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
18 #include <linux/tipc_netlink.h>
19 #include <linux/tipc.h>
20 #include <linux/genetlink.h>
21 
22 #include <libmnl/libmnl.h>
23 #include <sys/socket.h>
24 
25 #include "cmdl.h"
26 #include "msg.h"
27 #include "bearer.h"
28 
_print_bearer_opts(void)29 static void _print_bearer_opts(void)
30 {
31 	fprintf(stderr,
32 		"\nOPTIONS\n"
33 		" priority              - Bearer link priority\n"
34 		" tolerance             - Bearer link tolerance\n"
35 		" window                - Bearer link window\n");
36 }
37 
_print_bearer_media(void)38 static void _print_bearer_media(void)
39 {
40 	fprintf(stderr,
41 		"\nMEDIA\n"
42 		" udp                   - User Datagram Protocol\n"
43 		" ib                    - Infiniband\n"
44 		" eth                   - Ethernet\n");
45 }
46 
cmd_bearer_enable_l2_help(struct cmdl * cmdl)47 static void cmd_bearer_enable_l2_help(struct cmdl *cmdl)
48 {
49 	fprintf(stderr,
50 		"Usage: %s bearer enable media MEDIA device DEVICE [OPTIONS]\n"
51 		"\nOPTIONS\n"
52 		" domain DOMAIN         - Discovery domain\n"
53 		" priority PRIORITY     - Bearer priority\n",
54 		cmdl->argv[0]);
55 }
56 
cmd_bearer_enable_udp_help(struct cmdl * cmdl)57 static void cmd_bearer_enable_udp_help(struct cmdl *cmdl)
58 {
59 	fprintf(stderr,
60 		"Usage: %s bearer enable media udp name NAME localip IP [OPTIONS]\n"
61 		"\nOPTIONS\n"
62 		" domain DOMAIN         - Discovery domain\n"
63 		" priority PRIORITY     - Bearer priority\n"
64 		" localport PORT        - Local UDP port (default 6118)\n"
65 		" remoteip IP           - Remote IP address\n"
66 		" remoteport IP         - Remote UDP port (default 6118)\n",
67 		cmdl->argv[0]);
68 }
69 
enable_l2_bearer(struct nlmsghdr * nlh,struct opt * opts,struct cmdl * cmdl)70 static int enable_l2_bearer(struct nlmsghdr *nlh, struct opt *opts,
71 			    struct cmdl *cmdl)
72 {
73 	struct opt *opt;
74 	char id[TIPC_MAX_BEARER_NAME];
75 
76 	if (!(opt = get_opt(opts, "device"))) {
77 		fprintf(stderr, "error: missing bearer device\n");
78 		return -EINVAL;
79 	}
80 	snprintf(id, sizeof(id), "eth:%s", opt->val);
81 	mnl_attr_put_strz(nlh, TIPC_NLA_BEARER_NAME, id);
82 
83 	return 0;
84 }
85 
get_netid_cb(const struct nlmsghdr * nlh,void * data)86 static int get_netid_cb(const struct nlmsghdr *nlh, void *data)
87 {
88 	struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
89 	struct nlattr *info[TIPC_NLA_MAX + 1] = {};
90 	struct nlattr *attrs[TIPC_NLA_NET_MAX + 1] = {};
91 	int *netid = (int*)data;
92 
93 	mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, info);
94 	if (!info[TIPC_NLA_NET])
95 		return MNL_CB_ERROR;
96 	mnl_attr_parse_nested(info[TIPC_NLA_NET], parse_attrs, attrs);
97 	if (!attrs[TIPC_NLA_NET_ID])
98 		return MNL_CB_ERROR;
99 	*netid = mnl_attr_get_u32(attrs[TIPC_NLA_NET_ID]);
100 
101 	return MNL_CB_OK;
102 }
103 
generate_multicast(short af,char * buf,int bufsize)104 static int generate_multicast(short af, char *buf, int bufsize)
105 {
106 	int netid;
107 	char mnl_msg[MNL_SOCKET_BUFFER_SIZE];
108 	struct nlmsghdr *nlh;
109 
110 	if (!(nlh = msg_init(mnl_msg, TIPC_NL_NET_GET))) {
111 		fprintf(stderr, "error, message initialization failed\n");
112 		return -1;
113 	}
114 	if (msg_dumpit(nlh, get_netid_cb, &netid)) {
115 		fprintf(stderr, "error, failed to fetch TIPC network id from kernel\n");
116 		return -EINVAL;
117 	}
118 	if (af == AF_INET)
119 		snprintf(buf, bufsize, "228.0.%u.%u", (netid>>8) & 0xFF, netid & 0xFF);
120 	else
121 		snprintf(buf, bufsize, "ff02::%u", netid);
122 
123 	return 0;
124 }
125 
enable_udp_bearer(struct nlmsghdr * nlh,struct opt * opts,struct cmdl * cmdl)126 static int enable_udp_bearer(struct nlmsghdr *nlh, struct opt *opts,
127 			     struct cmdl *cmdl)
128 {
129 	int err;
130 	struct opt *opt;
131 	struct nlattr *nest;
132 	char buf[INET6_ADDRSTRLEN];
133 	char *locport = "6118";
134 	char *remport = "6118";
135 	char *locip = NULL;
136 	char *remip = NULL;
137 	char name[TIPC_MAX_BEARER_NAME];
138 	struct addrinfo *loc = NULL;
139 	struct addrinfo *rem = NULL;
140 	struct addrinfo hints = {
141 		.ai_family = AF_UNSPEC,
142 		.ai_socktype = SOCK_DGRAM
143 	};
144 
145 	if (help_flag) {
146 		cmd_bearer_enable_udp_help(cmdl);
147 		/* TODO find a better error code? */
148 		return -EINVAL;
149 	}
150 
151 	if (!(opt = get_opt(opts, "name"))) {
152 		fprintf(stderr, "error, udp bearer name missing\n");
153 		cmd_bearer_enable_udp_help(cmdl);
154 		return -EINVAL;
155 	}
156 	snprintf(name, sizeof(name), "udp:%s", opt->val);
157 
158 	if (!(opt = get_opt(opts, "localip"))) {
159 		fprintf(stderr, "error, udp bearer localip missing\n");
160 		cmd_bearer_enable_udp_help(cmdl);
161 		return -EINVAL;
162 	}
163 	locip = opt->val;
164 
165 	if ((opt = get_opt(opts, "remoteip")))
166 		remip = opt->val;
167 
168 	if ((opt = get_opt(opts, "localport")))
169 		locport = opt->val;
170 
171 	if ((opt = get_opt(opts, "remoteport")))
172 		remport = opt->val;
173 
174 	if ((err = getaddrinfo(locip, locport, &hints, &loc))) {
175 		fprintf(stderr, "UDP local address error: %s\n",
176 			gai_strerror(err));
177 		return err;
178 	}
179 
180 	if (!remip) {
181 		if (generate_multicast(loc->ai_family, buf, sizeof(buf))) {
182 			fprintf(stderr, "Failed to generate multicast address\n");
183 			return -EINVAL;
184 		}
185 		remip = buf;
186 	}
187 
188 	if ((err = getaddrinfo(remip, remport, &hints, &rem))) {
189 		fprintf(stderr, "UDP remote address error: %s\n",
190 			gai_strerror(err));
191 		freeaddrinfo(loc);
192 		return err;
193 	}
194 
195 	if (rem->ai_family != loc->ai_family) {
196 		fprintf(stderr, "UDP local and remote AF mismatch\n");
197 		return -EINVAL;
198 	}
199 
200 	mnl_attr_put_strz(nlh, TIPC_NLA_BEARER_NAME, name);
201 
202 	nest = mnl_attr_nest_start(nlh, TIPC_NLA_BEARER_UDP_OPTS);
203 	mnl_attr_put(nlh, TIPC_NLA_UDP_LOCAL, loc->ai_addrlen, loc->ai_addr);
204 	mnl_attr_put(nlh, TIPC_NLA_UDP_REMOTE, rem->ai_addrlen, rem->ai_addr);
205 	mnl_attr_nest_end(nlh, nest);
206 
207 	freeaddrinfo(rem);
208 	freeaddrinfo(loc);
209 
210 	return 0;
211 }
212 
cmd_bearer_enable_help(struct cmdl * cmdl)213 static void cmd_bearer_enable_help(struct cmdl *cmdl)
214 {
215 	fprintf(stderr,
216 		"Usage: %s bearer enable [OPTIONS] media MEDIA ARGS...\n\n"
217 		"OPTIONS\n"
218 		" domain DOMAIN         - Discovery domain\n"
219 		" priority PRIORITY     - Bearer priority\n",
220 		cmdl->argv[0]);
221 	_print_bearer_media();
222 }
223 
cmd_bearer_enable(struct nlmsghdr * nlh,const struct cmd * cmd,struct cmdl * cmdl,void * data)224 static int cmd_bearer_enable(struct nlmsghdr *nlh, const struct cmd *cmd,
225 			     struct cmdl *cmdl, void *data)
226 {
227 	int err;
228 	struct opt *opt;
229 	struct nlattr *nest;
230 	char buf[MNL_SOCKET_BUFFER_SIZE];
231 	char *media;
232 	struct opt opts[] = {
233 		{ "device",		NULL },
234 		{ "domain",		NULL },
235 		{ "localip",		NULL },
236 		{ "localport",		NULL },
237 		{ "media",		NULL },
238 		{ "name",		NULL },
239 		{ "priority",		NULL },
240 		{ "remoteip",		NULL },
241 		{ "remoteport",		NULL },
242 		{ NULL }
243 	};
244 
245 	if (parse_opts(opts, cmdl) < 0) {
246 		if (help_flag)
247 			(cmd->help)(cmdl);
248 		return -EINVAL;
249 	}
250 
251 	if (!(opt = get_opt(opts, "media"))) {
252 		if (help_flag)
253 			(cmd->help)(cmdl);
254 		else
255 			fprintf(stderr, "error, missing bearer media\n");
256 		return -EINVAL;
257 	}
258 	media = opt->val;
259 
260 	if (!(nlh = msg_init(buf, TIPC_NL_BEARER_ENABLE))) {
261 		fprintf(stderr, "error: message initialisation failed\n");
262 		return -1;
263 	}
264 	nest = mnl_attr_nest_start(nlh, TIPC_NLA_BEARER);
265 
266 	if ((opt = get_opt(opts, "domain")))
267 		mnl_attr_put_u32(nlh, TIPC_NLA_BEARER_DOMAIN, atoi(opt->val));
268 
269 	if ((opt = get_opt(opts, "priority"))) {
270 		struct nlattr *props;
271 
272 		props = mnl_attr_nest_start(nlh, TIPC_NLA_BEARER_PROP);
273 		mnl_attr_put_u32(nlh, TIPC_NLA_PROP_PRIO, atoi(opt->val));
274 		mnl_attr_nest_end(nlh, props);
275 	}
276 
277 	if (strcmp(media, "udp") == 0) {
278 		if (help_flag) {
279 			cmd_bearer_enable_udp_help(cmdl);
280 			return -EINVAL;
281 		}
282 		if ((err = enable_udp_bearer(nlh, opts, cmdl)))
283 			return err;
284 	} else if ((strcmp(media, "eth") == 0) || (strcmp(media, "udp") == 0)) {
285 		if (help_flag) {
286 			cmd_bearer_enable_l2_help(cmdl);
287 			return -EINVAL;
288 		}
289 		if ((err = enable_l2_bearer(nlh, opts, cmdl)))
290 			return err;
291 	} else {
292 		fprintf(stderr, "error, invalid media type \"%s\"\n", media);
293 		return -EINVAL;
294 	}
295 
296 	mnl_attr_nest_end(nlh, nest);
297 
298 	return msg_doit(nlh, NULL, NULL);
299 }
300 
add_l2_bearer(struct nlmsghdr * nlh,struct opt * opts)301 static int add_l2_bearer(struct nlmsghdr *nlh, struct opt *opts)
302 {
303 	struct opt *opt;
304 	char id[TIPC_MAX_BEARER_NAME];
305 
306 	if (!(opt = get_opt(opts, "device"))) {
307 		fprintf(stderr, "error: missing bearer device\n");
308 		return -EINVAL;
309 	}
310 	snprintf(id, sizeof(id), "eth:%s", opt->val);
311 
312 	mnl_attr_put_strz(nlh, TIPC_NLA_BEARER_NAME, id);
313 
314 	return 0;
315 }
316 
add_udp_bearer(struct nlmsghdr * nlh,struct opt * opts)317 static int add_udp_bearer(struct nlmsghdr *nlh, struct opt *opts)
318 {
319 	struct opt *opt;
320 	char id[TIPC_MAX_BEARER_NAME];
321 
322 	if (!(opt = get_opt(opts, "name"))) {
323 		fprintf(stderr, "error: missing bearer name\n");
324 		return -EINVAL;
325 	}
326 	snprintf(id, sizeof(id), "udp:%s", opt->val);
327 
328 	mnl_attr_put_strz(nlh, TIPC_NLA_BEARER_NAME, id);
329 
330 	return 0;
331 }
332 
cmd_bearer_disable_l2_help(struct cmdl * cmdl)333 static void cmd_bearer_disable_l2_help(struct cmdl *cmdl)
334 {
335 	fprintf(stderr, "Usage: %s bearer disable media udp device DEVICE\n",
336 		cmdl->argv[0]);
337 }
338 
cmd_bearer_disable_udp_help(struct cmdl * cmdl)339 static void cmd_bearer_disable_udp_help(struct cmdl *cmdl)
340 {
341 	fprintf(stderr, "Usage: %s bearer disable media udp name NAME\n",
342 		cmdl->argv[0]);
343 }
344 
cmd_bearer_disable_help(struct cmdl * cmdl)345 static void cmd_bearer_disable_help(struct cmdl *cmdl)
346 {
347 	fprintf(stderr, "Usage: %s bearer disable media MEDIA ARGS...\n",
348 		cmdl->argv[0]);
349 	_print_bearer_media();
350 }
351 
cmd_bearer_disable(struct nlmsghdr * nlh,const struct cmd * cmd,struct cmdl * cmdl,void * data)352 static int cmd_bearer_disable(struct nlmsghdr *nlh, const struct cmd *cmd,
353 			      struct cmdl *cmdl, void *data)
354 {
355 	int err;
356 	char *media;
357 	char buf[MNL_SOCKET_BUFFER_SIZE];
358 	struct nlattr *nest;
359 	struct opt *opt;
360 	struct opt opts[] = {
361 		{ "device",		NULL },
362 		{ "name",		NULL },
363 		{ "media",		NULL },
364 		{ NULL }
365 	};
366 
367 	if (parse_opts(opts, cmdl) < 0) {
368 		if (help_flag)
369 			(cmd->help)(cmdl);
370 		return -EINVAL;
371 	}
372 
373 	if (!(opt = get_opt(opts, "media"))) {
374 		if (help_flag)
375 			(cmd->help)(cmdl);
376 		else
377 			fprintf(stderr, "error, missing bearer media\n");
378 		return -EINVAL;
379 	}
380 	media = opt->val;
381 
382 	if (!(nlh = msg_init(buf, TIPC_NL_BEARER_DISABLE))) {
383 		fprintf(stderr, "error, message initialisation failed\n");
384 		return -1;
385 	}
386 
387 	nest = mnl_attr_nest_start(nlh, TIPC_NLA_BEARER);
388 
389 	if (strcmp(media, "udp") == 0) {
390 		if (help_flag) {
391 			cmd_bearer_disable_udp_help(cmdl);
392 			return -EINVAL;
393 		}
394 		if ((err = add_udp_bearer(nlh, opts)))
395 			return err;
396 	} else if ((strcmp(media, "eth") == 0) || (strcmp(media, "udp") == 0)) {
397 		if (help_flag) {
398 			cmd_bearer_disable_l2_help(cmdl);
399 			return -EINVAL;
400 		}
401 		if ((err = add_l2_bearer(nlh, opts)))
402 			return err;
403 	} else {
404 		fprintf(stderr, "error, invalid media type \"%s\"\n", media);
405 		return -EINVAL;
406 	}
407 	mnl_attr_nest_end(nlh, nest);
408 
409 	return msg_doit(nlh, NULL, NULL);
410 
411 }
412 
cmd_bearer_set_help(struct cmdl * cmdl)413 static void cmd_bearer_set_help(struct cmdl *cmdl)
414 {
415 	fprintf(stderr, "Usage: %s bearer set OPTION media MEDIA ARGS...\n",
416 		cmdl->argv[0]);
417 	_print_bearer_opts();
418 	_print_bearer_media();
419 }
420 
cmd_bearer_set_udp_help(struct cmdl * cmdl)421 static void cmd_bearer_set_udp_help(struct cmdl *cmdl)
422 {
423 	fprintf(stderr, "Usage: %s bearer set OPTION media udp name NAME\n\n",
424 		cmdl->argv[0]);
425 	_print_bearer_opts();
426 }
427 
cmd_bearer_set_l2_help(struct cmdl * cmdl,char * media)428 static void cmd_bearer_set_l2_help(struct cmdl *cmdl, char *media)
429 {
430 	fprintf(stderr,
431 		"Usage: %s bearer set [OPTION]... media %s device DEVICE\n",
432 		cmdl->argv[0], media);
433 	_print_bearer_opts();
434 }
435 
cmd_bearer_set_prop(struct nlmsghdr * nlh,const struct cmd * cmd,struct cmdl * cmdl,void * data)436 static int cmd_bearer_set_prop(struct nlmsghdr *nlh, const struct cmd *cmd,
437 			 struct cmdl *cmdl, void *data)
438 {
439 	int err;
440 	int val;
441 	int prop;
442 	char *media;
443 	char buf[MNL_SOCKET_BUFFER_SIZE];
444 	struct nlattr *props;
445 	struct nlattr *attrs;
446 	struct opt *opt;
447 	struct opt opts[] = {
448 		{ "device",		NULL },
449 		{ "media",		NULL },
450 		{ "name",		NULL },
451 		{ NULL }
452 	};
453 
454 	if (strcmp(cmd->cmd, "priority") == 0)
455 		prop = TIPC_NLA_PROP_PRIO;
456 	else if ((strcmp(cmd->cmd, "tolerance") == 0))
457 		prop = TIPC_NLA_PROP_TOL;
458 	else if ((strcmp(cmd->cmd, "window") == 0))
459 		prop = TIPC_NLA_PROP_WIN;
460 	else
461 		return -EINVAL;
462 
463 	if (help_flag) {
464 		(cmd->help)(cmdl);
465 		return -EINVAL;
466 	}
467 
468 	if (cmdl->optind >= cmdl->argc) {
469 		fprintf(stderr, "error, missing value\n");
470 		return -EINVAL;
471 	}
472 	val = atoi(shift_cmdl(cmdl));
473 
474 	if (parse_opts(opts, cmdl) < 0)
475 		return -EINVAL;
476 
477 	if (!(nlh = msg_init(buf, TIPC_NL_BEARER_SET))) {
478 		fprintf(stderr, "error, message initialisation failed\n");
479 		return -1;
480 	}
481 	attrs = mnl_attr_nest_start(nlh, TIPC_NLA_BEARER);
482 
483 	props = mnl_attr_nest_start(nlh, TIPC_NLA_BEARER_PROP);
484 	mnl_attr_put_u32(nlh, prop, val);
485 	mnl_attr_nest_end(nlh, props);
486 
487 	if (!(opt = get_opt(opts, "media"))) {
488 		fprintf(stderr, "error, missing media\n");
489 		return -EINVAL;
490 	}
491 	media = opt->val;
492 
493 	if (strcmp(media, "udp") == 0) {
494 		if (help_flag) {
495 			cmd_bearer_set_udp_help(cmdl);
496 			return -EINVAL;
497 		}
498 		if ((err = add_udp_bearer(nlh, opts)))
499 			return err;
500 	} else if ((strcmp(media, "eth") == 0) || (strcmp(media, "udp") == 0)) {
501 		if (help_flag) {
502 			cmd_bearer_set_l2_help(cmdl, media);
503 			return -EINVAL;
504 		}
505 		if ((err = add_l2_bearer(nlh, opts)))
506 			return err;
507 	} else {
508 		fprintf(stderr, "error, invalid media type \"%s\"\n", media);
509 		return -EINVAL;
510 	}
511 	mnl_attr_nest_end(nlh, attrs);
512 
513 	return msg_doit(nlh, NULL, NULL);
514 }
515 
cmd_bearer_set(struct nlmsghdr * nlh,const struct cmd * cmd,struct cmdl * cmdl,void * data)516 static int cmd_bearer_set(struct nlmsghdr *nlh, const struct cmd *cmd,
517 			  struct cmdl *cmdl, void *data)
518 {
519 	const struct cmd cmds[] = {
520 		{ "priority",	cmd_bearer_set_prop,	cmd_bearer_set_help },
521 		{ "tolerance",	cmd_bearer_set_prop,	cmd_bearer_set_help },
522 		{ "window",	cmd_bearer_set_prop,	cmd_bearer_set_help },
523 		{ NULL }
524 	};
525 
526 	return run_cmd(nlh, cmd, cmds, cmdl, NULL);
527 }
528 
cmd_bearer_get_help(struct cmdl * cmdl)529 static void cmd_bearer_get_help(struct cmdl *cmdl)
530 {
531 	fprintf(stderr, "Usage: %s bearer get OPTION media MEDIA ARGS...\n",
532 		cmdl->argv[0]);
533 	_print_bearer_opts();
534 	_print_bearer_media();
535 }
536 
cmd_bearer_get_udp_help(struct cmdl * cmdl)537 static void cmd_bearer_get_udp_help(struct cmdl *cmdl)
538 {
539 	fprintf(stderr, "Usage: %s bearer get OPTION media udp name NAME\n\n",
540 		cmdl->argv[0]);
541 	_print_bearer_opts();
542 }
543 
cmd_bearer_get_l2_help(struct cmdl * cmdl,char * media)544 static void cmd_bearer_get_l2_help(struct cmdl *cmdl, char *media)
545 {
546 	fprintf(stderr,
547 		"Usage: %s bearer get [OPTION]... media %s device DEVICE\n",
548 		cmdl->argv[0], media);
549 	_print_bearer_opts();
550 }
551 
bearer_get_cb(const struct nlmsghdr * nlh,void * data)552 static int bearer_get_cb(const struct nlmsghdr *nlh, void *data)
553 {
554 	int *prop = data;
555 	struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
556 	struct nlattr *info[TIPC_NLA_MAX + 1] = {};
557 	struct nlattr *attrs[TIPC_NLA_BEARER_MAX + 1] = {};
558 	struct nlattr *props[TIPC_NLA_PROP_MAX + 1] = {};
559 
560 	mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, info);
561 	if (!info[TIPC_NLA_BEARER])
562 		return MNL_CB_ERROR;
563 
564 	mnl_attr_parse_nested(info[TIPC_NLA_BEARER], parse_attrs, attrs);
565 	if (!attrs[TIPC_NLA_BEARER_PROP])
566 		return MNL_CB_ERROR;
567 
568 	mnl_attr_parse_nested(attrs[TIPC_NLA_BEARER_PROP], parse_attrs, props);
569 	if (!props[*prop])
570 		return MNL_CB_ERROR;
571 
572 	printf("%u\n", mnl_attr_get_u32(props[*prop]));
573 
574 	return MNL_CB_OK;
575 }
576 
cmd_bearer_get_prop(struct nlmsghdr * nlh,const struct cmd * cmd,struct cmdl * cmdl,void * data)577 static int cmd_bearer_get_prop(struct nlmsghdr *nlh, const struct cmd *cmd,
578 			       struct cmdl *cmdl, void *data)
579 {
580 	int err;
581 	int prop;
582 	char *media;
583 	char buf[MNL_SOCKET_BUFFER_SIZE];
584 	struct nlattr *attrs;
585 	struct opt *opt;
586 	struct opt opts[] = {
587 		{ "device",		NULL },
588 		{ "media",		NULL },
589 		{ "name",		NULL },
590 		{ NULL }
591 	};
592 
593 	if (strcmp(cmd->cmd, "priority") == 0)
594 		prop = TIPC_NLA_PROP_PRIO;
595 	else if ((strcmp(cmd->cmd, "tolerance") == 0))
596 		prop = TIPC_NLA_PROP_TOL;
597 	else if ((strcmp(cmd->cmd, "window") == 0))
598 		prop = TIPC_NLA_PROP_WIN;
599 	else
600 		return -EINVAL;
601 
602 	if (help_flag) {
603 		(cmd->help)(cmdl);
604 		return -EINVAL;
605 	}
606 
607 	if (parse_opts(opts, cmdl) < 0)
608 		return -EINVAL;
609 
610 	if (!(nlh = msg_init(buf, TIPC_NL_BEARER_GET))) {
611 		fprintf(stderr, "error, message initialisation failed\n");
612 		return -1;
613 	}
614 
615 	if (!(opt = get_opt(opts, "media"))) {
616 		fprintf(stderr, "error, missing media\n");
617 		return -EINVAL;
618 	}
619 	media = opt->val;
620 
621 	attrs = mnl_attr_nest_start(nlh, TIPC_NLA_BEARER);
622 	if (strcmp(media, "udp") == 0) {
623 		if (help_flag) {
624 			cmd_bearer_get_udp_help(cmdl);
625 			return -EINVAL;
626 		}
627 		if ((err = add_udp_bearer(nlh, opts)))
628 			return err;
629 	} else if ((strcmp(media, "eth") == 0) || (strcmp(media, "udp") == 0)) {
630 		if (help_flag) {
631 			cmd_bearer_get_l2_help(cmdl, media);
632 			return -EINVAL;
633 		}
634 		if ((err = add_l2_bearer(nlh, opts)))
635 			return err;
636 	} else {
637 		fprintf(stderr, "error, invalid media type \"%s\"\n", media);
638 		return -EINVAL;
639 	}
640 	mnl_attr_nest_end(nlh, attrs);
641 
642 	return msg_doit(nlh, bearer_get_cb, &prop);
643 }
644 
cmd_bearer_get(struct nlmsghdr * nlh,const struct cmd * cmd,struct cmdl * cmdl,void * data)645 static int cmd_bearer_get(struct nlmsghdr *nlh, const struct cmd *cmd,
646 			  struct cmdl *cmdl, void *data)
647 {
648 	const struct cmd cmds[] = {
649 		{ "priority",	cmd_bearer_get_prop,	cmd_bearer_get_help },
650 		{ "tolerance",	cmd_bearer_get_prop,	cmd_bearer_get_help },
651 		{ "window",	cmd_bearer_get_prop,	cmd_bearer_get_help },
652 		{ NULL }
653 	};
654 
655 	return run_cmd(nlh, cmd, cmds, cmdl, NULL);
656 }
657 
bearer_list_cb(const struct nlmsghdr * nlh,void * data)658 static int bearer_list_cb(const struct nlmsghdr *nlh, void *data)
659 {
660 	struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
661 	struct nlattr *info[TIPC_NLA_MAX + 1] = {};
662 	struct nlattr *attrs[TIPC_NLA_BEARER_MAX + 1] = {};
663 
664 	mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, info);
665 	if (!info[TIPC_NLA_BEARER]) {
666 		fprintf(stderr, "No bearer in netlink response\n");
667 		return MNL_CB_ERROR;
668 	}
669 
670 	mnl_attr_parse_nested(info[TIPC_NLA_BEARER], parse_attrs, attrs);
671 	if (!attrs[TIPC_NLA_BEARER_NAME]) {
672 		fprintf(stderr, "Bearer name missing in netlink response\n");
673 		return MNL_CB_ERROR;
674 	}
675 
676 	printf("%s\n", mnl_attr_get_str(attrs[TIPC_NLA_BEARER_NAME]));
677 
678 	return MNL_CB_OK;
679 }
680 
cmd_bearer_list(struct nlmsghdr * nlh,const struct cmd * cmd,struct cmdl * cmdl,void * data)681 static int cmd_bearer_list(struct nlmsghdr *nlh, const struct cmd *cmd,
682 			   struct cmdl *cmdl, void *data)
683 {
684 	char buf[MNL_SOCKET_BUFFER_SIZE];
685 
686 	if (help_flag) {
687 		fprintf(stderr, "Usage: %s bearer list\n", cmdl->argv[0]);
688 		return -EINVAL;
689 	}
690 
691 	if (!(nlh = msg_init(buf, TIPC_NL_BEARER_GET))) {
692 		fprintf(stderr, "error, message initialisation failed\n");
693 		return -1;
694 	}
695 
696 	return msg_dumpit(nlh, bearer_list_cb, NULL);
697 }
698 
cmd_bearer_help(struct cmdl * cmdl)699 void cmd_bearer_help(struct cmdl *cmdl)
700 {
701 	fprintf(stderr,
702 		"Usage: %s bearer COMMAND [ARGS] ...\n"
703 		"\n"
704 		"COMMANDS\n"
705 		" enable                - Enable a bearer\n"
706 		" disable               - Disable a bearer\n"
707 		" set                   - Set various bearer properties\n"
708 		" get                   - Get various bearer properties\n"
709 		" list                  - List bearers\n", cmdl->argv[0]);
710 }
711 
cmd_bearer(struct nlmsghdr * nlh,const struct cmd * cmd,struct cmdl * cmdl,void * data)712 int cmd_bearer(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl,
713 	       void *data)
714 {
715 	const struct cmd cmds[] = {
716 		{ "disable",	cmd_bearer_disable,	cmd_bearer_disable_help },
717 		{ "enable",	cmd_bearer_enable,	cmd_bearer_enable_help },
718 		{ "get",	cmd_bearer_get,		cmd_bearer_get_help },
719 		{ "list",	cmd_bearer_list,	NULL },
720 		{ "set",	cmd_bearer_set,		cmd_bearer_set_help },
721 		{ NULL }
722 	};
723 
724 	return run_cmd(nlh, cmd, cmds, cmdl, NULL);
725 }
726