source: rtems-libbsd/dhcpcd/dhcp6.c @ 338f300

5-freebsd-12
Last change on this file since 338f300 was 338f300, checked in by Christian Mauderer <christian.mauderer@…>, on Apr 25, 2018 at 2:28:00 PM

buildset: Add minimal and everything config.

This adds two new buildset configurations: One that leaves out as much
features as possible and one that enables all features. For the default
configuration WiFi? support is now disabled.

To disable IPv6 for the minimal configuration, all -DINET6 are
eliminated in libbsd.py. They are now replaced by a #ifdef that checks
for RTEMS_BSD_MODULE_NETINET6 instead.

Close #3351.

  • Property mode set to 100644
File size: 65.4 KB
Line 
1/*
2 * dhcpcd - DHCP client daemon
3 * Copyright (c) 2006-2014 Roy Marples <roy@marples.name>
4 * All rights reserved
5
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28/* TODO: We should decline dupliate addresses detected */
29
30#ifdef __rtems__
31#include <rtems/bsd/local/opt_inet6.h>
32#endif /* __rtems__ */
33#if defined(__rtems__) && defined(INET6)
34#include <sys/stat.h>
35#include <sys/utsname.h>
36
37#include <netinet/in.h>
38#ifdef __linux__
39#  define _LINUX_IN6_H
40#  include <linux/ipv6.h>
41#endif
42
43#include <ctype.h>
44#include <errno.h>
45#include <fcntl.h>
46#include <inttypes.h>
47#include <stdlib.h>
48#include <string.h>
49#include <syslog.h>
50#include <unistd.h>
51
52#define ELOOP_QUEUE 3
53
54#include "config.h"
55#include "common.h"
56#include "dhcp.h"
57#include "dhcp6.h"
58#include "duid.h"
59#include "eloop.h"
60#include "ipv6nd.h"
61#include "platform.h"
62#include "script.h"
63
64#ifndef __UNCONST
65#define __UNCONST(a) ((void *)(unsigned long)(const void *)(a))
66#endif
67
68/* DHCPCD Project has been assigned an IANA PEN of 40712 */
69#define DHCPCD_IANA_PEN 40712
70
71/* Unsure if I want this */
72//#define VENDOR_SPLIT
73
74static int sock = -1;
75static const struct in6_addr in6addr_linklocal_alldhcp =
76    IN6ADDR_LINKLOCAL_ALLDHCP_INIT;
77static struct sockaddr_in6 from;
78static struct msghdr sndhdr;
79static struct iovec sndiov[2];
80static unsigned char *sndbuf;
81static struct msghdr rcvhdr;
82static struct iovec rcviov[2];
83static unsigned char *rcvbuf;
84static unsigned char ansbuf[1500];
85static char ntopbuf[INET6_ADDRSTRLEN];
86static char *status;
87static size_t status_len;
88
89struct dhcp6_op {
90        uint16_t type;
91        const char *name;
92};
93
94static const struct dhcp6_op dhcp6_ops[] = {
95        { DHCP6_SOLICIT, "SOLICIT6" },
96        { DHCP6_ADVERTISE, "ADVERTISE6" },
97        { DHCP6_REQUEST, "REQUEST6" },
98        { DHCP6_REPLY, "REPLY6" },
99        { DHCP6_RENEW, "RENEW6" },
100        { DHCP6_REBIND, "REBIND6" },
101        { DHCP6_CONFIRM, "CONFIRM6" },
102        { DHCP6_INFORMATION_REQ, "INFORM6" },
103        { DHCP6_RELEASE, "RELEASE6" },
104        { 0, NULL }
105};
106
107struct dhcp_opt *dhcp6_opts = NULL;
108size_t dhcp6_opts_len = 0;
109
110struct dhcp_compat {
111        uint8_t dhcp_opt;
112        uint16_t dhcp6_opt;
113};
114
115const struct dhcp_compat dhcp_compats[] = {
116        { DHO_DNSSERVER,        D6_OPTION_DNS_SERVERS },
117        { DHO_HOSTNAME,         D6_OPTION_FQDN },
118        { DHO_DNSDOMAIN,        D6_OPTION_FQDN },
119        { DHO_NISSERVER,        D6_OPTION_NIS_SERVERS },
120        { DHO_NTPSERVER,        D6_OPTION_SNTP_SERVERS },
121        { DHO_RAPIDCOMMIT,      D6_OPTION_RAPID_COMMIT },
122        { DHO_FQDN,             D6_OPTION_FQDN },
123        { DHO_VIVCO,            D6_OPTION_VENDOR_CLASS },
124        { DHO_VIVSO,            D6_OPTION_VENDOR_OPTS },
125        { DHO_DNSSEARCH,        D6_OPTION_DOMAIN_LIST },
126        { 0, 0 }
127};
128
129static const char * const dhcp6_statuses[] = {
130        "Success",
131        "Unspecified Failure",
132        "No Addresses Available",
133        "No Binding",
134        "Not On Link",
135        "Use Multicast"
136};
137
138#if DEBUG_MEMORY
139static void
140dhcp6_cleanup(void)
141{
142
143        free(sndbuf);
144        free(rcvbuf);
145        free(status);
146}
147#endif
148
149void
150dhcp6_printoptions(void)
151{
152        size_t i;
153        const struct dhcp_opt *opt;
154
155        for (i = 0, opt = dhcp6_opts; i < dhcp6_opts_len; i++, opt++)
156                printf("%05d %s\n", opt->option, opt->var);
157}
158
159static int
160dhcp6_init(void)
161{
162        int len;
163
164#if DEBUG_MEMORY
165        atexit(dhcp6_cleanup);
166#endif
167
168        len = CMSG_SPACE(sizeof(struct in6_pktinfo));
169        sndbuf = calloc(1, len);
170        if (sndbuf == NULL)
171                return -1;
172        sndhdr.msg_namelen = sizeof(struct sockaddr_in6);
173        sndhdr.msg_iov = sndiov;
174        sndhdr.msg_iovlen = 1;
175        sndhdr.msg_control = sndbuf;
176        sndhdr.msg_controllen = len;
177
178        rcvbuf = calloc(1, len);
179        if (rcvbuf == NULL) {
180                free(sndbuf);
181                sndbuf = NULL;
182                return -1;
183        }
184        rcvhdr.msg_name = &from;
185        rcvhdr.msg_namelen = sizeof(from);
186        rcvhdr.msg_iov = rcviov;
187        rcvhdr.msg_iovlen = 1;
188        rcvhdr.msg_control = rcvbuf;
189        rcvhdr.msg_controllen = len;
190        rcviov[0].iov_base = ansbuf;
191        rcviov[0].iov_len = sizeof(ansbuf);
192
193        return 0;
194}
195
196static size_t
197dhcp6_makevendor(struct dhcp6_option *o, const struct interface *ifp)
198{
199        const struct if_options *ifo;
200        size_t len;
201        uint8_t *p;
202        uint16_t u16;
203        uint32_t u32;
204        size_t vlen, i;
205        const struct vivco *vivco;
206
207        ifo = ifp->options;
208        len = sizeof(uint32_t); /* IANA PEN */
209        if (ifo->vivco_en) {
210                for (i = 0, vivco = ifo->vivco;
211                    i < ifo->vivco_len;
212                    i++, vivco++)
213                        len += sizeof(uint16_t) + vivco->len;
214                vlen = 0; /* silence bogus gcc warning */
215        } else {
216                vlen = strlen(vendor);
217                len += sizeof(uint16_t) + vlen;
218        }
219
220        if (len > UINT16_MAX) {
221                syslog(LOG_ERR, "%s: DHCPv6 Vendor Class too big", ifp->name);
222                return 0;
223        }
224
225        if (o) {
226                o->code = htons(D6_OPTION_VENDOR_CLASS);
227                o->len = htons(len);
228                p = D6_OPTION_DATA(o);
229                u32 = htonl(ifo->vivco_en ? ifo->vivco_en : DHCPCD_IANA_PEN);
230                memcpy(p, &u32, sizeof(u32));
231                p += sizeof(u32);
232                if (ifo->vivco_en) {
233                        for (i = 0, vivco = ifo->vivco;
234                            i < ifo->vivco_len;
235                            i++, vivco++)
236                        {
237                                u16 = htons(vivco->len);
238                                memcpy(p, &u16, sizeof(u16));
239                                p += sizeof(u16);
240                                memcpy(p, vivco->data, vivco->len);
241                                p += vivco->len;
242                        }
243                } else {
244                        u16 = htons(vlen);
245                        memcpy(p, &u16, sizeof(u16));
246                        p += sizeof(u16);
247                        memcpy(p, vendor, vlen);
248                }
249        }
250
251        return len;
252}
253
254static const struct dhcp6_option *
255dhcp6_findoption(int code, const uint8_t *d, ssize_t len)
256{
257        const struct dhcp6_option *o;
258
259        code = htons(code);
260        for (o = (const struct dhcp6_option *)d;
261            len > (ssize_t)sizeof(*o);
262            o = D6_CNEXT_OPTION(o))
263        {
264                len -= sizeof(*o) + ntohs(o->len);
265                if (len < 0) {
266                        errno = EINVAL;
267                        return NULL;
268                }
269                if (o->code == code)
270                        return o;
271        }
272
273        errno = ESRCH;
274        return NULL;
275}
276
277static const uint8_t *
278dhcp6_getoption(unsigned int *os, unsigned int *code, unsigned int *len,
279    const uint8_t *od, unsigned int ol, struct dhcp_opt **oopt)
280{
281        const struct dhcp6_option *o;
282        size_t i;
283        struct dhcp_opt *opt;
284
285        if (od) {
286                *os = sizeof(*o);
287                if (ol < *os) {
288                        errno = EINVAL;
289                        return NULL;
290                }
291                o = (const struct dhcp6_option *)od;
292                *len = ntohs(o->len);
293                if (*len > ol) {
294                        errno = EINVAL;
295                        return NULL;
296                }
297                *code = ntohs(o->code);
298        } else
299                o = NULL;
300
301        for (i = 0, opt = dhcp6_opts; i < dhcp6_opts_len; i++, opt++) {
302                if (opt->option == *code) {
303                        *oopt = opt;
304                        break;
305                }
306        }
307
308        if (o)
309                return D6_COPTION_DATA(o);
310        return NULL;
311}
312
313static const struct dhcp6_option *
314dhcp6_getmoption(int code, const struct dhcp6_message *m, ssize_t len)
315{
316
317        len -= sizeof(*m);
318        return dhcp6_findoption(code,
319            (const uint8_t *)D6_CFIRST_OPTION(m), len);
320}
321
322static int
323dhcp6_updateelapsed(struct interface *ifp, struct dhcp6_message *m, ssize_t len)
324{
325        struct dhcp6_state *state;
326        const struct dhcp6_option *co;
327        struct dhcp6_option *o;
328        time_t up;
329        uint16_t u16;
330
331        co = dhcp6_getmoption(D6_OPTION_ELAPSED, m, len);
332        if (co == NULL)
333                return -1;
334
335        o = __UNCONST(co);
336        state = D6_STATE(ifp);
337        up = uptime() - state->start_uptime;
338        if (up < 0 || up > (time_t)UINT16_MAX)
339                up = (time_t)UINT16_MAX;
340        u16 = htons(up);
341        memcpy(D6_OPTION_DATA(o), &u16, sizeof(u16));
342        return 0;
343}
344
345static void
346dhcp6_newxid(const struct interface *ifp, struct dhcp6_message *m)
347{
348        uint32_t xid;
349
350        if (ifp->options->options & DHCPCD_XID_HWADDR &&
351            ifp->hwlen >= sizeof(xid))
352                /* The lower bits are probably more unique on the network */
353                memcpy(&xid, (ifp->hwaddr + ifp->hwlen) - sizeof(xid),
354                    sizeof(xid));
355        else
356                xid = arc4random();
357
358        m->xid[0] = (xid >> 16) & 0xff;
359        m->xid[1] = (xid >> 8) & 0xff;
360        m->xid[2] = xid & 0xff;
361}
362
363static int
364dhcp6_makemessage(struct interface *ifp)
365{
366        struct dhcp6_state *state;
367        struct dhcp6_message *m;
368        struct dhcp6_option *o, *so;
369        const struct dhcp6_option *si, *unicast;
370        ssize_t len, ml;
371        size_t l;
372        int auth_len;
373        uint8_t u8;
374        uint16_t *u16, n_options, type;
375        const struct if_options *ifo;
376        const struct dhcp_opt *opt;
377        uint8_t IA, *p;
378        uint32_t u32;
379        const struct ipv6_addr *ap;
380        const char *hostname = NULL; /* assignment just to appease GCC*/
381        int fqdn;
382
383        state = D6_STATE(ifp);
384        if (state->send) {
385                free(state->send);
386                state->send = NULL;
387        }
388
389        ifo = ifp->options;
390        fqdn = ifo->fqdn;
391
392        if (fqdn == FQDN_DISABLE && ifo->options & DHCPCD_HOSTNAME) {
393                /* We're sending the DHCPv4 hostname option, so send FQDN as
394                 * DHCPv6 has no FQDN option and DHCPv4 must not send
395                 * hostname and FQDN according to RFC4702 */
396                fqdn = FQDN_BOTH;
397        }
398        if (fqdn != FQDN_DISABLE) {
399                if (ifo->hostname[0] == '\0')
400                        hostname = get_hostname(ifo->options &
401                            DHCPCD_HOSTNAME_SHORT ? 1 : 0);
402                else
403                        hostname = ifo->hostname;
404        }
405
406        /* Work out option size first */
407        n_options = 0;
408        len = 0;
409        si = NULL;
410        if (state->state != DH6S_RELEASE) {
411                for (l = 0, opt = dhcp6_opts; l < dhcp6_opts_len ; l++, opt++) {
412                        if (!(opt->type & NOREQ) &&
413                            (opt->type & REQUEST ||
414                            has_option_mask(ifo->requestmask6, opt->option)))
415                        {
416                                n_options++;
417                                len += sizeof(*u16);
418                        }
419                }
420                if (len)
421                        len += sizeof(*o);
422
423                if (fqdn != FQDN_DISABLE)
424                        len += sizeof(*o) + 1 + encode_rfc1035(hostname, NULL);
425        }
426
427        len += sizeof(*state->send);
428        len += sizeof(*o) + duid_len;
429        len += sizeof(*o) + sizeof(uint16_t); /* elapsed */
430        len += sizeof(*o) + dhcp6_makevendor(NULL, ifp);
431
432        /* IA */
433        m = NULL;
434        ml = 0;
435        switch(state->state) {
436        case DH6S_REQUEST:
437                m = state->recv;
438                ml = state->recv_len;
439                /* FALLTHROUGH */
440        case DH6S_RELEASE:
441                /* FALLTHROUGH */
442        case DH6S_RENEW:
443                if (m == NULL) {
444                        m = state->new;
445                        ml = state->new_len;
446                }
447                si = dhcp6_getmoption(D6_OPTION_SERVERID, m, ml);
448                if (si == NULL) {
449                        errno = ESRCH;
450                        return -1;
451                }
452                len += sizeof(*si) + ntohs(si->len);
453                /* FALLTHROUGH */
454        case DH6S_REBIND:
455                /* FALLTHROUGH */
456        case DH6S_CONFIRM:
457                if (m == NULL) {
458                        m = state->new;
459                        ml = state->new_len;
460                }
461                TAILQ_FOREACH(ap, &state->addrs, next) {
462                        if (ap->prefix_vltime == 0)
463                                continue;
464                        if (ifo->ia_type == D6_OPTION_IA_PD)
465                                len += sizeof(*o) + sizeof(u8) +
466                                    sizeof(u32) + sizeof(u32) +
467                                    sizeof(ap->prefix.s6_addr);
468                        else
469                                len += sizeof(*o) + sizeof(ap->addr.s6_addr) +
470                                    sizeof(u32) + sizeof(u32);
471                }
472                /* FALLTHROUGH */
473        case DH6S_INIT: /* FALLTHROUGH */
474        case DH6S_DISCOVER:
475                len += ifo->ia_len * (sizeof(*o) + (sizeof(u32) * 3));
476                IA = 1;
477                break;
478        default:
479                IA = 0;
480        }
481
482        if (state->state == DH6S_DISCOVER &&
483            !(options & DHCPCD_TEST) &&
484            has_option_mask(ifo->requestmask6, D6_OPTION_RAPID_COMMIT))
485                len += sizeof(*o);
486
487        if (m == NULL) {
488                m = state->new;
489                ml = state->new_len;
490        }
491        unicast = NULL;
492        /* Depending on state, get the unicast address */
493        switch(state->state) {
494                break;
495        case DH6S_INIT: /* FALLTHROUGH */
496        case DH6S_DISCOVER:
497                type = DHCP6_SOLICIT;
498                break;
499        case DH6S_REQUEST:
500                type = DHCP6_REQUEST;
501                unicast = dhcp6_getmoption(D6_OPTION_UNICAST, m, ml);
502                break;
503        case DH6S_CONFIRM:
504                type = DHCP6_CONFIRM;
505                break;
506        case DH6S_REBIND:
507                type = DHCP6_REBIND;
508                break;
509        case DH6S_RENEW:
510                type = DHCP6_RENEW;
511                unicast = dhcp6_getmoption(D6_OPTION_UNICAST, m, ml);
512                break;
513        case DH6S_INFORM:
514                type = DHCP6_INFORMATION_REQ;
515                break;
516        case DH6S_RELEASE:
517                type = DHCP6_RELEASE;
518                unicast = dhcp6_getmoption(D6_OPTION_UNICAST, m, ml);
519                break;
520        default:
521                errno = EINVAL;
522                return -1;
523        }
524
525        if (ifo->auth.options & DHCPCD_AUTH_SEND) {
526                auth_len = dhcp_auth_encode(&ifo->auth, state->auth.token,
527                    NULL, 0, 6, type, NULL, 0);
528                if (auth_len > 0)
529                        len += sizeof(*o) + auth_len;
530        } else
531                auth_len = 0; /* appease GCC */
532
533        state->send = malloc(len);
534        if (state->send == NULL)
535                return -1;
536
537        state->send_len = len;
538        state->send->type = type;
539
540        /* If we found a unicast option, copy it to our state for sending */
541        if (unicast && ntohs(unicast->len) == sizeof(state->unicast.s6_addr))
542                memcpy(&state->unicast.s6_addr, D6_COPTION_DATA(unicast),
543                    sizeof(state->unicast.s6_addr));
544        else
545                state->unicast = in6addr_any;
546
547        dhcp6_newxid(ifp, state->send);
548
549        o = D6_FIRST_OPTION(state->send);
550        o->code = htons(D6_OPTION_CLIENTID);
551        o->len = htons(duid_len);
552        memcpy(D6_OPTION_DATA(o), duid, duid_len);
553
554        if (si) {
555                o = D6_NEXT_OPTION(o);
556                memcpy(o, si, sizeof(*si) + ntohs(si->len));
557        }
558
559        o = D6_NEXT_OPTION(o);
560        o->code = htons(D6_OPTION_ELAPSED);
561        o->len = htons(sizeof(uint16_t));
562        p = D6_OPTION_DATA(o);
563        memset(p, 0, sizeof(u16));
564
565        o = D6_NEXT_OPTION(o);
566        dhcp6_makevendor(o, ifp);
567
568        if (state->state == DH6S_DISCOVER &&
569            !(options & DHCPCD_TEST) &&
570            has_option_mask(ifo->requestmask6, D6_OPTION_RAPID_COMMIT))
571        {
572                o = D6_NEXT_OPTION(o);
573                o->code = htons(D6_OPTION_RAPID_COMMIT);
574                o->len = 0;
575        }
576
577        for (l = 0; IA && l < ifo->ia_len; l++) {
578                o = D6_NEXT_OPTION(o);
579                o->code = htons(ifo->ia_type);
580                o->len = htons(sizeof(u32) + sizeof(u32) + sizeof(u32));
581                p = D6_OPTION_DATA(o);
582                memcpy(p, ifo->ia[l].iaid, sizeof(u32));
583                p += sizeof(u32);
584                memset(p, 0, sizeof(u32) + sizeof(u32));
585                TAILQ_FOREACH(ap, &state->addrs, next) {
586                        if (ap->prefix_vltime == 0)
587                                continue;
588                        if (memcmp(ifo->ia[l].iaid, ap->iaid, sizeof(u32)))
589                                continue;
590                        so = D6_NEXT_OPTION(o);
591                        if (ifo->ia_type == D6_OPTION_IA_PD) {
592                                so->code = htons(D6_OPTION_IAPREFIX);
593                                so->len = htons(sizeof(ap->prefix.s6_addr) +
594                                    sizeof(u32) + sizeof(u32) + sizeof(u8));
595                                p = D6_OPTION_DATA(so);
596                                u32 = htonl(ap->prefix_pltime);
597                                memcpy(p, &u32, sizeof(u32));
598                                p += sizeof(u32);
599                                u32 = htonl(ap->prefix_vltime);
600                                memcpy(p, &u32, sizeof(u32));
601                                p += sizeof(u32);
602                                u8 = ap->prefix_len;
603                                memcpy(p, &u8, sizeof(u8));
604                                p += sizeof(u8);
605                                memcpy(p, &ap->prefix.s6_addr,
606                                    sizeof(ap->prefix.s6_addr));
607                                /* Avoid a shadowed declaration warning by
608                                 * moving our addition outside of the htons
609                                 * macro */
610                                u32 = ntohs(o->len) + sizeof(*so)
611                                    + ntohs(so->len);
612                                o->len = htons(u32);
613                        } else {
614                                so->code = htons(D6_OPTION_IA_ADDR);
615                                so->len = htons(sizeof(ap->addr.s6_addr) +
616                                    sizeof(u32) + sizeof(u32));
617                                p = D6_OPTION_DATA(so);
618                                memcpy(p, &ap->addr.s6_addr,
619                                    sizeof(ap->addr.s6_addr));
620                                p += sizeof(ap->addr.s6_addr);
621                                u32 = htonl(ap->prefix_pltime);
622                                memcpy(p, &u32, sizeof(u32));
623                                p += sizeof(u32);
624                                u32 = htonl(ap->prefix_vltime);
625                                memcpy(p, &u32, sizeof(u32));
626                                /* Avoid a shadowed declaration warning by
627                                 * moving our addition outside of the htons
628                                 * macro */
629                                u32 = ntohs(o->len) + sizeof(*so)
630                                    + ntohs(so->len);
631                                o->len = htons(u32);
632                        }
633                }
634        }
635
636        if (state->send->type !=  DHCP6_RELEASE) {
637                if (fqdn != FQDN_DISABLE) {
638                        o = D6_NEXT_OPTION(o);
639                        o->code = htons(D6_OPTION_FQDN);
640                        p = D6_OPTION_DATA(o);
641                        switch (fqdn) {
642                        case FQDN_BOTH:
643                                *p = D6_FQDN_BOTH;
644                                break;
645                        case FQDN_PTR:
646                                *p = D6_FQDN_PTR;
647                                break;
648                        default:
649                                *p = D6_FQDN_NONE;
650                                break;
651                        }
652                        l = encode_rfc1035(hostname, p + 1);
653                        if (l == 0)
654                                *p = D6_FQDN_NONE;
655                        o->len = htons(l + 1);
656                }
657
658                if (n_options) {
659                        o = D6_NEXT_OPTION(o);
660                        o->code = htons(D6_OPTION_ORO);
661                        o->len = 0;
662                        u16 = (uint16_t *)(void *)D6_OPTION_DATA(o);
663                        for (l = 0, opt = dhcp6_opts;
664                            l < dhcp6_opts_len;
665                            l++, opt++)
666                        {
667                                if (!(opt->type & NOREQ) &&
668                                    (opt->type & REQUEST ||
669                                    has_option_mask(ifo->requestmask6,
670                                        opt->option)))
671                                {
672                                        *u16++ = htons(opt->option);
673                                        o->len += sizeof(*u16);
674                                }
675                        }
676                        o->len = htons(o->len);
677                }
678        }
679
680        /* This has to be the last option */
681        if (ifo->auth.options & DHCPCD_AUTH_SEND && auth_len > 0) {
682                o = D6_NEXT_OPTION(o);
683                o->code = htons(D6_OPTION_AUTH);
684                o->len = htons(auth_len);
685                /* data will be filled at send message time */
686        }
687
688        return 0;
689}
690
691static const char *
692dhcp6_get_op(uint16_t type)
693{
694        const struct dhcp6_op *d;
695
696        for (d = dhcp6_ops; d->name; d++)
697                if (d->type == type)
698                        return d->name;
699        return NULL;
700}
701
702static void
703dhcp6_freedrop_addrs(struct interface *ifp, int drop,
704    const struct interface *ifd)
705{
706        struct dhcp6_state *state;
707
708        state = D6_STATE(ifp);
709        if (state) {
710                ipv6_freedrop_addrs(&state->addrs, drop, ifd);
711                if (drop)
712                        ipv6_buildroutes();
713        }
714}
715
716static void dhcp6_delete_delegates(struct interface *ifp)
717{
718        struct interface *ifp0;
719
720        if (ifaces) {
721                TAILQ_FOREACH(ifp0, ifaces, next) {
722                        if (ifp0 != ifp)
723                                dhcp6_freedrop_addrs(ifp0, 1, ifp);
724                }
725        }
726}
727
728
729static int
730dhcp6_update_auth(struct interface *ifp, struct dhcp6_message *m, ssize_t len)
731{
732        struct dhcp6_state *state;
733        const struct dhcp6_option *co;
734        struct dhcp6_option *o;
735
736        co = dhcp6_getmoption(D6_OPTION_AUTH, m, len);
737        if (co == NULL)
738                return -1;
739
740        o = __UNCONST(co);
741        state = D6_STATE(ifp);
742
743        return dhcp_auth_encode(&ifp->options->auth, state->auth.token,
744            (uint8_t *)state->send, state->send_len,
745            6, state->send->type,
746            D6_OPTION_DATA(o), ntohs(o->len));
747}
748
749static int
750dhcp6_sendmessage(struct interface *ifp, void (*callback)(void *))
751{
752        struct dhcp6_state *state;
753        struct sockaddr_in6 to;
754        struct cmsghdr *cm;
755        struct in6_pktinfo pi;
756        struct timeval RTprev;
757        double rnd;
758        suseconds_t ms;
759        uint8_t neg;
760        const char *broad_uni;
761
762        memset(&to, 0, sizeof(to));
763        to.sin6_family = AF_INET6;
764        to.sin6_port = htons(DHCP6_SERVER_PORT);
765#ifdef SIN6_LEN
766        to.sin6_len = sizeof(to);
767#endif
768
769        state = D6_STATE(ifp);
770        /* We need to ensure we have sufficient scope to unicast the address */
771        /* XXX FIXME: We should check any added addresses we have like from
772         * a Router Advertisement */
773        if (IN6_IS_ADDR_UNSPECIFIED(&state->unicast) ||
774            (state->state == DH6S_REQUEST &&
775            (!IN6_IS_ADDR_LINKLOCAL(&state->unicast) || !ipv6_linklocal(ifp))))
776        {
777                to.sin6_addr = in6addr_linklocal_alldhcp;
778                broad_uni = "broadcasting";
779        } else {
780                to.sin6_addr = state->unicast;
781                broad_uni = "unicasting";
782        }
783
784        if (!callback)
785                syslog(LOG_DEBUG, "%s: %s %s with xid 0x%02x%02x%02x",
786                    ifp->name,
787                    broad_uni,
788                    dhcp6_get_op(state->send->type),
789                    state->send->xid[0],
790                    state->send->xid[1],
791                    state->send->xid[2]);
792        else {
793                if (state->IMD) {
794                        /* Some buggy PPP servers close the link too early
795                         * after sending an invalid status in their reply
796                         * which means this host won't see it.
797                         * 1 second grace seems to be the sweet spot. */
798                        if (ifp->flags & IFF_POINTOPOINT)
799                                state->RT.tv_sec = 1;
800                        else
801                                state->RT.tv_sec = 0;
802                        state->RT.tv_usec = arc4random() %
803                            (state->IMD * 1000000);
804                        timernorm(&state->RT);
805                        broad_uni = "delaying";
806                        goto logsend;
807                }
808                if (state->RTC == 0) {
809                        RTprev.tv_sec = state->IRT;
810                        RTprev.tv_usec = 0;
811                        state->RT.tv_sec = RTprev.tv_sec;
812                        state->RT.tv_usec = 0;
813                } else {
814                        RTprev = state->RT;
815                        timeradd(&state->RT, &state->RT, &state->RT);
816                }
817
818                rnd = DHCP6_RAND_MIN;
819                rnd += arc4random() % (DHCP6_RAND_MAX - DHCP6_RAND_MIN);
820                rnd /= 1000;
821                neg = (rnd < 0.0);
822                if (neg)
823                        rnd = -rnd;
824                tv_to_ms(ms, &RTprev);
825                ms *= rnd;
826                ms_to_tv(&RTprev, ms);
827                if (neg)
828                        timersub(&state->RT, &RTprev, &state->RT);
829                else
830                        timeradd(&state->RT, &RTprev, &state->RT);
831
832                if (state->RT.tv_sec > state->MRT) {
833                        RTprev.tv_sec = state->MRT;
834                        RTprev.tv_usec = 0;
835                        state->RT.tv_sec = state->MRT;
836                        state->RT.tv_usec = 0;
837                        tv_to_ms(ms, &RTprev);
838                        ms *= rnd;
839                        ms_to_tv(&RTprev, ms);
840                        if (neg)
841                                timersub(&state->RT, &RTprev, &state->RT);
842                        else
843                                timeradd(&state->RT, &RTprev, &state->RT);
844                }
845
846logsend:
847                syslog(LOG_DEBUG,
848                    "%s: %s %s (xid 0x%02x%02x%02x),"
849                    " next in %0.1f seconds",
850                    ifp->name,
851                    broad_uni,
852                    dhcp6_get_op(state->send->type),
853                    state->send->xid[0],
854                    state->send->xid[1],
855                    state->send->xid[2],
856                    timeval_to_double(&state->RT));
857
858                /* Wait the initial delay */
859                if (state->IMD) {
860                        state->IMD = 0;
861                        eloop_timeout_add_tv(&state->RT, callback, ifp);
862                        return 0;
863                }
864        }
865
866        /* Update the elapsed time */
867        dhcp6_updateelapsed(ifp, state->send, state->send_len);
868        if (ifp->options->auth.options & DHCPCD_AUTH_SEND &&
869            dhcp6_update_auth(ifp, state->send, state->send_len) == -1)
870        {
871                syslog(LOG_ERR, "%s: dhcp6_updateauth: %m", ifp->name);
872                return -1;
873        }
874
875        to.sin6_scope_id = ifp->index;
876        sndhdr.msg_name = (caddr_t)&to;
877        sndhdr.msg_iov[0].iov_base = (caddr_t)state->send;
878        sndhdr.msg_iov[0].iov_len = state->send_len;
879
880        /* Set the outbound interface */
881        cm = CMSG_FIRSTHDR(&sndhdr);
882        cm->cmsg_level = IPPROTO_IPV6;
883        cm->cmsg_type = IPV6_PKTINFO;
884        cm->cmsg_len = CMSG_LEN(sizeof(pi));
885        memset(&pi, 0, sizeof(pi));
886        pi.ipi6_ifindex = ifp->index;
887        memcpy(CMSG_DATA(cm), &pi, sizeof(pi));
888
889        if (sendmsg(sock, &sndhdr, 0) == -1) {
890                syslog(LOG_ERR, "%s: %s: sendmsg: %m", ifp->name, __func__);
891                ifp->options->options &= ~DHCPCD_IPV6;
892                dhcp6_drop(ifp, "EXPIRE6");
893                return -1;
894        }
895
896        state->RTC++;
897        if (callback) {
898                if (state->MRC == 0 || state->RTC < state->MRC)
899                        eloop_timeout_add_tv(&state->RT, callback, ifp);
900                else if (state->MRC != 0 && state->MRCcallback)
901                        eloop_timeout_add_tv(&state->RT, state->MRCcallback,
902                            ifp);
903                else
904                        syslog(LOG_WARNING, "%s: sent %d times with no reply",
905                            ifp->name, state->RTC);
906        }
907        return 0;
908}
909
910static void
911dhcp6_sendinform(void *arg)
912{
913
914        dhcp6_sendmessage(arg, dhcp6_sendinform);
915}
916
917static void
918dhcp6_senddiscover(void *arg)
919{
920
921        dhcp6_sendmessage(arg, dhcp6_senddiscover);
922}
923
924static void
925dhcp6_sendrequest(void *arg)
926{
927
928        dhcp6_sendmessage(arg, dhcp6_sendrequest);
929}
930
931static void
932dhcp6_sendrebind(void *arg)
933{
934
935        dhcp6_sendmessage(arg, dhcp6_sendrebind);
936}
937
938static void
939dhcp6_sendrenew(void *arg)
940{
941
942        dhcp6_sendmessage(arg, dhcp6_sendrenew);
943}
944
945static void
946dhcp6_sendconfirm(void *arg)
947{
948
949        dhcp6_sendmessage(arg, dhcp6_sendconfirm);
950}
951
952/*
953static void
954dhcp6_sendrelease(void *arg)
955{
956
957        dhcp6_sendmessage(arg, dhcp6_sendrelease);
958}
959*/
960
961static void
962dhcp6_startrenew(void *arg)
963{
964        struct interface *ifp;
965        struct dhcp6_state *state;
966
967        ifp = arg;
968        state = D6_STATE(ifp);
969        state->state = DH6S_RENEW;
970        state->start_uptime = uptime();
971        state->RTC = 0;
972        state->IRT = REN_TIMEOUT;
973        state->MRT = REN_MAX_RT;
974        state->MRC = 0;
975
976        if (dhcp6_makemessage(ifp) == -1)
977                syslog(LOG_ERR, "%s: dhcp6_makemessage: %m", ifp->name);
978        else
979                dhcp6_sendrenew(ifp);
980}
981
982static void
983dhcp6_startdiscover(void *arg)
984{
985        struct interface *ifp;
986        struct dhcp6_state *state;
987
988        ifp = arg;
989        dhcp6_delete_delegates(ifp);
990        syslog(LOG_INFO, "%s: soliciting a DHCPv6 lease", ifp->name);
991        state = D6_STATE(ifp);
992        state->state = DH6S_DISCOVER;
993        state->start_uptime = uptime();
994        state->RTC = 0;
995        state->IMD = SOL_MAX_DELAY;
996        state->IRT = SOL_TIMEOUT;
997        state->MRT = SOL_MAX_RT;
998        state->MRC = 0;
999
1000        eloop_timeout_delete(NULL, ifp);
1001        free(state->new);
1002        state->new = NULL;
1003        state->new_len = 0;
1004
1005        dhcp6_freedrop_addrs(ifp, 0, NULL);
1006        unlink(state->leasefile);
1007
1008        if (dhcp6_makemessage(ifp) == -1)
1009                syslog(LOG_ERR, "%s: dhcp6_makemessage: %m", ifp->name);
1010        else
1011                dhcp6_senddiscover(ifp);
1012}
1013
1014static void
1015dhcp6_failconfirm(void *arg)
1016{
1017        struct interface *ifp;
1018
1019        ifp = arg;
1020        syslog(LOG_ERR, "%s: failed to confirm prior address", ifp->name);
1021        /* Section 18.1.2 says that we SHOULD use the last known
1022         * IP address(s) and lifetimes if we didn't get a reply.
1023         * I disagree with this. */
1024        dhcp6_startdiscover(ifp);
1025}
1026
1027static void
1028dhcp6_failrequest(void *arg)
1029{
1030        struct interface *ifp;
1031
1032        ifp = arg;
1033        syslog(LOG_ERR, "%s: failed to request address", ifp->name);
1034        /* Section 18.1.1 says that client local policy dictates
1035         * what happens if a REQUEST fails.
1036         * Of the possible scenarios listed, moving back to the
1037         * DISCOVER phase makes more sense for us. */
1038        dhcp6_startdiscover(ifp);
1039}
1040
1041static void
1042dhcp6_failrebind(void *arg)
1043{
1044        struct interface *ifp;
1045
1046        ifp = arg;
1047        syslog(LOG_ERR, "%s: failed to rebind prior delegation", ifp->name);
1048        dhcp6_delete_delegates(ifp);
1049        /* Section 18.1.2 says that we SHOULD use the last known
1050         * IP address(s) and lifetimes if we didn't get a reply.
1051         * I disagree with this. */
1052        dhcp6_startdiscover(ifp);
1053}
1054
1055static void
1056dhcp6_startrebind(void *arg)
1057{
1058        struct interface *ifp;
1059        struct dhcp6_state *state;
1060
1061        ifp = arg;
1062        eloop_timeout_delete(dhcp6_sendrenew, ifp);
1063        state = D6_STATE(ifp);
1064        if (state->state == DH6S_RENEW)
1065                syslog(LOG_WARNING, "%s: failed to renew DHCPv6, rebinding",
1066                    ifp->name);
1067        state->state = DH6S_REBIND;
1068        state->RTC = 0;
1069        state->MRC = 0;
1070
1071        /* RFC 3633 section 12.1 */
1072        if (ifp->options->ia_type == D6_OPTION_IA_PD) {
1073                syslog(LOG_INFO, "%s: confirming Prefix Delegation", ifp->name);
1074                state->IMD = CNF_MAX_DELAY;
1075                state->IRT = CNF_TIMEOUT;
1076                state->MRT = CNF_MAX_RT;
1077        } else {
1078                state->IRT = REB_TIMEOUT;
1079                state->MRT = REB_MAX_RT;
1080        }
1081
1082        if (dhcp6_makemessage(ifp) == -1)
1083                syslog(LOG_ERR, "%s: dhcp6_makemessage: %m", ifp->name);
1084        else
1085                dhcp6_sendrebind(ifp);
1086
1087        /* RFC 3633 section 12.1 */
1088        if (ifp->options->ia_type == D6_OPTION_IA_PD)
1089                eloop_timeout_add_sec(CNF_MAX_RD, dhcp6_failrebind, ifp);
1090}
1091
1092
1093static void
1094dhcp6_startrequest(struct interface *ifp)
1095{
1096        struct dhcp6_state *state;
1097
1098        eloop_timeout_delete(dhcp6_senddiscover, ifp);
1099        state = D6_STATE(ifp);
1100        state->state = DH6S_REQUEST;
1101        state->RTC = 0;
1102        state->IRT = REQ_TIMEOUT;
1103        state->MRT = REQ_MAX_RT;
1104        state->MRC = REQ_MAX_RC;
1105        state->MRCcallback = dhcp6_failrequest;
1106
1107        if (dhcp6_makemessage(ifp) == -1) {
1108                syslog(LOG_ERR, "%s: dhcp6_makemessage: %m", ifp->name);
1109                return;
1110        }
1111
1112        dhcp6_sendrequest(ifp);
1113}
1114
1115static void
1116dhcp6_startconfirm(struct interface *ifp)
1117{
1118        struct dhcp6_state *state;
1119
1120        state = D6_STATE(ifp);
1121        state->state = DH6S_CONFIRM;
1122        state->start_uptime = uptime();
1123        state->RTC = 0;
1124        state->IMD = CNF_MAX_DELAY;
1125        state->IRT = CNF_TIMEOUT;
1126        state->MRT = CNF_MAX_RT;
1127        state->MRC = 0;
1128
1129        syslog(LOG_INFO, "%s: confirming prior DHCPv6 lease", ifp->name);
1130        if (dhcp6_makemessage(ifp) == -1) {
1131                syslog(LOG_ERR, "%s: dhcp6_makemessage: %m", ifp->name);
1132                return;
1133        }
1134        dhcp6_sendconfirm(ifp);
1135        eloop_timeout_add_sec(CNF_MAX_RD, dhcp6_failconfirm, ifp);
1136}
1137
1138static void
1139dhcp6_startinform(void *arg)
1140{
1141        struct interface *ifp;
1142        struct dhcp6_state *state;
1143
1144        ifp = arg;
1145        state = D6_STATE(ifp);
1146        if (state->new == NULL || ifp->options->options & DHCPCD_DEBUG)
1147                syslog(LOG_INFO, "%s: requesting DHCPv6 information",
1148                    ifp->name);
1149        state->state = DH6S_INFORM;
1150        state->start_uptime = uptime();
1151        state->RTC = 0;
1152        state->IMD = INF_MAX_DELAY;
1153        state->IRT = INF_TIMEOUT;
1154        state->MRT = INF_MAX_RT;
1155        state->MRC = 0;
1156
1157        if (dhcp6_makemessage(ifp) == -1)
1158                syslog(LOG_ERR, "%s: dhcp6_makemessage: %m", ifp->name);
1159        else
1160                dhcp6_sendinform(ifp);
1161}
1162
1163static void
1164dhcp6_startexpire(void *arg)
1165{
1166        struct interface *ifp;
1167
1168        ifp = arg;
1169        eloop_timeout_delete(dhcp6_sendrebind, ifp);
1170
1171        syslog(LOG_ERR, "%s: DHCPv6 lease expired", ifp->name);
1172        dhcp6_freedrop_addrs(ifp, 1, NULL);
1173        dhcp6_delete_delegates(ifp);
1174        script_runreason(ifp, "EXPIRE6");
1175        dhcp6_startdiscover(ifp);
1176}
1177
1178static void
1179dhcp6_startrelease(struct interface *ifp)
1180{
1181        struct dhcp6_state *state;
1182
1183        state = D6_STATE(ifp);
1184        if (state->state != DH6S_BOUND)
1185                return;
1186
1187        state->state = DH6S_RELEASE;
1188        state->start_uptime = uptime();
1189        state->RTC = 0;
1190        state->IRT = REL_TIMEOUT;
1191        state->MRT = 0;
1192        state->MRC = REL_MAX_RC;
1193        //state->MRCcallback = dhcp6_failrelease;
1194        state->MRCcallback = NULL;
1195
1196        if (dhcp6_makemessage(ifp) == -1)
1197                syslog(LOG_ERR, "%s: dhcp6_makemessage: %m", ifp->name);
1198        else
1199                /* XXX: We should loop a few times
1200                 * Luckily RFC3315 section 18.1.6 says this is optional */
1201                //dhcp6_sendrelease(ifp);
1202                dhcp6_sendmessage(ifp, NULL);
1203}
1204
1205static int dhcp6_getstatus(const struct dhcp6_option *o)
1206{
1207        uint16_t code;
1208        char *nstatus;
1209        size_t len;
1210        const uint8_t *p;
1211
1212        len = ntohs(o->len);
1213        if (len < sizeof(code)) {
1214                syslog(LOG_ERR, "status truncated");
1215                return -1;
1216        }
1217        if (ntohs(o->code) != D6_OPTION_STATUS_CODE) {
1218                /* unlikely */
1219                syslog(LOG_ERR, "not a status");
1220                return -1;
1221        }
1222        p = D6_COPTION_DATA(o);
1223        len = ntohs(o->len);
1224        memcpy(&code, p, sizeof(code));
1225        code = ntohs(code);
1226        len -= sizeof(code);
1227
1228        if (len == 0) {
1229                if (code < sizeof(dhcp6_statuses) / sizeof(char *)) {
1230                        p = (const uint8_t *)dhcp6_statuses[code];
1231                        len = strlen((const char *)p);
1232                } else
1233                        p = NULL;
1234        } else {
1235                p = D6_COPTION_DATA(o) + sizeof(uint16_t);
1236        }
1237        if (status == NULL || len + 1 > status_len) {
1238                status_len = len;
1239                nstatus = realloc(status, status_len + 1);
1240                if (nstatus == NULL) {
1241                        syslog(LOG_ERR, "%s: %m", __func__);
1242                        free(status);
1243                }
1244                status = nstatus;
1245        }
1246        if (status) {
1247                memcpy(status, p, len);
1248                status[len] = '\0';
1249        }
1250        return code;
1251}
1252
1253static int
1254dhcp6_checkstatusok(const struct interface *ifp,
1255    const struct dhcp6_message *m, const uint8_t *p, size_t len)
1256{
1257        const struct dhcp6_option *o;
1258
1259        if (p)
1260                o = dhcp6_findoption(D6_OPTION_STATUS_CODE, p, len);
1261        else
1262                o = dhcp6_getmoption(D6_OPTION_STATUS_CODE, m, len);
1263        if (o == NULL) {
1264                //syslog(LOG_DEBUG, "%s: no status", ifp->name);
1265                return 0;
1266        }
1267        if (dhcp6_getstatus(o) != D6_STATUS_OK) {
1268                syslog(LOG_ERR, "%s: DHCPv6 REPLY: %s", ifp->name, status);
1269                return -1;
1270        }
1271        //syslog(LOG_DEBUG, "%s: status: %s", ifp->name, status);
1272        return 1;
1273}
1274
1275static struct ipv6_addr *
1276dhcp6_findaddr(struct interface *ifp, const struct in6_addr *addr)
1277{
1278        const struct dhcp6_state *state;
1279        struct ipv6_addr *ap;
1280
1281        state = D6_CSTATE(ifp);
1282        if (state) {
1283                TAILQ_FOREACH(ap, &state->addrs, next) {
1284                        if (addr == NULL) {
1285                                if ((ap->flags &
1286                                    (IPV6_AF_ADDED | IPV6_AF_DADCOMPLETED)) ==
1287                                    (IPV6_AF_ADDED | IPV6_AF_DADCOMPLETED))
1288                                        return ap;
1289                        } else if (IN6_ARE_ADDR_EQUAL(&ap->addr, addr))
1290                                return ap;
1291                }
1292        }
1293        return NULL;
1294}
1295
1296int
1297dhcp6_addrexists(const struct ipv6_addr *addr)
1298{
1299        struct interface *ifp;
1300
1301        TAILQ_FOREACH(ifp, ifaces, next) {
1302                if (dhcp6_findaddr(ifp, addr == NULL ? NULL : &addr->addr))
1303                        return 1;
1304        }
1305        return 0;
1306}
1307
1308static void
1309dhcp6_dadcallback(void *arg)
1310{
1311        struct ipv6_addr *ap = arg;
1312        struct interface *ifp;
1313        struct dhcp6_state *state;
1314        int wascompleted;
1315
1316        wascompleted = (ap->flags & IPV6_AF_DADCOMPLETED);
1317        ipv6nd_cancelprobeaddr(ap);
1318        ap->flags |= IPV6_AF_DADCOMPLETED;
1319        if (ap->flags & IPV6_AF_DUPLICATED)
1320                /* XXX FIXME
1321                 * We should decline the address */
1322                syslog(LOG_WARNING, "%s: DAD detected %s",
1323                    ap->iface->name, ap->saddr);
1324#ifdef IPV6_SEND_DAD
1325        else
1326                ipv6_addaddr(ap);
1327#endif
1328
1329        if (!wascompleted) {
1330                ifp = ap->iface;
1331                state = D6_STATE(ifp);
1332                if (state->state == DH6S_BOUND ||
1333                    state->state == DH6S_DELEGATED)
1334                {
1335                        TAILQ_FOREACH(ap, &state->addrs, next) {
1336                                if ((ap->flags & IPV6_AF_DADCOMPLETED) == 0) {
1337                                        wascompleted = 1;
1338                                        break;
1339                                }
1340                        }
1341                        if (!wascompleted) {
1342                                syslog(LOG_DEBUG, "%s: DHCPv6 DAD completed",
1343                                    ifp->name);
1344                                script_runreason(ifp, state->reason);
1345                                daemonise();
1346                        }
1347                }
1348        }
1349}
1350
1351static int
1352dhcp6_findna(struct interface *ifp, const uint8_t *iaid,
1353    const uint8_t *d, size_t l)
1354{
1355        struct dhcp6_state *state;
1356        const struct dhcp6_option *o;
1357        const uint8_t *p;
1358        struct in6_addr in6;
1359        struct ipv6_addr *a;
1360        char iabuf[INET6_ADDRSTRLEN];
1361        const char *ia;
1362        int i;
1363        uint32_t u32;
1364
1365        i = 0;
1366        state = D6_STATE(ifp);
1367        while ((o = dhcp6_findoption(D6_OPTION_IA_ADDR, d, l))) {
1368                l -= ((const uint8_t *)o - d);
1369                d += ((const uint8_t *)o - d);
1370                u32 = ntohs(o->len);
1371                l -= sizeof(*o) + u32;
1372                d += sizeof(*o) + u32;
1373                if (u32 < 24) {
1374                        errno = EINVAL;
1375                        syslog(LOG_ERR, "%s: IA Address option truncated",
1376                            ifp->name);
1377                        continue;
1378                }
1379                p = D6_COPTION_DATA(o);
1380                memcpy(&in6.s6_addr, p, sizeof(in6.s6_addr));
1381                p += sizeof(in6.s6_addr);
1382                a = dhcp6_findaddr(ifp, &in6);
1383                if (a == NULL) {
1384                        a = calloc(1, sizeof(*a));
1385                        if (a == NULL) {
1386                                syslog(LOG_ERR, "%s: %m", __func__);
1387                                break;
1388                        }
1389                        a->iface = ifp;
1390                        a->flags = IPV6_AF_NEW | IPV6_AF_ONLINK;
1391                        a->dadcallback = dhcp6_dadcallback;
1392                        memcpy(a->iaid, iaid, sizeof(a->iaid));
1393                        memcpy(&a->addr.s6_addr, &in6.s6_addr,
1394                            sizeof(in6.s6_addr));
1395
1396                        /*
1397                         * RFC 5942 Section 5
1398                         * We cannot assume any prefix length, nor tie the
1399                         * address to an existing one as it could expire
1400                         * before the address.
1401                         * As such we just give it a 128 prefix.
1402                         */
1403                        a->prefix_len = 128;
1404                        if (ipv6_makeprefix(&a->prefix, &a->addr,
1405                            a->prefix_len) == -1)
1406                        {
1407                                syslog(LOG_ERR, "%s: %m", __func__);
1408                                free(a);
1409                                continue;
1410                        }
1411                        ia = inet_ntop(AF_INET6, &a->addr.s6_addr,
1412                            iabuf, sizeof(iabuf));
1413                        snprintf(a->saddr, sizeof(a->saddr),
1414                            "%s/%d", ia, a->prefix_len);
1415                }
1416                memcpy(&u32, p, sizeof(u32));
1417                a->prefix_pltime = ntohl(u32);
1418                p += sizeof(u32);
1419                memcpy(&u32, p, sizeof(u32));
1420                u32 = ntohl(u32);
1421                if (a->prefix_vltime != u32) {
1422                        a->flags |= IPV6_AF_NEW;
1423                        a->prefix_vltime = u32;
1424                }
1425                if (a->prefix_pltime && a->prefix_pltime < state->lowpl)
1426                    state->lowpl = a->prefix_pltime;
1427                if (a->prefix_vltime && a->prefix_vltime > state->expire)
1428                    state->expire = a->prefix_vltime;
1429                if (a->flags & IPV6_AF_STALE)
1430                        a->flags &= ~IPV6_AF_STALE;
1431                else
1432                        TAILQ_INSERT_TAIL(&state->addrs, a, next);
1433                i++;
1434        }
1435        return i;
1436}
1437
1438static int
1439dhcp6_findpd(struct interface *ifp, const uint8_t *iaid,
1440    const uint8_t *d, size_t l)
1441{
1442        struct dhcp6_state *state;
1443        const struct dhcp6_option *o;
1444        const uint8_t *p;
1445        struct ipv6_addr *a;
1446        char iabuf[INET6_ADDRSTRLEN];
1447        const char *ia;
1448        int i;
1449        uint8_t u8, len;
1450        uint32_t u32, pltime, vltime;
1451        struct in6_addr prefix;
1452
1453        i = 0;
1454        state = D6_STATE(ifp);
1455        while ((o = dhcp6_findoption(D6_OPTION_IAPREFIX, d, l))) {
1456                l -= ((const uint8_t *)o - d);
1457                d += ((const uint8_t *)o - d);
1458                u32 = ntohs(o->len);
1459                l -= sizeof(*o) + u32;
1460                d += sizeof(*o) + u32;
1461                if (u32 < 25) {
1462                        errno = EINVAL;
1463                        syslog(LOG_ERR, "%s: IA Prefix option truncated",
1464                            ifp->name);
1465                        continue;
1466                }
1467                p = D6_COPTION_DATA(o);
1468                memcpy(&u32, p, sizeof(u32));
1469                pltime = ntohl(u32);
1470                p += sizeof(u32);
1471                memcpy(&u32, p, sizeof(u32));
1472                p += sizeof(u32);
1473                vltime = ntohl(u32);
1474                memcpy(&u8, p, sizeof(u8));
1475                p += sizeof(u8);
1476                len = u8;
1477                memcpy(&prefix.s6_addr, p, sizeof(prefix.s6_addr));
1478                p += sizeof(prefix.s6_addr);
1479
1480                TAILQ_FOREACH(a, &state->addrs, next) {
1481                        if (IN6_ARE_ADDR_EQUAL(&a->prefix, &prefix))
1482                                break;
1483                }
1484                if (a == NULL) {
1485                        a = calloc(1, sizeof(*a));
1486                        if (a == NULL) {
1487                                syslog(LOG_ERR, "%s: %m", __func__);
1488                                break;
1489                        }
1490                        a->iface = ifp;
1491                        a->flags = IPV6_AF_NEW;
1492                        a->dadcallback = dhcp6_dadcallback;
1493                        memcpy(a->iaid, iaid, sizeof(a->iaid));
1494                        memcpy(&a->prefix.s6_addr,
1495                            &prefix.s6_addr, sizeof(a->prefix.s6_addr));
1496                        a->prefix_len = len;
1497                        ia = inet_ntop(AF_INET6, &a->prefix.s6_addr,
1498                            iabuf, sizeof(iabuf));
1499                        snprintf(a->saddr, sizeof(a->saddr),
1500                            "%s/%d", ia, a->prefix_len);
1501                } else if (a->prefix_vltime != vltime)
1502                        a->flags |= IPV6_AF_NEW;
1503
1504                a->prefix_pltime = pltime;
1505                a->prefix_vltime = vltime;
1506                if (a->prefix_pltime && a->prefix_pltime < state->lowpl)
1507                        state->lowpl = a->prefix_pltime;
1508                if (a->prefix_vltime && a->prefix_vltime > state->expire)
1509                        state->expire = a->prefix_vltime;
1510                if (a->flags & IPV6_AF_STALE)
1511                        a->flags &= ~IPV6_AF_STALE;
1512                else
1513                        TAILQ_INSERT_TAIL(&state->addrs, a, next);
1514                i++;
1515        }
1516        return i;
1517}
1518
1519static int
1520dhcp6_findia(struct interface *ifp, const uint8_t *d, size_t l,
1521    const char *sfrom)
1522{
1523        struct dhcp6_state *state;
1524        const struct if_options *ifo;
1525        const struct dhcp6_option *o;
1526        const uint8_t *p;
1527        int i;
1528        uint32_t u32, renew, rebind;
1529        uint8_t iaid[4];
1530        size_t ol;
1531        struct ipv6_addr *ap, *nap;
1532
1533        ifo = ifp->options;
1534        i = 0;
1535        state = D6_STATE(ifp);
1536        TAILQ_FOREACH(ap, &state->addrs, next) {
1537                ap->flags |= IPV6_AF_STALE;
1538        }
1539        while ((o = dhcp6_findoption(ifo->ia_type, d, l))) {
1540                l -= ((const uint8_t *)o - d);
1541                d += ((const uint8_t *)o - d);
1542                ol = ntohs(o->len);
1543                l -= sizeof(*o) + ol;
1544                d += sizeof(*o) + ol;
1545                u32 = ifo->ia_type == D6_OPTION_IA_TA ? 4 : 12;
1546                if (ol < u32) {
1547                        errno = EINVAL;
1548                        syslog(LOG_ERR, "%s: IA option truncated", ifp->name);
1549                        continue;
1550                }
1551
1552                p = D6_COPTION_DATA(o);
1553                memcpy(iaid, p, sizeof(iaid));
1554                p += sizeof(iaid);
1555                ol -= sizeof(iaid);
1556                if (ifo->ia_type != D6_OPTION_IA_TA) {
1557                        memcpy(&u32, p, sizeof(u32));
1558                        renew = ntohl(u32);
1559                        p += sizeof(u32);
1560                        ol -= sizeof(u32);
1561                        memcpy(&u32, p, sizeof(u32));
1562                        rebind = ntohl(u32);
1563                        p += sizeof(u32);
1564                        ol -= sizeof(u32);
1565                        if (renew > rebind && rebind > 0) {
1566                                if (sfrom)
1567                                    syslog(LOG_WARNING,
1568                                        "%s: T1 (%d) > T2 (%d) from %s",
1569                                        ifp->name, renew, rebind, sfrom);
1570                                renew = 0;
1571                                rebind = 0;
1572                        }
1573                        if (renew != 0 &&
1574                            (renew < state->renew || state->renew == 0))
1575                                state->renew = renew;
1576                        if (rebind != 0 &&
1577                            (rebind < state->rebind || state->rebind == 0))
1578                                state->rebind = rebind;
1579                }
1580                if (dhcp6_checkstatusok(ifp, NULL, p, ol) == -1)
1581                        return -1;
1582                if (ifo->ia_type == D6_OPTION_IA_PD) {
1583                        if (dhcp6_findpd(ifp, iaid, p, ol) == 0) {
1584                                syslog(LOG_ERR,
1585                                    "%s: %s: DHCPv6 REPLY missing Prefix",
1586                                    ifp->name, sfrom);
1587                                return -1;
1588                        }
1589                } else {
1590                        if (dhcp6_findna(ifp, iaid, p, ol) == 0) {
1591                                syslog(LOG_ERR,
1592                                    "%s: %s: DHCPv6 REPLY missing IA Address",
1593                                    ifp->name, sfrom);
1594                                return -1;
1595                        }
1596                }
1597                i++;
1598        }
1599        TAILQ_FOREACH_SAFE(ap, &state->addrs, next, nap) {
1600                if (ap->flags & IPV6_AF_STALE) {
1601                        TAILQ_REMOVE(&state->addrs, ap, next);
1602                        if (ap->dadcallback)
1603                                eloop_q_timeout_delete(0, NULL,
1604                                    ap->dadcallback);
1605                        free(ap);
1606                }
1607        }
1608        return i;
1609}
1610
1611static int
1612dhcp6_validatelease(struct interface *ifp,
1613    const struct dhcp6_message *m, size_t len,
1614    const char *sfrom)
1615{
1616        struct dhcp6_state *state;
1617        const struct dhcp6_option *o;
1618
1619        state = D6_STATE(ifp);
1620        o = dhcp6_getmoption(ifp->options->ia_type, m, len);
1621        if (o == NULL) {
1622                if (sfrom &&
1623                    dhcp6_checkstatusok(ifp, m, NULL, len) != -1)
1624                        syslog(LOG_ERR, "%s: no IA in REPLY from %s",
1625                            ifp->name, sfrom);
1626                return -1;
1627        }
1628
1629        if (dhcp6_checkstatusok(ifp, m, NULL, len) == -1)
1630                return -1;
1631
1632        state->renew = state->rebind = state->expire = 0;
1633        state->lowpl = ND6_INFINITE_LIFETIME;
1634        len -= (const char *)o - (const char *)m;
1635        return dhcp6_findia(ifp, (const uint8_t *)o, len, sfrom);
1636}
1637
1638static ssize_t
1639dhcp6_writelease(const struct interface *ifp)
1640{
1641        const struct dhcp6_state *state;
1642        int fd;
1643        ssize_t bytes;
1644
1645        state = D6_CSTATE(ifp);
1646        syslog(LOG_DEBUG, "%s: writing lease `%s'",
1647            ifp->name, state->leasefile);
1648
1649        fd = open(state->leasefile, O_WRONLY | O_CREAT | O_TRUNC, 0644);
1650        if (fd == -1) {
1651                syslog(LOG_ERR, "%s: dhcp6_writelease: %m", ifp->name);
1652                return -1;
1653        }
1654        bytes = write(fd, state->new, state->new_len);
1655        close(fd);
1656        return bytes;
1657}
1658
1659static int
1660dhcp6_readlease(struct interface *ifp)
1661{
1662        struct dhcp6_state *state;
1663        struct stat st;
1664        int fd;
1665        ssize_t bytes;
1666        struct timeval now;
1667        const struct dhcp6_option *o;
1668
1669        state = D6_STATE(ifp);
1670        if (stat(state->leasefile, &st) == -1) {
1671                if (errno == ENOENT)
1672                        return 0;
1673                return -1;
1674        }
1675        syslog(LOG_DEBUG, "%s: reading lease `%s'",
1676            ifp->name, state->leasefile);
1677        state->new = malloc(st.st_size);
1678        if (state->new == NULL)
1679                return -1;
1680        state->new_len = st.st_size;
1681        fd = open(state->leasefile, O_RDONLY);
1682        if (fd == -1)
1683                return -1;
1684        bytes = read(fd, state->new, state->new_len);
1685        close(fd);
1686        if (bytes < (ssize_t)state->new_len) {
1687                syslog(LOG_ERR, "%s: read: %m", __func__);
1688                goto ex;
1689        }
1690
1691        /* Check to see if the lease is still valid */
1692        fd = dhcp6_validatelease(ifp, state->new, state->new_len, NULL);
1693        if (fd == -1)
1694                goto ex;
1695        if (fd == 0) {
1696                syslog(LOG_INFO, "%s: lease was for different IA type",
1697                    ifp->name);
1698                goto ex;
1699        }
1700
1701        if (state->expire != ND6_INFINITE_LIFETIME) {
1702                gettimeofday(&now, NULL);
1703                if ((time_t)state->expire < now.tv_sec - st.st_mtime) {
1704                        syslog(LOG_DEBUG,"%s: discarding expired lease",
1705                            ifp->name);
1706                        goto ex;
1707                }
1708        }
1709
1710        /* Authenticate the message */
1711        o = dhcp6_getmoption(D6_OPTION_AUTH, state->new, state->new_len);
1712        if (o) {
1713                if (dhcp_auth_validate(&state->auth, &ifp->options->auth,
1714                    (uint8_t *)state->new, state->new_len, 6, state->new->type,
1715                    D6_COPTION_DATA(o), ntohs(o->len)) == NULL)
1716                {
1717                        syslog(LOG_DEBUG, "%s: dhcp_auth_validate: %m",
1718                            ifp->name);
1719                        syslog(LOG_ERR, "%s: authentication failed",
1720                            ifp->name);
1721                        goto ex;
1722                }
1723                syslog(LOG_DEBUG, "%s: validated using 0x%08" PRIu32,
1724                    ifp->name, state->auth.token->secretid);
1725        } else if (ifp->options->auth.options & DHCPCD_AUTH_REQUIRE) {
1726                syslog(LOG_ERR, "%s: authentication now required", ifp->name);
1727                goto ex;
1728        }
1729
1730        return fd;
1731
1732ex:
1733        dhcp6_freedrop_addrs(ifp, 0, NULL);
1734        free(state->new);
1735        state->new = NULL;
1736        state->new_len = 0;
1737        unlink(state->leasefile);
1738        return 0;
1739}
1740
1741static void
1742dhcp6_startinit(struct interface *ifp)
1743{
1744        struct dhcp6_state *state;
1745        int r;
1746
1747        state = D6_STATE(ifp);
1748        state->state = DH6S_INIT;
1749        state->expire = ND6_INFINITE_LIFETIME;
1750        state->lowpl = ND6_INFINITE_LIFETIME;
1751        if (!(options & DHCPCD_TEST) &&
1752            ifp->options->ia_type != D6_OPTION_IA_TA &&
1753            ifp->options->reboot != 0)
1754        {
1755                r = dhcp6_readlease(ifp);
1756                if (r == -1)
1757                        syslog(LOG_ERR, "%s: dhcp6_readlease: %s: %m",
1758                                        ifp->name, state->leasefile);
1759                else if (r != 0) {
1760                        /* RFC 3633 section 12.1 */
1761                        if (ifp->options->ia_type == D6_OPTION_IA_PD)
1762                                dhcp6_startrebind(ifp);
1763                        else
1764                                dhcp6_startconfirm(ifp);
1765                        return;
1766                }
1767        }
1768        dhcp6_startdiscover(ifp);
1769}
1770
1771static uint32_t
1772dhcp6_findsla(void)
1773{
1774        uint32_t sla;
1775        const struct interface *ifp;
1776        const struct dhcp6_state *state;
1777
1778        /* Slow, but finding the lowest free SLA is needed if we get a
1779         * /62 or /63 prefix from upstream */
1780        for (sla = 0; sla < UINT32_MAX; sla++) {
1781                TAILQ_FOREACH(ifp, ifaces, next) {
1782                        state = D6_CSTATE(ifp);
1783                        if (state && state->sla_set && state->sla == sla)
1784                                break;
1785                }
1786                if (ifp == NULL)
1787                        return sla;
1788        }
1789
1790        errno = E2BIG;
1791        return 0;
1792}
1793
1794static struct ipv6_addr *
1795dhcp6_delegate_addr(struct interface *ifp, const struct ipv6_addr *prefix,
1796    const struct if_sla *sla, struct interface *ifs)
1797{
1798        struct dhcp6_state *state;
1799        struct if_sla asla;
1800        struct in6_addr addr;
1801        struct ipv6_addr *a, *ap, *apn;
1802        char iabuf[INET6_ADDRSTRLEN];
1803        const char *ia;
1804
1805        state = D6_STATE(ifp);
1806        if (state == NULL) {
1807                ifp->if_data[IF_DATA_DHCP6] = calloc(1, sizeof(*state));
1808                state = D6_STATE(ifp);
1809                if (state == NULL) {
1810                        syslog(LOG_ERR, "%s: %m", __func__);
1811                        return NULL;
1812                }
1813
1814                TAILQ_INIT(&state->addrs);
1815                state->state = DH6S_DELEGATED;
1816                state->reason = "DELEGATED6";
1817        }
1818
1819        if (sla == NULL || sla->sla_set == 0) {
1820                if (!state->sla_set) {
1821                        errno = 0;
1822                        state->sla = dhcp6_findsla();
1823                        if (errno) {
1824                                syslog(LOG_ERR, "%s: dhcp6_find_sla: %m",
1825                                    ifp->name);
1826                                return NULL;
1827                        }
1828                        syslog(LOG_DEBUG, "%s: set SLA %d",
1829                            ifp->name, state->sla);
1830                        state->sla_set = 1;
1831                }
1832                asla.sla = state->sla;
1833                asla.prefix_len = 64;
1834                sla = &asla;
1835        }
1836
1837        if (ipv6_userprefix(&prefix->prefix, prefix->prefix_len,
1838                sla->sla, &addr, sla->prefix_len) == -1)
1839        {
1840                ia = inet_ntop(AF_INET6, &prefix->prefix.s6_addr,
1841                    iabuf, sizeof(iabuf));
1842                syslog(LOG_ERR, "%s: invalid prefix %s/%d + %d/%d: %m",
1843                        ifp->name, ia, prefix->prefix_len,
1844                        sla->sla, sla->prefix_len);
1845                return NULL;
1846        }
1847
1848        a = calloc(1, sizeof(*a));
1849        if (a == NULL) {
1850                syslog(LOG_ERR, "%s: %m", __func__);
1851                return NULL;
1852        }
1853        a->iface = ifp;
1854        a->flags = IPV6_AF_NEW | IPV6_AF_ONLINK;
1855        a->dadcallback = dhcp6_dadcallback;
1856        a->delegating_iface = ifs;
1857        memcpy(&a->iaid, &prefix->iaid, sizeof(a->iaid));
1858        a->prefix_pltime = prefix->prefix_pltime;
1859        a->prefix_vltime = prefix->prefix_vltime;
1860        memcpy(&a->prefix.s6_addr, &addr.s6_addr, sizeof(a->prefix.s6_addr));
1861        a->prefix_len = sla->prefix_len;
1862
1863        if (ipv6_makeaddr(&a->addr, ifp, &a->prefix, a->prefix_len) == -1)
1864        {
1865                ia = inet_ntop(AF_INET6, &a->addr.s6_addr,
1866                    iabuf, sizeof(iabuf));
1867                syslog(LOG_ERR, "%s: %m (%s/%d)", __func__, ia, a->prefix_len);
1868                free(a);
1869                return NULL;
1870        }
1871
1872        /* Remove any exiting address */
1873        TAILQ_FOREACH_SAFE(ap, &state->addrs, next, apn) {
1874                if (IN6_ARE_ADDR_EQUAL(&ap->addr, &a->addr)) {
1875                        TAILQ_REMOVE(&state->addrs, ap, next);
1876                        /* Keep our flags */
1877                        a->flags |= ap->flags;
1878                        a->flags &= ~IPV6_AF_NEW;
1879                        free(ap);
1880                }
1881        }
1882
1883        ia = inet_ntop(AF_INET6, &a->addr.s6_addr, iabuf, sizeof(iabuf));
1884        snprintf(a->saddr, sizeof(a->saddr), "%s/%d", ia, a->prefix_len);
1885        TAILQ_INSERT_TAIL(&state->addrs, a, next);
1886        return a;
1887}
1888
1889static void
1890dhcp6_delegate_prefix(struct interface *ifp)
1891{
1892        struct if_options *ifo;
1893        struct dhcp6_state *state, *ifd_state;
1894        struct ipv6_addr *ap;
1895        size_t i, j, k;
1896        struct if_ia *ia;
1897        struct if_sla *sla;
1898        struct interface *ifd;
1899        uint8_t carrier_warned;
1900
1901        ifo = ifp->options;
1902        state = D6_STATE(ifp);
1903        TAILQ_FOREACH(ifd, ifaces, next) {
1904                k = 0;
1905                carrier_warned = 0;
1906                TAILQ_FOREACH(ap, &state->addrs, next) {
1907                        if (ap->flags & IPV6_AF_NEW) {
1908                                ap->flags &= ~IPV6_AF_NEW;
1909                                syslog(LOG_DEBUG, "%s: delegated prefix %s",
1910                                    ifp->name, ap->saddr);
1911                        }
1912                        for (i = 0; i < ifo->ia_len; i++) {
1913                                ia = &ifo->ia[i];
1914                                if (memcmp(ia->iaid, ap->iaid,
1915                                    sizeof(ia->iaid)))
1916                                        continue;
1917                                if (ia->sla_len == 0) {
1918                                        /* no SLA configured, so lets
1919                                         * automate it */
1920                                        if (ifp == ifd)
1921                                                continue;
1922                                        if (ifd->carrier == LINK_DOWN) {
1923                                                syslog(LOG_DEBUG,
1924                                                    "%s: has no carrier, cannot"
1925                                                    " delegate addresses",
1926                                                    ifd->name);
1927                                                carrier_warned = 1;
1928                                                break;
1929                                        }
1930                                        if (dhcp6_delegate_addr(ifd, ap,
1931                                            NULL, ifp))
1932                                                k++;
1933                                }
1934                                for (j = 0; j < ia->sla_len; j++) {
1935                                        sla = &ia->sla[j];
1936                                        if (strcmp(ifd->name, sla->ifname))
1937                                                continue;
1938                                        if (ifd->carrier == LINK_DOWN) {
1939                                                syslog(LOG_DEBUG,
1940                                                    "%s: has no carrier, cannot"
1941                                                    " delegate addresses",
1942                                                    ifd->name);
1943                                                carrier_warned = 1;
1944                                                break;
1945                                        }
1946                                        if (dhcp6_delegate_addr(ifd, ap,
1947                                            sla, ifp))
1948                                                k++;
1949                                }
1950                                if (carrier_warned)
1951                                        break;
1952                        }
1953                        if (carrier_warned)
1954                                break;
1955                }
1956                if (k && !carrier_warned) {
1957                        ifd_state = D6_STATE(ifd);
1958                        ipv6nd_probeaddrs(&ifd_state->addrs);
1959                }
1960        }
1961
1962        /* Warn about configured interfaces for delegation that do not exist */
1963        for (i = 0; i < ifo->ia_len; i++) {
1964                ia = &ifo->ia[i];
1965                for (j = 0; j < ia->sla_len; j++) {
1966                        sla = &ia->sla[j];
1967                        for (k = 0; k < i; j++)
1968                                if (strcmp(sla->ifname, ia->sla[j].ifname) == 0)
1969                                        break;
1970                        if (j >= i && find_interface(sla->ifname) == NULL)
1971                                syslog(LOG_ERR,
1972                                    "%s: interface does not exist"
1973                                    " for delegation",
1974                                    sla->ifname);
1975                }
1976        }
1977}
1978
1979static void
1980dhcp6_find_delegates1(void *arg)
1981{
1982
1983        dhcp6_find_delegates(arg);
1984}
1985
1986int
1987dhcp6_find_delegates(struct interface *ifp)
1988{
1989        struct if_options *ifo;
1990        struct dhcp6_state *state;
1991        struct ipv6_addr *ap;
1992        size_t i, j, k;
1993        struct if_ia *ia;
1994        struct if_sla *sla;
1995        struct interface *ifd;
1996
1997        k = 0;
1998        TAILQ_FOREACH(ifd, ifaces, next) {
1999                ifo = ifd->options;
2000                if (ifo->ia_type != D6_OPTION_IA_PD)
2001                        continue;
2002                state = D6_STATE(ifd);
2003                if (state == NULL || state->state != DH6S_BOUND)
2004                        continue;
2005                TAILQ_FOREACH(ap, &state->addrs, next) {
2006                        for (i = 0; i < ifo->ia_len; i++) {
2007                                ia = &ifo->ia[i];
2008                                if (memcmp(ia->iaid, ap->iaid,
2009                                    sizeof(ia->iaid)))
2010                                        continue;
2011                                for (j = 0; j < ia->sla_len; j++) {
2012                                        sla = &ia->sla[j];
2013                                        if (strcmp(ifp->name, sla->ifname))
2014                                                continue;
2015                                        if (ipv6_linklocal(ifp) == NULL) {
2016                                                syslog(LOG_DEBUG,
2017                                                    "%s: delaying adding"
2018                                                    " delegated addresses for"
2019                                                    " LL address",
2020                                                    ifp->name);
2021                                                ipv6_addlinklocalcallback(ifp,
2022                                                    dhcp6_find_delegates1, ifp);
2023                                                return 1;
2024                                        }
2025                                        if (dhcp6_delegate_addr(ifp, ap,
2026                                            sla, ifd))
2027                                            k++;
2028                                }
2029                        }
2030                }
2031        }
2032
2033        if (k) {
2034                syslog(LOG_INFO, "%s: adding delegated prefixes", ifp->name);
2035                state = D6_STATE(ifp);
2036                state->state = DH6S_DELEGATED;
2037                ipv6nd_probeaddrs(&state->addrs);
2038                ipv6_buildroutes();
2039        }
2040        return k;
2041}
2042
2043/* ARGSUSED */
2044static void
2045dhcp6_handledata(__unused void *arg)
2046{
2047        ssize_t len;
2048        size_t i;
2049        struct cmsghdr *cm;
2050        struct in6_pktinfo pkt;
2051        struct interface *ifp;
2052        const char *sfrom, *op;
2053        struct dhcp6_message *r;
2054        struct dhcp6_state *state;
2055        const struct dhcp6_option *o;
2056        const struct dhcp_opt *opt;
2057        const struct if_options *ifo;
2058        struct ipv6_addr *ap;
2059        uint8_t has_new;
2060        int error;
2061        uint32_t u32;
2062
2063        len = recvmsg(sock, &rcvhdr, 0);
2064        if (len == -1) {
2065                syslog(LOG_ERR, "recvmsg: %m");
2066                return;
2067        }
2068        sfrom = inet_ntop(AF_INET6, &from.sin6_addr,
2069            ntopbuf, INET6_ADDRSTRLEN);
2070        if ((size_t)len < sizeof(struct dhcp6_message)) {
2071                syslog(LOG_ERR, "DHCPv6 RA packet too short from %s", sfrom);
2072                return;
2073        }
2074
2075        pkt.ipi6_ifindex = 0;
2076        for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&rcvhdr);
2077             cm;
2078             cm = (struct cmsghdr *)CMSG_NXTHDR(&rcvhdr, cm))
2079        {
2080                if (cm->cmsg_level != IPPROTO_IPV6)
2081                        continue;
2082                switch(cm->cmsg_type) {
2083                case IPV6_PKTINFO:
2084                        if (cm->cmsg_len == CMSG_LEN(sizeof(pkt)))
2085                                memcpy(&pkt, CMSG_DATA(cm), sizeof(pkt));
2086                        break;
2087                }
2088        }
2089
2090        if (pkt.ipi6_ifindex == 0) {
2091                syslog(LOG_ERR,
2092                    "DHCPv6 reply did not contain index from %s",
2093                    sfrom);
2094                return;
2095        }
2096
2097        TAILQ_FOREACH(ifp, ifaces, next) {
2098                if (ifp->index == (unsigned int)pkt.ipi6_ifindex)
2099                        break;
2100        }
2101        if (ifp == NULL) {
2102                syslog(LOG_DEBUG,
2103                    "DHCPv6 reply for unexpected interface from %s", sfrom);
2104                return;
2105        }
2106        state = D6_STATE(ifp);
2107        if (state == NULL || state->send == NULL) {
2108                syslog(LOG_DEBUG, "%s: DHCPv6 reply received but not running",
2109                    ifp->name);
2110                return;
2111        }
2112        /* We're already bound and this message is for another machine */
2113        /* XXX DELEGATED? */
2114        if (state->state == DH6S_BOUND ||
2115            state->state == DH6S_INFORMED)
2116                return;
2117
2118        r = (struct dhcp6_message *)rcvhdr.msg_iov[0].iov_base;
2119        if (r->xid[0] != state->send->xid[0] ||
2120            r->xid[1] != state->send->xid[1] ||
2121            r->xid[2] != state->send->xid[2])
2122        {
2123                syslog(LOG_DEBUG,
2124                    "%s: wrong xid 0x%02x%02x%02x"
2125                    " (expecting 0x%02x%02x%02x) from %s",
2126                    ifp->name,
2127                    r->xid[0], r->xid[1], r->xid[2],
2128                    state->send->xid[0], state->send->xid[1],
2129                    state->send->xid[2],
2130                    sfrom);
2131                return;
2132        }
2133
2134        if (dhcp6_getmoption(D6_OPTION_SERVERID, r, len) == NULL) {
2135                syslog(LOG_DEBUG, "%s: no DHCPv6 server ID from %s",
2136                    ifp->name, sfrom);
2137                return;
2138        }
2139
2140        o = dhcp6_getmoption(D6_OPTION_CLIENTID, r, len);
2141        if (o == NULL || ntohs(o->len) != duid_len ||
2142            memcmp(D6_COPTION_DATA(o), duid, duid_len) != 0)
2143        {
2144                syslog(LOG_DEBUG, "%s: incorrect client ID from %s",
2145                    ifp->name, sfrom);
2146                return;
2147        }
2148
2149        ifo = ifp->options;
2150        for (i = 0, opt = dhcp6_opts; i < dhcp6_opts_len; i++, opt++) {
2151                if (has_option_mask(ifo->requiremask6, opt->option) &&
2152                    dhcp6_getmoption(opt->option, r, len) == NULL)
2153                {
2154                        syslog(LOG_WARNING,
2155                            "%s: reject DHCPv6 (no option %s) from %s",
2156                            ifp->name, opt->var, sfrom);
2157                        return;
2158                }
2159        }
2160
2161        /* Authenticate the message */
2162        o = dhcp6_getmoption(D6_OPTION_AUTH, r, len);
2163        if (o) {
2164                if (dhcp_auth_validate(&state->auth, &ifo->auth,
2165                    (uint8_t *)r, len, 6, r->type,
2166                    D6_COPTION_DATA(o), ntohs(o->len)) == NULL)
2167                {
2168                        syslog(LOG_DEBUG, "dhcp_auth_validate: %m");
2169                        syslog(LOG_ERR, "%s: authentication failed from %s",
2170                            ifp->name, sfrom);
2171                        return;
2172                }
2173                syslog(LOG_DEBUG, "%s: validated using 0x%08" PRIu32,
2174                    ifp->name, state->auth.token->secretid);
2175        } else if (ifo->auth.options & DHCPCD_AUTH_REQUIRE) {
2176                syslog(LOG_ERR, "%s: missing authentiation from %s",
2177                    ifp->name, sfrom);
2178                return;
2179        } else if (ifo->auth.options & DHCPCD_AUTH_SEND)
2180                syslog(LOG_WARNING,
2181                    "%s: missing authentiation from %s",
2182                    ifp->name, sfrom);
2183
2184        op = dhcp6_get_op(r->type);
2185        switch(r->type) {
2186        case DHCP6_REPLY:
2187                switch(state->state) {
2188                case DH6S_INFORM:
2189                        /* RFC4242 */
2190                        o = dhcp6_getmoption(D6_OPTION_INFO_REFRESH_TIME,
2191                            r, len);
2192                        if (o == NULL || ntohs(o->len) != sizeof(u32))
2193                                state->renew = IRT_DEFAULT;
2194                        else {
2195                                memcpy(&u32, D6_COPTION_DATA(o), sizeof(u32));
2196                                state->renew = ntohl(u32);
2197                                if (state->renew < IRT_MINIMUM)
2198                                        state->renew = IRT_MINIMUM;
2199                        }
2200                        break;
2201                case DH6S_CONFIRM:
2202                        error = dhcp6_checkstatusok(ifp, r, NULL, len);
2203                        /* If we got an OK status the chances are that we
2204                         * didn't get the IA's returned, so preserve them
2205                         * from our saved response */
2206                        if (error == 1)
2207                                goto recv;
2208                        if (error == -1 ||
2209                            dhcp6_validatelease(ifp, r, len, sfrom) == -1) {
2210                                dhcp6_startdiscover(ifp);
2211                                return;
2212                        }
2213                        break;
2214                case DH6S_DISCOVER:
2215                        if (has_option_mask(ifo->requestmask6,
2216                            D6_OPTION_RAPID_COMMIT) &&
2217                            dhcp6_getmoption(D6_OPTION_RAPID_COMMIT, r, len))
2218                                state->state = DH6S_REQUEST;
2219                        else
2220                                op = NULL;
2221                case DH6S_REQUEST: /* FALLTHROUGH */
2222                case DH6S_RENEW: /* FALLTHROUGH */
2223                case DH6S_REBIND:
2224                        if (dhcp6_validatelease(ifp, r, len, sfrom) == -1) {
2225                                /* PD doesn't use CONFIRM, so REBIND could
2226                                 * throw up an invalid prefix if we
2227                                 * changed link */
2228                                if (ifp->options->ia_type == D6_OPTION_IA_PD)
2229                                        dhcp6_startdiscover(ifp);
2230                                return;
2231                        }
2232                        break;
2233                default:
2234                        op = NULL;
2235                }
2236                break;
2237        case DHCP6_ADVERTISE:
2238                if (state->state != DH6S_DISCOVER) {
2239                        op = NULL;
2240                        break;
2241                }
2242                if (dhcp6_validatelease(ifp, r, len, sfrom) == -1)
2243                        return;
2244                break;
2245        default:
2246                syslog(LOG_ERR, "%s: invalid DHCP6 type %s (%d)",
2247                    ifp->name, op, r->type);
2248                return;
2249        }
2250        if (op == NULL) {
2251                syslog(LOG_WARNING, "%s: invalid state for DHCP6 type %s (%d)",
2252                    ifp->name, op, r->type);
2253                return;
2254        }
2255
2256        if (state->recv_len < (size_t)len) {
2257                free(state->recv);
2258                state->recv = malloc(len);
2259                if (state->recv == NULL) {
2260                        syslog(LOG_ERR, "%s: malloc recv: %m", ifp->name);
2261                        return;
2262                }
2263        }
2264        memcpy(state->recv, r, len);
2265        state->recv_len = len;
2266
2267        switch(r->type) {
2268        case DHCP6_ADVERTISE:
2269                if (state->state == DH6S_REQUEST) /* rapid commit */
2270                        break;
2271                ap = TAILQ_FIRST(&state->addrs);
2272                syslog(LOG_INFO, "%s: ADV %s from %s",
2273                    ifp->name, ap->saddr, sfrom);
2274                if (options & DHCPCD_TEST)
2275                        break;
2276                dhcp6_startrequest(ifp);
2277                return;
2278        }
2279
2280recv:
2281        has_new = 0;
2282        TAILQ_FOREACH(ap, &state->addrs, next) {
2283                if (ap->flags & IPV6_AF_NEW) {
2284                        has_new = 1;
2285                        break;
2286                }
2287        }
2288        syslog(has_new ? LOG_INFO : LOG_DEBUG,
2289            "%s: %s received from %s", ifp->name, op, sfrom);
2290
2291        state->reason = NULL;
2292        eloop_timeout_delete(NULL, ifp);
2293        switch(state->state) {
2294        case DH6S_INFORM:
2295                state->rebind = 0;
2296                state->expire = ND6_INFINITE_LIFETIME;
2297                state->lowpl = ND6_INFINITE_LIFETIME;
2298                state->reason = "INFORM6";
2299                break;
2300        case DH6S_REQUEST:
2301                if (state->reason == NULL)
2302                        state->reason = "BOUND6";
2303                /* FALLTHROUGH */
2304        case DH6S_RENEW:
2305                if (state->reason == NULL)
2306                        state->reason = "RENEW6";
2307                /* FALLTHROUGH */
2308        case DH6S_REBIND:
2309                if (state->reason == NULL)
2310                        state->reason = "REBIND6";
2311                /* FALLTHROUGH */
2312        case DH6S_CONFIRM:
2313                if (state->reason == NULL)
2314                        state->reason = "REBOOT6";
2315                if (state->renew == 0) {
2316                        if (state->expire == ND6_INFINITE_LIFETIME)
2317                                state->renew = ND6_INFINITE_LIFETIME;
2318                        else
2319                                state->renew = state->lowpl * 0.5;
2320                }
2321                if (state->rebind == 0) {
2322                        if (state->expire == ND6_INFINITE_LIFETIME)
2323                                state->rebind = ND6_INFINITE_LIFETIME;
2324                        else
2325                                state->rebind = state->lowpl * 0.8;
2326                }
2327                break;
2328        default:
2329                state->reason = "UNKNOWN6";
2330                break;
2331        }
2332
2333        if (state->state != DH6S_CONFIRM) {
2334                free(state->old);
2335                state->old = state->new;
2336                state->old_len = state->new_len;
2337                state->new = state->recv;
2338                state->new_len = state->recv_len;
2339                state->recv = NULL;
2340                state->recv_len = 0;
2341        }
2342
2343        if (options & DHCPCD_TEST)
2344                script_runreason(ifp, "TEST");
2345        else {
2346                if (state->state == DH6S_INFORM)
2347                        state->state = DH6S_INFORMED;
2348                else
2349                        state->state = DH6S_BOUND;
2350                if (state->renew && state->renew != ND6_INFINITE_LIFETIME)
2351                        eloop_timeout_add_sec(state->renew,
2352                            state->state == DH6S_INFORMED ?
2353                            dhcp6_startinform : dhcp6_startrenew, ifp);
2354                if (state->rebind && state->rebind != ND6_INFINITE_LIFETIME)
2355                        eloop_timeout_add_sec(state->rebind,
2356                            dhcp6_startrebind, ifp);
2357                if (state->expire && state->expire != ND6_INFINITE_LIFETIME)
2358                        eloop_timeout_add_sec(state->expire,
2359                            dhcp6_startexpire, ifp);
2360                if (ifp->options->ia_type == D6_OPTION_IA_PD)
2361                        dhcp6_delegate_prefix(ifp);
2362                ipv6nd_probeaddrs(&state->addrs);
2363                if (state->state == DH6S_INFORMED)
2364                        syslog(has_new ? LOG_INFO : LOG_DEBUG,
2365                            "%s: refresh in %"PRIu32" seconds",
2366                            ifp->name, state->renew);
2367                else if (state->renew || state->rebind)
2368                        syslog(has_new ? LOG_INFO : LOG_DEBUG,
2369                            "%s: renew in %"PRIu32" seconds,"
2370                            " rebind in %"PRIu32" seconds",
2371                            ifp->name, state->renew, state->rebind);
2372                ipv6_buildroutes();
2373                dhcp6_writelease(ifp);
2374
2375                len = 1;
2376                /* If all addresses have completed DAD run the script */
2377                TAILQ_FOREACH(ap, &state->addrs, next) {
2378                        if (ap->flags & IPV6_AF_ONLINK) {
2379                                if (!(ap->flags & IPV6_AF_DADCOMPLETED) &&
2380                                    ipv6_findaddr(ap->iface, &ap->addr))
2381                                        ap->flags |= IPV6_AF_DADCOMPLETED;
2382                                if ((ap->flags & IPV6_AF_DADCOMPLETED) == 0) {
2383                                        len = 0;
2384                                        break;
2385                                }
2386                        }
2387                }
2388                if (len) {
2389                        script_runreason(ifp, state->reason);
2390                        daemonise();
2391                } else
2392                        syslog(LOG_DEBUG,
2393                            "%s: waiting for DHCPv6 DAD to complete",
2394                            ifp->name);
2395        }
2396
2397        if (options & DHCPCD_TEST ||
2398            (ifp->options->options & DHCPCD_INFORM &&
2399            !(options & DHCPCD_MASTER)))
2400        {
2401#ifdef DEBUG_MEMORY
2402                dhcp6_free(ifp);
2403#endif
2404                exit(EXIT_SUCCESS);
2405        }
2406}
2407
2408static int
2409dhcp6_open(void)
2410{
2411        struct sockaddr_in6 sa;
2412        int n;
2413
2414        if (sndbuf == NULL && dhcp6_init() == -1)
2415                return -1;
2416
2417        memset(&sa, 0, sizeof(sa));
2418        sa.sin6_family = AF_INET6;
2419        sa.sin6_port = htons(DHCP6_CLIENT_PORT);
2420#ifdef BSD
2421        sa.sin6_len = sizeof(sa);
2422#endif
2423
2424        sock = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
2425        if (sock == -1)
2426                return -1;
2427
2428        n = 1;
2429        if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
2430            &n, sizeof(n)) == -1)
2431                goto errexit;
2432
2433        n = 1;
2434        if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST,
2435            &n, sizeof(n)) == -1)
2436                goto errexit;
2437
2438#ifdef SO_REUSEPORT
2439        n = 1;
2440        if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT,
2441            &n, sizeof(n)) == -1)
2442                goto errexit;
2443#endif
2444
2445        if (bind(sock, (struct sockaddr *)&sa, sizeof(sa)) == -1)
2446                goto errexit;
2447
2448        n = 1;
2449        if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO,
2450            &n, sizeof(n)) == -1)
2451                goto errexit;
2452
2453        if (set_cloexec(sock) == -1 || set_nonblock(sock) == -1)
2454                goto errexit;
2455
2456        eloop_event_add(sock, dhcp6_handledata, NULL);
2457
2458        return 0;
2459
2460errexit:
2461        close(sock);
2462        return -1;
2463}
2464
2465static void
2466dhcp6_start1(void *arg)
2467{
2468        struct interface *ifp = arg;
2469        struct if_options *ifo = ifp->options;
2470        struct dhcp6_state *state;
2471        size_t i;
2472        const struct dhcp_compat *dhc;
2473
2474        state = D6_STATE(ifp);
2475        /* Match any DHCPv4 opton to DHCPv6 options if given for easy
2476         * configuration */
2477        for (i = 0; i < sizeof(ifo->requestmask6); i++) {
2478                if (ifo->requestmask6[i] != '\0')
2479                        break;
2480        }
2481        if (i == sizeof(ifo->requestmask6)) {
2482                for (dhc = dhcp_compats; dhc->dhcp_opt; dhc++) {
2483                        if (has_option_mask(ifo->requestmask, dhc->dhcp_opt))
2484                                add_option_mask(ifo->requestmask6,
2485                                    dhc->dhcp6_opt);
2486                }
2487                if (ifo->fqdn != FQDN_DISABLE ||
2488                    ifo->options & DHCPCD_HOSTNAME)
2489                        add_option_mask(ifo->requestmask6, D6_OPTION_FQDN);
2490        }
2491
2492        if (state->state == DH6S_INFORM) {
2493                add_option_mask(ifo->requestmask6, D6_OPTION_INFO_REFRESH_TIME);
2494                dhcp6_startinform(ifp);
2495        } else {
2496                del_option_mask(ifo->requestmask6, D6_OPTION_INFO_REFRESH_TIME);
2497                dhcp6_startinit(ifp);
2498        }
2499}
2500
2501int
2502dhcp6_start(struct interface *ifp, enum DH6S init_state)
2503{
2504        struct dhcp6_state *state;
2505
2506        state = D6_STATE(ifp);
2507        if (state) {
2508                if (state->state == DH6S_DELEGATED) {
2509                        dhcp6_find_delegates(ifp);
2510                        return 0;
2511                }
2512                if (state->state == DH6S_INFORMED &&
2513                    init_state == DH6S_INFORM)
2514                {
2515                        dhcp6_startinform(ifp);
2516                        return 0;
2517                }
2518                /* We're already running DHCP6 */
2519                /* XXX: What if the managed flag changes? */
2520                return 0;
2521        }
2522
2523        if (!(ifp->options->options & DHCPCD_DHCP6))
2524                return 0;
2525
2526        if (sock == -1 && dhcp6_open() == -1)
2527                return -1;
2528
2529        ifp->if_data[IF_DATA_DHCP6] = calloc(1, sizeof(*state));
2530        state = D6_STATE(ifp);
2531        if (state == NULL)
2532                return -1;
2533
2534        TAILQ_INIT(&state->addrs);
2535        if (dhcp6_find_delegates(ifp))
2536                return 0;
2537
2538        state->state = init_state;
2539        snprintf(state->leasefile, sizeof(state->leasefile),
2540            LEASEFILE6, ifp->name);
2541
2542        if (ipv6_linklocal(ifp) == NULL) {
2543                syslog(LOG_DEBUG,
2544                    "%s: delaying DHCPv6 soliciation for LL address",
2545                    ifp->name);
2546                ipv6_addlinklocalcallback(ifp, dhcp6_start1, ifp);
2547                return 0;
2548        }
2549
2550        dhcp6_start1(ifp);
2551        return 0;
2552}
2553
2554void
2555dhcp6_reboot(struct interface *ifp)
2556{
2557        struct dhcp6_state *state;
2558
2559        state = D6_STATE(ifp);
2560        if (state) {
2561                switch (state->state) {
2562                case DH6S_BOUND:
2563                        dhcp6_startrebind(ifp);
2564                        break;
2565                case DH6S_INFORMED:
2566                        dhcp6_startinform(ifp);
2567                        break;
2568                default:
2569                        dhcp6_startdiscover(ifp);
2570                        break;
2571                }
2572        }
2573}
2574
2575static void
2576dhcp6_freedrop(struct interface *ifp, int drop, const char *reason)
2577{
2578        struct dhcp6_state *state;
2579
2580        eloop_timeout_delete(NULL, ifp);
2581
2582        /*
2583         * As the interface is going away from dhcpcd we need to
2584         * remove the delegated addresses, otherwise we lose track
2585         * of which interface is delegating as we remeber it by pointer.
2586         * So if we need to change this behaviour, we need to change
2587         * how we remember which interface delegated.
2588         * To make it more interesting, on some OS's with PPP links
2589         * there is no guarantee the delegating interface will have
2590         * the same name or index so think very hard before changing
2591         * this.
2592         */
2593        if (ifp->options &&
2594            ifp->options->options & (DHCPCD_STOPPING | DHCPCD_RELEASE) &&
2595            (ifp->options->options & (DHCPCD_EXITING | DHCPCD_PERSISTENT)) !=
2596            (DHCPCD_EXITING | DHCPCD_PERSISTENT))
2597                dhcp6_delete_delegates(ifp);
2598
2599        state = D6_STATE(ifp);
2600        if (state) {
2601                if (ifp->options->options & DHCPCD_RELEASE) {
2602                        if (ifp->carrier != LINK_DOWN)
2603                                dhcp6_startrelease(ifp);
2604                        unlink(state->leasefile);
2605                }
2606                dhcp6_freedrop_addrs(ifp, drop, NULL);
2607                if (drop && state->new &&
2608                    (ifp->options->options &
2609                    (DHCPCD_EXITING | DHCPCD_PERSISTENT)) !=
2610                    (DHCPCD_EXITING | DHCPCD_PERSISTENT))
2611                {
2612                        if (reason == NULL)
2613                                reason = "STOP6";
2614                        script_runreason(ifp, reason);
2615                }
2616                free(state->send);
2617                free(state->recv);
2618                free(state->new);
2619                free(state->old);
2620                free(state->auth.reconf);
2621                free(state);
2622                ifp->if_data[IF_DATA_DHCP6] = NULL;
2623        }
2624
2625        /* If we don't have any more DHCP6 enabled interfaces,
2626         * close the global socket */
2627        if (ifaces) {
2628                TAILQ_FOREACH(ifp, ifaces, next) {
2629                        if (D6_STATE(ifp))
2630                                break;
2631                }
2632        }
2633        if (ifp == NULL && sock != -1) {
2634                close(sock);
2635                eloop_event_delete(sock);
2636                sock = -1;
2637        }
2638}
2639
2640void
2641dhcp6_drop(struct interface *ifp, const char *reason)
2642{
2643
2644        dhcp6_freedrop(ifp, 1, reason);
2645}
2646
2647void
2648dhcp6_free(struct interface *ifp)
2649{
2650
2651        dhcp6_freedrop(ifp, 0, NULL);
2652}
2653
2654void
2655dhcp6_handleifa(int cmd, const char *ifname,
2656    const struct in6_addr *addr, int flags)
2657{
2658        struct interface *ifp;
2659        struct dhcp6_state *state;
2660
2661        if (ifaces == NULL)
2662                return;
2663
2664        TAILQ_FOREACH(ifp, ifaces, next) {
2665                state = D6_STATE(ifp);
2666                if (state == NULL || strcmp(ifp->name, ifname))
2667                        continue;
2668                ipv6_handleifa_addrs(cmd, &state->addrs, addr, flags);
2669        }
2670
2671}
2672
2673ssize_t
2674dhcp6_env(char **env, const char *prefix, const struct interface *ifp,
2675    const struct dhcp6_message *m, ssize_t len)
2676{
2677        const struct dhcp6_state *state;
2678        const struct if_options *ifo;
2679        struct dhcp_opt *opt, *vo;
2680        const struct dhcp6_option *o;
2681        size_t i, n;
2682        uint16_t ol, oc;
2683        char *v, *val, *pfx;
2684        const struct ipv6_addr *ap;
2685        uint32_t en;
2686
2687        state = D6_CSTATE(ifp);
2688        n = 0;
2689        ifo = ifp->options;
2690
2691        /* Zero our indexes */
2692        if (env) {
2693                for (i = 0, opt = dhcp6_opts; i < dhcp6_opts_len; i++, opt++)
2694                        dhcp_zero_index(opt);
2695                for (i = 0, opt = ifp->options->dhcp6_override;
2696                    i < ifp->options->dhcp6_override_len;
2697                    i++, opt++)
2698                        dhcp_zero_index(opt);
2699                for (i = 0, opt = vivso; i < vivso_len; i++, opt++)
2700                        dhcp_zero_index(opt);
2701                i = strlen(prefix) + strlen("_dhcp6") + 1;
2702                pfx = malloc(i);
2703                if (pfx == NULL) {
2704                        syslog(LOG_ERR, "%s: %m", __func__);
2705                        return 0;
2706                }
2707                snprintf(pfx, i, "%s_dhcp6", prefix);
2708        } else
2709                pfx = NULL;
2710
2711        /* Unlike DHCP, DHCPv6 options *may* occur more than once.
2712         * There is also no provision for option concatenation unlike DHCP. */
2713        for (o = D6_CFIRST_OPTION(m);
2714            len > (ssize_t)sizeof(*o);
2715            o = D6_CNEXT_OPTION(o))
2716        {
2717                ol = ntohs(o->len);
2718                len -= sizeof(*o) + ol;
2719                if (len < 0) {
2720                        errno = EINVAL;
2721                        break;
2722                }
2723                oc = ntohs(o->code);
2724                if (has_option_mask(ifo->nomask6, oc))
2725                        continue;
2726                for (i = 0, opt = ifo->dhcp6_override;
2727                    i < ifo->dhcp6_override_len;
2728                    i++, opt++)
2729                        if (opt->option == oc)
2730                                break;
2731                if (i == ifo->dhcp6_override_len &&
2732                    oc == D6_OPTION_VENDOR_OPTS &&
2733                    ol > sizeof(en))
2734                {
2735                        memcpy(&en, D6_COPTION_DATA(o), sizeof(en));
2736                        en = ntohl(en);
2737                        vo = vivso_find(en, ifp);
2738                } else
2739                        vo = NULL;
2740                if (i == ifo->dhcp6_override_len) {
2741                        for (i = 0, opt = dhcp6_opts;
2742                            i < dhcp6_opts_len;
2743                            i++, opt++)
2744                                if (opt->option == oc)
2745                                        break;
2746                        if (i == dhcp6_opts_len)
2747                                opt = NULL;
2748                }
2749                if (opt) {
2750                        n += dhcp_envoption(env == NULL ? NULL : &env[n],
2751                            pfx, ifp->name,
2752                            opt, dhcp6_getoption, D6_COPTION_DATA(o), ol);
2753                }
2754                if (vo) {
2755                        n += dhcp_envoption(env == NULL ? NULL : &env[n],
2756                            pfx, ifp->name,
2757                            vo, dhcp6_getoption,
2758                            D6_COPTION_DATA(o) + sizeof(en),
2759                            ol - sizeof(en));
2760                }
2761        }
2762        free(pfx);
2763
2764        /* It is tempting to remove this section.
2765         * However, we need it at least for Delegated Prefixes
2766         * (they don't have a DHCPv6 message to parse to get the addressses)
2767         * and it's easier for shell scripts to see which addresses have
2768         * been added */
2769        if (TAILQ_FIRST(&state->addrs)) {
2770                if (env) {
2771                        if (ifo->ia_type == D6_OPTION_IA_PD) {
2772                                i = strlen(prefix) +
2773                                    strlen("_dhcp6_prefix=");
2774                                TAILQ_FOREACH(ap, &state->addrs, next) {
2775                                        i += strlen(ap->saddr) + 1;
2776                                }
2777                                v = val = env[n] = malloc(i);
2778                                if (v == NULL) {
2779                                        syslog(LOG_ERR, "%s: %m", __func__);
2780                                        return -1;
2781                                }
2782                                v += snprintf(val, i, "%s_dhcp6_prefix=",
2783                                        prefix);
2784                                TAILQ_FOREACH(ap, &state->addrs, next) {
2785                                        strcpy(v, ap->saddr);
2786                                        v += strlen(ap->saddr);
2787                                        *v++ = ' ';
2788                                }
2789                                *--v = '\0';
2790                        } else {
2791                                i = strlen(prefix) +
2792                                    strlen("_dhcp6_ip_address=");
2793                                TAILQ_FOREACH(ap, &state->addrs, next) {
2794                                        i += strlen(ap->saddr) + 1;
2795                                }
2796                                v = val = env[n] = malloc(i);
2797                                if (v == NULL) {
2798                                        syslog(LOG_ERR, "%s: %m", __func__);
2799                                        return -1;
2800                                }
2801                                v += snprintf(val, i, "%s_dhcp6_ip_address=",
2802                                        prefix);
2803                                TAILQ_FOREACH(ap, &state->addrs, next) {
2804                                        strcpy(v, ap->saddr);
2805                                        v += strlen(ap->saddr);
2806                                        *v++ = ' ';
2807                                }
2808                                *--v = '\0';
2809                        }
2810                }
2811                n++;
2812        }
2813
2814        return n;
2815}
2816#endif /* defined(__rtems__) && defined(INET6) */
Note: See TracBrowser for help on using the repository browser.