1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
8 #include <linux/types.h>
9 #include <linux/genetlink.h>
10 #include <sys/socket.h>
14 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(*arr))
16 #define __yerr_msg(yse, _msg...) \
18 struct ynl_error *_yse = (yse); \
21 snprintf(_yse->msg, sizeof(_yse->msg) - 1, _msg); \
22 _yse->msg[sizeof(_yse->msg) - 1] = 0; \
26 #define __yerr_code(yse, _code...) \
28 struct ynl_error *_yse = (yse); \
35 #define __yerr(yse, _code, _msg...) \
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 */
49 ynl_err_walk_report_one(const struct ynl_policy_nest
*policy
, unsigned int type
,
50 char *str
, int str_sz
, int *n
)
54 *n
+= snprintf(str
, str_sz
, "!policy");
58 if (type
> policy
->max_attr
) {
60 *n
+= snprintf(str
, str_sz
, "!oob");
64 if (!policy
->table
[type
].name
) {
66 *n
+= snprintf(str
, str_sz
, "!name");
71 *n
+= snprintf(str
, str_sz
- *n
,
72 ".%s", policy
->table
[type
].name
);
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
;
90 n
+= snprintf(str
, str_sz
, "!policy");
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
);
110 type
= ynl_attr_type(attr
);
112 if (ynl_err_walk_report_one(policy
, type
, str
, str_sz
, &n
))
117 *nest_pol
= policy
->table
[type
].nest
;
121 if (!policy
->table
[type
].nest
) {
123 n
+= snprintf(str
, str_sz
, "!nest");
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)
140 ynl_ext_ack_check(struct ynl_sock
*ys
, const struct nlmsghdr
*nlh
,
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
)
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
;
172 case NLMSGERR_ATTR_MSG
:
173 str
= ynl_attr_get_str(attr
);
175 return YNL_PARSE_CB_ERROR
;
185 if (tb
[NLMSGERR_ATTR_OFFS
]) {
189 ys
->err
.attr_offs
= ynl_attr_get_u32(tb
[NLMSGERR_ATTR_OFFS
]);
191 n
= snprintf(bad_attr
, sizeof(bad_attr
), "%sbad attribute: ",
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;
208 if (tb
[NLMSGERR_ATTR_MISS_TYPE
]) {
209 const struct ynl_policy_nest
*nest_pol
= NULL
;
210 unsigned int n
, off
, type
;
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
,
234 ynl_err_walk_report_one(nest_pol
, type
, &miss_attr
[n
],
235 sizeof(miss_attr
) - n
, &n2
);
238 if (n
>= sizeof(miss_attr
))
239 n
= sizeof(miss_attr
) - 1;
243 /* Implicitly depend on ys->err.code already set */
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
);
254 yerr_msg(ys
, "%s", strerror(ys
->err
.code
));
256 return YNL_PARSE_CB_OK
;
260 ynl_cb_error(const struct nlmsghdr
*nlh
, struct ynl_parse_arg
*yarg
)
262 const struct nlmsgerr
*err
= ynl_nlmsg_data(nlh
);
266 code
= err
->error
>= 0 ? err
->error
: -err
->error
;
267 yarg
->ys
->err
.code
= code
;
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
)
283 err
= *(int *)NLMSG_DATA(nlh
);
285 yarg
->ys
->err
.code
= -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
;
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");
312 policy
= &yarg
->rsp_policy
->table
[type
];
314 switch (policy
->type
) {
316 yerr(yarg
->ys
, YNL_ERROR_ATTR_INVALID
,
317 "Rejected attribute (%s)", policy
->name
);
322 if (len
== sizeof(__u8
))
324 yerr(yarg
->ys
, YNL_ERROR_ATTR_INVALID
,
325 "Invalid attribute (u8 %s)", policy
->name
);
328 if (len
== sizeof(__u16
))
330 yerr(yarg
->ys
, YNL_ERROR_ATTR_INVALID
,
331 "Invalid attribute (u16 %s)", policy
->name
);
334 if (len
== sizeof(__u32
))
336 yerr(yarg
->ys
, YNL_ERROR_ATTR_INVALID
,
337 "Invalid attribute (u32 %s)", policy
->name
);
340 if (len
== sizeof(__u64
))
342 yerr(yarg
->ys
, YNL_ERROR_ATTR_INVALID
,
343 "Invalid attribute (u64 %s)", policy
->name
);
346 if (len
== sizeof(__u32
) || len
== sizeof(__u64
))
348 yerr(yarg
->ys
, YNL_ERROR_ATTR_INVALID
,
349 "Invalid attribute (uint %s)", policy
->name
);
352 /* Let flags grow into real attrs, why not.. */
355 if (!len
|| len
>= sizeof(*attr
))
357 yerr(yarg
->ys
, YNL_ERROR_ATTR_INVALID
,
358 "Invalid attribute (nest %s)", policy
->name
);
361 if (!policy
->len
|| len
== policy
->len
)
363 yerr(yarg
->ys
, YNL_ERROR_ATTR_INVALID
,
364 "Invalid attribute (binary %s)", policy
->name
);
367 if ((!policy
->len
|| len
<= policy
->len
) && !data
[len
- 1])
369 yerr(yarg
->ys
, YNL_ERROR_ATTR_INVALID
,
370 "Invalid attribute (string %s)", policy
->name
);
372 case YNL_PT_BITFIELD32
:
373 if (len
== sizeof(struct nla_bitfield32
))
375 yerr(yarg
->ys
, YNL_ERROR_ATTR_INVALID
,
376 "Invalid attribute (bitfield32 %s)", policy
->name
);
379 yerr(yarg
->ys
, YNL_ERROR_ATTR_INVALID
,
380 "Invalid attribute (unknown %s)", policy
->name
);
389 static void ynl_err_reset(struct ynl_sock
*ys
)
392 ys
->err
.attr_offs
= 0;
396 struct nlmsghdr
*ynl_msg_start(struct ynl_sock
*ys
, __u32 id
, __u16 flags
)
398 struct nlmsghdr
*nlh
;
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
;
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");
424 if (nlh
->nlmsg_pid
== YNL_MSG_OVERFLOW
) {
425 yerr(ys
, YNL_ERROR_INPUT_TOO_BIG
,
426 "Constructed message longer than internal buffer");
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
;
442 nlh
= ynl_msg_start(ys
, id
, flags
);
444 memset(&gehdr
, 0, sizeof(gehdr
));
446 gehdr
.version
= version
;
448 data
= ynl_nlmsg_put_extra_header(nlh
, sizeof(gehdr
));
449 memcpy(data
, &gehdr
, sizeof(gehdr
));
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
);
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
);
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
,
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
;
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
;
493 len
= recv(ys
->socket
, ys
->rx_buf
, YNL_SOCKET_BUFFER_SIZE
, flags
);
495 if (flags
& MSG_DONTWAIT
&& errno
== EAGAIN
)
496 return YNL_PARSE_CB_STOP
;
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
) {
518 yerr(yarg
->ys
, YNL_ERROR_INV_RESP
,
519 "Invalid message type in the response.");
520 return YNL_PARSE_CB_ERROR
;
522 case NLMSG_OVERRUN
... NLMSG_MIN_TYPE
- 1:
523 ret
= YNL_PARSE_CB_OK
;
526 ret
= ynl_cb_error(nlh
, yarg
);
529 ret
= ynl_cb_done(nlh
, yarg
);
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
, };
550 yerr(ys
, YNL_ERROR_EXPECT_ACK
,
551 "Expecting an ACK but nothing received");
555 return ynl_sock_read_msgs(&yarg
, ynl_cb_null
);
558 /* Init/fini and genetlink boiler plate */
560 ynl_get_family_info_mcast(struct ynl_sock
*ys
, const struct nlattr
*mcasts
)
562 const struct nlattr
*entry
, *attr
;
565 ynl_attr_for_each_nested(attr
, mcasts
)
566 ys
->n_mcast_groups
++;
568 if (!ys
->n_mcast_groups
)
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
;
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
),
585 ys
->mcast_groups
[i
].name
[GENL_NAMSIZ
- 1] = 0;
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
)
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
);
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
;
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
);
638 err
= send(ys
->socket
, nlh
, nlh
->nlmsg_len
, 0);
640 perr(ys
, "failed to request socket family info");
644 err
= ynl_sock_read_msgs(&yarg
, ynl_get_family_info_cb
);
646 free(ys
->mcast_groups
);
647 perr(ys
, "failed to receive the socket family info - no such family?");
651 err
= ynl_recv_ack(ys
, err
);
653 free(ys
->mcast_groups
);
661 ynl_sock_create(const struct ynl_family
*yf
, struct ynl_error
*yse
)
663 struct sockaddr_nl addr
;
668 ys
= malloc(sizeof(*ys
) + 2 * YNL_SOCKET_BUFFER_SIZE
);
671 memset(ys
, 0, sizeof(*ys
));
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");
684 if (setsockopt(ys
->socket
, SOL_NETLINK
, NETLINK_CAP_ACK
,
685 &one
, sizeof(one
))) {
686 __perr(yse
, "failed to enable netlink ACK");
689 if (setsockopt(ys
->socket
, SOL_NETLINK
, NETLINK_EXT_ACK
,
690 &one
, sizeof(one
))) {
691 __perr(yse
, "failed to enable netlink ext ACK");
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");
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");
708 ys
->portid
= addr
.nl_pid
;
712 if (ynl_sock_read_family(ys
, yf
->name
)) {
714 memcpy(yse
, &ys
->err
, sizeof(*yse
));
727 void ynl_sock_destroy(struct ynl_sock
*ys
)
729 struct ynl_ntf_base_type
*ntf
;
732 while ((ntf
= ynl_ntf_dequeue(ys
)))
734 free(ys
->mcast_groups
);
738 /* YNL multicast handling */
740 void ynl_ntf_free(struct ynl_ntf_base_type
*ntf
)
745 int ynl_subscribe(struct ynl_sock
*ys
, const char *grp_name
)
750 for (i
= 0; i
< ys
->n_mcast_groups
; i
++)
751 if (!strcmp(ys
->mcast_groups
[i
].name
, grp_name
))
753 if (i
== ys
->n_mcast_groups
) {
754 yerr(ys
, ENOENT
, "Multicast group '%s' not found", grp_name
);
758 err
= setsockopt(ys
->socket
, SOL_NETLINK
, NETLINK_ADD_MEMBERSHIP
,
759 &ys
->mcast_groups
[i
].id
,
760 sizeof(ys
->mcast_groups
[i
].id
));
762 perr(ys
, "Subscribing to multicast group failed");
769 int ynl_socket_get_fd(struct ynl_sock
*ys
)
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
))
782 ys
->ntf_first
= ntf
->next
;
783 if (ys
->ntf_last_next
== &ntf
->next
)
784 ys
->ntf_last_next
= &ys
->ntf_first
;
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
;
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
];
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
)
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
;
823 return YNL_PARSE_CB_ERROR
;
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
, };
838 err
= __ynl_sock_read_msgs(&yarg
, ynl_ntf_trampoline
,
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
;
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");
874 gehdr
= ynl_nlmsg_data(nlh
);
875 if (gehdr
->cmd
!= rsp_cmd
)
876 return ynl_ntf_parse(ys
, nlh
);
882 int ynl_req_trampoline(const struct nlmsghdr
*nlh
, struct ynl_parse_arg
*yarg
)
884 struct ynl_req_state
*yrs
= (void *)yarg
;
887 ret
= ynl_check_alien(yrs
->yarg
.ys
, nlh
, yrs
->rsp_cmd
);
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
)
899 err
= ynl_msg_end(ys
, req_nlh
);
903 err
= send(ys
->socket
, req_nlh
, req_nlh
->nlmsg_len
, 0);
908 err
= ynl_sock_read_msgs(&yrs
->yarg
, ynl_req_trampoline
);
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
= {};
922 ret
= ynl_check_alien(ds
->yarg
.ys
, nlh
, ds
->rsp_cmd
);
924 return ret
< 0 ? YNL_PARSE_CB_ERROR
: YNL_PARSE_CB_OK
;
926 obj
= calloc(1, ds
->alloc_sz
);
928 return YNL_PARSE_CB_ERROR
;
933 ds
->last
->next
= obj
;
937 yarg
.data
= &obj
->data
;
939 return ds
->cb(nlh
, &yarg
);
942 static void *ynl_dump_end(struct ynl_dump_state
*ds
)
947 ds
->last
->next
= YNL_LIST_END
;
951 int ynl_exec_dump(struct ynl_sock
*ys
, struct nlmsghdr
*req_nlh
,
952 struct ynl_dump_state
*yds
)
956 err
= ynl_msg_end(ys
, req_nlh
);
960 err
= send(ys
->socket
, req_nlh
, req_nlh
->nlmsg_len
, 0);
965 err
= ynl_sock_read_msgs(&yds
->yarg
, ynl_dump_trampoline
);
970 yds
->first
= ynl_dump_end(yds
);
974 yds
->first
= ynl_dump_end(yds
);