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