1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 Tom Gundersen <teg@jklm.no>
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
22 #include <netinet/in.h>
26 #include "sd-netlink.h"
28 #include "formats-util.h"
30 #include "netlink-internal.h"
31 #include "netlink-types.h"
32 #include "netlink-util.h"
34 #include "socket-util.h"
37 #define GET_CONTAINER(m, i) ((i) < (m)->n_containers ? (struct rtattr*)((uint8_t*)(m)->hdr + (m)->containers[i].offset) : NULL)
38 #define PUSH_CONTAINER(m, new) (m)->container_offsets[(m)->n_containers ++] = (uint8_t*)(new) - (uint8_t*)(m)->hdr;
40 #define RTA_TYPE(rta) ((rta)->rta_type & NLA_TYPE_MASK)
41 #define RTA_FLAGS(rta) ((rta)->rta_type & ~NLA_TYPE_MASK)
43 int message_new_empty(sd_netlink
*rtnl
, sd_netlink_message
**ret
) {
44 sd_netlink_message
*m
;
46 assert_return(ret
, -EINVAL
);
48 /* Note that 'rtnl' is currently unused, if we start using it internally
49 we must take care to avoid problems due to mutual references between
50 buses and their queued messages. See sd-bus.
53 m
= new0(sd_netlink_message
, 1);
57 m
->n_ref
= REFCNT_INIT
;
66 int message_new(sd_netlink
*rtnl
, sd_netlink_message
**ret
, uint16_t type
) {
67 _cleanup_netlink_message_unref_ sd_netlink_message
*m
= NULL
;
68 const NLType
*nl_type
;
72 r
= type_system_get_type(&type_system_root
, &nl_type
, type
);
76 if (type_get_type(nl_type
) != NETLINK_TYPE_NESTED
)
79 r
= message_new_empty(rtnl
, &m
);
83 size
= NLMSG_SPACE(type_get_size(nl_type
));
85 assert(size
>= sizeof(struct nlmsghdr
));
86 m
->hdr
= malloc0(size
);
90 m
->hdr
->nlmsg_flags
= NLM_F_REQUEST
| NLM_F_ACK
;
92 type_get_type_system(nl_type
, &m
->containers
[0].type_system
);
93 m
->hdr
->nlmsg_len
= size
;
94 m
->hdr
->nlmsg_type
= type
;
102 int sd_netlink_message_request_dump(sd_netlink_message
*m
, int dump
) {
103 assert_return(m
, -EINVAL
);
104 assert_return(m
->hdr
, -EINVAL
);
105 assert_return(m
->hdr
->nlmsg_type
== RTM_GETLINK
||
106 m
->hdr
->nlmsg_type
== RTM_GETADDR
||
107 m
->hdr
->nlmsg_type
== RTM_GETROUTE
||
108 m
->hdr
->nlmsg_type
== RTM_GETNEIGH
,
112 m
->hdr
->nlmsg_flags
|= NLM_F_DUMP
;
114 m
->hdr
->nlmsg_flags
&= ~NLM_F_DUMP
;
119 sd_netlink_message
*sd_netlink_message_ref(sd_netlink_message
*m
) {
121 assert_se(REFCNT_INC(m
->n_ref
) >= 2);
126 sd_netlink_message
*sd_netlink_message_unref(sd_netlink_message
*m
) {
127 if (m
&& REFCNT_DEC(m
->n_ref
) == 0) {
132 for (i
= 0; i
<= m
->n_containers
; i
++)
133 free(m
->containers
[i
].attributes
);
135 sd_netlink_message_unref(m
->next
);
143 int sd_netlink_message_get_type(sd_netlink_message
*m
, uint16_t *type
) {
144 assert_return(m
, -EINVAL
);
145 assert_return(type
, -EINVAL
);
147 *type
= m
->hdr
->nlmsg_type
;
152 int sd_netlink_message_set_flags(sd_netlink_message
*m
, uint16_t flags
) {
153 assert_return(m
, -EINVAL
);
154 assert_return(flags
, -EINVAL
);
156 m
->hdr
->nlmsg_flags
= flags
;
161 int sd_netlink_message_is_broadcast(sd_netlink_message
*m
) {
162 assert_return(m
, -EINVAL
);
167 /* If successful the updated message will be correctly aligned, if
168 unsuccessful the old message is untouched. */
169 static int add_rtattr(sd_netlink_message
*m
, unsigned short type
, const void *data
, size_t data_length
) {
171 size_t message_length
, padding_length
;
172 struct nlmsghdr
*new_hdr
;
181 assert(NLMSG_ALIGN(m
->hdr
->nlmsg_len
) == m
->hdr
->nlmsg_len
);
182 assert(!data
|| data_length
);
184 /* get offset of the new attribute */
185 offset
= m
->hdr
->nlmsg_len
;
187 /* get the size of the new rta attribute (with padding at the end) */
188 rta_length
= RTA_LENGTH(data_length
);
190 /* get the new message size (with padding at the end) */
191 message_length
= offset
+ RTA_ALIGN(rta_length
);
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
+ offset
);
202 /* if we are inside containers, extend them */
203 for (i
= 0; i
< m
->n_containers
; i
++)
204 GET_CONTAINER(m
, i
)->rta_len
+= message_length
- offset
;
206 /* fill in the attribute */
207 rta
->rta_type
= type
;
208 rta
->rta_len
= rta_length
;
210 /* we don't deal with the case where the user lies about the type
211 * and gives us too little data (so don't do that)
213 padding
= mempcpy(RTA_DATA(rta
), data
, data_length
);
215 /* if no data was passed, make sure we still initialize the padding
216 note that we can have data_length > 0 (used by some containers) */
217 padding
= RTA_DATA(rta
);
220 /* make sure also the padding at the end of the message is initialized */
221 padding_length
= (uint8_t*)m
->hdr
+ message_length
- (uint8_t*)padding
;
222 memzero(padding
, padding_length
);
224 /* update message size */
225 m
->hdr
->nlmsg_len
= message_length
;
230 static int message_attribute_has_type(sd_netlink_message
*m
, size_t *out_size
, uint16_t attribute_type
, uint16_t data_type
) {
236 r
= type_system_get_type(m
->containers
[m
->n_containers
].type_system
, &type
, attribute_type
);
240 if (type_get_type(type
) != data_type
)
244 *out_size
= type_get_size(type
);
248 int sd_netlink_message_append_string(sd_netlink_message
*m
, unsigned short type
, const char *data
) {
252 assert_return(m
, -EINVAL
);
253 assert_return(!m
->sealed
, -EPERM
);
254 assert_return(data
, -EINVAL
);
256 r
= message_attribute_has_type(m
, &size
, type
, NETLINK_TYPE_STRING
);
261 length
= strnlen(data
, size
+1);
265 length
= strlen(data
);
267 r
= add_rtattr(m
, type
, data
, length
+ 1);
274 int sd_netlink_message_append_flag(sd_netlink_message
*m
, unsigned short type
) {
278 assert_return(m
, -EINVAL
);
279 assert_return(!m
->sealed
, -EPERM
);
281 r
= message_attribute_has_type(m
, &size
, type
, NETLINK_TYPE_FLAG
);
285 r
= add_rtattr(m
, type
, NULL
, 0);
292 int sd_netlink_message_append_u8(sd_netlink_message
*m
, unsigned short type
, uint8_t data
) {
295 assert_return(m
, -EINVAL
);
296 assert_return(!m
->sealed
, -EPERM
);
298 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_U8
);
302 r
= add_rtattr(m
, type
, &data
, sizeof(uint8_t));
310 int sd_netlink_message_append_u16(sd_netlink_message
*m
, unsigned short type
, uint16_t data
) {
313 assert_return(m
, -EINVAL
);
314 assert_return(!m
->sealed
, -EPERM
);
316 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_U16
);
320 r
= add_rtattr(m
, type
, &data
, sizeof(uint16_t));
327 int sd_netlink_message_append_u32(sd_netlink_message
*m
, unsigned short type
, uint32_t data
) {
330 assert_return(m
, -EINVAL
);
331 assert_return(!m
->sealed
, -EPERM
);
333 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_U32
);
337 r
= add_rtattr(m
, type
, &data
, sizeof(uint32_t));
344 int sd_netlink_message_append_in_addr(sd_netlink_message
*m
, unsigned short type
, const struct in_addr
*data
) {
347 assert_return(m
, -EINVAL
);
348 assert_return(!m
->sealed
, -EPERM
);
349 assert_return(data
, -EINVAL
);
351 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_IN_ADDR
);
355 r
= add_rtattr(m
, type
, data
, sizeof(struct in_addr
));
362 int sd_netlink_message_append_in6_addr(sd_netlink_message
*m
, unsigned short type
, const struct in6_addr
*data
) {
365 assert_return(m
, -EINVAL
);
366 assert_return(!m
->sealed
, -EPERM
);
367 assert_return(data
, -EINVAL
);
369 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_IN_ADDR
);
373 r
= add_rtattr(m
, type
, data
, sizeof(struct in6_addr
));
380 int sd_netlink_message_append_ether_addr(sd_netlink_message
*m
, unsigned short type
, const struct ether_addr
*data
) {
383 assert_return(m
, -EINVAL
);
384 assert_return(!m
->sealed
, -EPERM
);
385 assert_return(data
, -EINVAL
);
387 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_ETHER_ADDR
);
391 r
= add_rtattr(m
, type
, data
, ETH_ALEN
);
398 int sd_netlink_message_append_cache_info(sd_netlink_message
*m
, unsigned short type
, const struct ifa_cacheinfo
*info
) {
401 assert_return(m
, -EINVAL
);
402 assert_return(!m
->sealed
, -EPERM
);
403 assert_return(info
, -EINVAL
);
405 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_CACHE_INFO
);
409 r
= add_rtattr(m
, type
, info
, sizeof(struct ifa_cacheinfo
));
416 int sd_netlink_message_open_container(sd_netlink_message
*m
, unsigned short type
) {
420 assert_return(m
, -EINVAL
);
421 assert_return(!m
->sealed
, -EPERM
);
422 assert_return(m
->n_containers
< RTNL_CONTAINER_DEPTH
, -ERANGE
);
424 r
= message_attribute_has_type(m
, &size
, type
, NETLINK_TYPE_NESTED
);
426 const NLTypeSystemUnion
*type_system_union
;
429 r
= message_attribute_has_type(m
, &size
, type
, NETLINK_TYPE_UNION
);
433 r
= sd_rtnl_message_get_family(m
, &family
);
437 r
= type_system_get_type_system_union(m
->containers
[m
->n_containers
].type_system
, &type_system_union
, type
);
441 r
= type_system_union_protocol_get_type_system(type_system_union
,
442 &m
->containers
[m
->n_containers
+ 1].type_system
,
447 r
= type_system_get_type_system(m
->containers
[m
->n_containers
].type_system
,
448 &m
->containers
[m
->n_containers
+ 1].type_system
,
454 r
= add_rtattr(m
, type
| NLA_F_NESTED
, NULL
, size
);
458 m
->containers
[m
->n_containers
++].offset
= r
;
463 int sd_netlink_message_open_container_union(sd_netlink_message
*m
, unsigned short type
, const char *key
) {
464 const NLTypeSystemUnion
*type_system_union
;
467 assert_return(m
, -EINVAL
);
468 assert_return(!m
->sealed
, -EPERM
);
470 r
= type_system_get_type_system_union(m
->containers
[m
->n_containers
].type_system
, &type_system_union
, type
);
474 r
= type_system_union_get_type_system(type_system_union
,
475 &m
->containers
[m
->n_containers
+ 1].type_system
,
480 r
= sd_netlink_message_append_string(m
, type_system_union
->match
, key
);
484 /* do we evere need non-null size */
485 r
= add_rtattr(m
, type
| NLA_F_NESTED
, NULL
, 0);
489 m
->containers
[m
->n_containers
++].offset
= r
;
495 int sd_netlink_message_close_container(sd_netlink_message
*m
) {
496 assert_return(m
, -EINVAL
);
497 assert_return(!m
->sealed
, -EPERM
);
498 assert_return(m
->n_containers
> 0, -EINVAL
);
500 m
->containers
[m
->n_containers
].type_system
= NULL
;
506 static int netlink_message_read_internal(sd_netlink_message
*m
, unsigned short type
, void **data
, bool *net_byteorder
) {
507 struct netlink_attribute
*attribute
;
510 assert_return(m
, -EINVAL
);
511 assert_return(m
->sealed
, -EPERM
);
512 assert_return(data
, -EINVAL
);
513 assert(m
->n_containers
< RTNL_CONTAINER_DEPTH
);
514 assert(m
->containers
[m
->n_containers
].attributes
);
515 assert(type
< m
->containers
[m
->n_containers
].n_attributes
);
517 attribute
= &m
->containers
[m
->n_containers
].attributes
[type
];
519 if(!attribute
->offset
)
522 rta
= (struct rtattr
*)((uint8_t *) m
->hdr
+ attribute
->offset
);
524 *data
= RTA_DATA(rta
);
527 *net_byteorder
= attribute
->net_byteorder
;
529 return RTA_PAYLOAD(rta
);
532 int sd_netlink_message_read_string(sd_netlink_message
*m
, unsigned short type
, const char **data
) {
536 assert_return(m
, -EINVAL
);
538 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_STRING
);
542 r
= netlink_message_read_internal(m
, type
, &attr_data
, NULL
);
545 else if (strnlen(attr_data
, r
) >= (size_t) r
)
549 *data
= (const char *) attr_data
;
554 int sd_netlink_message_read_u8(sd_netlink_message
*m
, unsigned short type
, uint8_t *data
) {
558 assert_return(m
, -EINVAL
);
560 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_U8
);
564 r
= netlink_message_read_internal(m
, type
, &attr_data
, NULL
);
567 else if ((size_t) r
< sizeof(uint8_t))
571 *data
= *(uint8_t *) attr_data
;
576 int sd_netlink_message_read_u16(sd_netlink_message
*m
, unsigned short type
, uint16_t *data
) {
581 assert_return(m
, -EINVAL
);
583 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_U16
);
587 r
= netlink_message_read_internal(m
, type
, &attr_data
, &net_byteorder
);
590 else if ((size_t) r
< sizeof(uint16_t))
595 *data
= be16toh(*(uint16_t *) attr_data
);
597 *data
= *(uint16_t *) attr_data
;
603 int sd_netlink_message_read_u32(sd_netlink_message
*m
, unsigned short type
, uint32_t *data
) {
608 assert_return(m
, -EINVAL
);
610 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_U32
);
614 r
= netlink_message_read_internal(m
, type
, &attr_data
, &net_byteorder
);
617 else if ((size_t)r
< sizeof(uint32_t))
622 *data
= be32toh(*(uint32_t *) attr_data
);
624 *data
= *(uint32_t *) attr_data
;
630 int sd_netlink_message_read_ether_addr(sd_netlink_message
*m
, unsigned short type
, struct ether_addr
*data
) {
634 assert_return(m
, -EINVAL
);
636 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_ETHER_ADDR
);
640 r
= netlink_message_read_internal(m
, type
, &attr_data
, NULL
);
643 else if ((size_t)r
< sizeof(struct ether_addr
))
647 memcpy(data
, attr_data
, sizeof(struct ether_addr
));
652 int sd_netlink_message_read_cache_info(sd_netlink_message
*m
, unsigned short type
, struct ifa_cacheinfo
*info
) {
656 assert_return(m
, -EINVAL
);
658 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_CACHE_INFO
);
662 r
= netlink_message_read_internal(m
, type
, &attr_data
, NULL
);
665 else if ((size_t)r
< sizeof(struct ifa_cacheinfo
))
669 memcpy(info
, attr_data
, sizeof(struct ifa_cacheinfo
));
674 int sd_netlink_message_read_in_addr(sd_netlink_message
*m
, unsigned short type
, struct in_addr
*data
) {
678 assert_return(m
, -EINVAL
);
680 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_IN_ADDR
);
684 r
= netlink_message_read_internal(m
, type
, &attr_data
, NULL
);
687 else if ((size_t)r
< sizeof(struct in_addr
))
691 memcpy(data
, attr_data
, sizeof(struct in_addr
));
696 int sd_netlink_message_read_in6_addr(sd_netlink_message
*m
, unsigned short type
, struct in6_addr
*data
) {
700 assert_return(m
, -EINVAL
);
702 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_IN_ADDR
);
706 r
= netlink_message_read_internal(m
, type
, &attr_data
, NULL
);
709 else if ((size_t)r
< sizeof(struct in6_addr
))
713 memcpy(data
, attr_data
, sizeof(struct in6_addr
));
718 static int netlink_container_parse(sd_netlink_message
*m
,
719 struct netlink_container
*container
,
722 unsigned int rt_len
) {
723 _cleanup_free_
struct netlink_attribute
*attributes
= NULL
;
725 attributes
= new0(struct netlink_attribute
, count
);
729 for (; RTA_OK(rta
, rt_len
); rta
= RTA_NEXT(rta
, rt_len
)) {
732 type
= RTA_TYPE(rta
);
734 /* if the kernel is newer than the headers we used
735 when building, we ignore out-of-range attributes */
739 if (attributes
[type
].offset
)
740 log_debug("rtnl: message parse - overwriting repeated attribute");
742 attributes
[type
].offset
= (uint8_t *) rta
- (uint8_t *) m
->hdr
;
743 attributes
[type
].nested
= RTA_FLAGS(rta
) & NLA_F_NESTED
;
744 attributes
[type
].net_byteorder
= RTA_FLAGS(rta
) & NLA_F_NET_BYTEORDER
;
747 container
->attributes
= attributes
;
749 container
->n_attributes
= count
;
754 int sd_netlink_message_enter_container(sd_netlink_message
*m
, unsigned short type_id
) {
755 const NLType
*nl_type
;
756 const NLTypeSystem
*type_system
;
762 assert_return(m
, -EINVAL
);
763 assert_return(m
->n_containers
< RTNL_CONTAINER_DEPTH
, -EINVAL
);
765 r
= type_system_get_type(m
->containers
[m
->n_containers
].type_system
,
771 type
= type_get_type(nl_type
);
773 if (type
== NETLINK_TYPE_NESTED
) {
774 r
= type_system_get_type_system(m
->containers
[m
->n_containers
].type_system
,
779 } else if (type
== NETLINK_TYPE_UNION
) {
780 const NLTypeSystemUnion
*type_system_union
;
782 r
= type_system_get_type_system_union(m
->containers
[m
->n_containers
].type_system
,
788 switch (type_system_union
->match_type
) {
789 case NL_MATCH_SIBLING
:
793 r
= sd_netlink_message_read_string(m
, type_system_union
->match
, &key
);
797 r
= type_system_union_get_type_system(type_system_union
,
805 case NL_MATCH_PROTOCOL
:
809 r
= sd_rtnl_message_get_family(m
, &family
);
813 r
= type_system_union_protocol_get_type_system(type_system_union
,
822 assert_not_reached("sd-netlink: invalid type system union type");
827 r
= netlink_message_read_internal(m
, type_id
, &container
, NULL
);
835 r
= netlink_container_parse(m
,
836 &m
->containers
[m
->n_containers
],
837 type_system_get_count(type_system
),
845 m
->containers
[m
->n_containers
].type_system
= type_system
;
850 int sd_netlink_message_exit_container(sd_netlink_message
*m
) {
851 assert_return(m
, -EINVAL
);
852 assert_return(m
->sealed
, -EINVAL
);
853 assert_return(m
->n_containers
> 0, -EINVAL
);
855 m
->containers
[m
->n_containers
].attributes
= mfree(m
->containers
[m
->n_containers
].attributes
);
856 m
->containers
[m
->n_containers
].type_system
= NULL
;
863 uint32_t rtnl_message_get_serial(sd_netlink_message
*m
) {
867 return m
->hdr
->nlmsg_seq
;
870 int sd_netlink_message_is_error(sd_netlink_message
*m
) {
872 assert_return(m
->hdr
, 0);
874 return m
->hdr
->nlmsg_type
== NLMSG_ERROR
;
877 int sd_netlink_message_get_errno(sd_netlink_message
*m
) {
878 struct nlmsgerr
*err
;
880 assert_return(m
, -EINVAL
);
881 assert_return(m
->hdr
, -EINVAL
);
883 if (!sd_netlink_message_is_error(m
))
886 err
= NLMSG_DATA(m
->hdr
);
891 int sd_netlink_message_rewind(sd_netlink_message
*m
) {
892 const NLType
*nl_type
;
898 assert_return(m
, -EINVAL
);
900 /* don't allow appending to message once parsed */
902 rtnl_message_seal(m
);
904 for (i
= 1; i
<= m
->n_containers
; i
++)
905 m
->containers
[i
].attributes
= mfree(m
->containers
[i
].attributes
);
909 if (m
->containers
[0].attributes
)
910 /* top-level attributes have already been parsed */
915 r
= type_system_get_type(&type_system_root
, &nl_type
, m
->hdr
->nlmsg_type
);
919 type
= type_get_type(nl_type
);
920 size
= type_get_size(nl_type
);
922 if (type
== NETLINK_TYPE_NESTED
) {
923 const NLTypeSystem
*type_system
;
925 type_get_type_system(nl_type
, &type_system
);
927 m
->containers
[0].type_system
= type_system
;
929 r
= netlink_container_parse(m
,
930 &m
->containers
[m
->n_containers
],
931 type_system_get_count(type_system
),
932 (struct rtattr
*)((uint8_t*)NLMSG_DATA(m
->hdr
) + NLMSG_ALIGN(size
)),
933 NLMSG_PAYLOAD(m
->hdr
, size
));
941 void rtnl_message_seal(sd_netlink_message
*m
) {
948 sd_netlink_message
*sd_netlink_message_next(sd_netlink_message
*m
) {
949 assert_return(m
, NULL
);