xref: /linux/tools/net/ynl/lib/ynl-priv.h (revision 6e7fd890f1d6ac83805409e9c346240de2705584)
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 };
29 
30 enum 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 
41 typedef int (*ynl_parse_cb_t)(const struct nlmsghdr *nlh,
42 			      struct ynl_parse_arg *yarg);
43 
44 struct ynl_policy_attr {
45 	enum ynl_policy_type type;
46 	unsigned int len;
47 	const char *name;
48 	const struct ynl_policy_nest *nest;
49 };
50 
51 struct ynl_policy_nest {
52 	unsigned int max_attr;
53 	const struct ynl_policy_attr *table;
54 };
55 
56 struct ynl_parse_arg {
57 	struct ynl_sock *ys;
58 	const struct ynl_policy_nest *rsp_policy;
59 	void *data;
60 };
61 
62 struct ynl_dump_list_type {
63 	struct ynl_dump_list_type *next;
64 	unsigned char data[] __attribute__((aligned(8)));
65 };
66 extern struct ynl_dump_list_type *YNL_LIST_END;
67 
68 static 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 
76 static 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 = (struct ynl_dump_list_type *)uptr;
83 	uptr = (unsigned long)list->next;
84 	uptr += offsetof(struct ynl_dump_list_type, data);
85 
86 	return (void *)uptr;
87 }
88 
89 struct 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 
97 struct nlmsghdr *
98 ynl_gemsg_start_req(struct ynl_sock *ys, __u32 id, __u8 cmd, __u8 version);
99 struct nlmsghdr *
100 ynl_gemsg_start_dump(struct ynl_sock *ys, __u32 id, __u8 cmd, __u8 version);
101 
102 int ynl_attr_validate(struct ynl_parse_arg *yarg, const struct nlattr *attr);
103 
104 /* YNL specific helpers used by the auto-generated code */
105 
106 struct ynl_req_state {
107 	struct ynl_parse_arg yarg;
108 	ynl_parse_cb_t cb;
109 	__u32 rsp_cmd;
110 };
111 
112 struct 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 
121 struct ynl_ntf_info {
122 	const 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 
128 int ynl_exec(struct ynl_sock *ys, struct nlmsghdr *req_nlh,
129 	     struct ynl_req_state *yrs);
130 int ynl_exec_dump(struct ynl_sock *ys, struct nlmsghdr *req_nlh,
131 		  struct ynl_dump_state *yds);
132 
133 void ynl_error_unknown_notification(struct ynl_sock *ys, __u8 cmd);
134 int 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 
140 static inline struct nlmsghdr *ynl_nlmsg_put_header(void *buf)
141 {
142 	struct nlmsghdr *nlh = (struct nlmsghdr *)buf;
143 
144 	memset(nlh, 0, sizeof(*nlh));
145 	nlh->nlmsg_len = NLMSG_HDRLEN;
146 
147 	return nlh;
148 }
149 
150 static inline unsigned int ynl_nlmsg_data_len(const struct nlmsghdr *nlh)
151 {
152 	return nlh->nlmsg_len - NLMSG_HDRLEN;
153 }
154 
155 static inline void *ynl_nlmsg_data(const struct nlmsghdr *nlh)
156 {
157 	return (unsigned char *)nlh + NLMSG_HDRLEN;
158 }
159 
160 static inline void *
161 ynl_nlmsg_data_offset(const struct nlmsghdr *nlh, unsigned int offset)
162 {
163 	return (unsigned char *)nlh + NLMSG_HDRLEN + offset;
164 }
165 
166 static inline void *ynl_nlmsg_end_addr(const struct nlmsghdr *nlh)
167 {
168 	return (char *)nlh + nlh->nlmsg_len;
169 }
170 
171 static inline void *
172 ynl_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 
182 static inline unsigned int ynl_attr_type(const struct nlattr *attr)
183 {
184 	return attr->nla_type & NLA_TYPE_MASK;
185 }
186 
187 static inline unsigned int ynl_attr_data_len(const struct nlattr *attr)
188 {
189 	return attr->nla_len - NLA_HDRLEN;
190 }
191 
192 static inline void *ynl_attr_data(const struct nlattr *attr)
193 {
194 	return (unsigned char *)attr + NLA_HDRLEN;
195 }
196 
197 static inline void *ynl_attr_data_end(const struct nlattr *attr)
198 {
199 	return (char *)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 
216 static inline struct nlattr *
217 ynl_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 
226 static inline struct nlattr *
227 ynl_attr_next(const void *end, const struct nlattr *prev)
228 {
229 	struct nlattr *attr;
230 
231 	attr = (struct nlattr *)((char *)prev + NLA_ALIGN(prev->nla_len));
232 	return ynl_attr_if_good(end, attr);
233 }
234 
235 static inline struct nlattr *
236 ynl_attr_first(const void *start, size_t len, size_t skip)
237 {
238 	struct nlattr *attr;
239 
240 	attr = (struct nlattr *)((char *)start + NLMSG_ALIGN(skip));
241 	return ynl_attr_if_good((char *)start + len, attr);
242 }
243 
244 static 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 
259 static inline struct nlattr *
260 ynl_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 (struct nlattr *)ynl_nlmsg_end_addr(nlh) - 1;
266 
267 	attr = (struct nlattr *)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 
274 static inline void
275 ynl_attr_nest_end(struct nlmsghdr *nlh, struct nlattr *attr)
276 {
277 	attr->nla_len = (char *)ynl_nlmsg_end_addr(nlh) - (char *)attr;
278 }
279 
280 static inline void
281 ynl_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 = (struct nlattr *)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 
298 static inline void
299 ynl_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 = (struct nlattr *)ynl_nlmsg_end_addr(nlh);
309 	attr->nla_type = attr_type;
310 
311 	strcpy((char *)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 
317 static inline const char *ynl_attr_get_str(const struct nlattr *attr)
318 {
319 	return (const char *)ynl_attr_data(attr);
320 }
321 
322 static inline __s8 ynl_attr_get_s8(const struct nlattr *attr)
323 {
324 	return *(__s8 *)ynl_attr_data(attr);
325 }
326 
327 static inline __s16 ynl_attr_get_s16(const struct nlattr *attr)
328 {
329 	return *(__s16 *)ynl_attr_data(attr);
330 }
331 
332 static inline __s32 ynl_attr_get_s32(const struct nlattr *attr)
333 {
334 	return *(__s32 *)ynl_attr_data(attr);
335 }
336 
337 static 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 
345 static inline __u8 ynl_attr_get_u8(const struct nlattr *attr)
346 {
347 	return *(__u8 *)ynl_attr_data(attr);
348 }
349 
350 static inline __u16 ynl_attr_get_u16(const struct nlattr *attr)
351 {
352 	return *(__u16 *)ynl_attr_data(attr);
353 }
354 
355 static inline __u32 ynl_attr_get_u32(const struct nlattr *attr)
356 {
357 	return *(__u32 *)ynl_attr_data(attr);
358 }
359 
360 static 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 
368 static inline void
369 ynl_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 
374 static inline void
375 ynl_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 
380 static inline void
381 ynl_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 
386 static inline void
387 ynl_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 
392 static inline void
393 ynl_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 
398 static inline void
399 ynl_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 
404 static inline void
405 ynl_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 
410 static inline void
411 ynl_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 
416 static 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 
428 static 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 
440 static inline void
441 ynl_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 
449 static inline void
450 ynl_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