xref: /aosp_15_r20/external/ethtool/netlink/parser.c (revision 1b481fc3bb1b45d4cf28d1ec12969dc1055f555d)
1*1b481fc3SMaciej Żenczykowski /*
2*1b481fc3SMaciej Żenczykowski  * parser.c - netlink command line parser
3*1b481fc3SMaciej Żenczykowski  *
4*1b481fc3SMaciej Żenczykowski  * Implementation of command line parser used by netlink code.
5*1b481fc3SMaciej Żenczykowski  */
6*1b481fc3SMaciej Żenczykowski 
7*1b481fc3SMaciej Żenczykowski #include <string.h>
8*1b481fc3SMaciej Żenczykowski #include <stdlib.h>
9*1b481fc3SMaciej Żenczykowski #include <errno.h>
10*1b481fc3SMaciej Żenczykowski #include <ctype.h>
11*1b481fc3SMaciej Żenczykowski 
12*1b481fc3SMaciej Żenczykowski #include "../internal.h"
13*1b481fc3SMaciej Żenczykowski #include "../common.h"
14*1b481fc3SMaciej Żenczykowski #include "netlink.h"
15*1b481fc3SMaciej Żenczykowski #include "parser.h"
16*1b481fc3SMaciej Żenczykowski 
parser_err_unknown_param(struct nl_context * nlctx)17*1b481fc3SMaciej Żenczykowski static void parser_err_unknown_param(struct nl_context *nlctx)
18*1b481fc3SMaciej Żenczykowski {
19*1b481fc3SMaciej Żenczykowski 	fprintf(stderr, "ethtool (%s): unknown parameter '%s'\n", nlctx->cmd,
20*1b481fc3SMaciej Żenczykowski 		nlctx->param);
21*1b481fc3SMaciej Żenczykowski }
22*1b481fc3SMaciej Żenczykowski 
parser_err_dup_param(struct nl_context * nlctx)23*1b481fc3SMaciej Żenczykowski static void parser_err_dup_param(struct nl_context *nlctx)
24*1b481fc3SMaciej Żenczykowski {
25*1b481fc3SMaciej Żenczykowski 	fprintf(stderr, "ethtool (%s): duplicate parameter '%s'\n", nlctx->cmd,
26*1b481fc3SMaciej Żenczykowski 		nlctx->param);
27*1b481fc3SMaciej Żenczykowski }
28*1b481fc3SMaciej Żenczykowski 
parser_err_min_argc(struct nl_context * nlctx,unsigned int min_argc)29*1b481fc3SMaciej Żenczykowski static void parser_err_min_argc(struct nl_context *nlctx, unsigned int min_argc)
30*1b481fc3SMaciej Żenczykowski {
31*1b481fc3SMaciej Żenczykowski 	if (min_argc == 1)
32*1b481fc3SMaciej Żenczykowski 		fprintf(stderr, "ethtool (%s): no value for parameter '%s'\n",
33*1b481fc3SMaciej Żenczykowski 			nlctx->cmd, nlctx->param);
34*1b481fc3SMaciej Żenczykowski 	else
35*1b481fc3SMaciej Żenczykowski 		fprintf(stderr,
36*1b481fc3SMaciej Żenczykowski 			"ethtool (%s): parameter '%s' requires %u words\n",
37*1b481fc3SMaciej Żenczykowski 			nlctx->cmd, nlctx->param, min_argc);
38*1b481fc3SMaciej Żenczykowski }
39*1b481fc3SMaciej Żenczykowski 
parser_err_invalid_value(struct nl_context * nlctx,const char * val)40*1b481fc3SMaciej Żenczykowski static void parser_err_invalid_value(struct nl_context *nlctx, const char *val)
41*1b481fc3SMaciej Żenczykowski {
42*1b481fc3SMaciej Żenczykowski 	fprintf(stderr, "ethtool (%s): invalid value '%s' for parameter '%s'\n",
43*1b481fc3SMaciej Żenczykowski 		nlctx->cmd, val, nlctx->param);
44*1b481fc3SMaciej Żenczykowski }
45*1b481fc3SMaciej Żenczykowski 
parser_err_invalid_flag(struct nl_context * nlctx,const char * flag)46*1b481fc3SMaciej Żenczykowski static void parser_err_invalid_flag(struct nl_context *nlctx, const char *flag)
47*1b481fc3SMaciej Żenczykowski {
48*1b481fc3SMaciej Żenczykowski 	fprintf(stderr, "ethtool (%s): flag '%s' for parameter '%s' is not followed by 'on' or 'off'\n",
49*1b481fc3SMaciej Żenczykowski 		nlctx->cmd, flag, nlctx->param);
50*1b481fc3SMaciej Żenczykowski }
51*1b481fc3SMaciej Żenczykowski 
__prefix_0x(const char * p)52*1b481fc3SMaciej Żenczykowski static bool __prefix_0x(const char *p)
53*1b481fc3SMaciej Żenczykowski {
54*1b481fc3SMaciej Żenczykowski 	return p[0] == '0' && (p[1] == 'x' || p[1] == 'X');
55*1b481fc3SMaciej Żenczykowski }
56*1b481fc3SMaciej Żenczykowski 
parse_float(const char * arg,float * result,float min,float max)57*1b481fc3SMaciej Żenczykowski static float parse_float(const char *arg, float *result, float min,
58*1b481fc3SMaciej Żenczykowski 			 float max)
59*1b481fc3SMaciej Żenczykowski {
60*1b481fc3SMaciej Żenczykowski 	char *endptr;
61*1b481fc3SMaciej Żenczykowski 	float val;
62*1b481fc3SMaciej Żenczykowski 
63*1b481fc3SMaciej Żenczykowski 	if (!arg || !arg[0])
64*1b481fc3SMaciej Żenczykowski 		return -EINVAL;
65*1b481fc3SMaciej Żenczykowski 	val = strtof(arg, &endptr);
66*1b481fc3SMaciej Żenczykowski 	if (*endptr || val < min || val > max)
67*1b481fc3SMaciej Żenczykowski 		return -EINVAL;
68*1b481fc3SMaciej Żenczykowski 
69*1b481fc3SMaciej Żenczykowski 	*result = val;
70*1b481fc3SMaciej Żenczykowski 	return 0;
71*1b481fc3SMaciej Żenczykowski }
72*1b481fc3SMaciej Żenczykowski 
__parse_u32(const char * arg,uint32_t * result,uint32_t min,uint32_t max,int base)73*1b481fc3SMaciej Żenczykowski static int __parse_u32(const char *arg, uint32_t *result, uint32_t min,
74*1b481fc3SMaciej Żenczykowski 		       uint32_t max, int base)
75*1b481fc3SMaciej Żenczykowski {
76*1b481fc3SMaciej Żenczykowski 	unsigned long long val;
77*1b481fc3SMaciej Żenczykowski 	char *endptr;
78*1b481fc3SMaciej Żenczykowski 
79*1b481fc3SMaciej Żenczykowski 	if (!arg || !arg[0])
80*1b481fc3SMaciej Żenczykowski 		return -EINVAL;
81*1b481fc3SMaciej Żenczykowski 	val = strtoul(arg, &endptr, base);
82*1b481fc3SMaciej Żenczykowski 	if (*endptr || val < min || val > max)
83*1b481fc3SMaciej Żenczykowski 		return -EINVAL;
84*1b481fc3SMaciej Żenczykowski 
85*1b481fc3SMaciej Żenczykowski 	*result = (uint32_t)val;
86*1b481fc3SMaciej Żenczykowski 	return 0;
87*1b481fc3SMaciej Żenczykowski }
88*1b481fc3SMaciej Żenczykowski 
parse_u32d(const char * arg,uint32_t * result)89*1b481fc3SMaciej Żenczykowski static int parse_u32d(const char *arg, uint32_t *result)
90*1b481fc3SMaciej Żenczykowski {
91*1b481fc3SMaciej Żenczykowski 	return __parse_u32(arg, result, 0, 0xffffffff, 10);
92*1b481fc3SMaciej Żenczykowski }
93*1b481fc3SMaciej Żenczykowski 
parse_x32(const char * arg,uint32_t * result)94*1b481fc3SMaciej Żenczykowski static int parse_x32(const char *arg, uint32_t *result)
95*1b481fc3SMaciej Żenczykowski {
96*1b481fc3SMaciej Żenczykowski 	return __parse_u32(arg, result, 0, 0xffffffff, 16);
97*1b481fc3SMaciej Żenczykowski }
98*1b481fc3SMaciej Żenczykowski 
parse_u32(const char * arg,uint32_t * result)99*1b481fc3SMaciej Żenczykowski int parse_u32(const char *arg, uint32_t *result)
100*1b481fc3SMaciej Żenczykowski {
101*1b481fc3SMaciej Żenczykowski 	if (!arg)
102*1b481fc3SMaciej Żenczykowski 		return -EINVAL;
103*1b481fc3SMaciej Żenczykowski 	if (__prefix_0x(arg))
104*1b481fc3SMaciej Żenczykowski 		return parse_x32(arg + 2, result);
105*1b481fc3SMaciej Żenczykowski 	else
106*1b481fc3SMaciej Żenczykowski 		return parse_u32d(arg, result);
107*1b481fc3SMaciej Żenczykowski }
108*1b481fc3SMaciej Żenczykowski 
parse_u8(const char * arg,uint8_t * result)109*1b481fc3SMaciej Żenczykowski static int parse_u8(const char *arg, uint8_t *result)
110*1b481fc3SMaciej Żenczykowski {
111*1b481fc3SMaciej Żenczykowski 	uint32_t val;
112*1b481fc3SMaciej Żenczykowski 	int ret = parse_u32(arg, &val);
113*1b481fc3SMaciej Żenczykowski 
114*1b481fc3SMaciej Żenczykowski 	if (ret < 0)
115*1b481fc3SMaciej Żenczykowski 		return ret;
116*1b481fc3SMaciej Żenczykowski 	if (val > UINT8_MAX)
117*1b481fc3SMaciej Żenczykowski 		return -EINVAL;
118*1b481fc3SMaciej Żenczykowski 
119*1b481fc3SMaciej Żenczykowski 	*result = (uint8_t)val;
120*1b481fc3SMaciej Żenczykowski 	return 0;
121*1b481fc3SMaciej Żenczykowski }
122*1b481fc3SMaciej Żenczykowski 
lookup_u32(const char * arg,uint32_t * result,const struct lookup_entry_u32 * tbl)123*1b481fc3SMaciej Żenczykowski static int lookup_u32(const char *arg, uint32_t *result,
124*1b481fc3SMaciej Żenczykowski 		      const struct lookup_entry_u32 *tbl)
125*1b481fc3SMaciej Żenczykowski {
126*1b481fc3SMaciej Żenczykowski 	if (!arg)
127*1b481fc3SMaciej Żenczykowski 		return -EINVAL;
128*1b481fc3SMaciej Żenczykowski 	while (tbl->arg) {
129*1b481fc3SMaciej Żenczykowski 		if (!strcmp(tbl->arg, arg)) {
130*1b481fc3SMaciej Żenczykowski 			*result = tbl->val;
131*1b481fc3SMaciej Żenczykowski 			return 0;
132*1b481fc3SMaciej Żenczykowski 		}
133*1b481fc3SMaciej Żenczykowski 		tbl++;
134*1b481fc3SMaciej Żenczykowski 	}
135*1b481fc3SMaciej Żenczykowski 
136*1b481fc3SMaciej Żenczykowski 	return -EINVAL;
137*1b481fc3SMaciej Żenczykowski }
138*1b481fc3SMaciej Żenczykowski 
lookup_u8(const char * arg,uint8_t * result,const struct lookup_entry_u8 * tbl)139*1b481fc3SMaciej Żenczykowski static int lookup_u8(const char *arg, uint8_t *result,
140*1b481fc3SMaciej Żenczykowski 		     const struct lookup_entry_u8 *tbl)
141*1b481fc3SMaciej Żenczykowski {
142*1b481fc3SMaciej Żenczykowski 	if (!arg)
143*1b481fc3SMaciej Żenczykowski 		return -EINVAL;
144*1b481fc3SMaciej Żenczykowski 	while (tbl->arg) {
145*1b481fc3SMaciej Żenczykowski 		if (!strcmp(tbl->arg, arg)) {
146*1b481fc3SMaciej Żenczykowski 			*result = tbl->val;
147*1b481fc3SMaciej Żenczykowski 			return 0;
148*1b481fc3SMaciej Żenczykowski 		}
149*1b481fc3SMaciej Żenczykowski 		tbl++;
150*1b481fc3SMaciej Żenczykowski 	}
151*1b481fc3SMaciej Żenczykowski 
152*1b481fc3SMaciej Żenczykowski 	return -EINVAL;
153*1b481fc3SMaciej Żenczykowski }
154*1b481fc3SMaciej Żenczykowski 
155*1b481fc3SMaciej Żenczykowski /* Parser handler for a flag. Expects a name (with no additional argument),
156*1b481fc3SMaciej Żenczykowski  * generates NLA_FLAG or sets a bool (if the name was present).
157*1b481fc3SMaciej Żenczykowski  */
nl_parse_flag(struct nl_context * nlctx __maybe_unused,uint16_t type,const void * data __maybe_unused,struct nl_msg_buff * msgbuff,void * dest)158*1b481fc3SMaciej Żenczykowski int nl_parse_flag(struct nl_context *nlctx __maybe_unused, uint16_t type,
159*1b481fc3SMaciej Żenczykowski 		  const void *data __maybe_unused, struct nl_msg_buff *msgbuff,
160*1b481fc3SMaciej Żenczykowski 		  void *dest)
161*1b481fc3SMaciej Żenczykowski {
162*1b481fc3SMaciej Żenczykowski 	if (dest)
163*1b481fc3SMaciej Żenczykowski 		*(bool *)dest = true;
164*1b481fc3SMaciej Żenczykowski 	return (type && ethnla_put_flag(msgbuff, type, true)) ? -EMSGSIZE : 0;
165*1b481fc3SMaciej Żenczykowski }
166*1b481fc3SMaciej Żenczykowski 
167*1b481fc3SMaciej Żenczykowski /* Parser handler for null terminated string. Expects a string argument,
168*1b481fc3SMaciej Żenczykowski  * generates NLA_NUL_STRING or fills const char *
169*1b481fc3SMaciej Żenczykowski  */
nl_parse_string(struct nl_context * nlctx,uint16_t type,const void * data __maybe_unused,struct nl_msg_buff * msgbuff,void * dest)170*1b481fc3SMaciej Żenczykowski int nl_parse_string(struct nl_context *nlctx, uint16_t type,
171*1b481fc3SMaciej Żenczykowski 		    const void *data __maybe_unused,
172*1b481fc3SMaciej Żenczykowski 		    struct nl_msg_buff *msgbuff, void *dest)
173*1b481fc3SMaciej Żenczykowski {
174*1b481fc3SMaciej Żenczykowski 	const char *arg = *nlctx->argp;
175*1b481fc3SMaciej Żenczykowski 
176*1b481fc3SMaciej Żenczykowski 	nlctx->argp++;
177*1b481fc3SMaciej Żenczykowski 	nlctx->argc--;
178*1b481fc3SMaciej Żenczykowski 
179*1b481fc3SMaciej Żenczykowski 	if (dest)
180*1b481fc3SMaciej Żenczykowski 		*(const char **)dest = arg;
181*1b481fc3SMaciej Żenczykowski 	return (type && ethnla_put_strz(msgbuff, type, arg)) ? -EMSGSIZE : 0;
182*1b481fc3SMaciej Żenczykowski }
183*1b481fc3SMaciej Żenczykowski 
184*1b481fc3SMaciej Żenczykowski /* Parser handler for unsigned 32-bit integer. Expects a numeric argument
185*1b481fc3SMaciej Żenczykowski  * (may use 0x prefix), generates NLA_U32 or fills an uint32_t.
186*1b481fc3SMaciej Żenczykowski  */
nl_parse_direct_u32(struct nl_context * nlctx,uint16_t type,const void * data __maybe_unused,struct nl_msg_buff * msgbuff,void * dest)187*1b481fc3SMaciej Żenczykowski int nl_parse_direct_u32(struct nl_context *nlctx, uint16_t type,
188*1b481fc3SMaciej Żenczykowski 			const void *data __maybe_unused,
189*1b481fc3SMaciej Żenczykowski 			struct nl_msg_buff *msgbuff, void *dest)
190*1b481fc3SMaciej Żenczykowski {
191*1b481fc3SMaciej Żenczykowski 	const char *arg = *nlctx->argp;
192*1b481fc3SMaciej Żenczykowski 	uint32_t val;
193*1b481fc3SMaciej Żenczykowski 	int ret;
194*1b481fc3SMaciej Żenczykowski 
195*1b481fc3SMaciej Żenczykowski 	nlctx->argp++;
196*1b481fc3SMaciej Żenczykowski 	nlctx->argc--;
197*1b481fc3SMaciej Żenczykowski 	ret = parse_u32(arg, &val);
198*1b481fc3SMaciej Żenczykowski 	if (ret < 0) {
199*1b481fc3SMaciej Żenczykowski 		parser_err_invalid_value(nlctx, arg);
200*1b481fc3SMaciej Żenczykowski 		return ret;
201*1b481fc3SMaciej Żenczykowski 	}
202*1b481fc3SMaciej Żenczykowski 
203*1b481fc3SMaciej Żenczykowski 	if (dest)
204*1b481fc3SMaciej Żenczykowski 		*(uint32_t *)dest = val;
205*1b481fc3SMaciej Żenczykowski 	return (type && ethnla_put_u32(msgbuff, type, val)) ? -EMSGSIZE : 0;
206*1b481fc3SMaciej Żenczykowski }
207*1b481fc3SMaciej Żenczykowski 
208*1b481fc3SMaciej Żenczykowski /* Parser handler for unsigned 32-bit integer. Expects a numeric argument
209*1b481fc3SMaciej Żenczykowski  * (may use 0x prefix), generates NLA_U32 or fills an uint32_t.
210*1b481fc3SMaciej Żenczykowski  */
nl_parse_direct_u8(struct nl_context * nlctx,uint16_t type,const void * data __maybe_unused,struct nl_msg_buff * msgbuff,void * dest)211*1b481fc3SMaciej Żenczykowski int nl_parse_direct_u8(struct nl_context *nlctx, uint16_t type,
212*1b481fc3SMaciej Żenczykowski 		       const void *data __maybe_unused,
213*1b481fc3SMaciej Żenczykowski 		       struct nl_msg_buff *msgbuff, void *dest)
214*1b481fc3SMaciej Żenczykowski {
215*1b481fc3SMaciej Żenczykowski 	const char *arg = *nlctx->argp;
216*1b481fc3SMaciej Żenczykowski 	uint8_t val;
217*1b481fc3SMaciej Żenczykowski 	int ret;
218*1b481fc3SMaciej Żenczykowski 
219*1b481fc3SMaciej Żenczykowski 	nlctx->argp++;
220*1b481fc3SMaciej Żenczykowski 	nlctx->argc--;
221*1b481fc3SMaciej Żenczykowski 	ret = parse_u8(arg, &val);
222*1b481fc3SMaciej Żenczykowski 	if (ret < 0) {
223*1b481fc3SMaciej Żenczykowski 		parser_err_invalid_value(nlctx, arg);
224*1b481fc3SMaciej Żenczykowski 		return ret;
225*1b481fc3SMaciej Żenczykowski 	}
226*1b481fc3SMaciej Żenczykowski 
227*1b481fc3SMaciej Żenczykowski 	if (dest)
228*1b481fc3SMaciej Żenczykowski 		*(uint8_t *)dest = val;
229*1b481fc3SMaciej Żenczykowski 	return (type && ethnla_put_u8(msgbuff, type, val)) ? -EMSGSIZE : 0;
230*1b481fc3SMaciej Żenczykowski }
231*1b481fc3SMaciej Żenczykowski 
232*1b481fc3SMaciej Żenczykowski /* Parser handler for float meters and convert it to cm. Generates
233*1b481fc3SMaciej Żenczykowski  * NLA_U32 or fills an uint32_t.
234*1b481fc3SMaciej Żenczykowski  */
nl_parse_direct_m2cm(struct nl_context * nlctx,uint16_t type,const void * data __maybe_unused,struct nl_msg_buff * msgbuff,void * dest)235*1b481fc3SMaciej Żenczykowski int nl_parse_direct_m2cm(struct nl_context *nlctx, uint16_t type,
236*1b481fc3SMaciej Żenczykowski 			 const void *data __maybe_unused,
237*1b481fc3SMaciej Żenczykowski 			 struct nl_msg_buff *msgbuff, void *dest)
238*1b481fc3SMaciej Żenczykowski {
239*1b481fc3SMaciej Żenczykowski 	const char *arg = *nlctx->argp;
240*1b481fc3SMaciej Żenczykowski 	float meters = 0.0;
241*1b481fc3SMaciej Żenczykowski 	uint32_t cm;
242*1b481fc3SMaciej Żenczykowski 	int ret;
243*1b481fc3SMaciej Żenczykowski 
244*1b481fc3SMaciej Żenczykowski 	nlctx->argp++;
245*1b481fc3SMaciej Żenczykowski 	nlctx->argc--;
246*1b481fc3SMaciej Żenczykowski 	ret = parse_float(arg, &meters, 0, 150);
247*1b481fc3SMaciej Żenczykowski 	if (ret < 0) {
248*1b481fc3SMaciej Żenczykowski 		parser_err_invalid_value(nlctx, arg);
249*1b481fc3SMaciej Żenczykowski 		return ret;
250*1b481fc3SMaciej Żenczykowski 	}
251*1b481fc3SMaciej Żenczykowski 
252*1b481fc3SMaciej Żenczykowski 	cm = (uint32_t)(meters * 100 + 0.5);
253*1b481fc3SMaciej Żenczykowski 	if (dest)
254*1b481fc3SMaciej Żenczykowski 		*(uint32_t *)dest = cm;
255*1b481fc3SMaciej Żenczykowski 	return (type && ethnla_put_u32(msgbuff, type, cm)) ? -EMSGSIZE : 0;
256*1b481fc3SMaciej Żenczykowski }
257*1b481fc3SMaciej Żenczykowski 
258*1b481fc3SMaciej Żenczykowski /* Parser handler for (tri-state) bool. Expects "name on|off", generates
259*1b481fc3SMaciej Żenczykowski  * NLA_U8 which is 1 for "on" and 0 for "off".
260*1b481fc3SMaciej Żenczykowski  */
nl_parse_u8bool(struct nl_context * nlctx,uint16_t type,const void * data __maybe_unused,struct nl_msg_buff * msgbuff,void * dest)261*1b481fc3SMaciej Żenczykowski int nl_parse_u8bool(struct nl_context *nlctx, uint16_t type,
262*1b481fc3SMaciej Żenczykowski 		    const void *data __maybe_unused,
263*1b481fc3SMaciej Żenczykowski 		    struct nl_msg_buff *msgbuff, void *dest)
264*1b481fc3SMaciej Żenczykowski {
265*1b481fc3SMaciej Żenczykowski 	const char *arg = *nlctx->argp;
266*1b481fc3SMaciej Żenczykowski 	int ret;
267*1b481fc3SMaciej Żenczykowski 
268*1b481fc3SMaciej Żenczykowski 	nlctx->argp++;
269*1b481fc3SMaciej Żenczykowski 	nlctx->argc--;
270*1b481fc3SMaciej Żenczykowski 	if (!strcmp(arg, "on")) {
271*1b481fc3SMaciej Żenczykowski 		if (dest)
272*1b481fc3SMaciej Żenczykowski 			*(uint8_t *)dest = 1;
273*1b481fc3SMaciej Żenczykowski 		ret = type ? ethnla_put_u8(msgbuff, type, 1) : 0;
274*1b481fc3SMaciej Żenczykowski 	} else if (!strcmp(arg, "off")) {
275*1b481fc3SMaciej Żenczykowski 		if (dest)
276*1b481fc3SMaciej Żenczykowski 			*(uint8_t *)dest = 0;
277*1b481fc3SMaciej Żenczykowski 		ret = type ? ethnla_put_u8(msgbuff, type, 0) : 0;
278*1b481fc3SMaciej Żenczykowski 	} else {
279*1b481fc3SMaciej Żenczykowski 		parser_err_invalid_value(nlctx, arg);
280*1b481fc3SMaciej Żenczykowski 		return -EINVAL;
281*1b481fc3SMaciej Żenczykowski 	}
282*1b481fc3SMaciej Żenczykowski 
283*1b481fc3SMaciej Żenczykowski 	return ret ? -EMSGSIZE : 0;
284*1b481fc3SMaciej Żenczykowski }
285*1b481fc3SMaciej Żenczykowski 
286*1b481fc3SMaciej Żenczykowski /* Parser handler for 32-bit lookup value. Expects a string argument, looks it
287*1b481fc3SMaciej Żenczykowski  * up in a table, generates NLA_U32 or fills uint32_t variable. The @data
288*1b481fc3SMaciej Żenczykowski  * parameter is a null terminated array of struct lookup_entry_u32.
289*1b481fc3SMaciej Żenczykowski  */
nl_parse_lookup_u32(struct nl_context * nlctx,uint16_t type,const void * data,struct nl_msg_buff * msgbuff,void * dest)290*1b481fc3SMaciej Żenczykowski int nl_parse_lookup_u32(struct nl_context *nlctx, uint16_t type,
291*1b481fc3SMaciej Żenczykowski 			const void *data, struct nl_msg_buff *msgbuff,
292*1b481fc3SMaciej Żenczykowski 			void *dest)
293*1b481fc3SMaciej Żenczykowski {
294*1b481fc3SMaciej Żenczykowski 	const char *arg = *nlctx->argp;
295*1b481fc3SMaciej Żenczykowski 	uint32_t val;
296*1b481fc3SMaciej Żenczykowski 	int ret;
297*1b481fc3SMaciej Żenczykowski 
298*1b481fc3SMaciej Żenczykowski 	nlctx->argp++;
299*1b481fc3SMaciej Żenczykowski 	nlctx->argc--;
300*1b481fc3SMaciej Żenczykowski 	ret = lookup_u32(arg, &val, data);
301*1b481fc3SMaciej Żenczykowski 	if (ret < 0) {
302*1b481fc3SMaciej Żenczykowski 		parser_err_invalid_value(nlctx, arg);
303*1b481fc3SMaciej Żenczykowski 		return ret;
304*1b481fc3SMaciej Żenczykowski 	}
305*1b481fc3SMaciej Żenczykowski 
306*1b481fc3SMaciej Żenczykowski 	if (dest)
307*1b481fc3SMaciej Żenczykowski 		*(uint32_t *)dest = val;
308*1b481fc3SMaciej Żenczykowski 	return (type && ethnla_put_u32(msgbuff, type, val)) ? -EMSGSIZE : 0;
309*1b481fc3SMaciej Żenczykowski }
310*1b481fc3SMaciej Żenczykowski 
311*1b481fc3SMaciej Żenczykowski /* Parser handler for 8-bit lookup value. Expects a string argument, looks it
312*1b481fc3SMaciej Żenczykowski  * up in a table, generates NLA_U8 or fills uint8_t variable. The @data
313*1b481fc3SMaciej Żenczykowski  * parameter is a null terminated array of struct lookup_entry_u8.
314*1b481fc3SMaciej Żenczykowski  */
nl_parse_lookup_u8(struct nl_context * nlctx,uint16_t type,const void * data,struct nl_msg_buff * msgbuff,void * dest)315*1b481fc3SMaciej Żenczykowski int nl_parse_lookup_u8(struct nl_context *nlctx, uint16_t type,
316*1b481fc3SMaciej Żenczykowski 		       const void *data, struct nl_msg_buff *msgbuff,
317*1b481fc3SMaciej Żenczykowski 		       void *dest)
318*1b481fc3SMaciej Żenczykowski {
319*1b481fc3SMaciej Żenczykowski 	const char *arg = *nlctx->argp;
320*1b481fc3SMaciej Żenczykowski 	uint8_t val;
321*1b481fc3SMaciej Żenczykowski 	int ret;
322*1b481fc3SMaciej Żenczykowski 
323*1b481fc3SMaciej Żenczykowski 	nlctx->argp++;
324*1b481fc3SMaciej Żenczykowski 	nlctx->argc--;
325*1b481fc3SMaciej Żenczykowski 	ret = lookup_u8(arg, &val, data);
326*1b481fc3SMaciej Żenczykowski 	if (ret < 0) {
327*1b481fc3SMaciej Żenczykowski 		parser_err_invalid_value(nlctx, arg);
328*1b481fc3SMaciej Żenczykowski 		return ret;
329*1b481fc3SMaciej Żenczykowski 	}
330*1b481fc3SMaciej Żenczykowski 
331*1b481fc3SMaciej Żenczykowski 	if (dest)
332*1b481fc3SMaciej Żenczykowski 		*(uint8_t *)dest = val;
333*1b481fc3SMaciej Żenczykowski 	return (type && ethnla_put_u8(msgbuff, type, val)) ? -EMSGSIZE : 0;
334*1b481fc3SMaciej Żenczykowski }
335*1b481fc3SMaciej Żenczykowski 
336*1b481fc3SMaciej Żenczykowski /* number of significant bits */
__nsb(uint32_t x)337*1b481fc3SMaciej Żenczykowski static unsigned int __nsb(uint32_t x)
338*1b481fc3SMaciej Żenczykowski {
339*1b481fc3SMaciej Żenczykowski 	unsigned int ret = 0;
340*1b481fc3SMaciej Żenczykowski 
341*1b481fc3SMaciej Żenczykowski 	if (x & 0xffff0000U) {
342*1b481fc3SMaciej Żenczykowski 		x >>= 16;
343*1b481fc3SMaciej Żenczykowski 		ret += 16;
344*1b481fc3SMaciej Żenczykowski 	}
345*1b481fc3SMaciej Żenczykowski 	if (x & 0xff00U) {
346*1b481fc3SMaciej Żenczykowski 		x >>= 8;
347*1b481fc3SMaciej Żenczykowski 		ret += 8;
348*1b481fc3SMaciej Żenczykowski 	}
349*1b481fc3SMaciej Żenczykowski 	if (x & 0xf0U) {
350*1b481fc3SMaciej Żenczykowski 		x >>= 4;
351*1b481fc3SMaciej Żenczykowski 		ret += 4;
352*1b481fc3SMaciej Żenczykowski 	}
353*1b481fc3SMaciej Żenczykowski 	if (x & 0xcU) {
354*1b481fc3SMaciej Żenczykowski 		x >>= 2;
355*1b481fc3SMaciej Żenczykowski 		ret += 2;
356*1b481fc3SMaciej Żenczykowski 	}
357*1b481fc3SMaciej Żenczykowski 	if (x & 0x2U) {
358*1b481fc3SMaciej Żenczykowski 		x >>= 1;
359*1b481fc3SMaciej Żenczykowski 		ret += 1;
360*1b481fc3SMaciej Żenczykowski 	}
361*1b481fc3SMaciej Żenczykowski 
362*1b481fc3SMaciej Żenczykowski 	return ret + x;
363*1b481fc3SMaciej Żenczykowski }
364*1b481fc3SMaciej Żenczykowski 
__is_hex(char c)365*1b481fc3SMaciej Żenczykowski static bool __is_hex(char c)
366*1b481fc3SMaciej Żenczykowski {
367*1b481fc3SMaciej Żenczykowski 	if (isdigit(c))
368*1b481fc3SMaciej Żenczykowski 		return true;
369*1b481fc3SMaciej Żenczykowski 	else
370*1b481fc3SMaciej Żenczykowski 		return (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
371*1b481fc3SMaciej Żenczykowski }
372*1b481fc3SMaciej Żenczykowski 
__hex_val(char c)373*1b481fc3SMaciej Żenczykowski static unsigned int __hex_val(char c)
374*1b481fc3SMaciej Żenczykowski {
375*1b481fc3SMaciej Żenczykowski 	if (c >= '0' && c <= '9')
376*1b481fc3SMaciej Żenczykowski 		return c - '0';
377*1b481fc3SMaciej Żenczykowski 	if (c >= 'a' && c <= 'f')
378*1b481fc3SMaciej Żenczykowski 		return c - 'a' + 0xa;
379*1b481fc3SMaciej Żenczykowski 	if (c >= 'A' && c <= 'F')
380*1b481fc3SMaciej Żenczykowski 		return c - 'A' + 0xa;
381*1b481fc3SMaciej Żenczykowski 	return 0;
382*1b481fc3SMaciej Żenczykowski }
383*1b481fc3SMaciej Żenczykowski 
__bytestr_delim(const char * p,char delim)384*1b481fc3SMaciej Żenczykowski static bool __bytestr_delim(const char *p, char delim)
385*1b481fc3SMaciej Żenczykowski {
386*1b481fc3SMaciej Żenczykowski 	return !*p || (delim ? (*p == delim) : !__is_hex(*p));
387*1b481fc3SMaciej Żenczykowski }
388*1b481fc3SMaciej Żenczykowski 
389*1b481fc3SMaciej Żenczykowski /* Parser handler for generic byte string in MAC-like format. Expects string
390*1b481fc3SMaciej Żenczykowski  * argument in the "[[:xdigit:]]{2}(:[[:xdigit:]]{2})*" format, generates
391*1b481fc3SMaciej Żenczykowski  * NLA_BINARY or fills a struct byte_str_value (if @dest is not null and the
392*1b481fc3SMaciej Żenczykowski  * handler succeeds, caller is responsible for freeing the value). The @data
393*1b481fc3SMaciej Żenczykowski  * parameter points to struct byte_str_parser_data.
394*1b481fc3SMaciej Żenczykowski  */
nl_parse_byte_str(struct nl_context * nlctx,uint16_t type,const void * data,struct nl_msg_buff * msgbuff,void * dest)395*1b481fc3SMaciej Żenczykowski int nl_parse_byte_str(struct nl_context *nlctx, uint16_t type, const void *data,
396*1b481fc3SMaciej Żenczykowski 		      struct nl_msg_buff *msgbuff, void *dest)
397*1b481fc3SMaciej Żenczykowski {
398*1b481fc3SMaciej Żenczykowski 	const struct byte_str_parser_data *pdata = data;
399*1b481fc3SMaciej Żenczykowski 	struct byte_str_value *dest_value = dest;
400*1b481fc3SMaciej Żenczykowski 	const char *arg = *nlctx->argp;
401*1b481fc3SMaciej Żenczykowski 	uint8_t *val = NULL;
402*1b481fc3SMaciej Żenczykowski 	unsigned int len, i;
403*1b481fc3SMaciej Żenczykowski 	const char *p;
404*1b481fc3SMaciej Żenczykowski 	int ret;
405*1b481fc3SMaciej Żenczykowski 
406*1b481fc3SMaciej Żenczykowski 	nlctx->argp++;
407*1b481fc3SMaciej Żenczykowski 	nlctx->argc--;
408*1b481fc3SMaciej Żenczykowski 
409*1b481fc3SMaciej Żenczykowski 	len = 0;
410*1b481fc3SMaciej Żenczykowski 	p = arg;
411*1b481fc3SMaciej Żenczykowski 	if (!*p)
412*1b481fc3SMaciej Żenczykowski 		goto err;
413*1b481fc3SMaciej Żenczykowski 	while (true) {
414*1b481fc3SMaciej Żenczykowski 		len++;
415*1b481fc3SMaciej Żenczykowski 		if (!__bytestr_delim(p, pdata->delim))
416*1b481fc3SMaciej Żenczykowski 			p++;
417*1b481fc3SMaciej Żenczykowski 		if (!__bytestr_delim(p, pdata->delim))
418*1b481fc3SMaciej Żenczykowski 			p++;
419*1b481fc3SMaciej Żenczykowski 		if (!__bytestr_delim(p, pdata->delim))
420*1b481fc3SMaciej Żenczykowski 			goto err;
421*1b481fc3SMaciej Żenczykowski 		if (!*p)
422*1b481fc3SMaciej Żenczykowski 			break;
423*1b481fc3SMaciej Żenczykowski 		p++;
424*1b481fc3SMaciej Żenczykowski 		if (*p && __bytestr_delim(p, pdata->delim))
425*1b481fc3SMaciej Żenczykowski 			goto err;
426*1b481fc3SMaciej Żenczykowski 	}
427*1b481fc3SMaciej Żenczykowski 	if (len < pdata->min_len || (pdata->max_len && len > pdata->max_len))
428*1b481fc3SMaciej Żenczykowski 		goto err;
429*1b481fc3SMaciej Żenczykowski 	val = malloc(len);
430*1b481fc3SMaciej Żenczykowski 	if (!val)
431*1b481fc3SMaciej Żenczykowski 		return -ENOMEM;
432*1b481fc3SMaciej Żenczykowski 
433*1b481fc3SMaciej Żenczykowski 	p = arg;
434*1b481fc3SMaciej Żenczykowski 	for (i = 0; i < len; i++) {
435*1b481fc3SMaciej Żenczykowski 		uint8_t byte = 0;
436*1b481fc3SMaciej Żenczykowski 
437*1b481fc3SMaciej Żenczykowski 		if (!__is_hex(*p))
438*1b481fc3SMaciej Żenczykowski 			goto err;
439*1b481fc3SMaciej Żenczykowski 		while (__is_hex(*p))
440*1b481fc3SMaciej Żenczykowski 			byte = 16 * byte + __hex_val(*p++);
441*1b481fc3SMaciej Żenczykowski 		if (!__bytestr_delim(p, pdata->delim))
442*1b481fc3SMaciej Żenczykowski 			goto err;
443*1b481fc3SMaciej Żenczykowski 		val[i] = byte;
444*1b481fc3SMaciej Żenczykowski 		if (*p)
445*1b481fc3SMaciej Żenczykowski 			p++;
446*1b481fc3SMaciej Żenczykowski 	}
447*1b481fc3SMaciej Żenczykowski 	ret = type ? ethnla_put(msgbuff, type, len, val) : 0;
448*1b481fc3SMaciej Żenczykowski 	if (dest) {
449*1b481fc3SMaciej Żenczykowski 		dest_value->len = len;
450*1b481fc3SMaciej Żenczykowski 		dest_value->data = val;
451*1b481fc3SMaciej Żenczykowski 	} else {
452*1b481fc3SMaciej Żenczykowski 		free(val);
453*1b481fc3SMaciej Żenczykowski 	}
454*1b481fc3SMaciej Żenczykowski 	return ret;
455*1b481fc3SMaciej Żenczykowski 
456*1b481fc3SMaciej Żenczykowski err:
457*1b481fc3SMaciej Żenczykowski 	free(val);
458*1b481fc3SMaciej Żenczykowski 	fprintf(stderr, "ethtool (%s): invalid value '%s' of parameter '%s'\n",
459*1b481fc3SMaciej Żenczykowski 		nlctx->cmd, arg, nlctx->param);
460*1b481fc3SMaciej Żenczykowski 	return -EINVAL;
461*1b481fc3SMaciej Żenczykowski }
462*1b481fc3SMaciej Żenczykowski 
463*1b481fc3SMaciej Żenczykowski /* Parser handler for parameters recognized for backward compatibility but
464*1b481fc3SMaciej Żenczykowski  * supposed to fail without passing to kernel. Does not generate any netlink
465*1b481fc3SMaciej Żenczykowski  * attributes of fill any variable. The @data parameter points to struct
466*1b481fc3SMaciej Żenczykowski  * error_parser_params (error message, return value and number of extra
467*1b481fc3SMaciej Żenczykowski  * arguments to skip).
468*1b481fc3SMaciej Żenczykowski  */
nl_parse_error(struct nl_context * nlctx,uint16_t type __maybe_unused,const void * data,struct nl_msg_buff * msgbuff __maybe_unused,void * dest __maybe_unused)469*1b481fc3SMaciej Żenczykowski int nl_parse_error(struct nl_context *nlctx, uint16_t type __maybe_unused,
470*1b481fc3SMaciej Żenczykowski 		   const void *data, struct nl_msg_buff *msgbuff __maybe_unused,
471*1b481fc3SMaciej Żenczykowski 		   void *dest __maybe_unused)
472*1b481fc3SMaciej Żenczykowski {
473*1b481fc3SMaciej Żenczykowski 	const struct error_parser_data *parser_data = data;
474*1b481fc3SMaciej Żenczykowski 	unsigned int skip = parser_data->extra_args;
475*1b481fc3SMaciej Żenczykowski 
476*1b481fc3SMaciej Żenczykowski 	fprintf(stderr, "ethtool (%s): ", nlctx->cmd);
477*1b481fc3SMaciej Żenczykowski 	fprintf(stderr, parser_data->err_msg, nlctx->param);
478*1b481fc3SMaciej Żenczykowski 	if (nlctx->argc < skip) {
479*1b481fc3SMaciej Żenczykowski 		fprintf(stderr, "ethtool (%s): too few arguments for parameter '%s' (expected %u)\n",
480*1b481fc3SMaciej Żenczykowski 			nlctx->cmd, nlctx->param, skip);
481*1b481fc3SMaciej Żenczykowski 	} else {
482*1b481fc3SMaciej Żenczykowski 		nlctx->argp += skip;
483*1b481fc3SMaciej Żenczykowski 		nlctx->argc -= skip;
484*1b481fc3SMaciej Żenczykowski 	}
485*1b481fc3SMaciej Żenczykowski 
486*1b481fc3SMaciej Żenczykowski 	return parser_data->ret_val;
487*1b481fc3SMaciej Żenczykowski }
488*1b481fc3SMaciej Żenczykowski 
489*1b481fc3SMaciej Żenczykowski /* bitset parser handlers */
490*1b481fc3SMaciej Żenczykowski 
491*1b481fc3SMaciej Żenczykowski /* Return true if a bitset argument should be parsed as numeric, i.e.
492*1b481fc3SMaciej Żenczykowski  * (a) it starts with '0x'
493*1b481fc3SMaciej Żenczykowski  * (b) it consists only of hex digits and at most one slash which can be
494*1b481fc3SMaciej Żenczykowski  *     optionally followed by "0x"; if no_mask is true, slash is not allowed
495*1b481fc3SMaciej Żenczykowski  */
is_numeric_bitset(const char * arg,bool no_mask)496*1b481fc3SMaciej Żenczykowski static bool is_numeric_bitset(const char *arg, bool no_mask)
497*1b481fc3SMaciej Żenczykowski {
498*1b481fc3SMaciej Żenczykowski 	const char *p = arg;
499*1b481fc3SMaciej Żenczykowski 	bool has_slash = false;
500*1b481fc3SMaciej Żenczykowski 
501*1b481fc3SMaciej Żenczykowski 	if (!arg)
502*1b481fc3SMaciej Żenczykowski 		return false;
503*1b481fc3SMaciej Żenczykowski 	if (__prefix_0x(arg))
504*1b481fc3SMaciej Żenczykowski 		return true;
505*1b481fc3SMaciej Żenczykowski 	while (*p) {
506*1b481fc3SMaciej Żenczykowski 		if (*p == '/') {
507*1b481fc3SMaciej Żenczykowski 			if (has_slash || no_mask)
508*1b481fc3SMaciej Żenczykowski 				return false;
509*1b481fc3SMaciej Żenczykowski 			has_slash = true;
510*1b481fc3SMaciej Żenczykowski 			p++;
511*1b481fc3SMaciej Żenczykowski 			if (__prefix_0x(p))
512*1b481fc3SMaciej Żenczykowski 				p += 2;
513*1b481fc3SMaciej Żenczykowski 			continue;
514*1b481fc3SMaciej Żenczykowski 		}
515*1b481fc3SMaciej Żenczykowski 		if (!__is_hex(*p))
516*1b481fc3SMaciej Żenczykowski 			return false;
517*1b481fc3SMaciej Żenczykowski 		p++;
518*1b481fc3SMaciej Żenczykowski 	}
519*1b481fc3SMaciej Żenczykowski 	return true;
520*1b481fc3SMaciej Żenczykowski }
521*1b481fc3SMaciej Żenczykowski 
522*1b481fc3SMaciej Żenczykowski #define __MAX_U32_DIGITS 10
523*1b481fc3SMaciej Żenczykowski 
524*1b481fc3SMaciej Żenczykowski /* Parse hex string (without leading "0x") into a bitmap consisting of 32-bit
525*1b481fc3SMaciej Żenczykowski  * words. Caller must make sure arg is at least len characters long and dst has
526*1b481fc3SMaciej Żenczykowski  * place for at least (len + 7) / 8 32-bit words. If force_hex is false, allow
527*1b481fc3SMaciej Żenczykowski  * also base 10 unsigned 32-bit value.
528*1b481fc3SMaciej Żenczykowski  *
529*1b481fc3SMaciej Żenczykowski  * Returns number of significant bits in the bitmap on success and negative
530*1b481fc3SMaciej Żenczykowski  * value on error.
531*1b481fc3SMaciej Żenczykowski  */
__parse_num_string(const char * arg,unsigned int len,uint32_t * dst,bool force_hex)532*1b481fc3SMaciej Żenczykowski static int __parse_num_string(const char *arg, unsigned int len, uint32_t *dst,
533*1b481fc3SMaciej Żenczykowski 			      bool force_hex)
534*1b481fc3SMaciej Żenczykowski {
535*1b481fc3SMaciej Żenczykowski 	char buff[__MAX_U32_DIGITS + 1] = {};
536*1b481fc3SMaciej Żenczykowski 	unsigned int nbits = 0;
537*1b481fc3SMaciej Żenczykowski 	const char *p = arg;
538*1b481fc3SMaciej Żenczykowski 
539*1b481fc3SMaciej Żenczykowski 	if (!len)
540*1b481fc3SMaciej Żenczykowski 		return -EINVAL;
541*1b481fc3SMaciej Żenczykowski 	if (!force_hex && len <= __MAX_U32_DIGITS) {
542*1b481fc3SMaciej Żenczykowski 		strncpy(buff, arg, len);
543*1b481fc3SMaciej Żenczykowski 		if (!buff[__MAX_U32_DIGITS]) {
544*1b481fc3SMaciej Żenczykowski 			u32 val;
545*1b481fc3SMaciej Żenczykowski 			int ret;
546*1b481fc3SMaciej Żenczykowski 
547*1b481fc3SMaciej Żenczykowski 			ret = parse_u32d(buff, &val);
548*1b481fc3SMaciej Żenczykowski 			if (!ret) {
549*1b481fc3SMaciej Żenczykowski 				*dst = val;
550*1b481fc3SMaciej Żenczykowski 				return __nsb(val);
551*1b481fc3SMaciej Żenczykowski 			}
552*1b481fc3SMaciej Żenczykowski 		}
553*1b481fc3SMaciej Żenczykowski 	}
554*1b481fc3SMaciej Żenczykowski 
555*1b481fc3SMaciej Żenczykowski 	dst += (len - 1) / 8;
556*1b481fc3SMaciej Żenczykowski 	while (len > 0) {
557*1b481fc3SMaciej Żenczykowski 		unsigned int chunk = (len % 8) ?: 8;
558*1b481fc3SMaciej Żenczykowski 		unsigned long val;
559*1b481fc3SMaciej Żenczykowski 		char *endp;
560*1b481fc3SMaciej Żenczykowski 
561*1b481fc3SMaciej Żenczykowski 		memcpy(buff, p, chunk);
562*1b481fc3SMaciej Żenczykowski 		buff[chunk] = '\0';
563*1b481fc3SMaciej Żenczykowski 		val = strtoul(buff, &endp, 16);
564*1b481fc3SMaciej Żenczykowski 		if (*endp)
565*1b481fc3SMaciej Żenczykowski 			return -EINVAL;
566*1b481fc3SMaciej Żenczykowski 		*dst-- = (uint32_t)val;
567*1b481fc3SMaciej Żenczykowski 		if (nbits)
568*1b481fc3SMaciej Żenczykowski 			nbits += 4 * chunk;
569*1b481fc3SMaciej Żenczykowski 		else
570*1b481fc3SMaciej Żenczykowski 			nbits = __nsb(val);
571*1b481fc3SMaciej Żenczykowski 
572*1b481fc3SMaciej Żenczykowski 		p += chunk;
573*1b481fc3SMaciej Żenczykowski 		len -= chunk;
574*1b481fc3SMaciej Żenczykowski 	}
575*1b481fc3SMaciej Żenczykowski 	return nbits;
576*1b481fc3SMaciej Żenczykowski }
577*1b481fc3SMaciej Żenczykowski 
578*1b481fc3SMaciej Żenczykowski /* Parse bitset provided as a base 16 numeric value (@no_mask is true) or pair
579*1b481fc3SMaciej Żenczykowski  * of base 16 numeric values  separated by '/' (@no_mask is false). The "0x"
580*1b481fc3SMaciej Żenczykowski  * prefix is optional. Generates bitset nested attribute in compact form.
581*1b481fc3SMaciej Żenczykowski  */
parse_numeric_bitset(struct nl_context * nlctx,uint16_t type,bool no_mask,bool force_hex,struct nl_msg_buff * msgbuff)582*1b481fc3SMaciej Żenczykowski static int parse_numeric_bitset(struct nl_context *nlctx, uint16_t type,
583*1b481fc3SMaciej Żenczykowski 				bool no_mask, bool force_hex,
584*1b481fc3SMaciej Żenczykowski 				struct nl_msg_buff *msgbuff)
585*1b481fc3SMaciej Żenczykowski {
586*1b481fc3SMaciej Żenczykowski 	unsigned int nwords, len1, len2;
587*1b481fc3SMaciej Żenczykowski 	const char *arg = *nlctx->argp;
588*1b481fc3SMaciej Żenczykowski 	bool force_hex1 = force_hex;
589*1b481fc3SMaciej Żenczykowski 	bool force_hex2 = force_hex;
590*1b481fc3SMaciej Żenczykowski 	uint32_t *value = NULL;
591*1b481fc3SMaciej Żenczykowski 	uint32_t *mask = NULL;
592*1b481fc3SMaciej Żenczykowski 	struct nlattr *nest;
593*1b481fc3SMaciej Żenczykowski 	const char *maskptr;
594*1b481fc3SMaciej Żenczykowski 	int ret = 0;
595*1b481fc3SMaciej Żenczykowski 	int nbits;
596*1b481fc3SMaciej Żenczykowski 
597*1b481fc3SMaciej Żenczykowski 	if (__prefix_0x(arg)) {
598*1b481fc3SMaciej Żenczykowski 		force_hex1 = true;
599*1b481fc3SMaciej Żenczykowski 		arg += 2;
600*1b481fc3SMaciej Żenczykowski 	}
601*1b481fc3SMaciej Żenczykowski 
602*1b481fc3SMaciej Żenczykowski 	maskptr = strchr(arg, '/');
603*1b481fc3SMaciej Żenczykowski 	if (maskptr && no_mask) {
604*1b481fc3SMaciej Żenczykowski 		parser_err_invalid_value(nlctx, arg);
605*1b481fc3SMaciej Żenczykowski 		return -EINVAL;
606*1b481fc3SMaciej Żenczykowski 	}
607*1b481fc3SMaciej Żenczykowski 	len1 = maskptr ? (unsigned int)(maskptr - arg) : strlen(arg);
608*1b481fc3SMaciej Żenczykowski 	nwords = DIV_ROUND_UP(len1, 8);
609*1b481fc3SMaciej Żenczykowski 	nbits = 0;
610*1b481fc3SMaciej Żenczykowski 
611*1b481fc3SMaciej Żenczykowski 	if (maskptr) {
612*1b481fc3SMaciej Żenczykowski 		maskptr++;
613*1b481fc3SMaciej Żenczykowski 		if (__prefix_0x(maskptr)) {
614*1b481fc3SMaciej Żenczykowski 			maskptr += 2;
615*1b481fc3SMaciej Żenczykowski 			force_hex2 = true;
616*1b481fc3SMaciej Żenczykowski 		}
617*1b481fc3SMaciej Żenczykowski 		len2 = strlen(maskptr);
618*1b481fc3SMaciej Żenczykowski 		if (len2 > len1)
619*1b481fc3SMaciej Żenczykowski 			nwords = DIV_ROUND_UP(len2, 8);
620*1b481fc3SMaciej Żenczykowski 		mask = calloc(nwords, sizeof(uint32_t));
621*1b481fc3SMaciej Żenczykowski 		if (!mask)
622*1b481fc3SMaciej Żenczykowski 			return -ENOMEM;
623*1b481fc3SMaciej Żenczykowski 		ret = __parse_num_string(maskptr, strlen(maskptr), mask,
624*1b481fc3SMaciej Żenczykowski 					 force_hex2);
625*1b481fc3SMaciej Żenczykowski 		if (ret < 0) {
626*1b481fc3SMaciej Żenczykowski 			parser_err_invalid_value(nlctx, arg);
627*1b481fc3SMaciej Żenczykowski 			goto out_free;
628*1b481fc3SMaciej Żenczykowski 		}
629*1b481fc3SMaciej Żenczykowski 		nbits = ret;
630*1b481fc3SMaciej Żenczykowski 	}
631*1b481fc3SMaciej Żenczykowski 
632*1b481fc3SMaciej Żenczykowski 	value = calloc(nwords, sizeof(uint32_t));
633*1b481fc3SMaciej Żenczykowski 	if (!value) {
634*1b481fc3SMaciej Żenczykowski 		free(mask);
635*1b481fc3SMaciej Żenczykowski 		return -ENOMEM;
636*1b481fc3SMaciej Żenczykowski 	}
637*1b481fc3SMaciej Żenczykowski 	ret = __parse_num_string(arg, len1, value, force_hex1);
638*1b481fc3SMaciej Żenczykowski 	if (ret < 0) {
639*1b481fc3SMaciej Żenczykowski 		parser_err_invalid_value(nlctx, arg);
640*1b481fc3SMaciej Żenczykowski 		goto out_free;
641*1b481fc3SMaciej Żenczykowski 	}
642*1b481fc3SMaciej Żenczykowski 	nbits = (nbits < ret) ? ret : nbits;
643*1b481fc3SMaciej Żenczykowski 	nwords = (nbits + 31) / 32;
644*1b481fc3SMaciej Żenczykowski 
645*1b481fc3SMaciej Żenczykowski 	ret = 0;
646*1b481fc3SMaciej Żenczykowski 	if (!type)
647*1b481fc3SMaciej Żenczykowski 		goto out_free;
648*1b481fc3SMaciej Żenczykowski 	ret = -EMSGSIZE;
649*1b481fc3SMaciej Żenczykowski 	nest = ethnla_nest_start(msgbuff, type);
650*1b481fc3SMaciej Żenczykowski 	if (!nest)
651*1b481fc3SMaciej Żenczykowski 	       goto out_free;
652*1b481fc3SMaciej Żenczykowski 	if (ethnla_put_flag(msgbuff, ETHTOOL_A_BITSET_NOMASK, !mask) ||
653*1b481fc3SMaciej Żenczykowski 	    ethnla_put_u32(msgbuff, ETHTOOL_A_BITSET_SIZE, nbits) ||
654*1b481fc3SMaciej Żenczykowski 	    ethnla_put(msgbuff, ETHTOOL_A_BITSET_VALUE,
655*1b481fc3SMaciej Żenczykowski 		       nwords * sizeof(uint32_t), value) ||
656*1b481fc3SMaciej Żenczykowski 	    (mask &&
657*1b481fc3SMaciej Żenczykowski 	     ethnla_put(msgbuff, ETHTOOL_A_BITSET_MASK,
658*1b481fc3SMaciej Żenczykowski 			nwords * sizeof(uint32_t), mask)))
659*1b481fc3SMaciej Żenczykowski 		goto out_free;
660*1b481fc3SMaciej Żenczykowski 	ethnla_nest_end(msgbuff, nest);
661*1b481fc3SMaciej Żenczykowski 	ret = 0;
662*1b481fc3SMaciej Żenczykowski 
663*1b481fc3SMaciej Żenczykowski out_free:
664*1b481fc3SMaciej Żenczykowski 	free(value);
665*1b481fc3SMaciej Żenczykowski 	free(mask);
666*1b481fc3SMaciej Żenczykowski 	nlctx->argp++;
667*1b481fc3SMaciej Żenczykowski 	nlctx->argc--;
668*1b481fc3SMaciej Żenczykowski 	return ret;
669*1b481fc3SMaciej Żenczykowski }
670*1b481fc3SMaciej Żenczykowski 
671*1b481fc3SMaciej Żenczykowski /* Parse bitset provided as series of "name on|off" pairs (@no_mask is false)
672*1b481fc3SMaciej Żenczykowski  * or names (@no_mask is true). Generates bitset nested attribute in verbose
673*1b481fc3SMaciej Żenczykowski  * form with names from command line.
674*1b481fc3SMaciej Żenczykowski  */
parse_name_bitset(struct nl_context * nlctx,uint16_t type,bool no_mask,struct nl_msg_buff * msgbuff)675*1b481fc3SMaciej Żenczykowski static int parse_name_bitset(struct nl_context *nlctx, uint16_t type,
676*1b481fc3SMaciej Żenczykowski 			     bool no_mask, struct nl_msg_buff *msgbuff)
677*1b481fc3SMaciej Żenczykowski {
678*1b481fc3SMaciej Żenczykowski 	struct nlattr *bitset_attr;
679*1b481fc3SMaciej Żenczykowski 	struct nlattr *bits_attr;
680*1b481fc3SMaciej Żenczykowski 	struct nlattr *bit_attr;
681*1b481fc3SMaciej Żenczykowski 	int ret;
682*1b481fc3SMaciej Żenczykowski 
683*1b481fc3SMaciej Żenczykowski 	bitset_attr = ethnla_nest_start(msgbuff, type);
684*1b481fc3SMaciej Żenczykowski 	if (!bitset_attr)
685*1b481fc3SMaciej Żenczykowski 		return -EMSGSIZE;
686*1b481fc3SMaciej Żenczykowski 	ret = -EMSGSIZE;
687*1b481fc3SMaciej Żenczykowski 	if (no_mask && ethnla_put_flag(msgbuff, ETHTOOL_A_BITSET_NOMASK, true))
688*1b481fc3SMaciej Żenczykowski 		goto err;
689*1b481fc3SMaciej Żenczykowski 	bits_attr = ethnla_nest_start(msgbuff, ETHTOOL_A_BITSET_BITS);
690*1b481fc3SMaciej Żenczykowski 	if (!bits_attr)
691*1b481fc3SMaciej Żenczykowski 		goto err;
692*1b481fc3SMaciej Żenczykowski 
693*1b481fc3SMaciej Żenczykowski 	while (nlctx->argc > 0) {
694*1b481fc3SMaciej Żenczykowski 		bool bit_val = true;
695*1b481fc3SMaciej Żenczykowski 
696*1b481fc3SMaciej Żenczykowski 		if (!strcmp(*nlctx->argp, "--")) {
697*1b481fc3SMaciej Żenczykowski 			nlctx->argp++;
698*1b481fc3SMaciej Żenczykowski 			nlctx->argc--;
699*1b481fc3SMaciej Żenczykowski 			break;
700*1b481fc3SMaciej Żenczykowski 		}
701*1b481fc3SMaciej Żenczykowski 		ret = -EINVAL;
702*1b481fc3SMaciej Żenczykowski 		if (!no_mask) {
703*1b481fc3SMaciej Żenczykowski 			if (nlctx->argc < 2 ||
704*1b481fc3SMaciej Żenczykowski 			    (strcmp(nlctx->argp[1], "on") &&
705*1b481fc3SMaciej Żenczykowski 			     strcmp(nlctx->argp[1], "off"))) {
706*1b481fc3SMaciej Żenczykowski 				parser_err_invalid_flag(nlctx, *nlctx->argp);
707*1b481fc3SMaciej Żenczykowski 				goto err;
708*1b481fc3SMaciej Żenczykowski 			}
709*1b481fc3SMaciej Żenczykowski 			bit_val = !strcmp(nlctx->argp[1], "on");
710*1b481fc3SMaciej Żenczykowski 		}
711*1b481fc3SMaciej Żenczykowski 
712*1b481fc3SMaciej Żenczykowski 		ret = -EMSGSIZE;
713*1b481fc3SMaciej Żenczykowski 		bit_attr = ethnla_nest_start(msgbuff,
714*1b481fc3SMaciej Żenczykowski 					     ETHTOOL_A_BITSET_BITS_BIT);
715*1b481fc3SMaciej Żenczykowski 		if (!bit_attr)
716*1b481fc3SMaciej Żenczykowski 			goto err;
717*1b481fc3SMaciej Żenczykowski 		if (ethnla_put_strz(msgbuff, ETHTOOL_A_BITSET_BIT_NAME,
718*1b481fc3SMaciej Żenczykowski 				    nlctx->argp[0]))
719*1b481fc3SMaciej Żenczykowski 			goto err;
720*1b481fc3SMaciej Żenczykowski 		if (!no_mask &&
721*1b481fc3SMaciej Żenczykowski 		    ethnla_put_flag(msgbuff, ETHTOOL_A_BITSET_BIT_VALUE,
722*1b481fc3SMaciej Żenczykowski 				    bit_val))
723*1b481fc3SMaciej Żenczykowski 			goto err;
724*1b481fc3SMaciej Żenczykowski 		ethnla_nest_end(msgbuff, bit_attr);
725*1b481fc3SMaciej Żenczykowski 
726*1b481fc3SMaciej Żenczykowski 		nlctx->argp += (no_mask ? 1 : 2);
727*1b481fc3SMaciej Żenczykowski 		nlctx->argc -= (no_mask ? 1 : 2);
728*1b481fc3SMaciej Żenczykowski 	}
729*1b481fc3SMaciej Żenczykowski 
730*1b481fc3SMaciej Żenczykowski 	ethnla_nest_end(msgbuff, bits_attr);
731*1b481fc3SMaciej Żenczykowski 	ethnla_nest_end(msgbuff, bitset_attr);
732*1b481fc3SMaciej Żenczykowski 	return 0;
733*1b481fc3SMaciej Żenczykowski err:
734*1b481fc3SMaciej Żenczykowski 	ethnla_nest_cancel(msgbuff, bitset_attr);
735*1b481fc3SMaciej Żenczykowski 	return ret;
736*1b481fc3SMaciej Żenczykowski }
737*1b481fc3SMaciej Żenczykowski 
is_char_bitset(const char * arg,const struct char_bitset_parser_data * data)738*1b481fc3SMaciej Żenczykowski static bool is_char_bitset(const char *arg,
739*1b481fc3SMaciej Żenczykowski 			   const struct char_bitset_parser_data *data)
740*1b481fc3SMaciej Żenczykowski {
741*1b481fc3SMaciej Żenczykowski 	bool mask = (arg[0] == '+' || arg[0] == '-');
742*1b481fc3SMaciej Żenczykowski 	unsigned int i;
743*1b481fc3SMaciej Żenczykowski 	const char *p;
744*1b481fc3SMaciej Żenczykowski 
745*1b481fc3SMaciej Żenczykowski 	for (p = arg; *p; p++) {
746*1b481fc3SMaciej Żenczykowski 		if (*p == data->reset_char)
747*1b481fc3SMaciej Żenczykowski 			continue;
748*1b481fc3SMaciej Żenczykowski 		if (mask && (*p == '+' || *p == '-'))
749*1b481fc3SMaciej Żenczykowski 			continue;
750*1b481fc3SMaciej Żenczykowski 		for (i = 0; i < data->nbits; i++)
751*1b481fc3SMaciej Żenczykowski 			if (*p == data->bit_chars[i])
752*1b481fc3SMaciej Żenczykowski 				goto found;
753*1b481fc3SMaciej Żenczykowski 		return false;
754*1b481fc3SMaciej Żenczykowski found:
755*1b481fc3SMaciej Żenczykowski 		;
756*1b481fc3SMaciej Żenczykowski 	}
757*1b481fc3SMaciej Żenczykowski 
758*1b481fc3SMaciej Żenczykowski 	return true;
759*1b481fc3SMaciej Żenczykowski }
760*1b481fc3SMaciej Żenczykowski 
761*1b481fc3SMaciej Żenczykowski /* Parse bitset provided as a string consisting of characters corresponding to
762*1b481fc3SMaciej Żenczykowski  * bit indices. The "reset character" resets the no-mask bitset to empty. If
763*1b481fc3SMaciej Żenczykowski  * the first character is '+' or '-', generated bitset has mask and '+' and
764*1b481fc3SMaciej Żenczykowski  * '-' switch between enabling and disabling the following bits (i.e. their
765*1b481fc3SMaciej Żenczykowski  * value being true/false). In such case, "reset character" is not allowed.
766*1b481fc3SMaciej Żenczykowski  */
parse_char_bitset(struct nl_context * nlctx,uint16_t type,const struct char_bitset_parser_data * data,struct nl_msg_buff * msgbuff)767*1b481fc3SMaciej Żenczykowski static int parse_char_bitset(struct nl_context *nlctx, uint16_t type,
768*1b481fc3SMaciej Żenczykowski 			     const struct char_bitset_parser_data *data,
769*1b481fc3SMaciej Żenczykowski 			     struct nl_msg_buff *msgbuff)
770*1b481fc3SMaciej Żenczykowski {
771*1b481fc3SMaciej Żenczykowski 	const char *arg = *nlctx->argp;
772*1b481fc3SMaciej Żenczykowski 	struct nlattr *bitset_attr;
773*1b481fc3SMaciej Żenczykowski 	struct nlattr *saved_pos;
774*1b481fc3SMaciej Żenczykowski 	struct nlattr *bits_attr;
775*1b481fc3SMaciej Żenczykowski 	struct nlattr *bit_attr;
776*1b481fc3SMaciej Żenczykowski 	unsigned int idx;
777*1b481fc3SMaciej Żenczykowski 	bool val = true;
778*1b481fc3SMaciej Żenczykowski 	const char *p;
779*1b481fc3SMaciej Żenczykowski 	bool no_mask;
780*1b481fc3SMaciej Żenczykowski 	int ret;
781*1b481fc3SMaciej Żenczykowski 
782*1b481fc3SMaciej Żenczykowski 	no_mask = data->no_mask || !(arg[0] == '+' || arg[0] == '-');
783*1b481fc3SMaciej Żenczykowski 	bitset_attr = ethnla_nest_start(msgbuff, type);
784*1b481fc3SMaciej Żenczykowski 	if (!bitset_attr)
785*1b481fc3SMaciej Żenczykowski 		return -EMSGSIZE;
786*1b481fc3SMaciej Żenczykowski 	ret = -EMSGSIZE;
787*1b481fc3SMaciej Żenczykowski 	if (no_mask && ethnla_put_flag(msgbuff, ETHTOOL_A_BITSET_NOMASK, true))
788*1b481fc3SMaciej Żenczykowski 		goto err;
789*1b481fc3SMaciej Żenczykowski 	bits_attr = ethnla_nest_start(msgbuff, ETHTOOL_A_BITSET_BITS);
790*1b481fc3SMaciej Żenczykowski 	if (!bits_attr)
791*1b481fc3SMaciej Żenczykowski 		goto err;
792*1b481fc3SMaciej Żenczykowski 	saved_pos = mnl_nlmsg_get_payload_tail(msgbuff->nlhdr);
793*1b481fc3SMaciej Żenczykowski 
794*1b481fc3SMaciej Żenczykowski 	for (p = arg; *p; p++) {
795*1b481fc3SMaciej Żenczykowski 		if (*p == '+' || *p == '-') {
796*1b481fc3SMaciej Żenczykowski 			if (no_mask) {
797*1b481fc3SMaciej Żenczykowski 				parser_err_invalid_value(nlctx, arg);
798*1b481fc3SMaciej Żenczykowski 				ret = -EINVAL;
799*1b481fc3SMaciej Żenczykowski 				goto err;
800*1b481fc3SMaciej Żenczykowski 			}
801*1b481fc3SMaciej Żenczykowski 			val = (*p == '+');
802*1b481fc3SMaciej Żenczykowski 			continue;
803*1b481fc3SMaciej Żenczykowski 		}
804*1b481fc3SMaciej Żenczykowski 		if (*p == data->reset_char) {
805*1b481fc3SMaciej Żenczykowski 			if (no_mask) {
806*1b481fc3SMaciej Żenczykowski 				mnl_attr_nest_cancel(msgbuff->nlhdr, saved_pos);
807*1b481fc3SMaciej Żenczykowski 				continue;
808*1b481fc3SMaciej Żenczykowski 			}
809*1b481fc3SMaciej Żenczykowski 			fprintf(stderr, "ethtool (%s): invalid char '%c' in '%s' for parameter '%s'\n",
810*1b481fc3SMaciej Żenczykowski 				nlctx->cmd, *p, arg, nlctx->param);
811*1b481fc3SMaciej Żenczykowski 			ret = -EINVAL;
812*1b481fc3SMaciej Żenczykowski 			goto err;
813*1b481fc3SMaciej Żenczykowski 		}
814*1b481fc3SMaciej Żenczykowski 
815*1b481fc3SMaciej Żenczykowski 		for (idx = 0; idx < data->nbits; idx++) {
816*1b481fc3SMaciej Żenczykowski 			if (data->bit_chars[idx] == *p)
817*1b481fc3SMaciej Żenczykowski 				break;
818*1b481fc3SMaciej Żenczykowski 		}
819*1b481fc3SMaciej Żenczykowski 		if (idx >= data->nbits) {
820*1b481fc3SMaciej Żenczykowski 			fprintf(stderr, "ethtool (%s): invalid char '%c' in '%s' for parameter '%s'\n",
821*1b481fc3SMaciej Żenczykowski 				nlctx->cmd, *p, arg, nlctx->param);
822*1b481fc3SMaciej Żenczykowski 			ret = -EINVAL;
823*1b481fc3SMaciej Żenczykowski 			goto err;
824*1b481fc3SMaciej Żenczykowski 		}
825*1b481fc3SMaciej Żenczykowski 		bit_attr = ethnla_nest_start(msgbuff,
826*1b481fc3SMaciej Żenczykowski 					     ETHTOOL_A_BITSET_BITS_BIT);
827*1b481fc3SMaciej Żenczykowski 		if (!bit_attr)
828*1b481fc3SMaciej Żenczykowski 			goto err;
829*1b481fc3SMaciej Żenczykowski 		if (ethnla_put_u32(msgbuff, ETHTOOL_A_BITSET_BIT_INDEX, idx))
830*1b481fc3SMaciej Żenczykowski 			goto err;
831*1b481fc3SMaciej Żenczykowski 		if (!no_mask &&
832*1b481fc3SMaciej Żenczykowski 		    ethnla_put_flag(msgbuff, ETHTOOL_A_BITSET_BIT_VALUE, val))
833*1b481fc3SMaciej Żenczykowski 			goto err;
834*1b481fc3SMaciej Żenczykowski 		ethnla_nest_end(msgbuff, bit_attr);
835*1b481fc3SMaciej Żenczykowski 	}
836*1b481fc3SMaciej Żenczykowski 
837*1b481fc3SMaciej Żenczykowski 	ethnla_nest_end(msgbuff, bits_attr);
838*1b481fc3SMaciej Żenczykowski 	ethnla_nest_end(msgbuff, bitset_attr);
839*1b481fc3SMaciej Żenczykowski 	nlctx->argp++;
840*1b481fc3SMaciej Żenczykowski 	nlctx->argc--;
841*1b481fc3SMaciej Żenczykowski 	return 0;
842*1b481fc3SMaciej Żenczykowski err:
843*1b481fc3SMaciej Żenczykowski 	ethnla_nest_cancel(msgbuff, bitset_attr);
844*1b481fc3SMaciej Żenczykowski 	return ret;
845*1b481fc3SMaciej Żenczykowski }
846*1b481fc3SMaciej Żenczykowski 
847*1b481fc3SMaciej Żenczykowski /* Parser handler for bitset. Expects either a numeric value (base 16 or 10
848*1b481fc3SMaciej Żenczykowski  * (unless force_hex is set)), optionally followed by '/' and another numeric
849*1b481fc3SMaciej Żenczykowski  * value (mask, unless no_mask is set), or a series of "name on|off" pairs
850*1b481fc3SMaciej Żenczykowski  * (no_mask not set) or names (no_mask set). In the latter case, names are
851*1b481fc3SMaciej Żenczykowski  * passed on as they are and kernel performs their interpretation and
852*1b481fc3SMaciej Żenczykowski  * validation. The @data parameter points to struct bitset_parser_data.
853*1b481fc3SMaciej Żenczykowski  * Generates only a bitset nested attribute. Fails if @type is zero or @dest
854*1b481fc3SMaciej Żenczykowski  * is not null.
855*1b481fc3SMaciej Żenczykowski  */
nl_parse_bitset(struct nl_context * nlctx,uint16_t type,const void * data,struct nl_msg_buff * msgbuff,void * dest)856*1b481fc3SMaciej Żenczykowski int nl_parse_bitset(struct nl_context *nlctx, uint16_t type, const void *data,
857*1b481fc3SMaciej Żenczykowski 		    struct nl_msg_buff *msgbuff, void *dest)
858*1b481fc3SMaciej Żenczykowski {
859*1b481fc3SMaciej Żenczykowski 	const struct bitset_parser_data *parser_data = data;
860*1b481fc3SMaciej Żenczykowski 
861*1b481fc3SMaciej Żenczykowski 	if (!type || dest) {
862*1b481fc3SMaciej Żenczykowski 		fprintf(stderr, "ethtool (%s): internal error parsing '%s'\n",
863*1b481fc3SMaciej Żenczykowski 			nlctx->cmd, nlctx->param);
864*1b481fc3SMaciej Żenczykowski 		return -EFAULT;
865*1b481fc3SMaciej Żenczykowski 	}
866*1b481fc3SMaciej Żenczykowski 	if (is_numeric_bitset(*nlctx->argp, false))
867*1b481fc3SMaciej Żenczykowski 		return parse_numeric_bitset(nlctx, type, parser_data->no_mask,
868*1b481fc3SMaciej Żenczykowski 					    parser_data->force_hex, msgbuff);
869*1b481fc3SMaciej Żenczykowski 	else
870*1b481fc3SMaciej Żenczykowski 		return parse_name_bitset(nlctx, type, parser_data->no_mask,
871*1b481fc3SMaciej Żenczykowski 					 msgbuff);
872*1b481fc3SMaciej Żenczykowski }
873*1b481fc3SMaciej Żenczykowski 
874*1b481fc3SMaciej Żenczykowski /* Parser handler for bitset. Expects either a numeric value (base 10 or 16),
875*1b481fc3SMaciej Żenczykowski  * optionally followed by '/' and another numeric value (mask, unless no_mask
876*1b481fc3SMaciej Żenczykowski  * is set), or a string consisting of characters corresponding to bit indices.
877*1b481fc3SMaciej Żenczykowski  * The @data parameter points to struct char_bitset_parser_data. Generates
878*1b481fc3SMaciej Żenczykowski  * biset nested attribute. Fails if type is zero or if @dest is not null.
879*1b481fc3SMaciej Żenczykowski  */
nl_parse_char_bitset(struct nl_context * nlctx,uint16_t type,const void * data,struct nl_msg_buff * msgbuff,void * dest)880*1b481fc3SMaciej Żenczykowski int nl_parse_char_bitset(struct nl_context *nlctx, uint16_t type,
881*1b481fc3SMaciej Żenczykowski 			 const void *data, struct nl_msg_buff *msgbuff,
882*1b481fc3SMaciej Żenczykowski 			 void *dest)
883*1b481fc3SMaciej Żenczykowski {
884*1b481fc3SMaciej Żenczykowski 	const struct char_bitset_parser_data *parser_data = data;
885*1b481fc3SMaciej Żenczykowski 
886*1b481fc3SMaciej Żenczykowski 	if (!type || dest) {
887*1b481fc3SMaciej Żenczykowski 		fprintf(stderr, "ethtool (%s): internal error parsing '%s'\n",
888*1b481fc3SMaciej Żenczykowski 			nlctx->cmd, nlctx->param);
889*1b481fc3SMaciej Żenczykowski 		return -EFAULT;
890*1b481fc3SMaciej Żenczykowski 	}
891*1b481fc3SMaciej Żenczykowski 	if (is_char_bitset(*nlctx->argp, data) ||
892*1b481fc3SMaciej Żenczykowski 	    !is_numeric_bitset(*nlctx->argp, false))
893*1b481fc3SMaciej Żenczykowski 		return parse_char_bitset(nlctx, type, parser_data, msgbuff);
894*1b481fc3SMaciej Żenczykowski 	else
895*1b481fc3SMaciej Żenczykowski 		return parse_numeric_bitset(nlctx, type, parser_data->no_mask,
896*1b481fc3SMaciej Żenczykowski 					    false, msgbuff);
897*1b481fc3SMaciej Żenczykowski }
898*1b481fc3SMaciej Żenczykowski 
899*1b481fc3SMaciej Żenczykowski /* parser implementation */
900*1b481fc3SMaciej Żenczykowski 
find_parser(const struct param_parser * params,const char * arg)901*1b481fc3SMaciej Żenczykowski static const struct param_parser *find_parser(const struct param_parser *params,
902*1b481fc3SMaciej Żenczykowski 					      const char *arg)
903*1b481fc3SMaciej Żenczykowski {
904*1b481fc3SMaciej Żenczykowski 	const struct param_parser *parser;
905*1b481fc3SMaciej Żenczykowski 
906*1b481fc3SMaciej Żenczykowski 	for (parser = params; parser->arg; parser++)
907*1b481fc3SMaciej Żenczykowski 		if (!strcmp(arg, parser->arg))
908*1b481fc3SMaciej Żenczykowski 			return parser;
909*1b481fc3SMaciej Żenczykowski 	return NULL;
910*1b481fc3SMaciej Żenczykowski }
911*1b481fc3SMaciej Żenczykowski 
__parser_bit(const uint64_t * map,unsigned int idx)912*1b481fc3SMaciej Żenczykowski static bool __parser_bit(const uint64_t *map, unsigned int idx)
913*1b481fc3SMaciej Żenczykowski {
914*1b481fc3SMaciej Żenczykowski 	return map[idx / 64] & (1 << (idx % 64));
915*1b481fc3SMaciej Żenczykowski }
916*1b481fc3SMaciej Żenczykowski 
__parser_set(uint64_t * map,unsigned int idx)917*1b481fc3SMaciej Żenczykowski static void __parser_set(uint64_t *map, unsigned int idx)
918*1b481fc3SMaciej Żenczykowski {
919*1b481fc3SMaciej Żenczykowski 	map[idx / 64] |= (1 << (idx % 64));
920*1b481fc3SMaciej Żenczykowski }
921*1b481fc3SMaciej Żenczykowski 
__parser_set_group(const struct param_parser * params,uint64_t * map,unsigned int alt_group)922*1b481fc3SMaciej Żenczykowski static void __parser_set_group(const struct param_parser *params,
923*1b481fc3SMaciej Żenczykowski 			       uint64_t *map, unsigned int alt_group)
924*1b481fc3SMaciej Żenczykowski {
925*1b481fc3SMaciej Żenczykowski 	const struct param_parser *parser;
926*1b481fc3SMaciej Żenczykowski 	unsigned int idx = 0;
927*1b481fc3SMaciej Żenczykowski 
928*1b481fc3SMaciej Żenczykowski 	for (parser = params; parser->arg; parser++, idx++)
929*1b481fc3SMaciej Żenczykowski 		if (parser->alt_group == alt_group)
930*1b481fc3SMaciej Żenczykowski 			__parser_set(map, idx);
931*1b481fc3SMaciej Żenczykowski }
932*1b481fc3SMaciej Żenczykowski 
933*1b481fc3SMaciej Żenczykowski struct tmp_buff {
934*1b481fc3SMaciej Żenczykowski 	struct nl_msg_buff	*msgbuff;
935*1b481fc3SMaciej Żenczykowski 	unsigned int		id;
936*1b481fc3SMaciej Żenczykowski 	unsigned int		orig_len;
937*1b481fc3SMaciej Żenczykowski 	struct tmp_buff		*next;
938*1b481fc3SMaciej Żenczykowski };
939*1b481fc3SMaciej Żenczykowski 
tmp_buff_find(struct tmp_buff * head,unsigned int id)940*1b481fc3SMaciej Żenczykowski static struct tmp_buff *tmp_buff_find(struct tmp_buff *head, unsigned int id)
941*1b481fc3SMaciej Żenczykowski {
942*1b481fc3SMaciej Żenczykowski 	struct tmp_buff *buff;
943*1b481fc3SMaciej Żenczykowski 
944*1b481fc3SMaciej Żenczykowski 	for (buff = head; buff; buff = buff->next)
945*1b481fc3SMaciej Żenczykowski 		if (buff->id == id)
946*1b481fc3SMaciej Żenczykowski 			break;
947*1b481fc3SMaciej Żenczykowski 
948*1b481fc3SMaciej Żenczykowski 	return buff;
949*1b481fc3SMaciej Żenczykowski }
950*1b481fc3SMaciej Żenczykowski 
tmp_buff_find_or_create(struct tmp_buff ** phead,unsigned int id)951*1b481fc3SMaciej Żenczykowski static struct tmp_buff *tmp_buff_find_or_create(struct tmp_buff **phead,
952*1b481fc3SMaciej Żenczykowski 						unsigned int id)
953*1b481fc3SMaciej Żenczykowski {
954*1b481fc3SMaciej Żenczykowski 	struct tmp_buff **pbuff;
955*1b481fc3SMaciej Żenczykowski 	struct tmp_buff *new_buff;
956*1b481fc3SMaciej Żenczykowski 
957*1b481fc3SMaciej Żenczykowski 	for (pbuff = phead; *pbuff; pbuff = &(*pbuff)->next)
958*1b481fc3SMaciej Żenczykowski 		if ((*pbuff)->id == id)
959*1b481fc3SMaciej Żenczykowski 			return *pbuff;
960*1b481fc3SMaciej Żenczykowski 
961*1b481fc3SMaciej Żenczykowski 	new_buff = malloc(sizeof(*new_buff));
962*1b481fc3SMaciej Żenczykowski 	if (!new_buff)
963*1b481fc3SMaciej Żenczykowski 		return NULL;
964*1b481fc3SMaciej Żenczykowski 	new_buff->id = id;
965*1b481fc3SMaciej Żenczykowski 	new_buff->msgbuff = malloc(sizeof(*new_buff->msgbuff));
966*1b481fc3SMaciej Żenczykowski 	if (!new_buff->msgbuff) {
967*1b481fc3SMaciej Żenczykowski 		free(new_buff);
968*1b481fc3SMaciej Żenczykowski 		return NULL;
969*1b481fc3SMaciej Żenczykowski 	}
970*1b481fc3SMaciej Żenczykowski 	msgbuff_init(new_buff->msgbuff);
971*1b481fc3SMaciej Żenczykowski 	new_buff->next = NULL;
972*1b481fc3SMaciej Żenczykowski 	*pbuff = new_buff;
973*1b481fc3SMaciej Żenczykowski 
974*1b481fc3SMaciej Żenczykowski 	return new_buff;
975*1b481fc3SMaciej Żenczykowski }
976*1b481fc3SMaciej Żenczykowski 
tmp_buff_destroy(struct tmp_buff * head)977*1b481fc3SMaciej Żenczykowski static void tmp_buff_destroy(struct tmp_buff *head)
978*1b481fc3SMaciej Żenczykowski {
979*1b481fc3SMaciej Żenczykowski 	struct tmp_buff *buff = head;
980*1b481fc3SMaciej Żenczykowski 	struct tmp_buff *next;
981*1b481fc3SMaciej Żenczykowski 
982*1b481fc3SMaciej Żenczykowski 	while (buff) {
983*1b481fc3SMaciej Żenczykowski 		next = buff->next;
984*1b481fc3SMaciej Żenczykowski 		if (buff->msgbuff) {
985*1b481fc3SMaciej Żenczykowski 			msgbuff_done(buff->msgbuff);
986*1b481fc3SMaciej Żenczykowski 			free(buff->msgbuff);
987*1b481fc3SMaciej Żenczykowski 		}
988*1b481fc3SMaciej Żenczykowski 		free(buff);
989*1b481fc3SMaciej Żenczykowski 		buff = next;
990*1b481fc3SMaciej Żenczykowski 	}
991*1b481fc3SMaciej Żenczykowski }
992*1b481fc3SMaciej Żenczykowski 
993*1b481fc3SMaciej Żenczykowski /* Main entry point of parser implementation.
994*1b481fc3SMaciej Żenczykowski  * @nlctx: netlink context
995*1b481fc3SMaciej Żenczykowski  * @params:      array of struct param_parser describing expected arguments
996*1b481fc3SMaciej Żenczykowski  *               and their handlers; the array must be terminated by null
997*1b481fc3SMaciej Żenczykowski  *               element {}
998*1b481fc3SMaciej Żenczykowski  * @dest:        optional destination to copy parsed data to (at
999*1b481fc3SMaciej Żenczykowski  *               param_parser::offset)
1000*1b481fc3SMaciej Żenczykowski  * @group_style: defines if identifiers in .group represent separate messages,
1001*1b481fc3SMaciej Żenczykowski  *               nested attributes or are not allowed
1002*1b481fc3SMaciej Żenczykowski  * @msgbuffs:    (only used for @group_style = PARSER_GROUP_MSG) array to store
1003*1b481fc3SMaciej Żenczykowski  *               pointers to composed messages; caller must make sure this
1004*1b481fc3SMaciej Żenczykowski  *               array is sufficient, i.e. that it has at least as many entries
1005*1b481fc3SMaciej Żenczykowski  *               as the number of different .group values in params array;
1006*1b481fc3SMaciej Żenczykowski  *               entries are filled from the start, remaining entries are not
1007*1b481fc3SMaciej Żenczykowski  *               modified; caller should zero initialize the array before
1008*1b481fc3SMaciej Żenczykowski  *               calling nl_parser()
1009*1b481fc3SMaciej Żenczykowski  */
nl_parser(struct nl_context * nlctx,const struct param_parser * params,void * dest,enum parser_group_style group_style,struct nl_msg_buff ** msgbuffs)1010*1b481fc3SMaciej Żenczykowski int nl_parser(struct nl_context *nlctx, const struct param_parser *params,
1011*1b481fc3SMaciej Żenczykowski 	      void *dest, enum parser_group_style group_style,
1012*1b481fc3SMaciej Żenczykowski 	      struct nl_msg_buff **msgbuffs)
1013*1b481fc3SMaciej Żenczykowski {
1014*1b481fc3SMaciej Żenczykowski 	struct nl_socket *nlsk = nlctx->ethnl_socket;
1015*1b481fc3SMaciej Żenczykowski 	const struct param_parser *parser;
1016*1b481fc3SMaciej Żenczykowski 	struct tmp_buff *buffs = NULL;
1017*1b481fc3SMaciej Żenczykowski 	unsigned int n_msgbuffs = 0;
1018*1b481fc3SMaciej Żenczykowski 	struct tmp_buff *buff;
1019*1b481fc3SMaciej Żenczykowski 	unsigned int n_params;
1020*1b481fc3SMaciej Żenczykowski 	uint64_t *params_seen;
1021*1b481fc3SMaciej Żenczykowski 	int ret;
1022*1b481fc3SMaciej Żenczykowski 
1023*1b481fc3SMaciej Żenczykowski 	n_params = 0;
1024*1b481fc3SMaciej Żenczykowski 	for (parser = params; parser->arg; parser++) {
1025*1b481fc3SMaciej Żenczykowski 		struct nl_msg_buff *msgbuff;
1026*1b481fc3SMaciej Żenczykowski 		struct nlattr *nest;
1027*1b481fc3SMaciej Żenczykowski 
1028*1b481fc3SMaciej Żenczykowski 		n_params++;
1029*1b481fc3SMaciej Żenczykowski 		if (group_style == PARSER_GROUP_NONE || !parser->group)
1030*1b481fc3SMaciej Żenczykowski 			continue;
1031*1b481fc3SMaciej Żenczykowski 		ret = -ENOMEM;
1032*1b481fc3SMaciej Żenczykowski 		buff = tmp_buff_find_or_create(&buffs, parser->group);
1033*1b481fc3SMaciej Żenczykowski 		if (!buff)
1034*1b481fc3SMaciej Żenczykowski 			goto out_free_buffs;
1035*1b481fc3SMaciej Żenczykowski 		msgbuff = buff->msgbuff;
1036*1b481fc3SMaciej Żenczykowski 		ret = msg_init(nlctx, msgbuff, parser->group,
1037*1b481fc3SMaciej Żenczykowski 			       NLM_F_REQUEST | NLM_F_ACK);
1038*1b481fc3SMaciej Żenczykowski 		if (ret < 0)
1039*1b481fc3SMaciej Żenczykowski 			goto out_free_buffs;
1040*1b481fc3SMaciej Żenczykowski 
1041*1b481fc3SMaciej Żenczykowski 		switch (group_style) {
1042*1b481fc3SMaciej Żenczykowski 		case PARSER_GROUP_NEST:
1043*1b481fc3SMaciej Żenczykowski 			ret = -EMSGSIZE;
1044*1b481fc3SMaciej Żenczykowski 			nest = ethnla_nest_start(buff->msgbuff, parser->group);
1045*1b481fc3SMaciej Żenczykowski 			if (!nest)
1046*1b481fc3SMaciej Żenczykowski 				goto out_free_buffs;
1047*1b481fc3SMaciej Żenczykowski 			break;
1048*1b481fc3SMaciej Żenczykowski 		case PARSER_GROUP_MSG:
1049*1b481fc3SMaciej Żenczykowski 			if (ethnla_fill_header(msgbuff,
1050*1b481fc3SMaciej Żenczykowski 					       ETHTOOL_A_LINKINFO_HEADER,
1051*1b481fc3SMaciej Żenczykowski 					       nlctx->devname, 0))
1052*1b481fc3SMaciej Żenczykowski 				goto out_free_buffs;
1053*1b481fc3SMaciej Żenczykowski 			break;
1054*1b481fc3SMaciej Żenczykowski 		default:
1055*1b481fc3SMaciej Żenczykowski 			break;
1056*1b481fc3SMaciej Żenczykowski 		}
1057*1b481fc3SMaciej Żenczykowski 
1058*1b481fc3SMaciej Żenczykowski 		buff->orig_len = msgbuff_len(msgbuff);
1059*1b481fc3SMaciej Żenczykowski 	}
1060*1b481fc3SMaciej Żenczykowski 	ret = -ENOMEM;
1061*1b481fc3SMaciej Żenczykowski 	params_seen = calloc(DIV_ROUND_UP(n_params, 64), sizeof(uint64_t));
1062*1b481fc3SMaciej Żenczykowski 	if (!params_seen)
1063*1b481fc3SMaciej Żenczykowski 		goto out_free_buffs;
1064*1b481fc3SMaciej Żenczykowski 
1065*1b481fc3SMaciej Żenczykowski 	while (nlctx->argc > 0) {
1066*1b481fc3SMaciej Żenczykowski 		struct nl_msg_buff *msgbuff;
1067*1b481fc3SMaciej Żenczykowski 		void *param_dest;
1068*1b481fc3SMaciej Żenczykowski 
1069*1b481fc3SMaciej Żenczykowski 		nlctx->param = *nlctx->argp;
1070*1b481fc3SMaciej Żenczykowski 		ret = -EINVAL;
1071*1b481fc3SMaciej Żenczykowski 		parser = find_parser(params, nlctx->param);
1072*1b481fc3SMaciej Żenczykowski 		if (!parser) {
1073*1b481fc3SMaciej Żenczykowski 			parser_err_unknown_param(nlctx);
1074*1b481fc3SMaciej Żenczykowski 			goto out_free;
1075*1b481fc3SMaciej Żenczykowski 		}
1076*1b481fc3SMaciej Żenczykowski 
1077*1b481fc3SMaciej Żenczykowski 		/* check duplicates and minimum number of arguments */
1078*1b481fc3SMaciej Żenczykowski 		if (__parser_bit(params_seen, parser - params)) {
1079*1b481fc3SMaciej Żenczykowski 			parser_err_dup_param(nlctx);
1080*1b481fc3SMaciej Żenczykowski 			goto out_free;
1081*1b481fc3SMaciej Żenczykowski 		}
1082*1b481fc3SMaciej Żenczykowski 		nlctx->argc--;
1083*1b481fc3SMaciej Żenczykowski 		nlctx->argp++;
1084*1b481fc3SMaciej Żenczykowski 		if (nlctx->argc < parser->min_argc) {
1085*1b481fc3SMaciej Żenczykowski 			parser_err_min_argc(nlctx, parser->min_argc);
1086*1b481fc3SMaciej Żenczykowski 			goto out_free;
1087*1b481fc3SMaciej Żenczykowski 		}
1088*1b481fc3SMaciej Żenczykowski 		if (parser->alt_group)
1089*1b481fc3SMaciej Żenczykowski 			__parser_set_group(params, params_seen,
1090*1b481fc3SMaciej Żenczykowski 					   parser->alt_group);
1091*1b481fc3SMaciej Żenczykowski 		else
1092*1b481fc3SMaciej Żenczykowski 			__parser_set(params_seen, parser - params);
1093*1b481fc3SMaciej Żenczykowski 
1094*1b481fc3SMaciej Żenczykowski 		buff = NULL;
1095*1b481fc3SMaciej Żenczykowski 		if (parser->group)
1096*1b481fc3SMaciej Żenczykowski 			buff = tmp_buff_find(buffs, parser->group);
1097*1b481fc3SMaciej Żenczykowski 		msgbuff = buff ? buff->msgbuff : &nlsk->msgbuff;
1098*1b481fc3SMaciej Żenczykowski 
1099*1b481fc3SMaciej Żenczykowski 		param_dest = dest ? ((char *)dest + parser->dest_offset) : NULL;
1100*1b481fc3SMaciej Żenczykowski 		ret = parser->handler(nlctx, parser->type, parser->handler_data,
1101*1b481fc3SMaciej Żenczykowski 				      msgbuff, param_dest);
1102*1b481fc3SMaciej Żenczykowski 		if (ret < 0)
1103*1b481fc3SMaciej Żenczykowski 			goto out_free;
1104*1b481fc3SMaciej Żenczykowski 	}
1105*1b481fc3SMaciej Żenczykowski 
1106*1b481fc3SMaciej Żenczykowski 	if (group_style == PARSER_GROUP_MSG) {
1107*1b481fc3SMaciej Żenczykowski 		ret = -EOPNOTSUPP;
1108*1b481fc3SMaciej Żenczykowski 		for (buff = buffs; buff; buff = buff->next)
1109*1b481fc3SMaciej Żenczykowski 			if (msgbuff_len(buff->msgbuff) > buff->orig_len &&
1110*1b481fc3SMaciej Żenczykowski 			    netlink_cmd_check(nlctx->ctx, buff->id, false))
1111*1b481fc3SMaciej Żenczykowski 				goto out_free;
1112*1b481fc3SMaciej Żenczykowski 	}
1113*1b481fc3SMaciej Żenczykowski 	for (buff = buffs; buff; buff = buff->next) {
1114*1b481fc3SMaciej Żenczykowski 		struct nl_msg_buff *msgbuff = buff->msgbuff;
1115*1b481fc3SMaciej Żenczykowski 
1116*1b481fc3SMaciej Żenczykowski 		if (group_style == PARSER_GROUP_NONE ||
1117*1b481fc3SMaciej Żenczykowski 		    msgbuff_len(msgbuff) == buff->orig_len)
1118*1b481fc3SMaciej Żenczykowski 			continue;
1119*1b481fc3SMaciej Żenczykowski 		switch (group_style) {
1120*1b481fc3SMaciej Żenczykowski 		case PARSER_GROUP_NEST:
1121*1b481fc3SMaciej Żenczykowski 			ethnla_nest_end(msgbuff, msgbuff->payload);
1122*1b481fc3SMaciej Żenczykowski 			ret = msgbuff_append(&nlsk->msgbuff, msgbuff);
1123*1b481fc3SMaciej Żenczykowski 			if (ret < 0)
1124*1b481fc3SMaciej Żenczykowski 				goto out_free;
1125*1b481fc3SMaciej Żenczykowski 			break;
1126*1b481fc3SMaciej Żenczykowski 		case PARSER_GROUP_MSG:
1127*1b481fc3SMaciej Żenczykowski 			msgbuffs[n_msgbuffs++] = msgbuff;
1128*1b481fc3SMaciej Żenczykowski 			buff->msgbuff = NULL;
1129*1b481fc3SMaciej Żenczykowski 			break;
1130*1b481fc3SMaciej Żenczykowski 		default:
1131*1b481fc3SMaciej Żenczykowski 			break;
1132*1b481fc3SMaciej Żenczykowski 		}
1133*1b481fc3SMaciej Żenczykowski 	}
1134*1b481fc3SMaciej Żenczykowski 
1135*1b481fc3SMaciej Żenczykowski 	ret = 0;
1136*1b481fc3SMaciej Żenczykowski out_free:
1137*1b481fc3SMaciej Żenczykowski 	free(params_seen);
1138*1b481fc3SMaciej Żenczykowski out_free_buffs:
1139*1b481fc3SMaciej Żenczykowski 	tmp_buff_destroy(buffs);
1140*1b481fc3SMaciej Żenczykowski 	return ret;
1141*1b481fc3SMaciej Żenczykowski }
1142