1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 #include <netinet/in.h>
5 #include "sd-netlink.h"
7 #include "alloc-util.h"
8 #include "ether-addr-util.h"
10 #include "memory-util.h"
11 #include "netlink-internal.h"
12 #include "netlink-types.h"
13 #include "netlink-util.h"
14 #include "socket-util.h"
15 #include "string-util.h"
18 #define GET_CONTAINER(m, i) ((struct rtattr*)((uint8_t*)(m)->hdr + (m)->containers[i].offset))
20 int message_new_empty(sd_netlink
*nl
, sd_netlink_message
**ret
) {
21 sd_netlink_message
*m
;
26 /* Note that 'nl' is currently unused, if we start using it internally we must take care to
27 * avoid problems due to mutual references between buses and their queued messages. See sd-bus. */
29 m
= new(sd_netlink_message
, 1);
33 *m
= (sd_netlink_message
) {
35 .protocol
= nl
->protocol
,
47 const NLAPolicySet
*policy_set
,
49 sd_netlink_message
**ret
) {
51 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*m
= NULL
;
59 size
= NLMSG_SPACE(header_size
);
60 assert(size
>= sizeof(struct nlmsghdr
));
62 r
= message_new_empty(nl
, &m
);
66 m
->containers
[0].policy_set
= policy_set
;
68 m
->hdr
= malloc0(size
);
72 m
->hdr
->nlmsg_flags
= nlmsg_flags
;
73 m
->hdr
->nlmsg_len
= size
;
74 m
->hdr
->nlmsg_type
= nlmsg_type
;
80 int message_new(sd_netlink
*nl
, sd_netlink_message
**ret
, uint16_t nlmsg_type
, uint16_t nlmsg_flags
) {
81 const NLAPolicySet
*policy_set
;
85 assert_return(nl
, -EINVAL
);
86 assert_return(ret
, -EINVAL
);
88 r
= netlink_get_policy_set_and_header_size(nl
, nlmsg_type
, nlmsg_flags
, &policy_set
, &size
);
92 return message_new_full(nl
, nlmsg_type
, nlmsg_flags
, policy_set
, size
, ret
);
95 int message_new_synthetic_error(sd_netlink
*nl
, int error
, uint32_t serial
, sd_netlink_message
**ret
) {
101 r
= message_new(nl
, ret
, NLMSG_ERROR
, 0);
106 (*ret
)->hdr
->nlmsg_seq
= serial
;
108 err
= NLMSG_DATA((*ret
)->hdr
);
114 int sd_netlink_message_set_request_dump(sd_netlink_message
*m
, int dump
) {
115 assert_return(m
, -EINVAL
);
116 assert_return(m
->hdr
, -EINVAL
);
117 assert_return(m
->protocol
!= NETLINK_ROUTE
||
118 IN_SET(m
->hdr
->nlmsg_type
,
119 RTM_GETLINK
, RTM_GETLINKPROP
, RTM_GETADDR
, RTM_GETROUTE
, RTM_GETNEIGH
,
120 RTM_GETRULE
, RTM_GETADDRLABEL
, RTM_GETNEXTHOP
, RTM_GETQDISC
, RTM_GETTCLASS
),
123 SET_FLAG(m
->hdr
->nlmsg_flags
, NLM_F_DUMP
, dump
);
128 DEFINE_TRIVIAL_REF_FUNC(sd_netlink_message
, sd_netlink_message
);
130 sd_netlink_message
* sd_netlink_message_unref(sd_netlink_message
*m
) {
131 while (m
&& --m
->n_ref
== 0) {
136 for (i
= 0; i
<= m
->n_containers
; i
++)
137 free(m
->containers
[i
].attributes
);
139 sd_netlink_message
*t
= m
;
147 int sd_netlink_message_get_type(sd_netlink_message
*m
, uint16_t *ret
) {
148 assert_return(m
, -EINVAL
);
149 assert_return(ret
, -EINVAL
);
151 *ret
= m
->hdr
->nlmsg_type
;
156 int sd_netlink_message_set_flags(sd_netlink_message
*m
, uint16_t flags
) {
157 assert_return(m
, -EINVAL
);
158 assert_return(flags
!= 0, -EINVAL
);
160 m
->hdr
->nlmsg_flags
= flags
;
165 int sd_netlink_message_is_broadcast(sd_netlink_message
*m
) {
166 assert_return(m
, -EINVAL
);
168 return m
->multicast_group
!= 0;
171 /* If successful the updated message will be correctly aligned, if unsuccessful the old message is untouched. */
172 static int add_rtattr(sd_netlink_message
*m
, uint16_t attr_type
, const void *data
, size_t data_length
) {
173 size_t message_length
;
174 struct nlmsghdr
*new_hdr
;
181 assert(NLMSG_ALIGN(m
->hdr
->nlmsg_len
) == m
->hdr
->nlmsg_len
);
182 assert(!data
|| data_length
> 0);
184 /* get the new message size (with padding at the end) */
185 message_length
= m
->hdr
->nlmsg_len
+ RTA_SPACE(data_length
);
187 /* buffer should be smaller than both one page or 8K to be accepted by the kernel */
188 if (message_length
> MIN(page_size(), 8192UL))
191 /* realloc to fit the new attribute */
192 new_hdr
= realloc(m
->hdr
, message_length
);
197 /* get pointer to the attribute we are about to add */
198 rta
= (struct rtattr
*) ((uint8_t *) m
->hdr
+ m
->hdr
->nlmsg_len
);
200 rtattr_append_attribute_internal(rta
, attr_type
, data
, data_length
);
202 /* if we are inside containers, extend them */
203 for (unsigned i
= 0; i
< m
->n_containers
; i
++)
204 GET_CONTAINER(m
, i
)->rta_len
+= RTA_SPACE(data_length
);
206 /* update message size */
207 offset
= m
->hdr
->nlmsg_len
;
208 m
->hdr
->nlmsg_len
= message_length
;
210 /* return old message size */
214 static int message_attribute_has_type(sd_netlink_message
*m
, size_t *ret_size
, uint16_t attr_type
, NLAType type
) {
215 const NLAPolicy
*policy
;
219 policy
= policy_set_get_policy(m
->containers
[m
->n_containers
].policy_set
, attr_type
);
223 if (policy_get_type(policy
) != type
)
227 *ret_size
= policy_get_size(policy
);
231 int sd_netlink_message_append_string(sd_netlink_message
*m
, uint16_t attr_type
, const char *data
) {
235 assert_return(m
, -EINVAL
);
236 assert_return(!m
->sealed
, -EPERM
);
237 assert_return(data
, -EINVAL
);
239 r
= message_attribute_has_type(m
, &size
, attr_type
, NETLINK_TYPE_STRING
);
244 length
= strnlen(data
, size
+1);
248 length
= strlen(data
);
250 r
= add_rtattr(m
, attr_type
, data
, length
+ 1);
257 int sd_netlink_message_append_strv(sd_netlink_message
*m
, uint16_t attr_type
, const char* const *data
) {
261 assert_return(m
, -EINVAL
);
262 assert_return(!m
->sealed
, -EPERM
);
263 assert_return(data
, -EINVAL
);
265 r
= message_attribute_has_type(m
, &size
, attr_type
, NETLINK_TYPE_STRING
);
269 STRV_FOREACH(p
, data
) {
271 length
= strnlen(*p
, size
+1);
277 r
= add_rtattr(m
, attr_type
, *p
, length
+ 1);
285 int sd_netlink_message_append_flag(sd_netlink_message
*m
, uint16_t attr_type
) {
289 assert_return(m
, -EINVAL
);
290 assert_return(!m
->sealed
, -EPERM
);
292 r
= message_attribute_has_type(m
, &size
, attr_type
, NETLINK_TYPE_FLAG
);
296 r
= add_rtattr(m
, attr_type
, NULL
, 0);
303 int sd_netlink_message_append_u8(sd_netlink_message
*m
, uint16_t attr_type
, uint8_t data
) {
306 assert_return(m
, -EINVAL
);
307 assert_return(!m
->sealed
, -EPERM
);
309 r
= message_attribute_has_type(m
, NULL
, attr_type
, NETLINK_TYPE_U8
);
313 r
= add_rtattr(m
, attr_type
, &data
, sizeof(uint8_t));
320 int sd_netlink_message_append_u16(sd_netlink_message
*m
, uint16_t attr_type
, uint16_t data
) {
323 assert_return(m
, -EINVAL
);
324 assert_return(!m
->sealed
, -EPERM
);
326 r
= message_attribute_has_type(m
, NULL
, attr_type
, NETLINK_TYPE_U16
);
330 r
= add_rtattr(m
, attr_type
, &data
, sizeof(uint16_t));
337 int sd_netlink_message_append_u32(sd_netlink_message
*m
, uint16_t attr_type
, uint32_t data
) {
340 assert_return(m
, -EINVAL
);
341 assert_return(!m
->sealed
, -EPERM
);
343 r
= message_attribute_has_type(m
, NULL
, attr_type
, NETLINK_TYPE_U32
);
347 r
= add_rtattr(m
, attr_type
, &data
, sizeof(uint32_t));
354 int sd_netlink_message_append_u64(sd_netlink_message
*m
, uint16_t attr_type
, uint64_t data
) {
357 assert_return(m
, -EINVAL
);
358 assert_return(!m
->sealed
, -EPERM
);
360 r
= message_attribute_has_type(m
, NULL
, attr_type
, NETLINK_TYPE_U64
);
364 r
= add_rtattr(m
, attr_type
, &data
, sizeof(uint64_t));
371 int sd_netlink_message_append_s8(sd_netlink_message
*m
, uint16_t attr_type
, int8_t data
) {
374 assert_return(m
, -EINVAL
);
375 assert_return(!m
->sealed
, -EPERM
);
377 r
= message_attribute_has_type(m
, NULL
, attr_type
, NETLINK_TYPE_S8
);
381 r
= add_rtattr(m
, attr_type
, &data
, sizeof(int8_t));
388 int sd_netlink_message_append_s16(sd_netlink_message
*m
, uint16_t attr_type
, int16_t data
) {
391 assert_return(m
, -EINVAL
);
392 assert_return(!m
->sealed
, -EPERM
);
394 r
= message_attribute_has_type(m
, NULL
, attr_type
, NETLINK_TYPE_S16
);
398 r
= add_rtattr(m
, attr_type
, &data
, sizeof(int16_t));
405 int sd_netlink_message_append_s32(sd_netlink_message
*m
, uint16_t attr_type
, int32_t data
) {
408 assert_return(m
, -EINVAL
);
409 assert_return(!m
->sealed
, -EPERM
);
411 r
= message_attribute_has_type(m
, NULL
, attr_type
, NETLINK_TYPE_S32
);
415 r
= add_rtattr(m
, attr_type
, &data
, sizeof(int32_t));
422 int sd_netlink_message_append_s64(sd_netlink_message
*m
, uint16_t attr_type
, int64_t data
) {
425 assert_return(m
, -EINVAL
);
426 assert_return(!m
->sealed
, -EPERM
);
428 r
= message_attribute_has_type(m
, NULL
, attr_type
, NETLINK_TYPE_S64
);
432 r
= add_rtattr(m
, attr_type
, &data
, sizeof(int64_t));
439 int sd_netlink_message_append_data(sd_netlink_message
*m
, uint16_t attr_type
, const void *data
, size_t len
) {
442 assert_return(m
, -EINVAL
);
443 assert_return(!m
->sealed
, -EPERM
);
445 r
= add_rtattr(m
, attr_type
, data
, len
);
452 int sd_netlink_message_append_container_data(
453 sd_netlink_message
*m
,
454 uint16_t container_type
,
461 assert_return(m
, -EINVAL
);
462 assert_return(!m
->sealed
, -EPERM
);
464 r
= sd_netlink_message_open_container(m
, container_type
);
468 r
= sd_netlink_message_append_data(m
, attr_type
, data
, len
);
472 return sd_netlink_message_close_container(m
);
475 int netlink_message_append_in_addr_union(sd_netlink_message
*m
, uint16_t attr_type
, int family
, const union in_addr_union
*data
) {
478 assert_return(m
, -EINVAL
);
479 assert_return(!m
->sealed
, -EPERM
);
480 assert_return(data
, -EINVAL
);
481 assert_return(IN_SET(family
, AF_INET
, AF_INET6
), -EINVAL
);
483 r
= message_attribute_has_type(m
, NULL
, attr_type
, NETLINK_TYPE_IN_ADDR
);
487 r
= add_rtattr(m
, attr_type
, data
, FAMILY_ADDRESS_SIZE(family
));
494 int sd_netlink_message_append_in_addr(sd_netlink_message
*m
, uint16_t attr_type
, const struct in_addr
*data
) {
495 return netlink_message_append_in_addr_union(m
, attr_type
, AF_INET
, (const union in_addr_union
*) data
);
498 int sd_netlink_message_append_in6_addr(sd_netlink_message
*m
, uint16_t attr_type
, const struct in6_addr
*data
) {
499 return netlink_message_append_in_addr_union(m
, attr_type
, AF_INET6
, (const union in_addr_union
*) data
);
502 int netlink_message_append_sockaddr_union(sd_netlink_message
*m
, uint16_t attr_type
, const union sockaddr_union
*data
) {
505 assert_return(m
, -EINVAL
);
506 assert_return(!m
->sealed
, -EPERM
);
507 assert_return(data
, -EINVAL
);
508 assert_return(IN_SET(data
->sa
.sa_family
, AF_INET
, AF_INET6
), -EINVAL
);
510 r
= message_attribute_has_type(m
, NULL
, attr_type
, NETLINK_TYPE_SOCKADDR
);
514 r
= add_rtattr(m
, attr_type
, data
, data
->sa
.sa_family
== AF_INET
? sizeof(struct sockaddr_in
) : sizeof(struct sockaddr_in6
));
521 int sd_netlink_message_append_sockaddr_in(sd_netlink_message
*m
, uint16_t attr_type
, const struct sockaddr_in
*data
) {
522 return netlink_message_append_sockaddr_union(m
, attr_type
, (const union sockaddr_union
*) data
);
525 int sd_netlink_message_append_sockaddr_in6(sd_netlink_message
*m
, uint16_t attr_type
, const struct sockaddr_in6
*data
) {
526 return netlink_message_append_sockaddr_union(m
, attr_type
, (const union sockaddr_union
*) data
);
529 int sd_netlink_message_append_ether_addr(sd_netlink_message
*m
, uint16_t attr_type
, const struct ether_addr
*data
) {
532 assert_return(m
, -EINVAL
);
533 assert_return(!m
->sealed
, -EPERM
);
534 assert_return(data
, -EINVAL
);
536 r
= message_attribute_has_type(m
, NULL
, attr_type
, NETLINK_TYPE_ETHER_ADDR
);
540 r
= add_rtattr(m
, attr_type
, data
, ETH_ALEN
);
547 int netlink_message_append_hw_addr(sd_netlink_message
*m
, uint16_t attr_type
, const struct hw_addr_data
*data
) {
550 assert_return(m
, -EINVAL
);
551 assert_return(!m
->sealed
, -EPERM
);
552 assert_return(data
, -EINVAL
);
553 assert_return(data
->length
> 0, -EINVAL
);
555 r
= message_attribute_has_type(m
, NULL
, attr_type
, NETLINK_TYPE_ETHER_ADDR
);
559 r
= add_rtattr(m
, attr_type
, data
->bytes
, data
->length
);
566 int sd_netlink_message_append_cache_info(sd_netlink_message
*m
, uint16_t attr_type
, const struct ifa_cacheinfo
*info
) {
569 assert_return(m
, -EINVAL
);
570 assert_return(!m
->sealed
, -EPERM
);
571 assert_return(info
, -EINVAL
);
573 r
= message_attribute_has_type(m
, NULL
, attr_type
, NETLINK_TYPE_CACHE_INFO
);
577 r
= add_rtattr(m
, attr_type
, info
, sizeof(struct ifa_cacheinfo
));
584 int sd_netlink_message_open_container(sd_netlink_message
*m
, uint16_t attr_type
) {
588 assert_return(m
, -EINVAL
);
589 assert_return(!m
->sealed
, -EPERM
);
590 /* m->containers[m->n_containers + 1] is accessed both in read and write. Prevent access out of bound */
591 assert_return(m
->n_containers
< (NETLINK_CONTAINER_DEPTH
- 1), -ERANGE
);
593 r
= message_attribute_has_type(m
, &size
, attr_type
, NETLINK_TYPE_NESTED
);
595 const NLAPolicySetUnion
*policy_set_union
;
598 r
= message_attribute_has_type(m
, &size
, attr_type
, NETLINK_TYPE_NESTED_UNION_BY_FAMILY
);
602 r
= sd_rtnl_message_get_family(m
, &family
);
606 policy_set_union
= policy_set_get_policy_set_union(
607 m
->containers
[m
->n_containers
].policy_set
,
609 if (!policy_set_union
)
612 m
->containers
[m
->n_containers
+ 1].policy_set
=
613 policy_set_union_get_policy_set_by_family(
617 m
->containers
[m
->n_containers
+ 1].policy_set
=
618 policy_set_get_policy_set(
619 m
->containers
[m
->n_containers
].policy_set
,
621 if (!m
->containers
[m
->n_containers
+ 1].policy_set
)
624 r
= add_rtattr(m
, attr_type
| NLA_F_NESTED
, NULL
, size
);
628 m
->containers
[m
->n_containers
++].offset
= r
;
633 int sd_netlink_message_open_container_union(sd_netlink_message
*m
, uint16_t attr_type
, const char *key
) {
634 const NLAPolicySetUnion
*policy_set_union
;
637 assert_return(m
, -EINVAL
);
638 assert_return(!m
->sealed
, -EPERM
);
639 assert_return(m
->n_containers
< (NETLINK_CONTAINER_DEPTH
- 1), -ERANGE
);
641 r
= message_attribute_has_type(m
, NULL
, attr_type
, NETLINK_TYPE_NESTED_UNION_BY_STRING
);
645 policy_set_union
= policy_set_get_policy_set_union(
646 m
->containers
[m
->n_containers
].policy_set
,
648 if (!policy_set_union
)
651 m
->containers
[m
->n_containers
+ 1].policy_set
=
652 policy_set_union_get_policy_set_by_string(
655 if (!m
->containers
[m
->n_containers
+ 1].policy_set
)
658 r
= sd_netlink_message_append_string(m
, policy_set_union_get_match_attribute(policy_set_union
), key
);
662 /* do we ever need non-null size */
663 r
= add_rtattr(m
, attr_type
| NLA_F_NESTED
, NULL
, 0);
667 m
->containers
[m
->n_containers
++].offset
= r
;
672 int sd_netlink_message_close_container(sd_netlink_message
*m
) {
673 assert_return(m
, -EINVAL
);
674 assert_return(!m
->sealed
, -EPERM
);
675 assert_return(m
->n_containers
> 0, -EINVAL
);
677 m
->containers
[m
->n_containers
].policy_set
= NULL
;
678 m
->containers
[m
->n_containers
].offset
= 0;
684 int sd_netlink_message_open_array(sd_netlink_message
*m
, uint16_t attr_type
) {
687 assert_return(m
, -EINVAL
);
688 assert_return(!m
->sealed
, -EPERM
);
689 assert_return(m
->n_containers
< (NETLINK_CONTAINER_DEPTH
- 1), -ERANGE
);
691 r
= add_rtattr(m
, attr_type
| NLA_F_NESTED
, NULL
, 0);
695 m
->containers
[m
->n_containers
].offset
= r
;
697 m
->containers
[m
->n_containers
].policy_set
= m
->containers
[m
->n_containers
- 1].policy_set
;
702 int sd_netlink_message_cancel_array(sd_netlink_message
*m
) {
705 assert_return(m
, -EINVAL
);
706 assert_return(!m
->sealed
, -EPERM
);
707 assert_return(m
->n_containers
> 1, -EINVAL
);
709 rta_len
= GET_CONTAINER(m
, (m
->n_containers
- 1))->rta_len
;
711 for (unsigned i
= 0; i
< m
->n_containers
; i
++)
712 GET_CONTAINER(m
, i
)->rta_len
-= rta_len
;
714 m
->hdr
->nlmsg_len
-= rta_len
;
717 m
->containers
[m
->n_containers
].policy_set
= NULL
;
722 static int netlink_message_read_internal(
723 sd_netlink_message
*m
,
726 bool *ret_net_byteorder
) {
728 struct netlink_attribute
*attribute
;
731 assert_return(m
, -EINVAL
);
732 assert_return(m
->sealed
, -EPERM
);
734 assert(m
->n_containers
< NETLINK_CONTAINER_DEPTH
);
736 if (!m
->containers
[m
->n_containers
].attributes
)
739 if (attr_type
> m
->containers
[m
->n_containers
].max_attribute
)
742 attribute
= &m
->containers
[m
->n_containers
].attributes
[attr_type
];
744 if (attribute
->offset
== 0)
747 rta
= (struct rtattr
*)((uint8_t *) m
->hdr
+ attribute
->offset
);
750 *ret_data
= RTA_DATA(rta
);
752 if (ret_net_byteorder
)
753 *ret_net_byteorder
= attribute
->net_byteorder
;
755 return RTA_PAYLOAD(rta
);
758 static int netlink_message_read_impl(
759 sd_netlink_message
*m
,
765 bool *ret_net_byteorder
) {
774 r
= message_attribute_has_type(m
, NULL
, attr_type
, type
);
779 r
= netlink_message_read_internal(m
, attr_type
, &attr_data
, &net_byteorder
);
783 if ((size_t) r
> size
)
786 if (strict
&& (size_t) r
!= size
)
790 memzero(mempcpy(ret
, attr_data
, r
), size
- (size_t) r
);
792 if (ret_net_byteorder
)
793 *ret_net_byteorder
= net_byteorder
;
798 int sd_netlink_message_read(sd_netlink_message
*m
, uint16_t attr_type
, size_t size
, void *ret
) {
799 assert_return(m
, -EINVAL
);
801 return netlink_message_read_impl(
802 m
, attr_type
, /* strict = */ false,
803 _NETLINK_TYPE_INVALID
, size
,
804 ret
, /* ret_net_byteorder = */ NULL
);
807 int sd_netlink_message_read_data(sd_netlink_message
*m
, uint16_t attr_type
, size_t *ret_size
, void **ret_data
) {
811 assert_return(m
, -EINVAL
);
813 r
= netlink_message_read_internal(m
, attr_type
, &attr_data
, NULL
);
820 data
= memdup_suffix0(attr_data
, r
);
833 int sd_netlink_message_read_string_strdup(sd_netlink_message
*m
, uint16_t attr_type
, char **ret
) {
837 assert_return(m
, -EINVAL
);
839 r
= sd_netlink_message_read_string(m
, attr_type
, &s
);
843 return strdup_to(ret
, s
);
846 int sd_netlink_message_read_string(sd_netlink_message
*m
, uint16_t attr_type
, const char **ret
) {
850 assert_return(m
, -EINVAL
);
852 r
= message_attribute_has_type(m
, NULL
, attr_type
, NETLINK_TYPE_STRING
);
856 r
= netlink_message_read_internal(m
, attr_type
, &attr_data
, NULL
);
860 if (strnlen(attr_data
, r
) >= (size_t) r
)
864 *ret
= (const char *) attr_data
;
869 int sd_netlink_message_read_u8(sd_netlink_message
*m
, uint16_t attr_type
, uint8_t *ret
) {
870 assert_return(m
, -EINVAL
);
872 return netlink_message_read_impl(
873 m
, attr_type
, /* strict = */ true,
874 NETLINK_TYPE_U8
, sizeof(uint8_t),
875 ret
, /* ret_net_byteorder = */ NULL
);
878 int sd_netlink_message_read_u16(sd_netlink_message
*m
, uint16_t attr_type
, uint16_t *ret
) {
883 assert_return(m
, -EINVAL
);
885 r
= netlink_message_read_impl(
886 m
, attr_type
, /* strict = */ true,
887 NETLINK_TYPE_U16
, sizeof(uint16_t),
888 ret
? &u
: NULL
, &net_byteorder
);
893 *ret
= net_byteorder
? be16toh(u
) : u
;
898 int sd_netlink_message_read_u32(sd_netlink_message
*m
, uint16_t attr_type
, uint32_t *ret
) {
903 assert_return(m
, -EINVAL
);
905 r
= netlink_message_read_impl(
906 m
, attr_type
, /* strict = */ true,
907 NETLINK_TYPE_U32
, sizeof(uint32_t),
908 ret
? &u
: NULL
, &net_byteorder
);
913 *ret
= net_byteorder
? be32toh(u
) : u
;
918 int sd_netlink_message_read_u64(sd_netlink_message
*m
, uint16_t attr_type
, uint64_t *ret
) {
923 assert_return(m
, -EINVAL
);
925 r
= netlink_message_read_impl(
926 m
, attr_type
, /* strict = */ true,
927 NETLINK_TYPE_U64
, sizeof(uint64_t),
928 ret
? &u
: NULL
, &net_byteorder
);
933 *ret
= net_byteorder
? be64toh(u
) : u
;
938 int sd_netlink_message_read_ether_addr(sd_netlink_message
*m
, uint16_t attr_type
, struct ether_addr
*ret
) {
939 assert_return(m
, -EINVAL
);
941 return netlink_message_read_impl(
942 m
, attr_type
, /* strict = */ true,
943 NETLINK_TYPE_ETHER_ADDR
, sizeof(struct ether_addr
),
944 ret
, /* ret_net_byteorder = */ NULL
);
947 int netlink_message_read_hw_addr(sd_netlink_message
*m
, uint16_t attr_type
, struct hw_addr_data
*ret
) {
950 assert_return(m
, -EINVAL
);
952 r
= netlink_message_read_impl(
953 m
, attr_type
, /* strict = */ false,
954 NETLINK_TYPE_ETHER_ADDR
, HW_ADDR_MAX_SIZE
,
955 ret
? ret
->bytes
: NULL
, /* ret_net_byteorder = */ NULL
);
965 int sd_netlink_message_read_cache_info(sd_netlink_message
*m
, uint16_t attr_type
, struct ifa_cacheinfo
*ret
) {
966 assert_return(m
, -EINVAL
);
968 return netlink_message_read_impl(
969 m
, attr_type
, /* strict = */ true,
970 NETLINK_TYPE_CACHE_INFO
, sizeof(struct ifa_cacheinfo
),
971 ret
, /* ret_net_byteorder = */ NULL
);
974 int netlink_message_read_in_addr_union(sd_netlink_message
*m
, uint16_t attr_type
, int family
, union in_addr_union
*ret
) {
977 assert_return(m
, -EINVAL
);
978 assert_return(IN_SET(family
, AF_INET
, AF_INET6
), -EINVAL
);
980 r
= netlink_message_read_impl(
981 m
, attr_type
, /* strict = */ true,
982 NETLINK_TYPE_IN_ADDR
, FAMILY_ADDRESS_SIZE(family
),
983 ret
, /* ret_net_byteorder = */ NULL
);
988 memzero((uint8_t*) ret
+ FAMILY_ADDRESS_SIZE(family
), sizeof(union in_addr_union
) - FAMILY_ADDRESS_SIZE(family
));
993 int sd_netlink_message_read_in_addr(sd_netlink_message
*m
, uint16_t attr_type
, struct in_addr
*ret
) {
994 assert_return(m
, -EINVAL
);
996 return netlink_message_read_impl(
997 m
, attr_type
, /* strict = */ true,
998 NETLINK_TYPE_IN_ADDR
, sizeof(struct in_addr
),
999 ret
, /* ret_net_byteorder = */ NULL
);
1002 int sd_netlink_message_read_in6_addr(sd_netlink_message
*m
, uint16_t attr_type
, struct in6_addr
*ret
) {
1003 assert_return(m
, -EINVAL
);
1005 return netlink_message_read_impl(
1006 m
, attr_type
, /* strict = */ true,
1007 NETLINK_TYPE_IN_ADDR
, sizeof(struct in6_addr
),
1008 ret
, /* ret_net_byteorder = */ NULL
);
1011 int sd_netlink_message_has_flag(sd_netlink_message
*m
, uint16_t attr_type
) {
1015 assert_return(m
, -EINVAL
);
1017 /* This returns 1 when the flag is set, 0 when not set, negative errno on error. */
1019 r
= message_attribute_has_type(m
, NULL
, attr_type
, NETLINK_TYPE_FLAG
);
1023 r
= netlink_message_read_internal(m
, attr_type
, &attr_data
, NULL
);
1032 int sd_netlink_message_read_strv(sd_netlink_message
*m
, uint16_t container_type
, uint16_t attr_type
, char ***ret
) {
1033 _cleanup_strv_free_
char **s
= NULL
;
1034 const NLAPolicySet
*policy_set
;
1035 const NLAPolicy
*policy
;
1041 assert_return(m
, -EINVAL
);
1042 assert_return(m
->n_containers
< NETLINK_CONTAINER_DEPTH
, -EINVAL
);
1044 policy
= policy_set_get_policy(
1045 m
->containers
[m
->n_containers
].policy_set
,
1050 if (policy_get_type(policy
) != NETLINK_TYPE_NESTED
)
1053 policy_set
= policy_set_get_policy_set(
1054 m
->containers
[m
->n_containers
].policy_set
,
1059 policy
= policy_set_get_policy(policy_set
, attr_type
);
1063 if (policy_get_type(policy
) != NETLINK_TYPE_STRING
)
1066 r
= netlink_message_read_internal(m
, container_type
, &container
, NULL
);
1070 rt_len
= (size_t) r
;
1073 /* RTA_OK() macro compares with rta->rt_len, which is unsigned short, and
1074 * LGTM.com analysis does not like the type difference. Hence, here we
1075 * introduce an unsigned short variable as a workaround. */
1076 unsigned short len
= rt_len
;
1077 for (; RTA_OK(rta
, len
); rta
= RTA_NEXT(rta
, len
)) {
1080 type
= RTA_TYPE(rta
);
1081 if (type
!= attr_type
)
1084 r
= strv_extend(&s
, RTA_DATA(rta
));
1093 static int netlink_container_parse(
1094 sd_netlink_message
*m
,
1095 struct netlink_container
*container
,
1099 _cleanup_free_
struct netlink_attribute
*attributes
= NULL
;
1100 uint16_t max_attr
= 0;
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
)) {
1109 attr
= RTA_TYPE(rta
);
1110 max_attr
= MAX(max_attr
, attr
);
1112 if (!GREEDY_REALLOC0(attributes
, (size_t) max_attr
+ 1))
1115 if (attributes
[attr
].offset
!= 0)
1116 log_debug("sd-netlink: message parse - overwriting repeated attribute");
1118 attributes
[attr
].offset
= (uint8_t *) rta
- (uint8_t *) m
->hdr
;
1119 attributes
[attr
].nested
= RTA_FLAGS(rta
) & NLA_F_NESTED
;
1120 attributes
[attr
].net_byteorder
= RTA_FLAGS(rta
) & NLA_F_NET_BYTEORDER
;
1123 container
->attributes
= TAKE_PTR(attributes
);
1124 container
->max_attribute
= max_attr
;
1129 int sd_netlink_message_enter_container(sd_netlink_message
*m
, uint16_t attr_type
) {
1130 const NLAPolicy
*policy
;
1131 const NLAPolicySet
*policy_set
;
1136 assert_return(m
, -EINVAL
);
1137 assert_return(m
->n_containers
< (NETLINK_CONTAINER_DEPTH
- 1), -EINVAL
);
1139 policy
= policy_set_get_policy(
1140 m
->containers
[m
->n_containers
].policy_set
,
1145 switch (policy_get_type(policy
)) {
1146 case NETLINK_TYPE_NESTED
:
1147 policy_set
= policy_set_get_policy_set(
1148 m
->containers
[m
->n_containers
].policy_set
,
1152 case NETLINK_TYPE_NESTED_UNION_BY_STRING
: {
1153 const NLAPolicySetUnion
*policy_set_union
;
1156 policy_set_union
= policy_get_policy_set_union(policy
);
1157 if (!policy_set_union
)
1160 r
= sd_netlink_message_read_string(
1162 policy_set_union_get_match_attribute(policy_set_union
),
1167 policy_set
= policy_set_union_get_policy_set_by_string(
1172 case NETLINK_TYPE_NESTED_UNION_BY_FAMILY
: {
1173 const NLAPolicySetUnion
*policy_set_union
;
1176 policy_set_union
= policy_get_policy_set_union(policy
);
1177 if (!policy_set_union
)
1180 r
= sd_rtnl_message_get_family(m
, &family
);
1184 policy_set
= policy_set_union_get_policy_set_by_family(
1190 assert_not_reached();
1195 r
= netlink_message_read_internal(m
, attr_type
, &container
, NULL
);
1202 r
= netlink_container_parse(m
,
1203 &m
->containers
[m
->n_containers
],
1211 m
->containers
[m
->n_containers
].policy_set
= policy_set
;
1216 int sd_netlink_message_enter_array(sd_netlink_message
*m
, uint16_t attr_type
) {
1221 assert_return(m
, -EINVAL
);
1222 assert_return(m
->n_containers
< (NETLINK_CONTAINER_DEPTH
- 1), -EINVAL
);
1224 r
= netlink_message_read_internal(m
, attr_type
, &container
, NULL
);
1231 r
= netlink_container_parse(m
,
1232 &m
->containers
[m
->n_containers
],
1240 m
->containers
[m
->n_containers
].policy_set
= m
->containers
[m
->n_containers
- 1].policy_set
;
1245 int sd_netlink_message_exit_container(sd_netlink_message
*m
) {
1246 assert_return(m
, -EINVAL
);
1247 assert_return(m
->sealed
, -EINVAL
);
1248 assert_return(m
->n_containers
> 0, -EINVAL
);
1250 m
->containers
[m
->n_containers
].attributes
= mfree(m
->containers
[m
->n_containers
].attributes
);
1251 m
->containers
[m
->n_containers
].max_attribute
= 0;
1252 m
->containers
[m
->n_containers
].policy_set
= NULL
;
1259 int sd_netlink_message_get_max_attribute(sd_netlink_message
*m
, uint16_t *ret
) {
1260 assert_return(m
, -EINVAL
);
1261 assert_return(m
->sealed
, -EINVAL
);
1262 assert_return(ret
, -EINVAL
);
1264 *ret
= m
->containers
[m
->n_containers
].max_attribute
;
1268 int sd_netlink_message_is_error(sd_netlink_message
*m
) {
1269 assert_return(m
, 0);
1270 assert_return(m
->hdr
, 0);
1272 return m
->hdr
->nlmsg_type
== NLMSG_ERROR
;
1275 int sd_netlink_message_get_errno(sd_netlink_message
*m
) {
1276 struct nlmsgerr
*err
;
1278 assert_return(m
, -EINVAL
);
1279 assert_return(m
->hdr
, -EINVAL
);
1281 if (!sd_netlink_message_is_error(m
))
1284 err
= NLMSG_DATA(m
->hdr
);
1289 static int netlink_message_parse_error(sd_netlink_message
*m
) {
1290 struct nlmsgerr
*err
= NLMSG_DATA(m
->hdr
);
1291 size_t hlen
= sizeof(struct nlmsgerr
);
1293 /* no TLVs, nothing to do here */
1294 if (!(m
->hdr
->nlmsg_flags
& NLM_F_ACK_TLVS
))
1297 /* if NLM_F_CAPPED is set then the inner err msg was capped */
1298 if (!(m
->hdr
->nlmsg_flags
& NLM_F_CAPPED
))
1299 hlen
+= err
->msg
.nlmsg_len
- sizeof(struct nlmsghdr
);
1301 if (m
->hdr
->nlmsg_len
<= NLMSG_SPACE(hlen
))
1304 return netlink_container_parse(m
,
1305 &m
->containers
[m
->n_containers
],
1306 (struct rtattr
*)((uint8_t*) NLMSG_DATA(m
->hdr
) + hlen
),
1307 NLMSG_PAYLOAD(m
->hdr
, hlen
));
1310 int sd_netlink_message_rewind(sd_netlink_message
*m
, sd_netlink
*nl
) {
1314 assert_return(m
, -EINVAL
);
1315 assert_return(nl
, -EINVAL
);
1317 /* don't allow appending to message once parsed */
1320 for (unsigned i
= 1; i
<= m
->n_containers
; i
++)
1321 m
->containers
[i
].attributes
= mfree(m
->containers
[i
].attributes
);
1323 m
->n_containers
= 0;
1325 if (m
->containers
[0].attributes
)
1326 /* top-level attributes have already been parsed */
1331 r
= netlink_get_policy_set_and_header_size(
1334 m
->hdr
->nlmsg_flags
,
1335 &m
->containers
[0].policy_set
,
1340 if (sd_netlink_message_is_error(m
))
1341 return netlink_message_parse_error(m
);
1343 return netlink_container_parse(m
,
1345 (struct rtattr
*)((uint8_t*) NLMSG_DATA(m
->hdr
) + NLMSG_ALIGN(size
)),
1346 NLMSG_PAYLOAD(m
->hdr
, size
));
1349 void message_seal(sd_netlink_message
*m
) {
1355 sd_netlink_message
* sd_netlink_message_next(sd_netlink_message
*m
) {
1356 assert_return(m
, NULL
);