drm/nouveau: consume the return of large GSP message
[drm/drm-misc.git] / tools / net / ynl / lib / ynl.c
blobe16cef160bc2cb3df7ecd076713953248dbb80f3
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>
12 #include "ynl.h"
14 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(*arr))
16 #define __yerr_msg(yse, _msg...) \
17 ({ \
18 struct ynl_error *_yse = (yse); \
20 if (_yse) { \
21 snprintf(_yse->msg, sizeof(_yse->msg) - 1, _msg); \
22 _yse->msg[sizeof(_yse->msg) - 1] = 0; \
23 } \
26 #define __yerr_code(yse, _code...) \
27 ({ \
28 struct ynl_error *_yse = (yse); \
30 if (_yse) { \
31 _yse->code = _code; \
32 } \
35 #define __yerr(yse, _code, _msg...) \
36 ({ \
37 __yerr_msg(yse, _msg); \
38 __yerr_code(yse, _code); \
41 #define __perr(yse, _msg) __yerr(yse, errno, _msg)
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)
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)
52 if (!policy) {
53 if (*n < str_sz)
54 *n += snprintf(str, str_sz, "!policy");
55 return 1;
58 if (type > policy->max_attr) {
59 if (*n < str_sz)
60 *n += snprintf(str, str_sz, "!oob");
61 return 1;
64 if (!policy->table[type].name) {
65 if (*n < str_sz)
66 *n += snprintf(str, str_sz, "!name");
67 return 1;
70 if (*n < str_sz)
71 *n += snprintf(str, str_sz - *n,
72 ".%s", policy->table[type].name);
73 return 0;
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)
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;
88 if (!policy) {
89 if (n < str_sz)
90 n += snprintf(str, str_sz, "!policy");
91 return n;
94 data_len = end - start;
96 ynl_attr_for_each_payload(start, data_len, attr) {
97 astart_off = (char *)attr - (char *)start;
98 aend_off = astart_off + ynl_attr_data_len(attr);
99 if (aend_off <= off)
100 continue;
102 found = true;
103 break;
105 if (!found)
106 return 0;
108 off -= astart_off;
110 type = ynl_attr_type(attr);
112 if (ynl_err_walk_report_one(policy, type, str, str_sz, &n))
113 return n;
115 if (!off) {
116 if (nest_pol)
117 *nest_pol = policy->table[type].nest;
118 return n;
121 if (!policy->table[type].nest) {
122 if (n < str_sz)
123 n += snprintf(str, str_sz, "!nest");
124 return n;
127 off -= sizeof(struct nlattr);
128 start = ynl_attr_data(attr);
129 end = start + ynl_attr_data_len(attr);
131 return n + ynl_err_walk(ys, start, end, off, policy->table[type].nest,
132 &str[n], str_sz - n, nest_pol);
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)
139 static int
140 ynl_ext_ack_check(struct ynl_sock *ys, const struct nlmsghdr *nlh,
141 unsigned int hlen)
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;
149 if (!(nlh->nlmsg_flags & NLM_F_ACK_TLVS)) {
150 yerr_msg(ys, "%s", strerror(ys->err.code));
151 return YNL_PARSE_CB_OK;
154 ynl_attr_for_each(attr, nlh, hlen) {
155 unsigned int len, type;
157 len = ynl_attr_data_len(attr);
158 type = ynl_attr_type(attr);
160 if (type > NLMSGERR_ATTR_MAX)
161 continue;
163 tb[type] = attr;
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;
182 bad_attr[0] = '\0';
183 miss_attr[0] = '\0';
185 if (tb[NLMSGERR_ATTR_OFFS]) {
186 unsigned int n, off;
187 void *start, *end;
189 ys->err.attr_offs = ynl_attr_get_u32(tb[NLMSGERR_ATTR_OFFS]);
191 n = snprintf(bad_attr, sizeof(bad_attr), "%sbad attribute: ",
192 str ? " (" : "");
194 start = ynl_nlmsg_data_offset(ys->nlh, ys->family->hdr_len);
195 end = ynl_nlmsg_end_addr(ys->nlh);
197 off = ys->err.attr_offs;
198 off -= sizeof(struct nlmsghdr);
199 off -= ys->family->hdr_len;
201 n += ynl_err_walk(ys, start, end, off, ys->req_policy,
202 &bad_attr[n], sizeof(bad_attr) - n, NULL);
204 if (n >= sizeof(bad_attr))
205 n = sizeof(bad_attr) - 1;
206 bad_attr[n] = '\0';
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;
214 type = ynl_attr_get_u32(tb[NLMSGERR_ATTR_MISS_TYPE]);
216 n = snprintf(miss_attr, sizeof(miss_attr), "%smissing attribute: ",
217 bad_attr[0] ? ", " : (str ? " (" : ""));
219 start = ynl_nlmsg_data_offset(ys->nlh, ys->family->hdr_len);
220 end = ynl_nlmsg_end_addr(ys->nlh);
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;
228 n += ynl_err_walk(ys, start, end, off, ys->req_policy,
229 &miss_attr[n], sizeof(miss_attr) - n,
230 &nest_pol);
233 n2 = 0;
234 ynl_err_walk_report_one(nest_pol, type, &miss_attr[n],
235 sizeof(miss_attr) - n, &n2);
236 n += n2;
238 if (n >= sizeof(miss_attr))
239 n = sizeof(miss_attr) - 1;
240 miss_attr[n] = '\0';
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));
256 return YNL_PARSE_CB_OK;
259 static int
260 ynl_cb_error(const struct nlmsghdr *nlh, struct ynl_parse_arg *yarg)
262 const struct nlmsgerr *err = ynl_nlmsg_data(nlh);
263 unsigned int hlen;
264 int code;
266 code = err->error >= 0 ? err->error : -err->error;
267 yarg->ys->err.code = code;
268 errno = code;
270 hlen = sizeof(*err);
271 if (!(nlh->nlmsg_flags & NLM_F_CAPPED))
272 hlen += ynl_nlmsg_data_len(&err->msg);
274 ynl_ext_ack_check(yarg->ys, nlh, hlen);
276 return code ? YNL_PARSE_CB_ERROR : YNL_PARSE_CB_STOP;
279 static int ynl_cb_done(const struct nlmsghdr *nlh, struct ynl_parse_arg *yarg)
281 int err;
283 err = *(int *)NLMSG_DATA(nlh);
284 if (err < 0) {
285 yarg->ys->err.code = -err;
286 errno = -err;
288 ynl_ext_ack_check(yarg->ys, nlh, sizeof(int));
290 return YNL_PARSE_CB_ERROR;
292 return YNL_PARSE_CB_STOP;
295 /* Attribute validation */
297 int ynl_attr_validate(struct ynl_parse_arg *yarg, const struct nlattr *attr)
299 const struct ynl_policy_attr *policy;
300 unsigned int type, len;
301 unsigned char *data;
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;
312 policy = &yarg->rsp_policy->table[type];
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;
384 return 0;
387 /* Generic code */
389 static void ynl_err_reset(struct ynl_sock *ys)
391 ys->err.code = 0;
392 ys->err.attr_offs = 0;
393 ys->err.msg[0] = 0;
396 struct nlmsghdr *ynl_msg_start(struct ynl_sock *ys, __u32 id, __u16 flags)
398 struct nlmsghdr *nlh;
400 ynl_err_reset(ys);
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;
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().
411 nlh->nlmsg_pid = YNL_SOCKET_BUFFER_SIZE;
413 return nlh;
416 static int ynl_msg_end(struct ynl_sock *ys, struct nlmsghdr *nlh)
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;
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;
430 nlh->nlmsg_pid = 0;
431 return 0;
434 struct nlmsghdr *
435 ynl_gemsg_start(struct ynl_sock *ys, __u32 id, __u16 flags,
436 __u8 cmd, __u8 version)
438 struct genlmsghdr gehdr;
439 struct nlmsghdr *nlh;
440 void *data;
442 nlh = ynl_msg_start(ys, id, flags);
444 memset(&gehdr, 0, sizeof(gehdr));
445 gehdr.cmd = cmd;
446 gehdr.version = version;
448 data = ynl_nlmsg_put_extra_header(nlh, sizeof(gehdr));
449 memcpy(data, &gehdr, sizeof(gehdr));
451 return nlh;
454 void ynl_msg_start_req(struct ynl_sock *ys, __u32 id)
456 ynl_msg_start(ys, id, NLM_F_REQUEST | NLM_F_ACK);
459 void ynl_msg_start_dump(struct ynl_sock *ys, __u32 id)
461 ynl_msg_start(ys, id, NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP);
464 struct nlmsghdr *
465 ynl_gemsg_start_req(struct ynl_sock *ys, __u32 id, __u8 cmd, __u8 version)
467 return ynl_gemsg_start(ys, id, NLM_F_REQUEST | NLM_F_ACK, cmd, version);
470 struct nlmsghdr *
471 ynl_gemsg_start_dump(struct ynl_sock *ys, __u32 id, __u8 cmd, __u8 version)
473 return ynl_gemsg_start(ys, id, NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP,
474 cmd, version);
477 static int ynl_cb_null(const struct nlmsghdr *nlh, struct ynl_parse_arg *yarg)
479 yerr(yarg->ys, YNL_ERROR_UNEXPECT_MSG,
480 "Received a message when none were expected");
482 return YNL_PARSE_CB_ERROR;
485 static int
486 __ynl_sock_read_msgs(struct ynl_parse_arg *yarg, ynl_parse_cb_t cb, int flags)
488 struct ynl_sock *ys = yarg->ys;
489 const struct nlmsghdr *nlh;
490 ssize_t len, rem;
491 int ret;
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;
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;
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;
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;
537 return ret;
540 static int ynl_sock_read_msgs(struct ynl_parse_arg *yarg, ynl_parse_cb_t cb)
542 return __ynl_sock_read_msgs(yarg, cb, 0);
545 static int ynl_recv_ack(struct ynl_sock *ys, int ret)
547 struct ynl_parse_arg yarg = { .ys = ys, };
549 if (!ret) {
550 yerr(ys, YNL_ERROR_EXPECT_ACK,
551 "Expecting an ACK but nothing received");
552 return -1;
555 return ynl_sock_read_msgs(&yarg, ynl_cb_null);
558 /* Init/fini and genetlink boiler plate */
559 static int
560 ynl_get_family_info_mcast(struct ynl_sock *ys, const struct nlattr *mcasts)
562 const struct nlattr *entry, *attr;
563 unsigned int i;
565 ynl_attr_for_each_nested(attr, mcasts)
566 ys->n_mcast_groups++;
568 if (!ys->n_mcast_groups)
569 return 0;
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;
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;
588 i++;
591 return 0;
594 static int
595 ynl_get_family_info_cb(const struct nlmsghdr *nlh, struct ynl_parse_arg *yarg)
597 struct ynl_sock *ys = yarg->ys;
598 const struct nlattr *attr;
599 bool found_id = true;
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;
606 if (ynl_attr_type(attr) != CTRL_ATTR_FAMILY_ID)
607 continue;
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;
614 ys->family_id = ynl_attr_get_u16(attr);
615 found_id = true;
618 if (!found_id) {
619 yerr(ys, YNL_ERROR_ATTR_MISSING, "Family ID missing");
620 return YNL_PARSE_CB_ERROR;
622 return YNL_PARSE_CB_OK;
625 static int ynl_sock_read_family(struct ynl_sock *ys, const char *family_name)
627 struct ynl_parse_arg yarg = { .ys = ys, };
628 struct nlmsghdr *nlh;
629 int err;
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);
634 err = ynl_msg_end(ys, nlh);
635 if (err < 0)
636 return err;
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;
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;
651 err = ynl_recv_ack(ys, err);
652 if (err < 0) {
653 free(ys->mcast_groups);
654 return err;
657 return 0;
660 struct ynl_sock *
661 ynl_sock_create(const struct ynl_family *yf, struct ynl_error *yse)
663 struct sockaddr_nl addr;
664 struct ynl_sock *ys;
665 socklen_t addrlen;
666 int one = 1;
668 ys = malloc(sizeof(*ys) + 2 * YNL_SOCKET_BUFFER_SIZE);
669 if (!ys)
670 return NULL;
671 memset(ys, 0, sizeof(*ys));
673 ys->family = yf;
674 ys->tx_buf = &ys->raw_buf[0];
675 ys->rx_buf = &ys->raw_buf[YNL_SOCKET_BUFFER_SIZE];
676 ys->ntf_last_next = &ys->ntf_first;
678 ys->socket = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
679 if (ys->socket < 0) {
680 __perr(yse, "failed to create a netlink socket");
681 goto err_free_sock;
684 if (setsockopt(ys->socket, SOL_NETLINK, NETLINK_CAP_ACK,
685 &one, sizeof(one))) {
686 __perr(yse, "failed to enable netlink ACK");
687 goto err_close_sock;
689 if (setsockopt(ys->socket, SOL_NETLINK, NETLINK_EXT_ACK,
690 &one, sizeof(one))) {
691 __perr(yse, "failed to enable netlink ext ACK");
692 goto err_close_sock;
695 memset(&addr, 0, sizeof(addr));
696 addr.nl_family = AF_NETLINK;
697 if (bind(ys->socket, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
698 __perr(yse, "unable to bind to a socket address");
699 goto err_close_sock;
702 memset(&addr, 0, sizeof(addr));
703 addrlen = sizeof(addr);
704 if (getsockname(ys->socket, (struct sockaddr *)&addr, &addrlen) < 0) {
705 __perr(yse, "unable to read socket address");
706 goto err_close_sock;
708 ys->portid = addr.nl_pid;
709 ys->seq = random();
712 if (ynl_sock_read_family(ys, yf->name)) {
713 if (yse)
714 memcpy(yse, &ys->err, sizeof(*yse));
715 goto err_close_sock;
718 return ys;
720 err_close_sock:
721 close(ys->socket);
722 err_free_sock:
723 free(ys);
724 return NULL;
727 void ynl_sock_destroy(struct ynl_sock *ys)
729 struct ynl_ntf_base_type *ntf;
731 close(ys->socket);
732 while ((ntf = ynl_ntf_dequeue(ys)))
733 ynl_ntf_free(ntf);
734 free(ys->mcast_groups);
735 free(ys);
738 /* YNL multicast handling */
740 void ynl_ntf_free(struct ynl_ntf_base_type *ntf)
742 ntf->free(ntf);
745 int ynl_subscribe(struct ynl_sock *ys, const char *grp_name)
747 unsigned int i;
748 int err;
750 for (i = 0; i < ys->n_mcast_groups; i++)
751 if (!strcmp(ys->mcast_groups[i].name, grp_name))
752 break;
753 if (i == ys->n_mcast_groups) {
754 yerr(ys, ENOENT, "Multicast group '%s' not found", grp_name);
755 return -1;
758 err = setsockopt(ys->socket, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP,
759 &ys->mcast_groups[i].id,
760 sizeof(ys->mcast_groups[i].id));
761 if (err < 0) {
762 perr(ys, "Subscribing to multicast group failed");
763 return -1;
766 return 0;
769 int ynl_socket_get_fd(struct ynl_sock *ys)
771 return ys->socket;
774 struct ynl_ntf_base_type *ynl_ntf_dequeue(struct ynl_sock *ys)
776 struct ynl_ntf_base_type *ntf;
778 if (!ynl_has_ntf(ys))
779 return NULL;
781 ntf = ys->ntf_first;
782 ys->ntf_first = ntf->next;
783 if (ys->ntf_last_next == &ntf->next)
784 ys->ntf_last_next = &ys->ntf_first;
786 return ntf;
789 static int ynl_ntf_parse(struct ynl_sock *ys, const struct nlmsghdr *nlh)
791 struct ynl_parse_arg yarg = { .ys = ys, };
792 const struct ynl_ntf_info *info;
793 struct ynl_ntf_base_type *rsp;
794 struct genlmsghdr *gehdr;
795 int ret;
797 gehdr = ynl_nlmsg_data(nlh);
798 if (gehdr->cmd >= ys->family->ntf_info_size)
799 return YNL_PARSE_CB_ERROR;
800 info = &ys->family->ntf_info[gehdr->cmd];
801 if (!info->cb)
802 return YNL_PARSE_CB_ERROR;
804 rsp = calloc(1, info->alloc_sz);
805 rsp->free = info->free;
806 yarg.data = rsp->data;
807 yarg.rsp_policy = info->policy;
809 ret = info->cb(nlh, &yarg);
810 if (ret <= YNL_PARSE_CB_STOP)
811 goto err_free;
813 rsp->family = nlh->nlmsg_type;
814 rsp->cmd = gehdr->cmd;
816 *ys->ntf_last_next = rsp;
817 ys->ntf_last_next = &rsp->next;
819 return YNL_PARSE_CB_OK;
821 err_free:
822 info->free(rsp);
823 return YNL_PARSE_CB_ERROR;
826 static int
827 ynl_ntf_trampoline(const struct nlmsghdr *nlh, struct ynl_parse_arg *yarg)
829 return ynl_ntf_parse(yarg->ys, nlh);
832 int ynl_ntf_check(struct ynl_sock *ys)
834 struct ynl_parse_arg yarg = { .ys = ys, };
835 int err;
837 do {
838 err = __ynl_sock_read_msgs(&yarg, ynl_ntf_trampoline,
839 MSG_DONTWAIT);
840 if (err < 0)
841 return err;
842 } while (err > 0);
844 return 0;
847 /* YNL specific helpers used by the auto-generated code */
849 struct ynl_dump_list_type *YNL_LIST_END = (void *)(0xb4d123);
851 void ynl_error_unknown_notification(struct ynl_sock *ys, __u8 cmd)
853 yerr(ys, YNL_ERROR_UNKNOWN_NTF,
854 "Unknown notification message type '%d'", cmd);
857 int ynl_error_parse(struct ynl_parse_arg *yarg, const char *msg)
859 yerr(yarg->ys, YNL_ERROR_INV_RESP, "Error parsing response: %s", msg);
860 return YNL_PARSE_CB_ERROR;
863 static int
864 ynl_check_alien(struct ynl_sock *ys, const struct nlmsghdr *nlh, __u32 rsp_cmd)
866 struct genlmsghdr *gehdr;
868 if (ynl_nlmsg_data_len(nlh) < sizeof(*gehdr)) {
869 yerr(ys, YNL_ERROR_INV_RESP,
870 "Kernel responded with truncated message");
871 return -1;
874 gehdr = ynl_nlmsg_data(nlh);
875 if (gehdr->cmd != rsp_cmd)
876 return ynl_ntf_parse(ys, nlh);
878 return 0;
881 static
882 int ynl_req_trampoline(const struct nlmsghdr *nlh, struct ynl_parse_arg *yarg)
884 struct ynl_req_state *yrs = (void *)yarg;
885 int ret;
887 ret = ynl_check_alien(yrs->yarg.ys, nlh, yrs->rsp_cmd);
888 if (ret)
889 return ret < 0 ? YNL_PARSE_CB_ERROR : YNL_PARSE_CB_OK;
891 return yrs->cb(nlh, &yrs->yarg);
894 int ynl_exec(struct ynl_sock *ys, struct nlmsghdr *req_nlh,
895 struct ynl_req_state *yrs)
897 int err;
899 err = ynl_msg_end(ys, req_nlh);
900 if (err < 0)
901 return err;
903 err = send(ys->socket, req_nlh, req_nlh->nlmsg_len, 0);
904 if (err < 0)
905 return err;
907 do {
908 err = ynl_sock_read_msgs(&yrs->yarg, ynl_req_trampoline);
909 } while (err > 0);
911 return err;
914 static int
915 ynl_dump_trampoline(const struct nlmsghdr *nlh, struct ynl_parse_arg *data)
917 struct ynl_dump_state *ds = (void *)data;
918 struct ynl_dump_list_type *obj;
919 struct ynl_parse_arg yarg = {};
920 int ret;
922 ret = ynl_check_alien(ds->yarg.ys, nlh, ds->rsp_cmd);
923 if (ret)
924 return ret < 0 ? YNL_PARSE_CB_ERROR : YNL_PARSE_CB_OK;
926 obj = calloc(1, ds->alloc_sz);
927 if (!obj)
928 return YNL_PARSE_CB_ERROR;
930 if (!ds->first)
931 ds->first = obj;
932 if (ds->last)
933 ds->last->next = obj;
934 ds->last = obj;
936 yarg = ds->yarg;
937 yarg.data = &obj->data;
939 return ds->cb(nlh, &yarg);
942 static void *ynl_dump_end(struct ynl_dump_state *ds)
944 if (!ds->first)
945 return YNL_LIST_END;
947 ds->last->next = YNL_LIST_END;
948 return ds->first;
951 int ynl_exec_dump(struct ynl_sock *ys, struct nlmsghdr *req_nlh,
952 struct ynl_dump_state *yds)
954 int err;
956 err = ynl_msg_end(ys, req_nlh);
957 if (err < 0)
958 return err;
960 err = send(ys->socket, req_nlh, req_nlh->nlmsg_len, 0);
961 if (err < 0)
962 return err;
964 do {
965 err = ynl_sock_read_msgs(&yds->yarg, ynl_dump_trampoline);
966 if (err < 0)
967 goto err_close_list;
968 } while (err > 0);
970 yds->first = ynl_dump_end(yds);
971 return 0;
973 err_close_list:
974 yds->first = ynl_dump_end(yds);
975 return -1;