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_submsg_failed(struct ynl_parse_arg *yarg, const char *field_name,
110 const char *sel_name);
111
112 /* YNL specific helpers used by the auto-generated code */
113
114 struct ynl_req_state {
115 struct ynl_parse_arg yarg;
116 ynl_parse_cb_t cb;
117 __u32 rsp_cmd;
118 };
119
120 struct ynl_dump_state {
121 struct ynl_parse_arg yarg;
122 void *first;
123 struct ynl_dump_list_type *last;
124 size_t alloc_sz;
125 ynl_parse_cb_t cb;
126 __u32 rsp_cmd;
127 };
128
129 struct ynl_ntf_info {
130 const struct ynl_policy_nest *policy;
131 ynl_parse_cb_t cb;
132 size_t alloc_sz;
133 void (*free)(struct ynl_ntf_base_type *ntf);
134 };
135
136 int ynl_exec(struct ynl_sock *ys, struct nlmsghdr *req_nlh,
137 struct ynl_req_state *yrs);
138 int ynl_exec_dump(struct ynl_sock *ys, struct nlmsghdr *req_nlh,
139 struct ynl_dump_state *yds);
140
141 void ynl_error_unknown_notification(struct ynl_sock *ys, __u8 cmd);
142 int ynl_error_parse(struct ynl_parse_arg *yarg, const char *msg);
143
144 /* Netlink message handling helpers */
145
146 #define YNL_MSG_OVERFLOW 1
147
ynl_nlmsg_put_header(void * buf)148 static inline struct nlmsghdr *ynl_nlmsg_put_header(void *buf)
149 {
150 struct nlmsghdr *nlh = (struct nlmsghdr *)buf;
151
152 memset(nlh, 0, sizeof(*nlh));
153 nlh->nlmsg_len = NLMSG_HDRLEN;
154
155 return nlh;
156 }
157
ynl_nlmsg_data_len(const struct nlmsghdr * nlh)158 static inline unsigned int ynl_nlmsg_data_len(const struct nlmsghdr *nlh)
159 {
160 return nlh->nlmsg_len - NLMSG_HDRLEN;
161 }
162
ynl_nlmsg_data(const struct nlmsghdr * nlh)163 static inline void *ynl_nlmsg_data(const struct nlmsghdr *nlh)
164 {
165 return (unsigned char *)nlh + NLMSG_HDRLEN;
166 }
167
168 static inline void *
ynl_nlmsg_data_offset(const struct nlmsghdr * nlh,unsigned int offset)169 ynl_nlmsg_data_offset(const struct nlmsghdr *nlh, unsigned int offset)
170 {
171 return (unsigned char *)nlh + NLMSG_HDRLEN + offset;
172 }
173
ynl_nlmsg_end_addr(const struct nlmsghdr * nlh)174 static inline void *ynl_nlmsg_end_addr(const struct nlmsghdr *nlh)
175 {
176 return (char *)nlh + nlh->nlmsg_len;
177 }
178
179 static inline void *
ynl_nlmsg_put_extra_header(struct nlmsghdr * nlh,unsigned int size)180 ynl_nlmsg_put_extra_header(struct nlmsghdr *nlh, unsigned int size)
181 {
182 void *tail = ynl_nlmsg_end_addr(nlh);
183
184 nlh->nlmsg_len += NLMSG_ALIGN(size);
185 return tail;
186 }
187
188 /* Netlink attribute helpers */
189
ynl_attr_type(const struct nlattr * attr)190 static inline unsigned int ynl_attr_type(const struct nlattr *attr)
191 {
192 return attr->nla_type & NLA_TYPE_MASK;
193 }
194
ynl_attr_data_len(const struct nlattr * attr)195 static inline unsigned int ynl_attr_data_len(const struct nlattr *attr)
196 {
197 return attr->nla_len - NLA_HDRLEN;
198 }
199
ynl_attr_data(const struct nlattr * attr)200 static inline void *ynl_attr_data(const struct nlattr *attr)
201 {
202 return (unsigned char *)attr + NLA_HDRLEN;
203 }
204
ynl_attr_data_end(const struct nlattr * attr)205 static inline void *ynl_attr_data_end(const struct nlattr *attr)
206 {
207 return (char *)ynl_attr_data(attr) + ynl_attr_data_len(attr);
208 }
209
210 #define ynl_attr_for_each(attr, nlh, fixed_hdr_sz) \
211 for ((attr) = ynl_attr_first(nlh, (nlh)->nlmsg_len, \
212 NLMSG_HDRLEN + fixed_hdr_sz); attr; \
213 (attr) = ynl_attr_next(ynl_nlmsg_end_addr(nlh), attr))
214
215 #define ynl_attr_for_each_nested_off(attr, outer, offset) \
216 for ((attr) = ynl_attr_first(outer, outer->nla_len, \
217 sizeof(struct nlattr) + offset); \
218 attr; \
219 (attr) = ynl_attr_next(ynl_attr_data_end(outer), attr))
220
221 #define ynl_attr_for_each_nested(attr, outer) \
222 ynl_attr_for_each_nested_off(attr, outer, 0)
223
224 #define ynl_attr_for_each_payload(start, len, attr) \
225 for ((attr) = ynl_attr_first(start, len, 0); attr; \
226 (attr) = ynl_attr_next(start + len, attr))
227
228 static inline struct nlattr *
ynl_attr_if_good(const void * end,struct nlattr * attr)229 ynl_attr_if_good(const void *end, struct nlattr *attr)
230 {
231 if (attr + 1 > (const struct nlattr *)end)
232 return NULL;
233 if (ynl_attr_data_end(attr) > end)
234 return NULL;
235 return attr;
236 }
237
238 static inline struct nlattr *
ynl_attr_next(const void * end,const struct nlattr * prev)239 ynl_attr_next(const void *end, const struct nlattr *prev)
240 {
241 struct nlattr *attr;
242
243 attr = (struct nlattr *)((char *)prev + NLA_ALIGN(prev->nla_len));
244 return ynl_attr_if_good(end, attr);
245 }
246
247 static inline struct nlattr *
ynl_attr_first(const void * start,size_t len,size_t skip)248 ynl_attr_first(const void *start, size_t len, size_t skip)
249 {
250 struct nlattr *attr;
251
252 attr = (struct nlattr *)((char *)start + NLMSG_ALIGN(skip));
253 return ynl_attr_if_good((char *)start + len, attr);
254 }
255
256 static inline bool
__ynl_attr_put_overflow(struct nlmsghdr * nlh,size_t size)257 __ynl_attr_put_overflow(struct nlmsghdr *nlh, size_t size)
258 {
259 bool o;
260
261 /* ynl_msg_start() stashed buffer length in nlmsg_pid. */
262 o = nlh->nlmsg_len + NLA_HDRLEN + NLMSG_ALIGN(size) > nlh->nlmsg_pid;
263 if (o)
264 /* YNL_MSG_OVERFLOW is < NLMSG_HDRLEN, all subsequent checks
265 * are guaranteed to fail.
266 */
267 nlh->nlmsg_pid = YNL_MSG_OVERFLOW;
268 return o;
269 }
270
271 static inline struct nlattr *
ynl_attr_nest_start(struct nlmsghdr * nlh,unsigned int attr_type)272 ynl_attr_nest_start(struct nlmsghdr *nlh, unsigned int attr_type)
273 {
274 struct nlattr *attr;
275
276 if (__ynl_attr_put_overflow(nlh, 0))
277 return (struct nlattr *)ynl_nlmsg_end_addr(nlh) - 1;
278
279 attr = (struct nlattr *)ynl_nlmsg_end_addr(nlh);
280 attr->nla_type = attr_type | NLA_F_NESTED;
281 nlh->nlmsg_len += NLA_HDRLEN;
282
283 return attr;
284 }
285
286 static inline void
ynl_attr_nest_end(struct nlmsghdr * nlh,struct nlattr * attr)287 ynl_attr_nest_end(struct nlmsghdr *nlh, struct nlattr *attr)
288 {
289 attr->nla_len = (char *)ynl_nlmsg_end_addr(nlh) - (char *)attr;
290 }
291
292 static inline void
ynl_attr_put(struct nlmsghdr * nlh,unsigned int attr_type,const void * value,size_t size)293 ynl_attr_put(struct nlmsghdr *nlh, unsigned int attr_type,
294 const void *value, size_t size)
295 {
296 struct nlattr *attr;
297
298 if (__ynl_attr_put_overflow(nlh, size))
299 return;
300
301 attr = (struct nlattr *)ynl_nlmsg_end_addr(nlh);
302 attr->nla_type = attr_type;
303 attr->nla_len = NLA_HDRLEN + size;
304
305 memcpy(ynl_attr_data(attr), value, size);
306
307 nlh->nlmsg_len += NLMSG_ALIGN(attr->nla_len);
308 }
309
310 static inline void
ynl_attr_put_str(struct nlmsghdr * nlh,unsigned int attr_type,const char * str)311 ynl_attr_put_str(struct nlmsghdr *nlh, unsigned int attr_type, const char *str)
312 {
313 struct nlattr *attr;
314 size_t len;
315
316 len = strlen(str) + 1;
317 if (__ynl_attr_put_overflow(nlh, len))
318 return;
319
320 attr = (struct nlattr *)ynl_nlmsg_end_addr(nlh);
321 attr->nla_type = attr_type;
322
323 strcpy((char *)ynl_attr_data(attr), str);
324 attr->nla_len = NLA_HDRLEN + len;
325
326 nlh->nlmsg_len += NLMSG_ALIGN(attr->nla_len);
327 }
328
ynl_attr_get_str(const struct nlattr * attr)329 static inline const char *ynl_attr_get_str(const struct nlattr *attr)
330 {
331 return (const char *)ynl_attr_data(attr);
332 }
333
ynl_attr_get_s8(const struct nlattr * attr)334 static inline __s8 ynl_attr_get_s8(const struct nlattr *attr)
335 {
336 return *(__s8 *)ynl_attr_data(attr);
337 }
338
ynl_attr_get_s16(const struct nlattr * attr)339 static inline __s16 ynl_attr_get_s16(const struct nlattr *attr)
340 {
341 return *(__s16 *)ynl_attr_data(attr);
342 }
343
ynl_attr_get_s32(const struct nlattr * attr)344 static inline __s32 ynl_attr_get_s32(const struct nlattr *attr)
345 {
346 return *(__s32 *)ynl_attr_data(attr);
347 }
348
ynl_attr_get_s64(const struct nlattr * attr)349 static inline __s64 ynl_attr_get_s64(const struct nlattr *attr)
350 {
351 __s64 tmp;
352
353 memcpy(&tmp, (unsigned char *)(attr + 1), sizeof(tmp));
354 return tmp;
355 }
356
ynl_attr_get_u8(const struct nlattr * attr)357 static inline __u8 ynl_attr_get_u8(const struct nlattr *attr)
358 {
359 return *(__u8 *)ynl_attr_data(attr);
360 }
361
ynl_attr_get_u16(const struct nlattr * attr)362 static inline __u16 ynl_attr_get_u16(const struct nlattr *attr)
363 {
364 return *(__u16 *)ynl_attr_data(attr);
365 }
366
ynl_attr_get_u32(const struct nlattr * attr)367 static inline __u32 ynl_attr_get_u32(const struct nlattr *attr)
368 {
369 return *(__u32 *)ynl_attr_data(attr);
370 }
371
ynl_attr_get_u64(const struct nlattr * attr)372 static inline __u64 ynl_attr_get_u64(const struct nlattr *attr)
373 {
374 __u64 tmp;
375
376 memcpy(&tmp, (unsigned char *)(attr + 1), sizeof(tmp));
377 return tmp;
378 }
379
380 static inline void
ynl_attr_put_s8(struct nlmsghdr * nlh,unsigned int attr_type,__s8 value)381 ynl_attr_put_s8(struct nlmsghdr *nlh, unsigned int attr_type, __s8 value)
382 {
383 ynl_attr_put(nlh, attr_type, &value, sizeof(value));
384 }
385
386 static inline void
ynl_attr_put_s16(struct nlmsghdr * nlh,unsigned int attr_type,__s16 value)387 ynl_attr_put_s16(struct nlmsghdr *nlh, unsigned int attr_type, __s16 value)
388 {
389 ynl_attr_put(nlh, attr_type, &value, sizeof(value));
390 }
391
392 static inline void
ynl_attr_put_s32(struct nlmsghdr * nlh,unsigned int attr_type,__s32 value)393 ynl_attr_put_s32(struct nlmsghdr *nlh, unsigned int attr_type, __s32 value)
394 {
395 ynl_attr_put(nlh, attr_type, &value, sizeof(value));
396 }
397
398 static inline void
ynl_attr_put_s64(struct nlmsghdr * nlh,unsigned int attr_type,__s64 value)399 ynl_attr_put_s64(struct nlmsghdr *nlh, unsigned int attr_type, __s64 value)
400 {
401 ynl_attr_put(nlh, attr_type, &value, sizeof(value));
402 }
403
404 static inline void
ynl_attr_put_u8(struct nlmsghdr * nlh,unsigned int attr_type,__u8 value)405 ynl_attr_put_u8(struct nlmsghdr *nlh, unsigned int attr_type, __u8 value)
406 {
407 ynl_attr_put(nlh, attr_type, &value, sizeof(value));
408 }
409
410 static inline void
ynl_attr_put_u16(struct nlmsghdr * nlh,unsigned int attr_type,__u16 value)411 ynl_attr_put_u16(struct nlmsghdr *nlh, unsigned int attr_type, __u16 value)
412 {
413 ynl_attr_put(nlh, attr_type, &value, sizeof(value));
414 }
415
416 static inline void
ynl_attr_put_u32(struct nlmsghdr * nlh,unsigned int attr_type,__u32 value)417 ynl_attr_put_u32(struct nlmsghdr *nlh, unsigned int attr_type, __u32 value)
418 {
419 ynl_attr_put(nlh, attr_type, &value, sizeof(value));
420 }
421
422 static inline void
ynl_attr_put_u64(struct nlmsghdr * nlh,unsigned int attr_type,__u64 value)423 ynl_attr_put_u64(struct nlmsghdr *nlh, unsigned int attr_type, __u64 value)
424 {
425 ynl_attr_put(nlh, attr_type, &value, sizeof(value));
426 }
427
ynl_attr_get_uint(const struct nlattr * attr)428 static inline __u64 ynl_attr_get_uint(const struct nlattr *attr)
429 {
430 switch (ynl_attr_data_len(attr)) {
431 case 4:
432 return ynl_attr_get_u32(attr);
433 case 8:
434 return ynl_attr_get_u64(attr);
435 default:
436 return 0;
437 }
438 }
439
ynl_attr_get_sint(const struct nlattr * attr)440 static inline __s64 ynl_attr_get_sint(const struct nlattr *attr)
441 {
442 switch (ynl_attr_data_len(attr)) {
443 case 4:
444 return ynl_attr_get_s32(attr);
445 case 8:
446 return ynl_attr_get_s64(attr);
447 default:
448 return 0;
449 }
450 }
451
452 static inline void
ynl_attr_put_uint(struct nlmsghdr * nlh,__u16 type,__u64 data)453 ynl_attr_put_uint(struct nlmsghdr *nlh, __u16 type, __u64 data)
454 {
455 if ((__u32)data == (__u64)data)
456 ynl_attr_put_u32(nlh, type, data);
457 else
458 ynl_attr_put_u64(nlh, type, data);
459 }
460
461 static inline void
ynl_attr_put_sint(struct nlmsghdr * nlh,__u16 type,__s64 data)462 ynl_attr_put_sint(struct nlmsghdr *nlh, __u16 type, __s64 data)
463 {
464 if ((__s32)data == (__s64)data)
465 ynl_attr_put_s32(nlh, type, data);
466 else
467 ynl_attr_put_s64(nlh, type, data);
468 }
469
470 int __ynl_attr_validate(struct ynl_parse_arg *yarg, const struct nlattr *attr,
471 unsigned int type);
472
ynl_attr_validate(struct ynl_parse_arg * yarg,const struct nlattr * attr)473 static inline int ynl_attr_validate(struct ynl_parse_arg *yarg,
474 const struct nlattr *attr)
475 {
476 return __ynl_attr_validate(yarg, attr, ynl_attr_type(attr));
477 }
478 #endif
479