1 /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
2 #ifndef __YNL_C_PRIV_H
3 #define __YNL_C_PRIV_H 1
4
5 #include <stdbool.h>
6 #include <stddef.h>
7 #include <linux/types.h>
8
9 struct ynl_parse_arg;
10
11 /*
12 * YNL internals / low level stuff
13 */
14
15 enum ynl_policy_type {
16 YNL_PT_REJECT = 1,
17 YNL_PT_IGNORE,
18 YNL_PT_NEST,
19 YNL_PT_FLAG,
20 YNL_PT_BINARY,
21 YNL_PT_U8,
22 YNL_PT_U16,
23 YNL_PT_U32,
24 YNL_PT_U64,
25 YNL_PT_UINT,
26 YNL_PT_NUL_STR,
27 YNL_PT_BITFIELD32,
28 YNL_PT_SUBMSG,
29 };
30
31 enum ynl_parse_result {
32 YNL_PARSE_CB_ERROR = -1,
33 YNL_PARSE_CB_STOP = 0,
34 YNL_PARSE_CB_OK = 1,
35 };
36
37 #define YNL_SOCKET_BUFFER_SIZE (1 << 17)
38
39 #define YNL_ARRAY_SIZE(array) (sizeof(array) ? \
40 sizeof(array) / sizeof(array[0]) : 0)
41
42 typedef int (*ynl_parse_cb_t)(const struct nlmsghdr *nlh,
43 struct ynl_parse_arg *yarg);
44
45 struct ynl_policy_attr {
46 enum ynl_policy_type type:8;
47 __u8 is_submsg:1;
48 __u8 is_selector:1;
49 __u16 selector_type;
50 unsigned int len;
51 const char *name;
52 const struct ynl_policy_nest *nest;
53 };
54
55 struct ynl_policy_nest {
56 unsigned int max_attr;
57 const struct ynl_policy_attr *table;
58 };
59
60 struct ynl_parse_arg {
61 struct ynl_sock *ys;
62 const struct ynl_policy_nest *rsp_policy;
63 void *data;
64 };
65
66 struct ynl_dump_list_type {
67 struct ynl_dump_list_type *next;
68 unsigned char data[] __attribute__((aligned(8)));
69 };
70 extern struct ynl_dump_list_type *YNL_LIST_END;
71
ynl_dump_obj_is_last(void * obj)72 static inline bool ynl_dump_obj_is_last(void *obj)
73 {
74 unsigned long uptr = (unsigned long)obj;
75
76 uptr -= offsetof(struct ynl_dump_list_type, data);
77 return uptr == (unsigned long)YNL_LIST_END;
78 }
79
ynl_dump_obj_next(void * obj)80 static inline void *ynl_dump_obj_next(void *obj)
81 {
82 unsigned long uptr = (unsigned long)obj;
83 struct ynl_dump_list_type *list;
84
85 uptr -= offsetof(struct ynl_dump_list_type, data);
86 list = (struct ynl_dump_list_type *)uptr;
87 uptr = (unsigned long)list->next;
88 uptr += offsetof(struct ynl_dump_list_type, data);
89
90 return (void *)uptr;
91 }
92
93 struct ynl_ntf_base_type {
94 __u16 family;
95 __u8 cmd;
96 struct ynl_ntf_base_type *next;
97 void (*free)(struct ynl_ntf_base_type *ntf);
98 unsigned char data[] __attribute__((aligned(8)));
99 };
100
101 struct nlmsghdr *ynl_msg_start_req(struct ynl_sock *ys, __u32 id, __u16 flags);
102 struct nlmsghdr *ynl_msg_start_dump(struct ynl_sock *ys, __u32 id);
103
104 struct nlmsghdr *
105 ynl_gemsg_start_req(struct ynl_sock *ys, __u32 id, __u8 cmd, __u8 version);
106 struct nlmsghdr *
107 ynl_gemsg_start_dump(struct ynl_sock *ys, __u32 id, __u8 cmd, __u8 version);
108
109 int ynl_attr_validate(struct ynl_parse_arg *yarg, const struct nlattr *attr);
110 int ynl_submsg_failed(struct ynl_parse_arg *yarg, const char *field_name,
111 const char *sel_name);
112
113 /* YNL specific helpers used by the auto-generated code */
114
115 struct ynl_req_state {
116 struct ynl_parse_arg yarg;
117 ynl_parse_cb_t cb;
118 __u32 rsp_cmd;
119 };
120
121 struct ynl_dump_state {
122 struct ynl_parse_arg yarg;
123 void *first;
124 struct ynl_dump_list_type *last;
125 size_t alloc_sz;
126 ynl_parse_cb_t cb;
127 __u32 rsp_cmd;
128 };
129
130 struct ynl_ntf_info {
131 const struct ynl_policy_nest *policy;
132 ynl_parse_cb_t cb;
133 size_t alloc_sz;
134 void (*free)(struct ynl_ntf_base_type *ntf);
135 };
136
137 int ynl_exec(struct ynl_sock *ys, struct nlmsghdr *req_nlh,
138 struct ynl_req_state *yrs);
139 int ynl_exec_dump(struct ynl_sock *ys, struct nlmsghdr *req_nlh,
140 struct ynl_dump_state *yds);
141
142 void ynl_error_unknown_notification(struct ynl_sock *ys, __u8 cmd);
143 int ynl_error_parse(struct ynl_parse_arg *yarg, const char *msg);
144
145 /* Netlink message handling helpers */
146
147 #define YNL_MSG_OVERFLOW 1
148
ynl_nlmsg_put_header(void * buf)149 static inline struct nlmsghdr *ynl_nlmsg_put_header(void *buf)
150 {
151 struct nlmsghdr *nlh = (struct nlmsghdr *)buf;
152
153 memset(nlh, 0, sizeof(*nlh));
154 nlh->nlmsg_len = NLMSG_HDRLEN;
155
156 return nlh;
157 }
158
ynl_nlmsg_data_len(const struct nlmsghdr * nlh)159 static inline unsigned int ynl_nlmsg_data_len(const struct nlmsghdr *nlh)
160 {
161 return nlh->nlmsg_len - NLMSG_HDRLEN;
162 }
163
ynl_nlmsg_data(const struct nlmsghdr * nlh)164 static inline void *ynl_nlmsg_data(const struct nlmsghdr *nlh)
165 {
166 return (unsigned char *)nlh + NLMSG_HDRLEN;
167 }
168
169 static inline void *
ynl_nlmsg_data_offset(const struct nlmsghdr * nlh,unsigned int offset)170 ynl_nlmsg_data_offset(const struct nlmsghdr *nlh, unsigned int offset)
171 {
172 return (unsigned char *)nlh + NLMSG_HDRLEN + offset;
173 }
174
ynl_nlmsg_end_addr(const struct nlmsghdr * nlh)175 static inline void *ynl_nlmsg_end_addr(const struct nlmsghdr *nlh)
176 {
177 return (char *)nlh + nlh->nlmsg_len;
178 }
179
180 static inline void *
ynl_nlmsg_put_extra_header(struct nlmsghdr * nlh,unsigned int size)181 ynl_nlmsg_put_extra_header(struct nlmsghdr *nlh, unsigned int size)
182 {
183 void *tail = ynl_nlmsg_end_addr(nlh);
184
185 nlh->nlmsg_len += NLMSG_ALIGN(size);
186 return tail;
187 }
188
189 /* Netlink attribute helpers */
190
ynl_attr_type(const struct nlattr * attr)191 static inline unsigned int ynl_attr_type(const struct nlattr *attr)
192 {
193 return attr->nla_type & NLA_TYPE_MASK;
194 }
195
ynl_attr_data_len(const struct nlattr * attr)196 static inline unsigned int ynl_attr_data_len(const struct nlattr *attr)
197 {
198 return attr->nla_len - NLA_HDRLEN;
199 }
200
ynl_attr_data(const struct nlattr * attr)201 static inline void *ynl_attr_data(const struct nlattr *attr)
202 {
203 return (unsigned char *)attr + NLA_HDRLEN;
204 }
205
ynl_attr_data_end(const struct nlattr * attr)206 static inline void *ynl_attr_data_end(const struct nlattr *attr)
207 {
208 return (char *)ynl_attr_data(attr) + ynl_attr_data_len(attr);
209 }
210
211 #define ynl_attr_for_each(attr, nlh, fixed_hdr_sz) \
212 for ((attr) = ynl_attr_first(nlh, (nlh)->nlmsg_len, \
213 NLMSG_HDRLEN + fixed_hdr_sz); attr; \
214 (attr) = ynl_attr_next(ynl_nlmsg_end_addr(nlh), attr))
215
216 #define ynl_attr_for_each_nested_off(attr, outer, offset) \
217 for ((attr) = ynl_attr_first(outer, outer->nla_len, \
218 sizeof(struct nlattr) + offset); \
219 attr; \
220 (attr) = ynl_attr_next(ynl_attr_data_end(outer), attr))
221
222 #define ynl_attr_for_each_nested(attr, outer) \
223 ynl_attr_for_each_nested_off(attr, outer, 0)
224
225 #define ynl_attr_for_each_payload(start, len, attr) \
226 for ((attr) = ynl_attr_first(start, len, 0); attr; \
227 (attr) = ynl_attr_next(start + len, attr))
228
229 static inline struct nlattr *
ynl_attr_if_good(const void * end,struct nlattr * attr)230 ynl_attr_if_good(const void *end, struct nlattr *attr)
231 {
232 if (attr + 1 > (const struct nlattr *)end)
233 return NULL;
234 if (ynl_attr_data_end(attr) > end)
235 return NULL;
236 return attr;
237 }
238
239 static inline struct nlattr *
ynl_attr_next(const void * end,const struct nlattr * prev)240 ynl_attr_next(const void *end, const struct nlattr *prev)
241 {
242 struct nlattr *attr;
243
244 attr = (struct nlattr *)((char *)prev + NLA_ALIGN(prev->nla_len));
245 return ynl_attr_if_good(end, attr);
246 }
247
248 static inline struct nlattr *
ynl_attr_first(const void * start,size_t len,size_t skip)249 ynl_attr_first(const void *start, size_t len, size_t skip)
250 {
251 struct nlattr *attr;
252
253 attr = (struct nlattr *)((char *)start + NLMSG_ALIGN(skip));
254 return ynl_attr_if_good((char *)start + len, attr);
255 }
256
257 static inline bool
__ynl_attr_put_overflow(struct nlmsghdr * nlh,size_t size)258 __ynl_attr_put_overflow(struct nlmsghdr *nlh, size_t size)
259 {
260 bool o;
261
262 /* ynl_msg_start() stashed buffer length in nlmsg_pid. */
263 o = nlh->nlmsg_len + NLA_HDRLEN + NLMSG_ALIGN(size) > nlh->nlmsg_pid;
264 if (o)
265 /* YNL_MSG_OVERFLOW is < NLMSG_HDRLEN, all subsequent checks
266 * are guaranteed to fail.
267 */
268 nlh->nlmsg_pid = YNL_MSG_OVERFLOW;
269 return o;
270 }
271
272 static inline struct nlattr *
ynl_attr_nest_start(struct nlmsghdr * nlh,unsigned int attr_type)273 ynl_attr_nest_start(struct nlmsghdr *nlh, unsigned int attr_type)
274 {
275 struct nlattr *attr;
276
277 if (__ynl_attr_put_overflow(nlh, 0))
278 return (struct nlattr *)ynl_nlmsg_end_addr(nlh) - 1;
279
280 attr = (struct nlattr *)ynl_nlmsg_end_addr(nlh);
281 attr->nla_type = attr_type | NLA_F_NESTED;
282 nlh->nlmsg_len += NLA_HDRLEN;
283
284 return attr;
285 }
286
287 static inline void
ynl_attr_nest_end(struct nlmsghdr * nlh,struct nlattr * attr)288 ynl_attr_nest_end(struct nlmsghdr *nlh, struct nlattr *attr)
289 {
290 attr->nla_len = (char *)ynl_nlmsg_end_addr(nlh) - (char *)attr;
291 }
292
293 static inline void
ynl_attr_put(struct nlmsghdr * nlh,unsigned int attr_type,const void * value,size_t size)294 ynl_attr_put(struct nlmsghdr *nlh, unsigned int attr_type,
295 const void *value, size_t size)
296 {
297 struct nlattr *attr;
298
299 if (__ynl_attr_put_overflow(nlh, size))
300 return;
301
302 attr = (struct nlattr *)ynl_nlmsg_end_addr(nlh);
303 attr->nla_type = attr_type;
304 attr->nla_len = NLA_HDRLEN + size;
305
306 memcpy(ynl_attr_data(attr), value, size);
307
308 nlh->nlmsg_len += NLMSG_ALIGN(attr->nla_len);
309 }
310
311 static inline void
ynl_attr_put_str(struct nlmsghdr * nlh,unsigned int attr_type,const char * str)312 ynl_attr_put_str(struct nlmsghdr *nlh, unsigned int attr_type, const char *str)
313 {
314 struct nlattr *attr;
315 size_t len;
316
317 len = strlen(str);
318 if (__ynl_attr_put_overflow(nlh, len))
319 return;
320
321 attr = (struct nlattr *)ynl_nlmsg_end_addr(nlh);
322 attr->nla_type = attr_type;
323
324 strcpy((char *)ynl_attr_data(attr), str);
325 attr->nla_len = NLA_HDRLEN + NLA_ALIGN(len);
326
327 nlh->nlmsg_len += NLMSG_ALIGN(attr->nla_len);
328 }
329
ynl_attr_get_str(const struct nlattr * attr)330 static inline const char *ynl_attr_get_str(const struct nlattr *attr)
331 {
332 return (const char *)ynl_attr_data(attr);
333 }
334
ynl_attr_get_s8(const struct nlattr * attr)335 static inline __s8 ynl_attr_get_s8(const struct nlattr *attr)
336 {
337 return *(__s8 *)ynl_attr_data(attr);
338 }
339
ynl_attr_get_s16(const struct nlattr * attr)340 static inline __s16 ynl_attr_get_s16(const struct nlattr *attr)
341 {
342 return *(__s16 *)ynl_attr_data(attr);
343 }
344
ynl_attr_get_s32(const struct nlattr * attr)345 static inline __s32 ynl_attr_get_s32(const struct nlattr *attr)
346 {
347 return *(__s32 *)ynl_attr_data(attr);
348 }
349
ynl_attr_get_s64(const struct nlattr * attr)350 static inline __s64 ynl_attr_get_s64(const struct nlattr *attr)
351 {
352 __s64 tmp;
353
354 memcpy(&tmp, (unsigned char *)(attr + 1), sizeof(tmp));
355 return tmp;
356 }
357
ynl_attr_get_u8(const struct nlattr * attr)358 static inline __u8 ynl_attr_get_u8(const struct nlattr *attr)
359 {
360 return *(__u8 *)ynl_attr_data(attr);
361 }
362
ynl_attr_get_u16(const struct nlattr * attr)363 static inline __u16 ynl_attr_get_u16(const struct nlattr *attr)
364 {
365 return *(__u16 *)ynl_attr_data(attr);
366 }
367
ynl_attr_get_u32(const struct nlattr * attr)368 static inline __u32 ynl_attr_get_u32(const struct nlattr *attr)
369 {
370 return *(__u32 *)ynl_attr_data(attr);
371 }
372
ynl_attr_get_u64(const struct nlattr * attr)373 static inline __u64 ynl_attr_get_u64(const struct nlattr *attr)
374 {
375 __u64 tmp;
376
377 memcpy(&tmp, (unsigned char *)(attr + 1), sizeof(tmp));
378 return tmp;
379 }
380
381 static inline void
ynl_attr_put_s8(struct nlmsghdr * nlh,unsigned int attr_type,__s8 value)382 ynl_attr_put_s8(struct nlmsghdr *nlh, unsigned int attr_type, __s8 value)
383 {
384 ynl_attr_put(nlh, attr_type, &value, sizeof(value));
385 }
386
387 static inline void
ynl_attr_put_s16(struct nlmsghdr * nlh,unsigned int attr_type,__s16 value)388 ynl_attr_put_s16(struct nlmsghdr *nlh, unsigned int attr_type, __s16 value)
389 {
390 ynl_attr_put(nlh, attr_type, &value, sizeof(value));
391 }
392
393 static inline void
ynl_attr_put_s32(struct nlmsghdr * nlh,unsigned int attr_type,__s32 value)394 ynl_attr_put_s32(struct nlmsghdr *nlh, unsigned int attr_type, __s32 value)
395 {
396 ynl_attr_put(nlh, attr_type, &value, sizeof(value));
397 }
398
399 static inline void
ynl_attr_put_s64(struct nlmsghdr * nlh,unsigned int attr_type,__s64 value)400 ynl_attr_put_s64(struct nlmsghdr *nlh, unsigned int attr_type, __s64 value)
401 {
402 ynl_attr_put(nlh, attr_type, &value, sizeof(value));
403 }
404
405 static inline void
ynl_attr_put_u8(struct nlmsghdr * nlh,unsigned int attr_type,__u8 value)406 ynl_attr_put_u8(struct nlmsghdr *nlh, unsigned int attr_type, __u8 value)
407 {
408 ynl_attr_put(nlh, attr_type, &value, sizeof(value));
409 }
410
411 static inline void
ynl_attr_put_u16(struct nlmsghdr * nlh,unsigned int attr_type,__u16 value)412 ynl_attr_put_u16(struct nlmsghdr *nlh, unsigned int attr_type, __u16 value)
413 {
414 ynl_attr_put(nlh, attr_type, &value, sizeof(value));
415 }
416
417 static inline void
ynl_attr_put_u32(struct nlmsghdr * nlh,unsigned int attr_type,__u32 value)418 ynl_attr_put_u32(struct nlmsghdr *nlh, unsigned int attr_type, __u32 value)
419 {
420 ynl_attr_put(nlh, attr_type, &value, sizeof(value));
421 }
422
423 static inline void
ynl_attr_put_u64(struct nlmsghdr * nlh,unsigned int attr_type,__u64 value)424 ynl_attr_put_u64(struct nlmsghdr *nlh, unsigned int attr_type, __u64 value)
425 {
426 ynl_attr_put(nlh, attr_type, &value, sizeof(value));
427 }
428
ynl_attr_get_uint(const struct nlattr * attr)429 static inline __u64 ynl_attr_get_uint(const struct nlattr *attr)
430 {
431 switch (ynl_attr_data_len(attr)) {
432 case 4:
433 return ynl_attr_get_u32(attr);
434 case 8:
435 return ynl_attr_get_u64(attr);
436 default:
437 return 0;
438 }
439 }
440
ynl_attr_get_sint(const struct nlattr * attr)441 static inline __s64 ynl_attr_get_sint(const struct nlattr *attr)
442 {
443 switch (ynl_attr_data_len(attr)) {
444 case 4:
445 return ynl_attr_get_s32(attr);
446 case 8:
447 return ynl_attr_get_s64(attr);
448 default:
449 return 0;
450 }
451 }
452
453 static inline void
ynl_attr_put_uint(struct nlmsghdr * nlh,__u16 type,__u64 data)454 ynl_attr_put_uint(struct nlmsghdr *nlh, __u16 type, __u64 data)
455 {
456 if ((__u32)data == (__u64)data)
457 ynl_attr_put_u32(nlh, type, data);
458 else
459 ynl_attr_put_u64(nlh, type, data);
460 }
461
462 static inline void
ynl_attr_put_sint(struct nlmsghdr * nlh,__u16 type,__s64 data)463 ynl_attr_put_sint(struct nlmsghdr *nlh, __u16 type, __s64 data)
464 {
465 if ((__s32)data == (__s64)data)
466 ynl_attr_put_s32(nlh, type, data);
467 else
468 ynl_attr_put_s64(nlh, type, data);
469 }
470 #endif
471