1/*
2 * media.c	TIPC link 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 <errno.h>
16
17#include <linux/tipc_netlink.h>
18#include <linux/tipc.h>
19#include <linux/genetlink.h>
20#include <libmnl/libmnl.h>
21
22#include "cmdl.h"
23#include "msg.h"
24#include "media.h"
25
26static int media_list_cb(const struct nlmsghdr *nlh, void *data)
27{
28	struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
29	struct nlattr *info[TIPC_NLA_MAX + 1] = {};
30	struct nlattr *attrs[TIPC_NLA_MEDIA_MAX + 1] = {};
31
32	mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, info);
33	if (!info[TIPC_NLA_MEDIA])
34		return MNL_CB_ERROR;
35
36	mnl_attr_parse_nested(info[TIPC_NLA_MEDIA], parse_attrs, attrs);
37	if (!attrs[TIPC_NLA_MEDIA_NAME])
38		return MNL_CB_ERROR;
39
40	printf("%s\n", mnl_attr_get_str(attrs[TIPC_NLA_MEDIA_NAME]));
41
42	return MNL_CB_OK;
43}
44
45static int cmd_media_list(struct nlmsghdr *nlh, const struct cmd *cmd,
46			 struct cmdl *cmdl, void *data)
47{
48	char buf[MNL_SOCKET_BUFFER_SIZE];
49
50	if (help_flag) {
51		fprintf(stderr, "Usage: %s media list\n", cmdl->argv[0]);
52		return -EINVAL;
53	}
54
55	if (!(nlh = msg_init(buf, TIPC_NL_MEDIA_GET))) {
56		fprintf(stderr, "error, message initialisation failed\n");
57		return -1;
58	}
59
60	return msg_dumpit(nlh, media_list_cb, NULL);
61}
62
63static int media_get_cb(const struct nlmsghdr *nlh, void *data)
64{
65	int *prop = data;
66	struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
67	struct nlattr *info[TIPC_NLA_MAX + 1] = {};
68	struct nlattr *attrs[TIPC_NLA_MEDIA_MAX + 1] = {};
69	struct nlattr *props[TIPC_NLA_PROP_MAX + 1] = {};
70
71	mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, info);
72	if (!info[TIPC_NLA_MEDIA])
73		return MNL_CB_ERROR;
74
75	mnl_attr_parse_nested(info[TIPC_NLA_MEDIA], parse_attrs, attrs);
76	if (!attrs[TIPC_NLA_MEDIA_PROP])
77		return MNL_CB_ERROR;
78
79	mnl_attr_parse_nested(attrs[TIPC_NLA_MEDIA_PROP], parse_attrs, props);
80	if (!props[*prop])
81		return MNL_CB_ERROR;
82
83	printf("%u\n", mnl_attr_get_u32(props[*prop]));
84
85	return MNL_CB_OK;
86}
87
88static int cmd_media_get_prop(struct nlmsghdr *nlh, const struct cmd *cmd,
89			      struct cmdl *cmdl, void *data)
90{
91	int prop;
92	char buf[MNL_SOCKET_BUFFER_SIZE];
93	struct nlattr *nest;
94	struct opt *opt;
95	struct opt opts[] = {
96		{ "media",		NULL },
97		{ NULL }
98	};
99
100	if (strcmp(cmd->cmd, "priority") == 0)
101		prop = TIPC_NLA_PROP_PRIO;
102	else if ((strcmp(cmd->cmd, "tolerance") == 0))
103		prop = TIPC_NLA_PROP_TOL;
104	else if ((strcmp(cmd->cmd, "window") == 0))
105		prop = TIPC_NLA_PROP_WIN;
106	else
107		return -EINVAL;
108
109	if (help_flag) {
110		(cmd->help)(cmdl);
111		return -EINVAL;
112	}
113
114	if (parse_opts(opts, cmdl) < 0)
115		return -EINVAL;
116
117	if (!(nlh = msg_init(buf, TIPC_NL_MEDIA_GET))) {
118		fprintf(stderr, "error, message initialisation failed\n");
119		return -1;
120	}
121
122	if (!(opt = get_opt(opts, "media"))) {
123		fprintf(stderr, "error, missing media\n");
124		return -EINVAL;
125	}
126	nest = mnl_attr_nest_start(nlh, TIPC_NLA_MEDIA);
127	mnl_attr_put_strz(nlh, TIPC_NLA_MEDIA_NAME, opt->val);
128	mnl_attr_nest_end(nlh, nest);
129
130	return msg_doit(nlh, media_get_cb, &prop);
131}
132
133static void cmd_media_get_help(struct cmdl *cmdl)
134{
135	fprintf(stderr, "Usage: %s media get PPROPERTY media MEDIA\n\n"
136		"PROPERTIES\n"
137		" tolerance             - Get media tolerance\n"
138		" priority              - Get media priority\n"
139		" window                - Get media window\n",
140		cmdl->argv[0]);
141}
142
143static int cmd_media_get(struct nlmsghdr *nlh, const struct cmd *cmd,
144			struct cmdl *cmdl, void *data)
145{
146	const struct cmd cmds[] = {
147		{ "priority",	cmd_media_get_prop,	cmd_media_get_help },
148		{ "tolerance",	cmd_media_get_prop,	cmd_media_get_help },
149		{ "window",	cmd_media_get_prop,	cmd_media_get_help },
150		{ NULL }
151	};
152
153	return run_cmd(nlh, cmd, cmds, cmdl, NULL);
154}
155
156static void cmd_media_set_help(struct cmdl *cmdl)
157{
158	fprintf(stderr, "Usage: %s media set PPROPERTY media MEDIA\n\n"
159		"PROPERTIES\n"
160		" tolerance TOLERANCE   - Set media tolerance\n"
161		" priority PRIORITY     - Set media priority\n"
162		" window WINDOW         - Set media window\n",
163		cmdl->argv[0]);
164}
165
166static int cmd_media_set_prop(struct nlmsghdr *nlh, const struct cmd *cmd,
167			 struct cmdl *cmdl, void *data)
168{
169	int val;
170	int prop;
171	char buf[MNL_SOCKET_BUFFER_SIZE];
172	struct nlattr *props;
173	struct nlattr *attrs;
174	struct opt *opt;
175	struct opt opts[] = {
176		{ "media",		NULL },
177		{ NULL }
178	};
179
180	if (strcmp(cmd->cmd, "priority") == 0)
181		prop = TIPC_NLA_PROP_PRIO;
182	else if ((strcmp(cmd->cmd, "tolerance") == 0))
183		prop = TIPC_NLA_PROP_TOL;
184	else if ((strcmp(cmd->cmd, "window") == 0))
185		prop = TIPC_NLA_PROP_WIN;
186	else
187		return -EINVAL;
188
189	if (help_flag) {
190		(cmd->help)(cmdl);
191		return -EINVAL;
192	}
193
194	if (cmdl->optind >= cmdl->argc) {
195		fprintf(stderr, "error, missing value\n");
196		return -EINVAL;
197	}
198	val = atoi(shift_cmdl(cmdl));
199
200	if (parse_opts(opts, cmdl) < 0)
201		return -EINVAL;
202
203	if (!(nlh = msg_init(buf, TIPC_NL_MEDIA_SET))) {
204		fprintf(stderr, "error, message initialisation failed\n");
205		return -1;
206	}
207	attrs = mnl_attr_nest_start(nlh, TIPC_NLA_MEDIA);
208
209	if (!(opt = get_opt(opts, "media"))) {
210		fprintf(stderr, "error, missing media\n");
211		return -EINVAL;
212	}
213	mnl_attr_put_strz(nlh, TIPC_NLA_MEDIA_NAME, opt->val);
214
215	props = mnl_attr_nest_start(nlh, TIPC_NLA_MEDIA_PROP);
216	mnl_attr_put_u32(nlh, prop, val);
217	mnl_attr_nest_end(nlh, props);
218
219	mnl_attr_nest_end(nlh, attrs);
220
221	return msg_doit(nlh, NULL, NULL);
222}
223
224static int cmd_media_set(struct nlmsghdr *nlh, const struct cmd *cmd,
225			 struct cmdl *cmdl, void *data)
226{
227	const struct cmd cmds[] = {
228		{ "priority",	cmd_media_set_prop,	cmd_media_set_help },
229		{ "tolerance",	cmd_media_set_prop,	cmd_media_set_help },
230		{ "window",	cmd_media_set_prop,	cmd_media_set_help },
231		{ NULL }
232	};
233
234	return run_cmd(nlh, cmd, cmds, cmdl, NULL);
235}
236
237void cmd_media_help(struct cmdl *cmdl)
238{
239	fprintf(stderr,
240		"Usage: %s media COMMAND [ARGS] ...\n"
241		"\n"
242		"Commands:\n"
243		" list                  - List active media types\n"
244		" get                   - Get various media properties\n"
245		" set                   - Set various media properties\n",
246		cmdl->argv[0]);
247}
248
249int cmd_media(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl,
250	     void *data)
251{
252	const struct cmd cmds[] = {
253		{ "get",	cmd_media_get,	cmd_media_get_help },
254		{ "list",	cmd_media_list,	NULL },
255		{ "set",	cmd_media_set,	cmd_media_set_help },
256		{ NULL }
257	};
258
259	return run_cmd(nlh, cmd, cmds, cmdl, NULL);
260}
261