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