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(&type_system_root, &nl_type, type);
75 if (type_get_type(nl_type) != NETLINK_TYPE_NESTED)
78 r = message_new_empty(rtnl, &m);
82 size = NLMSG_SPACE(type_get_size(nl_type));
84 assert(size >= sizeof(struct nlmsghdr));
85 m->hdr = malloc0(size);
89 m->hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
91 type_get_type_system(nl_type, &m->container_type_system[0]);
92 m->hdr->nlmsg_len = size;
93 m->hdr->nlmsg_type = type;
101 int sd_netlink_message_request_dump(sd_netlink_message *m, int dump) {
102 assert_return(m, -EINVAL);
103 assert_return(m->hdr, -EINVAL);
104 assert_return(m->hdr->nlmsg_type == RTM_GETLINK ||
105 m->hdr->nlmsg_type == RTM_GETADDR ||
106 m->hdr->nlmsg_type == RTM_GETROUTE ||
107 m->hdr->nlmsg_type == RTM_GETNEIGH,
111 m->hdr->nlmsg_flags |= NLM_F_DUMP;
113 m->hdr->nlmsg_flags &= ~NLM_F_DUMP;
118 sd_netlink_message *sd_netlink_message_ref(sd_netlink_message *m) {
120 assert_se(REFCNT_INC(m->n_ref) >= 2);
125 sd_netlink_message *sd_netlink_message_unref(sd_netlink_message *m) {
126 if (m && REFCNT_DEC(m->n_ref) == 0) {
131 for (i = 0; i <= m->n_containers; i++)
132 free(m->rta_offset_tb[i]);
134 sd_netlink_message_unref(m->next);
142 int sd_netlink_message_get_type(sd_netlink_message *m, uint16_t *type) {
143 assert_return(m, -EINVAL);
144 assert_return(type, -EINVAL);
146 *type = m->hdr->nlmsg_type;
151 int sd_netlink_message_is_broadcast(sd_netlink_message *m) {
152 assert_return(m, -EINVAL);
157 /* If successful the updated message will be correctly aligned, if
158 unsuccessful the old message is untouched. */
159 static int add_rtattr(sd_netlink_message *m, unsigned short type, const void *data, size_t data_length) {
161 size_t message_length, padding_length;
162 struct nlmsghdr *new_hdr;
171 assert(NLMSG_ALIGN(m->hdr->nlmsg_len) == m->hdr->nlmsg_len);
172 assert(!data || data_length);
174 /* get offset of the new attribute */
175 offset = m->hdr->nlmsg_len;
177 /* get the size of the new rta attribute (with padding at the end) */
178 rta_length = RTA_LENGTH(data_length);
180 /* get the new message size (with padding at the end) */
181 message_length = offset + RTA_ALIGN(rta_length);
183 /* realloc to fit the new attribute */
184 new_hdr = realloc(m->hdr, message_length);
189 /* get pointer to the attribute we are about to add */
190 rta = (struct rtattr *) ((uint8_t *) m->hdr + offset);
192 /* if we are inside containers, extend them */
193 for (i = 0; i < m->n_containers; i++)
194 GET_CONTAINER(m, i)->rta_len += message_length - offset;
196 /* fill in the attribute */
197 rta->rta_type = type;
198 rta->rta_len = rta_length;
200 /* we don't deal with the case where the user lies about the type
201 * and gives us too little data (so don't do that)
203 padding = mempcpy(RTA_DATA(rta), data, data_length);
205 /* if no data was passed, make sure we still initialize the padding
206 note that we can have data_length > 0 (used by some containers) */
207 padding = RTA_DATA(rta);
210 /* make sure also the padding at the end of the message is initialized */
211 padding_length = (uint8_t*)m->hdr + message_length - (uint8_t*)padding;
212 memzero(padding, padding_length);
214 /* update message size */
215 m->hdr->nlmsg_len = message_length;
220 static int message_attribute_has_type(sd_netlink_message *m, size_t *out_size, uint16_t attribute_type, uint16_t data_type) {
226 r = type_system_get_type(m->container_type_system[m->n_containers], &type, attribute_type);
230 if (type_get_type(type) != data_type)
234 *out_size = type_get_size(type);
238 int sd_netlink_message_append_string(sd_netlink_message *m, unsigned short type, const char *data) {
242 assert_return(m, -EINVAL);
243 assert_return(!m->sealed, -EPERM);
244 assert_return(data, -EINVAL);
246 r = message_attribute_has_type(m, &size, type, NETLINK_TYPE_STRING);
251 length = strnlen(data, size+1);
255 length = strlen(data);
257 r = add_rtattr(m, type, data, length + 1);
264 int sd_netlink_message_append_flag(sd_netlink_message *m, unsigned short type) {
268 assert_return(m, -EINVAL);
269 assert_return(!m->sealed, -EPERM);
271 r = message_attribute_has_type(m, &size, type, NETLINK_TYPE_FLAG);
275 r = add_rtattr(m, type, NULL, 0);
282 int sd_netlink_message_append_u8(sd_netlink_message *m, unsigned short type, uint8_t data) {
285 assert_return(m, -EINVAL);
286 assert_return(!m->sealed, -EPERM);
288 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U8);
292 r = add_rtattr(m, type, &data, sizeof(uint8_t));
300 int sd_netlink_message_append_u16(sd_netlink_message *m, unsigned short type, uint16_t data) {
303 assert_return(m, -EINVAL);
304 assert_return(!m->sealed, -EPERM);
306 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U16);
310 r = add_rtattr(m, type, &data, sizeof(uint16_t));
317 int sd_netlink_message_append_u32(sd_netlink_message *m, unsigned short type, uint32_t data) {
320 assert_return(m, -EINVAL);
321 assert_return(!m->sealed, -EPERM);
323 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U32);
327 r = add_rtattr(m, type, &data, sizeof(uint32_t));
334 int sd_netlink_message_append_in_addr(sd_netlink_message *m, unsigned short type, const struct in_addr *data) {
337 assert_return(m, -EINVAL);
338 assert_return(!m->sealed, -EPERM);
339 assert_return(data, -EINVAL);
341 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_IN_ADDR);
345 r = add_rtattr(m, type, data, sizeof(struct in_addr));
352 int sd_netlink_message_append_in6_addr(sd_netlink_message *m, unsigned short type, const struct in6_addr *data) {
355 assert_return(m, -EINVAL);
356 assert_return(!m->sealed, -EPERM);
357 assert_return(data, -EINVAL);
359 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_IN_ADDR);
363 r = add_rtattr(m, type, data, sizeof(struct in6_addr));
370 int sd_netlink_message_append_ether_addr(sd_netlink_message *m, unsigned short type, const struct ether_addr *data) {
373 assert_return(m, -EINVAL);
374 assert_return(!m->sealed, -EPERM);
375 assert_return(data, -EINVAL);
377 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_ETHER_ADDR);
381 r = add_rtattr(m, type, data, ETH_ALEN);
388 int sd_netlink_message_append_cache_info(sd_netlink_message *m, unsigned short type, const struct ifa_cacheinfo *info) {
391 assert_return(m, -EINVAL);
392 assert_return(!m->sealed, -EPERM);
393 assert_return(info, -EINVAL);
395 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_CACHE_INFO);
399 r = add_rtattr(m, type, info, sizeof(struct ifa_cacheinfo));
406 int sd_netlink_message_open_container(sd_netlink_message *m, unsigned short type) {
410 assert_return(m, -EINVAL);
411 assert_return(!m->sealed, -EPERM);
412 assert_return(m->n_containers < RTNL_CONTAINER_DEPTH, -ERANGE);
414 r = message_attribute_has_type(m, &size, type, NETLINK_TYPE_NESTED);
416 const NLTypeSystemUnion *type_system_union;
419 r = message_attribute_has_type(m, &size, type, NETLINK_TYPE_UNION);
423 r = sd_rtnl_message_get_family(m, &family);
427 r = type_system_get_type_system_union(m->container_type_system[m->n_containers], &type_system_union, type);
431 r = type_system_union_protocol_get_type_system(type_system_union,
432 &m->container_type_system[m->n_containers + 1],
437 r = type_system_get_type_system(m->container_type_system[m->n_containers],
438 &m->container_type_system[m->n_containers + 1],
444 r = add_rtattr(m, type | NLA_F_NESTED, NULL, size);
448 m->container_offsets[m->n_containers ++] = r;
453 int sd_netlink_message_open_container_union(sd_netlink_message *m, unsigned short type, const char *key) {
454 const NLTypeSystemUnion *type_system_union;
457 assert_return(m, -EINVAL);
458 assert_return(!m->sealed, -EPERM);
460 r = type_system_get_type_system_union(m->container_type_system[m->n_containers], &type_system_union, type);
464 r = type_system_union_get_type_system(type_system_union,
465 &m->container_type_system[m->n_containers + 1],
470 r = sd_netlink_message_append_string(m, type_system_union->match, key);
474 /* do we evere need non-null size */
475 r = add_rtattr(m, type | NLA_F_NESTED, NULL, 0);
479 m->container_offsets[m->n_containers ++] = r;
485 int sd_netlink_message_close_container(sd_netlink_message *m) {
486 assert_return(m, -EINVAL);
487 assert_return(!m->sealed, -EPERM);
488 assert_return(m->n_containers > 0, -EINVAL);
490 m->container_type_system[m->n_containers] = NULL;
496 static int netlink_message_read_internal(sd_netlink_message *m, unsigned short type, void **data) {
499 assert_return(m, -EINVAL);
500 assert_return(m->sealed, -EPERM);
501 assert_return(data, -EINVAL);
502 assert(m->n_containers <= RTNL_CONTAINER_DEPTH);
503 assert(m->rta_offset_tb[m->n_containers]);
504 assert(type < m->rta_tb_size[m->n_containers]);
506 if(!m->rta_offset_tb[m->n_containers][type])
509 rta = (struct rtattr*)((uint8_t *) m->hdr + m->rta_offset_tb[m->n_containers][type]);
511 *data = RTA_DATA(rta);
513 return RTA_PAYLOAD(rta);
516 int sd_netlink_message_read_string(sd_netlink_message *m, unsigned short type, const char **data) {
520 assert_return(m, -EINVAL);
522 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_STRING);
526 r = netlink_message_read_internal(m, type, &attr_data);
529 else if (strnlen(attr_data, r) >= (size_t) r)
533 *data = (const char *) attr_data;
538 int sd_netlink_message_read_u8(sd_netlink_message *m, unsigned short type, uint8_t *data) {
542 assert_return(m, -EINVAL);
544 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U8);
548 r = netlink_message_read_internal(m, type, &attr_data);
551 else if ((size_t) r < sizeof(uint8_t))
555 *data = *(uint8_t *) attr_data;
560 int sd_netlink_message_read_u16(sd_netlink_message *m, unsigned short type, uint16_t *data) {
564 assert_return(m, -EINVAL);
566 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U16);
570 r = netlink_message_read_internal(m, type, &attr_data);
573 else if ((size_t) r < sizeof(uint16_t))
577 *data = *(uint16_t *) attr_data;
582 int sd_netlink_message_read_u32(sd_netlink_message *m, unsigned short type, uint32_t *data) {
586 assert_return(m, -EINVAL);
588 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U32);
592 r = netlink_message_read_internal(m, type, &attr_data);
595 else if ((size_t)r < sizeof(uint32_t))
599 *data = *(uint32_t *) attr_data;
604 int sd_netlink_message_read_ether_addr(sd_netlink_message *m, unsigned short type, struct ether_addr *data) {
608 assert_return(m, -EINVAL);
610 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_ETHER_ADDR);
614 r = netlink_message_read_internal(m, type, &attr_data);
617 else if ((size_t)r < sizeof(struct ether_addr))
621 memcpy(data, attr_data, sizeof(struct ether_addr));
626 int sd_netlink_message_read_cache_info(sd_netlink_message *m, unsigned short type, struct ifa_cacheinfo *info) {
630 assert_return(m, -EINVAL);
632 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_CACHE_INFO);
636 r = netlink_message_read_internal(m, type, &attr_data);
639 else if ((size_t)r < sizeof(struct ifa_cacheinfo))
643 memcpy(info, attr_data, sizeof(struct ifa_cacheinfo));
648 int sd_netlink_message_read_in_addr(sd_netlink_message *m, unsigned short type, struct in_addr *data) {
652 assert_return(m, -EINVAL);
654 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_IN_ADDR);
658 r = netlink_message_read_internal(m, type, &attr_data);
661 else if ((size_t)r < sizeof(struct in_addr))
665 memcpy(data, attr_data, sizeof(struct in_addr));
670 int sd_netlink_message_read_in6_addr(sd_netlink_message *m, unsigned short type, struct in6_addr *data) {
674 assert_return(m, -EINVAL);
676 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_IN_ADDR);
680 r = netlink_message_read_internal(m, type, &attr_data);
683 else if ((size_t)r < sizeof(struct in6_addr))
687 memcpy(data, attr_data, sizeof(struct in6_addr));
692 static int netlink_message_parse(sd_netlink_message *m,
693 size_t **rta_offset_tb,
694 unsigned short *rta_tb_size,
697 unsigned int rt_len) {
701 tb = new0(size_t, count);
705 *rta_tb_size = count;
707 for (; RTA_OK(rta, rt_len); rta = RTA_NEXT(rta, rt_len)) {
708 type = RTA_TYPE(rta);
710 /* if the kernel is newer than the headers we used
711 when building, we ignore out-of-range attributes
717 log_debug("rtnl: message parse - overwriting repeated attribute");
719 tb[type] = (uint8_t *) rta - (uint8_t *) m->hdr;
727 int sd_netlink_message_enter_container(sd_netlink_message *m, unsigned short type_id) {
728 const NLType *nl_type;
729 const NLTypeSystem *type_system;
735 assert_return(m, -EINVAL);
736 assert_return(m->n_containers < RTNL_CONTAINER_DEPTH, -EINVAL);
738 r = type_system_get_type(m->container_type_system[m->n_containers],
744 type = type_get_type(nl_type);
746 if (type == NETLINK_TYPE_NESTED) {
747 r = type_system_get_type_system(m->container_type_system[m->n_containers],
752 } else if (type == NETLINK_TYPE_UNION) {
753 const NLTypeSystemUnion *type_system_union;
755 r = type_system_get_type_system_union(m->container_type_system[m->n_containers],
761 switch (type_system_union->match_type) {
762 case NL_MATCH_SIBLING:
766 r = sd_netlink_message_read_string(m, type_system_union->match, &key);
770 r = type_system_union_get_type_system(type_system_union,
778 case NL_MATCH_PROTOCOL:
782 r = sd_rtnl_message_get_family(m, &family);
786 r = type_system_union_protocol_get_type_system(type_system_union,
795 assert_not_reached("sd-netlink: invalid type system union type");
800 r = netlink_message_read_internal(m, type_id, &container);
808 r = netlink_message_parse(m,
809 &m->rta_offset_tb[m->n_containers],
810 &m->rta_tb_size[m->n_containers],
811 type_system_get_count(type_system),
819 m->container_type_system[m->n_containers] = type_system;
824 int sd_netlink_message_exit_container(sd_netlink_message *m) {
825 assert_return(m, -EINVAL);
826 assert_return(m->sealed, -EINVAL);
827 assert_return(m->n_containers > 0, -EINVAL);
829 free(m->rta_offset_tb[m->n_containers]);
830 m->rta_offset_tb[m->n_containers] = NULL;
831 m->container_type_system[m->n_containers] = NULL;
838 uint32_t rtnl_message_get_serial(sd_netlink_message *m) {
842 return m->hdr->nlmsg_seq;
845 int sd_netlink_message_is_error(sd_netlink_message *m) {
847 assert_return(m->hdr, 0);
849 return m->hdr->nlmsg_type == NLMSG_ERROR;
852 int sd_netlink_message_get_errno(sd_netlink_message *m) {
853 struct nlmsgerr *err;
855 assert_return(m, -EINVAL);
856 assert_return(m->hdr, -EINVAL);
858 if (!sd_netlink_message_is_error(m))
861 err = NLMSG_DATA(m->hdr);
866 int sd_netlink_message_rewind(sd_netlink_message *m) {
867 const NLType *nl_type;
873 assert_return(m, -EINVAL);
875 /* don't allow appending to message once parsed */
877 rtnl_message_seal(m);
879 for (i = 1; i <= m->n_containers; i++) {
880 free(m->rta_offset_tb[i]);
881 m->rta_offset_tb[i] = NULL;
882 m->rta_tb_size[i] = 0;
883 m->container_type_system[i] = NULL;
888 if (m->rta_offset_tb[0]) {
889 /* top-level attributes have already been parsed */
895 r = type_system_get_type(&type_system_root, &nl_type, m->hdr->nlmsg_type);
899 type = type_get_type(nl_type);
900 size = type_get_size(nl_type);
902 if (type == NETLINK_TYPE_NESTED) {
903 const NLTypeSystem *type_system;
905 type_get_type_system(nl_type, &type_system);
907 m->container_type_system[0] = type_system;
909 r = netlink_message_parse(m,
910 &m->rta_offset_tb[m->n_containers],
911 &m->rta_tb_size[m->n_containers],
912 type_system_get_count(type_system),
913 (struct rtattr*)((uint8_t*)NLMSG_DATA(m->hdr) + NLMSG_ALIGN(size)),
914 NLMSG_PAYLOAD(m->hdr, size));
922 void rtnl_message_seal(sd_netlink_message *m) {
929 sd_netlink_message *sd_netlink_message_next(sd_netlink_message *m) {
930 assert_return(m, NULL);