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)->container_offsets[i]) : 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)
42 int message_new_empty(sd_netlink
*rtnl
, sd_netlink_message
**ret
) {
43 sd_netlink_message
*m
;
45 assert_return(ret
, -EINVAL
);
47 /* Note that 'rtnl' is currently unused, if we start using it internally
48 we must take care to avoid problems due to mutual references between
49 buses and their queued messages. See sd-bus.
52 m
= new0(sd_netlink_message
, 1);
56 m
->n_ref
= REFCNT_INIT
;
65 int message_new(sd_netlink
*rtnl
, sd_netlink_message
**ret
, uint16_t type
) {
66 _cleanup_netlink_message_unref_ sd_netlink_message
*m
= NULL
;
67 const NLType
*nl_type
;
71 r
= type_system_get_type(NULL
, &nl_type
, type
);
75 r
= message_new_empty(rtnl
, &m
);
79 size
= NLMSG_SPACE(nl_type
->size
);
81 assert(size
>= sizeof(struct nlmsghdr
));
82 m
->hdr
= malloc0(size
);
86 m
->hdr
->nlmsg_flags
= NLM_F_REQUEST
| NLM_F_ACK
;
88 m
->container_type_system
[0] = nl_type
->type_system
;
89 m
->hdr
->nlmsg_len
= size
;
90 m
->hdr
->nlmsg_type
= type
;
98 int sd_netlink_message_request_dump(sd_netlink_message
*m
, int dump
) {
99 assert_return(m
, -EINVAL
);
100 assert_return(m
->hdr
, -EINVAL
);
101 assert_return(m
->hdr
->nlmsg_type
== RTM_GETLINK
||
102 m
->hdr
->nlmsg_type
== RTM_GETADDR
||
103 m
->hdr
->nlmsg_type
== RTM_GETROUTE
||
104 m
->hdr
->nlmsg_type
== RTM_GETNEIGH
,
108 m
->hdr
->nlmsg_flags
|= NLM_F_DUMP
;
110 m
->hdr
->nlmsg_flags
&= ~NLM_F_DUMP
;
115 sd_netlink_message
*sd_netlink_message_ref(sd_netlink_message
*m
) {
117 assert_se(REFCNT_INC(m
->n_ref
) >= 2);
122 sd_netlink_message
*sd_netlink_message_unref(sd_netlink_message
*m
) {
123 if (m
&& REFCNT_DEC(m
->n_ref
) == 0) {
128 for (i
= 0; i
<= m
->n_containers
; i
++)
129 free(m
->rta_offset_tb
[i
]);
131 sd_netlink_message_unref(m
->next
);
139 int sd_netlink_message_get_type(sd_netlink_message
*m
, uint16_t *type
) {
140 assert_return(m
, -EINVAL
);
141 assert_return(type
, -EINVAL
);
143 *type
= m
->hdr
->nlmsg_type
;
148 int sd_netlink_message_is_broadcast(sd_netlink_message
*m
) {
149 assert_return(m
, -EINVAL
);
154 /* If successful the updated message will be correctly aligned, if
155 unsuccessful the old message is untouched. */
156 static int add_rtattr(sd_netlink_message
*m
, unsigned short type
, const void *data
, size_t data_length
) {
158 size_t message_length
, padding_length
;
159 struct nlmsghdr
*new_hdr
;
168 assert(NLMSG_ALIGN(m
->hdr
->nlmsg_len
) == m
->hdr
->nlmsg_len
);
169 assert(!data
|| data_length
);
171 /* get offset of the new attribute */
172 offset
= m
->hdr
->nlmsg_len
;
174 /* get the size of the new rta attribute (with padding at the end) */
175 rta_length
= RTA_LENGTH(data_length
);
177 /* get the new message size (with padding at the end) */
178 message_length
= offset
+ RTA_ALIGN(rta_length
);
180 /* realloc to fit the new attribute */
181 new_hdr
= realloc(m
->hdr
, message_length
);
186 /* get pointer to the attribute we are about to add */
187 rta
= (struct rtattr
*) ((uint8_t *) m
->hdr
+ offset
);
189 /* if we are inside containers, extend them */
190 for (i
= 0; i
< m
->n_containers
; i
++)
191 GET_CONTAINER(m
, i
)->rta_len
+= message_length
- offset
;
193 /* fill in the attribute */
194 rta
->rta_type
= type
;
195 rta
->rta_len
= rta_length
;
197 /* we don't deal with the case where the user lies about the type
198 * and gives us too little data (so don't do that)
200 padding
= mempcpy(RTA_DATA(rta
), data
, data_length
);
202 /* if no data was passed, make sure we still initialize the padding
203 note that we can have data_length > 0 (used by some containers) */
204 padding
= RTA_DATA(rta
);
207 /* make sure also the padding at the end of the message is initialized */
208 padding_length
= (uint8_t*)m
->hdr
+ message_length
- (uint8_t*)padding
;
209 memzero(padding
, padding_length
);
211 /* update message size */
212 m
->hdr
->nlmsg_len
= message_length
;
217 static int message_attribute_has_type(sd_netlink_message
*m
, uint16_t attribute_type
, uint16_t data_type
) {
221 r
= type_system_get_type(m
->container_type_system
[m
->n_containers
], &type
, attribute_type
);
225 if (type
->type
!= data_type
)
231 int sd_netlink_message_append_string(sd_netlink_message
*m
, unsigned short 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
, type
, NLA_STRING
);
246 length
= strnlen(data
, size
+1);
250 length
= strlen(data
);
252 r
= add_rtattr(m
, type
, data
, length
+ 1);
259 int sd_netlink_message_append_u8(sd_netlink_message
*m
, unsigned short type
, uint8_t data
) {
262 assert_return(m
, -EINVAL
);
263 assert_return(!m
->sealed
, -EPERM
);
265 r
= message_attribute_has_type(m
, type
, NLA_U8
);
269 r
= add_rtattr(m
, type
, &data
, sizeof(uint8_t));
277 int sd_netlink_message_append_u16(sd_netlink_message
*m
, unsigned short type
, uint16_t data
) {
280 assert_return(m
, -EINVAL
);
281 assert_return(!m
->sealed
, -EPERM
);
283 r
= message_attribute_has_type(m
, type
, NLA_U16
);
287 r
= add_rtattr(m
, type
, &data
, sizeof(uint16_t));
294 int sd_netlink_message_append_u32(sd_netlink_message
*m
, unsigned short type
, uint32_t data
) {
297 assert_return(m
, -EINVAL
);
298 assert_return(!m
->sealed
, -EPERM
);
300 r
= message_attribute_has_type(m
, type
, NLA_U32
);
304 r
= add_rtattr(m
, type
, &data
, sizeof(uint32_t));
311 int sd_netlink_message_append_in_addr(sd_netlink_message
*m
, unsigned short type
, const struct in_addr
*data
) {
314 assert_return(m
, -EINVAL
);
315 assert_return(!m
->sealed
, -EPERM
);
316 assert_return(data
, -EINVAL
);
318 r
= message_attribute_has_type(m
, type
, NLA_IN_ADDR
);
322 r
= add_rtattr(m
, type
, data
, sizeof(struct in_addr
));
329 int sd_netlink_message_append_in6_addr(sd_netlink_message
*m
, unsigned short type
, const struct in6_addr
*data
) {
332 assert_return(m
, -EINVAL
);
333 assert_return(!m
->sealed
, -EPERM
);
334 assert_return(data
, -EINVAL
);
336 r
= message_attribute_has_type(m
, type
, NLA_IN_ADDR
);
340 r
= add_rtattr(m
, type
, data
, sizeof(struct in6_addr
));
347 int sd_netlink_message_append_ether_addr(sd_netlink_message
*m
, unsigned short type
, const struct ether_addr
*data
) {
350 assert_return(m
, -EINVAL
);
351 assert_return(!m
->sealed
, -EPERM
);
352 assert_return(data
, -EINVAL
);
354 r
= message_attribute_has_type(m
, type
, NLA_ETHER_ADDR
);
358 r
= add_rtattr(m
, type
, data
, ETH_ALEN
);
365 int sd_netlink_message_append_cache_info(sd_netlink_message
*m
, unsigned short type
, const struct ifa_cacheinfo
*info
) {
368 assert_return(m
, -EINVAL
);
369 assert_return(!m
->sealed
, -EPERM
);
370 assert_return(info
, -EINVAL
);
372 r
= message_attribute_has_type(m
, type
, NLA_CACHE_INFO
);
376 r
= add_rtattr(m
, type
, info
, sizeof(struct ifa_cacheinfo
));
383 int sd_netlink_message_open_container(sd_netlink_message
*m
, unsigned short type
) {
387 assert_return(m
, -EINVAL
);
388 assert_return(!m
->sealed
, -EPERM
);
389 assert_return(m
->n_containers
< RTNL_CONTAINER_DEPTH
, -ERANGE
);
391 r
= message_attribute_has_type(m
, type
, NLA_NESTED
);
393 const NLTypeSystemUnion
*type_system_union
;
396 r
= message_attribute_has_type(m
, type
, NLA_UNION
);
401 r
= sd_rtnl_message_get_family(m
, &family
);
405 r
= type_system_get_type_system_union(m
->container_type_system
[m
->n_containers
], &type_system_union
, type
);
409 r
= type_system_union_protocol_get_type_system(type_system_union
,
410 &m
->container_type_system
[m
->n_containers
+ 1],
417 r
= type_system_get_type_system(m
->container_type_system
[m
->n_containers
],
418 &m
->container_type_system
[m
->n_containers
+ 1],
424 r
= add_rtattr(m
, type
| NLA_F_NESTED
, NULL
, size
);
428 m
->container_offsets
[m
->n_containers
++] = r
;
433 int sd_netlink_message_open_container_union(sd_netlink_message
*m
, unsigned short type
, const char *key
) {
434 const NLTypeSystemUnion
*type_system_union
;
437 assert_return(m
, -EINVAL
);
438 assert_return(!m
->sealed
, -EPERM
);
440 r
= type_system_get_type_system_union(m
->container_type_system
[m
->n_containers
], &type_system_union
, type
);
444 r
= type_system_union_get_type_system(type_system_union
,
445 &m
->container_type_system
[m
->n_containers
+ 1],
450 r
= sd_netlink_message_append_string(m
, type_system_union
->match
, key
);
454 /* do we evere need non-null size */
455 r
= add_rtattr(m
, type
, NULL
, 0);
459 m
->container_offsets
[m
->n_containers
++] = r
;
465 int sd_netlink_message_close_container(sd_netlink_message
*m
) {
466 assert_return(m
, -EINVAL
);
467 assert_return(!m
->sealed
, -EPERM
);
468 assert_return(m
->n_containers
> 0, -EINVAL
);
470 m
->container_type_system
[m
->n_containers
] = NULL
;
476 int rtnl_message_read_internal(sd_netlink_message
*m
, unsigned short type
, void **data
) {
479 assert_return(m
, -EINVAL
);
480 assert_return(m
->sealed
, -EPERM
);
481 assert_return(data
, -EINVAL
);
482 assert(m
->n_containers
<= RTNL_CONTAINER_DEPTH
);
483 assert(m
->rta_offset_tb
[m
->n_containers
]);
484 assert(type
< m
->rta_tb_size
[m
->n_containers
]);
486 if(!m
->rta_offset_tb
[m
->n_containers
][type
])
489 rta
= (struct rtattr
*)((uint8_t *) m
->hdr
+ m
->rta_offset_tb
[m
->n_containers
][type
]);
491 *data
= RTA_DATA(rta
);
493 return RTA_PAYLOAD(rta
);
496 int sd_netlink_message_read_string(sd_netlink_message
*m
, unsigned short type
, const char **data
) {
500 assert_return(m
, -EINVAL
);
502 r
= message_attribute_has_type(m
, type
, NLA_STRING
);
506 r
= rtnl_message_read_internal(m
, type
, &attr_data
);
509 else if (strnlen(attr_data
, r
) >= (size_t) r
)
513 *data
= (const char *) attr_data
;
518 int sd_netlink_message_read_u8(sd_netlink_message
*m
, unsigned short type
, uint8_t *data
) {
522 assert_return(m
, -EINVAL
);
524 r
= message_attribute_has_type(m
, type
, NLA_U8
);
528 r
= rtnl_message_read_internal(m
, type
, &attr_data
);
531 else if ((size_t) r
< sizeof(uint8_t))
535 *data
= *(uint8_t *) attr_data
;
540 int sd_netlink_message_read_u16(sd_netlink_message
*m
, unsigned short type
, uint16_t *data
) {
544 assert_return(m
, -EINVAL
);
546 r
= message_attribute_has_type(m
, type
, NLA_U16
);
550 r
= rtnl_message_read_internal(m
, type
, &attr_data
);
553 else if ((size_t) r
< sizeof(uint16_t))
557 *data
= *(uint16_t *) attr_data
;
562 int sd_netlink_message_read_u32(sd_netlink_message
*m
, unsigned short type
, uint32_t *data
) {
566 assert_return(m
, -EINVAL
);
568 r
= message_attribute_has_type(m
, type
, NLA_U32
);
572 r
= rtnl_message_read_internal(m
, type
, &attr_data
);
575 else if ((size_t)r
< sizeof(uint32_t))
579 *data
= *(uint32_t *) attr_data
;
584 int sd_netlink_message_read_ether_addr(sd_netlink_message
*m
, unsigned short type
, struct ether_addr
*data
) {
588 assert_return(m
, -EINVAL
);
590 r
= message_attribute_has_type(m
, type
, NLA_ETHER_ADDR
);
594 r
= rtnl_message_read_internal(m
, type
, &attr_data
);
597 else if ((size_t)r
< sizeof(struct ether_addr
))
601 memcpy(data
, attr_data
, sizeof(struct ether_addr
));
606 int sd_netlink_message_read_cache_info(sd_netlink_message
*m
, unsigned short type
, struct ifa_cacheinfo
*info
) {
610 assert_return(m
, -EINVAL
);
612 r
= message_attribute_has_type(m
, type
, NLA_CACHE_INFO
);
616 r
= rtnl_message_read_internal(m
, type
, &attr_data
);
619 else if ((size_t)r
< sizeof(struct ifa_cacheinfo
))
623 memcpy(info
, attr_data
, sizeof(struct ifa_cacheinfo
));
628 int sd_netlink_message_read_in_addr(sd_netlink_message
*m
, unsigned short type
, struct in_addr
*data
) {
632 assert_return(m
, -EINVAL
);
634 r
= message_attribute_has_type(m
, type
, NLA_IN_ADDR
);
638 r
= rtnl_message_read_internal(m
, type
, &attr_data
);
641 else if ((size_t)r
< sizeof(struct in_addr
))
645 memcpy(data
, attr_data
, sizeof(struct in_addr
));
650 int sd_netlink_message_read_in6_addr(sd_netlink_message
*m
, unsigned short type
, struct in6_addr
*data
) {
654 assert_return(m
, -EINVAL
);
656 r
= message_attribute_has_type(m
, type
, NLA_IN_ADDR
);
660 r
= rtnl_message_read_internal(m
, type
, &attr_data
);
663 else if ((size_t)r
< sizeof(struct in6_addr
))
667 memcpy(data
, attr_data
, sizeof(struct in6_addr
));
672 int sd_netlink_message_enter_container(sd_netlink_message
*m
, unsigned short type
) {
673 const NLType
*nl_type
;
674 const NLTypeSystem
*type_system
;
679 assert_return(m
, -EINVAL
);
680 assert_return(m
->n_containers
< RTNL_CONTAINER_DEPTH
, -EINVAL
);
682 r
= type_system_get_type(m
->container_type_system
[m
->n_containers
],
688 if (nl_type
->type
== NLA_NESTED
) {
689 r
= type_system_get_type_system(m
->container_type_system
[m
->n_containers
],
694 } else if (nl_type
->type
== NLA_UNION
) {
695 const NLTypeSystemUnion
*type_system_union
;
697 r
= type_system_get_type_system_union(m
->container_type_system
[m
->n_containers
],
703 switch (type_system_union
->match_type
) {
704 case NL_MATCH_SIBLING
:
708 r
= sd_netlink_message_read_string(m
, type_system_union
->match
, &key
);
712 r
= type_system_union_get_type_system(type_system_union
,
720 case NL_MATCH_PROTOCOL
:
724 r
= sd_rtnl_message_get_family(m
, &family
);
728 r
= type_system_union_protocol_get_type_system(type_system_union
,
737 assert_not_reached("sd-netlink: invalid type system union type");
742 r
= rtnl_message_read_internal(m
, type
, &container
);
750 r
= rtnl_message_parse(m
,
751 &m
->rta_offset_tb
[m
->n_containers
],
752 &m
->rta_tb_size
[m
->n_containers
],
761 m
->container_type_system
[m
->n_containers
] = type_system
;
766 int sd_netlink_message_exit_container(sd_netlink_message
*m
) {
767 assert_return(m
, -EINVAL
);
768 assert_return(m
->sealed
, -EINVAL
);
769 assert_return(m
->n_containers
> 0, -EINVAL
);
771 free(m
->rta_offset_tb
[m
->n_containers
]);
772 m
->rta_offset_tb
[m
->n_containers
] = NULL
;
773 m
->container_type_system
[m
->n_containers
] = NULL
;
780 uint32_t rtnl_message_get_serial(sd_netlink_message
*m
) {
784 return m
->hdr
->nlmsg_seq
;
787 int sd_netlink_message_is_error(sd_netlink_message
*m
) {
789 assert_return(m
->hdr
, 0);
791 return m
->hdr
->nlmsg_type
== NLMSG_ERROR
;
794 int sd_netlink_message_get_errno(sd_netlink_message
*m
) {
795 struct nlmsgerr
*err
;
797 assert_return(m
, -EINVAL
);
798 assert_return(m
->hdr
, -EINVAL
);
800 if (!sd_netlink_message_is_error(m
))
803 err
= NLMSG_DATA(m
->hdr
);
808 int rtnl_message_parse(sd_netlink_message
*m
,
809 size_t **rta_offset_tb
,
810 unsigned short *rta_tb_size
,
813 unsigned int rt_len
) {
817 tb
= new0(size_t, max
+ 1);
821 *rta_tb_size
= max
+ 1;
823 for (; RTA_OK(rta
, rt_len
); rta
= RTA_NEXT(rta
, rt_len
)) {
824 type
= RTA_TYPE(rta
);
826 /* if the kernel is newer than the headers we used
827 when building, we ignore out-of-range attributes
833 log_debug("rtnl: message parse - overwriting repeated attribute");
835 tb
[type
] = (uint8_t *) rta
- (uint8_t *) m
->hdr
;
843 int sd_netlink_message_rewind(sd_netlink_message
*m
) {
848 assert_return(m
, -EINVAL
);
850 /* don't allow appending to message once parsed */
852 rtnl_message_seal(m
);
854 for (i
= 1; i
<= m
->n_containers
; i
++) {
855 free(m
->rta_offset_tb
[i
]);
856 m
->rta_offset_tb
[i
] = NULL
;
857 m
->rta_tb_size
[i
] = 0;
858 m
->container_type_system
[i
] = NULL
;
863 if (m
->rta_offset_tb
[0]) {
864 /* top-level attributes have already been parsed */
870 r
= type_system_get_type(NULL
, &type
, m
->hdr
->nlmsg_type
);
874 if (type
->type
== NLA_NESTED
) {
875 const NLTypeSystem
*type_system
= type
->type_system
;
879 m
->container_type_system
[0] = type_system
;
881 r
= rtnl_message_parse(m
,
882 &m
->rta_offset_tb
[m
->n_containers
],
883 &m
->rta_tb_size
[m
->n_containers
],
885 (struct rtattr
*)((uint8_t*)NLMSG_DATA(m
->hdr
) +
886 NLMSG_ALIGN(type
->size
)),
887 NLMSG_PAYLOAD(m
->hdr
, type
->size
));
895 void rtnl_message_seal(sd_netlink_message
*m
) {
902 sd_netlink_message
*sd_netlink_message_next(sd_netlink_message
*m
) {
903 assert_return(m
, NULL
);