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(type_get_size(nl_type));
81 assert(size >= sizeof(struct nlmsghdr));
82 m->hdr = malloc0(size);
86 m->hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
88 if (type_get_type(nl_type) == NETLINK_TYPE_NESTED)
89 type_get_type_system(nl_type, &m->container_type_system[0]);
90 m->hdr->nlmsg_len = size;
91 m->hdr->nlmsg_type = type;
99 int sd_netlink_message_request_dump(sd_netlink_message *m, int dump) {
100 assert_return(m, -EINVAL);
101 assert_return(m->hdr, -EINVAL);
102 assert_return(m->hdr->nlmsg_type == RTM_GETLINK ||
103 m->hdr->nlmsg_type == RTM_GETADDR ||
104 m->hdr->nlmsg_type == RTM_GETROUTE ||
105 m->hdr->nlmsg_type == RTM_GETNEIGH,
109 m->hdr->nlmsg_flags |= NLM_F_DUMP;
111 m->hdr->nlmsg_flags &= ~NLM_F_DUMP;
116 sd_netlink_message *sd_netlink_message_ref(sd_netlink_message *m) {
118 assert_se(REFCNT_INC(m->n_ref) >= 2);
123 sd_netlink_message *sd_netlink_message_unref(sd_netlink_message *m) {
124 if (m && REFCNT_DEC(m->n_ref) == 0) {
129 for (i = 0; i <= m->n_containers; i++)
130 free(m->rta_offset_tb[i]);
132 sd_netlink_message_unref(m->next);
140 int sd_netlink_message_get_type(sd_netlink_message *m, uint16_t *type) {
141 assert_return(m, -EINVAL);
142 assert_return(type, -EINVAL);
144 *type = m->hdr->nlmsg_type;
149 int sd_netlink_message_is_broadcast(sd_netlink_message *m) {
150 assert_return(m, -EINVAL);
155 /* If successful the updated message will be correctly aligned, if
156 unsuccessful the old message is untouched. */
157 static int add_rtattr(sd_netlink_message *m, unsigned short type, const void *data, size_t data_length) {
159 size_t message_length, padding_length;
160 struct nlmsghdr *new_hdr;
169 assert(NLMSG_ALIGN(m->hdr->nlmsg_len) == m->hdr->nlmsg_len);
170 assert(!data || data_length);
172 /* get offset of the new attribute */
173 offset = m->hdr->nlmsg_len;
175 /* get the size of the new rta attribute (with padding at the end) */
176 rta_length = RTA_LENGTH(data_length);
178 /* get the new message size (with padding at the end) */
179 message_length = offset + RTA_ALIGN(rta_length);
181 /* realloc to fit the new attribute */
182 new_hdr = realloc(m->hdr, message_length);
187 /* get pointer to the attribute we are about to add */
188 rta = (struct rtattr *) ((uint8_t *) m->hdr + offset);
190 /* if we are inside containers, extend them */
191 for (i = 0; i < m->n_containers; i++)
192 GET_CONTAINER(m, i)->rta_len += message_length - offset;
194 /* fill in the attribute */
195 rta->rta_type = type;
196 rta->rta_len = rta_length;
198 /* we don't deal with the case where the user lies about the type
199 * and gives us too little data (so don't do that)
201 padding = mempcpy(RTA_DATA(rta), data, data_length);
203 /* if no data was passed, make sure we still initialize the padding
204 note that we can have data_length > 0 (used by some containers) */
205 padding = RTA_DATA(rta);
208 /* make sure also the padding at the end of the message is initialized */
209 padding_length = (uint8_t*)m->hdr + message_length - (uint8_t*)padding;
210 memzero(padding, padding_length);
212 /* update message size */
213 m->hdr->nlmsg_len = message_length;
218 static int message_attribute_has_type(sd_netlink_message *m, size_t *out_size, uint16_t attribute_type, uint16_t data_type) {
224 r = type_system_get_type(m->container_type_system[m->n_containers], &type, attribute_type);
228 if (type_get_type(type) != data_type)
232 *out_size = type_get_size(type);
236 int sd_netlink_message_append_string(sd_netlink_message *m, unsigned short type, const char *data) {
240 assert_return(m, -EINVAL);
241 assert_return(!m->sealed, -EPERM);
242 assert_return(data, -EINVAL);
244 r = message_attribute_has_type(m, &size, type, NETLINK_TYPE_STRING);
249 length = strnlen(data, size+1);
253 length = strlen(data);
255 r = add_rtattr(m, type, data, length + 1);
262 int sd_netlink_message_append_u8(sd_netlink_message *m, unsigned short type, uint8_t data) {
265 assert_return(m, -EINVAL);
266 assert_return(!m->sealed, -EPERM);
268 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U8);
272 r = add_rtattr(m, type, &data, sizeof(uint8_t));
280 int sd_netlink_message_append_u16(sd_netlink_message *m, unsigned short type, uint16_t data) {
283 assert_return(m, -EINVAL);
284 assert_return(!m->sealed, -EPERM);
286 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U16);
290 r = add_rtattr(m, type, &data, sizeof(uint16_t));
297 int sd_netlink_message_append_u32(sd_netlink_message *m, unsigned short type, uint32_t data) {
300 assert_return(m, -EINVAL);
301 assert_return(!m->sealed, -EPERM);
303 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U32);
307 r = add_rtattr(m, type, &data, sizeof(uint32_t));
314 int sd_netlink_message_append_in_addr(sd_netlink_message *m, unsigned short type, const struct in_addr *data) {
317 assert_return(m, -EINVAL);
318 assert_return(!m->sealed, -EPERM);
319 assert_return(data, -EINVAL);
321 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_IN_ADDR);
325 r = add_rtattr(m, type, data, sizeof(struct in_addr));
332 int sd_netlink_message_append_in6_addr(sd_netlink_message *m, unsigned short type, const struct in6_addr *data) {
335 assert_return(m, -EINVAL);
336 assert_return(!m->sealed, -EPERM);
337 assert_return(data, -EINVAL);
339 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_IN_ADDR);
343 r = add_rtattr(m, type, data, sizeof(struct in6_addr));
350 int sd_netlink_message_append_ether_addr(sd_netlink_message *m, unsigned short type, const struct ether_addr *data) {
353 assert_return(m, -EINVAL);
354 assert_return(!m->sealed, -EPERM);
355 assert_return(data, -EINVAL);
357 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_ETHER_ADDR);
361 r = add_rtattr(m, type, data, ETH_ALEN);
368 int sd_netlink_message_append_cache_info(sd_netlink_message *m, unsigned short type, const struct ifa_cacheinfo *info) {
371 assert_return(m, -EINVAL);
372 assert_return(!m->sealed, -EPERM);
373 assert_return(info, -EINVAL);
375 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_CACHE_INFO);
379 r = add_rtattr(m, type, info, sizeof(struct ifa_cacheinfo));
386 int sd_netlink_message_open_container(sd_netlink_message *m, unsigned short type) {
390 assert_return(m, -EINVAL);
391 assert_return(!m->sealed, -EPERM);
392 assert_return(m->n_containers < RTNL_CONTAINER_DEPTH, -ERANGE);
394 r = message_attribute_has_type(m, &size, type, NETLINK_TYPE_NESTED);
396 const NLTypeSystemUnion *type_system_union;
399 r = message_attribute_has_type(m, &size, type, NETLINK_TYPE_UNION);
403 r = sd_rtnl_message_get_family(m, &family);
407 r = type_system_get_type_system_union(m->container_type_system[m->n_containers], &type_system_union, type);
411 r = type_system_union_protocol_get_type_system(type_system_union,
412 &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, NULL, type, NETLINK_TYPE_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, NULL, type, NETLINK_TYPE_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, NULL, type, NETLINK_TYPE_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, NULL, type, NETLINK_TYPE_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, NULL, type, NETLINK_TYPE_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, NULL, type, NETLINK_TYPE_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, NULL, type, NETLINK_TYPE_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, NULL, type, NETLINK_TYPE_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_id) {
673 const NLType *nl_type;
674 const NLTypeSystem *type_system;
680 assert_return(m, -EINVAL);
681 assert_return(m->n_containers < RTNL_CONTAINER_DEPTH, -EINVAL);
683 r = type_system_get_type(m->container_type_system[m->n_containers],
689 type = type_get_type(nl_type);
691 if (type == NETLINK_TYPE_NESTED) {
692 r = type_system_get_type_system(m->container_type_system[m->n_containers],
697 } else if (type == NETLINK_TYPE_UNION) {
698 const NLTypeSystemUnion *type_system_union;
700 r = type_system_get_type_system_union(m->container_type_system[m->n_containers],
706 switch (type_system_union->match_type) {
707 case NL_MATCH_SIBLING:
711 r = sd_netlink_message_read_string(m, type_system_union->match, &key);
715 r = type_system_union_get_type_system(type_system_union,
723 case NL_MATCH_PROTOCOL:
727 r = sd_rtnl_message_get_family(m, &family);
731 r = type_system_union_protocol_get_type_system(type_system_union,
740 assert_not_reached("sd-netlink: invalid type system union type");
745 r = rtnl_message_read_internal(m, type_id, &container);
753 r = rtnl_message_parse(m,
754 &m->rta_offset_tb[m->n_containers],
755 &m->rta_tb_size[m->n_containers],
756 type_system_get_count(type_system),
764 m->container_type_system[m->n_containers] = type_system;
769 int sd_netlink_message_exit_container(sd_netlink_message *m) {
770 assert_return(m, -EINVAL);
771 assert_return(m->sealed, -EINVAL);
772 assert_return(m->n_containers > 0, -EINVAL);
774 free(m->rta_offset_tb[m->n_containers]);
775 m->rta_offset_tb[m->n_containers] = NULL;
776 m->container_type_system[m->n_containers] = NULL;
783 uint32_t rtnl_message_get_serial(sd_netlink_message *m) {
787 return m->hdr->nlmsg_seq;
790 int sd_netlink_message_is_error(sd_netlink_message *m) {
792 assert_return(m->hdr, 0);
794 return m->hdr->nlmsg_type == NLMSG_ERROR;
797 int sd_netlink_message_get_errno(sd_netlink_message *m) {
798 struct nlmsgerr *err;
800 assert_return(m, -EINVAL);
801 assert_return(m->hdr, -EINVAL);
803 if (!sd_netlink_message_is_error(m))
806 err = NLMSG_DATA(m->hdr);
811 int rtnl_message_parse(sd_netlink_message *m,
812 size_t **rta_offset_tb,
813 unsigned short *rta_tb_size,
816 unsigned int rt_len) {
820 tb = new0(size_t, count);
824 *rta_tb_size = count;
826 for (; RTA_OK(rta, rt_len); rta = RTA_NEXT(rta, rt_len)) {
827 type = RTA_TYPE(rta);
829 /* if the kernel is newer than the headers we used
830 when building, we ignore out-of-range attributes
836 log_debug("rtnl: message parse - overwriting repeated attribute");
838 tb[type] = (uint8_t *) rta - (uint8_t *) m->hdr;
846 int sd_netlink_message_rewind(sd_netlink_message *m) {
847 const NLType *nl_type;
853 assert_return(m, -EINVAL);
855 /* don't allow appending to message once parsed */
857 rtnl_message_seal(m);
859 for (i = 1; i <= m->n_containers; i++) {
860 free(m->rta_offset_tb[i]);
861 m->rta_offset_tb[i] = NULL;
862 m->rta_tb_size[i] = 0;
863 m->container_type_system[i] = NULL;
868 if (m->rta_offset_tb[0]) {
869 /* top-level attributes have already been parsed */
875 r = type_system_get_type(NULL, &nl_type, m->hdr->nlmsg_type);
879 type = type_get_type(nl_type);
880 size = type_get_size(nl_type);
882 if (type == NETLINK_TYPE_NESTED) {
883 const NLTypeSystem *type_system;
885 type_get_type_system(nl_type, &type_system);
887 m->container_type_system[0] = type_system;
889 r = rtnl_message_parse(m,
890 &m->rta_offset_tb[m->n_containers],
891 &m->rta_tb_size[m->n_containers],
892 type_system_get_count(type_system),
893 (struct rtattr*)((uint8_t*)NLMSG_DATA(m->hdr) + NLMSG_ALIGN(size)),
894 NLMSG_PAYLOAD(m->hdr, size));
902 void rtnl_message_seal(sd_netlink_message *m) {
909 sd_netlink_message *sd_netlink_message_next(sd_netlink_message *m) {
910 assert_return(m, NULL);