source: rtems-libbsd/dhcpcd/dhcp6.c @ f2ed769

4.115-freebsd-12freebsd-9.3
Last change on this file since f2ed769 was f2ed769, checked in by Sebastian Huber <sebastian.huber@…>, on Jan 30, 2014 at 12:29:46 PM

DHCPCD(8): Import

Import DHCPCD(8) from:

http://roy.marples.name/projects/dhcpcd/

The upstream sources can be obtained via:

fossil clone http://roy.marples.name/projects/dhcpcd

The imported version is 2014-01-29 19:46:44 [6b209507bb].

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