1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 #include <netinet/in.h>
7 #include "sd-netlink.h"
9 #include "alloc-util.h"
10 #include "format-util.h"
12 #include "netlink-internal.h"
13 #include "netlink-types.h"
14 #include "netlink-util.h"
16 #include "socket-util.h"
19 #define GET_CONTAINER(m, i) ((i) < (m)->n_containers ? (struct rtattr*)((uint8_t*)(m)->hdr + (m)->containers[i].offset) : NULL)
20 #define PUSH_CONTAINER(m, new) (m)->container_offsets[(m)->n_containers++] = (uint8_t*)(new) - (uint8_t*)(m)->hdr;
22 #define RTA_TYPE(rta) ((rta)->rta_type & NLA_TYPE_MASK)
23 #define RTA_FLAGS(rta) ((rta)->rta_type & ~NLA_TYPE_MASK)
25 int message_new_empty(sd_netlink
*rtnl
, sd_netlink_message
**ret
) {
26 sd_netlink_message
*m
;
28 assert_return(ret
, -EINVAL
);
30 /* Note that 'rtnl' is currently unused, if we start using it internally
31 we must take care to avoid problems due to mutual references between
32 buses and their queued messages. See sd-bus.
35 m
= new0(sd_netlink_message
, 1);
39 m
->n_ref
= REFCNT_INIT
;
40 m
->protocol
= rtnl
->protocol
;
48 int message_new(sd_netlink
*rtnl
, sd_netlink_message
**ret
, uint16_t type
) {
49 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*m
= NULL
;
50 const NLType
*nl_type
;
51 const NLTypeSystem
*type_system_root
;
55 assert_return(rtnl
, -EINVAL
);
57 type_system_root
= type_system_get_root(rtnl
->protocol
);
59 r
= type_system_get_type(type_system_root
, &nl_type
, type
);
63 if (type_get_type(nl_type
) != NETLINK_TYPE_NESTED
)
66 r
= message_new_empty(rtnl
, &m
);
70 size
= NLMSG_SPACE(type_get_size(nl_type
));
72 assert(size
>= sizeof(struct nlmsghdr
));
73 m
->hdr
= malloc0(size
);
77 m
->hdr
->nlmsg_flags
= NLM_F_REQUEST
| NLM_F_ACK
;
79 type_get_type_system(nl_type
, &m
->containers
[0].type_system
);
80 m
->hdr
->nlmsg_len
= size
;
81 m
->hdr
->nlmsg_type
= type
;
88 int sd_netlink_message_request_dump(sd_netlink_message
*m
, int dump
) {
89 assert_return(m
, -EINVAL
);
90 assert_return(m
->hdr
, -EINVAL
);
92 assert_return(IN_SET(m
->hdr
->nlmsg_type
, RTM_GETLINK
, RTM_GETADDR
, RTM_GETROUTE
, RTM_GETNEIGH
, RTM_GETRULE
, RTM_GETADDRLABEL
), -EINVAL
);
94 SET_FLAG(m
->hdr
->nlmsg_flags
, NLM_F_DUMP
, dump
);
99 DEFINE_ATOMIC_REF_FUNC(sd_netlink_message
, sd_netlink_message
);
101 sd_netlink_message
*sd_netlink_message_unref(sd_netlink_message
*m
) {
102 sd_netlink_message
*t
;
104 while (m
&& REFCNT_DEC(m
->n_ref
) == 0) {
109 for (i
= 0; i
<= m
->n_containers
; i
++)
110 free(m
->containers
[i
].attributes
);
120 int sd_netlink_message_get_type(sd_netlink_message
*m
, uint16_t *type
) {
121 assert_return(m
, -EINVAL
);
122 assert_return(type
, -EINVAL
);
124 *type
= m
->hdr
->nlmsg_type
;
129 int sd_netlink_message_set_flags(sd_netlink_message
*m
, uint16_t flags
) {
130 assert_return(m
, -EINVAL
);
131 assert_return(flags
, -EINVAL
);
133 m
->hdr
->nlmsg_flags
= flags
;
138 int sd_netlink_message_is_broadcast(sd_netlink_message
*m
) {
139 assert_return(m
, -EINVAL
);
144 /* If successful the updated message will be correctly aligned, if
145 unsuccessful the old message is untouched. */
146 static int add_rtattr(sd_netlink_message
*m
, unsigned short type
, const void *data
, size_t data_length
) {
148 size_t message_length
, padding_length
;
149 struct nlmsghdr
*new_hdr
;
158 assert(NLMSG_ALIGN(m
->hdr
->nlmsg_len
) == m
->hdr
->nlmsg_len
);
159 assert(!data
|| data_length
);
161 /* get offset of the new attribute */
162 offset
= m
->hdr
->nlmsg_len
;
164 /* get the size of the new rta attribute (with padding at the end) */
165 rta_length
= RTA_LENGTH(data_length
);
167 /* get the new message size (with padding at the end) */
168 message_length
= offset
+ RTA_ALIGN(rta_length
);
170 /* buffer should be smaller than both one page or 8K to be accepted by the kernel */
171 if (message_length
> MIN(page_size(), 8192UL))
174 /* realloc to fit the new attribute */
175 new_hdr
= realloc(m
->hdr
, message_length
);
180 /* get pointer to the attribute we are about to add */
181 rta
= (struct rtattr
*) ((uint8_t *) m
->hdr
+ offset
);
183 /* if we are inside containers, extend them */
184 for (i
= 0; i
< m
->n_containers
; i
++)
185 GET_CONTAINER(m
, i
)->rta_len
+= message_length
- offset
;
187 /* fill in the attribute */
188 rta
->rta_type
= type
;
189 rta
->rta_len
= rta_length
;
191 /* we don't deal with the case where the user lies about the type
192 * and gives us too little data (so don't do that)
194 padding
= mempcpy(RTA_DATA(rta
), data
, data_length
);
197 /* if no data was passed, make sure we still initialize the padding
198 note that we can have data_length > 0 (used by some containers) */
199 padding
= RTA_DATA(rta
);
201 /* make sure also the padding at the end of the message is initialized */
202 padding_length
= (uint8_t*)m
->hdr
+ message_length
- (uint8_t*)padding
;
203 memzero(padding
, padding_length
);
205 /* update message size */
206 m
->hdr
->nlmsg_len
= message_length
;
211 static int message_attribute_has_type(sd_netlink_message
*m
, size_t *out_size
, uint16_t attribute_type
, uint16_t data_type
) {
217 r
= type_system_get_type(m
->containers
[m
->n_containers
].type_system
, &type
, attribute_type
);
221 if (type_get_type(type
) != data_type
)
225 *out_size
= type_get_size(type
);
229 int sd_netlink_message_append_string(sd_netlink_message
*m
, unsigned short type
, const char *data
) {
233 assert_return(m
, -EINVAL
);
234 assert_return(!m
->sealed
, -EPERM
);
235 assert_return(data
, -EINVAL
);
237 r
= message_attribute_has_type(m
, &size
, type
, NETLINK_TYPE_STRING
);
242 length
= strnlen(data
, size
+1);
246 length
= strlen(data
);
248 r
= add_rtattr(m
, type
, data
, length
+ 1);
255 int sd_netlink_message_append_flag(sd_netlink_message
*m
, unsigned short type
) {
259 assert_return(m
, -EINVAL
);
260 assert_return(!m
->sealed
, -EPERM
);
262 r
= message_attribute_has_type(m
, &size
, type
, NETLINK_TYPE_FLAG
);
266 r
= add_rtattr(m
, type
, NULL
, 0);
273 int sd_netlink_message_append_u8(sd_netlink_message
*m
, unsigned short type
, uint8_t data
) {
276 assert_return(m
, -EINVAL
);
277 assert_return(!m
->sealed
, -EPERM
);
279 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_U8
);
283 r
= add_rtattr(m
, type
, &data
, sizeof(uint8_t));
290 int sd_netlink_message_append_u16(sd_netlink_message
*m
, unsigned short type
, uint16_t data
) {
293 assert_return(m
, -EINVAL
);
294 assert_return(!m
->sealed
, -EPERM
);
296 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_U16
);
300 r
= add_rtattr(m
, type
, &data
, sizeof(uint16_t));
307 int sd_netlink_message_append_u32(sd_netlink_message
*m
, unsigned short type
, uint32_t data
) {
310 assert_return(m
, -EINVAL
);
311 assert_return(!m
->sealed
, -EPERM
);
313 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_U32
);
317 r
= add_rtattr(m
, type
, &data
, sizeof(uint32_t));
324 int sd_netlink_message_append_data(sd_netlink_message
*m
, unsigned short type
, const void *data
, size_t len
) {
327 assert_return(m
, -EINVAL
);
328 assert_return(!m
->sealed
, -EPERM
);
330 r
= add_rtattr(m
, type
, data
, len
);
337 int sd_netlink_message_append_in_addr(sd_netlink_message
*m
, unsigned short type
, const struct in_addr
*data
) {
340 assert_return(m
, -EINVAL
);
341 assert_return(!m
->sealed
, -EPERM
);
342 assert_return(data
, -EINVAL
);
344 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_IN_ADDR
);
348 r
= add_rtattr(m
, type
, data
, sizeof(struct in_addr
));
355 int sd_netlink_message_append_in6_addr(sd_netlink_message
*m
, unsigned short type
, const struct in6_addr
*data
) {
358 assert_return(m
, -EINVAL
);
359 assert_return(!m
->sealed
, -EPERM
);
360 assert_return(data
, -EINVAL
);
362 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_IN_ADDR
);
366 r
= add_rtattr(m
, type
, data
, sizeof(struct in6_addr
));
373 int sd_netlink_message_append_ether_addr(sd_netlink_message
*m
, unsigned short type
, const struct ether_addr
*data
) {
376 assert_return(m
, -EINVAL
);
377 assert_return(!m
->sealed
, -EPERM
);
378 assert_return(data
, -EINVAL
);
380 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_ETHER_ADDR
);
384 r
= add_rtattr(m
, type
, data
, ETH_ALEN
);
391 int sd_netlink_message_append_cache_info(sd_netlink_message
*m
, unsigned short type
, const struct ifa_cacheinfo
*info
) {
394 assert_return(m
, -EINVAL
);
395 assert_return(!m
->sealed
, -EPERM
);
396 assert_return(info
, -EINVAL
);
398 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_CACHE_INFO
);
402 r
= add_rtattr(m
, type
, info
, sizeof(struct ifa_cacheinfo
));
409 int sd_netlink_message_open_container(sd_netlink_message
*m
, unsigned short type
) {
413 assert_return(m
, -EINVAL
);
414 assert_return(!m
->sealed
, -EPERM
);
415 assert_return(m
->n_containers
< RTNL_CONTAINER_DEPTH
, -ERANGE
);
417 r
= message_attribute_has_type(m
, &size
, type
, NETLINK_TYPE_NESTED
);
419 const NLTypeSystemUnion
*type_system_union
;
422 r
= message_attribute_has_type(m
, &size
, type
, NETLINK_TYPE_UNION
);
426 r
= sd_rtnl_message_get_family(m
, &family
);
430 r
= type_system_get_type_system_union(m
->containers
[m
->n_containers
].type_system
, &type_system_union
, type
);
434 r
= type_system_union_protocol_get_type_system(type_system_union
,
435 &m
->containers
[m
->n_containers
+ 1].type_system
,
440 r
= type_system_get_type_system(m
->containers
[m
->n_containers
].type_system
,
441 &m
->containers
[m
->n_containers
+ 1].type_system
,
447 r
= add_rtattr(m
, type
| NLA_F_NESTED
, NULL
, size
);
451 m
->containers
[m
->n_containers
++].offset
= r
;
456 int sd_netlink_message_open_container_union(sd_netlink_message
*m
, unsigned short type
, const char *key
) {
457 const NLTypeSystemUnion
*type_system_union
;
460 assert_return(m
, -EINVAL
);
461 assert_return(!m
->sealed
, -EPERM
);
463 r
= type_system_get_type_system_union(m
->containers
[m
->n_containers
].type_system
, &type_system_union
, type
);
467 r
= type_system_union_get_type_system(type_system_union
,
468 &m
->containers
[m
->n_containers
+ 1].type_system
,
473 r
= sd_netlink_message_append_string(m
, type_system_union
->match
, key
);
477 /* do we ever need non-null size */
478 r
= add_rtattr(m
, type
| NLA_F_NESTED
, NULL
, 0);
482 m
->containers
[m
->n_containers
++].offset
= r
;
487 int sd_netlink_message_close_container(sd_netlink_message
*m
) {
488 assert_return(m
, -EINVAL
);
489 assert_return(!m
->sealed
, -EPERM
);
490 assert_return(m
->n_containers
> 0, -EINVAL
);
492 m
->containers
[m
->n_containers
].type_system
= NULL
;
493 m
->containers
[m
->n_containers
].offset
= 0;
499 int sd_netlink_message_open_array(sd_netlink_message
*m
, uint16_t type
) {
502 assert_return(m
, -EINVAL
);
503 assert_return(!m
->sealed
, -EPERM
);
504 assert_return(m
->n_containers
> 0, -EINVAL
);
506 r
= add_rtattr(m
, type
| NLA_F_NESTED
, NULL
, 0);
510 m
->containers
[m
->n_containers
].offset
= r
;
512 m
->containers
[m
->n_containers
].type_system
= m
->containers
[m
->n_containers
- 1].type_system
;
517 int sd_netlink_message_cancel_array(sd_netlink_message
*m
) {
521 assert_return(m
, -EINVAL
);
522 assert_return(!m
->sealed
, -EPERM
);
523 assert_return(m
->n_containers
> 1, -EINVAL
);
525 rta_len
= GET_CONTAINER(m
, (m
->n_containers
- 1))->rta_len
;
527 for (i
= 0; i
< m
->n_containers
; i
++)
528 GET_CONTAINER(m
, i
)->rta_len
-= rta_len
;
530 m
->hdr
->nlmsg_len
-= rta_len
;
533 m
->containers
[m
->n_containers
].type_system
= NULL
;
538 static int netlink_message_read_internal(sd_netlink_message
*m
, unsigned short type
, void **data
, bool *net_byteorder
) {
539 struct netlink_attribute
*attribute
;
542 assert_return(m
, -EINVAL
);
543 assert_return(m
->sealed
, -EPERM
);
544 assert_return(data
, -EINVAL
);
546 assert(m
->n_containers
< RTNL_CONTAINER_DEPTH
);
547 assert(m
->containers
[m
->n_containers
].attributes
);
548 assert(type
< m
->containers
[m
->n_containers
].n_attributes
);
550 attribute
= &m
->containers
[m
->n_containers
].attributes
[type
];
552 if (attribute
->offset
== 0)
555 rta
= (struct rtattr
*)((uint8_t *) m
->hdr
+ attribute
->offset
);
557 *data
= RTA_DATA(rta
);
560 *net_byteorder
= attribute
->net_byteorder
;
562 return RTA_PAYLOAD(rta
);
565 int sd_netlink_message_read(sd_netlink_message
*m
, unsigned short type
, size_t size
, void *data
) {
569 assert_return(m
, -EINVAL
);
571 r
= netlink_message_read_internal(m
, type
, &attr_data
, NULL
);
575 if ((size_t) r
< size
)
579 memcpy(data
, attr_data
, size
);
584 int sd_netlink_message_read_string(sd_netlink_message
*m
, unsigned short type
, const char **data
) {
588 assert_return(m
, -EINVAL
);
590 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_STRING
);
594 r
= netlink_message_read_internal(m
, type
, &attr_data
, NULL
);
597 else if (strnlen(attr_data
, r
) >= (size_t) r
)
601 *data
= (const char *) attr_data
;
606 int sd_netlink_message_read_u8(sd_netlink_message
*m
, unsigned short type
, uint8_t *data
) {
610 assert_return(m
, -EINVAL
);
612 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_U8
);
616 r
= netlink_message_read_internal(m
, type
, &attr_data
, NULL
);
619 else if ((size_t) r
< sizeof(uint8_t))
623 *data
= *(uint8_t *) attr_data
;
628 int sd_netlink_message_read_u16(sd_netlink_message
*m
, unsigned short type
, uint16_t *data
) {
633 assert_return(m
, -EINVAL
);
635 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_U16
);
639 r
= netlink_message_read_internal(m
, type
, &attr_data
, &net_byteorder
);
642 else if ((size_t) r
< sizeof(uint16_t))
647 *data
= be16toh(*(uint16_t *) attr_data
);
649 *data
= *(uint16_t *) attr_data
;
655 int sd_netlink_message_read_u32(sd_netlink_message
*m
, unsigned short type
, uint32_t *data
) {
660 assert_return(m
, -EINVAL
);
662 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_U32
);
666 r
= netlink_message_read_internal(m
, type
, &attr_data
, &net_byteorder
);
669 else if ((size_t)r
< sizeof(uint32_t))
674 *data
= be32toh(*(uint32_t *) attr_data
);
676 *data
= *(uint32_t *) attr_data
;
682 int sd_netlink_message_read_ether_addr(sd_netlink_message
*m
, unsigned short type
, struct ether_addr
*data
) {
686 assert_return(m
, -EINVAL
);
688 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_ETHER_ADDR
);
692 r
= netlink_message_read_internal(m
, type
, &attr_data
, NULL
);
695 else if ((size_t)r
< sizeof(struct ether_addr
))
699 memcpy(data
, attr_data
, sizeof(struct ether_addr
));
704 int sd_netlink_message_read_cache_info(sd_netlink_message
*m
, unsigned short type
, struct ifa_cacheinfo
*info
) {
708 assert_return(m
, -EINVAL
);
710 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_CACHE_INFO
);
714 r
= netlink_message_read_internal(m
, type
, &attr_data
, NULL
);
717 else if ((size_t)r
< sizeof(struct ifa_cacheinfo
))
721 memcpy(info
, attr_data
, sizeof(struct ifa_cacheinfo
));
726 int sd_netlink_message_read_in_addr(sd_netlink_message
*m
, unsigned short type
, struct in_addr
*data
) {
730 assert_return(m
, -EINVAL
);
732 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_IN_ADDR
);
736 r
= netlink_message_read_internal(m
, type
, &attr_data
, NULL
);
739 else if ((size_t)r
< sizeof(struct in_addr
))
743 memcpy(data
, attr_data
, sizeof(struct in_addr
));
748 int sd_netlink_message_read_in6_addr(sd_netlink_message
*m
, unsigned short type
, struct in6_addr
*data
) {
752 assert_return(m
, -EINVAL
);
754 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_IN_ADDR
);
758 r
= netlink_message_read_internal(m
, type
, &attr_data
, NULL
);
761 else if ((size_t)r
< sizeof(struct in6_addr
))
765 memcpy(data
, attr_data
, sizeof(struct in6_addr
));
770 static int netlink_container_parse(sd_netlink_message
*m
,
771 struct netlink_container
*container
,
775 _cleanup_free_
struct netlink_attribute
*attributes
= NULL
;
777 attributes
= new0(struct netlink_attribute
, count
);
781 for (; RTA_OK(rta
, rt_len
); rta
= RTA_NEXT(rta
, rt_len
)) {
784 type
= RTA_TYPE(rta
);
786 /* if the kernel is newer than the headers we used
787 when building, we ignore out-of-range attributes */
791 if (attributes
[type
].offset
!= 0)
792 log_debug("rtnl: message parse - overwriting repeated attribute");
794 attributes
[type
].offset
= (uint8_t *) rta
- (uint8_t *) m
->hdr
;
795 attributes
[type
].nested
= RTA_FLAGS(rta
) & NLA_F_NESTED
;
796 attributes
[type
].net_byteorder
= RTA_FLAGS(rta
) & NLA_F_NET_BYTEORDER
;
799 container
->attributes
= TAKE_PTR(attributes
);
800 container
->n_attributes
= count
;
805 int sd_netlink_message_enter_container(sd_netlink_message
*m
, unsigned short type_id
) {
806 const NLType
*nl_type
;
807 const NLTypeSystem
*type_system
;
813 assert_return(m
, -EINVAL
);
814 assert_return(m
->n_containers
< RTNL_CONTAINER_DEPTH
, -EINVAL
);
816 r
= type_system_get_type(m
->containers
[m
->n_containers
].type_system
,
822 type
= type_get_type(nl_type
);
824 if (type
== NETLINK_TYPE_NESTED
) {
825 r
= type_system_get_type_system(m
->containers
[m
->n_containers
].type_system
,
830 } else if (type
== NETLINK_TYPE_UNION
) {
831 const NLTypeSystemUnion
*type_system_union
;
833 r
= type_system_get_type_system_union(m
->containers
[m
->n_containers
].type_system
,
839 switch (type_system_union
->match_type
) {
840 case NL_MATCH_SIBLING
:
844 r
= sd_netlink_message_read_string(m
, type_system_union
->match
, &key
);
848 r
= type_system_union_get_type_system(type_system_union
,
856 case NL_MATCH_PROTOCOL
:
860 r
= sd_rtnl_message_get_family(m
, &family
);
864 r
= type_system_union_protocol_get_type_system(type_system_union
,
873 assert_not_reached("sd-netlink: invalid type system union type");
878 r
= netlink_message_read_internal(m
, type_id
, &container
, NULL
);
886 r
= netlink_container_parse(m
,
887 &m
->containers
[m
->n_containers
],
888 type_system_get_count(type_system
),
896 m
->containers
[m
->n_containers
].type_system
= type_system
;
901 int sd_netlink_message_exit_container(sd_netlink_message
*m
) {
902 assert_return(m
, -EINVAL
);
903 assert_return(m
->sealed
, -EINVAL
);
904 assert_return(m
->n_containers
> 0, -EINVAL
);
906 m
->containers
[m
->n_containers
].attributes
= mfree(m
->containers
[m
->n_containers
].attributes
);
907 m
->containers
[m
->n_containers
].type_system
= NULL
;
914 uint32_t rtnl_message_get_serial(sd_netlink_message
*m
) {
918 return m
->hdr
->nlmsg_seq
;
921 int sd_netlink_message_is_error(sd_netlink_message
*m
) {
923 assert_return(m
->hdr
, 0);
925 return m
->hdr
->nlmsg_type
== NLMSG_ERROR
;
928 int sd_netlink_message_get_errno(sd_netlink_message
*m
) {
929 struct nlmsgerr
*err
;
931 assert_return(m
, -EINVAL
);
932 assert_return(m
->hdr
, -EINVAL
);
934 if (!sd_netlink_message_is_error(m
))
937 err
= NLMSG_DATA(m
->hdr
);
942 int sd_netlink_message_rewind(sd_netlink_message
*m
) {
943 const NLType
*nl_type
;
944 const NLTypeSystem
*type_system_root
;
950 assert_return(m
, -EINVAL
);
952 /* don't allow appending to message once parsed */
954 rtnl_message_seal(m
);
956 type_system_root
= type_system_get_root(m
->protocol
);
958 for (i
= 1; i
<= m
->n_containers
; i
++)
959 m
->containers
[i
].attributes
= mfree(m
->containers
[i
].attributes
);
963 if (m
->containers
[0].attributes
)
964 /* top-level attributes have already been parsed */
969 r
= type_system_get_type(type_system_root
, &nl_type
, m
->hdr
->nlmsg_type
);
973 type
= type_get_type(nl_type
);
974 size
= type_get_size(nl_type
);
976 if (type
== NETLINK_TYPE_NESTED
) {
977 const NLTypeSystem
*type_system
;
979 type_get_type_system(nl_type
, &type_system
);
981 m
->containers
[0].type_system
= type_system
;
983 r
= netlink_container_parse(m
,
984 &m
->containers
[m
->n_containers
],
985 type_system_get_count(type_system
),
986 (struct rtattr
*)((uint8_t*)NLMSG_DATA(m
->hdr
) + NLMSG_ALIGN(size
)),
987 NLMSG_PAYLOAD(m
->hdr
, size
));
995 void rtnl_message_seal(sd_netlink_message
*m
) {
1002 sd_netlink_message
*sd_netlink_message_next(sd_netlink_message
*m
) {
1003 assert_return(m
, NULL
);