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>
23 #include <netinet/ether.h>
26 #include <linux/netlink.h>
27 #include <linux/veth.h>
30 #include <linux/if_tunnel.h>
31 #include <linux/if_bridge.h>
38 #include "rtnl-util.h"
39 #include "rtnl-internal.h"
40 #include "rtnl-types.h"
42 #define GET_CONTAINER(m, i) ((i) < (m)->n_containers ? (struct rtattr*)((uint8_t*)(m)->hdr + (m)->container_offsets[i]) : NULL)
43 #define PUSH_CONTAINER(m, new) (m)->container_offsets[(m)->n_containers ++] = (uint8_t*)(new) - (uint8_t*)(m)->hdr;
45 static int message_new_empty(sd_rtnl *rtnl, sd_rtnl_message **ret, size_t initial_size) {
48 assert_return(ret, -EINVAL);
49 assert_return(initial_size >= sizeof(struct nlmsghdr), -EINVAL);
51 /* Note that 'rtnl' is curretly unused, if we start using it internally
52 we must take care to avoid problems due to mutual references between
53 busses and their queued messages. See sd-bus.
56 m = new0(sd_rtnl_message, 1);
60 m->hdr = malloc0(initial_size);
66 m->n_ref = REFCNT_INIT;
68 m->hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
76 int message_new(sd_rtnl *rtnl, sd_rtnl_message **ret, uint16_t type) {
77 const NLType *nl_type;
81 r = type_system_get_type(NULL, &nl_type, type);
85 assert(nl_type->type == NLA_NESTED);
87 size = NLMSG_SPACE(nl_type->size);
89 r = message_new_empty(rtnl, ret, size);
93 (*ret)->container_type_system[0] = nl_type->type_system;
94 (*ret)->hdr->nlmsg_len = size;
95 (*ret)->hdr->nlmsg_type = type;
100 int sd_rtnl_message_route_set_dst_prefixlen(sd_rtnl_message *m, unsigned char prefixlen) {
103 assert_return(m, -EINVAL);
104 assert_return(m->hdr, -EINVAL);
105 assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
107 rtm = NLMSG_DATA(m->hdr);
109 if ((rtm->rtm_family == AF_INET && prefixlen > 32) ||
110 (rtm->rtm_family == AF_INET6 && prefixlen > 128))
113 rtm->rtm_dst_len = prefixlen;
118 int sd_rtnl_message_route_set_scope(sd_rtnl_message *m, unsigned char scope) {
121 assert_return(m, -EINVAL);
122 assert_return(m->hdr, -EINVAL);
123 assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
125 rtm = NLMSG_DATA(m->hdr);
127 rtm->rtm_scope = scope;
132 int sd_rtnl_message_new_route(sd_rtnl *rtnl, sd_rtnl_message **ret,
133 uint16_t nlmsg_type, unsigned char rtm_family) {
137 assert_return(rtnl_message_type_is_route(nlmsg_type), -EINVAL);
138 assert_return(rtm_family == AF_INET || rtm_family == AF_INET6, -EINVAL);
139 assert_return(ret, -EINVAL);
141 r = message_new(rtnl, ret, nlmsg_type);
145 if (nlmsg_type == RTM_NEWROUTE)
146 (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
148 rtm = NLMSG_DATA((*ret)->hdr);
150 rtm->rtm_family = rtm_family;
151 rtm->rtm_scope = RT_SCOPE_UNIVERSE;
152 rtm->rtm_type = RTN_UNICAST;
153 rtm->rtm_table = RT_TABLE_MAIN;
154 rtm->rtm_protocol = RTPROT_BOOT;
159 int sd_rtnl_message_link_set_flags(sd_rtnl_message *m, unsigned flags, unsigned change) {
160 struct ifinfomsg *ifi;
162 assert_return(m, -EINVAL);
163 assert_return(m->hdr, -EINVAL);
164 assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
165 assert_return(change, -EINVAL);
167 ifi = NLMSG_DATA(m->hdr);
169 ifi->ifi_flags = flags;
170 ifi->ifi_change = change;
175 int sd_rtnl_message_link_set_type(sd_rtnl_message *m, unsigned type) {
176 struct ifinfomsg *ifi;
178 assert_return(m, -EINVAL);
179 assert_return(m->hdr, -EINVAL);
180 assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
182 ifi = NLMSG_DATA(m->hdr);
184 ifi->ifi_type = type;
189 int sd_rtnl_message_new_link(sd_rtnl *rtnl, sd_rtnl_message **ret,
190 uint16_t nlmsg_type, int index) {
191 struct ifinfomsg *ifi;
194 assert_return(rtnl_message_type_is_link(nlmsg_type), -EINVAL);
195 assert_return(nlmsg_type != RTM_DELLINK || index > 0, -EINVAL);
196 assert_return(ret, -EINVAL);
198 r = message_new(rtnl, ret, nlmsg_type);
202 if (nlmsg_type == RTM_NEWLINK)
203 (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
205 ifi = NLMSG_DATA((*ret)->hdr);
207 ifi->ifi_family = AF_UNSPEC;
208 ifi->ifi_index = index;
213 int sd_rtnl_message_addr_set_prefixlen(sd_rtnl_message *m, unsigned char prefixlen) {
214 struct ifaddrmsg *ifa;
216 assert_return(m, -EINVAL);
217 assert_return(m->hdr, -EINVAL);
218 assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
220 ifa = NLMSG_DATA(m->hdr);
222 if ((ifa->ifa_family == AF_INET && prefixlen > 32) ||
223 (ifa->ifa_family == AF_INET6 && prefixlen > 128))
226 ifa->ifa_prefixlen = prefixlen;
231 int sd_rtnl_message_addr_set_flags(sd_rtnl_message *m, unsigned char flags) {
232 struct ifaddrmsg *ifa;
234 assert_return(m, -EINVAL);
235 assert_return(m->hdr, -EINVAL);
236 assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
238 ifa = NLMSG_DATA(m->hdr);
240 ifa->ifa_flags = flags;
245 int sd_rtnl_message_addr_set_scope(sd_rtnl_message *m, unsigned char scope) {
246 struct ifaddrmsg *ifa;
248 assert_return(m, -EINVAL);
249 assert_return(m->hdr, -EINVAL);
250 assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
252 ifa = NLMSG_DATA(m->hdr);
254 ifa->ifa_scope = scope;
259 int sd_rtnl_message_new_addr(sd_rtnl *rtnl, sd_rtnl_message **ret,
260 uint16_t nlmsg_type, int index,
261 unsigned char family) {
262 struct ifaddrmsg *ifa;
265 assert_return(rtnl_message_type_is_addr(nlmsg_type), -EINVAL);
266 assert_return(index > 0, -EINVAL);
267 assert_return(family == AF_INET || family == AF_INET6, -EINVAL);
268 assert_return(ret, -EINVAL);
270 r = message_new(rtnl, ret, nlmsg_type);
274 if (nlmsg_type == RTM_GETADDR && family == AF_INET)
275 (*ret)->hdr->nlmsg_flags |= NLM_F_DUMP;
277 ifa = NLMSG_DATA((*ret)->hdr);
279 ifa->ifa_index = index;
280 ifa->ifa_family = family;
281 if (family == AF_INET)
282 ifa->ifa_prefixlen = 32;
283 else if (family == AF_INET6)
284 ifa->ifa_prefixlen = 128;
289 int sd_rtnl_message_new_addr_update(sd_rtnl *rtnl, sd_rtnl_message **ret,
290 int index, unsigned char family) {
293 r = sd_rtnl_message_new_addr(rtnl, ret, RTM_NEWADDR, index, family);
297 (*ret)->hdr->nlmsg_flags |= NLM_F_REPLACE;
302 sd_rtnl_message *sd_rtnl_message_ref(sd_rtnl_message *m) {
304 assert_se(REFCNT_INC(m->n_ref) >= 2);
309 sd_rtnl_message *sd_rtnl_message_unref(sd_rtnl_message *m) {
310 if (m && REFCNT_DEC(m->n_ref) <= 0) {
315 for (i = 0; i <= m->n_containers; i++)
316 free(m->rta_offset_tb[i]);
324 int sd_rtnl_message_get_type(sd_rtnl_message *m, uint16_t *type) {
325 assert_return(m, -EINVAL);
326 assert_return(type, -EINVAL);
328 *type = m->hdr->nlmsg_type;
333 int sd_rtnl_message_is_broadcast(sd_rtnl_message *m) {
334 assert_return(m, -EINVAL);
336 return !m->hdr->nlmsg_pid;
339 int sd_rtnl_message_link_get_ifindex(sd_rtnl_message *m, int *ifindex) {
340 struct ifinfomsg *ifi;
342 assert_return(m, -EINVAL);
343 assert_return(m->hdr, -EINVAL);
344 assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
345 assert_return(ifindex, -EINVAL);
347 ifi = NLMSG_DATA(m->hdr);
349 *ifindex = ifi->ifi_index;
354 int sd_rtnl_message_link_get_flags(sd_rtnl_message *m, unsigned *flags) {
355 struct ifinfomsg *ifi;
357 assert_return(m, -EINVAL);
358 assert_return(m->hdr, -EINVAL);
359 assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
360 assert_return(flags, -EINVAL);
362 ifi = NLMSG_DATA(m->hdr);
364 *flags = ifi->ifi_flags;
369 /* If successful the updated message will be correctly aligned, if
370 unsuccessful the old message is untouched. */
371 static int add_rtattr(sd_rtnl_message *m, unsigned short type, const void *data, size_t data_length) {
372 uint32_t rta_length, message_length;
373 struct nlmsghdr *new_hdr;
381 assert(NLMSG_ALIGN(m->hdr->nlmsg_len) == m->hdr->nlmsg_len);
382 assert(!data || data_length > 0);
383 assert(data || m->n_containers < RTNL_CONTAINER_DEPTH);
385 /* get the size of the new rta attribute (with padding at the end) */
386 rta_length = RTA_LENGTH(data_length);
388 /* get the new message size (with padding at the end) */
389 message_length = m->hdr->nlmsg_len + RTA_ALIGN(rta_length);
391 /* realloc to fit the new attribute */
392 new_hdr = realloc(m->hdr, message_length);
397 /* get pointer to the attribute we are about to add */
398 rta = (struct rtattr *) ((uint8_t *) m->hdr + m->hdr->nlmsg_len);
400 /* if we are inside containers, extend them */
401 for (i = 0; i < m->n_containers; i++)
402 GET_CONTAINER(m, i)->rta_len += message_length - m->hdr->nlmsg_len;
404 /* fill in the attribute */
405 rta->rta_type = type;
406 rta->rta_len = rta_length;
408 //TODO: simply return this value rather than check for !data
409 /* this is the start of a new container */
410 m->container_offsets[m->n_containers ++] = m->hdr->nlmsg_len;
412 /* we don't deal with the case where the user lies about the type
413 * and gives us too little data (so don't do that)
415 padding = mempcpy(RTA_DATA(rta), data, data_length);
416 /* make sure also the padding at the end of the message is initialized */
418 (uint8_t *) m->hdr + message_length - (uint8_t *) padding);
421 /* update message size */
422 m->hdr->nlmsg_len = message_length;
427 static int message_attribute_has_type(sd_rtnl_message *m, uint16_t attribute_type, uint16_t data_type) {
431 r = type_system_get_type(m->container_type_system[m->n_containers], &type, attribute_type);
435 if (type->type != data_type)
441 int sd_rtnl_message_append_string(sd_rtnl_message *m, unsigned short type, const char *data) {
445 assert_return(m, -EINVAL);
446 assert_return(!m->sealed, -EPERM);
447 assert_return(data, -EINVAL);
449 r = message_attribute_has_type(m, type, NLA_STRING);
456 length = strnlen(data, size);
460 length = strlen(data);
462 r = add_rtattr(m, type, data, length + 1);
469 int sd_rtnl_message_append_u8(sd_rtnl_message *m, unsigned short type, uint8_t data) {
472 assert_return(m, -EINVAL);
473 assert_return(!m->sealed, -EPERM);
475 r = message_attribute_has_type(m, type, NLA_U8);
479 r = add_rtattr(m, type, &data, sizeof(uint8_t));
487 int sd_rtnl_message_append_u16(sd_rtnl_message *m, unsigned short type, uint16_t data) {
490 assert_return(m, -EINVAL);
491 assert_return(!m->sealed, -EPERM);
493 r = message_attribute_has_type(m, type, NLA_U16);
497 r = add_rtattr(m, type, &data, sizeof(uint16_t));
504 int sd_rtnl_message_append_u32(sd_rtnl_message *m, unsigned short type, uint32_t data) {
507 assert_return(m, -EINVAL);
508 assert_return(!m->sealed, -EPERM);
510 r = message_attribute_has_type(m, type, NLA_U32);
514 r = add_rtattr(m, type, &data, sizeof(uint32_t));
521 int sd_rtnl_message_append_in_addr(sd_rtnl_message *m, unsigned short type, const struct in_addr *data) {
524 assert_return(m, -EINVAL);
525 assert_return(!m->sealed, -EPERM);
526 assert_return(data, -EINVAL);
528 r = message_attribute_has_type(m, type, NLA_IN_ADDR);
532 r = add_rtattr(m, type, data, sizeof(struct in_addr));
539 int sd_rtnl_message_append_in6_addr(sd_rtnl_message *m, unsigned short type, const struct in6_addr *data) {
542 assert_return(m, -EINVAL);
543 assert_return(!m->sealed, -EPERM);
544 assert_return(data, -EINVAL);
546 r = message_attribute_has_type(m, type, NLA_IN_ADDR);
550 r = add_rtattr(m, type, data, sizeof(struct in6_addr));
557 int sd_rtnl_message_append_ether_addr(sd_rtnl_message *m, unsigned short type, const struct ether_addr *data) {
560 assert_return(m, -EINVAL);
561 assert_return(!m->sealed, -EPERM);
562 assert_return(data, -EINVAL);
564 r = message_attribute_has_type(m, type, NLA_ETHER_ADDR);
568 r = add_rtattr(m, type, data, ETH_ALEN);
575 int sd_rtnl_message_append_cache_info(sd_rtnl_message *m, unsigned short type, const struct ifa_cacheinfo *info) {
578 assert_return(m, -EINVAL);
579 assert_return(!m->sealed, -EPERM);
580 assert_return(info, -EINVAL);
582 r = message_attribute_has_type(m, type, NLA_CACHE_INFO);
586 r = add_rtattr(m, type, info, sizeof(struct ifa_cacheinfo));
593 int sd_rtnl_message_open_container(sd_rtnl_message *m, unsigned short type) {
597 assert_return(m, -EINVAL);
598 assert_return(!m->sealed, -EPERM);
600 r = message_attribute_has_type(m, type, NLA_NESTED);
606 r = type_system_get_type_system(m->container_type_system[m->n_containers],
607 &m->container_type_system[m->n_containers + 1],
612 r = add_rtattr(m, type, NULL, size);
619 int sd_rtnl_message_open_container_union(sd_rtnl_message *m, unsigned short type, const char *key) {
620 const NLTypeSystemUnion *type_system_union;
623 assert_return(m, -EINVAL);
624 assert_return(!m->sealed, -EPERM);
626 r = type_system_get_type_system_union(m->container_type_system[m->n_containers], &type_system_union, type);
630 r = type_system_union_get_type_system(type_system_union,
631 &m->container_type_system[m->n_containers + 1],
636 r = sd_rtnl_message_append_string(m, type_system_union->match, key);
640 /* do we evere need non-null size */
641 r = add_rtattr(m, type, NULL, 0);
649 int sd_rtnl_message_close_container(sd_rtnl_message *m) {
650 assert_return(m, -EINVAL);
651 assert_return(!m->sealed, -EPERM);
652 assert_return(m->n_containers > 0, -EINVAL);
654 m->container_type_system[m->n_containers] = NULL;
660 int rtnl_message_read_internal(sd_rtnl_message *m, unsigned short type, void **data) {
663 assert_return(m, -EINVAL);
664 assert_return(m->sealed, -EPERM);
665 assert_return(data, -EINVAL);
666 assert(m->n_containers <= RTNL_CONTAINER_DEPTH);
667 assert(m->rta_offset_tb[m->n_containers]);
668 assert(type < m->rta_tb_size[m->n_containers]);
670 if(!m->rta_offset_tb[m->n_containers][type])
673 rta = (struct rtattr*)((uint8_t *) m->hdr + m->rta_offset_tb[m->n_containers][type]);
675 *data = RTA_DATA(rta);
677 return RTA_PAYLOAD(rta);
680 int sd_rtnl_message_read_string(sd_rtnl_message *m, unsigned short type, char **data) {
684 r = message_attribute_has_type(m, type, NLA_STRING);
688 r = rtnl_message_read_internal(m, type, &attr_data);
691 else if (strnlen(attr_data, r) >= (size_t) r)
694 *data = (char *) attr_data;
699 int sd_rtnl_message_read_u8(sd_rtnl_message *m, unsigned short type, uint8_t *data) {
703 r = message_attribute_has_type(m, type, NLA_U8);
707 r = rtnl_message_read_internal(m, type, &attr_data);
710 else if ((size_t) r < sizeof(uint8_t))
713 *data = *(uint8_t *) attr_data;
718 int sd_rtnl_message_read_u16(sd_rtnl_message *m, unsigned short type, uint16_t *data) {
722 r = message_attribute_has_type(m, type, NLA_U16);
726 r = rtnl_message_read_internal(m, type, &attr_data);
729 else if ((size_t) r < sizeof(uint16_t))
732 *data = *(uint16_t *) attr_data;
737 int sd_rtnl_message_read_u32(sd_rtnl_message *m, unsigned short type, uint32_t *data) {
741 r = message_attribute_has_type(m, type, NLA_U32);
745 r = rtnl_message_read_internal(m, type, &attr_data);
748 else if ((size_t)r < sizeof(uint32_t))
751 *data = *(uint32_t *) attr_data;
756 int sd_rtnl_message_read_ether_addr(sd_rtnl_message *m, unsigned short type, struct ether_addr *data) {
760 r = message_attribute_has_type(m, type, NLA_ETHER_ADDR);
764 r = rtnl_message_read_internal(m, type, &attr_data);
767 else if ((size_t)r < sizeof(struct ether_addr))
770 memcpy(data, attr_data, sizeof(struct ether_addr));
775 int sd_rtnl_message_read_cache_info(sd_rtnl_message *m, unsigned short type, struct ifa_cacheinfo *info) {
779 r = message_attribute_has_type(m, type, NLA_CACHE_INFO);
783 r = rtnl_message_read_internal(m, type, &attr_data);
786 else if ((size_t)r < sizeof(struct ifa_cacheinfo))
789 memcpy(info, attr_data, sizeof(struct ifa_cacheinfo));
794 int sd_rtnl_message_read_in_addr(sd_rtnl_message *m, unsigned short type, struct in_addr *data) {
798 r = message_attribute_has_type(m, type, NLA_IN_ADDR);
802 r = rtnl_message_read_internal(m, type, &attr_data);
805 else if ((size_t)r < sizeof(struct in_addr))
808 memcpy(data, attr_data, sizeof(struct in_addr));
813 int sd_rtnl_message_read_in6_addr(sd_rtnl_message *m, unsigned short type, struct in6_addr *data) {
817 r = message_attribute_has_type(m, type, NLA_IN_ADDR);
821 r = rtnl_message_read_internal(m, type, &attr_data);
824 else if ((size_t)r < sizeof(struct in6_addr))
827 memcpy(data, attr_data, sizeof(struct in6_addr));
832 int sd_rtnl_message_enter_container(sd_rtnl_message *m, unsigned short type) {
833 const NLType *nl_type;
834 const NLTypeSystem *type_system;
839 assert_return(m, -EINVAL);
840 assert_return(m->n_containers < RTNL_CONTAINER_DEPTH, -EINVAL);
842 r = type_system_get_type(m->container_type_system[m->n_containers],
848 if (nl_type->type == NLA_NESTED) {
849 r = type_system_get_type_system(m->container_type_system[m->n_containers],
854 } else if (nl_type->type == NLA_UNION) {
855 const NLTypeSystemUnion *type_system_union;
858 r = type_system_get_type_system_union(m->container_type_system[m->n_containers],
864 r = sd_rtnl_message_read_string(m, type_system_union->match, &key);
868 r = type_system_union_get_type_system(type_system_union,
876 r = rtnl_message_read_internal(m, type, &container);
884 r = rtnl_message_parse(m,
885 &m->rta_offset_tb[m->n_containers],
886 &m->rta_tb_size[m->n_containers],
895 m->container_type_system[m->n_containers] = type_system;
900 int sd_rtnl_message_exit_container(sd_rtnl_message *m) {
901 assert_return(m, -EINVAL);
902 assert_return(m->sealed, -EINVAL);
903 assert_return(m->n_containers > 0, -EINVAL);
905 free(m->rta_offset_tb[m->n_containers]);
906 m->rta_offset_tb[m->n_containers] = NULL;
907 m->container_type_system[m->n_containers] = NULL;
914 uint32_t rtnl_message_get_serial(sd_rtnl_message *m) {
918 return m->hdr->nlmsg_seq;
921 int sd_rtnl_message_get_errno(sd_rtnl_message *m) {
922 struct nlmsgerr *err;
924 assert_return(m, -EINVAL);
925 assert_return(m->hdr, -EINVAL);
927 if (m->hdr->nlmsg_type != NLMSG_ERROR)
930 err = NLMSG_DATA(m->hdr);
935 static int message_receive_need(sd_rtnl *rtnl, size_t *need) {
939 /* ioctl(rtnl->fd, FIONREAD, &need)
940 Does not appear to work on netlink sockets. libnl uses
941 MSG_PEEK instead. I don't know if that is worth the
944 For now we simply use the maximum message size the kernel
945 may use (NLMSG_GOODSIZE), and then realloc to the actual
946 size after reading the message (hence avoiding huge memory
947 usage in case many small messages are kept around) */
955 int rtnl_message_parse(sd_rtnl_message *m,
956 size_t **rta_offset_tb,
957 unsigned short *rta_tb_size,
960 unsigned int rt_len) {
964 tb = new0(size_t, max + 1);
968 *rta_tb_size = max + 1;
970 for (; RTA_OK(rta, rt_len); rta = RTA_NEXT(rta, rt_len)) {
971 type = rta->rta_type;
973 /* if the kernel is newer than the headers we used
974 when building, we ignore out-of-range attributes
980 log_debug("rtnl: message parse - overwriting repeated attribute");
982 tb[type] = (uint8_t *) rta - (uint8_t *) m->hdr;
990 /* returns the number of bytes sent, or a negative error code */
991 int socket_write_message(sd_rtnl *nl, sd_rtnl_message *m) {
994 struct sockaddr_nl nl;
996 .nl.nl_family = AF_NETLINK,
1004 k = sendto(nl->fd, m->hdr, m->hdr->nlmsg_len,
1005 0, &addr.sa, sizeof(addr));
1007 return (errno == EAGAIN) ? 0 : -errno;
1012 /* On success, the number of bytes received is returned and *ret points to the received message
1013 * which has a valid header and the correct size.
1014 * If nothing useful was received 0 is returned.
1015 * On failure, a negative error code is returned.
1017 int socket_read_message(sd_rtnl *nl, sd_rtnl_message **ret) {
1018 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
1019 const NLType *nl_type;
1020 struct nlmsghdr *new_hdr;
1023 struct sockaddr_nl nl;
1032 r = message_receive_need(nl, &need);
1036 r = message_new_empty(nl, &m, need);
1040 addr_len = sizeof(addr);
1042 r = recvfrom(nl->fd, m->hdr, need,
1043 0, &addr.sa, &addr_len);
1045 return (errno == EAGAIN) ? 0 : -errno; /* no data */
1047 return -ECONNRESET; /* connection was closed by the kernel */
1048 else if (addr_len != sizeof(addr.nl) ||
1049 addr.nl.nl_family != AF_NETLINK)
1050 return -EIO; /* not a netlink message */
1051 else if (addr.nl.nl_pid != 0)
1052 return 0; /* not from the kernel */
1053 else if ((size_t) r < sizeof(struct nlmsghdr) ||
1054 (size_t) r < m->hdr->nlmsg_len)
1055 return -EIO; /* too small (we do accept too big though) */
1056 else if (m->hdr->nlmsg_pid && m->hdr->nlmsg_pid != nl->sockaddr.nl.nl_pid)
1057 return 0; /* not broadcast and not for us */
1061 /* silently drop noop messages */
1062 if (m->hdr->nlmsg_type == NLMSG_NOOP)
1065 /* check that we support this message type */
1066 r = type_system_get_type(NULL, &nl_type, m->hdr->nlmsg_type);
1069 log_debug("sd-rtnl: ignored message with unknown type: %u",
1070 m->hdr->nlmsg_type);
1075 /* check that the size matches the message type */
1076 if (len < NLMSG_LENGTH(nl_type->size))
1079 /* we probably allocated way too much memory, give it back */
1080 new_hdr = realloc(m->hdr, len);
1085 /* seal and parse the top-level message */
1086 r = sd_rtnl_message_rewind(m);
1096 int sd_rtnl_message_rewind(sd_rtnl_message *m) {
1101 assert_return(m, -EINVAL);
1103 /* don't allow appending to message once parsed */
1105 rtnl_message_seal(m);
1107 for (i = 1; i <= m->n_containers; i++) {
1108 free(m->rta_offset_tb[i]);
1109 m->rta_offset_tb[i] = NULL;
1110 m->rta_tb_size[i] = 0;
1111 m->container_type_system[i] = NULL;
1114 m->n_containers = 0;
1116 if (m->rta_offset_tb[0]) {
1117 /* top-level attributes have already been parsed */
1123 r = type_system_get_type(NULL, &type, m->hdr->nlmsg_type);
1127 if (type->type == NLA_NESTED) {
1128 const NLTypeSystem *type_system = type->type_system;
1130 assert(type_system);
1132 m->container_type_system[0] = type_system;
1134 r = rtnl_message_parse(m,
1135 &m->rta_offset_tb[m->n_containers],
1136 &m->rta_tb_size[m->n_containers],
1138 (struct rtattr*)((uint8_t*)NLMSG_DATA(m->hdr) +
1139 NLMSG_ALIGN(type->size)),
1140 NLMSG_PAYLOAD(m->hdr, type->size));
1148 void rtnl_message_seal(sd_rtnl_message *m) {