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