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