chiark / gitweb /
af8f8cf76286c03502889b7406ca2602b37a3b23
[elogind.git] / src / libsystemd / sd-rtnl / rtnl-message.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2013 Tom Gundersen <teg@jklm.no>
7
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.
12
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.
17
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/>.
20 ***/
21
22 #include <linux/rtnetlink.h>
23 #include <netinet/in.h>
24 #include <netinet/ether.h>
25 #include <stdbool.h>
26 #include <unistd.h>
27
28 #include "util.h"
29 #include "refcnt.h"
30
31 #include "sd-rtnl.h"
32 #include "rtnl-internal.h"
33
34 struct sd_rtnl_message {
35         RefCount n_ref;
36
37         struct nlmsghdr *hdr;
38         size_t container_offset; /* offset from hdr to container start */
39         size_t next_rta_offset; /* offset from hdr to next rta */
40
41         bool sealed:1;
42 };
43
44 #define CURRENT_CONTAINER(m) ((m)->container_offset ? (struct rtattr*)((uint8_t*)(m)->hdr + (m)->container_offset) : NULL)
45 #define NEXT_RTA(m) ((struct rtattr*)((uint8_t*)(m)->hdr + (m)->next_rta_offset))
46 #define UPDATE_RTA(m, new) (m)->next_rta_offset = (uint8_t*)(new) - (uint8_t*)(m)->hdr;
47
48 static int message_new(sd_rtnl_message **ret, size_t initial_size) {
49         sd_rtnl_message *m;
50
51         assert_return(ret, -EINVAL);
52         assert_return(initial_size >= sizeof(struct nlmsghdr), -EINVAL);
53
54         m = new0(sd_rtnl_message, 1);
55         if (!m)
56                 return -ENOMEM;
57
58         m->hdr = malloc0(initial_size);
59         if (!m->hdr) {
60                 free(m);
61                 return -ENOMEM;
62         }
63
64         m->n_ref = REFCNT_INIT;
65
66         m->hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
67         m->sealed = false;
68
69         *ret = m;
70
71         return 0;
72 }
73
74 int message_new_synthetic_error(int error, uint32_t serial, sd_rtnl_message **ret) {
75         struct nlmsgerr *err;
76         int r;
77
78         assert(error <= 0);
79
80         r = message_new(ret, NLMSG_SPACE(sizeof(struct nlmsgerr)));
81         if (r < 0)
82                 return r;
83
84         (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr));
85         (*ret)->hdr->nlmsg_type = NLMSG_ERROR;
86         (*ret)->hdr->nlmsg_seq = serial;
87
88         err = NLMSG_DATA((*ret)->hdr);
89
90         err->error = error;
91
92         return 0;
93 }
94
95 bool message_type_is_route(uint16_t type) {
96         switch (type) {
97                 case RTM_NEWROUTE:
98                 case RTM_GETROUTE:
99                 case RTM_DELROUTE:
100                         return true;
101                 default:
102                         return false;
103         }
104 }
105
106 bool message_type_is_link(uint16_t type) {
107         switch (type) {
108                 case RTM_NEWLINK:
109                 case RTM_SETLINK:
110                 case RTM_GETLINK:
111                 case RTM_DELLINK:
112                         return true;
113                 default:
114                         return false;
115         }
116 }
117
118 bool message_type_is_addr(uint16_t type) {
119         switch (type) {
120                 case RTM_NEWADDR:
121                 case RTM_GETADDR:
122                 case RTM_DELADDR:
123                         return true;
124                 default:
125                         return false;
126         }
127 }
128
129 int sd_rtnl_message_route_set_dst_prefixlen(sd_rtnl_message *m, unsigned char prefixlen) {
130         struct rtmsg *rtm;
131
132         rtm = NLMSG_DATA(m->hdr);
133
134         rtm->rtm_dst_len = prefixlen;
135
136         return 0;
137 }
138
139 int sd_rtnl_message_route_new(uint16_t nlmsg_type, unsigned char rtm_family,
140                               sd_rtnl_message **ret) {
141         struct rtmsg *rtm;
142         int r;
143
144         assert_return(message_type_is_route(nlmsg_type), -EINVAL);
145         assert_return(rtm_family == AF_INET || rtm_family == AF_INET6, -EINVAL);
146         assert_return(ret, -EINVAL);
147
148         r = message_new(ret, NLMSG_SPACE(sizeof(struct rtmsg)));
149         if (r < 0)
150                 return r;
151
152         (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
153         (*ret)->hdr->nlmsg_type = nlmsg_type;
154         if (nlmsg_type == RTM_NEWROUTE)
155                 (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
156
157         rtm = NLMSG_DATA((*ret)->hdr);
158
159         UPDATE_RTA(*ret, RTM_RTA(rtm));
160
161         rtm->rtm_family = rtm_family;
162         rtm->rtm_scope = RT_SCOPE_UNIVERSE;
163         rtm->rtm_type = RTN_UNICAST;
164         rtm->rtm_table = RT_TABLE_MAIN;
165         rtm->rtm_protocol = RTPROT_BOOT;
166
167         return 0;
168 }
169
170 int sd_rtnl_message_link_set_flags(sd_rtnl_message *m, unsigned flags, unsigned change) {
171         struct ifinfomsg *ifi;
172
173         ifi = NLMSG_DATA(m->hdr);
174
175         ifi->ifi_flags = flags;
176         if (change)
177                 ifi->ifi_change = change;
178         else
179                 ifi->ifi_change = 0xffffffff;
180
181         return 0;
182 }
183
184 int sd_rtnl_message_link_set_type(sd_rtnl_message *m, unsigned type) {
185         struct ifinfomsg *ifi;
186
187         ifi = NLMSG_DATA(m->hdr);
188
189         ifi->ifi_type = type;
190
191         return 0;
192 }
193
194 int sd_rtnl_message_link_new(uint16_t nlmsg_type, int index, sd_rtnl_message **ret) {
195         struct ifinfomsg *ifi;
196         int r;
197
198         assert_return(message_type_is_link(nlmsg_type), -EINVAL);
199         assert_return(nlmsg_type == RTM_NEWLINK || index > 0, -EINVAL);
200         assert_return(ret, -EINVAL);
201
202         r = message_new(ret, NLMSG_SPACE(sizeof(struct ifinfomsg)));
203         if (r < 0)
204                 return r;
205
206         (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
207         (*ret)->hdr->nlmsg_type = nlmsg_type;
208         if (nlmsg_type == RTM_NEWLINK)
209                 (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE;
210
211         ifi = NLMSG_DATA((*ret)->hdr);
212
213         ifi->ifi_family = AF_UNSPEC;
214         ifi->ifi_index = index;
215
216         UPDATE_RTA(*ret, IFLA_RTA(ifi));
217
218         return 0;
219 }
220
221 int sd_rtnl_message_addr_new(uint16_t nlmsg_type, int index, unsigned char family, unsigned char prefixlen, unsigned char flags, unsigned char scope, sd_rtnl_message **ret) {
222         struct ifaddrmsg *ifa;
223         int r;
224
225         assert_return(message_type_is_addr(nlmsg_type), -EINVAL);
226         assert_return(index > 0, -EINVAL);
227         assert_return(ret, -EINVAL);
228
229         r = message_new(ret, NLMSG_SPACE(sizeof(struct ifaddrmsg)));
230         if (r < 0)
231                 return r;
232
233         (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
234         (*ret)->hdr->nlmsg_type = nlmsg_type;
235
236         ifa = NLMSG_DATA((*ret)->hdr);
237
238         ifa->ifa_family = family;
239         ifa->ifa_prefixlen = prefixlen;
240         ifa->ifa_flags = flags;
241         ifa->ifa_scope = scope;
242         ifa->ifa_index = index;
243
244         UPDATE_RTA(*ret, IFA_RTA(ifa));
245
246         return 0;
247 }
248
249 sd_rtnl_message *sd_rtnl_message_ref(sd_rtnl_message *m) {
250         if (m)
251                 assert_se(REFCNT_INC(m->n_ref) >= 2);
252
253         return m;
254 }
255
256 sd_rtnl_message *sd_rtnl_message_unref(sd_rtnl_message *m) {
257         if (m && REFCNT_DEC(m->n_ref) <= 0) {
258                 free(m->hdr);
259                 free(m);
260         }
261
262         return NULL;
263 }
264
265 int sd_rtnl_message_get_type(sd_rtnl_message *m, uint16_t *type) {
266         assert_return(m, -EINVAL);
267         assert_return(type, -EINVAL);
268
269         *type = m->hdr->nlmsg_type;
270
271         return 0;
272 }
273
274 int sd_rtnl_message_link_get_ifindex(sd_rtnl_message *m, int *ifindex) {
275         struct ifinfomsg *ifi;
276
277         assert_return(m, -EINVAL);
278         assert_return(m->hdr, -EINVAL);
279         assert_return(message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
280         assert_return(ifindex, -EINVAL);
281
282         ifi = NLMSG_DATA(m->hdr);
283
284         *ifindex = ifi->ifi_index;
285
286         return 0;
287 }
288
289 int sd_rtnl_message_link_get_flags(sd_rtnl_message *m, unsigned *flags) {
290         struct ifinfomsg *ifi;
291
292         assert_return(m, -EINVAL);
293         assert_return(m->hdr, -EINVAL);
294         assert_return(message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
295         assert_return(flags, -EINVAL);
296
297         ifi = NLMSG_DATA(m->hdr);
298
299         *flags = ifi->ifi_flags;
300
301         return 0;
302 }
303
304 /* If successful the updated message will be correctly aligned, if
305    unsuccessful the old message is untouched. */
306 static int add_rtattr(sd_rtnl_message *m, unsigned short type, const void *data, size_t data_length) {
307         uint32_t rta_length, message_length;
308         struct nlmsghdr *new_hdr;
309         struct rtattr *rta;
310         char *padding;
311
312         assert(m);
313         assert(m->hdr);
314         assert(NLMSG_ALIGN(m->hdr->nlmsg_len) == m->hdr->nlmsg_len);
315         assert(!data || data_length > 0);
316
317         /* get the size of the new rta attribute (with padding at the end) */
318         rta_length = RTA_LENGTH(data_length);
319
320         /* get the new message size (with padding at the end) */
321         message_length = m->hdr->nlmsg_len + RTA_ALIGN(rta_length);
322
323         /* realloc to fit the new attribute */
324         new_hdr = realloc(m->hdr, message_length);
325         if (!new_hdr)
326                 return -ENOMEM;
327         m->hdr = new_hdr;
328
329         /* get pointer to the attribute we are about to add */
330         rta = (struct rtattr *) ((uint8_t *) m->hdr + m->hdr->nlmsg_len);
331
332         /* if we are inside a container, extend it */
333         if (CURRENT_CONTAINER(m))
334                 CURRENT_CONTAINER(m)->rta_len += message_length - m->hdr->nlmsg_len;
335
336         /* fill in the attribute */
337         rta->rta_type = type;
338         rta->rta_len = rta_length;
339         if (!data) {
340                 /* this is the start of a new container */
341                 m->container_offset = m->hdr->nlmsg_len;
342         } else {
343                 /* we don't deal with the case where the user lies about the type
344                  * and gives us too little data (so don't do that)
345                 */
346                 padding = mempcpy(RTA_DATA(rta), data, data_length);
347                 /* make sure also the padding at the end of the message is initialized */
348                 memzero(padding,
349                         (uint8_t *) m->hdr + message_length - (uint8_t *) padding);
350         }
351
352         /* update message size */
353         m->hdr->nlmsg_len = message_length;
354
355         return 0;
356 }
357
358 int sd_rtnl_message_append_string(sd_rtnl_message *m, unsigned short type, const char *data) {
359         uint16_t rtm_type;
360         int r;
361
362         assert_return(m, -EINVAL);
363         assert_return(data, -EINVAL);
364
365         r = sd_rtnl_message_get_type(m, &rtm_type);
366         if (r < 0)
367                 return r;
368
369         /* check that the type is correct */
370         switch (rtm_type) {
371                 case RTM_NEWLINK:
372                 case RTM_SETLINK:
373                 case RTM_GETLINK:
374                 case RTM_DELLINK:
375                         if (CURRENT_CONTAINER(m)) {
376                                 if (CURRENT_CONTAINER(m)->rta_type != IFLA_LINKINFO ||
377                                     type != IFLA_INFO_KIND)
378                                         return -ENOTSUP;
379                         } else {
380                                 switch (type) {
381                                         case IFLA_IFNAME:
382                                         case IFLA_IFALIAS:
383                                         case IFLA_QDISC:
384                                                 break;
385                                         default:
386                                                 return -ENOTSUP;
387                                 }
388                         }
389                         break;
390                 case RTM_NEWADDR:
391                 case RTM_GETADDR:
392                 case RTM_DELADDR:
393                         if (type != IFA_LABEL)
394                                 return -ENOTSUP;
395                         break;
396                 default:
397                         return -ENOTSUP;
398         }
399
400         r = add_rtattr(m, type, data, strlen(data) + 1);
401         if (r < 0)
402                 return r;
403
404         return 0;
405 }
406
407 int sd_rtnl_message_append_u32(sd_rtnl_message *m, unsigned short type, uint32_t data) {
408         uint16_t rtm_type;
409         int r;
410
411         assert_return(m, -EINVAL);
412
413         r = sd_rtnl_message_get_type(m, &rtm_type);
414         if (r < 0)
415                 return r;
416
417         /* check that the type is correct */
418         switch (rtm_type) {
419                 case RTM_NEWLINK:
420                 case RTM_SETLINK:
421                 case RTM_GETLINK:
422                 case RTM_DELLINK:
423                         switch (type) {
424                                 case IFLA_MASTER:
425                                 case IFLA_MTU:
426                                 case IFLA_LINK:
427                                         break;
428                                 default:
429                                         return -ENOTSUP;
430                         }
431                         break;
432                 case RTM_NEWROUTE:
433                 case RTM_GETROUTE:
434                 case RTM_DELROUTE:
435                         switch (type) {
436                                 case RTA_TABLE:
437                                 case RTA_PRIORITY:
438                                 case RTA_IIF:
439                                 case RTA_OIF:
440                                         break;
441                                 default:
442                                         return -ENOTSUP;
443                         }
444                         break;
445                 default:
446                         return -ENOTSUP;
447         }
448
449         r = add_rtattr(m, type, &data, sizeof(uint32_t));
450         if (r < 0)
451                 return r;
452
453         return 0;
454 }
455
456 int sd_rtnl_message_append_in_addr(sd_rtnl_message *m, unsigned short type, const struct in_addr *data) {
457         struct ifaddrmsg *ifa;
458         struct rtmsg *rtm;
459         uint16_t rtm_type;
460         int r;
461
462         assert_return(m, -EINVAL);
463         assert_return(data, -EINVAL);
464
465         r = sd_rtnl_message_get_type(m, &rtm_type);
466         if (r < 0)
467                 return r;
468
469         /* check that the type is correct */
470         switch (rtm_type) {
471                 case RTM_NEWADDR:
472                 case RTM_GETADDR:
473                 case RTM_DELADDR:
474                         switch (type) {
475                                 case IFA_ADDRESS:
476                                 case IFA_LOCAL:
477                                 case IFA_BROADCAST:
478                                 case IFA_ANYCAST:
479                                         ifa = NLMSG_DATA(m->hdr);
480
481                                         if (ifa->ifa_family != AF_INET)
482                                                 return -EINVAL;
483
484                                         break;
485                                 default:
486                                         return -ENOTSUP;
487                         }
488                         break;
489                 case RTM_NEWROUTE:
490                 case RTM_GETROUTE:
491                 case RTM_DELROUTE:
492                         switch (type) {
493                                 case RTA_DST:
494                                 case RTA_SRC:
495                                 case RTA_GATEWAY:
496                                         rtm = NLMSG_DATA(m->hdr);
497
498                                         if (rtm->rtm_family != AF_INET)
499                                                 return -EINVAL;
500
501                                         break;
502                                 default:
503                                         return -ENOTSUP;
504                         }
505                         break;
506                 default:
507                         return -ENOTSUP;
508         }
509
510         r = add_rtattr(m, type, data, sizeof(struct in_addr));
511         if (r < 0)
512                 return r;
513
514         return 0;
515 }
516
517 int sd_rtnl_message_append_in6_addr(sd_rtnl_message *m, unsigned short type, const struct in6_addr *data) {
518         struct ifaddrmsg *ifa;
519         struct rtmsg *rtm;
520         uint16_t rtm_type;
521         int r;
522
523         assert_return(m, -EINVAL);
524         assert_return(data, -EINVAL);
525
526         r = sd_rtnl_message_get_type(m, &rtm_type);
527         if (r < 0)
528                 return r;
529
530         /* check that the type is correct */
531         switch (rtm_type) {
532                 case RTM_NEWADDR:
533                 case RTM_GETADDR:
534                 case RTM_DELADDR:
535                         switch (type) {
536                                 case IFA_ADDRESS:
537                                 case IFA_LOCAL:
538                                 case IFA_BROADCAST:
539                                 case IFA_ANYCAST:
540                                         ifa = NLMSG_DATA(m->hdr);
541
542                                         if (ifa->ifa_family != AF_INET6)
543                                                 return -EINVAL;
544
545                                         break;
546                                 default:
547                                         return -ENOTSUP;
548                         }
549                         break;
550                 case RTM_NEWROUTE:
551                 case RTM_GETROUTE:
552                 case RTM_DELROUTE:
553                         switch (type) {
554                                 case RTA_DST:
555                                 case RTA_SRC:
556                                 case RTA_GATEWAY:
557                                         rtm = NLMSG_DATA(m->hdr);
558
559                                         if (rtm->rtm_family != AF_INET6)
560                                                 return -EINVAL;
561
562                                         break;
563                                 default:
564                                         return -ENOTSUP;
565                         }
566                 default:
567                         return -ENOTSUP;
568         }
569
570         r = add_rtattr(m, type, data, sizeof(struct in6_addr));
571         if (r < 0)
572                 return r;
573
574         return 0;
575 }
576
577 int sd_rtnl_message_append_ether_addr(sd_rtnl_message *m, unsigned short type, const struct ether_addr *data) {
578         uint16_t rtm_type;
579         int r;
580
581         assert_return(m, -EINVAL);
582         assert_return(data, -EINVAL);
583
584         sd_rtnl_message_get_type(m, &rtm_type);
585
586         switch (rtm_type) {
587                 case RTM_NEWLINK:
588                 case RTM_SETLINK:
589                 case RTM_DELLINK:
590                 case RTM_GETLINK:
591                         switch (type) {
592                                 case IFLA_ADDRESS:
593                                 case IFLA_BROADCAST:
594                                         break;
595                                 default:
596                                         return -ENOTSUP;
597                         }
598                         break;
599                 default:
600                         return -ENOTSUP;
601         }
602
603         r = add_rtattr(m, type, data, ETH_ALEN);
604         if (r < 0)
605                 return r;
606
607         return 0;
608 }
609
610 int sd_rtnl_message_open_container(sd_rtnl_message *m, unsigned short type) {
611         uint16_t rtm_type;
612
613         assert_return(m, -EINVAL);
614         assert_return(!CURRENT_CONTAINER(m), -EINVAL);
615
616         sd_rtnl_message_get_type(m, &rtm_type);
617
618         if (message_type_is_link(rtm_type)) {
619                 if (type == IFLA_LINKINFO)
620                         return add_rtattr(m, type, NULL, 0);
621                 else
622                         return -ENOTSUP;
623         } else
624                 return -ENOTSUP;
625
626         return 0;
627 }
628
629 int sd_rtnl_message_close_container(sd_rtnl_message *m) {
630         assert_return(m, -EINVAL);
631         assert_return(CURRENT_CONTAINER(m), -EINVAL);
632
633         m->container_offset = 0;
634
635         return 0;
636 }
637
638 int sd_rtnl_message_read(sd_rtnl_message *m, unsigned short *type, void **data) {
639         size_t remaining_size;
640         uint16_t rtm_type;
641         int r;
642
643         assert(m);
644         assert(m->next_rta_offset);
645         assert(type);
646         assert(data);
647
648         remaining_size = m->hdr->nlmsg_len - m->next_rta_offset;
649
650         if (!RTA_OK(NEXT_RTA(m), remaining_size))
651                 return 0;
652
653         /* make sure we don't try to read a container
654          * TODO: add support for entering containers for reading */
655         r = sd_rtnl_message_get_type(m, &rtm_type);
656         if (r < 0)
657                 return r;
658
659         if (message_type_is_link(rtm_type) &&
660             NEXT_RTA(m)->rta_type == IFLA_LINKINFO)
661                return -EINVAL;
662
663         *data = RTA_DATA(NEXT_RTA(m));
664         *type = NEXT_RTA(m)->rta_type;
665
666         UPDATE_RTA(m, RTA_NEXT(NEXT_RTA(m), remaining_size));
667
668         return 1;
669 }
670
671 uint32_t message_get_serial(sd_rtnl_message *m) {
672         assert(m);
673         assert(m->hdr);
674
675         return m->hdr->nlmsg_seq;
676 }
677
678 int sd_rtnl_message_get_errno(sd_rtnl_message *m) {
679         struct nlmsgerr *err;
680
681         assert_return(m, -EINVAL);
682         assert_return(m->hdr, -EINVAL);
683
684         if (m->hdr->nlmsg_type != NLMSG_ERROR)
685                 return 0;
686
687         err = NLMSG_DATA(m->hdr);
688
689         return err->error;
690 }
691
692 int message_seal(sd_rtnl *nl, sd_rtnl_message *m) {
693         assert(nl);
694         assert(m);
695         assert(m->hdr);
696
697         if (m->sealed)
698                 return -EPERM;
699
700         m->hdr->nlmsg_seq = nl->serial++;
701         m->sealed = true;
702
703         return 0;
704 }
705
706 static int message_receive_need(sd_rtnl *rtnl, size_t *need) {
707         assert(rtnl);
708         assert(need);
709
710         /* ioctl(rtnl->fd, FIONREAD, &need)
711            Does not appear to work on netlink sockets. libnl uses
712            MSG_PEEK instead. I don't know if that is worth the
713            extra roundtrip.
714
715            For now we simply use the maximum message size the kernel
716            may use (NLMSG_GOODSIZE), and then realloc to the actual
717            size after reading the message (hence avoiding huge memory
718            usage in case many small messages are kept around) */
719         *need = page_size();
720         if (*need > 8192UL)
721                 *need = 8192UL;
722
723         return 0;
724 }
725
726 /* returns the number of bytes sent, or a negative error code */
727 int socket_write_message(sd_rtnl *nl, sd_rtnl_message *m) {
728         union {
729                 struct sockaddr sa;
730                 struct sockaddr_nl nl;
731         } addr = {
732                 .nl.nl_family = AF_NETLINK,
733         };
734         ssize_t k;
735
736         assert(nl);
737         assert(m);
738         assert(m->hdr);
739
740         k = sendto(nl->fd, m->hdr, m->hdr->nlmsg_len,
741                         0, &addr.sa, sizeof(addr));
742         if (k < 0)
743                 return (errno == EAGAIN) ? 0 : -errno;
744
745         return k;
746 }
747
748 /* On success, the number of bytes received is returned and *ret points to the received message
749  * which has a valid header and the correct size.
750  * If nothing useful was received 0 is returned.
751  * On failure, a negative error code is returned.
752  */
753 int socket_read_message(sd_rtnl *nl, sd_rtnl_message **ret) {
754         sd_rtnl_message *m;
755         union {
756                 struct sockaddr sa;
757                 struct sockaddr_nl nl;
758         } addr;
759         socklen_t addr_len;
760         int r;
761         ssize_t k;
762         size_t need;
763
764         assert(nl);
765         assert(ret);
766
767         r = message_receive_need(nl, &need);
768         if (r < 0)
769                 return r;
770
771         r = message_new(&m, need);
772         if (r < 0)
773                 return r;
774
775         addr_len = sizeof(addr);
776
777         k = recvfrom(nl->fd, m->hdr, need,
778                         0, &addr.sa, &addr_len);
779         if (k < 0)
780                 k = (errno == EAGAIN) ? 0 : -errno; /* no data */
781         else if (k == 0)
782                 k = -ECONNRESET; /* connection was closed by the kernel */
783         else if (addr_len != sizeof(addr.nl) ||
784                         addr.nl.nl_family != AF_NETLINK)
785                 k = -EIO; /* not a netlink message */
786         else if (addr.nl.nl_pid != 0)
787                 k = 0; /* not from the kernel */
788         else if ((size_t) k < sizeof(struct nlmsghdr) ||
789                         (size_t) k < m->hdr->nlmsg_len)
790                 k = -EIO; /* too small (we do accept too big though) */
791         else if (m->hdr->nlmsg_pid && m->hdr->nlmsg_pid != nl->sockaddr.nl.nl_pid)
792                 k = 0; /* not broadcast and not for us */
793
794         if (k > 0)
795                 switch (m->hdr->nlmsg_type) {
796                         struct ifinfomsg *ifi;
797                         struct ifaddrmsg *ifa;
798                         struct rtmsg *rtm;
799
800                         /* check that the size matches the message type */
801                         case NLMSG_ERROR:
802                                 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
803                                         k = -EIO;
804                                 break;
805                         case RTM_NEWLINK:
806                         case RTM_SETLINK:
807                         case RTM_DELLINK:
808                         case RTM_GETLINK:
809                                 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifinfomsg)))
810                                         k = -EIO;
811                                 else {
812                                         ifi = NLMSG_DATA(m->hdr);
813                                         UPDATE_RTA(m, IFLA_RTA(ifi));
814                                 }
815                                 break;
816                         case RTM_NEWADDR:
817                         case RTM_DELADDR:
818                         case RTM_GETADDR:
819                                 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifaddrmsg)))
820                                         k = -EIO;
821                                 else {
822                                         ifa = NLMSG_DATA(m->hdr);
823                                         UPDATE_RTA(m, IFA_RTA(ifa));
824                                 }
825                                 break;
826                         case RTM_NEWROUTE:
827                         case RTM_DELROUTE:
828                         case RTM_GETROUTE:
829                                 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct rtmsg)))
830                                         k = -EIO;
831                                 else {
832                                         rtm = NLMSG_DATA(m->hdr);
833                                         UPDATE_RTA(m, RTM_RTA(rtm));
834                                 }
835                                 break;
836                         case NLMSG_NOOP:
837                                 k = 0;
838                                 break;
839                         default:
840                                 k = 0; /* ignoring message of unknown type */
841                 }
842
843         if (k <= 0)
844                 sd_rtnl_message_unref(m);
845         else {
846                 /* we probably allocated way too much memory, give it back */
847                 m->hdr = realloc(m->hdr, m->hdr->nlmsg_len);
848                 *ret = m;
849         }
850
851         return k;
852 }
853
854 int sd_rtnl_message_rewind(sd_rtnl_message *m) {
855         struct ifinfomsg *ifi;
856         struct ifaddrmsg *ifa;
857         struct rtmsg *rtm;
858
859         assert_return(m, -EINVAL);
860         assert_return(m->hdr, -EINVAL);
861
862         switch(m->hdr->nlmsg_type) {
863                 case RTM_NEWLINK:
864                 case RTM_SETLINK:
865                 case RTM_GETLINK:
866                 case RTM_DELLINK:
867                         ifi = NLMSG_DATA(m->hdr);
868                         UPDATE_RTA(m, IFLA_RTA(ifi));
869
870                         break;
871                 case RTM_NEWADDR:
872                 case RTM_GETADDR:
873                 case RTM_DELADDR:
874                         ifa = NLMSG_DATA(m->hdr);
875                         UPDATE_RTA(m, IFA_RTA(ifa));
876
877                         break;
878                 case RTM_NEWROUTE:
879                 case RTM_GETROUTE:
880                 case RTM_DELROUTE:
881                         rtm = NLMSG_DATA(m->hdr);
882                         UPDATE_RTA(m, RTM_RTA(rtm));
883
884                         break;
885                 default:
886                         return -ENOTSUP;
887         }
888
889         return 0;
890 }