Home | History | Annotate | Download | only in tipc
      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 (at) 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 
     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 
     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 
     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 
     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 
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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