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