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 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
,
46 const NLAPolicySet
*policy_set
,
48 sd_netlink_message
**ret
) {
50 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*m
= NULL
;
58 size
= NLMSG_SPACE(header_size
);
59 assert(size
>= sizeof(struct nlmsghdr
));
61 r
= message_new_empty(nl
, &m
);
65 m
->containers
[0].policy_set
= policy_set
;
67 m
->hdr
= malloc0(size
);
71 m
->hdr
->nlmsg_flags
= NLM_F_REQUEST
| NLM_F_ACK
;
72 m
->hdr
->nlmsg_len
= size
;
73 m
->hdr
->nlmsg_type
= nlmsg_type
;
79 int message_new(sd_netlink
*nl
, sd_netlink_message
**ret
, uint16_t nlmsg_type
) {
80 const NLAPolicySet
*policy_set
;
84 assert_return(nl
, -EINVAL
);
85 assert_return(ret
, -EINVAL
);
87 r
= netlink_get_policy_set_and_header_size(nl
, nlmsg_type
, &policy_set
, &size
);
91 return message_new_full(nl
, nlmsg_type
, policy_set
, size
, ret
);
94 int message_new_synthetic_error(sd_netlink
*nl
, int error
, uint32_t serial
, sd_netlink_message
**ret
) {
100 r
= message_new(nl
, ret
, NLMSG_ERROR
);
105 (*ret
)->hdr
->nlmsg_seq
= serial
;
107 err
= NLMSG_DATA((*ret
)->hdr
);
113 int sd_netlink_message_set_request_dump(sd_netlink_message
*m
, int dump
) {
114 assert_return(m
, -EINVAL
);
115 assert_return(m
->hdr
, -EINVAL
);
116 assert_return(m
->protocol
!= NETLINK_ROUTE
||
117 IN_SET(m
->hdr
->nlmsg_type
,
118 RTM_GETLINK
, RTM_GETLINKPROP
, RTM_GETADDR
, RTM_GETROUTE
, RTM_GETNEIGH
,
119 RTM_GETRULE
, RTM_GETADDRLABEL
, RTM_GETNEXTHOP
, RTM_GETQDISC
, RTM_GETTCLASS
),
122 SET_FLAG(m
->hdr
->nlmsg_flags
, NLM_F_DUMP
, dump
);
127 DEFINE_TRIVIAL_REF_FUNC(sd_netlink_message
, sd_netlink_message
);
129 sd_netlink_message
* sd_netlink_message_unref(sd_netlink_message
*m
) {
130 while (m
&& --m
->n_ref
== 0) {
135 for (i
= 0; i
<= m
->n_containers
; i
++)
136 free(m
->containers
[i
].attributes
);
138 sd_netlink_message
*t
= m
;
146 int sd_netlink_message_get_type(sd_netlink_message
*m
, uint16_t *ret
) {
147 assert_return(m
, -EINVAL
);
148 assert_return(ret
, -EINVAL
);
150 *ret
= m
->hdr
->nlmsg_type
;
155 int sd_netlink_message_set_flags(sd_netlink_message
*m
, uint16_t flags
) {
156 assert_return(m
, -EINVAL
);
157 assert_return(flags
!= 0, -EINVAL
);
159 m
->hdr
->nlmsg_flags
= flags
;
164 int sd_netlink_message_is_broadcast(sd_netlink_message
*m
) {
165 assert_return(m
, -EINVAL
);
167 return m
->multicast_group
!= 0;
170 /* If successful the updated message will be correctly aligned, if unsuccessful the old message is untouched. */
171 static int add_rtattr(sd_netlink_message
*m
, uint16_t attr_type
, const void *data
, size_t data_length
) {
172 size_t message_length
;
173 struct nlmsghdr
*new_hdr
;
180 assert(NLMSG_ALIGN(m
->hdr
->nlmsg_len
) == m
->hdr
->nlmsg_len
);
181 assert(!data
|| data_length
> 0);
183 /* get the new message size (with padding at the end) */
184 message_length
= m
->hdr
->nlmsg_len
+ RTA_SPACE(data_length
);
186 /* buffer should be smaller than both one page or 8K to be accepted by the kernel */
187 if (message_length
> MIN(page_size(), 8192UL))
190 /* realloc to fit the new attribute */
191 new_hdr
= realloc(m
->hdr
, message_length
);
196 /* get pointer to the attribute we are about to add */
197 rta
= (struct rtattr
*) ((uint8_t *) m
->hdr
+ m
->hdr
->nlmsg_len
);
199 rtattr_append_attribute_internal(rta
, attr_type
, data
, data_length
);
201 /* if we are inside containers, extend them */
202 for (unsigned i
= 0; i
< m
->n_containers
; i
++)
203 GET_CONTAINER(m
, i
)->rta_len
+= RTA_SPACE(data_length
);
205 /* update message size */
206 offset
= m
->hdr
->nlmsg_len
;
207 m
->hdr
->nlmsg_len
= message_length
;
209 /* return old message size */
213 static int message_attribute_has_type(sd_netlink_message
*m
, size_t *ret_size
, uint16_t attr_type
, NLAType type
) {
214 const NLAPolicy
*policy
;
218 policy
= policy_set_get_policy(m
->containers
[m
->n_containers
].policy_set
, attr_type
);
222 if (policy_get_type(policy
) != type
)
226 *ret_size
= policy_get_size(policy
);
230 int sd_netlink_message_append_string(sd_netlink_message
*m
, uint16_t attr_type
, const char *data
) {
234 assert_return(m
, -EINVAL
);
235 assert_return(!m
->sealed
, -EPERM
);
236 assert_return(data
, -EINVAL
);
238 r
= message_attribute_has_type(m
, &size
, attr_type
, NETLINK_TYPE_STRING
);
243 length
= strnlen(data
, size
+1);
247 length
= strlen(data
);
249 r
= add_rtattr(m
, attr_type
, data
, length
+ 1);
256 int sd_netlink_message_append_strv(sd_netlink_message
*m
, uint16_t attr_type
, const char* const *data
) {
260 assert_return(m
, -EINVAL
);
261 assert_return(!m
->sealed
, -EPERM
);
262 assert_return(data
, -EINVAL
);
264 r
= message_attribute_has_type(m
, &size
, attr_type
, NETLINK_TYPE_STRING
);
268 STRV_FOREACH(p
, data
) {
270 length
= strnlen(*p
, size
+1);
276 r
= add_rtattr(m
, attr_type
, *p
, length
+ 1);
284 int sd_netlink_message_append_flag(sd_netlink_message
*m
, uint16_t attr_type
) {
288 assert_return(m
, -EINVAL
);
289 assert_return(!m
->sealed
, -EPERM
);
291 r
= message_attribute_has_type(m
, &size
, attr_type
, NETLINK_TYPE_FLAG
);
295 r
= add_rtattr(m
, attr_type
, NULL
, 0);
302 int sd_netlink_message_append_u8(sd_netlink_message
*m
, uint16_t attr_type
, uint8_t data
) {
305 assert_return(m
, -EINVAL
);
306 assert_return(!m
->sealed
, -EPERM
);
308 r
= message_attribute_has_type(m
, NULL
, attr_type
, NETLINK_TYPE_U8
);
312 r
= add_rtattr(m
, attr_type
, &data
, sizeof(uint8_t));
319 int sd_netlink_message_append_u16(sd_netlink_message
*m
, uint16_t attr_type
, uint16_t data
) {
322 assert_return(m
, -EINVAL
);
323 assert_return(!m
->sealed
, -EPERM
);
325 r
= message_attribute_has_type(m
, NULL
, attr_type
, NETLINK_TYPE_U16
);
329 r
= add_rtattr(m
, attr_type
, &data
, sizeof(uint16_t));
336 int sd_netlink_message_append_u32(sd_netlink_message
*m
, uint16_t attr_type
, uint32_t data
) {
339 assert_return(m
, -EINVAL
);
340 assert_return(!m
->sealed
, -EPERM
);
342 r
= message_attribute_has_type(m
, NULL
, attr_type
, NETLINK_TYPE_U32
);
346 r
= add_rtattr(m
, attr_type
, &data
, sizeof(uint32_t));
353 int sd_netlink_message_append_u64(sd_netlink_message
*m
, uint16_t attr_type
, uint64_t data
) {
356 assert_return(m
, -EINVAL
);
357 assert_return(!m
->sealed
, -EPERM
);
359 r
= message_attribute_has_type(m
, NULL
, attr_type
, NETLINK_TYPE_U64
);
363 r
= add_rtattr(m
, attr_type
, &data
, sizeof(uint64_t));
370 int sd_netlink_message_append_s8(sd_netlink_message
*m
, uint16_t attr_type
, int8_t data
) {
373 assert_return(m
, -EINVAL
);
374 assert_return(!m
->sealed
, -EPERM
);
376 r
= message_attribute_has_type(m
, NULL
, attr_type
, NETLINK_TYPE_S8
);
380 r
= add_rtattr(m
, attr_type
, &data
, sizeof(int8_t));
387 int sd_netlink_message_append_s16(sd_netlink_message
*m
, uint16_t attr_type
, int16_t data
) {
390 assert_return(m
, -EINVAL
);
391 assert_return(!m
->sealed
, -EPERM
);
393 r
= message_attribute_has_type(m
, NULL
, attr_type
, NETLINK_TYPE_S16
);
397 r
= add_rtattr(m
, attr_type
, &data
, sizeof(int16_t));
404 int sd_netlink_message_append_s32(sd_netlink_message
*m
, uint16_t attr_type
, int32_t data
) {
407 assert_return(m
, -EINVAL
);
408 assert_return(!m
->sealed
, -EPERM
);
410 r
= message_attribute_has_type(m
, NULL
, attr_type
, NETLINK_TYPE_S32
);
414 r
= add_rtattr(m
, attr_type
, &data
, sizeof(int32_t));
421 int sd_netlink_message_append_s64(sd_netlink_message
*m
, uint16_t attr_type
, int64_t data
) {
424 assert_return(m
, -EINVAL
);
425 assert_return(!m
->sealed
, -EPERM
);
427 r
= message_attribute_has_type(m
, NULL
, attr_type
, NETLINK_TYPE_S64
);
431 r
= add_rtattr(m
, attr_type
, &data
, sizeof(int64_t));
438 int sd_netlink_message_append_data(sd_netlink_message
*m
, uint16_t attr_type
, const void *data
, size_t len
) {
441 assert_return(m
, -EINVAL
);
442 assert_return(!m
->sealed
, -EPERM
);
444 r
= add_rtattr(m
, attr_type
, data
, len
);
451 int sd_netlink_message_append_container_data(
452 sd_netlink_message
*m
,
453 uint16_t container_type
,
460 assert_return(m
, -EINVAL
);
461 assert_return(!m
->sealed
, -EPERM
);
463 r
= sd_netlink_message_open_container(m
, container_type
);
467 r
= sd_netlink_message_append_data(m
, attr_type
, data
, len
);
471 return sd_netlink_message_close_container(m
);
474 int netlink_message_append_in_addr_union(sd_netlink_message
*m
, uint16_t attr_type
, int family
, const union in_addr_union
*data
) {
477 assert_return(m
, -EINVAL
);
478 assert_return(!m
->sealed
, -EPERM
);
479 assert_return(data
, -EINVAL
);
480 assert_return(IN_SET(family
, AF_INET
, AF_INET6
), -EINVAL
);
482 r
= message_attribute_has_type(m
, NULL
, attr_type
, NETLINK_TYPE_IN_ADDR
);
486 r
= add_rtattr(m
, attr_type
, data
, FAMILY_ADDRESS_SIZE(family
));
493 int sd_netlink_message_append_in_addr(sd_netlink_message
*m
, uint16_t attr_type
, const struct in_addr
*data
) {
494 return netlink_message_append_in_addr_union(m
, attr_type
, AF_INET
, (const union in_addr_union
*) data
);
497 int sd_netlink_message_append_in6_addr(sd_netlink_message
*m
, uint16_t attr_type
, const struct in6_addr
*data
) {
498 return netlink_message_append_in_addr_union(m
, attr_type
, AF_INET6
, (const union in_addr_union
*) data
);
501 int netlink_message_append_sockaddr_union(sd_netlink_message
*m
, uint16_t attr_type
, const union sockaddr_union
*data
) {
504 assert_return(m
, -EINVAL
);
505 assert_return(!m
->sealed
, -EPERM
);
506 assert_return(data
, -EINVAL
);
507 assert_return(IN_SET(data
->sa
.sa_family
, AF_INET
, AF_INET6
), -EINVAL
);
509 r
= message_attribute_has_type(m
, NULL
, attr_type
, NETLINK_TYPE_SOCKADDR
);
513 r
= add_rtattr(m
, attr_type
, data
, data
->sa
.sa_family
== AF_INET
? sizeof(struct sockaddr_in
) : sizeof(struct sockaddr_in6
));
520 int sd_netlink_message_append_sockaddr_in(sd_netlink_message
*m
, uint16_t attr_type
, const struct sockaddr_in
*data
) {
521 return netlink_message_append_sockaddr_union(m
, attr_type
, (const union sockaddr_union
*) data
);
524 int sd_netlink_message_append_sockaddr_in6(sd_netlink_message
*m
, uint16_t attr_type
, const struct sockaddr_in6
*data
) {
525 return netlink_message_append_sockaddr_union(m
, attr_type
, (const union sockaddr_union
*) data
);
528 int sd_netlink_message_append_ether_addr(sd_netlink_message
*m
, uint16_t attr_type
, const struct ether_addr
*data
) {
531 assert_return(m
, -EINVAL
);
532 assert_return(!m
->sealed
, -EPERM
);
533 assert_return(data
, -EINVAL
);
535 r
= message_attribute_has_type(m
, NULL
, attr_type
, NETLINK_TYPE_ETHER_ADDR
);
539 r
= add_rtattr(m
, attr_type
, data
, ETH_ALEN
);
546 int netlink_message_append_hw_addr(sd_netlink_message
*m
, uint16_t attr_type
, const struct hw_addr_data
*data
) {
549 assert_return(m
, -EINVAL
);
550 assert_return(!m
->sealed
, -EPERM
);
551 assert_return(data
, -EINVAL
);
552 assert_return(data
->length
> 0, -EINVAL
);
554 r
= message_attribute_has_type(m
, NULL
, attr_type
, NETLINK_TYPE_ETHER_ADDR
);
558 r
= add_rtattr(m
, attr_type
, data
->bytes
, data
->length
);
565 int sd_netlink_message_append_cache_info(sd_netlink_message
*m
, uint16_t attr_type
, const struct ifa_cacheinfo
*info
) {
568 assert_return(m
, -EINVAL
);
569 assert_return(!m
->sealed
, -EPERM
);
570 assert_return(info
, -EINVAL
);
572 r
= message_attribute_has_type(m
, NULL
, attr_type
, NETLINK_TYPE_CACHE_INFO
);
576 r
= add_rtattr(m
, attr_type
, info
, sizeof(struct ifa_cacheinfo
));
583 int sd_netlink_message_open_container(sd_netlink_message
*m
, uint16_t attr_type
) {
587 assert_return(m
, -EINVAL
);
588 assert_return(!m
->sealed
, -EPERM
);
589 /* m->containers[m->n_containers + 1] is accessed both in read and write. Prevent access out of bound */
590 assert_return(m
->n_containers
< (NETLINK_CONTAINER_DEPTH
- 1), -ERANGE
);
592 r
= message_attribute_has_type(m
, &size
, attr_type
, NETLINK_TYPE_NESTED
);
594 const NLAPolicySetUnion
*policy_set_union
;
597 r
= message_attribute_has_type(m
, &size
, attr_type
, NETLINK_TYPE_NESTED_UNION_BY_FAMILY
);
601 r
= sd_rtnl_message_get_family(m
, &family
);
605 policy_set_union
= policy_set_get_policy_set_union(
606 m
->containers
[m
->n_containers
].policy_set
,
608 if (!policy_set_union
)
611 m
->containers
[m
->n_containers
+ 1].policy_set
=
612 policy_set_union_get_policy_set_by_family(
616 m
->containers
[m
->n_containers
+ 1].policy_set
=
617 policy_set_get_policy_set(
618 m
->containers
[m
->n_containers
].policy_set
,
620 if (!m
->containers
[m
->n_containers
+ 1].policy_set
)
623 r
= add_rtattr(m
, attr_type
| NLA_F_NESTED
, NULL
, size
);
627 m
->containers
[m
->n_containers
++].offset
= r
;
632 int sd_netlink_message_open_container_union(sd_netlink_message
*m
, uint16_t attr_type
, const char *key
) {
633 const NLAPolicySetUnion
*policy_set_union
;
636 assert_return(m
, -EINVAL
);
637 assert_return(!m
->sealed
, -EPERM
);
638 assert_return(m
->n_containers
< (NETLINK_CONTAINER_DEPTH
- 1), -ERANGE
);
640 r
= message_attribute_has_type(m
, NULL
, attr_type
, NETLINK_TYPE_NESTED_UNION_BY_STRING
);
644 policy_set_union
= policy_set_get_policy_set_union(
645 m
->containers
[m
->n_containers
].policy_set
,
647 if (!policy_set_union
)
650 m
->containers
[m
->n_containers
+ 1].policy_set
=
651 policy_set_union_get_policy_set_by_string(
654 if (!m
->containers
[m
->n_containers
+ 1].policy_set
)
657 r
= sd_netlink_message_append_string(m
, policy_set_union_get_match_attribute(policy_set_union
), key
);
661 /* do we ever need non-null size */
662 r
= add_rtattr(m
, attr_type
| NLA_F_NESTED
, NULL
, 0);
666 m
->containers
[m
->n_containers
++].offset
= r
;
671 int sd_netlink_message_close_container(sd_netlink_message
*m
) {
672 assert_return(m
, -EINVAL
);
673 assert_return(!m
->sealed
, -EPERM
);
674 assert_return(m
->n_containers
> 0, -EINVAL
);
676 m
->containers
[m
->n_containers
].policy_set
= NULL
;
677 m
->containers
[m
->n_containers
].offset
= 0;
683 int sd_netlink_message_open_array(sd_netlink_message
*m
, uint16_t attr_type
) {
686 assert_return(m
, -EINVAL
);
687 assert_return(!m
->sealed
, -EPERM
);
688 assert_return(m
->n_containers
< (NETLINK_CONTAINER_DEPTH
- 1), -ERANGE
);
690 r
= add_rtattr(m
, attr_type
| NLA_F_NESTED
, NULL
, 0);
694 m
->containers
[m
->n_containers
].offset
= r
;
696 m
->containers
[m
->n_containers
].policy_set
= m
->containers
[m
->n_containers
- 1].policy_set
;
701 int sd_netlink_message_cancel_array(sd_netlink_message
*m
) {
704 assert_return(m
, -EINVAL
);
705 assert_return(!m
->sealed
, -EPERM
);
706 assert_return(m
->n_containers
> 1, -EINVAL
);
708 rta_len
= GET_CONTAINER(m
, (m
->n_containers
- 1))->rta_len
;
710 for (unsigned i
= 0; i
< m
->n_containers
; i
++)
711 GET_CONTAINER(m
, i
)->rta_len
-= rta_len
;
713 m
->hdr
->nlmsg_len
-= rta_len
;
716 m
->containers
[m
->n_containers
].policy_set
= NULL
;
721 static int netlink_message_read_internal(
722 sd_netlink_message
*m
,
725 bool *ret_net_byteorder
) {
727 struct netlink_attribute
*attribute
;
730 assert_return(m
, -EINVAL
);
731 assert_return(m
->sealed
, -EPERM
);
733 assert(m
->n_containers
< NETLINK_CONTAINER_DEPTH
);
735 if (!m
->containers
[m
->n_containers
].attributes
)
738 if (attr_type
> m
->containers
[m
->n_containers
].max_attribute
)
741 attribute
= &m
->containers
[m
->n_containers
].attributes
[attr_type
];
743 if (attribute
->offset
== 0)
746 rta
= (struct rtattr
*)((uint8_t *) m
->hdr
+ attribute
->offset
);
749 *ret_data
= RTA_DATA(rta
);
751 if (ret_net_byteorder
)
752 *ret_net_byteorder
= attribute
->net_byteorder
;
754 return RTA_PAYLOAD(rta
);
757 int sd_netlink_message_read(sd_netlink_message
*m
, uint16_t attr_type
, size_t size
, void *data
) {
761 assert_return(m
, -EINVAL
);
763 r
= netlink_message_read_internal(m
, attr_type
, &attr_data
, NULL
);
767 if ((size_t) r
> size
)
771 memcpy(data
, attr_data
, r
);
776 int sd_netlink_message_read_data(sd_netlink_message
*m
, uint16_t attr_type
, size_t *ret_size
, void **ret_data
) {
780 assert_return(m
, -EINVAL
);
782 r
= netlink_message_read_internal(m
, attr_type
, &attr_data
, NULL
);
789 data
= memdup(attr_data
, r
);
802 int sd_netlink_message_read_data_suffix0(sd_netlink_message
*m
, uint16_t attr_type
, size_t *ret_size
, void **ret_data
) {
806 assert_return(m
, -EINVAL
);
808 r
= netlink_message_read_internal(m
, attr_type
, &attr_data
, NULL
);
815 data
= memdup_suffix0(attr_data
, r
);
828 int sd_netlink_message_read_string_strdup(sd_netlink_message
*m
, uint16_t attr_type
, char **data
) {
832 assert_return(m
, -EINVAL
);
834 r
= message_attribute_has_type(m
, NULL
, attr_type
, NETLINK_TYPE_STRING
);
838 r
= netlink_message_read_internal(m
, attr_type
, &attr_data
, NULL
);
845 str
= strndup(attr_data
, r
);
855 int sd_netlink_message_read_string(sd_netlink_message
*m
, uint16_t attr_type
, const char **data
) {
859 assert_return(m
, -EINVAL
);
861 r
= message_attribute_has_type(m
, NULL
, attr_type
, NETLINK_TYPE_STRING
);
865 r
= netlink_message_read_internal(m
, attr_type
, &attr_data
, NULL
);
869 if (strnlen(attr_data
, r
) >= (size_t) r
)
873 *data
= (const char *) attr_data
;
878 int sd_netlink_message_read_u8(sd_netlink_message
*m
, uint16_t attr_type
, uint8_t *data
) {
882 assert_return(m
, -EINVAL
);
884 r
= message_attribute_has_type(m
, NULL
, attr_type
, NETLINK_TYPE_U8
);
888 r
= netlink_message_read_internal(m
, attr_type
, &attr_data
, NULL
);
892 if ((size_t) r
< sizeof(uint8_t))
896 *data
= *(uint8_t *) attr_data
;
901 int sd_netlink_message_read_u16(sd_netlink_message
*m
, uint16_t attr_type
, uint16_t *data
) {
906 assert_return(m
, -EINVAL
);
908 r
= message_attribute_has_type(m
, NULL
, attr_type
, NETLINK_TYPE_U16
);
912 r
= netlink_message_read_internal(m
, attr_type
, &attr_data
, &net_byteorder
);
916 if ((size_t) r
< sizeof(uint16_t))
921 *data
= be16toh(*(uint16_t *) attr_data
);
923 *data
= *(uint16_t *) attr_data
;
929 int sd_netlink_message_read_u32(sd_netlink_message
*m
, uint16_t attr_type
, uint32_t *data
) {
934 assert_return(m
, -EINVAL
);
936 r
= message_attribute_has_type(m
, NULL
, attr_type
, NETLINK_TYPE_U32
);
940 r
= netlink_message_read_internal(m
, attr_type
, &attr_data
, &net_byteorder
);
944 if ((size_t) r
< sizeof(uint32_t))
949 *data
= be32toh(*(uint32_t *) attr_data
);
951 *data
= *(uint32_t *) attr_data
;
957 int sd_netlink_message_read_ether_addr(sd_netlink_message
*m
, uint16_t attr_type
, struct ether_addr
*data
) {
961 assert_return(m
, -EINVAL
);
963 r
= message_attribute_has_type(m
, NULL
, attr_type
, NETLINK_TYPE_ETHER_ADDR
);
967 r
= netlink_message_read_internal(m
, attr_type
, &attr_data
, NULL
);
971 if ((size_t) r
< sizeof(struct ether_addr
))
975 memcpy(data
, attr_data
, sizeof(struct ether_addr
));
980 int netlink_message_read_hw_addr(sd_netlink_message
*m
, uint16_t attr_type
, struct hw_addr_data
*data
) {
984 assert_return(m
, -EINVAL
);
986 r
= message_attribute_has_type(m
, NULL
, attr_type
, NETLINK_TYPE_ETHER_ADDR
);
990 r
= netlink_message_read_internal(m
, attr_type
, &attr_data
, NULL
);
994 if (r
> HW_ADDR_MAX_SIZE
)
998 memcpy(data
->bytes
, attr_data
, r
);
1005 int sd_netlink_message_read_cache_info(sd_netlink_message
*m
, uint16_t attr_type
, struct ifa_cacheinfo
*info
) {
1009 assert_return(m
, -EINVAL
);
1011 r
= message_attribute_has_type(m
, NULL
, attr_type
, NETLINK_TYPE_CACHE_INFO
);
1015 r
= netlink_message_read_internal(m
, attr_type
, &attr_data
, NULL
);
1019 if ((size_t) r
< sizeof(struct ifa_cacheinfo
))
1023 memcpy(info
, attr_data
, sizeof(struct ifa_cacheinfo
));
1028 int netlink_message_read_in_addr_union(sd_netlink_message
*m
, uint16_t attr_type
, int family
, union in_addr_union
*data
) {
1032 assert_return(m
, -EINVAL
);
1033 assert_return(IN_SET(family
, AF_INET
, AF_INET6
), -EINVAL
);
1035 r
= message_attribute_has_type(m
, NULL
, attr_type
, NETLINK_TYPE_IN_ADDR
);
1039 r
= netlink_message_read_internal(m
, attr_type
, &attr_data
, NULL
);
1043 if ((size_t) r
< FAMILY_ADDRESS_SIZE(family
))
1047 memcpy(data
, attr_data
, FAMILY_ADDRESS_SIZE(family
));
1052 int sd_netlink_message_read_in_addr(sd_netlink_message
*m
, uint16_t attr_type
, struct in_addr
*data
) {
1053 union in_addr_union u
;
1056 r
= netlink_message_read_in_addr_union(m
, attr_type
, AF_INET
, &u
);
1063 int sd_netlink_message_read_in6_addr(sd_netlink_message
*m
, uint16_t attr_type
, struct in6_addr
*data
) {
1064 union in_addr_union u
;
1067 r
= netlink_message_read_in_addr_union(m
, attr_type
, AF_INET6
, &u
);
1074 int sd_netlink_message_has_flag(sd_netlink_message
*m
, uint16_t attr_type
) {
1078 assert_return(m
, -EINVAL
);
1080 /* This returns 1 when the flag is set, 0 when not set, negative errno on error. */
1082 r
= message_attribute_has_type(m
, NULL
, attr_type
, NETLINK_TYPE_FLAG
);
1086 r
= netlink_message_read_internal(m
, attr_type
, &attr_data
, NULL
);
1095 int sd_netlink_message_read_strv(sd_netlink_message
*m
, uint16_t container_type
, uint16_t attr_type
, char ***ret
) {
1096 _cleanup_strv_free_
char **s
= NULL
;
1097 const NLAPolicySet
*policy_set
;
1098 const NLAPolicy
*policy
;
1104 assert_return(m
, -EINVAL
);
1105 assert_return(m
->n_containers
< NETLINK_CONTAINER_DEPTH
, -EINVAL
);
1107 policy
= policy_set_get_policy(
1108 m
->containers
[m
->n_containers
].policy_set
,
1113 if (policy_get_type(policy
) != NETLINK_TYPE_NESTED
)
1116 policy_set
= policy_set_get_policy_set(
1117 m
->containers
[m
->n_containers
].policy_set
,
1122 policy
= policy_set_get_policy(policy_set
, attr_type
);
1126 if (policy_get_type(policy
) != NETLINK_TYPE_STRING
)
1129 r
= netlink_message_read_internal(m
, container_type
, &container
, NULL
);
1133 rt_len
= (size_t) r
;
1136 /* RTA_OK() macro compares with rta->rt_len, which is unsigned short, and
1137 * LGTM.com analysis does not like the type difference. Hence, here we
1138 * introduce an unsigned short variable as a workaround. */
1139 unsigned short len
= rt_len
;
1140 for (; RTA_OK(rta
, len
); rta
= RTA_NEXT(rta
, len
)) {
1143 type
= RTA_TYPE(rta
);
1144 if (type
!= attr_type
)
1147 r
= strv_extend(&s
, RTA_DATA(rta
));
1156 static int netlink_container_parse(
1157 sd_netlink_message
*m
,
1158 struct netlink_container
*container
,
1162 _cleanup_free_
struct netlink_attribute
*attributes
= NULL
;
1163 uint16_t max_attr
= 0;
1165 /* RTA_OK() macro compares with rta->rt_len, which is unsigned short, and
1166 * LGTM.com analysis does not like the type difference. Hence, here we
1167 * introduce an unsigned short variable as a workaround. */
1168 unsigned short len
= rt_len
;
1169 for (; RTA_OK(rta
, len
); rta
= RTA_NEXT(rta
, len
)) {
1172 attr
= RTA_TYPE(rta
);
1173 max_attr
= MAX(max_attr
, attr
);
1175 if (!GREEDY_REALLOC0(attributes
, (size_t) max_attr
+ 1))
1178 if (attributes
[attr
].offset
!= 0)
1179 log_debug("sd-netlink: message parse - overwriting repeated attribute");
1181 attributes
[attr
].offset
= (uint8_t *) rta
- (uint8_t *) m
->hdr
;
1182 attributes
[attr
].nested
= RTA_FLAGS(rta
) & NLA_F_NESTED
;
1183 attributes
[attr
].net_byteorder
= RTA_FLAGS(rta
) & NLA_F_NET_BYTEORDER
;
1186 container
->attributes
= TAKE_PTR(attributes
);
1187 container
->max_attribute
= max_attr
;
1192 int sd_netlink_message_enter_container(sd_netlink_message
*m
, uint16_t attr_type
) {
1193 const NLAPolicy
*policy
;
1194 const NLAPolicySet
*policy_set
;
1199 assert_return(m
, -EINVAL
);
1200 assert_return(m
->n_containers
< (NETLINK_CONTAINER_DEPTH
- 1), -EINVAL
);
1202 policy
= policy_set_get_policy(
1203 m
->containers
[m
->n_containers
].policy_set
,
1208 switch (policy_get_type(policy
)) {
1209 case NETLINK_TYPE_NESTED
:
1210 policy_set
= policy_set_get_policy_set(
1211 m
->containers
[m
->n_containers
].policy_set
,
1215 case NETLINK_TYPE_NESTED_UNION_BY_STRING
: {
1216 const NLAPolicySetUnion
*policy_set_union
;
1219 policy_set_union
= policy_get_policy_set_union(policy
);
1220 if (!policy_set_union
)
1223 r
= sd_netlink_message_read_string(
1225 policy_set_union_get_match_attribute(policy_set_union
),
1230 policy_set
= policy_set_union_get_policy_set_by_string(
1235 case NETLINK_TYPE_NESTED_UNION_BY_FAMILY
: {
1236 const NLAPolicySetUnion
*policy_set_union
;
1239 policy_set_union
= policy_get_policy_set_union(policy
);
1240 if (!policy_set_union
)
1243 r
= sd_rtnl_message_get_family(m
, &family
);
1247 policy_set
= policy_set_union_get_policy_set_by_family(
1253 assert_not_reached();
1258 r
= netlink_message_read_internal(m
, attr_type
, &container
, NULL
);
1265 r
= netlink_container_parse(m
,
1266 &m
->containers
[m
->n_containers
],
1274 m
->containers
[m
->n_containers
].policy_set
= policy_set
;
1279 int sd_netlink_message_enter_array(sd_netlink_message
*m
, uint16_t attr_type
) {
1284 assert_return(m
, -EINVAL
);
1285 assert_return(m
->n_containers
< (NETLINK_CONTAINER_DEPTH
- 1), -EINVAL
);
1287 r
= netlink_message_read_internal(m
, attr_type
, &container
, NULL
);
1294 r
= netlink_container_parse(m
,
1295 &m
->containers
[m
->n_containers
],
1303 m
->containers
[m
->n_containers
].policy_set
= m
->containers
[m
->n_containers
- 1].policy_set
;
1308 int sd_netlink_message_exit_container(sd_netlink_message
*m
) {
1309 assert_return(m
, -EINVAL
);
1310 assert_return(m
->sealed
, -EINVAL
);
1311 assert_return(m
->n_containers
> 0, -EINVAL
);
1313 m
->containers
[m
->n_containers
].attributes
= mfree(m
->containers
[m
->n_containers
].attributes
);
1314 m
->containers
[m
->n_containers
].max_attribute
= 0;
1315 m
->containers
[m
->n_containers
].policy_set
= NULL
;
1322 int sd_netlink_message_get_max_attribute(sd_netlink_message
*m
, uint16_t *ret
) {
1323 assert_return(m
, -EINVAL
);
1324 assert_return(m
->sealed
, -EINVAL
);
1325 assert_return(ret
, -EINVAL
);
1327 *ret
= m
->containers
[m
->n_containers
].max_attribute
;
1331 int sd_netlink_message_is_error(sd_netlink_message
*m
) {
1332 assert_return(m
, 0);
1333 assert_return(m
->hdr
, 0);
1335 return m
->hdr
->nlmsg_type
== NLMSG_ERROR
;
1338 int sd_netlink_message_get_errno(sd_netlink_message
*m
) {
1339 struct nlmsgerr
*err
;
1341 assert_return(m
, -EINVAL
);
1342 assert_return(m
->hdr
, -EINVAL
);
1344 if (!sd_netlink_message_is_error(m
))
1347 err
= NLMSG_DATA(m
->hdr
);
1352 static int netlink_message_parse_error(sd_netlink_message
*m
) {
1353 struct nlmsgerr
*err
= NLMSG_DATA(m
->hdr
);
1354 size_t hlen
= sizeof(struct nlmsgerr
);
1356 /* no TLVs, nothing to do here */
1357 if (!(m
->hdr
->nlmsg_flags
& NLM_F_ACK_TLVS
))
1360 /* if NLM_F_CAPPED is set then the inner err msg was capped */
1361 if (!(m
->hdr
->nlmsg_flags
& NLM_F_CAPPED
))
1362 hlen
+= err
->msg
.nlmsg_len
- sizeof(struct nlmsghdr
);
1364 if (m
->hdr
->nlmsg_len
<= NLMSG_SPACE(hlen
))
1367 return netlink_container_parse(m
,
1368 &m
->containers
[m
->n_containers
],
1369 (struct rtattr
*)((uint8_t*) NLMSG_DATA(m
->hdr
) + hlen
),
1370 NLMSG_PAYLOAD(m
->hdr
, hlen
));
1373 int sd_netlink_message_rewind(sd_netlink_message
*m
, sd_netlink
*nl
) {
1377 assert_return(m
, -EINVAL
);
1378 assert_return(nl
, -EINVAL
);
1380 /* don't allow appending to message once parsed */
1383 for (unsigned i
= 1; i
<= m
->n_containers
; i
++)
1384 m
->containers
[i
].attributes
= mfree(m
->containers
[i
].attributes
);
1386 m
->n_containers
= 0;
1388 if (m
->containers
[0].attributes
)
1389 /* top-level attributes have already been parsed */
1394 r
= netlink_get_policy_set_and_header_size(nl
, m
->hdr
->nlmsg_type
,
1395 &m
->containers
[0].policy_set
, &size
);
1399 if (sd_netlink_message_is_error(m
))
1400 return netlink_message_parse_error(m
);
1402 return netlink_container_parse(m
,
1404 (struct rtattr
*)((uint8_t*) NLMSG_DATA(m
->hdr
) + NLMSG_ALIGN(size
)),
1405 NLMSG_PAYLOAD(m
->hdr
, size
));
1408 void message_seal(sd_netlink_message
*m
) {
1414 sd_netlink_message
*sd_netlink_message_next(sd_netlink_message
*m
) {
1415 assert_return(m
, NULL
);