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