xref: /linux/tools/net/ynl/lib/ynl-priv.h (revision 07fdad3a93756b872da7b53647715c48d0f4a2d0)
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_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 
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 
158 static inline unsigned int ynl_nlmsg_data_len(const struct nlmsghdr *nlh)
159 {
160 	return nlh->nlmsg_len - NLMSG_HDRLEN;
161 }
162 
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 *
169 ynl_nlmsg_data_offset(const struct nlmsghdr *nlh, unsigned int offset)
170 {
171 	return (unsigned char *)nlh + NLMSG_HDRLEN + offset;
172 }
173 
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 *
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 
190 static inline unsigned int ynl_attr_type(const struct nlattr *attr)
191 {
192 	return attr->nla_type & NLA_TYPE_MASK;
193 }
194 
195 static inline unsigned int ynl_attr_data_len(const struct nlattr *attr)
196 {
197 	return attr->nla_len - NLA_HDRLEN;
198 }
199 
200 static inline void *ynl_attr_data(const struct nlattr *attr)
201 {
202 	return (unsigned char *)attr + NLA_HDRLEN;
203 }
204 
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 *
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 *
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 *
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
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 *
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
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
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
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);
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 + NLA_ALIGN(len);
325 
326 	nlh->nlmsg_len += NLMSG_ALIGN(attr->nla_len);
327 }
328 
329 static inline const char *ynl_attr_get_str(const struct nlattr *attr)
330 {
331 	return (const char *)ynl_attr_data(attr);
332 }
333 
334 static inline __s8 ynl_attr_get_s8(const struct nlattr *attr)
335 {
336 	return *(__s8 *)ynl_attr_data(attr);
337 }
338 
339 static inline __s16 ynl_attr_get_s16(const struct nlattr *attr)
340 {
341 	return *(__s16 *)ynl_attr_data(attr);
342 }
343 
344 static inline __s32 ynl_attr_get_s32(const struct nlattr *attr)
345 {
346 	return *(__s32 *)ynl_attr_data(attr);
347 }
348 
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 
357 static inline __u8 ynl_attr_get_u8(const struct nlattr *attr)
358 {
359 	return *(__u8 *)ynl_attr_data(attr);
360 }
361 
362 static inline __u16 ynl_attr_get_u16(const struct nlattr *attr)
363 {
364 	return *(__u16 *)ynl_attr_data(attr);
365 }
366 
367 static inline __u32 ynl_attr_get_u32(const struct nlattr *attr)
368 {
369 	return *(__u32 *)ynl_attr_data(attr);
370 }
371 
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
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
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
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
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
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
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
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
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 
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 
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
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
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 
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