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