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