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