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
29static 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
38static 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
47static 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
57static 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
70static 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
86static 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
104static 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
126static 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
213static 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
224static 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
301static 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
317static 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
333static 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
339static 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
345static 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
352static 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
413static 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
421static 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
428static 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
436static 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
516static 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
529static 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
537static 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
544static 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
552static 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
577static 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
645static 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
658static 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
681static 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
699void 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
712int 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