• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * module.c - netlink implementation of module commands
3  *
4  * Implementation of "ethtool --show-module <dev>" and
5  * "ethtool --set-module <dev> ..."
6  */
7 
8 #include <errno.h>
9 #include <ctype.h>
10 #include <inttypes.h>
11 #include <string.h>
12 #include <stdio.h>
13 #include <stdarg.h>
14 
15 #include "../internal.h"
16 #include "../common.h"
17 #include "netlink.h"
18 #include "parser.h"
19 
20 /* MODULE_GET */
21 
module_power_mode_policy_name(u8 val)22 static const char *module_power_mode_policy_name(u8 val)
23 {
24 	switch (val) {
25 	case ETHTOOL_MODULE_POWER_MODE_POLICY_HIGH:
26 		return "high";
27 	case ETHTOOL_MODULE_POWER_MODE_POLICY_AUTO:
28 		return "auto";
29 	default:
30 		return "unknown";
31 	}
32 }
33 
module_power_mode_name(u8 val)34 static const char *module_power_mode_name(u8 val)
35 {
36 	switch (val) {
37 	case ETHTOOL_MODULE_POWER_MODE_LOW:
38 		return "low";
39 	case ETHTOOL_MODULE_POWER_MODE_HIGH:
40 		return "high";
41 	default:
42 		return "unknown";
43 	}
44 }
45 
module_reply_cb(const struct nlmsghdr * nlhdr,void * data)46 int module_reply_cb(const struct nlmsghdr *nlhdr, void *data)
47 {
48 	const struct nlattr *tb[ETHTOOL_A_MODULE_MAX + 1] = {};
49 	struct nl_context *nlctx = data;
50 	DECLARE_ATTR_TB_INFO(tb);
51 	bool silent;
52 	int err_ret;
53 	int ret;
54 
55 	silent = nlctx->is_dump || nlctx->is_monitor;
56 	err_ret = silent ? MNL_CB_OK : MNL_CB_ERROR;
57 	ret = mnl_attr_parse(nlhdr, GENL_HDRLEN, attr_cb, &tb_info);
58 	if (ret < 0)
59 		return err_ret;
60 	nlctx->devname = get_dev_name(tb[ETHTOOL_A_MODULE_HEADER]);
61 	if (!dev_ok(nlctx))
62 		return err_ret;
63 
64 	if (silent)
65 		print_nl();
66 
67 	open_json_object(NULL);
68 
69 	print_string(PRINT_ANY, "ifname", "Module parameters for %s:\n",
70 		     nlctx->devname);
71 
72 	if (tb[ETHTOOL_A_MODULE_POWER_MODE_POLICY]) {
73 		u8 val;
74 
75 		val = mnl_attr_get_u8(tb[ETHTOOL_A_MODULE_POWER_MODE_POLICY]);
76 		print_string(PRINT_ANY, "power-mode-policy",
77 			     "power-mode-policy: %s\n",
78 			     module_power_mode_policy_name(val));
79 	}
80 
81 	if (tb[ETHTOOL_A_MODULE_POWER_MODE]) {
82 		u8 val;
83 
84 		val = mnl_attr_get_u8(tb[ETHTOOL_A_MODULE_POWER_MODE]);
85 		print_string(PRINT_ANY, "power-mode",
86 			     "power-mode: %s\n", module_power_mode_name(val));
87 	}
88 
89 	close_json_object();
90 
91 	return MNL_CB_OK;
92 }
93 
nl_gmodule(struct cmd_context * ctx)94 int nl_gmodule(struct cmd_context *ctx)
95 {
96 	struct nl_context *nlctx = ctx->nlctx;
97 	struct nl_socket *nlsk;
98 	int ret;
99 
100 	if (netlink_cmd_check(ctx, ETHTOOL_MSG_MODULE_GET, true))
101 		return -EOPNOTSUPP;
102 	if (ctx->argc > 0) {
103 		fprintf(stderr, "ethtool: unexpected parameter '%s'\n",
104 			*ctx->argp);
105 		return 1;
106 	}
107 
108 	nlsk = nlctx->ethnl_socket;
109 	ret = nlsock_prep_get_request(nlsk, ETHTOOL_MSG_MODULE_GET,
110 				      ETHTOOL_A_MODULE_HEADER, 0);
111 	if (ret < 0)
112 		return ret;
113 
114 	new_json_obj(ctx->json);
115 	ret = nlsock_send_get_request(nlsk, module_reply_cb);
116 	delete_json_obj();
117 	return ret;
118 }
119 
120 /* MODULE_SET */
121 
122 static const struct lookup_entry_u8 power_mode_policy_values[] = {
123 	{ .arg = "high",	.val = ETHTOOL_MODULE_POWER_MODE_POLICY_HIGH },
124 	{ .arg = "auto",	.val = ETHTOOL_MODULE_POWER_MODE_POLICY_AUTO },
125 	{}
126 };
127 
128 static const struct param_parser smodule_params[] = {
129 	{
130 		.arg		= "power-mode-policy",
131 		.type		= ETHTOOL_A_MODULE_POWER_MODE_POLICY,
132 		.handler	= nl_parse_lookup_u8,
133 		.handler_data	= power_mode_policy_values,
134 		.min_argc	= 1,
135 	},
136 	{}
137 };
138 
nl_smodule(struct cmd_context * ctx)139 int nl_smodule(struct cmd_context *ctx)
140 {
141 	struct nl_context *nlctx = ctx->nlctx;
142 	struct nl_msg_buff *msgbuff;
143 	struct nl_socket *nlsk;
144 	int ret;
145 
146 	if (netlink_cmd_check(ctx, ETHTOOL_MSG_MODULE_SET, false))
147 		return -EOPNOTSUPP;
148 	if (!ctx->argc) {
149 		fprintf(stderr, "ethtool (--set-module): parameters missing\n");
150 		return 1;
151 	}
152 
153 	nlctx->cmd = "--set-module";
154 	nlctx->argp = ctx->argp;
155 	nlctx->argc = ctx->argc;
156 	nlctx->devname = ctx->devname;
157 	nlsk = nlctx->ethnl_socket;
158 	msgbuff = &nlsk->msgbuff;
159 
160 	ret = msg_init(nlctx, msgbuff, ETHTOOL_MSG_MODULE_SET,
161 		       NLM_F_REQUEST | NLM_F_ACK);
162 	if (ret < 0)
163 		return 2;
164 	if (ethnla_fill_header(msgbuff, ETHTOOL_A_MODULE_HEADER,
165 			       ctx->devname, 0))
166 		return -EMSGSIZE;
167 
168 	ret = nl_parser(nlctx, smodule_params, NULL, PARSER_GROUP_NONE, NULL);
169 	if (ret < 0)
170 		return 1;
171 
172 	ret = nlsock_sendmsg(nlsk, NULL);
173 	if (ret < 0)
174 		return 83;
175 	ret = nlsock_process_reply(nlsk, nomsg_reply_cb, nlctx);
176 	if (ret == 0)
177 		return 0;
178 	else
179 		return nlctx->exit_code ?: 83;
180 }
181 
182 /* MODULE_FW_FLASH_ACT */
183 
184 static const struct param_parser flash_module_fw_params[] = {
185 	{
186 		.arg		= "file",
187 		.type		= ETHTOOL_A_MODULE_FW_FLASH_FILE_NAME,
188 		.handler	= nl_parse_string,
189 		.min_argc	= 1,
190 	},
191 	{
192 		.arg		= "pass",
193 		.type		= ETHTOOL_A_MODULE_FW_FLASH_PASSWORD,
194 		.handler	= nl_parse_direct_u32,
195 		.min_argc	= 1,
196 	},
197 	{}
198 };
199 
200 struct module_flash_context {
201 	uint8_t breakout:1,
202 		first:1;
203 };
204 
module_fw_flash_ntf_cb(const struct nlmsghdr * nlhdr,void * data)205 static int module_fw_flash_ntf_cb(const struct nlmsghdr *nlhdr, void *data)
206 {
207 	const struct nlattr *tb[ETHTOOL_A_MODULE_FW_FLASH_MAX + 1] = {};
208 	struct module_flash_context *mfctx;
209 	struct nl_context *nlctx = data;
210 	DECLARE_ATTR_TB_INFO(tb);
211 	u8 status = 0;
212 	int ret;
213 
214 	mfctx = nlctx->cmd_private;
215 
216 	ret = mnl_attr_parse(nlhdr, GENL_HDRLEN, attr_cb, &tb_info);
217 	if (ret < 0)
218 		return MNL_CB_OK;
219 	nlctx->devname = get_dev_name(tb[ETHTOOL_A_MODULE_FW_FLASH_HEADER]);
220 	if (!dev_ok(nlctx))
221 		return MNL_CB_OK;
222 
223 	if (tb[ETHTOOL_A_MODULE_FW_FLASH_STATUS])
224 		status = mnl_attr_get_u32(tb[ETHTOOL_A_MODULE_FW_FLASH_STATUS]);
225 
226 	switch (status) {
227 	case ETHTOOL_MODULE_FW_FLASH_STATUS_STARTED:
228 		print_string(PRINT_FP, NULL,
229 			     "Transceiver module firmware flashing started for device %s\n",
230 			     nlctx->devname);
231 		break;
232 	case ETHTOOL_MODULE_FW_FLASH_STATUS_IN_PROGRESS:
233 		if (mfctx->first) {
234 			print_string(PRINT_FP, NULL,
235 				     "Transceiver module firmware flashing in progress for device %s\n",
236 				     nlctx->devname);
237 			mfctx->first = 0;
238 		}
239 		break;
240 	case ETHTOOL_MODULE_FW_FLASH_STATUS_COMPLETED:
241 		print_nl();
242 		print_string(PRINT_FP, NULL,
243 			     "Transceiver module firmware flashing completed for device %s\n",
244 			     nlctx->devname);
245 		mfctx->breakout = 1;
246 		break;
247 	case ETHTOOL_MODULE_FW_FLASH_STATUS_ERROR:
248 		print_nl();
249 		print_string(PRINT_FP, NULL,
250 			     "Transceiver module firmware flashing encountered an error for device %s\n",
251 			     nlctx->devname);
252 		mfctx->breakout = 1;
253 		break;
254 	default:
255 		break;
256 	}
257 
258 	if (tb[ETHTOOL_A_MODULE_FW_FLASH_STATUS_MSG]) {
259 		const char *status_msg;
260 
261 		status_msg = mnl_attr_get_str(tb[ETHTOOL_A_MODULE_FW_FLASH_STATUS_MSG]);
262 		print_string(PRINT_FP, NULL, "Status message: %s\n", status_msg);
263 	}
264 
265 	if (tb[ETHTOOL_A_MODULE_FW_FLASH_DONE] &&
266 	    tb[ETHTOOL_A_MODULE_FW_FLASH_TOTAL]) {
267 		uint64_t done, total;
268 
269 		done = attr_get_uint(tb[ETHTOOL_A_MODULE_FW_FLASH_DONE]);
270 		total = attr_get_uint(tb[ETHTOOL_A_MODULE_FW_FLASH_TOTAL]);
271 
272 		if (total)
273 			print_u64(PRINT_FP, NULL, "Progress: %"PRIu64"%\r",
274 				  done * 100 / total);
275 	}
276 
277 	return MNL_CB_OK;
278 }
279 
nl_flash_module_fw_cb(const struct nlmsghdr * nlhdr,void * data)280 static int nl_flash_module_fw_cb(const struct nlmsghdr *nlhdr, void *data)
281 {
282 	const struct genlmsghdr *ghdr = (const struct genlmsghdr *)(nlhdr + 1);
283 
284 	if (ghdr->cmd != ETHTOOL_MSG_MODULE_FW_FLASH_NTF)
285 		return MNL_CB_OK;
286 
287 	module_fw_flash_ntf_cb(nlhdr, data);
288 
289 	return MNL_CB_STOP;
290 }
291 
nl_flash_module_fw_process_ntf(struct cmd_context * ctx)292 static int nl_flash_module_fw_process_ntf(struct cmd_context *ctx)
293 {
294 	struct nl_context *nlctx = ctx->nlctx;
295 	struct module_flash_context *mfctx;
296 	struct nl_socket *nlsk;
297 	int ret;
298 
299 	nlsk = nlctx->ethnl_socket;
300 
301 	mfctx = malloc(sizeof(struct module_flash_context));
302 	if (!mfctx)
303 		return -ENOMEM;
304 
305 	mfctx->breakout = 0;
306 	mfctx->first = 1;
307 	nlctx->cmd_private = mfctx;
308 
309 	while (!mfctx->breakout) {
310 		ret = nlsock_process_reply(nlsk, nl_flash_module_fw_cb, nlctx);
311 		if (ret)
312 			goto out;
313 		nlsk->seq++;
314 	}
315 
316 out:
317 	free(mfctx);
318 	return ret;
319 }
320 
nl_flash_module_fw(struct cmd_context * ctx)321 int nl_flash_module_fw(struct cmd_context *ctx)
322 {
323 	struct nl_context *nlctx = ctx->nlctx;
324 	struct nl_msg_buff *msgbuff;
325 	struct nl_socket *nlsk;
326 	int ret;
327 
328 	if (netlink_cmd_check(ctx, ETHTOOL_MSG_MODULE_FW_FLASH_ACT, false))
329 		return -EOPNOTSUPP;
330 	if (!ctx->argc) {
331 		fprintf(stderr, "ethtool (--flash-module-firmware): parameters missing\n");
332 		return 1;
333 	}
334 
335 	nlctx->cmd = "--flash-module-firmware";
336 	nlctx->argp = ctx->argp;
337 	nlctx->argc = ctx->argc;
338 	nlctx->devname = ctx->devname;
339 	nlsk = nlctx->ethnl_socket;
340 	msgbuff = &nlsk->msgbuff;
341 
342 	ret = msg_init(nlctx, msgbuff, ETHTOOL_MSG_MODULE_FW_FLASH_ACT,
343 		       NLM_F_REQUEST | NLM_F_ACK);
344 	if (ret < 0)
345 		return 2;
346 	if (ethnla_fill_header(msgbuff, ETHTOOL_A_MODULE_FW_FLASH_HEADER,
347 			       ctx->devname, 0))
348 		return -EMSGSIZE;
349 
350 	ret = nl_parser(nlctx, flash_module_fw_params, NULL, PARSER_GROUP_NONE,
351 			NULL);
352 	if (ret < 0)
353 		return 1;
354 
355 	ret = nlsock_sendmsg(nlsk, NULL);
356 	if (ret < 0)
357 		fprintf(stderr, "Cannot flash transceiver module firmware\n");
358 	else
359 		ret = nl_flash_module_fw_process_ntf(ctx);
360 
361 	return ret;
362 }
363