chiark / gitweb /
sd-rtnl: added support for a few more attributes
[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_u8(sd_rtnl_message *m, unsigned short type, uint8_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         switch (rtm_type) {
425                 case RTM_NEWLINK:
426                 case RTM_SETLINK:
427                 case RTM_GETLINK:
428                 case RTM_DELLINK:
429                         switch (type) {
430                                 case IFLA_CARRIER:
431                                 case IFLA_OPERSTATE:
432                                 case IFLA_LINKMODE:
433                                 break;
434                         default:
435                                 return -ENOTSUP;
436                         }
437
438                         break;
439                 default:
440                         return -ENOTSUP;
441         }
442
443         r = add_rtattr(m, type, &data, sizeof(uint8_t));
444         if (r < 0)
445                 return r;
446
447         return 0;
448 }
449
450
451 int sd_rtnl_message_append_u16(sd_rtnl_message *m, unsigned short type, uint16_t data) {
452         uint16_t rtm_type;
453         int r;
454
455         assert_return(m, -EINVAL);
456         assert_return(!m->sealed, -EPERM);
457
458         r = sd_rtnl_message_get_type(m, &rtm_type);
459         if (r < 0)
460                 return r;
461
462         /* check that the type is correct */
463         switch (rtm_type) {
464                 case RTM_NEWLINK:
465                 case RTM_SETLINK:
466                 case RTM_GETLINK:
467                 case RTM_DELLINK:
468                         if (m->n_containers == 2 &&
469                             GET_CONTAINER(m, 0)->rta_type == IFLA_LINKINFO &&
470                             GET_CONTAINER(m, 1)->rta_type == IFLA_INFO_DATA &&
471                             type == IFLA_VLAN_ID)
472                                 break;
473                         else
474                                 return -ENOTSUP;
475                         break;
476                 default:
477                         return -ENOTSUP;
478         }
479
480         r = add_rtattr(m, type, &data, sizeof(uint16_t));
481         if (r < 0)
482                 return r;
483
484         return 0;
485 }
486
487 int sd_rtnl_message_append_u32(sd_rtnl_message *m, unsigned short type, uint32_t data) {
488         uint16_t rtm_type;
489         int r;
490
491         assert_return(m, -EINVAL);
492         assert_return(!m->sealed, -EPERM);
493
494         r = sd_rtnl_message_get_type(m, &rtm_type);
495         if (r < 0)
496                 return r;
497
498         /* check that the type is correct */
499         switch (rtm_type) {
500                 case RTM_NEWLINK:
501                 case RTM_SETLINK:
502                 case RTM_GETLINK:
503                 case RTM_DELLINK:
504                         switch (type) {
505                                 case IFLA_MASTER:
506                                 case IFLA_MTU:
507                                 case IFLA_LINK:
508                                 case IFLA_GROUP:
509                                 case IFLA_TXQLEN:
510                                 case IFLA_WEIGHT:
511                                 case IFLA_NET_NS_FD:
512                                 case IFLA_NET_NS_PID:
513                                 case IFLA_PROMISCUITY:
514                                 case IFLA_NUM_TX_QUEUES:
515                                 case IFLA_NUM_RX_QUEUES:
516                                         break;
517                                 default:
518                                         return -ENOTSUP;
519                         }
520                         break;
521                 case RTM_NEWROUTE:
522                 case RTM_GETROUTE:
523                 case RTM_DELROUTE:
524                         switch (type) {
525                                 case RTA_TABLE:
526                                 case RTA_PRIORITY:
527                                 case RTA_IIF:
528                                 case RTA_OIF:
529                                 case RTA_MARK:
530                                         break;
531                                 default:
532                                         return -ENOTSUP;
533                         }
534                         break;
535                 default:
536                         return -ENOTSUP;
537         }
538
539         r = add_rtattr(m, type, &data, sizeof(uint32_t));
540         if (r < 0)
541                 return r;
542
543         return 0;
544 }
545
546 int sd_rtnl_message_append_in_addr(sd_rtnl_message *m, unsigned short type, const struct in_addr *data) {
547         struct ifaddrmsg *ifa;
548         struct rtmsg *rtm;
549         uint16_t rtm_type;
550         int r;
551
552         assert_return(m, -EINVAL);
553         assert_return(!m->sealed, -EPERM);
554         assert_return(data, -EINVAL);
555
556         r = sd_rtnl_message_get_type(m, &rtm_type);
557         if (r < 0)
558                 return r;
559
560         /* check that the type is correct */
561         switch (rtm_type) {
562                 case RTM_NEWADDR:
563                 case RTM_GETADDR:
564                 case RTM_DELADDR:
565                         switch (type) {
566                                 case IFA_ADDRESS:
567                                 case IFA_LOCAL:
568                                 case IFA_BROADCAST:
569                                 case IFA_ANYCAST:
570                                         ifa = NLMSG_DATA(m->hdr);
571
572                                         if (ifa->ifa_family != AF_INET)
573                                                 return -EINVAL;
574
575                                         break;
576                                 default:
577                                         return -ENOTSUP;
578                         }
579                         break;
580                 case RTM_NEWROUTE:
581                 case RTM_GETROUTE:
582                 case RTM_DELROUTE:
583                         switch (type) {
584                                 case RTA_DST:
585                                 case RTA_SRC:
586                                 case RTA_GATEWAY:
587                                         rtm = NLMSG_DATA(m->hdr);
588
589                                         if (rtm->rtm_family != AF_INET)
590                                                 return -EINVAL;
591
592                                         break;
593                                 default:
594                                         return -ENOTSUP;
595                         }
596                         break;
597                 default:
598                         return -ENOTSUP;
599         }
600
601         r = add_rtattr(m, type, data, sizeof(struct in_addr));
602         if (r < 0)
603                 return r;
604
605         return 0;
606 }
607
608 int sd_rtnl_message_append_in6_addr(sd_rtnl_message *m, unsigned short type, const struct in6_addr *data) {
609         struct ifaddrmsg *ifa;
610         struct rtmsg *rtm;
611         uint16_t rtm_type;
612         int r;
613
614         assert_return(m, -EINVAL);
615         assert_return(!m->sealed, -EPERM);
616         assert_return(data, -EINVAL);
617
618         r = sd_rtnl_message_get_type(m, &rtm_type);
619         if (r < 0)
620                 return r;
621
622         /* check that the type is correct */
623         switch (rtm_type) {
624                 case RTM_NEWADDR:
625                 case RTM_GETADDR:
626                 case RTM_DELADDR:
627                         switch (type) {
628                                 case IFA_ADDRESS:
629                                 case IFA_LOCAL:
630                                 case IFA_BROADCAST:
631                                 case IFA_ANYCAST:
632                                         ifa = NLMSG_DATA(m->hdr);
633
634                                         if (ifa->ifa_family != AF_INET6)
635                                                 return -EINVAL;
636
637                                         break;
638                                 default:
639                                         return -ENOTSUP;
640                         }
641                         break;
642                 case RTM_NEWROUTE:
643                 case RTM_GETROUTE:
644                 case RTM_DELROUTE:
645                         switch (type) {
646                                 case RTA_DST:
647                                 case RTA_SRC:
648                                 case RTA_GATEWAY:
649                                         rtm = NLMSG_DATA(m->hdr);
650
651                                         if (rtm->rtm_family != AF_INET6)
652                                                 return -EINVAL;
653
654                                         break;
655                                 default:
656                                         return -ENOTSUP;
657                         }
658                 default:
659                         return -ENOTSUP;
660         }
661
662         r = add_rtattr(m, type, data, sizeof(struct in6_addr));
663         if (r < 0)
664                 return r;
665
666         return 0;
667 }
668
669 int sd_rtnl_message_append_ether_addr(sd_rtnl_message *m, unsigned short type, const struct ether_addr *data) {
670         uint16_t rtm_type;
671         int r;
672
673         assert_return(m, -EINVAL);
674         assert_return(!m->sealed, -EPERM);
675         assert_return(data, -EINVAL);
676
677         sd_rtnl_message_get_type(m, &rtm_type);
678
679         switch (rtm_type) {
680                 case RTM_NEWLINK:
681                 case RTM_SETLINK:
682                 case RTM_DELLINK:
683                 case RTM_GETLINK:
684                         switch (type) {
685                                 case IFLA_ADDRESS:
686                                 case IFLA_BROADCAST:
687                                         break;
688                                 default:
689                                         return -ENOTSUP;
690                         }
691                         break;
692                 default:
693                         return -ENOTSUP;
694         }
695
696         r = add_rtattr(m, type, data, ETH_ALEN);
697         if (r < 0)
698                 return r;
699
700         return 0;
701 }
702
703 int sd_rtnl_message_open_container(sd_rtnl_message *m, unsigned short type) {
704         uint16_t rtm_type;
705
706         assert_return(m, -EINVAL);
707         assert_return(!m->sealed, -EPERM);
708
709         sd_rtnl_message_get_type(m, &rtm_type);
710
711         if (rtnl_message_type_is_link(rtm_type)) {
712                 if ((type == IFLA_LINKINFO && m->n_containers == 0) ||
713                     (type == IFLA_INFO_DATA && m->n_containers == 1 &&
714                      GET_CONTAINER(m, 0)->rta_type == IFLA_LINKINFO))
715                         return add_rtattr(m, type, NULL, 0);
716                 else
717                         return -ENOTSUP;
718         } else
719                 return -ENOTSUP;
720
721         return 0;
722 }
723
724 int sd_rtnl_message_close_container(sd_rtnl_message *m) {
725         assert_return(m, -EINVAL);
726         assert_return(!m->sealed, -EPERM);
727         assert_return(m->n_containers > 0, -EINVAL);
728
729         m->n_containers --;
730
731         return 0;
732 }
733
734 int sd_rtnl_message_read(sd_rtnl_message *m, unsigned short *type, void **data) {
735         size_t remaining_size;
736         uint16_t rtm_type;
737         int r;
738
739         assert_return(m, -EINVAL);
740         assert_return(m->sealed, -EPERM);
741         assert_return(m->next_rta_offset, -EINVAL);
742         assert_return(type, -EINVAL);
743         assert_return(data, -EINVAL);
744
745         /* only read until the end of the current container */
746         if (m->n_containers)
747                 remaining_size = GET_CONTAINER(m, m->n_containers - 1)->rta_len -
748                                  (m->next_rta_offset -
749                                   m->container_offsets[m->n_containers - 1]);
750         else
751                 remaining_size = m->hdr->nlmsg_len - m->next_rta_offset;
752
753         if (!RTA_OK(NEXT_RTA(m), remaining_size))
754                 return 0;
755
756         /* if we read a container, enter it and return its type */
757         r = sd_rtnl_message_get_type(m, &rtm_type);
758         if (r < 0)
759                 return r;
760
761         *type = NEXT_RTA(m)->rta_type;
762
763         if (rtnl_message_type_is_link(rtm_type) &&
764             ((m->n_containers == 0 &&
765               NEXT_RTA(m)->rta_type == IFLA_LINKINFO) ||
766              (m->n_containers == 1 &&
767               GET_CONTAINER(m, 0)->rta_type == IFLA_LINKINFO &&
768               NEXT_RTA(m)->rta_type == IFLA_INFO_DATA))) {
769                 *data = NULL;
770                 PUSH_CONTAINER(m, NEXT_RTA(m));
771                 UPDATE_RTA(m, RTA_DATA(NEXT_RTA(m)));
772         } else {
773                 *data = RTA_DATA(NEXT_RTA(m));
774                 UPDATE_RTA(m, RTA_NEXT(NEXT_RTA(m), remaining_size));
775         }
776
777         return 1;
778 }
779
780 int sd_rtnl_message_exit_container(sd_rtnl_message *m) {
781         assert_return(m, -EINVAL);
782         assert_return(m->sealed, -EINVAL);
783         assert_return(m->n_containers > 0, -EINVAL);
784
785         m->n_containers --;
786
787         return 0;
788 }
789
790 uint32_t rtnl_message_get_serial(sd_rtnl_message *m) {
791         assert(m);
792         assert(m->hdr);
793
794         return m->hdr->nlmsg_seq;
795 }
796
797 int sd_rtnl_message_get_errno(sd_rtnl_message *m) {
798         struct nlmsgerr *err;
799
800         assert_return(m, -EINVAL);
801         assert_return(m->hdr, -EINVAL);
802
803         if (m->hdr->nlmsg_type != NLMSG_ERROR)
804                 return 0;
805
806         err = NLMSG_DATA(m->hdr);
807
808         return err->error;
809 }
810
811 int rtnl_message_seal(sd_rtnl *nl, sd_rtnl_message *m) {
812         int r;
813
814         assert(m);
815         assert(m->hdr);
816
817         if (m->sealed)
818                 return -EPERM;
819
820         if (nl)
821                 m->hdr->nlmsg_seq = nl->serial++;
822
823         m->sealed = true;
824
825         r = sd_rtnl_message_rewind(m);
826         if (r < 0)
827                 return r;
828
829         return 0;
830 }
831
832 static int message_receive_need(sd_rtnl *rtnl, size_t *need) {
833         assert(rtnl);
834         assert(need);
835
836         /* ioctl(rtnl->fd, FIONREAD, &need)
837            Does not appear to work on netlink sockets. libnl uses
838            MSG_PEEK instead. I don't know if that is worth the
839            extra roundtrip.
840
841            For now we simply use the maximum message size the kernel
842            may use (NLMSG_GOODSIZE), and then realloc to the actual
843            size after reading the message (hence avoiding huge memory
844            usage in case many small messages are kept around) */
845         *need = page_size();
846         if (*need > 8192UL)
847                 *need = 8192UL;
848
849         return 0;
850 }
851
852 /* returns the number of bytes sent, or a negative error code */
853 int socket_write_message(sd_rtnl *nl, sd_rtnl_message *m) {
854         union {
855                 struct sockaddr sa;
856                 struct sockaddr_nl nl;
857         } addr = {
858                 .nl.nl_family = AF_NETLINK,
859         };
860         ssize_t k;
861
862         assert(nl);
863         assert(m);
864         assert(m->hdr);
865
866         k = sendto(nl->fd, m->hdr, m->hdr->nlmsg_len,
867                         0, &addr.sa, sizeof(addr));
868         if (k < 0)
869                 return (errno == EAGAIN) ? 0 : -errno;
870
871         return k;
872 }
873
874 /* On success, the number of bytes received is returned and *ret points to the received message
875  * which has a valid header and the correct size.
876  * If nothing useful was received 0 is returned.
877  * On failure, a negative error code is returned.
878  */
879 int socket_read_message(sd_rtnl *nl, sd_rtnl_message **ret) {
880         sd_rtnl_message *m;
881         union {
882                 struct sockaddr sa;
883                 struct sockaddr_nl nl;
884         } addr;
885         socklen_t addr_len;
886         int r;
887         ssize_t k;
888         size_t need;
889
890         assert(nl);
891         assert(ret);
892
893         r = message_receive_need(nl, &need);
894         if (r < 0)
895                 return r;
896
897         r = message_new(&m, need);
898         if (r < 0)
899                 return r;
900
901         /* don't allow sealing/appending to received messages */
902         m->sealed = true;
903
904         addr_len = sizeof(addr);
905
906         k = recvfrom(nl->fd, m->hdr, need,
907                         0, &addr.sa, &addr_len);
908         if (k < 0)
909                 k = (errno == EAGAIN) ? 0 : -errno; /* no data */
910         else if (k == 0)
911                 k = -ECONNRESET; /* connection was closed by the kernel */
912         else if (addr_len != sizeof(addr.nl) ||
913                         addr.nl.nl_family != AF_NETLINK)
914                 k = -EIO; /* not a netlink message */
915         else if (addr.nl.nl_pid != 0)
916                 k = 0; /* not from the kernel */
917         else if ((size_t) k < sizeof(struct nlmsghdr) ||
918                         (size_t) k < m->hdr->nlmsg_len)
919                 k = -EIO; /* too small (we do accept too big though) */
920         else if (m->hdr->nlmsg_pid && m->hdr->nlmsg_pid != nl->sockaddr.nl.nl_pid)
921                 k = 0; /* not broadcast and not for us */
922
923         if (k > 0)
924                 switch (m->hdr->nlmsg_type) {
925                         struct ifinfomsg *ifi;
926                         struct ifaddrmsg *ifa;
927                         struct rtmsg *rtm;
928
929                         /* check that the size matches the message type */
930                         case NLMSG_ERROR:
931                                 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
932                                         k = -EIO;
933                                 break;
934                         case RTM_NEWLINK:
935                         case RTM_SETLINK:
936                         case RTM_DELLINK:
937                         case RTM_GETLINK:
938                                 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifinfomsg)))
939                                         k = -EIO;
940                                 else {
941                                         ifi = NLMSG_DATA(m->hdr);
942                                         UPDATE_RTA(m, IFLA_RTA(ifi));
943                                 }
944                                 break;
945                         case RTM_NEWADDR:
946                         case RTM_DELADDR:
947                         case RTM_GETADDR:
948                                 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifaddrmsg)))
949                                         k = -EIO;
950                                 else {
951                                         ifa = NLMSG_DATA(m->hdr);
952                                         UPDATE_RTA(m, IFA_RTA(ifa));
953                                 }
954                                 break;
955                         case RTM_NEWROUTE:
956                         case RTM_DELROUTE:
957                         case RTM_GETROUTE:
958                                 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct rtmsg)))
959                                         k = -EIO;
960                                 else {
961                                         rtm = NLMSG_DATA(m->hdr);
962                                         UPDATE_RTA(m, RTM_RTA(rtm));
963                                 }
964                                 break;
965                         case NLMSG_NOOP:
966                                 k = 0;
967                                 break;
968                         default:
969                                 k = 0; /* ignoring message of unknown type */
970                 }
971
972         if (k <= 0)
973                 sd_rtnl_message_unref(m);
974         else {
975                 /* we probably allocated way too much memory, give it back */
976                 m->hdr = realloc(m->hdr, m->hdr->nlmsg_len);
977                 *ret = m;
978         }
979
980         return k;
981 }
982
983 int sd_rtnl_message_rewind(sd_rtnl_message *m) {
984         struct ifinfomsg *ifi;
985         struct ifaddrmsg *ifa;
986         struct rtmsg *rtm;
987
988         assert_return(m, -EINVAL);
989         assert_return(m->sealed, -EPERM);
990         assert_return(m->hdr, -EINVAL);
991
992         switch(m->hdr->nlmsg_type) {
993                 case RTM_NEWLINK:
994                 case RTM_SETLINK:
995                 case RTM_GETLINK:
996                 case RTM_DELLINK:
997                         ifi = NLMSG_DATA(m->hdr);
998                         UPDATE_RTA(m, IFLA_RTA(ifi));
999
1000                         break;
1001                 case RTM_NEWADDR:
1002                 case RTM_GETADDR:
1003                 case RTM_DELADDR:
1004                         ifa = NLMSG_DATA(m->hdr);
1005                         UPDATE_RTA(m, IFA_RTA(ifa));
1006
1007                         break;
1008                 case RTM_NEWROUTE:
1009                 case RTM_GETROUTE:
1010                 case RTM_DELROUTE:
1011                         rtm = NLMSG_DATA(m->hdr);
1012                         UPDATE_RTA(m, RTM_RTA(rtm));
1013
1014                         break;
1015                 default:
1016                         return -ENOTSUP;
1017         }
1018
1019         m->n_containers = 0;
1020
1021         return 0;
1022 }