xref: /linux/tools/net/ynl/lib/ynl-priv.h (revision 6bab77ced3ffbce3d6c5b5bcce17da7c8a3f8266)
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 
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 
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 
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 
159 static inline unsigned int ynl_nlmsg_data_len(const struct nlmsghdr *nlh)
160 {
161 	return nlh->nlmsg_len - NLMSG_HDRLEN;
162 }
163 
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 *
170 ynl_nlmsg_data_offset(const struct nlmsghdr *nlh, unsigned int offset)
171 {
172 	return (unsigned char *)nlh + NLMSG_HDRLEN + offset;
173 }
174 
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 *
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 
191 static inline unsigned int ynl_attr_type(const struct nlattr *attr)
192 {
193 	return attr->nla_type & NLA_TYPE_MASK;
194 }
195 
196 static inline unsigned int ynl_attr_data_len(const struct nlattr *attr)
197 {
198 	return attr->nla_len - NLA_HDRLEN;
199 }
200 
201 static inline void *ynl_attr_data(const struct nlattr *attr)
202 {
203 	return (unsigned char *)attr + NLA_HDRLEN;
204 }
205 
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(attr, outer)				\
217 	for ((attr) = ynl_attr_first(outer, outer->nla_len,		\
218 				     sizeof(struct nlattr)); attr;	\
219 	     (attr) = ynl_attr_next(ynl_attr_data_end(outer), attr))
220 
221 #define ynl_attr_for_each_payload(start, len, attr)			\
222 	for ((attr) = ynl_attr_first(start, len, 0); attr;		\
223 	     (attr) = ynl_attr_next(start + len, attr))
224 
225 static inline struct nlattr *
226 ynl_attr_if_good(const void *end, struct nlattr *attr)
227 {
228 	if (attr + 1 > (const struct nlattr *)end)
229 		return NULL;
230 	if (ynl_attr_data_end(attr) > end)
231 		return NULL;
232 	return attr;
233 }
234 
235 static inline struct nlattr *
236 ynl_attr_next(const void *end, const struct nlattr *prev)
237 {
238 	struct nlattr *attr;
239 
240 	attr = (struct nlattr *)((char *)prev + NLA_ALIGN(prev->nla_len));
241 	return ynl_attr_if_good(end, attr);
242 }
243 
244 static inline struct nlattr *
245 ynl_attr_first(const void *start, size_t len, size_t skip)
246 {
247 	struct nlattr *attr;
248 
249 	attr = (struct nlattr *)((char *)start + NLMSG_ALIGN(skip));
250 	return ynl_attr_if_good((char *)start + len, attr);
251 }
252 
253 static inline bool
254 __ynl_attr_put_overflow(struct nlmsghdr *nlh, size_t size)
255 {
256 	bool o;
257 
258 	/* ynl_msg_start() stashed buffer length in nlmsg_pid. */
259 	o = nlh->nlmsg_len + NLA_HDRLEN + NLMSG_ALIGN(size) > nlh->nlmsg_pid;
260 	if (o)
261 		/* YNL_MSG_OVERFLOW is < NLMSG_HDRLEN, all subsequent checks
262 		 * are guaranteed to fail.
263 		 */
264 		nlh->nlmsg_pid = YNL_MSG_OVERFLOW;
265 	return o;
266 }
267 
268 static inline struct nlattr *
269 ynl_attr_nest_start(struct nlmsghdr *nlh, unsigned int attr_type)
270 {
271 	struct nlattr *attr;
272 
273 	if (__ynl_attr_put_overflow(nlh, 0))
274 		return (struct nlattr *)ynl_nlmsg_end_addr(nlh) - 1;
275 
276 	attr = (struct nlattr *)ynl_nlmsg_end_addr(nlh);
277 	attr->nla_type = attr_type | NLA_F_NESTED;
278 	nlh->nlmsg_len += NLA_HDRLEN;
279 
280 	return attr;
281 }
282 
283 static inline void
284 ynl_attr_nest_end(struct nlmsghdr *nlh, struct nlattr *attr)
285 {
286 	attr->nla_len = (char *)ynl_nlmsg_end_addr(nlh) - (char *)attr;
287 }
288 
289 static inline void
290 ynl_attr_put(struct nlmsghdr *nlh, unsigned int attr_type,
291 	     const void *value, size_t size)
292 {
293 	struct nlattr *attr;
294 
295 	if (__ynl_attr_put_overflow(nlh, size))
296 		return;
297 
298 	attr = (struct nlattr *)ynl_nlmsg_end_addr(nlh);
299 	attr->nla_type = attr_type;
300 	attr->nla_len = NLA_HDRLEN + size;
301 
302 	memcpy(ynl_attr_data(attr), value, size);
303 
304 	nlh->nlmsg_len += NLMSG_ALIGN(attr->nla_len);
305 }
306 
307 static inline void
308 ynl_attr_put_str(struct nlmsghdr *nlh, unsigned int attr_type, const char *str)
309 {
310 	struct nlattr *attr;
311 	size_t len;
312 
313 	len = strlen(str);
314 	if (__ynl_attr_put_overflow(nlh, len))
315 		return;
316 
317 	attr = (struct nlattr *)ynl_nlmsg_end_addr(nlh);
318 	attr->nla_type = attr_type;
319 
320 	strcpy((char *)ynl_attr_data(attr), str);
321 	attr->nla_len = NLA_HDRLEN + NLA_ALIGN(len);
322 
323 	nlh->nlmsg_len += NLMSG_ALIGN(attr->nla_len);
324 }
325 
326 static inline const char *ynl_attr_get_str(const struct nlattr *attr)
327 {
328 	return (const char *)ynl_attr_data(attr);
329 }
330 
331 static inline __s8 ynl_attr_get_s8(const struct nlattr *attr)
332 {
333 	return *(__s8 *)ynl_attr_data(attr);
334 }
335 
336 static inline __s16 ynl_attr_get_s16(const struct nlattr *attr)
337 {
338 	return *(__s16 *)ynl_attr_data(attr);
339 }
340 
341 static inline __s32 ynl_attr_get_s32(const struct nlattr *attr)
342 {
343 	return *(__s32 *)ynl_attr_data(attr);
344 }
345 
346 static inline __s64 ynl_attr_get_s64(const struct nlattr *attr)
347 {
348 	__s64 tmp;
349 
350 	memcpy(&tmp, (unsigned char *)(attr + 1), sizeof(tmp));
351 	return tmp;
352 }
353 
354 static inline __u8 ynl_attr_get_u8(const struct nlattr *attr)
355 {
356 	return *(__u8 *)ynl_attr_data(attr);
357 }
358 
359 static inline __u16 ynl_attr_get_u16(const struct nlattr *attr)
360 {
361 	return *(__u16 *)ynl_attr_data(attr);
362 }
363 
364 static inline __u32 ynl_attr_get_u32(const struct nlattr *attr)
365 {
366 	return *(__u32 *)ynl_attr_data(attr);
367 }
368 
369 static inline __u64 ynl_attr_get_u64(const struct nlattr *attr)
370 {
371 	__u64 tmp;
372 
373 	memcpy(&tmp, (unsigned char *)(attr + 1), sizeof(tmp));
374 	return tmp;
375 }
376 
377 static inline void
378 ynl_attr_put_s8(struct nlmsghdr *nlh, unsigned int attr_type, __s8 value)
379 {
380 	ynl_attr_put(nlh, attr_type, &value, sizeof(value));
381 }
382 
383 static inline void
384 ynl_attr_put_s16(struct nlmsghdr *nlh, unsigned int attr_type, __s16 value)
385 {
386 	ynl_attr_put(nlh, attr_type, &value, sizeof(value));
387 }
388 
389 static inline void
390 ynl_attr_put_s32(struct nlmsghdr *nlh, unsigned int attr_type, __s32 value)
391 {
392 	ynl_attr_put(nlh, attr_type, &value, sizeof(value));
393 }
394 
395 static inline void
396 ynl_attr_put_s64(struct nlmsghdr *nlh, unsigned int attr_type, __s64 value)
397 {
398 	ynl_attr_put(nlh, attr_type, &value, sizeof(value));
399 }
400 
401 static inline void
402 ynl_attr_put_u8(struct nlmsghdr *nlh, unsigned int attr_type, __u8 value)
403 {
404 	ynl_attr_put(nlh, attr_type, &value, sizeof(value));
405 }
406 
407 static inline void
408 ynl_attr_put_u16(struct nlmsghdr *nlh, unsigned int attr_type, __u16 value)
409 {
410 	ynl_attr_put(nlh, attr_type, &value, sizeof(value));
411 }
412 
413 static inline void
414 ynl_attr_put_u32(struct nlmsghdr *nlh, unsigned int attr_type, __u32 value)
415 {
416 	ynl_attr_put(nlh, attr_type, &value, sizeof(value));
417 }
418 
419 static inline void
420 ynl_attr_put_u64(struct nlmsghdr *nlh, unsigned int attr_type, __u64 value)
421 {
422 	ynl_attr_put(nlh, attr_type, &value, sizeof(value));
423 }
424 
425 static inline __u64 ynl_attr_get_uint(const struct nlattr *attr)
426 {
427 	switch (ynl_attr_data_len(attr)) {
428 	case 4:
429 		return ynl_attr_get_u32(attr);
430 	case 8:
431 		return ynl_attr_get_u64(attr);
432 	default:
433 		return 0;
434 	}
435 }
436 
437 static inline __s64 ynl_attr_get_sint(const struct nlattr *attr)
438 {
439 	switch (ynl_attr_data_len(attr)) {
440 	case 4:
441 		return ynl_attr_get_s32(attr);
442 	case 8:
443 		return ynl_attr_get_s64(attr);
444 	default:
445 		return 0;
446 	}
447 }
448 
449 static inline void
450 ynl_attr_put_uint(struct nlmsghdr *nlh, __u16 type, __u64 data)
451 {
452 	if ((__u32)data == (__u64)data)
453 		ynl_attr_put_u32(nlh, type, data);
454 	else
455 		ynl_attr_put_u64(nlh, type, data);
456 }
457 
458 static inline void
459 ynl_attr_put_sint(struct nlmsghdr *nlh, __u16 type, __s64 data)
460 {
461 	if ((__s32)data == (__s64)data)
462 		ynl_attr_put_s32(nlh, type, data);
463 	else
464 		ynl_attr_put_s64(nlh, type, data);
465 }
466 #endif
467