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 "alloc-util.h"
29 #include "formats-util.h"
31 #include "netlink-internal.h"
32 #include "netlink-types.h"
33 #include "netlink-util.h"
35 #include "socket-util.h"
38 #define GET_CONTAINER(m, i) ((i) < (m)->n_containers ? (struct rtattr*)((uint8_t*)(m)->hdr + (m)->containers[i].offset) : NULL)
39 #define PUSH_CONTAINER(m, new) (m)->container_offsets[(m)->n_containers ++] = (uint8_t*)(new) - (uint8_t*)(m)->hdr;
41 #define RTA_TYPE(rta) ((rta)->rta_type & NLA_TYPE_MASK)
42 #define RTA_FLAGS(rta) ((rta)->rta_type & ~NLA_TYPE_MASK)
44 int message_new_empty(sd_netlink
*rtnl
, sd_netlink_message
**ret
) {
45 sd_netlink_message
*m
;
47 assert_return(ret
, -EINVAL
);
49 /* Note that 'rtnl' is currently unused, if we start using it internally
50 we must take care to avoid problems due to mutual references between
51 buses and their queued messages. See sd-bus.
54 m
= new0(sd_netlink_message
, 1);
58 m
->n_ref
= REFCNT_INIT
;
67 int message_new(sd_netlink
*rtnl
, sd_netlink_message
**ret
, uint16_t type
) {
68 _cleanup_netlink_message_unref_ sd_netlink_message
*m
= NULL
;
69 const NLType
*nl_type
;
73 r
= type_system_get_type(&type_system_root
, &nl_type
, type
);
77 if (type_get_type(nl_type
) != NETLINK_TYPE_NESTED
)
80 r
= message_new_empty(rtnl
, &m
);
84 size
= NLMSG_SPACE(type_get_size(nl_type
));
86 assert(size
>= sizeof(struct nlmsghdr
));
87 m
->hdr
= malloc0(size
);
91 m
->hdr
->nlmsg_flags
= NLM_F_REQUEST
| NLM_F_ACK
;
93 type_get_type_system(nl_type
, &m
->containers
[0].type_system
);
94 m
->hdr
->nlmsg_len
= size
;
95 m
->hdr
->nlmsg_type
= type
;
103 int sd_netlink_message_request_dump(sd_netlink_message
*m
, int dump
) {
104 assert_return(m
, -EINVAL
);
105 assert_return(m
->hdr
, -EINVAL
);
106 assert_return(m
->hdr
->nlmsg_type
== RTM_GETLINK
||
107 m
->hdr
->nlmsg_type
== RTM_GETADDR
||
108 m
->hdr
->nlmsg_type
== RTM_GETROUTE
||
109 m
->hdr
->nlmsg_type
== RTM_GETNEIGH
,
113 m
->hdr
->nlmsg_flags
|= NLM_F_DUMP
;
115 m
->hdr
->nlmsg_flags
&= ~NLM_F_DUMP
;
120 sd_netlink_message
*sd_netlink_message_ref(sd_netlink_message
*m
) {
122 assert_se(REFCNT_INC(m
->n_ref
) >= 2);
127 sd_netlink_message
*sd_netlink_message_unref(sd_netlink_message
*m
) {
128 if (m
&& REFCNT_DEC(m
->n_ref
) == 0) {
133 for (i
= 0; i
<= m
->n_containers
; i
++)
134 free(m
->containers
[i
].attributes
);
136 sd_netlink_message_unref(m
->next
);
144 int sd_netlink_message_get_type(sd_netlink_message
*m
, uint16_t *type
) {
145 assert_return(m
, -EINVAL
);
146 assert_return(type
, -EINVAL
);
148 *type
= m
->hdr
->nlmsg_type
;
153 int sd_netlink_message_set_flags(sd_netlink_message
*m
, uint16_t flags
) {
154 assert_return(m
, -EINVAL
);
155 assert_return(flags
, -EINVAL
);
157 m
->hdr
->nlmsg_flags
= flags
;
162 int sd_netlink_message_is_broadcast(sd_netlink_message
*m
) {
163 assert_return(m
, -EINVAL
);
168 /* If successful the updated message will be correctly aligned, if
169 unsuccessful the old message is untouched. */
170 static int add_rtattr(sd_netlink_message
*m
, unsigned short type
, const void *data
, size_t data_length
) {
172 size_t message_length
, padding_length
;
173 struct nlmsghdr
*new_hdr
;
182 assert(NLMSG_ALIGN(m
->hdr
->nlmsg_len
) == m
->hdr
->nlmsg_len
);
183 assert(!data
|| data_length
);
185 /* get offset of the new attribute */
186 offset
= m
->hdr
->nlmsg_len
;
188 /* get the size of the new rta attribute (with padding at the end) */
189 rta_length
= RTA_LENGTH(data_length
);
191 /* get the new message size (with padding at the end) */
192 message_length
= offset
+ RTA_ALIGN(rta_length
);
194 /* realloc to fit the new attribute */
195 new_hdr
= realloc(m
->hdr
, message_length
);
200 /* get pointer to the attribute we are about to add */
201 rta
= (struct rtattr
*) ((uint8_t *) m
->hdr
+ offset
);
203 /* if we are inside containers, extend them */
204 for (i
= 0; i
< m
->n_containers
; i
++)
205 GET_CONTAINER(m
, i
)->rta_len
+= message_length
- offset
;
207 /* fill in the attribute */
208 rta
->rta_type
= type
;
209 rta
->rta_len
= rta_length
;
211 /* we don't deal with the case where the user lies about the type
212 * and gives us too little data (so don't do that)
214 padding
= mempcpy(RTA_DATA(rta
), data
, data_length
);
216 /* if no data was passed, make sure we still initialize the padding
217 note that we can have data_length > 0 (used by some containers) */
218 padding
= RTA_DATA(rta
);
221 /* make sure also the padding at the end of the message is initialized */
222 padding_length
= (uint8_t*)m
->hdr
+ message_length
- (uint8_t*)padding
;
223 memzero(padding
, padding_length
);
225 /* update message size */
226 m
->hdr
->nlmsg_len
= message_length
;
231 static int message_attribute_has_type(sd_netlink_message
*m
, size_t *out_size
, uint16_t attribute_type
, uint16_t data_type
) {
237 r
= type_system_get_type(m
->containers
[m
->n_containers
].type_system
, &type
, attribute_type
);
241 if (type_get_type(type
) != data_type
)
245 *out_size
= type_get_size(type
);
249 int sd_netlink_message_append_string(sd_netlink_message
*m
, unsigned short type
, const char *data
) {
253 assert_return(m
, -EINVAL
);
254 assert_return(!m
->sealed
, -EPERM
);
255 assert_return(data
, -EINVAL
);
257 r
= message_attribute_has_type(m
, &size
, type
, NETLINK_TYPE_STRING
);
262 length
= strnlen(data
, size
+1);
266 length
= strlen(data
);
268 r
= add_rtattr(m
, type
, data
, length
+ 1);
275 int sd_netlink_message_append_flag(sd_netlink_message
*m
, unsigned short type
) {
279 assert_return(m
, -EINVAL
);
280 assert_return(!m
->sealed
, -EPERM
);
282 r
= message_attribute_has_type(m
, &size
, type
, NETLINK_TYPE_FLAG
);
286 r
= add_rtattr(m
, type
, NULL
, 0);
293 int sd_netlink_message_append_u8(sd_netlink_message
*m
, unsigned short type
, uint8_t data
) {
296 assert_return(m
, -EINVAL
);
297 assert_return(!m
->sealed
, -EPERM
);
299 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_U8
);
303 r
= add_rtattr(m
, type
, &data
, sizeof(uint8_t));
311 int sd_netlink_message_append_u16(sd_netlink_message
*m
, unsigned short type
, uint16_t data
) {
314 assert_return(m
, -EINVAL
);
315 assert_return(!m
->sealed
, -EPERM
);
317 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_U16
);
321 r
= add_rtattr(m
, type
, &data
, sizeof(uint16_t));
328 int sd_netlink_message_append_u32(sd_netlink_message
*m
, unsigned short type
, uint32_t data
) {
331 assert_return(m
, -EINVAL
);
332 assert_return(!m
->sealed
, -EPERM
);
334 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_U32
);
338 r
= add_rtattr(m
, type
, &data
, sizeof(uint32_t));
345 int sd_netlink_message_append_in_addr(sd_netlink_message
*m
, unsigned short type
, const struct in_addr
*data
) {
348 assert_return(m
, -EINVAL
);
349 assert_return(!m
->sealed
, -EPERM
);
350 assert_return(data
, -EINVAL
);
352 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_IN_ADDR
);
356 r
= add_rtattr(m
, type
, data
, sizeof(struct in_addr
));
363 int sd_netlink_message_append_in6_addr(sd_netlink_message
*m
, unsigned short type
, const struct in6_addr
*data
) {
366 assert_return(m
, -EINVAL
);
367 assert_return(!m
->sealed
, -EPERM
);
368 assert_return(data
, -EINVAL
);
370 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_IN_ADDR
);
374 r
= add_rtattr(m
, type
, data
, sizeof(struct in6_addr
));
381 int sd_netlink_message_append_ether_addr(sd_netlink_message
*m
, unsigned short type
, const struct ether_addr
*data
) {
384 assert_return(m
, -EINVAL
);
385 assert_return(!m
->sealed
, -EPERM
);
386 assert_return(data
, -EINVAL
);
388 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_ETHER_ADDR
);
392 r
= add_rtattr(m
, type
, data
, ETH_ALEN
);
399 int sd_netlink_message_append_cache_info(sd_netlink_message
*m
, unsigned short type
, const struct ifa_cacheinfo
*info
) {
402 assert_return(m
, -EINVAL
);
403 assert_return(!m
->sealed
, -EPERM
);
404 assert_return(info
, -EINVAL
);
406 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_CACHE_INFO
);
410 r
= add_rtattr(m
, type
, info
, sizeof(struct ifa_cacheinfo
));
417 int sd_netlink_message_open_container(sd_netlink_message
*m
, unsigned short type
) {
421 assert_return(m
, -EINVAL
);
422 assert_return(!m
->sealed
, -EPERM
);
423 assert_return(m
->n_containers
< RTNL_CONTAINER_DEPTH
, -ERANGE
);
425 r
= message_attribute_has_type(m
, &size
, type
, NETLINK_TYPE_NESTED
);
427 const NLTypeSystemUnion
*type_system_union
;
430 r
= message_attribute_has_type(m
, &size
, type
, NETLINK_TYPE_UNION
);
434 r
= sd_rtnl_message_get_family(m
, &family
);
438 r
= type_system_get_type_system_union(m
->containers
[m
->n_containers
].type_system
, &type_system_union
, type
);
442 r
= type_system_union_protocol_get_type_system(type_system_union
,
443 &m
->containers
[m
->n_containers
+ 1].type_system
,
448 r
= type_system_get_type_system(m
->containers
[m
->n_containers
].type_system
,
449 &m
->containers
[m
->n_containers
+ 1].type_system
,
455 r
= add_rtattr(m
, type
| NLA_F_NESTED
, NULL
, size
);
459 m
->containers
[m
->n_containers
++].offset
= r
;
464 int sd_netlink_message_open_container_union(sd_netlink_message
*m
, unsigned short type
, const char *key
) {
465 const NLTypeSystemUnion
*type_system_union
;
468 assert_return(m
, -EINVAL
);
469 assert_return(!m
->sealed
, -EPERM
);
471 r
= type_system_get_type_system_union(m
->containers
[m
->n_containers
].type_system
, &type_system_union
, type
);
475 r
= type_system_union_get_type_system(type_system_union
,
476 &m
->containers
[m
->n_containers
+ 1].type_system
,
481 r
= sd_netlink_message_append_string(m
, type_system_union
->match
, key
);
485 /* do we evere need non-null size */
486 r
= add_rtattr(m
, type
| NLA_F_NESTED
, NULL
, 0);
490 m
->containers
[m
->n_containers
++].offset
= r
;
496 int sd_netlink_message_close_container(sd_netlink_message
*m
) {
497 assert_return(m
, -EINVAL
);
498 assert_return(!m
->sealed
, -EPERM
);
499 assert_return(m
->n_containers
> 0, -EINVAL
);
501 m
->containers
[m
->n_containers
].type_system
= NULL
;
507 static int netlink_message_read_internal(sd_netlink_message
*m
, unsigned short type
, void **data
, bool *net_byteorder
) {
508 struct netlink_attribute
*attribute
;
511 assert_return(m
, -EINVAL
);
512 assert_return(m
->sealed
, -EPERM
);
513 assert_return(data
, -EINVAL
);
514 assert(m
->n_containers
< RTNL_CONTAINER_DEPTH
);
515 assert(m
->containers
[m
->n_containers
].attributes
);
516 assert(type
< m
->containers
[m
->n_containers
].n_attributes
);
518 attribute
= &m
->containers
[m
->n_containers
].attributes
[type
];
520 if(!attribute
->offset
)
523 rta
= (struct rtattr
*)((uint8_t *) m
->hdr
+ attribute
->offset
);
525 *data
= RTA_DATA(rta
);
528 *net_byteorder
= attribute
->net_byteorder
;
530 return RTA_PAYLOAD(rta
);
533 int sd_netlink_message_read_string(sd_netlink_message
*m
, unsigned short type
, const char **data
) {
537 assert_return(m
, -EINVAL
);
539 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_STRING
);
543 r
= netlink_message_read_internal(m
, type
, &attr_data
, NULL
);
546 else if (strnlen(attr_data
, r
) >= (size_t) r
)
550 *data
= (const char *) attr_data
;
555 int sd_netlink_message_read_u8(sd_netlink_message
*m
, unsigned short type
, uint8_t *data
) {
559 assert_return(m
, -EINVAL
);
561 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_U8
);
565 r
= netlink_message_read_internal(m
, type
, &attr_data
, NULL
);
568 else if ((size_t) r
< sizeof(uint8_t))
572 *data
= *(uint8_t *) attr_data
;
577 int sd_netlink_message_read_u16(sd_netlink_message
*m
, unsigned short type
, uint16_t *data
) {
582 assert_return(m
, -EINVAL
);
584 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_U16
);
588 r
= netlink_message_read_internal(m
, type
, &attr_data
, &net_byteorder
);
591 else if ((size_t) r
< sizeof(uint16_t))
596 *data
= be16toh(*(uint16_t *) attr_data
);
598 *data
= *(uint16_t *) attr_data
;
604 int sd_netlink_message_read_u32(sd_netlink_message
*m
, unsigned short type
, uint32_t *data
) {
609 assert_return(m
, -EINVAL
);
611 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_U32
);
615 r
= netlink_message_read_internal(m
, type
, &attr_data
, &net_byteorder
);
618 else if ((size_t)r
< sizeof(uint32_t))
623 *data
= be32toh(*(uint32_t *) attr_data
);
625 *data
= *(uint32_t *) attr_data
;
631 int sd_netlink_message_read_ether_addr(sd_netlink_message
*m
, unsigned short type
, struct ether_addr
*data
) {
635 assert_return(m
, -EINVAL
);
637 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_ETHER_ADDR
);
641 r
= netlink_message_read_internal(m
, type
, &attr_data
, NULL
);
644 else if ((size_t)r
< sizeof(struct ether_addr
))
648 memcpy(data
, attr_data
, sizeof(struct ether_addr
));
653 int sd_netlink_message_read_cache_info(sd_netlink_message
*m
, unsigned short type
, struct ifa_cacheinfo
*info
) {
657 assert_return(m
, -EINVAL
);
659 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_CACHE_INFO
);
663 r
= netlink_message_read_internal(m
, type
, &attr_data
, NULL
);
666 else if ((size_t)r
< sizeof(struct ifa_cacheinfo
))
670 memcpy(info
, attr_data
, sizeof(struct ifa_cacheinfo
));
675 int sd_netlink_message_read_in_addr(sd_netlink_message
*m
, unsigned short type
, struct in_addr
*data
) {
679 assert_return(m
, -EINVAL
);
681 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_IN_ADDR
);
685 r
= netlink_message_read_internal(m
, type
, &attr_data
, NULL
);
688 else if ((size_t)r
< sizeof(struct in_addr
))
692 memcpy(data
, attr_data
, sizeof(struct in_addr
));
697 int sd_netlink_message_read_in6_addr(sd_netlink_message
*m
, unsigned short type
, struct in6_addr
*data
) {
701 assert_return(m
, -EINVAL
);
703 r
= message_attribute_has_type(m
, NULL
, type
, NETLINK_TYPE_IN_ADDR
);
707 r
= netlink_message_read_internal(m
, type
, &attr_data
, NULL
);
710 else if ((size_t)r
< sizeof(struct in6_addr
))
714 memcpy(data
, attr_data
, sizeof(struct in6_addr
));
719 static int netlink_container_parse(sd_netlink_message
*m
,
720 struct netlink_container
*container
,
723 unsigned int rt_len
) {
724 _cleanup_free_
struct netlink_attribute
*attributes
= NULL
;
726 attributes
= new0(struct netlink_attribute
, count
);
730 for (; RTA_OK(rta
, rt_len
); rta
= RTA_NEXT(rta
, rt_len
)) {
733 type
= RTA_TYPE(rta
);
735 /* if the kernel is newer than the headers we used
736 when building, we ignore out-of-range attributes */
740 if (attributes
[type
].offset
)
741 log_debug("rtnl: message parse - overwriting repeated attribute");
743 attributes
[type
].offset
= (uint8_t *) rta
- (uint8_t *) m
->hdr
;
744 attributes
[type
].nested
= RTA_FLAGS(rta
) & NLA_F_NESTED
;
745 attributes
[type
].net_byteorder
= RTA_FLAGS(rta
) & NLA_F_NET_BYTEORDER
;
748 container
->attributes
= attributes
;
750 container
->n_attributes
= count
;
755 int sd_netlink_message_enter_container(sd_netlink_message
*m
, unsigned short type_id
) {
756 const NLType
*nl_type
;
757 const NLTypeSystem
*type_system
;
763 assert_return(m
, -EINVAL
);
764 assert_return(m
->n_containers
< RTNL_CONTAINER_DEPTH
, -EINVAL
);
766 r
= type_system_get_type(m
->containers
[m
->n_containers
].type_system
,
772 type
= type_get_type(nl_type
);
774 if (type
== NETLINK_TYPE_NESTED
) {
775 r
= type_system_get_type_system(m
->containers
[m
->n_containers
].type_system
,
780 } else if (type
== NETLINK_TYPE_UNION
) {
781 const NLTypeSystemUnion
*type_system_union
;
783 r
= type_system_get_type_system_union(m
->containers
[m
->n_containers
].type_system
,
789 switch (type_system_union
->match_type
) {
790 case NL_MATCH_SIBLING
:
794 r
= sd_netlink_message_read_string(m
, type_system_union
->match
, &key
);
798 r
= type_system_union_get_type_system(type_system_union
,
806 case NL_MATCH_PROTOCOL
:
810 r
= sd_rtnl_message_get_family(m
, &family
);
814 r
= type_system_union_protocol_get_type_system(type_system_union
,
823 assert_not_reached("sd-netlink: invalid type system union type");
828 r
= netlink_message_read_internal(m
, type_id
, &container
, NULL
);
836 r
= netlink_container_parse(m
,
837 &m
->containers
[m
->n_containers
],
838 type_system_get_count(type_system
),
846 m
->containers
[m
->n_containers
].type_system
= type_system
;
851 int sd_netlink_message_exit_container(sd_netlink_message
*m
) {
852 assert_return(m
, -EINVAL
);
853 assert_return(m
->sealed
, -EINVAL
);
854 assert_return(m
->n_containers
> 0, -EINVAL
);
856 m
->containers
[m
->n_containers
].attributes
= mfree(m
->containers
[m
->n_containers
].attributes
);
857 m
->containers
[m
->n_containers
].type_system
= NULL
;
864 uint32_t rtnl_message_get_serial(sd_netlink_message
*m
) {
868 return m
->hdr
->nlmsg_seq
;
871 int sd_netlink_message_is_error(sd_netlink_message
*m
) {
873 assert_return(m
->hdr
, 0);
875 return m
->hdr
->nlmsg_type
== NLMSG_ERROR
;
878 int sd_netlink_message_get_errno(sd_netlink_message
*m
) {
879 struct nlmsgerr
*err
;
881 assert_return(m
, -EINVAL
);
882 assert_return(m
->hdr
, -EINVAL
);
884 if (!sd_netlink_message_is_error(m
))
887 err
= NLMSG_DATA(m
->hdr
);
892 int sd_netlink_message_rewind(sd_netlink_message
*m
) {
893 const NLType
*nl_type
;
899 assert_return(m
, -EINVAL
);
901 /* don't allow appending to message once parsed */
903 rtnl_message_seal(m
);
905 for (i
= 1; i
<= m
->n_containers
; i
++)
906 m
->containers
[i
].attributes
= mfree(m
->containers
[i
].attributes
);
910 if (m
->containers
[0].attributes
)
911 /* top-level attributes have already been parsed */
916 r
= type_system_get_type(&type_system_root
, &nl_type
, m
->hdr
->nlmsg_type
);
920 type
= type_get_type(nl_type
);
921 size
= type_get_size(nl_type
);
923 if (type
== NETLINK_TYPE_NESTED
) {
924 const NLTypeSystem
*type_system
;
926 type_get_type_system(nl_type
, &type_system
);
928 m
->containers
[0].type_system
= type_system
;
930 r
= netlink_container_parse(m
,
931 &m
->containers
[m
->n_containers
],
932 type_system_get_count(type_system
),
933 (struct rtattr
*)((uint8_t*)NLMSG_DATA(m
->hdr
) + NLMSG_ALIGN(size
)),
934 NLMSG_PAYLOAD(m
->hdr
, size
));
942 void rtnl_message_seal(sd_netlink_message
*m
) {
949 sd_netlink_message
*sd_netlink_message_next(sd_netlink_message
*m
) {
950 assert_return(m
, NULL
);