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 netlink_message_append_in_addr_union(sd_netlink_message
*m
, unsigned short type
, int family
, const union in_addr_union
*data
) {
340 assert_return(m
, -EINVAL
);
341 assert_return(!m
->sealed
, -EPERM
);
342 assert_return(data
, -EINVAL
);
343 assert_return(IN_SET(family
, AF_INET
, AF_INET6
), -EINVAL
);
345 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_IN_ADDR
);
349 r
= add_rtattr(m
, type
, data
, FAMILY_ADDRESS_SIZE(family
));
356 int sd_netlink_message_append_in_addr(sd_netlink_message
*m
, unsigned short type
, const struct in_addr
*data
) {
357 return netlink_message_append_in_addr_union(m
, type
, AF_INET
, (const union in_addr_union
*) data
);
360 int sd_netlink_message_append_in6_addr(sd_netlink_message
*m
, unsigned short type
, const struct in6_addr
*data
) {
361 return netlink_message_append_in_addr_union(m
, type
, AF_INET6
, (const union in_addr_union
*) data
);
364 int netlink_message_append_sockaddr_union(sd_netlink_message
*m
, unsigned short type
, const union sockaddr_union
*data
) {
367 assert_return(m
, -EINVAL
);
368 assert_return(!m
->sealed
, -EPERM
);
369 assert_return(data
, -EINVAL
);
370 assert_return(IN_SET(data
->sa
.sa_family
, AF_INET
, AF_INET6
), -EINVAL
);
372 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_SOCKADDR
);
376 r
= add_rtattr(m
, type
, data
, data
->sa
.sa_family
== AF_INET
? sizeof(struct sockaddr_in
) : sizeof(struct sockaddr_in6
));
383 int sd_netlink_message_append_sockaddr_in(sd_netlink_message
*m
, unsigned short type
, const struct sockaddr_in
*data
) {
384 return netlink_message_append_sockaddr_union(m
, type
, (const union sockaddr_union
*) data
);
387 int sd_netlink_message_append_sockaddr_in6(sd_netlink_message
*m
, unsigned short type
, const struct sockaddr_in6
*data
) {
388 return netlink_message_append_sockaddr_union(m
, type
, (const union sockaddr_union
*) data
);
392 int sd_netlink_message_append_ether_addr(sd_netlink_message
*m
, unsigned short type
, const struct ether_addr
*data
) {
395 assert_return(m
, -EINVAL
);
396 assert_return(!m
->sealed
, -EPERM
);
397 assert_return(data
, -EINVAL
);
399 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_ETHER_ADDR
);
403 r
= add_rtattr(m
, type
, data
, ETH_ALEN
);
410 int sd_netlink_message_append_cache_info(sd_netlink_message
*m
, unsigned short type
, const struct ifa_cacheinfo
*info
) {
413 assert_return(m
, -EINVAL
);
414 assert_return(!m
->sealed
, -EPERM
);
415 assert_return(info
, -EINVAL
);
417 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_CACHE_INFO
);
421 r
= add_rtattr(m
, type
, info
, sizeof(struct ifa_cacheinfo
));
428 int sd_netlink_message_open_container(sd_netlink_message
*m
, unsigned short type
) {
432 assert_return(m
, -EINVAL
);
433 assert_return(!m
->sealed
, -EPERM
);
434 assert_return(m
->n_containers
< RTNL_CONTAINER_DEPTH
, -ERANGE
);
436 r
= message_attribute_has_type(m
, &size
, type
, NETLINK_TYPE_NESTED
);
438 const NLTypeSystemUnion
*type_system_union
;
441 r
= message_attribute_has_type(m
, &size
, type
, NETLINK_TYPE_UNION
);
445 r
= sd_rtnl_message_get_family(m
, &family
);
449 r
= type_system_get_type_system_union(m
->containers
[m
->n_containers
].type_system
, &type_system_union
, type
);
453 r
= type_system_union_protocol_get_type_system(type_system_union
,
454 &m
->containers
[m
->n_containers
+ 1].type_system
,
459 r
= type_system_get_type_system(m
->containers
[m
->n_containers
].type_system
,
460 &m
->containers
[m
->n_containers
+ 1].type_system
,
466 r
= add_rtattr(m
, type
| NLA_F_NESTED
, NULL
, size
);
470 m
->containers
[m
->n_containers
++].offset
= r
;
475 int sd_netlink_message_open_container_union(sd_netlink_message
*m
, unsigned short type
, const char *key
) {
476 const NLTypeSystemUnion
*type_system_union
;
479 assert_return(m
, -EINVAL
);
480 assert_return(!m
->sealed
, -EPERM
);
482 r
= type_system_get_type_system_union(m
->containers
[m
->n_containers
].type_system
, &type_system_union
, type
);
486 r
= type_system_union_get_type_system(type_system_union
,
487 &m
->containers
[m
->n_containers
+ 1].type_system
,
492 r
= sd_netlink_message_append_string(m
, type_system_union
->match
, key
);
496 /* do we ever need non-null size */
497 r
= add_rtattr(m
, type
| NLA_F_NESTED
, NULL
, 0);
501 m
->containers
[m
->n_containers
++].offset
= r
;
506 int sd_netlink_message_close_container(sd_netlink_message
*m
) {
507 assert_return(m
, -EINVAL
);
508 assert_return(!m
->sealed
, -EPERM
);
509 assert_return(m
->n_containers
> 0, -EINVAL
);
511 m
->containers
[m
->n_containers
].type_system
= NULL
;
512 m
->containers
[m
->n_containers
].offset
= 0;
518 int sd_netlink_message_open_array(sd_netlink_message
*m
, uint16_t type
) {
521 assert_return(m
, -EINVAL
);
522 assert_return(!m
->sealed
, -EPERM
);
523 assert_return(m
->n_containers
> 0, -EINVAL
);
525 r
= add_rtattr(m
, type
| NLA_F_NESTED
, NULL
, 0);
529 m
->containers
[m
->n_containers
].offset
= r
;
531 m
->containers
[m
->n_containers
].type_system
= m
->containers
[m
->n_containers
- 1].type_system
;
536 int sd_netlink_message_cancel_array(sd_netlink_message
*m
) {
540 assert_return(m
, -EINVAL
);
541 assert_return(!m
->sealed
, -EPERM
);
542 assert_return(m
->n_containers
> 1, -EINVAL
);
544 rta_len
= GET_CONTAINER(m
, (m
->n_containers
- 1))->rta_len
;
546 for (i
= 0; i
< m
->n_containers
; i
++)
547 GET_CONTAINER(m
, i
)->rta_len
-= rta_len
;
549 m
->hdr
->nlmsg_len
-= rta_len
;
552 m
->containers
[m
->n_containers
].type_system
= NULL
;
557 static int netlink_message_read_internal(sd_netlink_message
*m
, unsigned short type
, void **data
, bool *net_byteorder
) {
558 struct netlink_attribute
*attribute
;
561 assert_return(m
, -EINVAL
);
562 assert_return(m
->sealed
, -EPERM
);
563 assert_return(data
, -EINVAL
);
565 assert(m
->n_containers
< RTNL_CONTAINER_DEPTH
);
566 assert(m
->containers
[m
->n_containers
].attributes
);
567 assert(type
< m
->containers
[m
->n_containers
].n_attributes
);
569 attribute
= &m
->containers
[m
->n_containers
].attributes
[type
];
571 if (attribute
->offset
== 0)
574 rta
= (struct rtattr
*)((uint8_t *) m
->hdr
+ attribute
->offset
);
576 *data
= RTA_DATA(rta
);
579 *net_byteorder
= attribute
->net_byteorder
;
581 return RTA_PAYLOAD(rta
);
584 int sd_netlink_message_read(sd_netlink_message
*m
, unsigned short type
, size_t size
, void *data
) {
588 assert_return(m
, -EINVAL
);
590 r
= netlink_message_read_internal(m
, type
, &attr_data
, NULL
);
594 if ((size_t) r
< size
)
598 memcpy(data
, attr_data
, size
);
603 int sd_netlink_message_read_string(sd_netlink_message
*m
, unsigned short type
, const char **data
) {
607 assert_return(m
, -EINVAL
);
609 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_STRING
);
613 r
= netlink_message_read_internal(m
, type
, &attr_data
, NULL
);
616 else if (strnlen(attr_data
, r
) >= (size_t) r
)
620 *data
= (const char *) attr_data
;
625 int sd_netlink_message_read_u8(sd_netlink_message
*m
, unsigned short type
, uint8_t *data
) {
629 assert_return(m
, -EINVAL
);
631 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_U8
);
635 r
= netlink_message_read_internal(m
, type
, &attr_data
, NULL
);
638 else if ((size_t) r
< sizeof(uint8_t))
642 *data
= *(uint8_t *) attr_data
;
647 int sd_netlink_message_read_u16(sd_netlink_message
*m
, unsigned short type
, uint16_t *data
) {
652 assert_return(m
, -EINVAL
);
654 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_U16
);
658 r
= netlink_message_read_internal(m
, type
, &attr_data
, &net_byteorder
);
661 else if ((size_t) r
< sizeof(uint16_t))
666 *data
= be16toh(*(uint16_t *) attr_data
);
668 *data
= *(uint16_t *) attr_data
;
674 int sd_netlink_message_read_u32(sd_netlink_message
*m
, unsigned short type
, uint32_t *data
) {
679 assert_return(m
, -EINVAL
);
681 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_U32
);
685 r
= netlink_message_read_internal(m
, type
, &attr_data
, &net_byteorder
);
688 else if ((size_t)r
< sizeof(uint32_t))
693 *data
= be32toh(*(uint32_t *) attr_data
);
695 *data
= *(uint32_t *) attr_data
;
701 int sd_netlink_message_read_ether_addr(sd_netlink_message
*m
, unsigned short type
, struct ether_addr
*data
) {
705 assert_return(m
, -EINVAL
);
707 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_ETHER_ADDR
);
711 r
= netlink_message_read_internal(m
, type
, &attr_data
, NULL
);
714 else if ((size_t)r
< sizeof(struct ether_addr
))
718 memcpy(data
, attr_data
, sizeof(struct ether_addr
));
723 int sd_netlink_message_read_cache_info(sd_netlink_message
*m
, unsigned short type
, struct ifa_cacheinfo
*info
) {
727 assert_return(m
, -EINVAL
);
729 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_CACHE_INFO
);
733 r
= netlink_message_read_internal(m
, type
, &attr_data
, NULL
);
736 else if ((size_t)r
< sizeof(struct ifa_cacheinfo
))
740 memcpy(info
, attr_data
, sizeof(struct ifa_cacheinfo
));
745 int sd_netlink_message_read_in_addr(sd_netlink_message
*m
, unsigned short type
, struct in_addr
*data
) {
749 assert_return(m
, -EINVAL
);
751 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_IN_ADDR
);
755 r
= netlink_message_read_internal(m
, type
, &attr_data
, NULL
);
758 else if ((size_t)r
< sizeof(struct in_addr
))
762 memcpy(data
, attr_data
, sizeof(struct in_addr
));
767 int sd_netlink_message_read_in6_addr(sd_netlink_message
*m
, unsigned short type
, struct in6_addr
*data
) {
771 assert_return(m
, -EINVAL
);
773 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_IN_ADDR
);
777 r
= netlink_message_read_internal(m
, type
, &attr_data
, NULL
);
780 else if ((size_t)r
< sizeof(struct in6_addr
))
784 memcpy(data
, attr_data
, sizeof(struct in6_addr
));
789 static int netlink_container_parse(sd_netlink_message
*m
,
790 struct netlink_container
*container
,
794 _cleanup_free_
struct netlink_attribute
*attributes
= NULL
;
796 attributes
= new0(struct netlink_attribute
, count
);
800 for (; RTA_OK(rta
, rt_len
); rta
= RTA_NEXT(rta
, rt_len
)) {
803 type
= RTA_TYPE(rta
);
805 /* if the kernel is newer than the headers we used
806 when building, we ignore out-of-range attributes */
810 if (attributes
[type
].offset
!= 0)
811 log_debug("rtnl: message parse - overwriting repeated attribute");
813 attributes
[type
].offset
= (uint8_t *) rta
- (uint8_t *) m
->hdr
;
814 attributes
[type
].nested
= RTA_FLAGS(rta
) & NLA_F_NESTED
;
815 attributes
[type
].net_byteorder
= RTA_FLAGS(rta
) & NLA_F_NET_BYTEORDER
;
818 container
->attributes
= TAKE_PTR(attributes
);
819 container
->n_attributes
= count
;
824 int sd_netlink_message_enter_container(sd_netlink_message
*m
, unsigned short type_id
) {
825 const NLType
*nl_type
;
826 const NLTypeSystem
*type_system
;
832 assert_return(m
, -EINVAL
);
833 assert_return(m
->n_containers
< RTNL_CONTAINER_DEPTH
, -EINVAL
);
835 r
= type_system_get_type(m
->containers
[m
->n_containers
].type_system
,
841 type
= type_get_type(nl_type
);
843 if (type
== NETLINK_TYPE_NESTED
) {
844 r
= type_system_get_type_system(m
->containers
[m
->n_containers
].type_system
,
849 } else if (type
== NETLINK_TYPE_UNION
) {
850 const NLTypeSystemUnion
*type_system_union
;
852 r
= type_system_get_type_system_union(m
->containers
[m
->n_containers
].type_system
,
858 switch (type_system_union
->match_type
) {
859 case NL_MATCH_SIBLING
:
863 r
= sd_netlink_message_read_string(m
, type_system_union
->match
, &key
);
867 r
= type_system_union_get_type_system(type_system_union
,
875 case NL_MATCH_PROTOCOL
:
879 r
= sd_rtnl_message_get_family(m
, &family
);
883 r
= type_system_union_protocol_get_type_system(type_system_union
,
892 assert_not_reached("sd-netlink: invalid type system union type");
897 r
= netlink_message_read_internal(m
, type_id
, &container
, NULL
);
905 r
= netlink_container_parse(m
,
906 &m
->containers
[m
->n_containers
],
907 type_system_get_count(type_system
),
915 m
->containers
[m
->n_containers
].type_system
= type_system
;
920 int sd_netlink_message_exit_container(sd_netlink_message
*m
) {
921 assert_return(m
, -EINVAL
);
922 assert_return(m
->sealed
, -EINVAL
);
923 assert_return(m
->n_containers
> 0, -EINVAL
);
925 m
->containers
[m
->n_containers
].attributes
= mfree(m
->containers
[m
->n_containers
].attributes
);
926 m
->containers
[m
->n_containers
].type_system
= NULL
;
933 uint32_t rtnl_message_get_serial(sd_netlink_message
*m
) {
937 return m
->hdr
->nlmsg_seq
;
940 int sd_netlink_message_is_error(sd_netlink_message
*m
) {
942 assert_return(m
->hdr
, 0);
944 return m
->hdr
->nlmsg_type
== NLMSG_ERROR
;
947 int sd_netlink_message_get_errno(sd_netlink_message
*m
) {
948 struct nlmsgerr
*err
;
950 assert_return(m
, -EINVAL
);
951 assert_return(m
->hdr
, -EINVAL
);
953 if (!sd_netlink_message_is_error(m
))
956 err
= NLMSG_DATA(m
->hdr
);
961 int sd_netlink_message_rewind(sd_netlink_message
*m
) {
962 const NLType
*nl_type
;
963 const NLTypeSystem
*type_system_root
;
969 assert_return(m
, -EINVAL
);
971 /* don't allow appending to message once parsed */
973 rtnl_message_seal(m
);
975 type_system_root
= type_system_get_root(m
->protocol
);
977 for (i
= 1; i
<= m
->n_containers
; i
++)
978 m
->containers
[i
].attributes
= mfree(m
->containers
[i
].attributes
);
982 if (m
->containers
[0].attributes
)
983 /* top-level attributes have already been parsed */
988 r
= type_system_get_type(type_system_root
, &nl_type
, m
->hdr
->nlmsg_type
);
992 type
= type_get_type(nl_type
);
993 size
= type_get_size(nl_type
);
995 if (type
== NETLINK_TYPE_NESTED
) {
996 const NLTypeSystem
*type_system
;
998 type_get_type_system(nl_type
, &type_system
);
1000 m
->containers
[0].type_system
= type_system
;
1002 r
= netlink_container_parse(m
,
1003 &m
->containers
[m
->n_containers
],
1004 type_system_get_count(type_system
),
1005 (struct rtattr
*)((uint8_t*)NLMSG_DATA(m
->hdr
) + NLMSG_ALIGN(size
)),
1006 NLMSG_PAYLOAD(m
->hdr
, size
));
1014 void rtnl_message_seal(sd_netlink_message
*m
) {
1021 sd_netlink_message
*sd_netlink_message_next(sd_netlink_message
*m
) {
1022 assert_return(m
, NULL
);