xref: /aosp_15_r20/external/ethtool/netlink/fec.c (revision 1b481fc3bb1b45d4cf28d1ec12969dc1055f555d)
1*1b481fc3SMaciej Żenczykowski /*
2*1b481fc3SMaciej Żenczykowski  * fec.c - netlink implementation of FEC commands
3*1b481fc3SMaciej Żenczykowski  *
4*1b481fc3SMaciej Żenczykowski  * Implementation of "ethtool --show-fec <dev>" and
5*1b481fc3SMaciej Żenczykowski  * "ethtool --set-fec <dev> ..."
6*1b481fc3SMaciej Żenczykowski  */
7*1b481fc3SMaciej Żenczykowski 
8*1b481fc3SMaciej Żenczykowski #include <errno.h>
9*1b481fc3SMaciej Żenczykowski #include <ctype.h>
10*1b481fc3SMaciej Żenczykowski #include <inttypes.h>
11*1b481fc3SMaciej Żenczykowski #include <string.h>
12*1b481fc3SMaciej Żenczykowski #include <strings.h>
13*1b481fc3SMaciej Żenczykowski #include <stdio.h>
14*1b481fc3SMaciej Żenczykowski 
15*1b481fc3SMaciej Żenczykowski #include "../internal.h"
16*1b481fc3SMaciej Żenczykowski #include "../common.h"
17*1b481fc3SMaciej Żenczykowski #include "netlink.h"
18*1b481fc3SMaciej Żenczykowski #include "bitset.h"
19*1b481fc3SMaciej Żenczykowski #include "parser.h"
20*1b481fc3SMaciej Żenczykowski 
21*1b481fc3SMaciej Żenczykowski /* FEC_GET */
22*1b481fc3SMaciej Żenczykowski 
23*1b481fc3SMaciej Żenczykowski static void
fec_mode_walk(unsigned int idx,const char * name,bool val,void * data)24*1b481fc3SMaciej Żenczykowski fec_mode_walk(unsigned int idx, const char *name, bool val, void *data)
25*1b481fc3SMaciej Żenczykowski {
26*1b481fc3SMaciej Żenczykowski 	bool *empty = data;
27*1b481fc3SMaciej Żenczykowski 
28*1b481fc3SMaciej Żenczykowski 	if (!val)
29*1b481fc3SMaciej Żenczykowski 		return;
30*1b481fc3SMaciej Żenczykowski 	if (empty)
31*1b481fc3SMaciej Żenczykowski 		*empty = false;
32*1b481fc3SMaciej Żenczykowski 
33*1b481fc3SMaciej Żenczykowski 	/* Rename None to Off - in legacy ioctl None means "not supported"
34*1b481fc3SMaciej Żenczykowski 	 * rather than supported but disabled.
35*1b481fc3SMaciej Żenczykowski 	 */
36*1b481fc3SMaciej Żenczykowski 	if (idx == ETHTOOL_LINK_MODE_FEC_NONE_BIT)
37*1b481fc3SMaciej Żenczykowski 		name = "Off";
38*1b481fc3SMaciej Żenczykowski 	/* Rename to match the ioctl letter case */
39*1b481fc3SMaciej Żenczykowski 	else if (idx == ETHTOOL_LINK_MODE_FEC_BASER_BIT)
40*1b481fc3SMaciej Żenczykowski 		name = "BaseR";
41*1b481fc3SMaciej Żenczykowski 
42*1b481fc3SMaciej Żenczykowski 	print_string(PRINT_ANY, NULL, " %s", name);
43*1b481fc3SMaciej Żenczykowski }
44*1b481fc3SMaciej Żenczykowski 
fec_show_stats(const struct nlattr * nest)45*1b481fc3SMaciej Żenczykowski static int fec_show_stats(const struct nlattr *nest)
46*1b481fc3SMaciej Żenczykowski {
47*1b481fc3SMaciej Żenczykowski 	const struct nlattr *tb[ETHTOOL_A_FEC_STAT_MAX + 1] = {};
48*1b481fc3SMaciej Żenczykowski 	DECLARE_ATTR_TB_INFO(tb);
49*1b481fc3SMaciej Żenczykowski 	static const struct {
50*1b481fc3SMaciej Żenczykowski 		unsigned int attr;
51*1b481fc3SMaciej Żenczykowski 		char *name;
52*1b481fc3SMaciej Żenczykowski 	} stats[] = {
53*1b481fc3SMaciej Żenczykowski 		{ ETHTOOL_A_FEC_STAT_CORRECTED, "corrected_blocks" },
54*1b481fc3SMaciej Żenczykowski 		{ ETHTOOL_A_FEC_STAT_UNCORR, "uncorrectable_blocks" },
55*1b481fc3SMaciej Żenczykowski 		{ ETHTOOL_A_FEC_STAT_CORR_BITS, "corrected_bits" },
56*1b481fc3SMaciej Żenczykowski 	};
57*1b481fc3SMaciej Żenczykowski 	bool header = false;
58*1b481fc3SMaciej Żenczykowski 	unsigned int i;
59*1b481fc3SMaciej Żenczykowski 	int ret;
60*1b481fc3SMaciej Żenczykowski 
61*1b481fc3SMaciej Żenczykowski 	ret = mnl_attr_parse_nested(nest, attr_cb, &tb_info);
62*1b481fc3SMaciej Żenczykowski 	if (ret < 0)
63*1b481fc3SMaciej Żenczykowski 		return ret;
64*1b481fc3SMaciej Żenczykowski 
65*1b481fc3SMaciej Żenczykowski 	open_json_object("statistics");
66*1b481fc3SMaciej Żenczykowski 	for (i = 0; i < ARRAY_SIZE(stats); i++) {
67*1b481fc3SMaciej Żenczykowski 		uint64_t *vals;
68*1b481fc3SMaciej Żenczykowski 		int lanes, l;
69*1b481fc3SMaciej Żenczykowski 
70*1b481fc3SMaciej Żenczykowski 		if (!tb[stats[i].attr] ||
71*1b481fc3SMaciej Żenczykowski 		    !mnl_attr_get_payload_len(tb[stats[i].attr]))
72*1b481fc3SMaciej Żenczykowski 			continue;
73*1b481fc3SMaciej Żenczykowski 
74*1b481fc3SMaciej Żenczykowski 		if (!header && !is_json_context()) {
75*1b481fc3SMaciej Żenczykowski 			printf("Statistics:\n");
76*1b481fc3SMaciej Żenczykowski 			header = true;
77*1b481fc3SMaciej Żenczykowski 		}
78*1b481fc3SMaciej Żenczykowski 
79*1b481fc3SMaciej Żenczykowski 		if (mnl_attr_get_payload_len(tb[stats[i].attr]) % 8) {
80*1b481fc3SMaciej Żenczykowski 			fprintf(stderr, "malformed netlink message (statistic)\n");
81*1b481fc3SMaciej Żenczykowski 			goto err_close_stats;
82*1b481fc3SMaciej Żenczykowski 		}
83*1b481fc3SMaciej Żenczykowski 
84*1b481fc3SMaciej Żenczykowski 		vals = mnl_attr_get_payload(tb[stats[i].attr]);
85*1b481fc3SMaciej Żenczykowski 		lanes = mnl_attr_get_payload_len(tb[stats[i].attr]) / 8 - 1;
86*1b481fc3SMaciej Żenczykowski 
87*1b481fc3SMaciej Żenczykowski 		if (!is_json_context()) {
88*1b481fc3SMaciej Żenczykowski 			fprintf(stdout, "  %s: %" PRIu64 "\n",
89*1b481fc3SMaciej Żenczykowski 				stats[i].name, *vals++);
90*1b481fc3SMaciej Żenczykowski 		} else {
91*1b481fc3SMaciej Żenczykowski 			open_json_object(stats[i].name);
92*1b481fc3SMaciej Żenczykowski 			print_u64(PRINT_JSON, "total", NULL, *vals++);
93*1b481fc3SMaciej Żenczykowski 		}
94*1b481fc3SMaciej Żenczykowski 
95*1b481fc3SMaciej Żenczykowski 		if (lanes)
96*1b481fc3SMaciej Żenczykowski 			open_json_array("lanes", "");
97*1b481fc3SMaciej Żenczykowski 		for (l = 0; l < lanes; l++) {
98*1b481fc3SMaciej Żenczykowski 			if (!is_json_context())
99*1b481fc3SMaciej Żenczykowski 				fprintf(stdout, "    Lane %d: %" PRIu64 "\n",
100*1b481fc3SMaciej Żenczykowski 					l, *vals++);
101*1b481fc3SMaciej Żenczykowski 			else
102*1b481fc3SMaciej Żenczykowski 				print_u64(PRINT_JSON, NULL, NULL, *vals++);
103*1b481fc3SMaciej Żenczykowski 		}
104*1b481fc3SMaciej Żenczykowski 		if (lanes)
105*1b481fc3SMaciej Żenczykowski 			close_json_array("");
106*1b481fc3SMaciej Żenczykowski 
107*1b481fc3SMaciej Żenczykowski 		close_json_object();
108*1b481fc3SMaciej Żenczykowski 	}
109*1b481fc3SMaciej Żenczykowski 	close_json_object();
110*1b481fc3SMaciej Żenczykowski 
111*1b481fc3SMaciej Żenczykowski 	return 0;
112*1b481fc3SMaciej Żenczykowski 
113*1b481fc3SMaciej Żenczykowski err_close_stats:
114*1b481fc3SMaciej Żenczykowski 	close_json_object();
115*1b481fc3SMaciej Żenczykowski 	return -1;
116*1b481fc3SMaciej Żenczykowski }
117*1b481fc3SMaciej Żenczykowski 
fec_reply_cb(const struct nlmsghdr * nlhdr,void * data)118*1b481fc3SMaciej Żenczykowski int fec_reply_cb(const struct nlmsghdr *nlhdr, void *data)
119*1b481fc3SMaciej Żenczykowski {
120*1b481fc3SMaciej Żenczykowski 	const struct nlattr *tb[ETHTOOL_A_FEC_MAX + 1] = {};
121*1b481fc3SMaciej Żenczykowski 	DECLARE_ATTR_TB_INFO(tb);
122*1b481fc3SMaciej Żenczykowski 	struct nl_context *nlctx = data;
123*1b481fc3SMaciej Żenczykowski 	const struct stringset *lm_strings;
124*1b481fc3SMaciej Żenczykowski 	const char *name;
125*1b481fc3SMaciej Żenczykowski 	bool fa, empty;
126*1b481fc3SMaciej Żenczykowski 	bool silent;
127*1b481fc3SMaciej Żenczykowski 	int err_ret;
128*1b481fc3SMaciej Żenczykowski 	u32 active;
129*1b481fc3SMaciej Żenczykowski 	int ret;
130*1b481fc3SMaciej Żenczykowski 
131*1b481fc3SMaciej Żenczykowski 	silent = nlctx->is_dump || nlctx->is_monitor;
132*1b481fc3SMaciej Żenczykowski 	err_ret = silent ? MNL_CB_OK : MNL_CB_ERROR;
133*1b481fc3SMaciej Żenczykowski 	ret = mnl_attr_parse(nlhdr, GENL_HDRLEN, attr_cb, &tb_info);
134*1b481fc3SMaciej Żenczykowski 	if (ret < 0)
135*1b481fc3SMaciej Żenczykowski 		return err_ret;
136*1b481fc3SMaciej Żenczykowski 	nlctx->devname = get_dev_name(tb[ETHTOOL_A_FEC_HEADER]);
137*1b481fc3SMaciej Żenczykowski 	if (!dev_ok(nlctx))
138*1b481fc3SMaciej Żenczykowski 		return err_ret;
139*1b481fc3SMaciej Żenczykowski 
140*1b481fc3SMaciej Żenczykowski 	ret = netlink_init_ethnl2_socket(nlctx);
141*1b481fc3SMaciej Żenczykowski 	if (ret < 0)
142*1b481fc3SMaciej Żenczykowski 		return err_ret;
143*1b481fc3SMaciej Żenczykowski 	lm_strings = global_stringset(ETH_SS_LINK_MODES, nlctx->ethnl2_socket);
144*1b481fc3SMaciej Żenczykowski 
145*1b481fc3SMaciej Żenczykowski 	active = 0;
146*1b481fc3SMaciej Żenczykowski 	if (tb[ETHTOOL_A_FEC_ACTIVE])
147*1b481fc3SMaciej Żenczykowski 		active = mnl_attr_get_u32(tb[ETHTOOL_A_FEC_ACTIVE]);
148*1b481fc3SMaciej Żenczykowski 
149*1b481fc3SMaciej Żenczykowski 	if (silent)
150*1b481fc3SMaciej Żenczykowski 		print_nl();
151*1b481fc3SMaciej Żenczykowski 
152*1b481fc3SMaciej Żenczykowski 	open_json_object(NULL);
153*1b481fc3SMaciej Żenczykowski 
154*1b481fc3SMaciej Żenczykowski 	print_string(PRINT_ANY, "ifname", "FEC parameters for %s:\n",
155*1b481fc3SMaciej Żenczykowski 		     nlctx->devname);
156*1b481fc3SMaciej Żenczykowski 
157*1b481fc3SMaciej Żenczykowski 	open_json_array("config", "Supported/Configured FEC encodings:");
158*1b481fc3SMaciej Żenczykowski 	fa = tb[ETHTOOL_A_FEC_AUTO] && mnl_attr_get_u8(tb[ETHTOOL_A_FEC_AUTO]);
159*1b481fc3SMaciej Żenczykowski 	if (fa)
160*1b481fc3SMaciej Żenczykowski 		print_string(PRINT_ANY, NULL, " %s", "Auto");
161*1b481fc3SMaciej Żenczykowski 	empty = !fa;
162*1b481fc3SMaciej Żenczykowski 
163*1b481fc3SMaciej Żenczykowski 	ret = walk_bitset(tb[ETHTOOL_A_FEC_MODES], lm_strings, fec_mode_walk,
164*1b481fc3SMaciej Żenczykowski 			  &empty);
165*1b481fc3SMaciej Żenczykowski 	if (ret < 0)
166*1b481fc3SMaciej Żenczykowski 		goto err_close_dev;
167*1b481fc3SMaciej Żenczykowski 	if (empty)
168*1b481fc3SMaciej Żenczykowski 		print_string(PRINT_ANY, NULL, " %s", "None");
169*1b481fc3SMaciej Żenczykowski 	close_json_array("\n");
170*1b481fc3SMaciej Żenczykowski 
171*1b481fc3SMaciej Żenczykowski 	open_json_array("active", "Active FEC encoding:");
172*1b481fc3SMaciej Żenczykowski 	if (active) {
173*1b481fc3SMaciej Żenczykowski 		name = get_string(lm_strings, active);
174*1b481fc3SMaciej Żenczykowski 		if (name)
175*1b481fc3SMaciej Żenczykowski 			/* Take care of renames */
176*1b481fc3SMaciej Żenczykowski 			fec_mode_walk(active, name, true, NULL);
177*1b481fc3SMaciej Żenczykowski 		else
178*1b481fc3SMaciej Żenczykowski 			print_uint(PRINT_ANY, NULL, " BIT%u", active);
179*1b481fc3SMaciej Żenczykowski 	} else {
180*1b481fc3SMaciej Żenczykowski 		print_string(PRINT_ANY, NULL, " %s", "None");
181*1b481fc3SMaciej Żenczykowski 	}
182*1b481fc3SMaciej Żenczykowski 	close_json_array("\n");
183*1b481fc3SMaciej Żenczykowski 
184*1b481fc3SMaciej Żenczykowski 	if (tb[ETHTOOL_A_FEC_STATS]) {
185*1b481fc3SMaciej Żenczykowski 		ret = fec_show_stats(tb[ETHTOOL_A_FEC_STATS]);
186*1b481fc3SMaciej Żenczykowski 		if (ret < 0)
187*1b481fc3SMaciej Żenczykowski 			goto err_close_dev;
188*1b481fc3SMaciej Żenczykowski 	}
189*1b481fc3SMaciej Żenczykowski 
190*1b481fc3SMaciej Żenczykowski 	close_json_object();
191*1b481fc3SMaciej Żenczykowski 
192*1b481fc3SMaciej Żenczykowski 	return MNL_CB_OK;
193*1b481fc3SMaciej Żenczykowski 
194*1b481fc3SMaciej Żenczykowski err_close_dev:
195*1b481fc3SMaciej Żenczykowski 	close_json_object();
196*1b481fc3SMaciej Żenczykowski 	return err_ret;
197*1b481fc3SMaciej Żenczykowski }
198*1b481fc3SMaciej Żenczykowski 
nl_gfec(struct cmd_context * ctx)199*1b481fc3SMaciej Żenczykowski int nl_gfec(struct cmd_context *ctx)
200*1b481fc3SMaciej Żenczykowski {
201*1b481fc3SMaciej Żenczykowski 	struct nl_context *nlctx = ctx->nlctx;
202*1b481fc3SMaciej Żenczykowski 	struct nl_socket *nlsk = nlctx->ethnl_socket;
203*1b481fc3SMaciej Żenczykowski 	u32 flags;
204*1b481fc3SMaciej Żenczykowski 	int ret;
205*1b481fc3SMaciej Żenczykowski 
206*1b481fc3SMaciej Żenczykowski 	if (netlink_cmd_check(ctx, ETHTOOL_MSG_FEC_GET, true))
207*1b481fc3SMaciej Żenczykowski 		return -EOPNOTSUPP;
208*1b481fc3SMaciej Żenczykowski 	if (ctx->argc > 0) {
209*1b481fc3SMaciej Żenczykowski 		fprintf(stderr, "ethtool: unexpected parameter '%s'\n",
210*1b481fc3SMaciej Żenczykowski 			*ctx->argp);
211*1b481fc3SMaciej Żenczykowski 		return 1;
212*1b481fc3SMaciej Żenczykowski 	}
213*1b481fc3SMaciej Żenczykowski 
214*1b481fc3SMaciej Żenczykowski 	flags = get_stats_flag(nlctx, ETHTOOL_MSG_FEC_GET,
215*1b481fc3SMaciej Żenczykowski 			       ETHTOOL_A_FEC_HEADER);
216*1b481fc3SMaciej Żenczykowski 	ret = nlsock_prep_get_request(nlsk, ETHTOOL_MSG_FEC_GET,
217*1b481fc3SMaciej Żenczykowski 				      ETHTOOL_A_FEC_HEADER, flags);
218*1b481fc3SMaciej Żenczykowski 	if (ret < 0)
219*1b481fc3SMaciej Żenczykowski 		return ret;
220*1b481fc3SMaciej Żenczykowski 
221*1b481fc3SMaciej Żenczykowski 	new_json_obj(ctx->json);
222*1b481fc3SMaciej Żenczykowski 	ret = nlsock_send_get_request(nlsk, fec_reply_cb);
223*1b481fc3SMaciej Żenczykowski 	delete_json_obj();
224*1b481fc3SMaciej Żenczykowski 	return ret;
225*1b481fc3SMaciej Żenczykowski }
226*1b481fc3SMaciej Żenczykowski 
227*1b481fc3SMaciej Żenczykowski /* FEC_SET */
228*1b481fc3SMaciej Żenczykowski 
strupc(char * dst,const char * src)229*1b481fc3SMaciej Żenczykowski static void strupc(char *dst, const char *src)
230*1b481fc3SMaciej Żenczykowski {
231*1b481fc3SMaciej Żenczykowski 	while (*src)
232*1b481fc3SMaciej Żenczykowski 		*dst++ = toupper(*src++);
233*1b481fc3SMaciej Żenczykowski 	*dst = '\0';
234*1b481fc3SMaciej Żenczykowski }
235*1b481fc3SMaciej Żenczykowski 
fec_parse_bitset(struct nl_context * nlctx,uint16_t type,const void * data __maybe_unused,struct nl_msg_buff * msgbuff,void * dest)236*1b481fc3SMaciej Żenczykowski static int fec_parse_bitset(struct nl_context *nlctx, uint16_t type,
237*1b481fc3SMaciej Żenczykowski 			    const void *data __maybe_unused,
238*1b481fc3SMaciej Żenczykowski 			    struct nl_msg_buff *msgbuff, void *dest)
239*1b481fc3SMaciej Żenczykowski {
240*1b481fc3SMaciej Żenczykowski 	struct nlattr *bitset_attr;
241*1b481fc3SMaciej Żenczykowski 	struct nlattr *bits_attr;
242*1b481fc3SMaciej Żenczykowski 	struct nlattr *bit_attr;
243*1b481fc3SMaciej Żenczykowski 	char upper[ETH_GSTRING_LEN];
244*1b481fc3SMaciej Żenczykowski 	bool fec_auto = false;
245*1b481fc3SMaciej Żenczykowski 	int ret;
246*1b481fc3SMaciej Żenczykowski 
247*1b481fc3SMaciej Żenczykowski 	if (!type || dest) {
248*1b481fc3SMaciej Żenczykowski 		fprintf(stderr, "ethtool (%s): internal error parsing '%s'\n",
249*1b481fc3SMaciej Żenczykowski 			nlctx->cmd, nlctx->param);
250*1b481fc3SMaciej Żenczykowski 		return -EFAULT;
251*1b481fc3SMaciej Żenczykowski 	}
252*1b481fc3SMaciej Żenczykowski 
253*1b481fc3SMaciej Żenczykowski 	bitset_attr = ethnla_nest_start(msgbuff, type);
254*1b481fc3SMaciej Żenczykowski 	if (!bitset_attr)
255*1b481fc3SMaciej Żenczykowski 		return -EMSGSIZE;
256*1b481fc3SMaciej Żenczykowski 	ret = -EMSGSIZE;
257*1b481fc3SMaciej Żenczykowski 	if (ethnla_put_flag(msgbuff, ETHTOOL_A_BITSET_NOMASK, true))
258*1b481fc3SMaciej Żenczykowski 		goto err;
259*1b481fc3SMaciej Żenczykowski 	bits_attr = ethnla_nest_start(msgbuff, ETHTOOL_A_BITSET_BITS);
260*1b481fc3SMaciej Żenczykowski 	if (!bits_attr)
261*1b481fc3SMaciej Żenczykowski 		goto err;
262*1b481fc3SMaciej Żenczykowski 
263*1b481fc3SMaciej Żenczykowski 	while (nlctx->argc > 0) {
264*1b481fc3SMaciej Żenczykowski 		const char *name = *nlctx->argp;
265*1b481fc3SMaciej Żenczykowski 
266*1b481fc3SMaciej Żenczykowski 		if (!strcmp(name, "--")) {
267*1b481fc3SMaciej Żenczykowski 			nlctx->argp++;
268*1b481fc3SMaciej Żenczykowski 			nlctx->argc--;
269*1b481fc3SMaciej Żenczykowski 			break;
270*1b481fc3SMaciej Żenczykowski 		}
271*1b481fc3SMaciej Żenczykowski 
272*1b481fc3SMaciej Żenczykowski 		if (!strcasecmp(name, "auto")) {
273*1b481fc3SMaciej Żenczykowski 			fec_auto = true;
274*1b481fc3SMaciej Żenczykowski 			goto next;
275*1b481fc3SMaciej Żenczykowski 		}
276*1b481fc3SMaciej Żenczykowski 		if (!strcasecmp(name, "off")) {
277*1b481fc3SMaciej Żenczykowski 			name = "None";
278*1b481fc3SMaciej Żenczykowski 		} else {
279*1b481fc3SMaciej Żenczykowski 			strupc(upper, name);
280*1b481fc3SMaciej Żenczykowski 			name = upper;
281*1b481fc3SMaciej Żenczykowski 		}
282*1b481fc3SMaciej Żenczykowski 
283*1b481fc3SMaciej Żenczykowski 		ret = -EMSGSIZE;
284*1b481fc3SMaciej Żenczykowski 		bit_attr = ethnla_nest_start(msgbuff,
285*1b481fc3SMaciej Żenczykowski 					     ETHTOOL_A_BITSET_BITS_BIT);
286*1b481fc3SMaciej Żenczykowski 		if (!bit_attr)
287*1b481fc3SMaciej Żenczykowski 			goto err;
288*1b481fc3SMaciej Żenczykowski 		if (ethnla_put_strz(msgbuff, ETHTOOL_A_BITSET_BIT_NAME, name))
289*1b481fc3SMaciej Żenczykowski 			goto err;
290*1b481fc3SMaciej Żenczykowski 		ethnla_nest_end(msgbuff, bit_attr);
291*1b481fc3SMaciej Żenczykowski 
292*1b481fc3SMaciej Żenczykowski next:
293*1b481fc3SMaciej Żenczykowski 		nlctx->argp++;
294*1b481fc3SMaciej Żenczykowski 		nlctx->argc--;
295*1b481fc3SMaciej Żenczykowski 	}
296*1b481fc3SMaciej Żenczykowski 
297*1b481fc3SMaciej Żenczykowski 	ethnla_nest_end(msgbuff, bits_attr);
298*1b481fc3SMaciej Żenczykowski 	ethnla_nest_end(msgbuff, bitset_attr);
299*1b481fc3SMaciej Żenczykowski 
300*1b481fc3SMaciej Żenczykowski 	if (ethnla_put_u8(msgbuff, ETHTOOL_A_FEC_AUTO, fec_auto))
301*1b481fc3SMaciej Żenczykowski 		goto err;
302*1b481fc3SMaciej Żenczykowski 
303*1b481fc3SMaciej Żenczykowski 	return 0;
304*1b481fc3SMaciej Żenczykowski err:
305*1b481fc3SMaciej Żenczykowski 	ethnla_nest_cancel(msgbuff, bitset_attr);
306*1b481fc3SMaciej Żenczykowski 	return ret;
307*1b481fc3SMaciej Żenczykowski }
308*1b481fc3SMaciej Żenczykowski 
309*1b481fc3SMaciej Żenczykowski static const struct param_parser sfec_params[] = {
310*1b481fc3SMaciej Żenczykowski 	{
311*1b481fc3SMaciej Żenczykowski 		.arg		= "encoding",
312*1b481fc3SMaciej Żenczykowski 		.type		= ETHTOOL_A_FEC_MODES,
313*1b481fc3SMaciej Żenczykowski 		.handler	= fec_parse_bitset,
314*1b481fc3SMaciej Żenczykowski 		.min_argc	= 1,
315*1b481fc3SMaciej Żenczykowski 	},
316*1b481fc3SMaciej Żenczykowski 	{}
317*1b481fc3SMaciej Żenczykowski };
318*1b481fc3SMaciej Żenczykowski 
nl_sfec(struct cmd_context * ctx)319*1b481fc3SMaciej Żenczykowski int nl_sfec(struct cmd_context *ctx)
320*1b481fc3SMaciej Żenczykowski {
321*1b481fc3SMaciej Żenczykowski 	struct nl_context *nlctx = ctx->nlctx;
322*1b481fc3SMaciej Żenczykowski 	struct nl_msg_buff *msgbuff;
323*1b481fc3SMaciej Żenczykowski 	struct nl_socket *nlsk;
324*1b481fc3SMaciej Żenczykowski 	int ret;
325*1b481fc3SMaciej Żenczykowski 
326*1b481fc3SMaciej Żenczykowski 	if (netlink_cmd_check(ctx, ETHTOOL_MSG_FEC_SET, false))
327*1b481fc3SMaciej Żenczykowski 		return -EOPNOTSUPP;
328*1b481fc3SMaciej Żenczykowski 	if (!ctx->argc) {
329*1b481fc3SMaciej Żenczykowski 		fprintf(stderr, "ethtool (--set-fec): parameters missing\n");
330*1b481fc3SMaciej Żenczykowski 		return 1;
331*1b481fc3SMaciej Żenczykowski 	}
332*1b481fc3SMaciej Żenczykowski 
333*1b481fc3SMaciej Żenczykowski 	nlctx->cmd = "--set-fec";
334*1b481fc3SMaciej Żenczykowski 	nlctx->argp = ctx->argp;
335*1b481fc3SMaciej Żenczykowski 	nlctx->argc = ctx->argc;
336*1b481fc3SMaciej Żenczykowski 	nlctx->devname = ctx->devname;
337*1b481fc3SMaciej Żenczykowski 	nlsk = nlctx->ethnl_socket;
338*1b481fc3SMaciej Żenczykowski 	msgbuff = &nlsk->msgbuff;
339*1b481fc3SMaciej Żenczykowski 
340*1b481fc3SMaciej Żenczykowski 	ret = msg_init(nlctx, msgbuff, ETHTOOL_MSG_FEC_SET,
341*1b481fc3SMaciej Żenczykowski 		       NLM_F_REQUEST | NLM_F_ACK);
342*1b481fc3SMaciej Żenczykowski 	if (ret < 0)
343*1b481fc3SMaciej Żenczykowski 		return 2;
344*1b481fc3SMaciej Żenczykowski 	if (ethnla_fill_header(msgbuff, ETHTOOL_A_FEC_HEADER,
345*1b481fc3SMaciej Żenczykowski 			       ctx->devname, 0))
346*1b481fc3SMaciej Żenczykowski 		return -EMSGSIZE;
347*1b481fc3SMaciej Żenczykowski 
348*1b481fc3SMaciej Żenczykowski 	ret = nl_parser(nlctx, sfec_params, NULL, PARSER_GROUP_NONE, NULL);
349*1b481fc3SMaciej Żenczykowski 	if (ret < 0)
350*1b481fc3SMaciej Żenczykowski 		return 1;
351*1b481fc3SMaciej Żenczykowski 
352*1b481fc3SMaciej Żenczykowski 	ret = nlsock_sendmsg(nlsk, NULL);
353*1b481fc3SMaciej Żenczykowski 	if (ret < 0)
354*1b481fc3SMaciej Żenczykowski 		return 83;
355*1b481fc3SMaciej Żenczykowski 	ret = nlsock_process_reply(nlsk, nomsg_reply_cb, nlctx);
356*1b481fc3SMaciej Żenczykowski 	if (ret == 0)
357*1b481fc3SMaciej Żenczykowski 		return 0;
358*1b481fc3SMaciej Żenczykowski 	else
359*1b481fc3SMaciej Żenczykowski 		return nlctx->exit_code ?: 83;
360*1b481fc3SMaciej Żenczykowski }
361