xref: /linux/tools/net/ynl/lib/ynl.c (revision 4e94ddfe2aab72139acb8d5372fac9e6c3f3e383)
1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2 #include <errno.h>
3 #include <poll.h>
4 #include <string.h>
5 #include <stdlib.h>
6 #include <linux/types.h>
7 
8 #include <libmnl/libmnl.h>
9 #include <linux/genetlink.h>
10 
11 #include "ynl.h"
12 
13 #define ARRAY_SIZE(arr)		(sizeof(arr) / sizeof(*arr))
14 
15 #define __yerr_msg(yse, _msg...)					\
16 	({								\
17 		struct ynl_error *_yse = (yse);				\
18 									\
19 		if (_yse) {						\
20 			snprintf(_yse->msg, sizeof(_yse->msg) - 1,  _msg); \
21 			_yse->msg[sizeof(_yse->msg) - 1] = 0;		\
22 		}							\
23 	})
24 
25 #define __yerr_code(yse, _code...)		\
26 	({					\
27 		struct ynl_error *_yse = (yse);	\
28 						\
29 		if (_yse) {			\
30 			_yse->code = _code;	\
31 		}				\
32 	})
33 
34 #define __yerr(yse, _code, _msg...)		\
35 	({					\
36 		__yerr_msg(yse, _msg);		\
37 		__yerr_code(yse, _code);	\
38 	})
39 
40 #define __perr(yse, _msg)		__yerr(yse, errno, _msg)
41 
42 #define yerr_msg(_ys, _msg...)		__yerr_msg(&(_ys)->err, _msg)
43 #define yerr(_ys, _code, _msg...)	__yerr(&(_ys)->err, _code, _msg)
44 #define perr(_ys, _msg)			__yerr(&(_ys)->err, errno, _msg)
45 
46 /* -- Netlink boiler plate */
47 static int
48 ynl_err_walk_report_one(struct ynl_policy_nest *policy, unsigned int type,
49 			char *str, int str_sz, int *n)
50 {
51 	if (!policy) {
52 		if (*n < str_sz)
53 			*n += snprintf(str, str_sz, "!policy");
54 		return 1;
55 	}
56 
57 	if (type > policy->max_attr) {
58 		if (*n < str_sz)
59 			*n += snprintf(str, str_sz, "!oob");
60 		return 1;
61 	}
62 
63 	if (!policy->table[type].name) {
64 		if (*n < str_sz)
65 			*n += snprintf(str, str_sz, "!name");
66 		return 1;
67 	}
68 
69 	if (*n < str_sz)
70 		*n += snprintf(str, str_sz - *n,
71 			       ".%s", policy->table[type].name);
72 	return 0;
73 }
74 
75 static int
76 ynl_err_walk(struct ynl_sock *ys, void *start, void *end, unsigned int off,
77 	     struct ynl_policy_nest *policy, char *str, int str_sz,
78 	     struct ynl_policy_nest **nest_pol)
79 {
80 	unsigned int astart_off, aend_off;
81 	const struct nlattr *attr;
82 	unsigned int data_len;
83 	unsigned int type;
84 	bool found = false;
85 	int n = 0;
86 
87 	if (!policy) {
88 		if (n < str_sz)
89 			n += snprintf(str, str_sz, "!policy");
90 		return n;
91 	}
92 
93 	data_len = end - start;
94 
95 	mnl_attr_for_each_payload(start, data_len) {
96 		astart_off = (char *)attr - (char *)start;
97 		aend_off = astart_off + mnl_attr_get_payload_len(attr);
98 		if (aend_off <= off)
99 			continue;
100 
101 		found = true;
102 		break;
103 	}
104 	if (!found)
105 		return 0;
106 
107 	off -= astart_off;
108 
109 	type = mnl_attr_get_type(attr);
110 
111 	if (ynl_err_walk_report_one(policy, type, str, str_sz, &n))
112 		return n;
113 
114 	if (!off) {
115 		if (nest_pol)
116 			*nest_pol = policy->table[type].nest;
117 		return n;
118 	}
119 
120 	if (!policy->table[type].nest) {
121 		if (n < str_sz)
122 			n += snprintf(str, str_sz, "!nest");
123 		return n;
124 	}
125 
126 	off -= sizeof(struct nlattr);
127 	start =  mnl_attr_get_payload(attr);
128 	end = start + mnl_attr_get_payload_len(attr);
129 
130 	return n + ynl_err_walk(ys, start, end, off, policy->table[type].nest,
131 				&str[n], str_sz - n, nest_pol);
132 }
133 
134 #define NLMSGERR_ATTR_MISS_TYPE (NLMSGERR_ATTR_POLICY + 1)
135 #define NLMSGERR_ATTR_MISS_NEST (NLMSGERR_ATTR_POLICY + 2)
136 #define NLMSGERR_ATTR_MAX (NLMSGERR_ATTR_MAX + 2)
137 
138 static int
139 ynl_ext_ack_check(struct ynl_sock *ys, const struct nlmsghdr *nlh,
140 		  unsigned int hlen)
141 {
142 	const struct nlattr *tb[NLMSGERR_ATTR_MAX + 1] = {};
143 	char miss_attr[sizeof(ys->err.msg)];
144 	char bad_attr[sizeof(ys->err.msg)];
145 	const struct nlattr *attr;
146 	const char *str = NULL;
147 
148 	if (!(nlh->nlmsg_flags & NLM_F_ACK_TLVS))
149 		return MNL_CB_OK;
150 
151 	mnl_attr_for_each(attr, nlh, hlen) {
152 		unsigned int len, type;
153 
154 		len = mnl_attr_get_payload_len(attr);
155 		type = mnl_attr_get_type(attr);
156 
157 		if (type > NLMSGERR_ATTR_MAX)
158 			continue;
159 
160 		tb[type] = attr;
161 
162 		switch (type) {
163 		case NLMSGERR_ATTR_OFFS:
164 		case NLMSGERR_ATTR_MISS_TYPE:
165 		case NLMSGERR_ATTR_MISS_NEST:
166 			if (len != sizeof(__u32))
167 				return MNL_CB_ERROR;
168 			break;
169 		case NLMSGERR_ATTR_MSG:
170 			str = mnl_attr_get_payload(attr);
171 			if (str[len - 1])
172 				return MNL_CB_ERROR;
173 			break;
174 		default:
175 			break;
176 		}
177 	}
178 
179 	bad_attr[0] = '\0';
180 	miss_attr[0] = '\0';
181 
182 	if (tb[NLMSGERR_ATTR_OFFS]) {
183 		unsigned int n, off;
184 		void *start, *end;
185 
186 		ys->err.attr_offs = mnl_attr_get_u32(tb[NLMSGERR_ATTR_OFFS]);
187 
188 		n = snprintf(bad_attr, sizeof(bad_attr), "%sbad attribute: ",
189 			     str ? " (" : "");
190 
191 		start = mnl_nlmsg_get_payload_offset(ys->nlh,
192 						     sizeof(struct genlmsghdr));
193 		end = mnl_nlmsg_get_payload_tail(ys->nlh);
194 
195 		off = ys->err.attr_offs;
196 		off -= sizeof(struct nlmsghdr);
197 		off -= sizeof(struct genlmsghdr);
198 
199 		n += ynl_err_walk(ys, start, end, off, ys->req_policy,
200 				  &bad_attr[n], sizeof(bad_attr) - n, NULL);
201 
202 		if (n >= sizeof(bad_attr))
203 			n = sizeof(bad_attr) - 1;
204 		bad_attr[n] = '\0';
205 	}
206 	if (tb[NLMSGERR_ATTR_MISS_TYPE]) {
207 		struct ynl_policy_nest *nest_pol = NULL;
208 		unsigned int n, off, type;
209 		void *start, *end;
210 		int n2;
211 
212 		type = mnl_attr_get_u32(tb[NLMSGERR_ATTR_MISS_TYPE]);
213 
214 		n = snprintf(miss_attr, sizeof(miss_attr), "%smissing attribute: ",
215 			     bad_attr[0] ? ", " : (str ? " (" : ""));
216 
217 		start = mnl_nlmsg_get_payload_offset(ys->nlh,
218 						     sizeof(struct genlmsghdr));
219 		end = mnl_nlmsg_get_payload_tail(ys->nlh);
220 
221 		nest_pol = ys->req_policy;
222 		if (tb[NLMSGERR_ATTR_MISS_NEST]) {
223 			off = mnl_attr_get_u32(tb[NLMSGERR_ATTR_MISS_NEST]);
224 			off -= sizeof(struct nlmsghdr);
225 			off -= sizeof(struct genlmsghdr);
226 
227 			n += ynl_err_walk(ys, start, end, off, ys->req_policy,
228 					  &miss_attr[n], sizeof(miss_attr) - n,
229 					  &nest_pol);
230 		}
231 
232 		n2 = 0;
233 		ynl_err_walk_report_one(nest_pol, type, &miss_attr[n],
234 					sizeof(miss_attr) - n, &n2);
235 		n += n2;
236 
237 		if (n >= sizeof(miss_attr))
238 			n = sizeof(miss_attr) - 1;
239 		miss_attr[n] = '\0';
240 	}
241 
242 	/* Implicitly depend on ys->err.code already set */
243 	if (str)
244 		yerr_msg(ys, "Kernel %s: '%s'%s%s%s",
245 			 ys->err.code ? "error" : "warning",
246 			 str, bad_attr, miss_attr,
247 			 bad_attr[0] || miss_attr[0] ? ")" : "");
248 	else if (bad_attr[0] || miss_attr[0])
249 		yerr_msg(ys, "Kernel %s: %s%s",
250 			 ys->err.code ? "error" : "warning",
251 			 bad_attr, miss_attr);
252 
253 	return MNL_CB_OK;
254 }
255 
256 static int ynl_cb_error(const struct nlmsghdr *nlh, void *data)
257 {
258 	const struct nlmsgerr *err = mnl_nlmsg_get_payload(nlh);
259 	struct ynl_parse_arg *yarg = data;
260 	unsigned int hlen;
261 	int code;
262 
263 	code = err->error >= 0 ? err->error : -err->error;
264 	yarg->ys->err.code = code;
265 	errno = code;
266 
267 	hlen = sizeof(*err);
268 	if (!(nlh->nlmsg_flags & NLM_F_CAPPED))
269 		hlen += mnl_nlmsg_get_payload_len(&err->msg);
270 
271 	ynl_ext_ack_check(yarg->ys, nlh, hlen);
272 
273 	return code ? MNL_CB_ERROR : MNL_CB_STOP;
274 }
275 
276 static int ynl_cb_done(const struct nlmsghdr *nlh, void *data)
277 {
278 	struct ynl_parse_arg *yarg = data;
279 	int err;
280 
281 	err = *(int *)NLMSG_DATA(nlh);
282 	if (err < 0) {
283 		yarg->ys->err.code = -err;
284 		errno = -err;
285 
286 		ynl_ext_ack_check(yarg->ys, nlh, sizeof(int));
287 
288 		return MNL_CB_ERROR;
289 	}
290 	return MNL_CB_STOP;
291 }
292 
293 static int ynl_cb_noop(const struct nlmsghdr *nlh, void *data)
294 {
295 	return MNL_CB_OK;
296 }
297 
298 mnl_cb_t ynl_cb_array[NLMSG_MIN_TYPE] = {
299 	[NLMSG_NOOP]	= ynl_cb_noop,
300 	[NLMSG_ERROR]	= ynl_cb_error,
301 	[NLMSG_DONE]	= ynl_cb_done,
302 	[NLMSG_OVERRUN]	= ynl_cb_noop,
303 };
304 
305 /* Attribute validation */
306 
307 int ynl_attr_validate(struct ynl_parse_arg *yarg, const struct nlattr *attr)
308 {
309 	struct ynl_policy_attr *policy;
310 	unsigned int type, len;
311 	unsigned char *data;
312 
313 	data = mnl_attr_get_payload(attr);
314 	len = mnl_attr_get_payload_len(attr);
315 	type = mnl_attr_get_type(attr);
316 	if (type > yarg->rsp_policy->max_attr) {
317 		yerr(yarg->ys, YNL_ERROR_INTERNAL,
318 		     "Internal error, validating unknown attribute");
319 		return -1;
320 	}
321 
322 	policy = &yarg->rsp_policy->table[type];
323 
324 	switch (policy->type) {
325 	case YNL_PT_REJECT:
326 		yerr(yarg->ys, YNL_ERROR_ATTR_INVALID,
327 		     "Rejected attribute (%s)", policy->name);
328 		return -1;
329 	case YNL_PT_IGNORE:
330 		break;
331 	case YNL_PT_U8:
332 		if (len == sizeof(__u8))
333 			break;
334 		yerr(yarg->ys, YNL_ERROR_ATTR_INVALID,
335 		     "Invalid attribute (u8 %s)", policy->name);
336 		return -1;
337 	case YNL_PT_U16:
338 		if (len == sizeof(__u16))
339 			break;
340 		yerr(yarg->ys, YNL_ERROR_ATTR_INVALID,
341 		     "Invalid attribute (u16 %s)", policy->name);
342 		return -1;
343 	case YNL_PT_U32:
344 		if (len == sizeof(__u32))
345 			break;
346 		yerr(yarg->ys, YNL_ERROR_ATTR_INVALID,
347 		     "Invalid attribute (u32 %s)", policy->name);
348 		return -1;
349 	case YNL_PT_U64:
350 		if (len == sizeof(__u64))
351 			break;
352 		yerr(yarg->ys, YNL_ERROR_ATTR_INVALID,
353 		     "Invalid attribute (u64 %s)", policy->name);
354 		return -1;
355 	case YNL_PT_UINT:
356 		if (len == sizeof(__u32) || len == sizeof(__u64))
357 			break;
358 		yerr(yarg->ys, YNL_ERROR_ATTR_INVALID,
359 		     "Invalid attribute (uint %s)", policy->name);
360 		return -1;
361 	case YNL_PT_FLAG:
362 		/* Let flags grow into real attrs, why not.. */
363 		break;
364 	case YNL_PT_NEST:
365 		if (!len || len >= sizeof(*attr))
366 			break;
367 		yerr(yarg->ys, YNL_ERROR_ATTR_INVALID,
368 		     "Invalid attribute (nest %s)", policy->name);
369 		return -1;
370 	case YNL_PT_BINARY:
371 		if (!policy->len || len == policy->len)
372 			break;
373 		yerr(yarg->ys, YNL_ERROR_ATTR_INVALID,
374 		     "Invalid attribute (binary %s)", policy->name);
375 		return -1;
376 	case YNL_PT_NUL_STR:
377 		if ((!policy->len || len <= policy->len) && !data[len - 1])
378 			break;
379 		yerr(yarg->ys, YNL_ERROR_ATTR_INVALID,
380 		     "Invalid attribute (string %s)", policy->name);
381 		return -1;
382 	case YNL_PT_BITFIELD32:
383 		if (len == sizeof(struct nla_bitfield32))
384 			break;
385 		yerr(yarg->ys, YNL_ERROR_ATTR_INVALID,
386 		     "Invalid attribute (bitfield32 %s)", policy->name);
387 		return -1;
388 	default:
389 		yerr(yarg->ys, YNL_ERROR_ATTR_INVALID,
390 		     "Invalid attribute (unknown %s)", policy->name);
391 		return -1;
392 	}
393 
394 	return 0;
395 }
396 
397 /* Generic code */
398 
399 static void ynl_err_reset(struct ynl_sock *ys)
400 {
401 	ys->err.code = 0;
402 	ys->err.attr_offs = 0;
403 	ys->err.msg[0] = 0;
404 }
405 
406 struct nlmsghdr *ynl_msg_start(struct ynl_sock *ys, __u32 id, __u16 flags)
407 {
408 	struct nlmsghdr *nlh;
409 
410 	ynl_err_reset(ys);
411 
412 	nlh = ys->nlh = mnl_nlmsg_put_header(ys->tx_buf);
413 	nlh->nlmsg_type	= id;
414 	nlh->nlmsg_flags = flags;
415 	nlh->nlmsg_seq = ++ys->seq;
416 
417 	return nlh;
418 }
419 
420 struct nlmsghdr *
421 ynl_gemsg_start(struct ynl_sock *ys, __u32 id, __u16 flags,
422 		__u8 cmd, __u8 version)
423 {
424 	struct genlmsghdr gehdr;
425 	struct nlmsghdr *nlh;
426 	void *data;
427 
428 	nlh = ynl_msg_start(ys, id, flags);
429 
430 	memset(&gehdr, 0, sizeof(gehdr));
431 	gehdr.cmd = cmd;
432 	gehdr.version = version;
433 
434 	data = mnl_nlmsg_put_extra_header(nlh, sizeof(gehdr));
435 	memcpy(data, &gehdr, sizeof(gehdr));
436 
437 	return nlh;
438 }
439 
440 void ynl_msg_start_req(struct ynl_sock *ys, __u32 id)
441 {
442 	ynl_msg_start(ys, id, NLM_F_REQUEST | NLM_F_ACK);
443 }
444 
445 void ynl_msg_start_dump(struct ynl_sock *ys, __u32 id)
446 {
447 	ynl_msg_start(ys, id, NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP);
448 }
449 
450 struct nlmsghdr *
451 ynl_gemsg_start_req(struct ynl_sock *ys, __u32 id, __u8 cmd, __u8 version)
452 {
453 	return ynl_gemsg_start(ys, id, NLM_F_REQUEST | NLM_F_ACK, cmd, version);
454 }
455 
456 struct nlmsghdr *
457 ynl_gemsg_start_dump(struct ynl_sock *ys, __u32 id, __u8 cmd, __u8 version)
458 {
459 	return ynl_gemsg_start(ys, id, NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP,
460 			       cmd, version);
461 }
462 
463 int ynl_recv_ack(struct ynl_sock *ys, int ret)
464 {
465 	if (!ret) {
466 		yerr(ys, YNL_ERROR_EXPECT_ACK,
467 		     "Expecting an ACK but nothing received");
468 		return -1;
469 	}
470 
471 	ret = mnl_socket_recvfrom(ys->sock, ys->rx_buf, MNL_SOCKET_BUFFER_SIZE);
472 	if (ret < 0) {
473 		perr(ys, "Socket receive failed");
474 		return ret;
475 	}
476 	return mnl_cb_run(ys->rx_buf, ret, ys->seq, ys->portid,
477 			  ynl_cb_null, ys);
478 }
479 
480 int ynl_cb_null(const struct nlmsghdr *nlh, void *data)
481 {
482 	struct ynl_parse_arg *yarg = data;
483 
484 	yerr(yarg->ys, YNL_ERROR_UNEXPECT_MSG,
485 	     "Received a message when none were expected");
486 
487 	return MNL_CB_ERROR;
488 }
489 
490 /* Init/fini and genetlink boiler plate */
491 static int
492 ynl_get_family_info_mcast(struct ynl_sock *ys, const struct nlattr *mcasts)
493 {
494 	const struct nlattr *entry, *attr;
495 	unsigned int i;
496 
497 	mnl_attr_for_each_nested(attr, mcasts)
498 		ys->n_mcast_groups++;
499 
500 	if (!ys->n_mcast_groups)
501 		return 0;
502 
503 	ys->mcast_groups = calloc(ys->n_mcast_groups,
504 				  sizeof(*ys->mcast_groups));
505 	if (!ys->mcast_groups)
506 		return MNL_CB_ERROR;
507 
508 	i = 0;
509 	mnl_attr_for_each_nested(entry, mcasts) {
510 		mnl_attr_for_each_nested(attr, entry) {
511 			if (mnl_attr_get_type(attr) == CTRL_ATTR_MCAST_GRP_ID)
512 				ys->mcast_groups[i].id = mnl_attr_get_u32(attr);
513 			if (mnl_attr_get_type(attr) == CTRL_ATTR_MCAST_GRP_NAME) {
514 				strncpy(ys->mcast_groups[i].name,
515 					mnl_attr_get_str(attr),
516 					GENL_NAMSIZ - 1);
517 				ys->mcast_groups[i].name[GENL_NAMSIZ - 1] = 0;
518 			}
519 		}
520 	}
521 
522 	return 0;
523 }
524 
525 static int ynl_get_family_info_cb(const struct nlmsghdr *nlh, void *data)
526 {
527 	struct ynl_parse_arg *yarg = data;
528 	struct ynl_sock *ys = yarg->ys;
529 	const struct nlattr *attr;
530 	bool found_id = true;
531 
532 	mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) {
533 		if (mnl_attr_get_type(attr) == CTRL_ATTR_MCAST_GROUPS)
534 			if (ynl_get_family_info_mcast(ys, attr))
535 				return MNL_CB_ERROR;
536 
537 		if (mnl_attr_get_type(attr) != CTRL_ATTR_FAMILY_ID)
538 			continue;
539 
540 		if (mnl_attr_get_payload_len(attr) != sizeof(__u16)) {
541 			yerr(ys, YNL_ERROR_ATTR_INVALID, "Invalid family ID");
542 			return MNL_CB_ERROR;
543 		}
544 
545 		ys->family_id = mnl_attr_get_u16(attr);
546 		found_id = true;
547 	}
548 
549 	if (!found_id) {
550 		yerr(ys, YNL_ERROR_ATTR_MISSING, "Family ID missing");
551 		return MNL_CB_ERROR;
552 	}
553 	return MNL_CB_OK;
554 }
555 
556 static int ynl_sock_read_family(struct ynl_sock *ys, const char *family_name)
557 {
558 	struct ynl_parse_arg yarg = { .ys = ys, };
559 	struct nlmsghdr *nlh;
560 	int err;
561 
562 	nlh = ynl_gemsg_start_req(ys, GENL_ID_CTRL, CTRL_CMD_GETFAMILY, 1);
563 	mnl_attr_put_strz(nlh, CTRL_ATTR_FAMILY_NAME, family_name);
564 
565 	err = mnl_socket_sendto(ys->sock, nlh, nlh->nlmsg_len);
566 	if (err < 0) {
567 		perr(ys, "failed to request socket family info");
568 		return err;
569 	}
570 
571 	err = mnl_socket_recvfrom(ys->sock, ys->rx_buf, MNL_SOCKET_BUFFER_SIZE);
572 	if (err <= 0) {
573 		perr(ys, "failed to receive the socket family info");
574 		return err;
575 	}
576 	err = mnl_cb_run2(ys->rx_buf, err, ys->seq, ys->portid,
577 			  ynl_get_family_info_cb, &yarg,
578 			  ynl_cb_array, ARRAY_SIZE(ynl_cb_array));
579 	if (err < 0) {
580 		free(ys->mcast_groups);
581 		perr(ys, "failed to receive the socket family info - no such family?");
582 		return err;
583 	}
584 
585 	return ynl_recv_ack(ys, err);
586 }
587 
588 struct ynl_sock *
589 ynl_sock_create(const struct ynl_family *yf, struct ynl_error *yse)
590 {
591 	struct ynl_sock *ys;
592 	int one = 1;
593 
594 	ys = malloc(sizeof(*ys) + 2 * MNL_SOCKET_BUFFER_SIZE);
595 	if (!ys)
596 		return NULL;
597 	memset(ys, 0, sizeof(*ys));
598 
599 	ys->family = yf;
600 	ys->tx_buf = &ys->raw_buf[0];
601 	ys->rx_buf = &ys->raw_buf[MNL_SOCKET_BUFFER_SIZE];
602 	ys->ntf_last_next = &ys->ntf_first;
603 
604 	ys->sock = mnl_socket_open(NETLINK_GENERIC);
605 	if (!ys->sock) {
606 		__perr(yse, "failed to create a netlink socket");
607 		goto err_free_sock;
608 	}
609 
610 	if (mnl_socket_setsockopt(ys->sock, NETLINK_CAP_ACK,
611 				  &one, sizeof(one))) {
612 		__perr(yse, "failed to enable netlink ACK");
613 		goto err_close_sock;
614 	}
615 	if (mnl_socket_setsockopt(ys->sock, NETLINK_EXT_ACK,
616 				  &one, sizeof(one))) {
617 		__perr(yse, "failed to enable netlink ext ACK");
618 		goto err_close_sock;
619 	}
620 
621 	ys->seq = random();
622 	ys->portid = mnl_socket_get_portid(ys->sock);
623 
624 	if (ynl_sock_read_family(ys, yf->name)) {
625 		if (yse)
626 			memcpy(yse, &ys->err, sizeof(*yse));
627 		goto err_close_sock;
628 	}
629 
630 	return ys;
631 
632 err_close_sock:
633 	mnl_socket_close(ys->sock);
634 err_free_sock:
635 	free(ys);
636 	return NULL;
637 }
638 
639 void ynl_sock_destroy(struct ynl_sock *ys)
640 {
641 	struct ynl_ntf_base_type *ntf;
642 
643 	mnl_socket_close(ys->sock);
644 	while ((ntf = ynl_ntf_dequeue(ys)))
645 		ynl_ntf_free(ntf);
646 	free(ys->mcast_groups);
647 	free(ys);
648 }
649 
650 /* YNL multicast handling */
651 
652 void ynl_ntf_free(struct ynl_ntf_base_type *ntf)
653 {
654 	ntf->free(ntf);
655 }
656 
657 int ynl_subscribe(struct ynl_sock *ys, const char *grp_name)
658 {
659 	unsigned int i;
660 	int err;
661 
662 	for (i = 0; i < ys->n_mcast_groups; i++)
663 		if (!strcmp(ys->mcast_groups[i].name, grp_name))
664 			break;
665 	if (i == ys->n_mcast_groups) {
666 		yerr(ys, ENOENT, "Multicast group '%s' not found", grp_name);
667 		return -1;
668 	}
669 
670 	err = mnl_socket_setsockopt(ys->sock, NETLINK_ADD_MEMBERSHIP,
671 				    &ys->mcast_groups[i].id,
672 				    sizeof(ys->mcast_groups[i].id));
673 	if (err < 0) {
674 		perr(ys, "Subscribing to multicast group failed");
675 		return -1;
676 	}
677 
678 	return 0;
679 }
680 
681 int ynl_socket_get_fd(struct ynl_sock *ys)
682 {
683 	return mnl_socket_get_fd(ys->sock);
684 }
685 
686 struct ynl_ntf_base_type *ynl_ntf_dequeue(struct ynl_sock *ys)
687 {
688 	struct ynl_ntf_base_type *ntf;
689 
690 	if (!ynl_has_ntf(ys))
691 		return NULL;
692 
693 	ntf = ys->ntf_first;
694 	ys->ntf_first = ntf->next;
695 	if (ys->ntf_last_next == &ntf->next)
696 		ys->ntf_last_next = &ys->ntf_first;
697 
698 	return ntf;
699 }
700 
701 static int ynl_ntf_parse(struct ynl_sock *ys, const struct nlmsghdr *nlh)
702 {
703 	struct ynl_parse_arg yarg = { .ys = ys, };
704 	const struct ynl_ntf_info *info;
705 	struct ynl_ntf_base_type *rsp;
706 	struct genlmsghdr *gehdr;
707 	int ret;
708 
709 	gehdr = mnl_nlmsg_get_payload(nlh);
710 	if (gehdr->cmd >= ys->family->ntf_info_size)
711 		return MNL_CB_ERROR;
712 	info = &ys->family->ntf_info[gehdr->cmd];
713 	if (!info->cb)
714 		return MNL_CB_ERROR;
715 
716 	rsp = calloc(1, info->alloc_sz);
717 	rsp->free = info->free;
718 	yarg.data = rsp->data;
719 	yarg.rsp_policy = info->policy;
720 
721 	ret = info->cb(nlh, &yarg);
722 	if (ret <= MNL_CB_STOP)
723 		goto err_free;
724 
725 	rsp->family = nlh->nlmsg_type;
726 	rsp->cmd = gehdr->cmd;
727 
728 	*ys->ntf_last_next = rsp;
729 	ys->ntf_last_next = &rsp->next;
730 
731 	return MNL_CB_OK;
732 
733 err_free:
734 	info->free(rsp);
735 	return MNL_CB_ERROR;
736 }
737 
738 static int ynl_ntf_trampoline(const struct nlmsghdr *nlh, void *data)
739 {
740 	return ynl_ntf_parse((struct ynl_sock *)data, nlh);
741 }
742 
743 int ynl_ntf_check(struct ynl_sock *ys)
744 {
745 	ssize_t len;
746 	int err;
747 
748 	do {
749 		/* libmnl doesn't let us pass flags to the recv to make
750 		 * it non-blocking so we need to poll() or peek() :|
751 		 */
752 		struct pollfd pfd = { };
753 
754 		pfd.fd = mnl_socket_get_fd(ys->sock);
755 		pfd.events = POLLIN;
756 		err = poll(&pfd, 1, 1);
757 		if (err < 1)
758 			return err;
759 
760 		len = mnl_socket_recvfrom(ys->sock, ys->rx_buf,
761 					  MNL_SOCKET_BUFFER_SIZE);
762 		if (len < 0)
763 			return len;
764 
765 		err = mnl_cb_run2(ys->rx_buf, len, ys->seq, ys->portid,
766 				  ynl_ntf_trampoline, ys,
767 				  ynl_cb_array, NLMSG_MIN_TYPE);
768 		if (err < 0)
769 			return err;
770 	} while (err > 0);
771 
772 	return 0;
773 }
774 
775 /* YNL specific helpers used by the auto-generated code */
776 
777 struct ynl_dump_list_type *YNL_LIST_END = (void *)(0xb4d123);
778 
779 void ynl_error_unknown_notification(struct ynl_sock *ys, __u8 cmd)
780 {
781 	yerr(ys, YNL_ERROR_UNKNOWN_NTF,
782 	     "Unknown notification message type '%d'", cmd);
783 }
784 
785 int ynl_error_parse(struct ynl_parse_arg *yarg, const char *msg)
786 {
787 	yerr(yarg->ys, YNL_ERROR_INV_RESP, "Error parsing response: %s", msg);
788 	return MNL_CB_ERROR;
789 }
790 
791 static int
792 ynl_check_alien(struct ynl_sock *ys, const struct nlmsghdr *nlh, __u32 rsp_cmd)
793 {
794 	struct genlmsghdr *gehdr;
795 
796 	if (mnl_nlmsg_get_payload_len(nlh) < sizeof(*gehdr)) {
797 		yerr(ys, YNL_ERROR_INV_RESP,
798 		     "Kernel responded with truncated message");
799 		return -1;
800 	}
801 
802 	gehdr = mnl_nlmsg_get_payload(nlh);
803 	if (gehdr->cmd != rsp_cmd)
804 		return ynl_ntf_parse(ys, nlh);
805 
806 	return 0;
807 }
808 
809 static int ynl_req_trampoline(const struct nlmsghdr *nlh, void *data)
810 {
811 	struct ynl_req_state *yrs = data;
812 	int ret;
813 
814 	ret = ynl_check_alien(yrs->yarg.ys, nlh, yrs->rsp_cmd);
815 	if (ret)
816 		return ret < 0 ? MNL_CB_ERROR : MNL_CB_OK;
817 
818 	return yrs->cb(nlh, &yrs->yarg);
819 }
820 
821 int ynl_exec(struct ynl_sock *ys, struct nlmsghdr *req_nlh,
822 	     struct ynl_req_state *yrs)
823 {
824 	ssize_t len;
825 	int err;
826 
827 	err = mnl_socket_sendto(ys->sock, req_nlh, req_nlh->nlmsg_len);
828 	if (err < 0)
829 		return err;
830 
831 	do {
832 		len = mnl_socket_recvfrom(ys->sock, ys->rx_buf,
833 					  MNL_SOCKET_BUFFER_SIZE);
834 		if (len < 0)
835 			return len;
836 
837 		err = mnl_cb_run2(ys->rx_buf, len, ys->seq, ys->portid,
838 				  ynl_req_trampoline, yrs,
839 				  ynl_cb_array, NLMSG_MIN_TYPE);
840 		if (err < 0)
841 			return err;
842 	} while (err > 0);
843 
844 	return 0;
845 }
846 
847 static int ynl_dump_trampoline(const struct nlmsghdr *nlh, void *data)
848 {
849 	struct ynl_dump_state *ds = data;
850 	struct ynl_dump_list_type *obj;
851 	struct ynl_parse_arg yarg = {};
852 	int ret;
853 
854 	ret = ynl_check_alien(ds->ys, nlh, ds->rsp_cmd);
855 	if (ret)
856 		return ret < 0 ? MNL_CB_ERROR : MNL_CB_OK;
857 
858 	obj = calloc(1, ds->alloc_sz);
859 	if (!obj)
860 		return MNL_CB_ERROR;
861 
862 	if (!ds->first)
863 		ds->first = obj;
864 	if (ds->last)
865 		ds->last->next = obj;
866 	ds->last = obj;
867 
868 	yarg.ys = ds->ys;
869 	yarg.rsp_policy = ds->rsp_policy;
870 	yarg.data = &obj->data;
871 
872 	return ds->cb(nlh, &yarg);
873 }
874 
875 static void *ynl_dump_end(struct ynl_dump_state *ds)
876 {
877 	if (!ds->first)
878 		return YNL_LIST_END;
879 
880 	ds->last->next = YNL_LIST_END;
881 	return ds->first;
882 }
883 
884 int ynl_exec_dump(struct ynl_sock *ys, struct nlmsghdr *req_nlh,
885 		  struct ynl_dump_state *yds)
886 {
887 	ssize_t len;
888 	int err;
889 
890 	err = mnl_socket_sendto(ys->sock, req_nlh, req_nlh->nlmsg_len);
891 	if (err < 0)
892 		return err;
893 
894 	do {
895 		len = mnl_socket_recvfrom(ys->sock, ys->rx_buf,
896 					  MNL_SOCKET_BUFFER_SIZE);
897 		if (len < 0)
898 			goto err_close_list;
899 
900 		err = mnl_cb_run2(ys->rx_buf, len, ys->seq, ys->portid,
901 				  ynl_dump_trampoline, yds,
902 				  ynl_cb_array, NLMSG_MIN_TYPE);
903 		if (err < 0)
904 			goto err_close_list;
905 	} while (err > 0);
906 
907 	yds->first = ynl_dump_end(yds);
908 	return 0;
909 
910 err_close_list:
911 	yds->first = ynl_dump_end(yds);
912 	return -1;
913 }
914