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>
27 #include "socket-util.h"
28 #include "formats-util.h"
32 #include "sd-netlink.h"
33 #include "netlink-util.h"
34 #include "netlink-internal.h"
35 #include "netlink-types.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_is_broadcast(sd_netlink_message
*m
) {
153 assert_return(m
, -EINVAL
);
158 /* If successful the updated message will be correctly aligned, if
159 unsuccessful the old message is untouched. */
160 static int add_rtattr(sd_netlink_message
*m
, unsigned short type
, const void *data
, size_t data_length
) {
162 size_t message_length
, padding_length
;
163 struct nlmsghdr
*new_hdr
;
172 assert(NLMSG_ALIGN(m
->hdr
->nlmsg_len
) == m
->hdr
->nlmsg_len
);
173 assert(!data
|| data_length
);
175 /* get offset of the new attribute */
176 offset
= m
->hdr
->nlmsg_len
;
178 /* get the size of the new rta attribute (with padding at the end) */
179 rta_length
= RTA_LENGTH(data_length
);
181 /* get the new message size (with padding at the end) */
182 message_length
= offset
+ RTA_ALIGN(rta_length
);
184 /* realloc to fit the new attribute */
185 new_hdr
= realloc(m
->hdr
, message_length
);
190 /* get pointer to the attribute we are about to add */
191 rta
= (struct rtattr
*) ((uint8_t *) m
->hdr
+ offset
);
193 /* if we are inside containers, extend them */
194 for (i
= 0; i
< m
->n_containers
; i
++)
195 GET_CONTAINER(m
, i
)->rta_len
+= message_length
- offset
;
197 /* fill in the attribute */
198 rta
->rta_type
= type
;
199 rta
->rta_len
= rta_length
;
201 /* we don't deal with the case where the user lies about the type
202 * and gives us too little data (so don't do that)
204 padding
= mempcpy(RTA_DATA(rta
), data
, data_length
);
206 /* if no data was passed, make sure we still initialize the padding
207 note that we can have data_length > 0 (used by some containers) */
208 padding
= RTA_DATA(rta
);
211 /* make sure also the padding at the end of the message is initialized */
212 padding_length
= (uint8_t*)m
->hdr
+ message_length
- (uint8_t*)padding
;
213 memzero(padding
, padding_length
);
215 /* update message size */
216 m
->hdr
->nlmsg_len
= message_length
;
221 static int message_attribute_has_type(sd_netlink_message
*m
, size_t *out_size
, uint16_t attribute_type
, uint16_t data_type
) {
227 r
= type_system_get_type(m
->containers
[m
->n_containers
].type_system
, &type
, attribute_type
);
231 if (type_get_type(type
) != data_type
)
235 *out_size
= type_get_size(type
);
239 int sd_netlink_message_append_string(sd_netlink_message
*m
, unsigned short type
, const char *data
) {
243 assert_return(m
, -EINVAL
);
244 assert_return(!m
->sealed
, -EPERM
);
245 assert_return(data
, -EINVAL
);
247 r
= message_attribute_has_type(m
, &size
, type
, NETLINK_TYPE_STRING
);
252 length
= strnlen(data
, size
+1);
256 length
= strlen(data
);
258 r
= add_rtattr(m
, type
, data
, length
+ 1);
265 int sd_netlink_message_append_flag(sd_netlink_message
*m
, unsigned short type
) {
269 assert_return(m
, -EINVAL
);
270 assert_return(!m
->sealed
, -EPERM
);
272 r
= message_attribute_has_type(m
, &size
, type
, NETLINK_TYPE_FLAG
);
276 r
= add_rtattr(m
, type
, NULL
, 0);
283 int sd_netlink_message_append_u8(sd_netlink_message
*m
, unsigned short type
, uint8_t data
) {
286 assert_return(m
, -EINVAL
);
287 assert_return(!m
->sealed
, -EPERM
);
289 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_U8
);
293 r
= add_rtattr(m
, type
, &data
, sizeof(uint8_t));
301 int sd_netlink_message_append_u16(sd_netlink_message
*m
, unsigned short type
, uint16_t data
) {
304 assert_return(m
, -EINVAL
);
305 assert_return(!m
->sealed
, -EPERM
);
307 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_U16
);
311 r
= add_rtattr(m
, type
, &data
, sizeof(uint16_t));
318 int sd_netlink_message_append_u32(sd_netlink_message
*m
, unsigned short type
, uint32_t data
) {
321 assert_return(m
, -EINVAL
);
322 assert_return(!m
->sealed
, -EPERM
);
324 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_U32
);
328 r
= add_rtattr(m
, type
, &data
, sizeof(uint32_t));
335 int sd_netlink_message_append_in_addr(sd_netlink_message
*m
, unsigned short type
, const struct in_addr
*data
) {
338 assert_return(m
, -EINVAL
);
339 assert_return(!m
->sealed
, -EPERM
);
340 assert_return(data
, -EINVAL
);
342 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_IN_ADDR
);
346 r
= add_rtattr(m
, type
, data
, sizeof(struct in_addr
));
353 int sd_netlink_message_append_in6_addr(sd_netlink_message
*m
, unsigned short type
, const struct in6_addr
*data
) {
356 assert_return(m
, -EINVAL
);
357 assert_return(!m
->sealed
, -EPERM
);
358 assert_return(data
, -EINVAL
);
360 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_IN_ADDR
);
364 r
= add_rtattr(m
, type
, data
, sizeof(struct in6_addr
));
371 int sd_netlink_message_append_ether_addr(sd_netlink_message
*m
, unsigned short type
, const struct ether_addr
*data
) {
374 assert_return(m
, -EINVAL
);
375 assert_return(!m
->sealed
, -EPERM
);
376 assert_return(data
, -EINVAL
);
378 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_ETHER_ADDR
);
382 r
= add_rtattr(m
, type
, data
, ETH_ALEN
);
389 int sd_netlink_message_append_cache_info(sd_netlink_message
*m
, unsigned short type
, const struct ifa_cacheinfo
*info
) {
392 assert_return(m
, -EINVAL
);
393 assert_return(!m
->sealed
, -EPERM
);
394 assert_return(info
, -EINVAL
);
396 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_CACHE_INFO
);
400 r
= add_rtattr(m
, type
, info
, sizeof(struct ifa_cacheinfo
));
407 int sd_netlink_message_open_container(sd_netlink_message
*m
, unsigned short type
) {
411 assert_return(m
, -EINVAL
);
412 assert_return(!m
->sealed
, -EPERM
);
413 assert_return(m
->n_containers
< RTNL_CONTAINER_DEPTH
, -ERANGE
);
415 r
= message_attribute_has_type(m
, &size
, type
, NETLINK_TYPE_NESTED
);
417 const NLTypeSystemUnion
*type_system_union
;
420 r
= message_attribute_has_type(m
, &size
, type
, NETLINK_TYPE_UNION
);
424 r
= sd_rtnl_message_get_family(m
, &family
);
428 r
= type_system_get_type_system_union(m
->containers
[m
->n_containers
].type_system
, &type_system_union
, type
);
432 r
= type_system_union_protocol_get_type_system(type_system_union
,
433 &m
->containers
[m
->n_containers
+ 1].type_system
,
438 r
= type_system_get_type_system(m
->containers
[m
->n_containers
].type_system
,
439 &m
->containers
[m
->n_containers
+ 1].type_system
,
445 r
= add_rtattr(m
, type
| NLA_F_NESTED
, NULL
, size
);
449 m
->containers
[m
->n_containers
++].offset
= r
;
454 int sd_netlink_message_open_container_union(sd_netlink_message
*m
, unsigned short type
, const char *key
) {
455 const NLTypeSystemUnion
*type_system_union
;
458 assert_return(m
, -EINVAL
);
459 assert_return(!m
->sealed
, -EPERM
);
461 r
= type_system_get_type_system_union(m
->containers
[m
->n_containers
].type_system
, &type_system_union
, type
);
465 r
= type_system_union_get_type_system(type_system_union
,
466 &m
->containers
[m
->n_containers
+ 1].type_system
,
471 r
= sd_netlink_message_append_string(m
, type_system_union
->match
, key
);
475 /* do we evere need non-null size */
476 r
= add_rtattr(m
, type
| NLA_F_NESTED
, NULL
, 0);
480 m
->containers
[m
->n_containers
++].offset
= r
;
486 int sd_netlink_message_close_container(sd_netlink_message
*m
) {
487 assert_return(m
, -EINVAL
);
488 assert_return(!m
->sealed
, -EPERM
);
489 assert_return(m
->n_containers
> 0, -EINVAL
);
491 m
->containers
[m
->n_containers
].type_system
= NULL
;
497 static int netlink_message_read_internal(sd_netlink_message
*m
, unsigned short type
, void **data
, bool *net_byteorder
) {
498 struct netlink_attribute
*attribute
;
501 assert_return(m
, -EINVAL
);
502 assert_return(m
->sealed
, -EPERM
);
503 assert_return(data
, -EINVAL
);
504 assert(m
->n_containers
< RTNL_CONTAINER_DEPTH
);
505 assert(m
->containers
[m
->n_containers
].attributes
);
506 assert(type
< m
->containers
[m
->n_containers
].n_attributes
);
508 attribute
= &m
->containers
[m
->n_containers
].attributes
[type
];
510 if(!attribute
->offset
)
513 rta
= (struct rtattr
*)((uint8_t *) m
->hdr
+ attribute
->offset
);
515 *data
= RTA_DATA(rta
);
518 *net_byteorder
= attribute
->net_byteorder
;
520 return RTA_PAYLOAD(rta
);
523 int sd_netlink_message_read_string(sd_netlink_message
*m
, unsigned short type
, const char **data
) {
527 assert_return(m
, -EINVAL
);
529 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_STRING
);
533 r
= netlink_message_read_internal(m
, type
, &attr_data
, NULL
);
536 else if (strnlen(attr_data
, r
) >= (size_t) r
)
540 *data
= (const char *) attr_data
;
545 int sd_netlink_message_read_u8(sd_netlink_message
*m
, unsigned short type
, uint8_t *data
) {
549 assert_return(m
, -EINVAL
);
551 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_U8
);
555 r
= netlink_message_read_internal(m
, type
, &attr_data
, NULL
);
558 else if ((size_t) r
< sizeof(uint8_t))
562 *data
= *(uint8_t *) attr_data
;
567 int sd_netlink_message_read_u16(sd_netlink_message
*m
, unsigned short type
, uint16_t *data
) {
572 assert_return(m
, -EINVAL
);
574 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_U16
);
578 r
= netlink_message_read_internal(m
, type
, &attr_data
, &net_byteorder
);
581 else if ((size_t) r
< sizeof(uint16_t))
586 *data
= be16toh(*(uint16_t *) attr_data
);
588 *data
= *(uint16_t *) attr_data
;
594 int sd_netlink_message_read_u32(sd_netlink_message
*m
, unsigned short type
, uint32_t *data
) {
599 assert_return(m
, -EINVAL
);
601 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_U32
);
605 r
= netlink_message_read_internal(m
, type
, &attr_data
, &net_byteorder
);
608 else if ((size_t)r
< sizeof(uint32_t))
613 *data
= be32toh(*(uint32_t *) attr_data
);
615 *data
= *(uint32_t *) attr_data
;
621 int sd_netlink_message_read_ether_addr(sd_netlink_message
*m
, unsigned short type
, struct ether_addr
*data
) {
625 assert_return(m
, -EINVAL
);
627 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_ETHER_ADDR
);
631 r
= netlink_message_read_internal(m
, type
, &attr_data
, NULL
);
634 else if ((size_t)r
< sizeof(struct ether_addr
))
638 memcpy(data
, attr_data
, sizeof(struct ether_addr
));
643 int sd_netlink_message_read_cache_info(sd_netlink_message
*m
, unsigned short type
, struct ifa_cacheinfo
*info
) {
647 assert_return(m
, -EINVAL
);
649 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_CACHE_INFO
);
653 r
= netlink_message_read_internal(m
, type
, &attr_data
, NULL
);
656 else if ((size_t)r
< sizeof(struct ifa_cacheinfo
))
660 memcpy(info
, attr_data
, sizeof(struct ifa_cacheinfo
));
665 int sd_netlink_message_read_in_addr(sd_netlink_message
*m
, unsigned short type
, struct in_addr
*data
) {
669 assert_return(m
, -EINVAL
);
671 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_IN_ADDR
);
675 r
= netlink_message_read_internal(m
, type
, &attr_data
, NULL
);
678 else if ((size_t)r
< sizeof(struct in_addr
))
682 memcpy(data
, attr_data
, sizeof(struct in_addr
));
687 int sd_netlink_message_read_in6_addr(sd_netlink_message
*m
, unsigned short type
, struct in6_addr
*data
) {
691 assert_return(m
, -EINVAL
);
693 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_IN_ADDR
);
697 r
= netlink_message_read_internal(m
, type
, &attr_data
, NULL
);
700 else if ((size_t)r
< sizeof(struct in6_addr
))
704 memcpy(data
, attr_data
, sizeof(struct in6_addr
));
709 static int netlink_container_parse(sd_netlink_message
*m
,
710 struct netlink_container
*container
,
713 unsigned int rt_len
) {
714 _cleanup_free_
struct netlink_attribute
*attributes
= NULL
;
716 attributes
= new0(struct netlink_attribute
, count
);
720 for (; RTA_OK(rta
, rt_len
); rta
= RTA_NEXT(rta
, rt_len
)) {
723 type
= RTA_TYPE(rta
);
725 /* if the kernel is newer than the headers we used
726 when building, we ignore out-of-range attributes */
730 if (attributes
[type
].offset
)
731 log_debug("rtnl: message parse - overwriting repeated attribute");
733 attributes
[type
].offset
= (uint8_t *) rta
- (uint8_t *) m
->hdr
;
734 attributes
[type
].nested
= RTA_FLAGS(rta
) & NLA_F_NESTED
;
735 attributes
[type
].net_byteorder
= RTA_FLAGS(rta
) & NLA_F_NET_BYTEORDER
;
738 container
->attributes
= attributes
;
740 container
->n_attributes
= count
;
745 int sd_netlink_message_enter_container(sd_netlink_message
*m
, unsigned short type_id
) {
746 const NLType
*nl_type
;
747 const NLTypeSystem
*type_system
;
753 assert_return(m
, -EINVAL
);
754 assert_return(m
->n_containers
< RTNL_CONTAINER_DEPTH
, -EINVAL
);
756 r
= type_system_get_type(m
->containers
[m
->n_containers
].type_system
,
762 type
= type_get_type(nl_type
);
764 if (type
== NETLINK_TYPE_NESTED
) {
765 r
= type_system_get_type_system(m
->containers
[m
->n_containers
].type_system
,
770 } else if (type
== NETLINK_TYPE_UNION
) {
771 const NLTypeSystemUnion
*type_system_union
;
773 r
= type_system_get_type_system_union(m
->containers
[m
->n_containers
].type_system
,
779 switch (type_system_union
->match_type
) {
780 case NL_MATCH_SIBLING
:
784 r
= sd_netlink_message_read_string(m
, type_system_union
->match
, &key
);
788 r
= type_system_union_get_type_system(type_system_union
,
796 case NL_MATCH_PROTOCOL
:
800 r
= sd_rtnl_message_get_family(m
, &family
);
804 r
= type_system_union_protocol_get_type_system(type_system_union
,
813 assert_not_reached("sd-netlink: invalid type system union type");
818 r
= netlink_message_read_internal(m
, type_id
, &container
, NULL
);
826 r
= netlink_container_parse(m
,
827 &m
->containers
[m
->n_containers
],
828 type_system_get_count(type_system
),
836 m
->containers
[m
->n_containers
].type_system
= type_system
;
841 int sd_netlink_message_exit_container(sd_netlink_message
*m
) {
842 assert_return(m
, -EINVAL
);
843 assert_return(m
->sealed
, -EINVAL
);
844 assert_return(m
->n_containers
> 0, -EINVAL
);
846 m
->containers
[m
->n_containers
].attributes
= mfree(m
->containers
[m
->n_containers
].attributes
);
847 m
->containers
[m
->n_containers
].type_system
= NULL
;
854 uint32_t rtnl_message_get_serial(sd_netlink_message
*m
) {
858 return m
->hdr
->nlmsg_seq
;
861 int sd_netlink_message_is_error(sd_netlink_message
*m
) {
863 assert_return(m
->hdr
, 0);
865 return m
->hdr
->nlmsg_type
== NLMSG_ERROR
;
868 int sd_netlink_message_get_errno(sd_netlink_message
*m
) {
869 struct nlmsgerr
*err
;
871 assert_return(m
, -EINVAL
);
872 assert_return(m
->hdr
, -EINVAL
);
874 if (!sd_netlink_message_is_error(m
))
877 err
= NLMSG_DATA(m
->hdr
);
882 int sd_netlink_message_rewind(sd_netlink_message
*m
) {
883 const NLType
*nl_type
;
889 assert_return(m
, -EINVAL
);
891 /* don't allow appending to message once parsed */
893 rtnl_message_seal(m
);
895 for (i
= 1; i
<= m
->n_containers
; i
++) {
896 m
->containers
[i
].attributes
= mfree(m
->containers
[i
].attributes
);
901 if (m
->containers
[0].attributes
)
902 /* top-level attributes have already been parsed */
907 r
= type_system_get_type(&type_system_root
, &nl_type
, m
->hdr
->nlmsg_type
);
911 type
= type_get_type(nl_type
);
912 size
= type_get_size(nl_type
);
914 if (type
== NETLINK_TYPE_NESTED
) {
915 const NLTypeSystem
*type_system
;
917 type_get_type_system(nl_type
, &type_system
);
919 m
->containers
[0].type_system
= type_system
;
921 r
= netlink_container_parse(m
,
922 &m
->containers
[m
->n_containers
],
923 type_system_get_count(type_system
),
924 (struct rtattr
*)((uint8_t*)NLMSG_DATA(m
->hdr
) + NLMSG_ALIGN(size
)),
925 NLMSG_PAYLOAD(m
->hdr
, size
));
933 void rtnl_message_seal(sd_netlink_message
*m
) {
940 sd_netlink_message
*sd_netlink_message_next(sd_netlink_message
*m
) {
941 assert_return(m
, NULL
);