1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 #include <netinet/in.h>
7 #include "sd-netlink.h"
9 #include "alloc-util.h"
10 #include "format-util.h"
11 #include "memory-util.h"
12 #include "netlink-internal.h"
13 #include "netlink-types.h"
14 #include "netlink-util.h"
15 #include "socket-util.h"
18 #define GET_CONTAINER(m, i) ((struct rtattr*)((uint8_t*)(m)->hdr + (m)->containers[i].offset))
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
*nl
, sd_netlink_message
**ret
) {
24 sd_netlink_message
*m
;
29 /* Note that 'nl' is currently unused, if we start using it internally we must take care to
30 * avoid problems due to mutual references between buses and their queued messages. See sd-bus. */
32 m
= new(sd_netlink_message
, 1);
36 *m
= (sd_netlink_message
) {
38 .protocol
= nl
->protocol
,
49 const NLTypeSystem
*type_system
,
51 sd_netlink_message
**ret
) {
53 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*m
= NULL
;
61 size
= NLMSG_SPACE(header_size
);
62 assert(size
>= sizeof(struct nlmsghdr
));
64 r
= message_new_empty(nl
, &m
);
68 m
->containers
[0].type_system
= type_system
;
70 m
->hdr
= malloc0(size
);
74 m
->hdr
->nlmsg_flags
= NLM_F_REQUEST
| NLM_F_ACK
;
75 m
->hdr
->nlmsg_len
= size
;
76 m
->hdr
->nlmsg_type
= nlmsg_type
;
82 int message_new(sd_netlink
*nl
, sd_netlink_message
**ret
, uint16_t type
) {
83 const NLTypeSystem
*type_system
;
87 assert_return(nl
, -EINVAL
);
88 assert_return(ret
, -EINVAL
);
90 r
= type_system_root_get_type_system_and_header_size(nl
, type
, &type_system
, &size
);
94 return message_new_full(nl
, type
, type_system
, size
, ret
);
97 int message_new_synthetic_error(sd_netlink
*nl
, int error
, uint32_t serial
, sd_netlink_message
**ret
) {
103 r
= message_new(nl
, ret
, NLMSG_ERROR
);
108 (*ret
)->hdr
->nlmsg_seq
= serial
;
110 err
= NLMSG_DATA((*ret
)->hdr
);
116 int sd_netlink_message_request_dump(sd_netlink_message
*m
, int dump
) {
117 assert_return(m
, -EINVAL
);
118 assert_return(m
->hdr
, -EINVAL
);
120 assert_return(IN_SET(m
->hdr
->nlmsg_type
,
121 RTM_GETLINK
, RTM_GETLINKPROP
, RTM_GETADDR
, RTM_GETROUTE
, RTM_GETNEIGH
,
122 RTM_GETRULE
, RTM_GETADDRLABEL
, RTM_GETNEXTHOP
), -EINVAL
);
124 SET_FLAG(m
->hdr
->nlmsg_flags
, NLM_F_DUMP
, dump
);
129 DEFINE_TRIVIAL_REF_FUNC(sd_netlink_message
, sd_netlink_message
);
131 sd_netlink_message
*sd_netlink_message_unref(sd_netlink_message
*m
) {
132 while (m
&& --m
->n_ref
== 0) {
137 for (i
= 0; i
<= m
->n_containers
; i
++)
138 free(m
->containers
[i
].attributes
);
140 sd_netlink_message
*t
= m
;
148 int sd_netlink_message_get_type(sd_netlink_message
*m
, uint16_t *type
) {
149 assert_return(m
, -EINVAL
);
150 assert_return(type
, -EINVAL
);
152 *type
= m
->hdr
->nlmsg_type
;
157 int sd_netlink_message_set_flags(sd_netlink_message
*m
, uint16_t flags
) {
158 assert_return(m
, -EINVAL
);
159 assert_return(flags
, -EINVAL
);
161 m
->hdr
->nlmsg_flags
= flags
;
166 int sd_netlink_message_is_broadcast(sd_netlink_message
*m
) {
167 assert_return(m
, -EINVAL
);
172 /* If successful the updated message will be correctly aligned, if
173 unsuccessful the old message is untouched. */
174 static int add_rtattr(sd_netlink_message
*m
, unsigned short type
, const void *data
, size_t data_length
) {
175 size_t message_length
;
176 struct nlmsghdr
*new_hdr
;
183 assert(NLMSG_ALIGN(m
->hdr
->nlmsg_len
) == m
->hdr
->nlmsg_len
);
184 assert(!data
|| data_length
> 0);
186 /* get the new message size (with padding at the end) */
187 message_length
= m
->hdr
->nlmsg_len
+ RTA_SPACE(data_length
);
189 /* buffer should be smaller than both one page or 8K to be accepted by the kernel */
190 if (message_length
> MIN(page_size(), 8192UL))
193 /* realloc to fit the new attribute */
194 new_hdr
= realloc(m
->hdr
, message_length
);
199 /* get pointer to the attribute we are about to add */
200 rta
= (struct rtattr
*) ((uint8_t *) m
->hdr
+ m
->hdr
->nlmsg_len
);
202 rtattr_append_attribute_internal(rta
, type
, data
, data_length
);
204 /* if we are inside containers, extend them */
205 for (unsigned i
= 0; i
< m
->n_containers
; i
++)
206 GET_CONTAINER(m
, i
)->rta_len
+= RTA_SPACE(data_length
);
208 /* update message size */
209 offset
= m
->hdr
->nlmsg_len
;
210 m
->hdr
->nlmsg_len
= message_length
;
212 /* return old message size */
216 static int message_attribute_has_type(sd_netlink_message
*m
, size_t *out_size
, uint16_t attribute_type
, uint16_t data_type
) {
222 r
= type_system_get_type(m
->containers
[m
->n_containers
].type_system
, &type
, attribute_type
);
226 if (type_get_type(type
) != data_type
)
230 *out_size
= type_get_size(type
);
234 int sd_netlink_message_append_string(sd_netlink_message
*m
, unsigned short type
, const char *data
) {
238 assert_return(m
, -EINVAL
);
239 assert_return(!m
->sealed
, -EPERM
);
240 assert_return(data
, -EINVAL
);
242 r
= message_attribute_has_type(m
, &size
, type
, NETLINK_TYPE_STRING
);
247 length
= strnlen(data
, size
+1);
251 length
= strlen(data
);
253 r
= add_rtattr(m
, type
, data
, length
+ 1);
260 int sd_netlink_message_append_strv(sd_netlink_message
*m
, unsigned short type
, char * const *data
) {
265 assert_return(m
, -EINVAL
);
266 assert_return(!m
->sealed
, -EPERM
);
267 assert_return(data
, -EINVAL
);
269 r
= message_attribute_has_type(m
, &size
, type
, NETLINK_TYPE_STRING
);
273 STRV_FOREACH(p
, data
) {
275 length
= strnlen(*p
, size
+1);
281 r
= add_rtattr(m
, type
, *p
, length
+ 1);
289 int sd_netlink_message_append_flag(sd_netlink_message
*m
, unsigned short type
) {
293 assert_return(m
, -EINVAL
);
294 assert_return(!m
->sealed
, -EPERM
);
296 r
= message_attribute_has_type(m
, &size
, type
, NETLINK_TYPE_FLAG
);
300 r
= add_rtattr(m
, type
, NULL
, 0);
307 int sd_netlink_message_append_u8(sd_netlink_message
*m
, unsigned short type
, uint8_t data
) {
310 assert_return(m
, -EINVAL
);
311 assert_return(!m
->sealed
, -EPERM
);
313 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_U8
);
317 r
= add_rtattr(m
, type
, &data
, sizeof(uint8_t));
324 int sd_netlink_message_append_u16(sd_netlink_message
*m
, unsigned short type
, uint16_t data
) {
327 assert_return(m
, -EINVAL
);
328 assert_return(!m
->sealed
, -EPERM
);
330 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_U16
);
334 r
= add_rtattr(m
, type
, &data
, sizeof(uint16_t));
341 int sd_netlink_message_append_u32(sd_netlink_message
*m
, unsigned short type
, uint32_t data
) {
344 assert_return(m
, -EINVAL
);
345 assert_return(!m
->sealed
, -EPERM
);
347 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_U32
);
351 r
= add_rtattr(m
, type
, &data
, sizeof(uint32_t));
358 int sd_netlink_message_append_u64(sd_netlink_message
*m
, unsigned short type
, uint64_t data
) {
361 assert_return(m
, -EINVAL
);
362 assert_return(!m
->sealed
, -EPERM
);
364 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_U64
);
368 r
= add_rtattr(m
, type
, &data
, sizeof(uint64_t));
375 int sd_netlink_message_append_s8(sd_netlink_message
*m
, unsigned short type
, int8_t data
) {
378 assert_return(m
, -EINVAL
);
379 assert_return(!m
->sealed
, -EPERM
);
381 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_S8
);
385 r
= add_rtattr(m
, type
, &data
, sizeof(int8_t));
392 int sd_netlink_message_append_s16(sd_netlink_message
*m
, unsigned short type
, int16_t data
) {
395 assert_return(m
, -EINVAL
);
396 assert_return(!m
->sealed
, -EPERM
);
398 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_S16
);
402 r
= add_rtattr(m
, type
, &data
, sizeof(int16_t));
409 int sd_netlink_message_append_s32(sd_netlink_message
*m
, unsigned short type
, int32_t data
) {
412 assert_return(m
, -EINVAL
);
413 assert_return(!m
->sealed
, -EPERM
);
415 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_S32
);
419 r
= add_rtattr(m
, type
, &data
, sizeof(int32_t));
426 int sd_netlink_message_append_s64(sd_netlink_message
*m
, unsigned short type
, int64_t data
) {
429 assert_return(m
, -EINVAL
);
430 assert_return(!m
->sealed
, -EPERM
);
432 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_S64
);
436 r
= add_rtattr(m
, type
, &data
, sizeof(int64_t));
443 int sd_netlink_message_append_data(sd_netlink_message
*m
, unsigned short type
, const void *data
, size_t len
) {
446 assert_return(m
, -EINVAL
);
447 assert_return(!m
->sealed
, -EPERM
);
449 r
= add_rtattr(m
, type
, data
, len
);
456 int netlink_message_append_in_addr_union(sd_netlink_message
*m
, unsigned short type
, int family
, const union in_addr_union
*data
) {
459 assert_return(m
, -EINVAL
);
460 assert_return(!m
->sealed
, -EPERM
);
461 assert_return(data
, -EINVAL
);
462 assert_return(IN_SET(family
, AF_INET
, AF_INET6
), -EINVAL
);
464 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_IN_ADDR
);
468 r
= add_rtattr(m
, type
, data
, FAMILY_ADDRESS_SIZE(family
));
475 int sd_netlink_message_append_in_addr(sd_netlink_message
*m
, unsigned short type
, const struct in_addr
*data
) {
476 return netlink_message_append_in_addr_union(m
, type
, AF_INET
, (const union in_addr_union
*) data
);
479 int sd_netlink_message_append_in6_addr(sd_netlink_message
*m
, unsigned short type
, const struct in6_addr
*data
) {
480 return netlink_message_append_in_addr_union(m
, type
, AF_INET6
, (const union in_addr_union
*) data
);
483 int netlink_message_append_sockaddr_union(sd_netlink_message
*m
, unsigned short type
, const union sockaddr_union
*data
) {
486 assert_return(m
, -EINVAL
);
487 assert_return(!m
->sealed
, -EPERM
);
488 assert_return(data
, -EINVAL
);
489 assert_return(IN_SET(data
->sa
.sa_family
, AF_INET
, AF_INET6
), -EINVAL
);
491 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_SOCKADDR
);
495 r
= add_rtattr(m
, type
, data
, data
->sa
.sa_family
== AF_INET
? sizeof(struct sockaddr_in
) : sizeof(struct sockaddr_in6
));
502 int sd_netlink_message_append_sockaddr_in(sd_netlink_message
*m
, unsigned short type
, const struct sockaddr_in
*data
) {
503 return netlink_message_append_sockaddr_union(m
, type
, (const union sockaddr_union
*) data
);
506 int sd_netlink_message_append_sockaddr_in6(sd_netlink_message
*m
, unsigned short type
, const struct sockaddr_in6
*data
) {
507 return netlink_message_append_sockaddr_union(m
, type
, (const union sockaddr_union
*) data
);
510 int sd_netlink_message_append_ether_addr(sd_netlink_message
*m
, unsigned short type
, const struct ether_addr
*data
) {
513 assert_return(m
, -EINVAL
);
514 assert_return(!m
->sealed
, -EPERM
);
515 assert_return(data
, -EINVAL
);
517 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_ETHER_ADDR
);
521 r
= add_rtattr(m
, type
, data
, ETH_ALEN
);
528 int netlink_message_append_hw_addr(sd_netlink_message
*m
, unsigned short type
, const struct hw_addr_data
*data
) {
531 assert_return(m
, -EINVAL
);
532 assert_return(!m
->sealed
, -EPERM
);
533 assert_return(data
, -EINVAL
);
534 assert_return(data
->length
> 0, -EINVAL
);
536 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_ETHER_ADDR
);
540 r
= add_rtattr(m
, type
, data
->bytes
, data
->length
);
547 int sd_netlink_message_append_cache_info(sd_netlink_message
*m
, unsigned short type
, const struct ifa_cacheinfo
*info
) {
550 assert_return(m
, -EINVAL
);
551 assert_return(!m
->sealed
, -EPERM
);
552 assert_return(info
, -EINVAL
);
554 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_CACHE_INFO
);
558 r
= add_rtattr(m
, type
, info
, sizeof(struct ifa_cacheinfo
));
565 int sd_netlink_message_open_container(sd_netlink_message
*m
, unsigned short type
) {
569 assert_return(m
, -EINVAL
);
570 assert_return(!m
->sealed
, -EPERM
);
571 /* m->containers[m->n_containers + 1] is accessed both in read and write. Prevent access out of bound */
572 assert_return(m
->n_containers
< (NETLINK_CONTAINER_DEPTH
- 1), -ERANGE
);
574 r
= message_attribute_has_type(m
, &size
, type
, NETLINK_TYPE_NESTED
);
576 const NLTypeSystemUnion
*type_system_union
;
579 r
= message_attribute_has_type(m
, &size
, type
, NETLINK_TYPE_UNION
);
583 r
= sd_rtnl_message_get_family(m
, &family
);
587 r
= type_system_get_type_system_union(m
->containers
[m
->n_containers
].type_system
, &type_system_union
, type
);
591 r
= type_system_union_get_type_system_by_protocol(
593 &m
->containers
[m
->n_containers
+ 1].type_system
,
598 r
= type_system_get_type_system(m
->containers
[m
->n_containers
].type_system
,
599 &m
->containers
[m
->n_containers
+ 1].type_system
,
605 r
= add_rtattr(m
, type
| NLA_F_NESTED
, NULL
, size
);
609 m
->containers
[m
->n_containers
++].offset
= r
;
614 int sd_netlink_message_open_container_union(sd_netlink_message
*m
, unsigned short type
, const char *key
) {
615 const NLTypeSystemUnion
*type_system_union
;
618 assert_return(m
, -EINVAL
);
619 assert_return(!m
->sealed
, -EPERM
);
620 assert_return(m
->n_containers
< (NETLINK_CONTAINER_DEPTH
- 1), -ERANGE
);
622 r
= type_system_get_type_system_union(m
->containers
[m
->n_containers
].type_system
, &type_system_union
, type
);
626 r
= type_system_union_get_type_system_by_string(
628 &m
->containers
[m
->n_containers
+ 1].type_system
,
633 r
= sd_netlink_message_append_string(m
, type_system_union_get_match_attribute(type_system_union
), key
);
637 /* do we ever need non-null size */
638 r
= add_rtattr(m
, type
| NLA_F_NESTED
, NULL
, 0);
642 m
->containers
[m
->n_containers
++].offset
= r
;
647 int sd_netlink_message_close_container(sd_netlink_message
*m
) {
648 assert_return(m
, -EINVAL
);
649 assert_return(!m
->sealed
, -EPERM
);
650 assert_return(m
->n_containers
> 0, -EINVAL
);
652 m
->containers
[m
->n_containers
].type_system
= NULL
;
653 m
->containers
[m
->n_containers
].offset
= 0;
659 int sd_netlink_message_open_array(sd_netlink_message
*m
, uint16_t type
) {
662 assert_return(m
, -EINVAL
);
663 assert_return(!m
->sealed
, -EPERM
);
664 assert_return(m
->n_containers
< (NETLINK_CONTAINER_DEPTH
- 1), -ERANGE
);
666 r
= add_rtattr(m
, type
| NLA_F_NESTED
, NULL
, 0);
670 m
->containers
[m
->n_containers
].offset
= r
;
672 m
->containers
[m
->n_containers
].type_system
= m
->containers
[m
->n_containers
- 1].type_system
;
677 int sd_netlink_message_cancel_array(sd_netlink_message
*m
) {
680 assert_return(m
, -EINVAL
);
681 assert_return(!m
->sealed
, -EPERM
);
682 assert_return(m
->n_containers
> 1, -EINVAL
);
684 rta_len
= GET_CONTAINER(m
, (m
->n_containers
- 1))->rta_len
;
686 for (unsigned i
= 0; i
< m
->n_containers
; i
++)
687 GET_CONTAINER(m
, i
)->rta_len
-= rta_len
;
689 m
->hdr
->nlmsg_len
-= rta_len
;
692 m
->containers
[m
->n_containers
].type_system
= NULL
;
697 static int netlink_message_read_internal(
698 sd_netlink_message
*m
,
701 bool *ret_net_byteorder
) {
703 struct netlink_attribute
*attribute
;
706 assert_return(m
, -EINVAL
);
707 assert_return(m
->sealed
, -EPERM
);
709 assert(m
->n_containers
< NETLINK_CONTAINER_DEPTH
);
711 if (!m
->containers
[m
->n_containers
].attributes
)
714 if (type
>= m
->containers
[m
->n_containers
].n_attributes
)
717 attribute
= &m
->containers
[m
->n_containers
].attributes
[type
];
719 if (attribute
->offset
== 0)
722 rta
= (struct rtattr
*)((uint8_t *) m
->hdr
+ attribute
->offset
);
725 *ret_data
= RTA_DATA(rta
);
727 if (ret_net_byteorder
)
728 *ret_net_byteorder
= attribute
->net_byteorder
;
730 return RTA_PAYLOAD(rta
);
733 int sd_netlink_message_read(sd_netlink_message
*m
, unsigned short type
, size_t size
, void *data
) {
737 assert_return(m
, -EINVAL
);
739 r
= netlink_message_read_internal(m
, type
, &attr_data
, NULL
);
743 if ((size_t) r
< size
)
747 memcpy(data
, attr_data
, size
);
752 int sd_netlink_message_read_data(sd_netlink_message
*m
, unsigned short type
, size_t *ret_size
, void **ret_data
) {
753 void *attr_data
, *data
;
756 assert_return(m
, -EINVAL
);
758 r
= netlink_message_read_internal(m
, type
, &attr_data
, NULL
);
763 data
= memdup(attr_data
, r
);
776 int sd_netlink_message_read_string_strdup(sd_netlink_message
*m
, unsigned short type
, char **data
) {
781 assert_return(m
, -EINVAL
);
783 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_STRING
);
787 r
= netlink_message_read_internal(m
, type
, &attr_data
, NULL
);
792 str
= strndup(attr_data
, r
);
802 int sd_netlink_message_read_string(sd_netlink_message
*m
, unsigned short type
, const char **data
) {
806 assert_return(m
, -EINVAL
);
808 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_STRING
);
812 r
= netlink_message_read_internal(m
, type
, &attr_data
, NULL
);
815 else if (strnlen(attr_data
, r
) >= (size_t) r
)
819 *data
= (const char *) attr_data
;
824 int sd_netlink_message_read_u8(sd_netlink_message
*m
, unsigned short type
, uint8_t *data
) {
828 assert_return(m
, -EINVAL
);
830 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_U8
);
834 r
= netlink_message_read_internal(m
, type
, &attr_data
, NULL
);
837 else if ((size_t) r
< sizeof(uint8_t))
841 *data
= *(uint8_t *) attr_data
;
846 int sd_netlink_message_read_u16(sd_netlink_message
*m
, unsigned short type
, uint16_t *data
) {
851 assert_return(m
, -EINVAL
);
853 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_U16
);
857 r
= netlink_message_read_internal(m
, type
, &attr_data
, &net_byteorder
);
860 else if ((size_t) r
< sizeof(uint16_t))
865 *data
= be16toh(*(uint16_t *) attr_data
);
867 *data
= *(uint16_t *) attr_data
;
873 int sd_netlink_message_read_u32(sd_netlink_message
*m
, unsigned short type
, uint32_t *data
) {
878 assert_return(m
, -EINVAL
);
880 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_U32
);
884 r
= netlink_message_read_internal(m
, type
, &attr_data
, &net_byteorder
);
887 else if ((size_t) r
< sizeof(uint32_t))
892 *data
= be32toh(*(uint32_t *) attr_data
);
894 *data
= *(uint32_t *) attr_data
;
900 int sd_netlink_message_read_ether_addr(sd_netlink_message
*m
, unsigned short type
, struct ether_addr
*data
) {
904 assert_return(m
, -EINVAL
);
906 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_ETHER_ADDR
);
910 r
= netlink_message_read_internal(m
, type
, &attr_data
, NULL
);
913 else if ((size_t) r
< sizeof(struct ether_addr
))
917 memcpy(data
, attr_data
, sizeof(struct ether_addr
));
922 int netlink_message_read_hw_addr(sd_netlink_message
*m
, unsigned short type
, struct hw_addr_data
*data
) {
926 assert_return(m
, -EINVAL
);
928 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_ETHER_ADDR
);
932 r
= netlink_message_read_internal(m
, type
, &attr_data
, NULL
);
935 else if (r
> HW_ADDR_MAX_SIZE
)
939 memcpy(data
->bytes
, attr_data
, r
);
946 int sd_netlink_message_read_cache_info(sd_netlink_message
*m
, unsigned short type
, struct ifa_cacheinfo
*info
) {
950 assert_return(m
, -EINVAL
);
952 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_CACHE_INFO
);
956 r
= netlink_message_read_internal(m
, type
, &attr_data
, NULL
);
959 else if ((size_t) r
< sizeof(struct ifa_cacheinfo
))
963 memcpy(info
, attr_data
, sizeof(struct ifa_cacheinfo
));
968 int netlink_message_read_in_addr_union(sd_netlink_message
*m
, unsigned short type
, int family
, union in_addr_union
*data
) {
972 assert_return(m
, -EINVAL
);
973 assert_return(IN_SET(family
, AF_INET
, AF_INET6
), -EINVAL
);
975 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_IN_ADDR
);
979 r
= netlink_message_read_internal(m
, type
, &attr_data
, NULL
);
982 else if ((size_t) r
< FAMILY_ADDRESS_SIZE(family
))
986 memcpy(data
, attr_data
, FAMILY_ADDRESS_SIZE(family
));
991 int sd_netlink_message_read_in_addr(sd_netlink_message
*m
, unsigned short type
, struct in_addr
*data
) {
992 union in_addr_union u
;
995 r
= netlink_message_read_in_addr_union(m
, type
, AF_INET
, &u
);
1002 int sd_netlink_message_read_in6_addr(sd_netlink_message
*m
, unsigned short type
, struct in6_addr
*data
) {
1003 union in_addr_union u
;
1006 r
= netlink_message_read_in_addr_union(m
, type
, AF_INET6
, &u
);
1013 int sd_netlink_message_has_flag(sd_netlink_message
*m
, unsigned short type
) {
1017 assert_return(m
, -EINVAL
);
1019 /* This returns 1 when the flag is set, 0 when not set, negative errno on error. */
1021 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_FLAG
);
1025 r
= netlink_message_read_internal(m
, type
, &attr_data
, NULL
);
1034 int sd_netlink_message_read_strv(sd_netlink_message
*m
, unsigned short container_type
, unsigned short type_id
, char ***ret
) {
1035 _cleanup_strv_free_
char **s
= NULL
;
1036 const NLTypeSystem
*type_system
;
1037 const NLType
*nl_type
;
1043 assert_return(m
, -EINVAL
);
1044 assert_return(m
->n_containers
< NETLINK_CONTAINER_DEPTH
, -EINVAL
);
1046 r
= type_system_get_type(m
->containers
[m
->n_containers
].type_system
,
1052 if (type_get_type(nl_type
) != NETLINK_TYPE_NESTED
)
1055 r
= type_system_get_type_system(m
->containers
[m
->n_containers
].type_system
,
1061 r
= type_system_get_type(type_system
, &nl_type
, type_id
);
1065 if (type_get_type(nl_type
) != NETLINK_TYPE_STRING
)
1068 r
= netlink_message_read_internal(m
, container_type
, &container
, NULL
);
1072 rt_len
= (size_t) r
;
1075 /* RTA_OK() macro compares with rta->rt_len, which is unsigned short, and
1076 * LGTM.com analysis does not like the type difference. Hence, here we
1077 * introduce an unsigned short variable as a workaround. */
1078 unsigned short len
= rt_len
;
1079 for (; RTA_OK(rta
, len
); rta
= RTA_NEXT(rta
, len
)) {
1080 unsigned short type
;
1082 type
= RTA_TYPE(rta
);
1083 if (type
!= type_id
)
1086 r
= strv_extend(&s
, RTA_DATA(rta
));
1095 static int netlink_container_parse(sd_netlink_message
*m
,
1096 struct netlink_container
*container
,
1099 _cleanup_free_
struct netlink_attribute
*attributes
= NULL
;
1102 /* RTA_OK() macro compares with rta->rt_len, which is unsigned short, and
1103 * LGTM.com analysis does not like the type difference. Hence, here we
1104 * introduce an unsigned short variable as a workaround. */
1105 unsigned short len
= rt_len
;
1106 for (; RTA_OK(rta
, len
); rta
= RTA_NEXT(rta
, len
)) {
1107 unsigned short type
;
1109 type
= RTA_TYPE(rta
);
1111 if (!GREEDY_REALLOC0(attributes
, type
+ 1))
1114 if (attributes
[type
].offset
!= 0)
1115 log_debug("sd-netlink: message parse - overwriting repeated attribute");
1117 attributes
[type
].offset
= (uint8_t *) rta
- (uint8_t *) m
->hdr
;
1118 attributes
[type
].nested
= RTA_FLAGS(rta
) & NLA_F_NESTED
;
1119 attributes
[type
].net_byteorder
= RTA_FLAGS(rta
) & NLA_F_NET_BYTEORDER
;
1125 container
->attributes
= TAKE_PTR(attributes
);
1126 container
->n_attributes
= n
;
1131 int sd_netlink_message_enter_container(sd_netlink_message
*m
, unsigned short type_id
) {
1132 const NLType
*nl_type
;
1133 const NLTypeSystem
*type_system
;
1139 assert_return(m
, -EINVAL
);
1140 assert_return(m
->n_containers
< (NETLINK_CONTAINER_DEPTH
- 1), -EINVAL
);
1142 r
= type_system_get_type(m
->containers
[m
->n_containers
].type_system
,
1148 type
= type_get_type(nl_type
);
1150 if (type
== NETLINK_TYPE_NESTED
) {
1151 r
= type_system_get_type_system(m
->containers
[m
->n_containers
].type_system
,
1156 } else if (type
== NETLINK_TYPE_UNION
) {
1157 const NLTypeSystemUnion
*type_system_union
;
1159 r
= type_system_get_type_system_union(m
->containers
[m
->n_containers
].type_system
,
1165 switch (type_system_union_get_match_type(type_system_union
)) {
1166 case NL_MATCH_SIBLING
: {
1169 r
= sd_netlink_message_read_string(
1171 type_system_union_get_match_attribute(type_system_union
),
1176 r
= type_system_union_get_type_system_by_string(
1185 case NL_MATCH_PROTOCOL
: {
1188 r
= sd_rtnl_message_get_family(m
, &family
);
1192 r
= type_system_union_get_type_system_by_protocol(
1202 assert_not_reached();
1207 r
= netlink_message_read_internal(m
, type_id
, &container
, NULL
);
1214 r
= netlink_container_parse(m
,
1215 &m
->containers
[m
->n_containers
],
1223 m
->containers
[m
->n_containers
].type_system
= type_system
;
1228 int sd_netlink_message_enter_array(sd_netlink_message
*m
, unsigned short type_id
) {
1233 assert_return(m
, -EINVAL
);
1234 assert_return(m
->n_containers
< (NETLINK_CONTAINER_DEPTH
- 1), -EINVAL
);
1236 r
= netlink_message_read_internal(m
, type_id
, &container
, NULL
);
1243 r
= netlink_container_parse(m
,
1244 &m
->containers
[m
->n_containers
],
1252 m
->containers
[m
->n_containers
].type_system
= m
->containers
[m
->n_containers
- 1].type_system
;
1257 int sd_netlink_message_exit_container(sd_netlink_message
*m
) {
1258 assert_return(m
, -EINVAL
);
1259 assert_return(m
->sealed
, -EINVAL
);
1260 assert_return(m
->n_containers
> 0, -EINVAL
);
1262 m
->containers
[m
->n_containers
].attributes
= mfree(m
->containers
[m
->n_containers
].attributes
);
1263 m
->containers
[m
->n_containers
].type_system
= NULL
;
1270 uint32_t message_get_serial(sd_netlink_message
*m
) {
1274 return m
->hdr
->nlmsg_seq
;
1277 int sd_netlink_message_is_error(sd_netlink_message
*m
) {
1278 assert_return(m
, 0);
1279 assert_return(m
->hdr
, 0);
1281 return m
->hdr
->nlmsg_type
== NLMSG_ERROR
;
1284 int sd_netlink_message_get_errno(sd_netlink_message
*m
) {
1285 struct nlmsgerr
*err
;
1287 assert_return(m
, -EINVAL
);
1288 assert_return(m
->hdr
, -EINVAL
);
1290 if (!sd_netlink_message_is_error(m
))
1293 err
= NLMSG_DATA(m
->hdr
);
1298 static int netlink_message_parse_error(sd_netlink_message
*m
) {
1299 struct nlmsgerr
*err
= NLMSG_DATA(m
->hdr
);
1300 size_t hlen
= sizeof(struct nlmsgerr
);
1302 /* no TLVs, nothing to do here */
1303 if (!(m
->hdr
->nlmsg_flags
& NLM_F_ACK_TLVS
))
1306 /* if NLM_F_CAPPED is set then the inner err msg was capped */
1307 if (!(m
->hdr
->nlmsg_flags
& NLM_F_CAPPED
))
1308 hlen
+= err
->msg
.nlmsg_len
- sizeof(struct nlmsghdr
);
1310 if (m
->hdr
->nlmsg_len
<= NLMSG_SPACE(hlen
))
1313 return netlink_container_parse(m
,
1314 &m
->containers
[m
->n_containers
],
1315 (struct rtattr
*)((uint8_t*) NLMSG_DATA(m
->hdr
) + hlen
),
1316 NLMSG_PAYLOAD(m
->hdr
, hlen
));
1319 int sd_netlink_message_rewind(sd_netlink_message
*m
, sd_netlink
*nl
) {
1323 assert_return(m
, -EINVAL
);
1324 assert_return(nl
, -EINVAL
);
1326 /* don't allow appending to message once parsed */
1329 for (unsigned i
= 1; i
<= m
->n_containers
; i
++)
1330 m
->containers
[i
].attributes
= mfree(m
->containers
[i
].attributes
);
1332 m
->n_containers
= 0;
1334 if (m
->containers
[0].attributes
)
1335 /* top-level attributes have already been parsed */
1340 r
= type_system_root_get_type_system_and_header_size(nl
, m
->hdr
->nlmsg_type
,
1341 &m
->containers
[0].type_system
, &size
);
1345 if (sd_netlink_message_is_error(m
))
1346 return netlink_message_parse_error(m
);
1348 return netlink_container_parse(m
,
1350 (struct rtattr
*)((uint8_t*) NLMSG_DATA(m
->hdr
) + NLMSG_ALIGN(size
)),
1351 NLMSG_PAYLOAD(m
->hdr
, size
));
1354 void message_seal(sd_netlink_message
*m
) {
1360 sd_netlink_message
*sd_netlink_message_next(sd_netlink_message
*m
) {
1361 assert_return(m
, NULL
);