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