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"
11 #include "netlink-internal.h"
12 #include "netlink-types.h"
13 #include "netlink-util.h"
14 #include "socket-util.h"
15 #include "memory-util.h"
17 #define GET_CONTAINER(m, i) ((i) < (m)->n_containers ? (struct rtattr*)((uint8_t*)(m)->hdr + (m)->containers[i].offset) : NULL)
18 #define PUSH_CONTAINER(m, new) (m)->container_offsets[(m)->n_containers++] = (uint8_t*)(new) - (uint8_t*)(m)->hdr;
20 #define RTA_TYPE(rta) ((rta)->rta_type & NLA_TYPE_MASK)
21 #define RTA_FLAGS(rta) ((rta)->rta_type & ~NLA_TYPE_MASK)
23 int message_new_empty(sd_netlink
*rtnl
, sd_netlink_message
**ret
) {
24 sd_netlink_message
*m
;
26 assert_return(ret
, -EINVAL
);
28 /* Note that 'rtnl' is currently unused, if we start using it internally
29 we must take care to avoid problems due to mutual references between
30 buses and their queued messages. See sd-bus.
33 m
= new(sd_netlink_message
, 1);
37 *m
= (sd_netlink_message
) {
39 .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
;
54 assert_return(rtnl
, -EINVAL
);
56 r
= type_system_root_get_type(rtnl
, &nl_type
, type
);
60 if (type_get_type(nl_type
) != NETLINK_TYPE_NESTED
)
63 r
= message_new_empty(rtnl
, &m
);
67 size
= NLMSG_SPACE(type_get_size(nl_type
));
69 assert(size
>= sizeof(struct nlmsghdr
));
70 m
->hdr
= malloc0(size
);
74 m
->hdr
->nlmsg_flags
= NLM_F_REQUEST
| NLM_F_ACK
;
76 type_get_type_system(nl_type
, &m
->containers
[0].type_system
);
77 m
->hdr
->nlmsg_len
= size
;
78 m
->hdr
->nlmsg_type
= type
;
85 int sd_netlink_message_request_dump(sd_netlink_message
*m
, int dump
) {
86 assert_return(m
, -EINVAL
);
87 assert_return(m
->hdr
, -EINVAL
);
89 assert_return(IN_SET(m
->hdr
->nlmsg_type
, RTM_GETLINK
, RTM_GETADDR
, RTM_GETROUTE
, RTM_GETNEIGH
,
90 RTM_GETRULE
, RTM_GETADDRLABEL
, RTM_GETNEXTHOP
), -EINVAL
);
92 SET_FLAG(m
->hdr
->nlmsg_flags
, NLM_F_DUMP
, dump
);
97 DEFINE_TRIVIAL_REF_FUNC(sd_netlink_message
, sd_netlink_message
);
99 sd_netlink_message
*sd_netlink_message_unref(sd_netlink_message
*m
) {
100 while (m
&& --m
->n_ref
== 0) {
105 for (i
= 0; i
<= m
->n_containers
; i
++)
106 free(m
->containers
[i
].attributes
);
108 sd_netlink_message
*t
= m
;
116 int sd_netlink_message_get_type(const sd_netlink_message
*m
, uint16_t *type
) {
117 assert_return(m
, -EINVAL
);
118 assert_return(type
, -EINVAL
);
120 *type
= m
->hdr
->nlmsg_type
;
125 int sd_netlink_message_set_flags(sd_netlink_message
*m
, uint16_t flags
) {
126 assert_return(m
, -EINVAL
);
127 assert_return(flags
, -EINVAL
);
129 m
->hdr
->nlmsg_flags
= flags
;
134 int sd_netlink_message_is_broadcast(const sd_netlink_message
*m
) {
135 assert_return(m
, -EINVAL
);
140 /* If successful the updated message will be correctly aligned, if
141 unsuccessful the old message is untouched. */
142 static int add_rtattr(sd_netlink_message
*m
, unsigned short type
, const void *data
, size_t data_length
) {
144 size_t message_length
, padding_length
;
145 struct nlmsghdr
*new_hdr
;
154 assert(NLMSG_ALIGN(m
->hdr
->nlmsg_len
) == m
->hdr
->nlmsg_len
);
155 assert(!data
|| data_length
);
157 /* get offset of the new attribute */
158 offset
= m
->hdr
->nlmsg_len
;
160 /* get the size of the new rta attribute (with padding at the end) */
161 rta_length
= RTA_LENGTH(data_length
);
163 /* get the new message size (with padding at the end) */
164 message_length
= offset
+ RTA_ALIGN(rta_length
);
166 /* buffer should be smaller than both one page or 8K to be accepted by the kernel */
167 if (message_length
> MIN(page_size(), 8192UL))
170 /* realloc to fit the new attribute */
171 new_hdr
= realloc(m
->hdr
, message_length
);
176 /* get pointer to the attribute we are about to add */
177 rta
= (struct rtattr
*) ((uint8_t *) m
->hdr
+ offset
);
179 /* if we are inside containers, extend them */
180 for (i
= 0; i
< m
->n_containers
; i
++)
181 GET_CONTAINER(m
, i
)->rta_len
+= message_length
- offset
;
183 /* fill in the attribute */
184 rta
->rta_type
= type
;
185 rta
->rta_len
= rta_length
;
187 /* we don't deal with the case where the user lies about the type
188 * and gives us too little data (so don't do that)
190 padding
= mempcpy(RTA_DATA(rta
), data
, data_length
);
193 /* if no data was passed, make sure we still initialize the padding
194 note that we can have data_length > 0 (used by some containers) */
195 padding
= RTA_DATA(rta
);
197 /* make sure also the padding at the end of the message is initialized */
198 padding_length
= (uint8_t*)m
->hdr
+ message_length
- (uint8_t*)padding
;
199 memzero(padding
, padding_length
);
201 /* update message size */
202 m
->hdr
->nlmsg_len
= message_length
;
207 static int message_attribute_has_type(sd_netlink_message
*m
, size_t *out_size
, uint16_t attribute_type
, uint16_t data_type
) {
213 r
= type_system_get_type(m
->containers
[m
->n_containers
].type_system
, &type
, attribute_type
);
217 if (type_get_type(type
) != data_type
)
221 *out_size
= type_get_size(type
);
225 int sd_netlink_message_append_string(sd_netlink_message
*m
, unsigned short type
, const char *data
) {
229 assert_return(m
, -EINVAL
);
230 assert_return(!m
->sealed
, -EPERM
);
231 assert_return(data
, -EINVAL
);
233 r
= message_attribute_has_type(m
, &size
, type
, NETLINK_TYPE_STRING
);
238 length
= strnlen(data
, size
+1);
242 length
= strlen(data
);
244 r
= add_rtattr(m
, type
, data
, length
+ 1);
251 int sd_netlink_message_append_flag(sd_netlink_message
*m
, unsigned short type
) {
255 assert_return(m
, -EINVAL
);
256 assert_return(!m
->sealed
, -EPERM
);
258 r
= message_attribute_has_type(m
, &size
, type
, NETLINK_TYPE_FLAG
);
262 r
= add_rtattr(m
, type
, NULL
, 0);
269 int sd_netlink_message_append_u8(sd_netlink_message
*m
, unsigned short type
, uint8_t data
) {
272 assert_return(m
, -EINVAL
);
273 assert_return(!m
->sealed
, -EPERM
);
275 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_U8
);
279 r
= add_rtattr(m
, type
, &data
, sizeof(uint8_t));
286 int sd_netlink_message_append_u16(sd_netlink_message
*m
, unsigned short type
, uint16_t data
) {
289 assert_return(m
, -EINVAL
);
290 assert_return(!m
->sealed
, -EPERM
);
292 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_U16
);
296 r
= add_rtattr(m
, type
, &data
, sizeof(uint16_t));
303 int sd_netlink_message_append_u32(sd_netlink_message
*m
, unsigned short type
, uint32_t data
) {
306 assert_return(m
, -EINVAL
);
307 assert_return(!m
->sealed
, -EPERM
);
309 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_U32
);
313 r
= add_rtattr(m
, type
, &data
, sizeof(uint32_t));
320 int sd_netlink_message_append_u64(sd_netlink_message
*m
, unsigned short type
, uint64_t data
) {
323 assert_return(m
, -EINVAL
);
324 assert_return(!m
->sealed
, -EPERM
);
326 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_U64
);
330 r
= add_rtattr(m
, type
, &data
, sizeof(uint64_t));
337 int sd_netlink_message_append_data(sd_netlink_message
*m
, unsigned short type
, const void *data
, size_t len
) {
340 assert_return(m
, -EINVAL
);
341 assert_return(!m
->sealed
, -EPERM
);
343 r
= add_rtattr(m
, type
, data
, len
);
350 int netlink_message_append_in_addr_union(sd_netlink_message
*m
, unsigned short type
, int family
, const union in_addr_union
*data
) {
353 assert_return(m
, -EINVAL
);
354 assert_return(!m
->sealed
, -EPERM
);
355 assert_return(data
, -EINVAL
);
356 assert_return(IN_SET(family
, AF_INET
, AF_INET6
), -EINVAL
);
358 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_IN_ADDR
);
362 r
= add_rtattr(m
, type
, data
, FAMILY_ADDRESS_SIZE(family
));
369 int sd_netlink_message_append_in_addr(sd_netlink_message
*m
, unsigned short type
, const struct in_addr
*data
) {
370 return netlink_message_append_in_addr_union(m
, type
, AF_INET
, (const union in_addr_union
*) data
);
373 int sd_netlink_message_append_in6_addr(sd_netlink_message
*m
, unsigned short type
, const struct in6_addr
*data
) {
374 return netlink_message_append_in_addr_union(m
, type
, AF_INET6
, (const union in_addr_union
*) data
);
377 int netlink_message_append_sockaddr_union(sd_netlink_message
*m
, unsigned short type
, const union sockaddr_union
*data
) {
380 assert_return(m
, -EINVAL
);
381 assert_return(!m
->sealed
, -EPERM
);
382 assert_return(data
, -EINVAL
);
383 assert_return(IN_SET(data
->sa
.sa_family
, AF_INET
, AF_INET6
), -EINVAL
);
385 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_SOCKADDR
);
389 r
= add_rtattr(m
, type
, data
, data
->sa
.sa_family
== AF_INET
? sizeof(struct sockaddr_in
) : sizeof(struct sockaddr_in6
));
396 int sd_netlink_message_append_sockaddr_in(sd_netlink_message
*m
, unsigned short type
, const struct sockaddr_in
*data
) {
397 return netlink_message_append_sockaddr_union(m
, type
, (const union sockaddr_union
*) data
);
400 int sd_netlink_message_append_sockaddr_in6(sd_netlink_message
*m
, unsigned short type
, const struct sockaddr_in6
*data
) {
401 return netlink_message_append_sockaddr_union(m
, type
, (const union sockaddr_union
*) data
);
404 int sd_netlink_message_append_ether_addr(sd_netlink_message
*m
, unsigned short type
, const struct ether_addr
*data
) {
407 assert_return(m
, -EINVAL
);
408 assert_return(!m
->sealed
, -EPERM
);
409 assert_return(data
, -EINVAL
);
411 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_ETHER_ADDR
);
415 r
= add_rtattr(m
, type
, data
, ETH_ALEN
);
422 int sd_netlink_message_append_cache_info(sd_netlink_message
*m
, unsigned short type
, const struct ifa_cacheinfo
*info
) {
425 assert_return(m
, -EINVAL
);
426 assert_return(!m
->sealed
, -EPERM
);
427 assert_return(info
, -EINVAL
);
429 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_CACHE_INFO
);
433 r
= add_rtattr(m
, type
, info
, sizeof(struct ifa_cacheinfo
));
440 int sd_netlink_message_open_container(sd_netlink_message
*m
, unsigned short type
) {
444 assert_return(m
, -EINVAL
);
445 assert_return(!m
->sealed
, -EPERM
);
446 assert_return(m
->n_containers
< RTNL_CONTAINER_DEPTH
, -ERANGE
);
448 r
= message_attribute_has_type(m
, &size
, type
, NETLINK_TYPE_NESTED
);
450 const NLTypeSystemUnion
*type_system_union
;
453 r
= message_attribute_has_type(m
, &size
, type
, NETLINK_TYPE_UNION
);
457 r
= sd_rtnl_message_get_family(m
, &family
);
461 r
= type_system_get_type_system_union(m
->containers
[m
->n_containers
].type_system
, &type_system_union
, type
);
465 r
= type_system_union_protocol_get_type_system(type_system_union
,
466 &m
->containers
[m
->n_containers
+ 1].type_system
,
471 r
= type_system_get_type_system(m
->containers
[m
->n_containers
].type_system
,
472 &m
->containers
[m
->n_containers
+ 1].type_system
,
478 r
= add_rtattr(m
, type
| NLA_F_NESTED
, NULL
, size
);
482 m
->containers
[m
->n_containers
++].offset
= r
;
487 int sd_netlink_message_open_container_union(sd_netlink_message
*m
, unsigned short type
, const char *key
) {
488 const NLTypeSystemUnion
*type_system_union
;
491 assert_return(m
, -EINVAL
);
492 assert_return(!m
->sealed
, -EPERM
);
494 r
= type_system_get_type_system_union(m
->containers
[m
->n_containers
].type_system
, &type_system_union
, type
);
498 r
= type_system_union_get_type_system(type_system_union
,
499 &m
->containers
[m
->n_containers
+ 1].type_system
,
504 r
= sd_netlink_message_append_string(m
, type_system_union
->match
, key
);
508 /* do we ever need non-null size */
509 r
= add_rtattr(m
, type
| NLA_F_NESTED
, NULL
, 0);
513 m
->containers
[m
->n_containers
++].offset
= r
;
518 int sd_netlink_message_close_container(sd_netlink_message
*m
) {
519 assert_return(m
, -EINVAL
);
520 assert_return(!m
->sealed
, -EPERM
);
521 assert_return(m
->n_containers
> 0, -EINVAL
);
523 m
->containers
[m
->n_containers
].type_system
= NULL
;
524 m
->containers
[m
->n_containers
].offset
= 0;
530 int sd_netlink_message_open_array(sd_netlink_message
*m
, uint16_t type
) {
533 assert_return(m
, -EINVAL
);
534 assert_return(!m
->sealed
, -EPERM
);
536 r
= add_rtattr(m
, type
| NLA_F_NESTED
, NULL
, 0);
540 m
->containers
[m
->n_containers
].offset
= r
;
542 m
->containers
[m
->n_containers
].type_system
= m
->containers
[m
->n_containers
- 1].type_system
;
547 int sd_netlink_message_cancel_array(sd_netlink_message
*m
) {
551 assert_return(m
, -EINVAL
);
552 assert_return(!m
->sealed
, -EPERM
);
553 assert_return(m
->n_containers
> 1, -EINVAL
);
555 rta_len
= GET_CONTAINER(m
, (m
->n_containers
- 1))->rta_len
;
557 for (i
= 0; i
< m
->n_containers
; i
++)
558 GET_CONTAINER(m
, i
)->rta_len
-= rta_len
;
560 m
->hdr
->nlmsg_len
-= rta_len
;
563 m
->containers
[m
->n_containers
].type_system
= NULL
;
568 static int netlink_message_read_internal(sd_netlink_message
*m
, unsigned short type
, void **data
, bool *net_byteorder
) {
569 struct netlink_attribute
*attribute
;
572 assert_return(m
, -EINVAL
);
573 assert_return(m
->sealed
, -EPERM
);
574 assert_return(data
, -EINVAL
);
576 assert(m
->n_containers
< RTNL_CONTAINER_DEPTH
);
578 if (!m
->containers
[m
->n_containers
].attributes
)
581 if (type
>= m
->containers
[m
->n_containers
].n_attributes
)
584 attribute
= &m
->containers
[m
->n_containers
].attributes
[type
];
586 if (attribute
->offset
== 0)
589 rta
= (struct rtattr
*)((uint8_t *) m
->hdr
+ attribute
->offset
);
591 *data
= RTA_DATA(rta
);
594 *net_byteorder
= attribute
->net_byteorder
;
596 return RTA_PAYLOAD(rta
);
599 int sd_netlink_message_read(sd_netlink_message
*m
, unsigned short type
, size_t size
, void *data
) {
603 assert_return(m
, -EINVAL
);
605 r
= netlink_message_read_internal(m
, type
, &attr_data
, NULL
);
609 if ((size_t) r
< size
)
613 memcpy(data
, attr_data
, size
);
618 int sd_netlink_message_read_string_strdup(sd_netlink_message
*m
, unsigned short type
, char **data
) {
623 assert_return(m
, -EINVAL
);
625 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_STRING
);
629 r
= netlink_message_read_internal(m
, type
, &attr_data
, NULL
);
634 str
= strndup(attr_data
, r
);
644 int sd_netlink_message_read_string(sd_netlink_message
*m
, unsigned short type
, const char **data
) {
648 assert_return(m
, -EINVAL
);
650 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_STRING
);
654 r
= netlink_message_read_internal(m
, type
, &attr_data
, NULL
);
657 else if (strnlen(attr_data
, r
) >= (size_t) r
)
661 *data
= (const char *) attr_data
;
666 int sd_netlink_message_read_u8(sd_netlink_message
*m
, unsigned short type
, uint8_t *data
) {
670 assert_return(m
, -EINVAL
);
672 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_U8
);
676 r
= netlink_message_read_internal(m
, type
, &attr_data
, NULL
);
679 else if ((size_t) r
< sizeof(uint8_t))
683 *data
= *(uint8_t *) attr_data
;
688 int sd_netlink_message_read_u16(sd_netlink_message
*m
, unsigned short type
, uint16_t *data
) {
693 assert_return(m
, -EINVAL
);
695 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_U16
);
699 r
= netlink_message_read_internal(m
, type
, &attr_data
, &net_byteorder
);
702 else if ((size_t) r
< sizeof(uint16_t))
707 *data
= be16toh(*(uint16_t *) attr_data
);
709 *data
= *(uint16_t *) attr_data
;
715 int sd_netlink_message_read_u32(sd_netlink_message
*m
, unsigned short type
, uint32_t *data
) {
720 assert_return(m
, -EINVAL
);
722 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_U32
);
726 r
= netlink_message_read_internal(m
, type
, &attr_data
, &net_byteorder
);
729 else if ((size_t)r
< sizeof(uint32_t))
734 *data
= be32toh(*(uint32_t *) attr_data
);
736 *data
= *(uint32_t *) attr_data
;
742 int sd_netlink_message_read_ether_addr(sd_netlink_message
*m
, unsigned short type
, struct ether_addr
*data
) {
746 assert_return(m
, -EINVAL
);
748 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_ETHER_ADDR
);
752 r
= netlink_message_read_internal(m
, type
, &attr_data
, NULL
);
755 else if ((size_t)r
< sizeof(struct ether_addr
))
759 memcpy(data
, attr_data
, sizeof(struct ether_addr
));
764 int sd_netlink_message_read_cache_info(sd_netlink_message
*m
, unsigned short type
, struct ifa_cacheinfo
*info
) {
768 assert_return(m
, -EINVAL
);
770 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_CACHE_INFO
);
774 r
= netlink_message_read_internal(m
, type
, &attr_data
, NULL
);
777 else if ((size_t)r
< sizeof(struct ifa_cacheinfo
))
781 memcpy(info
, attr_data
, sizeof(struct ifa_cacheinfo
));
786 int sd_netlink_message_read_in_addr(sd_netlink_message
*m
, unsigned short type
, struct in_addr
*data
) {
790 assert_return(m
, -EINVAL
);
792 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_IN_ADDR
);
796 r
= netlink_message_read_internal(m
, type
, &attr_data
, NULL
);
799 else if ((size_t)r
< sizeof(struct in_addr
))
803 memcpy(data
, attr_data
, sizeof(struct in_addr
));
808 int sd_netlink_message_read_in6_addr(sd_netlink_message
*m
, unsigned short type
, struct in6_addr
*data
) {
812 assert_return(m
, -EINVAL
);
814 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_IN_ADDR
);
818 r
= netlink_message_read_internal(m
, type
, &attr_data
, NULL
);
821 else if ((size_t)r
< sizeof(struct in6_addr
))
825 memcpy(data
, attr_data
, sizeof(struct in6_addr
));
830 static int netlink_container_parse(sd_netlink_message
*m
,
831 struct netlink_container
*container
,
834 _cleanup_free_
struct netlink_attribute
*attributes
= NULL
;
835 size_t n_allocated
= 0;
837 for (; RTA_OK(rta
, rt_len
); rta
= RTA_NEXT(rta
, rt_len
)) {
840 type
= RTA_TYPE(rta
);
842 if (!GREEDY_REALLOC0(attributes
, n_allocated
, type
+ 1))
845 if (attributes
[type
].offset
!= 0)
846 log_debug("rtnl: message parse - overwriting repeated attribute");
848 attributes
[type
].offset
= (uint8_t *) rta
- (uint8_t *) m
->hdr
;
849 attributes
[type
].nested
= RTA_FLAGS(rta
) & NLA_F_NESTED
;
850 attributes
[type
].net_byteorder
= RTA_FLAGS(rta
) & NLA_F_NET_BYTEORDER
;
853 container
->attributes
= TAKE_PTR(attributes
);
854 container
->n_attributes
= n_allocated
;
859 int sd_netlink_message_enter_container(sd_netlink_message
*m
, unsigned short type_id
) {
860 const NLType
*nl_type
;
861 const NLTypeSystem
*type_system
;
867 assert_return(m
, -EINVAL
);
868 assert_return(m
->n_containers
< RTNL_CONTAINER_DEPTH
, -EINVAL
);
870 r
= type_system_get_type(m
->containers
[m
->n_containers
].type_system
,
876 type
= type_get_type(nl_type
);
878 if (type
== NETLINK_TYPE_NESTED
) {
879 r
= type_system_get_type_system(m
->containers
[m
->n_containers
].type_system
,
884 } else if (type
== NETLINK_TYPE_UNION
) {
885 const NLTypeSystemUnion
*type_system_union
;
887 r
= type_system_get_type_system_union(m
->containers
[m
->n_containers
].type_system
,
893 switch (type_system_union
->match_type
) {
894 case NL_MATCH_SIBLING
:
898 r
= sd_netlink_message_read_string(m
, type_system_union
->match
, &key
);
902 r
= type_system_union_get_type_system(type_system_union
,
910 case NL_MATCH_PROTOCOL
:
914 r
= sd_rtnl_message_get_family(m
, &family
);
918 r
= type_system_union_protocol_get_type_system(type_system_union
,
927 assert_not_reached("sd-netlink: invalid type system union type");
932 r
= netlink_message_read_internal(m
, type_id
, &container
, NULL
);
940 r
= netlink_container_parse(m
,
941 &m
->containers
[m
->n_containers
],
949 m
->containers
[m
->n_containers
].type_system
= type_system
;
954 int sd_netlink_message_enter_array(sd_netlink_message
*m
, unsigned short type_id
) {
959 assert_return(m
, -EINVAL
);
960 assert_return(m
->n_containers
< RTNL_CONTAINER_DEPTH
, -EINVAL
);
962 r
= netlink_message_read_internal(m
, type_id
, &container
, NULL
);
970 r
= netlink_container_parse(m
,
971 &m
->containers
[m
->n_containers
],
979 m
->containers
[m
->n_containers
].type_system
= m
->containers
[m
->n_containers
- 1].type_system
;
984 int sd_netlink_message_exit_container(sd_netlink_message
*m
) {
985 assert_return(m
, -EINVAL
);
986 assert_return(m
->sealed
, -EINVAL
);
987 assert_return(m
->n_containers
> 0, -EINVAL
);
989 m
->containers
[m
->n_containers
].attributes
= mfree(m
->containers
[m
->n_containers
].attributes
);
990 m
->containers
[m
->n_containers
].type_system
= NULL
;
997 uint32_t rtnl_message_get_serial(sd_netlink_message
*m
) {
1001 return m
->hdr
->nlmsg_seq
;
1004 int sd_netlink_message_is_error(const sd_netlink_message
*m
) {
1005 assert_return(m
, 0);
1006 assert_return(m
->hdr
, 0);
1008 return m
->hdr
->nlmsg_type
== NLMSG_ERROR
;
1011 int sd_netlink_message_get_errno(const sd_netlink_message
*m
) {
1012 struct nlmsgerr
*err
;
1014 assert_return(m
, -EINVAL
);
1015 assert_return(m
->hdr
, -EINVAL
);
1017 if (!sd_netlink_message_is_error(m
))
1020 err
= NLMSG_DATA(m
->hdr
);
1025 static int netlink_message_parse_error(sd_netlink_message
*m
) {
1026 struct nlmsgerr
*err
= NLMSG_DATA(m
->hdr
);
1027 size_t hlen
= sizeof(struct nlmsgerr
);
1029 /* no TLVs, nothing to do here */
1030 if (!(m
->hdr
->nlmsg_flags
& NLM_F_ACK_TLVS
))
1033 /* if NLM_F_CAPPED is set then the inner err msg was capped */
1034 if (!(m
->hdr
->nlmsg_flags
& NLM_F_CAPPED
))
1035 hlen
+= err
->msg
.nlmsg_len
- sizeof(struct nlmsghdr
);
1037 if (m
->hdr
->nlmsg_len
<= NLMSG_SPACE(hlen
))
1040 return netlink_container_parse(m
,
1041 &m
->containers
[m
->n_containers
],
1042 (struct rtattr
*)((uint8_t*) NLMSG_DATA(m
->hdr
) + hlen
),
1043 NLMSG_PAYLOAD(m
->hdr
, hlen
));
1046 int sd_netlink_message_rewind(sd_netlink_message
*m
, sd_netlink
*genl
) {
1047 const NLType
*nl_type
;
1053 assert_return(m
, -EINVAL
);
1054 assert_return(genl
|| m
->protocol
!= NETLINK_GENERIC
, -EINVAL
);
1056 /* don't allow appending to message once parsed */
1058 rtnl_message_seal(m
);
1060 for (i
= 1; i
<= m
->n_containers
; i
++)
1061 m
->containers
[i
].attributes
= mfree(m
->containers
[i
].attributes
);
1063 m
->n_containers
= 0;
1065 if (m
->containers
[0].attributes
)
1066 /* top-level attributes have already been parsed */
1071 r
= type_system_root_get_type(genl
, &nl_type
, m
->hdr
->nlmsg_type
);
1075 type
= type_get_type(nl_type
);
1076 size
= type_get_size(nl_type
);
1078 if (type
== NETLINK_TYPE_NESTED
) {
1079 const NLTypeSystem
*type_system
;
1081 type_get_type_system(nl_type
, &type_system
);
1083 m
->containers
[0].type_system
= type_system
;
1085 if (sd_netlink_message_is_error(m
))
1086 r
= netlink_message_parse_error(m
);
1088 r
= netlink_container_parse(m
,
1089 &m
->containers
[m
->n_containers
],
1090 (struct rtattr
*)((uint8_t*) NLMSG_DATA(m
->hdr
) + NLMSG_ALIGN(size
)),
1091 NLMSG_PAYLOAD(m
->hdr
, size
));
1099 void rtnl_message_seal(sd_netlink_message
*m
) {
1106 sd_netlink_message
*sd_netlink_message_next(sd_netlink_message
*m
) {
1107 assert_return(m
, NULL
);