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 #include <arpa/inet.h>
     18 
     19 #include <linux/tipc_netlink.h>
     20 #include <linux/tipc.h>
     21 #include <linux/genetlink.h>
     22 
     23 #include <libmnl/libmnl.h>
     24 #include <sys/socket.h>
     25 
     26 #include "cmdl.h"
     27 #include "msg.h"
     28 #include "bearer.h"
     29 
     30 #define UDP_PROP_IP 1
     31 #define UDP_PROP_PORT 2
     32 
     33 struct cb_data {
     34 	int attr;
     35 	int prop;
     36 	struct nlmsghdr *nlh;
     37 };
     38 
     39 static void _print_bearer_opts(void)
     40 {
     41 	fprintf(stderr,
     42 		"OPTIONS\n"
     43 		" priority              - Bearer link priority\n"
     44 		" tolerance             - Bearer link tolerance\n"
     45 		" window                - Bearer link window\n");
     46 }
     47 
     48 void print_bearer_media(void)
     49 {
     50 	fprintf(stderr,
     51 		"\nMEDIA\n"
     52 		" udp                   - User Datagram Protocol\n"
     53 		" ib                    - Infiniband\n"
     54 		" eth                   - Ethernet\n");
     55 }
     56 
     57 static void cmd_bearer_enable_l2_help(struct cmdl *cmdl, char *media)
     58 {
     59 	fprintf(stderr,
     60 		"Usage: %s bearer enable media %s device DEVICE [OPTIONS]\n"
     61 		"\nOPTIONS\n"
     62 		" domain DOMAIN         - Discovery domain\n"
     63 		" priority PRIORITY     - Bearer priority\n",
     64 		cmdl->argv[0], media);
     65 }
     66 
     67 static void cmd_bearer_enable_udp_help(struct cmdl *cmdl, char *media)
     68 {
     69 	fprintf(stderr,
     70 		"Usage: %s bearer enable [OPTIONS] media %s name NAME localip IP [UDP OPTIONS]\n\n",
     71 		cmdl->argv[0], media);
     72 	fprintf(stderr,
     73 		"OPTIONS\n"
     74 		" domain DOMAIN         - Discovery domain\n"
     75 		" priority PRIORITY     - Bearer priority\n\n");
     76 	fprintf(stderr,
     77 		"UDP OPTIONS\n"
     78 		" localport PORT        - Local UDP port (default 6118)\n"
     79 		" remoteip IP           - Remote IP address\n"
     80 		" remoteport PORT       - Remote UDP port (default 6118)\n");
     81 }
     82 
     83 static int get_netid_cb(const struct nlmsghdr *nlh, void *data)
     84 {
     85 	struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
     86 	struct nlattr *info[TIPC_NLA_MAX + 1] = {};
     87 	struct nlattr *attrs[TIPC_NLA_NET_MAX + 1] = {};
     88 	int *netid = (int*)data;
     89 
     90 	mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, info);
     91 	if (!info[TIPC_NLA_NET])
     92 		return MNL_CB_ERROR;
     93 	mnl_attr_parse_nested(info[TIPC_NLA_NET], parse_attrs, attrs);
     94 	if (!attrs[TIPC_NLA_NET_ID])
     95 		return MNL_CB_ERROR;
     96 	*netid = mnl_attr_get_u32(attrs[TIPC_NLA_NET_ID]);
     97 
     98 	return MNL_CB_OK;
     99 }
    100 
    101 static int generate_multicast(short af, char *buf, int bufsize)
    102 {
    103 	int netid;
    104 	char mnl_msg[MNL_SOCKET_BUFFER_SIZE];
    105 	struct nlmsghdr *nlh;
    106 
    107 	if (!(nlh = msg_init(mnl_msg, TIPC_NL_NET_GET))) {
    108 		fprintf(stderr, "error, message initialization failed\n");
    109 		return -1;
    110 	}
    111 	if (msg_dumpit(nlh, get_netid_cb, &netid)) {
    112 		fprintf(stderr, "error, failed to fetch TIPC network id from kernel\n");
    113 		return -EINVAL;
    114 	}
    115 	if (af == AF_INET)
    116 		snprintf(buf, bufsize, "228.0.%u.%u", (netid>>8) & 0xFF, netid & 0xFF);
    117 	else
    118 		snprintf(buf, bufsize, "ff02::%u", netid);
    119 
    120 	return 0;
    121 }
    122 
    123 static int nl_add_udp_enable_opts(struct nlmsghdr *nlh, struct opt *opts,
    124 				  struct cmdl *cmdl)
    125 {
    126 	int err;
    127 	struct opt *opt;
    128 	struct nlattr *nest;
    129 	char buf[INET6_ADDRSTRLEN];
    130 	char *locport = "6118";
    131 	char *remport = "6118";
    132 	char *locip = NULL;
    133 	char *remip = NULL;
    134 	struct addrinfo *loc = NULL;
    135 	struct addrinfo *rem = NULL;
    136 	struct addrinfo hints = {
    137 		.ai_family = AF_UNSPEC,
    138 		.ai_socktype = SOCK_DGRAM
    139 	};
    140 
    141 	if (!(opt = get_opt(opts, "localip"))) {
    142 		fprintf(stderr, "error, udp bearer localip missing\n");
    143 		cmd_bearer_enable_udp_help(cmdl, "udp");
    144 		return -EINVAL;
    145 	}
    146 	locip = opt->val;
    147 
    148 	if ((opt = get_opt(opts, "remoteip")))
    149 		remip = opt->val;
    150 
    151 	if ((opt = get_opt(opts, "localport")))
    152 		locport = opt->val;
    153 
    154 	if ((opt = get_opt(opts, "remoteport")))
    155 		remport = opt->val;
    156 
    157 	if ((err = getaddrinfo(locip, locport, &hints, &loc))) {
    158 		fprintf(stderr, "UDP local address error: %s\n",
    159 			gai_strerror(err));
    160 		return err;
    161 	}
    162 
    163 	if (!remip) {
    164 		if (generate_multicast(loc->ai_family, buf, sizeof(buf))) {
    165 			fprintf(stderr, "Failed to generate multicast address\n");
    166 			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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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