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