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
;
107 int sd_netlink_message_request_dump(sd_netlink_message
*m
, int dump
) {
108 assert_return(m
, -EINVAL
);
109 assert_return(m
->hdr
, -EINVAL
);
111 assert_return(IN_SET(m
->hdr
->nlmsg_type
, RTM_GETLINK
, RTM_GETADDR
, RTM_GETROUTE
, RTM_GETNEIGH
, RTM_GETRULE
, RTM_GETADDRLABEL
), -EINVAL
);
113 SET_FLAG(m
->hdr
->nlmsg_flags
, NLM_F_DUMP
, dump
);
118 sd_netlink_message
*sd_netlink_message_ref(sd_netlink_message
*m
) {
122 assert_se(REFCNT_INC(m
->n_ref
) >= 2);
126 sd_netlink_message
*sd_netlink_message_unref(sd_netlink_message
*m
) {
127 sd_netlink_message
*t
;
129 while (m
&& REFCNT_DEC(m
->n_ref
) == 0) {
134 for (i
= 0; i
<= m
->n_containers
; i
++)
135 free(m
->containers
[i
].attributes
);
145 int sd_netlink_message_get_type(sd_netlink_message
*m
, uint16_t *type
) {
146 assert_return(m
, -EINVAL
);
147 assert_return(type
, -EINVAL
);
149 *type
= m
->hdr
->nlmsg_type
;
154 int sd_netlink_message_set_flags(sd_netlink_message
*m
, uint16_t flags
) {
155 assert_return(m
, -EINVAL
);
156 assert_return(flags
, -EINVAL
);
158 m
->hdr
->nlmsg_flags
= flags
;
163 int sd_netlink_message_is_broadcast(sd_netlink_message
*m
) {
164 assert_return(m
, -EINVAL
);
169 /* If successful the updated message will be correctly aligned, if
170 unsuccessful the old message is untouched. */
171 static int add_rtattr(sd_netlink_message
*m
, unsigned short type
, const void *data
, size_t data_length
) {
173 size_t message_length
, padding_length
;
174 struct nlmsghdr
*new_hdr
;
183 assert(NLMSG_ALIGN(m
->hdr
->nlmsg_len
) == m
->hdr
->nlmsg_len
);
184 assert(!data
|| data_length
);
186 /* get offset of the new attribute */
187 offset
= m
->hdr
->nlmsg_len
;
189 /* get the size of the new rta attribute (with padding at the end) */
190 rta_length
= RTA_LENGTH(data_length
);
192 /* get the new message size (with padding at the end) */
193 message_length
= offset
+ RTA_ALIGN(rta_length
);
195 /* buffer should be smaller than both one page or 8K to be accepted by the kernel */
196 if (message_length
> MIN(page_size(), 8192UL))
199 /* realloc to fit the new attribute */
200 new_hdr
= realloc(m
->hdr
, message_length
);
205 /* get pointer to the attribute we are about to add */
206 rta
= (struct rtattr
*) ((uint8_t *) m
->hdr
+ offset
);
208 /* if we are inside containers, extend them */
209 for (i
= 0; i
< m
->n_containers
; i
++)
210 GET_CONTAINER(m
, i
)->rta_len
+= message_length
- offset
;
212 /* fill in the attribute */
213 rta
->rta_type
= type
;
214 rta
->rta_len
= rta_length
;
216 /* we don't deal with the case where the user lies about the type
217 * and gives us too little data (so don't do that)
219 padding
= mempcpy(RTA_DATA(rta
), data
, data_length
);
222 /* if no data was passed, make sure we still initialize the padding
223 note that we can have data_length > 0 (used by some containers) */
224 padding
= RTA_DATA(rta
);
226 /* make sure also the padding at the end of the message is initialized */
227 padding_length
= (uint8_t*)m
->hdr
+ message_length
- (uint8_t*)padding
;
228 memzero(padding
, padding_length
);
230 /* update message size */
231 m
->hdr
->nlmsg_len
= message_length
;
236 static int message_attribute_has_type(sd_netlink_message
*m
, size_t *out_size
, uint16_t attribute_type
, uint16_t data_type
) {
242 r
= type_system_get_type(m
->containers
[m
->n_containers
].type_system
, &type
, attribute_type
);
246 if (type_get_type(type
) != data_type
)
250 *out_size
= type_get_size(type
);
254 int sd_netlink_message_append_string(sd_netlink_message
*m
, unsigned short type
, const char *data
) {
258 assert_return(m
, -EINVAL
);
259 assert_return(!m
->sealed
, -EPERM
);
260 assert_return(data
, -EINVAL
);
262 r
= message_attribute_has_type(m
, &size
, type
, NETLINK_TYPE_STRING
);
267 length
= strnlen(data
, size
+1);
271 length
= strlen(data
);
273 r
= add_rtattr(m
, type
, data
, length
+ 1);
280 int sd_netlink_message_append_flag(sd_netlink_message
*m
, unsigned short type
) {
284 assert_return(m
, -EINVAL
);
285 assert_return(!m
->sealed
, -EPERM
);
287 r
= message_attribute_has_type(m
, &size
, type
, NETLINK_TYPE_FLAG
);
291 r
= add_rtattr(m
, type
, NULL
, 0);
298 int sd_netlink_message_append_u8(sd_netlink_message
*m
, unsigned short type
, uint8_t data
) {
301 assert_return(m
, -EINVAL
);
302 assert_return(!m
->sealed
, -EPERM
);
304 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_U8
);
308 r
= add_rtattr(m
, type
, &data
, sizeof(uint8_t));
316 int sd_netlink_message_append_u16(sd_netlink_message
*m
, unsigned short type
, uint16_t data
) {
319 assert_return(m
, -EINVAL
);
320 assert_return(!m
->sealed
, -EPERM
);
322 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_U16
);
326 r
= add_rtattr(m
, type
, &data
, sizeof(uint16_t));
333 int sd_netlink_message_append_u32(sd_netlink_message
*m
, unsigned short type
, uint32_t data
) {
336 assert_return(m
, -EINVAL
);
337 assert_return(!m
->sealed
, -EPERM
);
339 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_U32
);
343 r
= add_rtattr(m
, type
, &data
, sizeof(uint32_t));
350 int sd_netlink_message_append_data(sd_netlink_message
*m
, unsigned short type
, const void *data
, size_t len
) {
353 assert_return(m
, -EINVAL
);
354 assert_return(!m
->sealed
, -EPERM
);
356 r
= add_rtattr(m
, type
, data
, len
);
363 int sd_netlink_message_append_in_addr(sd_netlink_message
*m
, unsigned short type
, const struct in_addr
*data
) {
366 assert_return(m
, -EINVAL
);
367 assert_return(!m
->sealed
, -EPERM
);
368 assert_return(data
, -EINVAL
);
370 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_IN_ADDR
);
374 r
= add_rtattr(m
, type
, data
, sizeof(struct in_addr
));
381 int sd_netlink_message_append_in6_addr(sd_netlink_message
*m
, unsigned short type
, const struct in6_addr
*data
) {
384 assert_return(m
, -EINVAL
);
385 assert_return(!m
->sealed
, -EPERM
);
386 assert_return(data
, -EINVAL
);
388 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_IN_ADDR
);
392 r
= add_rtattr(m
, type
, data
, sizeof(struct in6_addr
));
399 int sd_netlink_message_append_ether_addr(sd_netlink_message
*m
, unsigned short type
, const struct ether_addr
*data
) {
402 assert_return(m
, -EINVAL
);
403 assert_return(!m
->sealed
, -EPERM
);
404 assert_return(data
, -EINVAL
);
406 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_ETHER_ADDR
);
410 r
= add_rtattr(m
, type
, data
, ETH_ALEN
);
417 int sd_netlink_message_append_cache_info(sd_netlink_message
*m
, unsigned short type
, const struct ifa_cacheinfo
*info
) {
420 assert_return(m
, -EINVAL
);
421 assert_return(!m
->sealed
, -EPERM
);
422 assert_return(info
, -EINVAL
);
424 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_CACHE_INFO
);
428 r
= add_rtattr(m
, type
, info
, sizeof(struct ifa_cacheinfo
));
435 int sd_netlink_message_open_container(sd_netlink_message
*m
, unsigned short type
) {
439 assert_return(m
, -EINVAL
);
440 assert_return(!m
->sealed
, -EPERM
);
441 assert_return(m
->n_containers
< RTNL_CONTAINER_DEPTH
, -ERANGE
);
443 r
= message_attribute_has_type(m
, &size
, type
, NETLINK_TYPE_NESTED
);
445 const NLTypeSystemUnion
*type_system_union
;
448 r
= message_attribute_has_type(m
, &size
, type
, NETLINK_TYPE_UNION
);
452 r
= sd_rtnl_message_get_family(m
, &family
);
456 r
= type_system_get_type_system_union(m
->containers
[m
->n_containers
].type_system
, &type_system_union
, type
);
460 r
= type_system_union_protocol_get_type_system(type_system_union
,
461 &m
->containers
[m
->n_containers
+ 1].type_system
,
466 r
= type_system_get_type_system(m
->containers
[m
->n_containers
].type_system
,
467 &m
->containers
[m
->n_containers
+ 1].type_system
,
473 r
= add_rtattr(m
, type
| NLA_F_NESTED
, NULL
, size
);
477 m
->containers
[m
->n_containers
++].offset
= r
;
482 int sd_netlink_message_open_container_union(sd_netlink_message
*m
, unsigned short type
, const char *key
) {
483 const NLTypeSystemUnion
*type_system_union
;
486 assert_return(m
, -EINVAL
);
487 assert_return(!m
->sealed
, -EPERM
);
489 r
= type_system_get_type_system_union(m
->containers
[m
->n_containers
].type_system
, &type_system_union
, type
);
493 r
= type_system_union_get_type_system(type_system_union
,
494 &m
->containers
[m
->n_containers
+ 1].type_system
,
499 r
= sd_netlink_message_append_string(m
, type_system_union
->match
, key
);
503 /* do we ever need non-null size */
504 r
= add_rtattr(m
, type
| NLA_F_NESTED
, NULL
, 0);
508 m
->containers
[m
->n_containers
++].offset
= r
;
513 int sd_netlink_message_close_container(sd_netlink_message
*m
) {
514 assert_return(m
, -EINVAL
);
515 assert_return(!m
->sealed
, -EPERM
);
516 assert_return(m
->n_containers
> 0, -EINVAL
);
518 m
->containers
[m
->n_containers
].type_system
= NULL
;
519 m
->containers
[m
->n_containers
].offset
= 0;
525 int sd_netlink_message_open_array(sd_netlink_message
*m
, uint16_t type
) {
528 assert_return(m
, -EINVAL
);
529 assert_return(!m
->sealed
, -EPERM
);
530 assert_return(m
->n_containers
> 0, -EINVAL
);
532 r
= add_rtattr(m
, type
| NLA_F_NESTED
, NULL
, 0);
536 m
->containers
[m
->n_containers
].offset
= r
;
538 m
->containers
[m
->n_containers
].type_system
= m
->containers
[m
->n_containers
- 1].type_system
;
543 int sd_netlink_message_cancel_array(sd_netlink_message
*m
) {
547 assert_return(m
, -EINVAL
);
548 assert_return(!m
->sealed
, -EPERM
);
549 assert_return(m
->n_containers
> 1, -EINVAL
);
551 rta_len
= GET_CONTAINER(m
, (m
->n_containers
- 1))->rta_len
;
553 for (i
= 0; i
< m
->n_containers
; i
++)
554 GET_CONTAINER(m
, i
)->rta_len
-= rta_len
;
556 m
->hdr
->nlmsg_len
-= rta_len
;
559 m
->containers
[m
->n_containers
].type_system
= NULL
;
564 static int netlink_message_read_internal(sd_netlink_message
*m
, unsigned short type
, void **data
, bool *net_byteorder
) {
565 struct netlink_attribute
*attribute
;
568 assert_return(m
, -EINVAL
);
569 assert_return(m
->sealed
, -EPERM
);
570 assert_return(data
, -EINVAL
);
572 assert(m
->n_containers
< RTNL_CONTAINER_DEPTH
);
573 assert(m
->containers
[m
->n_containers
].attributes
);
574 assert(type
< m
->containers
[m
->n_containers
].n_attributes
);
576 attribute
= &m
->containers
[m
->n_containers
].attributes
[type
];
578 if (attribute
->offset
== 0)
581 rta
= (struct rtattr
*)((uint8_t *) m
->hdr
+ attribute
->offset
);
583 *data
= RTA_DATA(rta
);
586 *net_byteorder
= attribute
->net_byteorder
;
588 return RTA_PAYLOAD(rta
);
591 int sd_netlink_message_read_string(sd_netlink_message
*m
, unsigned short type
, const char **data
) {
595 assert_return(m
, -EINVAL
);
597 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_STRING
);
601 r
= netlink_message_read_internal(m
, type
, &attr_data
, NULL
);
604 else if (strnlen(attr_data
, r
) >= (size_t) r
)
608 *data
= (const char *) attr_data
;
613 int sd_netlink_message_read_u8(sd_netlink_message
*m
, unsigned short type
, uint8_t *data
) {
617 assert_return(m
, -EINVAL
);
619 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_U8
);
623 r
= netlink_message_read_internal(m
, type
, &attr_data
, NULL
);
626 else if ((size_t) r
< sizeof(uint8_t))
630 *data
= *(uint8_t *) attr_data
;
635 int sd_netlink_message_read_u16(sd_netlink_message
*m
, unsigned short type
, uint16_t *data
) {
640 assert_return(m
, -EINVAL
);
642 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_U16
);
646 r
= netlink_message_read_internal(m
, type
, &attr_data
, &net_byteorder
);
649 else if ((size_t) r
< sizeof(uint16_t))
654 *data
= be16toh(*(uint16_t *) attr_data
);
656 *data
= *(uint16_t *) attr_data
;
662 int sd_netlink_message_read_u32(sd_netlink_message
*m
, unsigned short type
, uint32_t *data
) {
667 assert_return(m
, -EINVAL
);
669 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_U32
);
673 r
= netlink_message_read_internal(m
, type
, &attr_data
, &net_byteorder
);
676 else if ((size_t)r
< sizeof(uint32_t))
681 *data
= be32toh(*(uint32_t *) attr_data
);
683 *data
= *(uint32_t *) attr_data
;
689 int sd_netlink_message_read_ether_addr(sd_netlink_message
*m
, unsigned short type
, struct ether_addr
*data
) {
693 assert_return(m
, -EINVAL
);
695 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_ETHER_ADDR
);
699 r
= netlink_message_read_internal(m
, type
, &attr_data
, NULL
);
702 else if ((size_t)r
< sizeof(struct ether_addr
))
706 memcpy(data
, attr_data
, sizeof(struct ether_addr
));
711 int sd_netlink_message_read_cache_info(sd_netlink_message
*m
, unsigned short type
, struct ifa_cacheinfo
*info
) {
715 assert_return(m
, -EINVAL
);
717 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_CACHE_INFO
);
721 r
= netlink_message_read_internal(m
, type
, &attr_data
, NULL
);
724 else if ((size_t)r
< sizeof(struct ifa_cacheinfo
))
728 memcpy(info
, attr_data
, sizeof(struct ifa_cacheinfo
));
733 int sd_netlink_message_read_in_addr(sd_netlink_message
*m
, unsigned short type
, struct in_addr
*data
) {
737 assert_return(m
, -EINVAL
);
739 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_IN_ADDR
);
743 r
= netlink_message_read_internal(m
, type
, &attr_data
, NULL
);
746 else if ((size_t)r
< sizeof(struct in_addr
))
750 memcpy(data
, attr_data
, sizeof(struct in_addr
));
755 int sd_netlink_message_read_in6_addr(sd_netlink_message
*m
, unsigned short type
, struct in6_addr
*data
) {
759 assert_return(m
, -EINVAL
);
761 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_IN_ADDR
);
765 r
= netlink_message_read_internal(m
, type
, &attr_data
, NULL
);
768 else if ((size_t)r
< sizeof(struct in6_addr
))
772 memcpy(data
, attr_data
, sizeof(struct in6_addr
));
777 static int netlink_container_parse(sd_netlink_message
*m
,
778 struct netlink_container
*container
,
781 unsigned int rt_len
) {
782 _cleanup_free_
struct netlink_attribute
*attributes
= NULL
;
784 attributes
= new0(struct netlink_attribute
, count
);
788 for (; RTA_OK(rta
, rt_len
); rta
= RTA_NEXT(rta
, rt_len
)) {
791 type
= RTA_TYPE(rta
);
793 /* if the kernel is newer than the headers we used
794 when building, we ignore out-of-range attributes */
798 if (attributes
[type
].offset
!= 0)
799 log_debug("rtnl: message parse - overwriting repeated attribute");
801 attributes
[type
].offset
= (uint8_t *) rta
- (uint8_t *) m
->hdr
;
802 attributes
[type
].nested
= RTA_FLAGS(rta
) & NLA_F_NESTED
;
803 attributes
[type
].net_byteorder
= RTA_FLAGS(rta
) & NLA_F_NET_BYTEORDER
;
806 container
->attributes
= TAKE_PTR(attributes
);
807 container
->n_attributes
= count
;
812 int sd_netlink_message_enter_container(sd_netlink_message
*m
, unsigned short type_id
) {
813 const NLType
*nl_type
;
814 const NLTypeSystem
*type_system
;
820 assert_return(m
, -EINVAL
);
821 assert_return(m
->n_containers
< RTNL_CONTAINER_DEPTH
, -EINVAL
);
823 r
= type_system_get_type(m
->containers
[m
->n_containers
].type_system
,
829 type
= type_get_type(nl_type
);
831 if (type
== NETLINK_TYPE_NESTED
) {
832 r
= type_system_get_type_system(m
->containers
[m
->n_containers
].type_system
,
837 } else if (type
== NETLINK_TYPE_UNION
) {
838 const NLTypeSystemUnion
*type_system_union
;
840 r
= type_system_get_type_system_union(m
->containers
[m
->n_containers
].type_system
,
846 switch (type_system_union
->match_type
) {
847 case NL_MATCH_SIBLING
:
851 r
= sd_netlink_message_read_string(m
, type_system_union
->match
, &key
);
855 r
= type_system_union_get_type_system(type_system_union
,
863 case NL_MATCH_PROTOCOL
:
867 r
= sd_rtnl_message_get_family(m
, &family
);
871 r
= type_system_union_protocol_get_type_system(type_system_union
,
880 assert_not_reached("sd-netlink: invalid type system union type");
885 r
= netlink_message_read_internal(m
, type_id
, &container
, NULL
);
893 r
= netlink_container_parse(m
,
894 &m
->containers
[m
->n_containers
],
895 type_system_get_count(type_system
),
903 m
->containers
[m
->n_containers
].type_system
= type_system
;
908 int sd_netlink_message_exit_container(sd_netlink_message
*m
) {
909 assert_return(m
, -EINVAL
);
910 assert_return(m
->sealed
, -EINVAL
);
911 assert_return(m
->n_containers
> 0, -EINVAL
);
913 m
->containers
[m
->n_containers
].attributes
= mfree(m
->containers
[m
->n_containers
].attributes
);
914 m
->containers
[m
->n_containers
].type_system
= NULL
;
921 uint32_t rtnl_message_get_serial(sd_netlink_message
*m
) {
925 return m
->hdr
->nlmsg_seq
;
928 int sd_netlink_message_is_error(sd_netlink_message
*m
) {
930 assert_return(m
->hdr
, 0);
932 return m
->hdr
->nlmsg_type
== NLMSG_ERROR
;
935 int sd_netlink_message_get_errno(sd_netlink_message
*m
) {
936 struct nlmsgerr
*err
;
938 assert_return(m
, -EINVAL
);
939 assert_return(m
->hdr
, -EINVAL
);
941 if (!sd_netlink_message_is_error(m
))
944 err
= NLMSG_DATA(m
->hdr
);
949 int sd_netlink_message_rewind(sd_netlink_message
*m
) {
950 const NLType
*nl_type
;
951 const NLTypeSystem
*type_system_root
;
957 assert_return(m
, -EINVAL
);
959 /* don't allow appending to message once parsed */
961 rtnl_message_seal(m
);
963 type_system_root
= type_system_get_root(m
->protocol
);
965 for (i
= 1; i
<= m
->n_containers
; i
++)
966 m
->containers
[i
].attributes
= mfree(m
->containers
[i
].attributes
);
970 if (m
->containers
[0].attributes
)
971 /* top-level attributes have already been parsed */
976 r
= type_system_get_type(type_system_root
, &nl_type
, m
->hdr
->nlmsg_type
);
980 type
= type_get_type(nl_type
);
981 size
= type_get_size(nl_type
);
983 if (type
== NETLINK_TYPE_NESTED
) {
984 const NLTypeSystem
*type_system
;
986 type_get_type_system(nl_type
, &type_system
);
988 m
->containers
[0].type_system
= type_system
;
990 r
= netlink_container_parse(m
,
991 &m
->containers
[m
->n_containers
],
992 type_system_get_count(type_system
),
993 (struct rtattr
*)((uint8_t*)NLMSG_DATA(m
->hdr
) + NLMSG_ALIGN(size
)),
994 NLMSG_PAYLOAD(m
->hdr
, size
));
1002 void rtnl_message_seal(sd_netlink_message
*m
) {
1009 sd_netlink_message
*sd_netlink_message_next(sd_netlink_message
*m
) {
1010 assert_return(m
, NULL
);