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