1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2013 Tom Gundersen <teg@jklm.no>
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
21 #include <netinet/in.h>
25 #include "sd-netlink.h"
27 #include "alloc-util.h"
28 #include "format-util.h"
30 #include "netlink-internal.h"
31 #include "netlink-types.h"
32 #include "netlink-util.h"
34 #include "socket-util.h"
37 #define GET_CONTAINER(m, i) ((i) < (m)->n_containers ? (struct rtattr*)((uint8_t*)(m)->hdr + (m)->containers[i].offset) : NULL)
38 #define PUSH_CONTAINER(m, new) (m)->container_offsets[(m)->n_containers++] = (uint8_t*)(new) - (uint8_t*)(m)->hdr;
40 #define RTA_TYPE(rta) ((rta)->rta_type & NLA_TYPE_MASK)
41 #define RTA_FLAGS(rta) ((rta)->rta_type & ~NLA_TYPE_MASK)
43 int message_new_empty(sd_netlink
*rtnl
, sd_netlink_message
**ret
) {
44 sd_netlink_message
*m
;
46 assert_return(ret
, -EINVAL
);
48 /* Note that 'rtnl' is currently unused, if we start using it internally
49 we must take care to avoid problems due to mutual references between
50 buses and their queued messages. See sd-bus.
53 m
= new0(sd_netlink_message
, 1);
57 m
->n_ref
= REFCNT_INIT
;
58 m
->protocol
= rtnl
->protocol
;
66 int message_new(sd_netlink
*rtnl
, sd_netlink_message
**ret
, uint16_t type
) {
67 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*m
= NULL
;
68 const NLType
*nl_type
;
69 const NLTypeSystem
*type_system_root
;
73 assert_return(rtnl
, -EINVAL
);
75 type_system_root
= type_system_get_root(rtnl
->protocol
);
77 r
= type_system_get_type(type_system_root
, &nl_type
, type
);
81 if (type_get_type(nl_type
) != NETLINK_TYPE_NESTED
)
84 r
= message_new_empty(rtnl
, &m
);
88 size
= NLMSG_SPACE(type_get_size(nl_type
));
90 assert(size
>= sizeof(struct nlmsghdr
));
91 m
->hdr
= malloc0(size
);
95 m
->hdr
->nlmsg_flags
= NLM_F_REQUEST
| NLM_F_ACK
;
97 type_get_type_system(nl_type
, &m
->containers
[0].type_system
);
98 m
->hdr
->nlmsg_len
= size
;
99 m
->hdr
->nlmsg_type
= type
;
106 int sd_netlink_message_request_dump(sd_netlink_message
*m
, int dump
) {
107 assert_return(m
, -EINVAL
);
108 assert_return(m
->hdr
, -EINVAL
);
110 assert_return(IN_SET(m
->hdr
->nlmsg_type
, RTM_GETLINK
, RTM_GETADDR
, RTM_GETROUTE
, RTM_GETNEIGH
, RTM_GETRULE
, RTM_GETADDRLABEL
), -EINVAL
);
112 SET_FLAG(m
->hdr
->nlmsg_flags
, NLM_F_DUMP
, dump
);
117 sd_netlink_message
*sd_netlink_message_ref(sd_netlink_message
*m
) {
121 assert_se(REFCNT_INC(m
->n_ref
) >= 2);
125 sd_netlink_message
*sd_netlink_message_unref(sd_netlink_message
*m
) {
126 sd_netlink_message
*t
;
128 while (m
&& REFCNT_DEC(m
->n_ref
) == 0) {
133 for (i
= 0; i
<= m
->n_containers
; i
++)
134 free(m
->containers
[i
].attributes
);
144 int sd_netlink_message_get_type(sd_netlink_message
*m
, uint16_t *type
) {
145 assert_return(m
, -EINVAL
);
146 assert_return(type
, -EINVAL
);
148 *type
= m
->hdr
->nlmsg_type
;
153 int sd_netlink_message_set_flags(sd_netlink_message
*m
, uint16_t flags
) {
154 assert_return(m
, -EINVAL
);
155 assert_return(flags
, -EINVAL
);
157 m
->hdr
->nlmsg_flags
= flags
;
162 int sd_netlink_message_is_broadcast(sd_netlink_message
*m
) {
163 assert_return(m
, -EINVAL
);
168 /* If successful the updated message will be correctly aligned, if
169 unsuccessful the old message is untouched. */
170 static int add_rtattr(sd_netlink_message
*m
, unsigned short type
, const void *data
, size_t data_length
) {
172 size_t message_length
, padding_length
;
173 struct nlmsghdr
*new_hdr
;
182 assert(NLMSG_ALIGN(m
->hdr
->nlmsg_len
) == m
->hdr
->nlmsg_len
);
183 assert(!data
|| data_length
);
185 /* get offset of the new attribute */
186 offset
= m
->hdr
->nlmsg_len
;
188 /* get the size of the new rta attribute (with padding at the end) */
189 rta_length
= RTA_LENGTH(data_length
);
191 /* get the new message size (with padding at the end) */
192 message_length
= offset
+ RTA_ALIGN(rta_length
);
194 /* buffer should be smaller than both one page or 8K to be accepted by the kernel */
195 if (message_length
> MIN(page_size(), 8192UL))
198 /* realloc to fit the new attribute */
199 new_hdr
= realloc(m
->hdr
, message_length
);
204 /* get pointer to the attribute we are about to add */
205 rta
= (struct rtattr
*) ((uint8_t *) m
->hdr
+ offset
);
207 /* if we are inside containers, extend them */
208 for (i
= 0; i
< m
->n_containers
; i
++)
209 GET_CONTAINER(m
, i
)->rta_len
+= message_length
- offset
;
211 /* fill in the attribute */
212 rta
->rta_type
= type
;
213 rta
->rta_len
= rta_length
;
215 /* we don't deal with the case where the user lies about the type
216 * and gives us too little data (so don't do that)
218 padding
= mempcpy(RTA_DATA(rta
), data
, data_length
);
221 /* if no data was passed, make sure we still initialize the padding
222 note that we can have data_length > 0 (used by some containers) */
223 padding
= RTA_DATA(rta
);
225 /* make sure also the padding at the end of the message is initialized */
226 padding_length
= (uint8_t*)m
->hdr
+ message_length
- (uint8_t*)padding
;
227 memzero(padding
, padding_length
);
229 /* update message size */
230 m
->hdr
->nlmsg_len
= message_length
;
235 static int message_attribute_has_type(sd_netlink_message
*m
, size_t *out_size
, uint16_t attribute_type
, uint16_t data_type
) {
241 r
= type_system_get_type(m
->containers
[m
->n_containers
].type_system
, &type
, attribute_type
);
245 if (type_get_type(type
) != data_type
)
249 *out_size
= type_get_size(type
);
253 int sd_netlink_message_append_string(sd_netlink_message
*m
, unsigned short type
, const char *data
) {
257 assert_return(m
, -EINVAL
);
258 assert_return(!m
->sealed
, -EPERM
);
259 assert_return(data
, -EINVAL
);
261 r
= message_attribute_has_type(m
, &size
, type
, NETLINK_TYPE_STRING
);
266 length
= strnlen(data
, size
+1);
270 length
= strlen(data
);
272 r
= add_rtattr(m
, type
, data
, length
+ 1);
279 int sd_netlink_message_append_flag(sd_netlink_message
*m
, unsigned short type
) {
283 assert_return(m
, -EINVAL
);
284 assert_return(!m
->sealed
, -EPERM
);
286 r
= message_attribute_has_type(m
, &size
, type
, NETLINK_TYPE_FLAG
);
290 r
= add_rtattr(m
, type
, NULL
, 0);
297 int sd_netlink_message_append_u8(sd_netlink_message
*m
, unsigned short type
, uint8_t data
) {
300 assert_return(m
, -EINVAL
);
301 assert_return(!m
->sealed
, -EPERM
);
303 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_U8
);
307 r
= add_rtattr(m
, type
, &data
, sizeof(uint8_t));
315 int sd_netlink_message_append_u16(sd_netlink_message
*m
, unsigned short type
, uint16_t data
) {
318 assert_return(m
, -EINVAL
);
319 assert_return(!m
->sealed
, -EPERM
);
321 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_U16
);
325 r
= add_rtattr(m
, type
, &data
, sizeof(uint16_t));
332 int sd_netlink_message_append_u32(sd_netlink_message
*m
, unsigned short type
, uint32_t data
) {
335 assert_return(m
, -EINVAL
);
336 assert_return(!m
->sealed
, -EPERM
);
338 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_U32
);
342 r
= add_rtattr(m
, type
, &data
, sizeof(uint32_t));
349 int sd_netlink_message_append_data(sd_netlink_message
*m
, unsigned short type
, const void *data
, size_t len
) {
352 assert_return(m
, -EINVAL
);
353 assert_return(!m
->sealed
, -EPERM
);
355 r
= add_rtattr(m
, type
, data
, len
);
362 int sd_netlink_message_append_in_addr(sd_netlink_message
*m
, unsigned short type
, const struct in_addr
*data
) {
365 assert_return(m
, -EINVAL
);
366 assert_return(!m
->sealed
, -EPERM
);
367 assert_return(data
, -EINVAL
);
369 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_IN_ADDR
);
373 r
= add_rtattr(m
, type
, data
, sizeof(struct in_addr
));
380 int sd_netlink_message_append_in6_addr(sd_netlink_message
*m
, unsigned short type
, const struct in6_addr
*data
) {
383 assert_return(m
, -EINVAL
);
384 assert_return(!m
->sealed
, -EPERM
);
385 assert_return(data
, -EINVAL
);
387 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_IN_ADDR
);
391 r
= add_rtattr(m
, type
, data
, sizeof(struct in6_addr
));
398 int sd_netlink_message_append_ether_addr(sd_netlink_message
*m
, unsigned short type
, const struct ether_addr
*data
) {
401 assert_return(m
, -EINVAL
);
402 assert_return(!m
->sealed
, -EPERM
);
403 assert_return(data
, -EINVAL
);
405 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_ETHER_ADDR
);
409 r
= add_rtattr(m
, type
, data
, ETH_ALEN
);
416 int sd_netlink_message_append_cache_info(sd_netlink_message
*m
, unsigned short type
, const struct ifa_cacheinfo
*info
) {
419 assert_return(m
, -EINVAL
);
420 assert_return(!m
->sealed
, -EPERM
);
421 assert_return(info
, -EINVAL
);
423 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_CACHE_INFO
);
427 r
= add_rtattr(m
, type
, info
, sizeof(struct ifa_cacheinfo
));
434 int sd_netlink_message_open_container(sd_netlink_message
*m
, unsigned short type
) {
438 assert_return(m
, -EINVAL
);
439 assert_return(!m
->sealed
, -EPERM
);
440 assert_return(m
->n_containers
< RTNL_CONTAINER_DEPTH
, -ERANGE
);
442 r
= message_attribute_has_type(m
, &size
, type
, NETLINK_TYPE_NESTED
);
444 const NLTypeSystemUnion
*type_system_union
;
447 r
= message_attribute_has_type(m
, &size
, type
, NETLINK_TYPE_UNION
);
451 r
= sd_rtnl_message_get_family(m
, &family
);
455 r
= type_system_get_type_system_union(m
->containers
[m
->n_containers
].type_system
, &type_system_union
, type
);
459 r
= type_system_union_protocol_get_type_system(type_system_union
,
460 &m
->containers
[m
->n_containers
+ 1].type_system
,
465 r
= type_system_get_type_system(m
->containers
[m
->n_containers
].type_system
,
466 &m
->containers
[m
->n_containers
+ 1].type_system
,
472 r
= add_rtattr(m
, type
| NLA_F_NESTED
, NULL
, size
);
476 m
->containers
[m
->n_containers
++].offset
= r
;
481 int sd_netlink_message_open_container_union(sd_netlink_message
*m
, unsigned short type
, const char *key
) {
482 const NLTypeSystemUnion
*type_system_union
;
485 assert_return(m
, -EINVAL
);
486 assert_return(!m
->sealed
, -EPERM
);
488 r
= type_system_get_type_system_union(m
->containers
[m
->n_containers
].type_system
, &type_system_union
, type
);
492 r
= type_system_union_get_type_system(type_system_union
,
493 &m
->containers
[m
->n_containers
+ 1].type_system
,
498 r
= sd_netlink_message_append_string(m
, type_system_union
->match
, key
);
502 /* do we ever need non-null size */
503 r
= add_rtattr(m
, type
| NLA_F_NESTED
, NULL
, 0);
507 m
->containers
[m
->n_containers
++].offset
= r
;
512 int sd_netlink_message_close_container(sd_netlink_message
*m
) {
513 assert_return(m
, -EINVAL
);
514 assert_return(!m
->sealed
, -EPERM
);
515 assert_return(m
->n_containers
> 0, -EINVAL
);
517 m
->containers
[m
->n_containers
].type_system
= NULL
;
518 m
->containers
[m
->n_containers
].offset
= 0;
524 int sd_netlink_message_open_array(sd_netlink_message
*m
, uint16_t type
) {
527 assert_return(m
, -EINVAL
);
528 assert_return(!m
->sealed
, -EPERM
);
529 assert_return(m
->n_containers
> 0, -EINVAL
);
531 r
= add_rtattr(m
, type
| NLA_F_NESTED
, NULL
, 0);
535 m
->containers
[m
->n_containers
].offset
= r
;
537 m
->containers
[m
->n_containers
].type_system
= m
->containers
[m
->n_containers
- 1].type_system
;
542 int sd_netlink_message_cancel_array(sd_netlink_message
*m
) {
546 assert_return(m
, -EINVAL
);
547 assert_return(!m
->sealed
, -EPERM
);
548 assert_return(m
->n_containers
> 1, -EINVAL
);
550 rta_len
= GET_CONTAINER(m
, (m
->n_containers
- 1))->rta_len
;
552 for (i
= 0; i
< m
->n_containers
; i
++)
553 GET_CONTAINER(m
, i
)->rta_len
-= rta_len
;
555 m
->hdr
->nlmsg_len
-= rta_len
;
558 m
->containers
[m
->n_containers
].type_system
= NULL
;
563 static int netlink_message_read_internal(sd_netlink_message
*m
, unsigned short type
, void **data
, bool *net_byteorder
) {
564 struct netlink_attribute
*attribute
;
567 assert_return(m
, -EINVAL
);
568 assert_return(m
->sealed
, -EPERM
);
569 assert_return(data
, -EINVAL
);
571 assert(m
->n_containers
< RTNL_CONTAINER_DEPTH
);
572 assert(m
->containers
[m
->n_containers
].attributes
);
573 assert(type
< m
->containers
[m
->n_containers
].n_attributes
);
575 attribute
= &m
->containers
[m
->n_containers
].attributes
[type
];
577 if (attribute
->offset
== 0)
580 rta
= (struct rtattr
*)((uint8_t *) m
->hdr
+ attribute
->offset
);
582 *data
= RTA_DATA(rta
);
585 *net_byteorder
= attribute
->net_byteorder
;
587 return RTA_PAYLOAD(rta
);
590 int sd_netlink_message_read_string(sd_netlink_message
*m
, unsigned short type
, const char **data
) {
594 assert_return(m
, -EINVAL
);
596 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_STRING
);
600 r
= netlink_message_read_internal(m
, type
, &attr_data
, NULL
);
603 else if (strnlen(attr_data
, r
) >= (size_t) r
)
607 *data
= (const char *) attr_data
;
612 int sd_netlink_message_read_u8(sd_netlink_message
*m
, unsigned short type
, uint8_t *data
) {
616 assert_return(m
, -EINVAL
);
618 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_U8
);
622 r
= netlink_message_read_internal(m
, type
, &attr_data
, NULL
);
625 else if ((size_t) r
< sizeof(uint8_t))
629 *data
= *(uint8_t *) attr_data
;
634 int sd_netlink_message_read_u16(sd_netlink_message
*m
, unsigned short type
, uint16_t *data
) {
639 assert_return(m
, -EINVAL
);
641 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_U16
);
645 r
= netlink_message_read_internal(m
, type
, &attr_data
, &net_byteorder
);
648 else if ((size_t) r
< sizeof(uint16_t))
653 *data
= be16toh(*(uint16_t *) attr_data
);
655 *data
= *(uint16_t *) attr_data
;
661 int sd_netlink_message_read_u32(sd_netlink_message
*m
, unsigned short type
, uint32_t *data
) {
666 assert_return(m
, -EINVAL
);
668 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_U32
);
672 r
= netlink_message_read_internal(m
, type
, &attr_data
, &net_byteorder
);
675 else if ((size_t)r
< sizeof(uint32_t))
680 *data
= be32toh(*(uint32_t *) attr_data
);
682 *data
= *(uint32_t *) attr_data
;
688 int sd_netlink_message_read_ether_addr(sd_netlink_message
*m
, unsigned short type
, struct ether_addr
*data
) {
692 assert_return(m
, -EINVAL
);
694 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_ETHER_ADDR
);
698 r
= netlink_message_read_internal(m
, type
, &attr_data
, NULL
);
701 else if ((size_t)r
< sizeof(struct ether_addr
))
705 memcpy(data
, attr_data
, sizeof(struct ether_addr
));
710 int sd_netlink_message_read_cache_info(sd_netlink_message
*m
, unsigned short type
, struct ifa_cacheinfo
*info
) {
714 assert_return(m
, -EINVAL
);
716 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_CACHE_INFO
);
720 r
= netlink_message_read_internal(m
, type
, &attr_data
, NULL
);
723 else if ((size_t)r
< sizeof(struct ifa_cacheinfo
))
727 memcpy(info
, attr_data
, sizeof(struct ifa_cacheinfo
));
732 int sd_netlink_message_read_in_addr(sd_netlink_message
*m
, unsigned short type
, struct in_addr
*data
) {
736 assert_return(m
, -EINVAL
);
738 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_IN_ADDR
);
742 r
= netlink_message_read_internal(m
, type
, &attr_data
, NULL
);
745 else if ((size_t)r
< sizeof(struct in_addr
))
749 memcpy(data
, attr_data
, sizeof(struct in_addr
));
754 int sd_netlink_message_read_in6_addr(sd_netlink_message
*m
, unsigned short type
, struct in6_addr
*data
) {
758 assert_return(m
, -EINVAL
);
760 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_IN_ADDR
);
764 r
= netlink_message_read_internal(m
, type
, &attr_data
, NULL
);
767 else if ((size_t)r
< sizeof(struct in6_addr
))
771 memcpy(data
, attr_data
, sizeof(struct in6_addr
));
776 static int netlink_container_parse(sd_netlink_message
*m
,
777 struct netlink_container
*container
,
780 unsigned int rt_len
) {
781 _cleanup_free_
struct netlink_attribute
*attributes
= NULL
;
783 attributes
= new0(struct netlink_attribute
, count
);
787 for (; RTA_OK(rta
, rt_len
); rta
= RTA_NEXT(rta
, rt_len
)) {
790 type
= RTA_TYPE(rta
);
792 /* if the kernel is newer than the headers we used
793 when building, we ignore out-of-range attributes */
797 if (attributes
[type
].offset
!= 0)
798 log_debug("rtnl: message parse - overwriting repeated attribute");
800 attributes
[type
].offset
= (uint8_t *) rta
- (uint8_t *) m
->hdr
;
801 attributes
[type
].nested
= RTA_FLAGS(rta
) & NLA_F_NESTED
;
802 attributes
[type
].net_byteorder
= RTA_FLAGS(rta
) & NLA_F_NET_BYTEORDER
;
805 container
->attributes
= TAKE_PTR(attributes
);
806 container
->n_attributes
= count
;
811 int sd_netlink_message_enter_container(sd_netlink_message
*m
, unsigned short type_id
) {
812 const NLType
*nl_type
;
813 const NLTypeSystem
*type_system
;
819 assert_return(m
, -EINVAL
);
820 assert_return(m
->n_containers
< RTNL_CONTAINER_DEPTH
, -EINVAL
);
822 r
= type_system_get_type(m
->containers
[m
->n_containers
].type_system
,
828 type
= type_get_type(nl_type
);
830 if (type
== NETLINK_TYPE_NESTED
) {
831 r
= type_system_get_type_system(m
->containers
[m
->n_containers
].type_system
,
836 } else if (type
== NETLINK_TYPE_UNION
) {
837 const NLTypeSystemUnion
*type_system_union
;
839 r
= type_system_get_type_system_union(m
->containers
[m
->n_containers
].type_system
,
845 switch (type_system_union
->match_type
) {
846 case NL_MATCH_SIBLING
:
850 r
= sd_netlink_message_read_string(m
, type_system_union
->match
, &key
);
854 r
= type_system_union_get_type_system(type_system_union
,
862 case NL_MATCH_PROTOCOL
:
866 r
= sd_rtnl_message_get_family(m
, &family
);
870 r
= type_system_union_protocol_get_type_system(type_system_union
,
879 assert_not_reached("sd-netlink: invalid type system union type");
884 r
= netlink_message_read_internal(m
, type_id
, &container
, NULL
);
892 r
= netlink_container_parse(m
,
893 &m
->containers
[m
->n_containers
],
894 type_system_get_count(type_system
),
902 m
->containers
[m
->n_containers
].type_system
= type_system
;
907 int sd_netlink_message_exit_container(sd_netlink_message
*m
) {
908 assert_return(m
, -EINVAL
);
909 assert_return(m
->sealed
, -EINVAL
);
910 assert_return(m
->n_containers
> 0, -EINVAL
);
912 m
->containers
[m
->n_containers
].attributes
= mfree(m
->containers
[m
->n_containers
].attributes
);
913 m
->containers
[m
->n_containers
].type_system
= NULL
;
920 uint32_t rtnl_message_get_serial(sd_netlink_message
*m
) {
924 return m
->hdr
->nlmsg_seq
;
927 int sd_netlink_message_is_error(sd_netlink_message
*m
) {
929 assert_return(m
->hdr
, 0);
931 return m
->hdr
->nlmsg_type
== NLMSG_ERROR
;
934 int sd_netlink_message_get_errno(sd_netlink_message
*m
) {
935 struct nlmsgerr
*err
;
937 assert_return(m
, -EINVAL
);
938 assert_return(m
->hdr
, -EINVAL
);
940 if (!sd_netlink_message_is_error(m
))
943 err
= NLMSG_DATA(m
->hdr
);
948 int sd_netlink_message_rewind(sd_netlink_message
*m
) {
949 const NLType
*nl_type
;
950 const NLTypeSystem
*type_system_root
;
956 assert_return(m
, -EINVAL
);
958 /* don't allow appending to message once parsed */
960 rtnl_message_seal(m
);
962 type_system_root
= type_system_get_root(m
->protocol
);
964 for (i
= 1; i
<= m
->n_containers
; i
++)
965 m
->containers
[i
].attributes
= mfree(m
->containers
[i
].attributes
);
969 if (m
->containers
[0].attributes
)
970 /* top-level attributes have already been parsed */
975 r
= type_system_get_type(type_system_root
, &nl_type
, m
->hdr
->nlmsg_type
);
979 type
= type_get_type(nl_type
);
980 size
= type_get_size(nl_type
);
982 if (type
== NETLINK_TYPE_NESTED
) {
983 const NLTypeSystem
*type_system
;
985 type_get_type_system(nl_type
, &type_system
);
987 m
->containers
[0].type_system
= type_system
;
989 r
= netlink_container_parse(m
,
990 &m
->containers
[m
->n_containers
],
991 type_system_get_count(type_system
),
992 (struct rtattr
*)((uint8_t*)NLMSG_DATA(m
->hdr
) + NLMSG_ALIGN(size
)),
993 NLMSG_PAYLOAD(m
->hdr
, size
));
1001 void rtnl_message_seal(sd_netlink_message
*m
) {
1008 sd_netlink_message
*sd_netlink_message_next(sd_netlink_message
*m
) {
1009 assert_return(m
, NULL
);