Annotation of embedaddon/dhcp/client/dhc6.c, revision 1.1

1.1     ! misho       1: /* dhc6.c - DHCPv6 client routines. */
        !             2: 
        !             3: /*
        !             4:  * Copyright (c) 2006-2010 by Internet Systems Consortium, Inc. ("ISC")
        !             5:  *
        !             6:  * Permission to use, copy, modify, and distribute this software for any
        !             7:  * purpose with or without fee is hereby granted, provided that the above
        !             8:  * copyright notice and this permission notice appear in all copies.
        !             9:  *
        !            10:  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
        !            11:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
        !            12:  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
        !            13:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
        !            14:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
        !            15:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
        !            16:  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
        !            17:  *
        !            18:  *   Internet Systems Consortium, Inc.
        !            19:  *   950 Charter Street
        !            20:  *   Redwood City, CA 94063
        !            21:  *   <info@isc.org>
        !            22:  *   https://www.isc.org/
        !            23:  */
        !            24: 
        !            25: #include "dhcpd.h"
        !            26: 
        !            27: #ifdef DHCPv6
        !            28: 
        !            29: struct sockaddr_in6 DHCPv6DestAddr;
        !            30: 
        !            31: /*
        !            32:  * Option definition structures that are used by the software - declared
        !            33:  * here once and assigned at startup to save lookups.
        !            34:  */
        !            35: struct option *clientid_option = NULL;
        !            36: struct option *elapsed_option = NULL;
        !            37: struct option *ia_na_option = NULL;
        !            38: struct option *ia_ta_option = NULL;
        !            39: struct option *ia_pd_option = NULL;
        !            40: struct option *iaaddr_option = NULL;
        !            41: struct option *iaprefix_option = NULL;
        !            42: struct option *oro_option = NULL;
        !            43: struct option *irt_option = NULL;
        !            44: 
        !            45: static struct dhc6_lease *dhc6_dup_lease(struct dhc6_lease *lease,
        !            46:                                         const char *file, int line);
        !            47: static struct dhc6_ia *dhc6_dup_ia(struct dhc6_ia *ia,
        !            48:                                   const char *file, int line);
        !            49: static struct dhc6_addr *dhc6_dup_addr(struct dhc6_addr *addr,
        !            50:                                       const char *file, int line);
        !            51: static void dhc6_ia_destroy(struct dhc6_ia **src, const char *file, int line);
        !            52: static isc_result_t dhc6_parse_ia_na(struct dhc6_ia **pia,
        !            53:                                     struct packet *packet,
        !            54:                                     struct option_state *options);
        !            55: static isc_result_t dhc6_parse_ia_ta(struct dhc6_ia **pia,
        !            56:                                     struct packet *packet,
        !            57:                                     struct option_state *options);
        !            58: static isc_result_t dhc6_parse_ia_pd(struct dhc6_ia **pia,
        !            59:                                     struct packet *packet,
        !            60:                                     struct option_state *options);
        !            61: static isc_result_t dhc6_parse_addrs(struct dhc6_addr **paddr,
        !            62:                                     struct packet *packet,
        !            63:                                     struct option_state *options);
        !            64: static isc_result_t dhc6_parse_prefixes(struct dhc6_addr **ppref,
        !            65:                                        struct packet *packet,
        !            66:                                        struct option_state *options);
        !            67: static struct dhc6_ia *find_ia(struct dhc6_ia *head,
        !            68:                               u_int16_t type, const char *id);
        !            69: static struct dhc6_addr *find_addr(struct dhc6_addr *head,
        !            70:                                   struct iaddr *address);
        !            71: static struct dhc6_addr *find_pref(struct dhc6_addr *head,
        !            72:                                   struct iaddr *prefix, u_int8_t plen);
        !            73: void init_handler(struct packet *packet, struct client_state *client);
        !            74: void info_request_handler(struct packet *packet, struct client_state *client);
        !            75: void rapid_commit_handler(struct packet *packet, struct client_state *client);
        !            76: void do_init6(void *input);
        !            77: void do_info_request6(void *input);
        !            78: void do_confirm6(void *input);
        !            79: void reply_handler(struct packet *packet, struct client_state *client);
        !            80: static isc_result_t dhc6_add_ia_na(struct client_state *client,
        !            81:                                   struct data_string *packet,
        !            82:                                   struct dhc6_lease *lease,
        !            83:                                   u_int8_t message);
        !            84: static isc_result_t dhc6_add_ia_ta(struct client_state *client,
        !            85:                                   struct data_string *packet,
        !            86:                                   struct dhc6_lease *lease,
        !            87:                                   u_int8_t message);
        !            88: static isc_result_t dhc6_add_ia_pd(struct client_state *client,
        !            89:                                   struct data_string *packet,
        !            90:                                   struct dhc6_lease *lease,
        !            91:                                   u_int8_t message);
        !            92: static isc_boolean_t stopping_finished(void);
        !            93: static void dhc6_merge_lease(struct dhc6_lease *src, struct dhc6_lease *dst);
        !            94: void do_select6(void *input);
        !            95: void do_refresh6(void *input);
        !            96: static void do_release6(void *input);
        !            97: static void start_bound(struct client_state *client);
        !            98: static void start_informed(struct client_state *client);
        !            99: void informed_handler(struct packet *packet, struct client_state *client);
        !           100: void bound_handler(struct packet *packet, struct client_state *client);
        !           101: void start_renew6(void *input);
        !           102: void start_rebind6(void *input);
        !           103: void do_depref(void *input);
        !           104: void do_expire(void *input);
        !           105: static void make_client6_options(struct client_state *client,
        !           106:                                 struct option_state **op,
        !           107:                                 struct dhc6_lease *lease, u_int8_t message);
        !           108: static void script_write_params6(struct client_state *client,
        !           109:                                 const char *prefix,
        !           110:                                 struct option_state *options);
        !           111: static isc_boolean_t active_prefix(struct client_state *client);
        !           112: 
        !           113: static int check_timing6(struct client_state *client, u_int8_t msg_type, 
        !           114:                         char *msg_str, struct dhc6_lease *lease,
        !           115:                         struct data_string *ds);
        !           116: 
        !           117: extern int onetry;
        !           118: extern int stateless;
        !           119: 
        !           120: /*
        !           121:  * The "best" default DUID, since we cannot predict any information
        !           122:  * about the system (such as whether or not the hardware addresses are
        !           123:  * integrated into the motherboard or similar), is the "LLT", link local
        !           124:  * plus time, DUID. For real stateless "LL" is better.
        !           125:  *
        !           126:  * Once generated, this duid is stored into the state database, and
        !           127:  * retained across restarts.
        !           128:  *
        !           129:  * For the time being, there is probably a different state database for
        !           130:  * every daemon, so this winds up being a per-interface identifier...which
        !           131:  * is not how it is intended.  Upcoming rearchitecting the client should
        !           132:  * address this "one daemon model."
        !           133:  */
        !           134: void
        !           135: form_duid(struct data_string *duid, const char *file, int line)
        !           136: {
        !           137:        struct interface_info *ip;
        !           138:        int len;
        !           139: 
        !           140:        /* For now, just use the first interface on the list. */
        !           141:        ip = interfaces;
        !           142: 
        !           143:        if (ip == NULL)
        !           144:                log_fatal("Impossible condition at %s:%d.", MDL);
        !           145: 
        !           146:        if ((ip->hw_address.hlen == 0) ||
        !           147:            (ip->hw_address.hlen > sizeof(ip->hw_address.hbuf)))
        !           148:                log_fatal("Impossible hardware address length at %s:%d.", MDL);
        !           149: 
        !           150:        /*
        !           151:         * 2 bytes for the 'duid type' field.
        !           152:         * 2 bytes for the 'htype' field.
        !           153:         * (not stateless) 4 bytes for the 'current time'.
        !           154:         * enough bytes for the hardware address (note that hw_address has
        !           155:         * the 'htype' on byte zero).
        !           156:         */
        !           157:        len = 4 + (ip->hw_address.hlen - 1);
        !           158:        if (!stateless)
        !           159:                len += 4;
        !           160:        if (!buffer_allocate(&duid->buffer, len, MDL))
        !           161:                log_fatal("no memory for default DUID!");
        !           162:        duid->data = duid->buffer->data;
        !           163:        duid->len = len;
        !           164: 
        !           165:        /* Basic Link Local Address type of DUID. */
        !           166:        if (!stateless) {
        !           167:                putUShort(duid->buffer->data, DUID_LLT);
        !           168:                putUShort(duid->buffer->data + 2, ip->hw_address.hbuf[0]);
        !           169:                putULong(duid->buffer->data + 4, cur_time - DUID_TIME_EPOCH);
        !           170:                memcpy(duid->buffer->data + 8, ip->hw_address.hbuf + 1,
        !           171:                       ip->hw_address.hlen - 1);
        !           172:        } else {
        !           173:                putUShort(duid->buffer->data, DUID_LL);
        !           174:                putUShort(duid->buffer->data + 2, ip->hw_address.hbuf[0]);
        !           175:                memcpy(duid->buffer->data + 4, ip->hw_address.hbuf + 1,
        !           176:                       ip->hw_address.hlen - 1);
        !           177:        }
        !           178: }
        !           179: 
        !           180: /*
        !           181:  * Assign DHCPv6 port numbers as a client.
        !           182:  */
        !           183: void
        !           184: dhcpv6_client_assignments(void)
        !           185: {
        !           186:        struct servent *ent;
        !           187:        unsigned code;
        !           188: 
        !           189:        if (path_dhclient_pid == NULL)
        !           190:                path_dhclient_pid = _PATH_DHCLIENT6_PID;
        !           191:        if (path_dhclient_db == NULL)
        !           192:                path_dhclient_db = _PATH_DHCLIENT6_DB;
        !           193: 
        !           194:        if (local_port == 0) {
        !           195:                ent = getservbyname("dhcpv6-client", "udp");
        !           196:                if (ent == NULL)
        !           197:                        local_port = htons(546);
        !           198:                else
        !           199:                        local_port = ent->s_port;
        !           200:        }
        !           201: 
        !           202:        if (remote_port == 0) {
        !           203:                ent = getservbyname("dhcpv6-server", "udp");
        !           204:                if (ent == NULL)
        !           205:                        remote_port = htons(547);
        !           206:                else
        !           207:                        remote_port = ent->s_port;
        !           208:        }
        !           209: 
        !           210:        memset(&DHCPv6DestAddr, 0, sizeof(DHCPv6DestAddr));
        !           211:        DHCPv6DestAddr.sin6_family = AF_INET6;
        !           212:        DHCPv6DestAddr.sin6_port = remote_port;
        !           213:        inet_pton(AF_INET6, All_DHCP_Relay_Agents_and_Servers,
        !           214:                  &DHCPv6DestAddr.sin6_addr);
        !           215: 
        !           216:        code = D6O_CLIENTID;
        !           217:        if (!option_code_hash_lookup(&clientid_option,
        !           218:                                     dhcpv6_universe.code_hash, &code, 0, MDL))
        !           219:                log_fatal("Unable to find the CLIENTID option definition.");
        !           220: 
        !           221:        code = D6O_ELAPSED_TIME;
        !           222:        if (!option_code_hash_lookup(&elapsed_option,
        !           223:                                     dhcpv6_universe.code_hash, &code, 0, MDL))
        !           224:                log_fatal("Unable to find the ELAPSED_TIME option definition.");
        !           225: 
        !           226:        code = D6O_IA_NA;
        !           227:        if (!option_code_hash_lookup(&ia_na_option, dhcpv6_universe.code_hash,
        !           228:                                     &code, 0, MDL))
        !           229:                log_fatal("Unable to find the IA_NA option definition.");
        !           230: 
        !           231:        code = D6O_IA_TA;
        !           232:        if (!option_code_hash_lookup(&ia_ta_option, dhcpv6_universe.code_hash,
        !           233:                                     &code, 0, MDL))
        !           234:                log_fatal("Unable to find the IA_TA option definition.");
        !           235: 
        !           236:        code = D6O_IA_PD;
        !           237:        if (!option_code_hash_lookup(&ia_pd_option, dhcpv6_universe.code_hash,
        !           238:                                     &code, 0, MDL))
        !           239:                log_fatal("Unable to find the IA_PD option definition.");
        !           240: 
        !           241:        code = D6O_IAADDR;
        !           242:        if (!option_code_hash_lookup(&iaaddr_option, dhcpv6_universe.code_hash,
        !           243:                                     &code, 0, MDL))
        !           244:                log_fatal("Unable to find the IAADDR option definition.");
        !           245: 
        !           246:        code = D6O_IAPREFIX;
        !           247:        if (!option_code_hash_lookup(&iaprefix_option,
        !           248:                                     dhcpv6_universe.code_hash,
        !           249:                                     &code, 0, MDL))
        !           250:                log_fatal("Unable to find the IAPREFIX option definition.");
        !           251: 
        !           252:        code = D6O_ORO;
        !           253:        if (!option_code_hash_lookup(&oro_option, dhcpv6_universe.code_hash,
        !           254:                                     &code, 0, MDL))
        !           255:                log_fatal("Unable to find the ORO option definition.");
        !           256: 
        !           257:        code = D6O_INFORMATION_REFRESH_TIME;
        !           258:        if (!option_code_hash_lookup(&irt_option, dhcpv6_universe.code_hash,
        !           259:                                     &code, 0, MDL))
        !           260:                log_fatal("Unable to find the IRT option definition.");
        !           261: 
        !           262: #ifndef __CYGWIN32__ /* XXX */
        !           263:        endservent();
        !           264: #endif
        !           265: }
        !           266: 
        !           267: /*
        !           268:  * Instead of implementing RFC3315 RAND (section 14) as a float "between"
        !           269:  * -0.1 and 0.1 non-inclusive, we implement it as an integer.
        !           270:  *
        !           271:  * The result is expected to follow this table:
        !           272:  *
        !           273:  *             split range answer
        !           274:  *                 - ERROR -                 base <= 0
        !           275:  *             0       1   0..0         1 <= base <= 10
        !           276:  *             1       3  -1..1        11 <= base <= 20
        !           277:  *             2       5  -2..2        21 <= base <= 30
        !           278:  *             3       7  -3..3        31 <= base <= 40
        !           279:  *             ...
        !           280:  *
        !           281:  * XXX: For this to make sense, we really need to do timing on a
        !           282:  * XXX: usec scale...we currently can assume zero for any value less than
        !           283:  * XXX: 11, which are very common in early stages of transmission for most
        !           284:  * XXX: messages.
        !           285:  */
        !           286: static TIME
        !           287: dhc6_rand(TIME base)
        !           288: {
        !           289:        TIME rval;
        !           290:        TIME range;
        !           291:        TIME split;
        !           292: 
        !           293:        /*
        !           294:         * A zero or less timeout is a bad thing...we don't want to
        !           295:         * DHCP-flood anyone.
        !           296:         */
        !           297:        if (base <= 0)
        !           298:                log_fatal("Impossible condition at %s:%d.", MDL);
        !           299: 
        !           300:        /*
        !           301:         * The first thing we do is count how many random integers we want
        !           302:         * in either direction (best thought of as the maximum negative
        !           303:         * integer, as we will subtract this potentially from a random 0).
        !           304:         */
        !           305:        split = (base - 1) / 10;
        !           306: 
        !           307:        /* Don't bother with the rest of the math if we know we'll get 0. */
        !           308:        if (split == 0)
        !           309:                return 0;
        !           310: 
        !           311:        /*
        !           312:         * Then we count the total number of integers in this set.  This
        !           313:         * is twice the number of integers in positive and negative
        !           314:         * directions, plus zero (-1, 0, 1 is 3, -2..2 adds 2 to 5, so forth).
        !           315:         */
        !           316:        range = (split * 2) + 1;
        !           317: 
        !           318:        /* Take a random number from [0..(range-1)]. */
        !           319:        rval = random();
        !           320:        rval %= range;
        !           321: 
        !           322:        /* Offset it to uncover potential negative values. */
        !           323:        rval -= split;
        !           324: 
        !           325:        return rval;
        !           326: }
        !           327: 
        !           328: /* Initialize message exchange timers (set RT from Initial-RT). */
        !           329: static void
        !           330: dhc6_retrans_init(struct client_state *client)
        !           331: {
        !           332:        int xid;
        !           333: 
        !           334:        /* Initialize timers. */
        !           335:        client->txcount = 0;
        !           336:        client->RT = client->IRT + dhc6_rand(client->IRT);
        !           337: 
        !           338:        /* Generate a new random 24-bit transaction ID for this exchange. */
        !           339: 
        !           340: #if (RAND_MAX >= 0x00ffffff)
        !           341:        xid = random();
        !           342: #elif (RAND_MAX >= 0x0000ffff)
        !           343:        xid = (random() << 16) ^ random();
        !           344: #elif (RAND_MAX >= 0x000000ff)
        !           345:        xid = (random() << 16) ^ (random() << 8) ^ random();
        !           346: #else
        !           347: # error "Random number generator of less than 8 bits not supported."
        !           348: #endif
        !           349: 
        !           350:        client->dhcpv6_transaction_id[0] = (xid >> 16) & 0xff;
        !           351:        client->dhcpv6_transaction_id[1] = (xid >>  8) & 0xff;
        !           352:        client->dhcpv6_transaction_id[2] =  xid        & 0xff;
        !           353: }
        !           354: 
        !           355: /* Advance the DHCPv6 retransmission state once. */
        !           356: static void
        !           357: dhc6_retrans_advance(struct client_state *client)
        !           358: {
        !           359:        struct timeval elapsed;
        !           360: 
        !           361:        /* elapsed = cur - start */
        !           362:        elapsed.tv_sec = cur_tv.tv_sec - client->start_time.tv_sec;
        !           363:        elapsed.tv_usec = cur_tv.tv_usec - client->start_time.tv_usec;
        !           364:        if (elapsed.tv_usec < 0) {
        !           365:                elapsed.tv_sec -= 1;
        !           366:                elapsed.tv_usec += 1000000;
        !           367:        }
        !           368:        /* retrans_advance is called after consuming client->RT. */
        !           369:        /* elapsed += RT */
        !           370:        elapsed.tv_sec += client->RT / 100;
        !           371:        elapsed.tv_usec += (client->RT % 100) * 10000;
        !           372:        if (elapsed.tv_usec >= 1000000) {
        !           373:                elapsed.tv_sec += 1;
        !           374:                elapsed.tv_usec -= 1000000;
        !           375:        }
        !           376: 
        !           377:        /*
        !           378:         * RT for each subsequent message transmission is based on the previous
        !           379:         * value of RT:
        !           380:         *
        !           381:         *    RT = 2*RTprev + RAND*RTprev
        !           382:         */
        !           383:        client->RT += client->RT + dhc6_rand(client->RT);
        !           384: 
        !           385:        /*
        !           386:         * MRT specifies an upper bound on the value of RT (disregarding the
        !           387:         * randomization added by the use of RAND).  If MRT has a value of 0,
        !           388:         * there is no upper limit on the value of RT.  Otherwise:
        !           389:         *
        !           390:         *    if (RT > MRT)
        !           391:         *       RT = MRT + RAND*MRT
        !           392:         */
        !           393:        if ((client->MRT != 0) && (client->RT > client->MRT))
        !           394:                client->RT = client->MRT + dhc6_rand(client->MRT);
        !           395: 
        !           396:        /*
        !           397:         * Further, if there's an MRD, we should wake up upon reaching
        !           398:         * the MRD rather than at some point after it.
        !           399:         */
        !           400:        if (client->MRD == 0) {
        !           401:                /* Done. */
        !           402:                client->txcount++;
        !           403:                return;
        !           404:        }
        !           405:        /* elapsed += client->RT */
        !           406:        elapsed.tv_sec += client->RT / 100;
        !           407:        elapsed.tv_usec += (client->RT % 100) * 10000;
        !           408:        if (elapsed.tv_usec >= 1000000) {
        !           409:                elapsed.tv_sec += 1;
        !           410:                elapsed.tv_usec -= 1000000;
        !           411:        }
        !           412:        if (elapsed.tv_sec >= client->MRD) {
        !           413:                /*
        !           414:                 * wake at RT + cur = start + MRD
        !           415:                 */
        !           416:                client->RT = client->MRD +
        !           417:                        (client->start_time.tv_sec - cur_tv.tv_sec);
        !           418:                client->RT = client->RT * 100 +
        !           419:                        (client->start_time.tv_usec - cur_tv.tv_usec) / 10000;
        !           420:        }
        !           421:        client->txcount++;
        !           422: }
        !           423: 
        !           424: /* Quick validation of DHCPv6 ADVERTISE packet contents. */
        !           425: static int
        !           426: valid_reply(struct packet *packet, struct client_state *client)
        !           427: {
        !           428:        struct data_string sid, cid;
        !           429:        struct option_cache *oc;
        !           430:        int rval = ISC_TRUE;
        !           431: 
        !           432:        memset(&sid, 0, sizeof(sid));
        !           433:        memset(&cid, 0, sizeof(cid));
        !           434: 
        !           435:        if (!lookup_option(&dhcpv6_universe, packet->options, D6O_SERVERID)) {
        !           436:                log_error("Response without a server identifier received.");
        !           437:                rval = ISC_FALSE;
        !           438:        }
        !           439: 
        !           440:        oc = lookup_option(&dhcpv6_universe, packet->options, D6O_CLIENTID);
        !           441:        if (!oc ||
        !           442:            !evaluate_option_cache(&sid, packet, NULL, client, packet->options,
        !           443:                                   client->sent_options, &global_scope, oc,
        !           444:                                   MDL)) {
        !           445:                log_error("Response without a client identifier.");
        !           446:                rval = ISC_FALSE;
        !           447:        }
        !           448: 
        !           449:        oc = lookup_option(&dhcpv6_universe, client->sent_options,
        !           450:                           D6O_CLIENTID);
        !           451:        if (!oc ||
        !           452:            !evaluate_option_cache(&cid, packet, NULL, client,
        !           453:                                   client->sent_options, NULL, &global_scope,
        !           454:                                   oc, MDL)) {
        !           455:                log_error("Local client identifier is missing!");
        !           456:                rval = ISC_FALSE;
        !           457:        }
        !           458: 
        !           459:        if (sid.len == 0 ||
        !           460:            sid.len != cid.len ||
        !           461:            memcmp(sid.data, cid.data, sid.len)) {
        !           462:                log_error("Advertise with matching transaction ID, but "
        !           463:                          "mismatching client id.");
        !           464:                rval = ISC_FALSE;
        !           465:        }
        !           466: 
        !           467:        return rval;
        !           468: }
        !           469: 
        !           470: /*
        !           471:  * Create a complete copy of a DHCPv6 lease structure.
        !           472:  */
        !           473: static struct dhc6_lease *
        !           474: dhc6_dup_lease(struct dhc6_lease *lease, const char *file, int line)
        !           475: {
        !           476:        struct dhc6_lease *copy;
        !           477:        struct dhc6_ia **insert_ia, *ia;
        !           478: 
        !           479:        copy = dmalloc(sizeof(*copy), file, line);
        !           480:        if (copy == NULL) {
        !           481:                log_error("Out of memory for v6 lease structure.");
        !           482:                return NULL;
        !           483:        }
        !           484: 
        !           485:        data_string_copy(&copy->server_id, &lease->server_id, file, line);
        !           486:        copy->pref = lease->pref;
        !           487: 
        !           488:        memcpy(copy->dhcpv6_transaction_id, lease->dhcpv6_transaction_id,
        !           489:               sizeof(copy->dhcpv6_transaction_id));
        !           490: 
        !           491:        option_state_reference(&copy->options, lease->options, file, line);
        !           492: 
        !           493:        insert_ia = &copy->bindings;
        !           494:        for (ia = lease->bindings ; ia != NULL ; ia = ia->next) {
        !           495:                *insert_ia = dhc6_dup_ia(ia, file, line);
        !           496: 
        !           497:                if (*insert_ia == NULL) {
        !           498:                        dhc6_lease_destroy(&copy, file, line);
        !           499:                        return NULL;
        !           500:                }
        !           501: 
        !           502:                insert_ia = &(*insert_ia)->next;
        !           503:        }
        !           504: 
        !           505:        return copy;
        !           506: }
        !           507: 
        !           508: /*
        !           509:  * Duplicate an IA structure.
        !           510:  */
        !           511: static struct dhc6_ia *
        !           512: dhc6_dup_ia(struct dhc6_ia *ia, const char *file, int line)
        !           513: {
        !           514:        struct dhc6_ia *copy;
        !           515:        struct dhc6_addr **insert_addr, *addr;
        !           516: 
        !           517:        copy = dmalloc(sizeof(*ia), file, line);
        !           518: 
        !           519:        memcpy(copy->iaid, ia->iaid, sizeof(copy->iaid));
        !           520: 
        !           521:        copy->ia_type = ia->ia_type;
        !           522:        copy->starts = ia->starts;
        !           523:        copy->renew = ia->renew;
        !           524:        copy->rebind = ia->rebind;
        !           525: 
        !           526:        insert_addr = &copy->addrs;
        !           527:        for (addr = ia->addrs ; addr != NULL ; addr = addr->next) {
        !           528:                *insert_addr = dhc6_dup_addr(addr, file, line);
        !           529: 
        !           530:                if (*insert_addr == NULL) {
        !           531:                        dhc6_ia_destroy(&copy, file, line);
        !           532:                        return NULL;
        !           533:                }
        !           534: 
        !           535:                insert_addr = &(*insert_addr)->next;
        !           536:        }
        !           537: 
        !           538:        if (ia->options != NULL)
        !           539:                option_state_reference(&copy->options, ia->options,
        !           540:                                       file, line);
        !           541: 
        !           542:        return copy;
        !           543: }
        !           544: 
        !           545: /*
        !           546:  * Duplicate an IAADDR or IAPREFIX structure.
        !           547:  */
        !           548: static struct dhc6_addr *
        !           549: dhc6_dup_addr(struct dhc6_addr *addr, const char *file, int line)
        !           550: {
        !           551:        struct dhc6_addr *copy;
        !           552: 
        !           553:        copy = dmalloc(sizeof(*addr), file, line);
        !           554: 
        !           555:        if (copy == NULL)
        !           556:                return NULL;
        !           557: 
        !           558:        memcpy(&copy->address, &addr->address, sizeof(copy->address));
        !           559: 
        !           560:        copy->plen = addr->plen;
        !           561:        copy->flags = addr->flags;
        !           562:        copy->starts = addr->starts;
        !           563:        copy->preferred_life = addr->preferred_life;
        !           564:        copy->max_life = addr->max_life;
        !           565: 
        !           566:        if (addr->options != NULL)
        !           567:                option_state_reference(&copy->options, addr->options,
        !           568:                                       file, line);
        !           569: 
        !           570:        return copy;
        !           571: }
        !           572: 
        !           573: /*
        !           574:  * Form a DHCPv6 lease structure based upon packet contents.  Creates and
        !           575:  * populates IA's and any IAADDR/IAPREFIX's they contain.
        !           576:  * Parsed options are deleted in order to not save them in the lease file.
        !           577:  */
        !           578: static struct dhc6_lease *
        !           579: dhc6_leaseify(struct packet *packet)
        !           580: {
        !           581:        struct data_string ds;
        !           582:        struct dhc6_lease *lease;
        !           583:        struct option_cache *oc;
        !           584: 
        !           585:        lease = dmalloc(sizeof(*lease), MDL);
        !           586:        if (lease == NULL) {
        !           587:                log_error("Out of memory for v6 lease structure.");
        !           588:                return NULL;
        !           589:        }
        !           590: 
        !           591:        memcpy(lease->dhcpv6_transaction_id, packet->dhcpv6_transaction_id, 3);
        !           592:        option_state_reference(&lease->options, packet->options, MDL);
        !           593: 
        !           594:        memset(&ds, 0, sizeof(ds));
        !           595: 
        !           596:        /* Determine preference (default zero). */
        !           597:        oc = lookup_option(&dhcpv6_universe, lease->options, D6O_PREFERENCE);
        !           598:        if (oc &&
        !           599:            evaluate_option_cache(&ds, packet, NULL, NULL, lease->options,
        !           600:                                  NULL, &global_scope, oc, MDL)) {
        !           601:                if (ds.len != 1) {
        !           602:                        log_error("Invalid length of DHCPv6 Preference option "
        !           603:                                  "(%d != 1)", ds.len);
        !           604:                        data_string_forget(&ds, MDL);
        !           605:                        dhc6_lease_destroy(&lease, MDL);
        !           606:                        return NULL;
        !           607:                } else {
        !           608:                        lease->pref = ds.data[0];
        !           609:                        log_debug("RCV:  X-- Preference %u.",
        !           610:                                  (unsigned)lease->pref);
        !           611:                }
        !           612: 
        !           613:                data_string_forget(&ds, MDL);
        !           614:        }
        !           615:        delete_option(&dhcpv6_universe, lease->options, D6O_PREFERENCE);
        !           616: 
        !           617:        /*
        !           618:         * Dig into recursive DHCPv6 pockets for IA_NA and contained IAADDR
        !           619:         * options.
        !           620:         */
        !           621:        if (dhc6_parse_ia_na(&lease->bindings, packet,
        !           622:                             lease->options) != ISC_R_SUCCESS) {
        !           623:                /* Error conditions are logged by the caller. */
        !           624:                dhc6_lease_destroy(&lease, MDL);
        !           625:                return NULL;
        !           626:        }
        !           627:        /*
        !           628:         * Dig into recursive DHCPv6 pockets for IA_TA and contained IAADDR
        !           629:         * options.
        !           630:         */
        !           631:        if (dhc6_parse_ia_ta(&lease->bindings, packet,
        !           632:                             lease->options) != ISC_R_SUCCESS) {
        !           633:                /* Error conditions are logged by the caller. */
        !           634:                dhc6_lease_destroy(&lease, MDL);
        !           635:                return NULL;
        !           636:        }
        !           637:        /*
        !           638:         * Dig into recursive DHCPv6 pockets for IA_PD and contained IAPREFIX
        !           639:         * options.
        !           640:         */
        !           641:        if (dhc6_parse_ia_pd(&lease->bindings, packet,
        !           642:                             lease->options) != ISC_R_SUCCESS) {
        !           643:                /* Error conditions are logged by the caller. */
        !           644:                dhc6_lease_destroy(&lease, MDL);
        !           645:                return NULL;
        !           646:        }
        !           647: 
        !           648:        /*
        !           649:         * This is last because in the future we may want to make a different
        !           650:         * key based upon additional information from the packet (we may need
        !           651:         * to allow multiple leases in one client state per server, but we're
        !           652:         * not sure based on what additional keys now).
        !           653:         */
        !           654:        oc = lookup_option(&dhcpv6_universe, packet->options, D6O_SERVERID);
        !           655:        if (!evaluate_option_cache(&lease->server_id, packet, NULL, NULL,
        !           656:                                   lease->options, NULL, &global_scope,
        !           657:                                   oc, MDL) ||
        !           658:            lease->server_id.len == 0) {
        !           659:                /* This should be impossible due to validation checks earlier.
        !           660:                 */
        !           661:                log_error("Invalid SERVERID option cache.");
        !           662:                dhc6_lease_destroy(&lease, MDL);
        !           663:                return NULL;
        !           664:        } else {
        !           665:                log_debug("RCV:  X-- Server ID: %s",
        !           666:                          print_hex_1(lease->server_id.len,
        !           667:                                      lease->server_id.data, 52));
        !           668:        }
        !           669: 
        !           670:        return lease;
        !           671: }
        !           672: 
        !           673: static isc_result_t
        !           674: dhc6_parse_ia_na(struct dhc6_ia **pia, struct packet *packet,
        !           675:                 struct option_state *options)
        !           676: {
        !           677:        struct data_string ds;
        !           678:        struct dhc6_ia *ia;
        !           679:        struct option_cache *oc;
        !           680:        isc_result_t result;
        !           681: 
        !           682:        memset(&ds, 0, sizeof(ds));
        !           683: 
        !           684:        oc = lookup_option(&dhcpv6_universe, options, D6O_IA_NA);
        !           685:        for ( ; oc != NULL ; oc = oc->next) {
        !           686:                ia = dmalloc(sizeof(*ia), MDL);
        !           687:                if (ia == NULL) {
        !           688:                        log_error("Out of memory allocating IA_NA structure.");
        !           689:                        return ISC_R_NOMEMORY;
        !           690:                } else if (evaluate_option_cache(&ds, packet, NULL, NULL,
        !           691:                                                 options, NULL,
        !           692:                                                 &global_scope, oc, MDL) &&
        !           693:                           ds.len >= 12) {
        !           694:                        memcpy(ia->iaid, ds.data, 4);
        !           695:                        ia->ia_type = D6O_IA_NA;
        !           696:                        ia->starts = cur_time;
        !           697:                        ia->renew = getULong(ds.data + 4);
        !           698:                        ia->rebind = getULong(ds.data + 8);
        !           699: 
        !           700:                        log_debug("RCV:  X-- IA_NA %s",
        !           701:                                  print_hex_1(4, ia->iaid, 59));
        !           702:                        /* XXX: This should be the printed time I think. */
        !           703:                        log_debug("RCV:  | X-- starts %u",
        !           704:                                  (unsigned)ia->starts);
        !           705:                        log_debug("RCV:  | X-- t1 - renew  +%u", ia->renew);
        !           706:                        log_debug("RCV:  | X-- t2 - rebind +%u", ia->rebind);
        !           707: 
        !           708:                        /*
        !           709:                         * RFC3315 section 22.4, discard IA_NA's that
        !           710:                         * have t1 greater than t2, and both not zero.
        !           711:                         * Since RFC3315 defines this behaviour, it is not
        !           712:                         * an error - just normal operation.
        !           713:                         *
        !           714:                         * Note that RFC3315 says we MUST honor these values
        !           715:                         * if they are not zero.  So insane values are
        !           716:                         * totally OK.
        !           717:                         */
        !           718:                        if ((ia->renew > 0) && (ia->rebind > 0) &&
        !           719:                            (ia->renew > ia->rebind)) {
        !           720:                                log_debug("RCV:  | !-- INVALID renew/rebind "
        !           721:                                          "times, IA_NA discarded.");
        !           722:                                dfree(ia, MDL);
        !           723:                                data_string_forget(&ds, MDL);
        !           724:                                continue;
        !           725:                        }
        !           726: 
        !           727:                        if (ds.len > 12) {
        !           728:                                log_debug("RCV:  | X-- [Options]");
        !           729: 
        !           730:                                if (!option_state_allocate(&ia->options,
        !           731:                                                           MDL)) {
        !           732:                                        log_error("Out of memory allocating "
        !           733:                                                  "IA_NA option state.");
        !           734:                                        dfree(ia, MDL);
        !           735:                                        data_string_forget(&ds, MDL);
        !           736:                                        return ISC_R_NOMEMORY;
        !           737:                                }
        !           738: 
        !           739:                                if (!parse_option_buffer(ia->options,
        !           740:                                                         ds.data + 12,
        !           741:                                                         ds.len - 12,
        !           742:                                                         &dhcpv6_universe)) {
        !           743:                                        log_error("Corrupt IA_NA options.");
        !           744:                                        option_state_dereference(&ia->options,
        !           745:                                                                 MDL);
        !           746:                                        dfree(ia, MDL);
        !           747:                                        data_string_forget(&ds, MDL);
        !           748:                                        return ISC_R_BADPARSE;
        !           749:                                }
        !           750:                        }
        !           751:                        data_string_forget(&ds, MDL);
        !           752: 
        !           753:                        if (ia->options != NULL) {
        !           754:                                result = dhc6_parse_addrs(&ia->addrs, packet,
        !           755:                                                          ia->options);
        !           756:                                if (result != ISC_R_SUCCESS) {
        !           757:                                        option_state_dereference(&ia->options,
        !           758:                                                                 MDL);
        !           759:                                        dfree(ia, MDL);
        !           760:                                        return result;
        !           761:                                }
        !           762:                        }
        !           763: 
        !           764:                        while (*pia != NULL)
        !           765:                                pia = &(*pia)->next;
        !           766:                        *pia = ia;
        !           767:                        pia = &ia->next;
        !           768:                } else {
        !           769:                        log_error("Invalid IA_NA option cache.");
        !           770:                        dfree(ia, MDL);
        !           771:                        if (ds.len != 0)
        !           772:                                data_string_forget(&ds, MDL);
        !           773:                        return ISC_R_UNEXPECTED;
        !           774:                }
        !           775:        }
        !           776:        delete_option(&dhcpv6_universe, options, D6O_IA_NA);
        !           777: 
        !           778:        return ISC_R_SUCCESS;
        !           779: }
        !           780: 
        !           781: static isc_result_t
        !           782: dhc6_parse_ia_ta(struct dhc6_ia **pia, struct packet *packet,
        !           783:                 struct option_state *options)
        !           784: {
        !           785:        struct data_string ds;
        !           786:        struct dhc6_ia *ia;
        !           787:        struct option_cache *oc;
        !           788:        isc_result_t result;
        !           789: 
        !           790:        memset(&ds, 0, sizeof(ds));
        !           791: 
        !           792:        oc = lookup_option(&dhcpv6_universe, options, D6O_IA_TA);
        !           793:        for ( ; oc != NULL ; oc = oc->next) {
        !           794:                ia = dmalloc(sizeof(*ia), MDL);
        !           795:                if (ia == NULL) {
        !           796:                        log_error("Out of memory allocating IA_TA structure.");
        !           797:                        return ISC_R_NOMEMORY;
        !           798:                } else if (evaluate_option_cache(&ds, packet, NULL, NULL,
        !           799:                                                 options, NULL,
        !           800:                                                 &global_scope, oc, MDL) &&
        !           801:                           ds.len >= 4) {
        !           802:                        memcpy(ia->iaid, ds.data, 4);
        !           803:                        ia->ia_type = D6O_IA_TA;
        !           804:                        ia->starts = cur_time;
        !           805: 
        !           806:                        log_debug("RCV:  X-- IA_TA %s",
        !           807:                                  print_hex_1(4, ia->iaid, 59));
        !           808:                        /* XXX: This should be the printed time I think. */
        !           809:                        log_debug("RCV:  | X-- starts %u",
        !           810:                                  (unsigned)ia->starts);
        !           811: 
        !           812:                        if (ds.len > 4) {
        !           813:                                log_debug("RCV:  | X-- [Options]");
        !           814: 
        !           815:                                if (!option_state_allocate(&ia->options,
        !           816:                                                           MDL)) {
        !           817:                                        log_error("Out of memory allocating "
        !           818:                                                  "IA_TA option state.");
        !           819:                                        dfree(ia, MDL);
        !           820:                                        data_string_forget(&ds, MDL);
        !           821:                                        return ISC_R_NOMEMORY;
        !           822:                                }
        !           823: 
        !           824:                                if (!parse_option_buffer(ia->options,
        !           825:                                                         ds.data + 4,
        !           826:                                                         ds.len - 4,
        !           827:                                                         &dhcpv6_universe)) {
        !           828:                                        log_error("Corrupt IA_TA options.");
        !           829:                                        option_state_dereference(&ia->options,
        !           830:                                                                 MDL);
        !           831:                                        dfree(ia, MDL);
        !           832:                                        data_string_forget(&ds, MDL);
        !           833:                                        return ISC_R_BADPARSE;
        !           834:                                }
        !           835:                        }
        !           836:                        data_string_forget(&ds, MDL);
        !           837: 
        !           838:                        if (ia->options != NULL) {
        !           839:                                result = dhc6_parse_addrs(&ia->addrs, packet,
        !           840:                                                          ia->options);
        !           841:                                if (result != ISC_R_SUCCESS) {
        !           842:                                        option_state_dereference(&ia->options,
        !           843:                                                                 MDL);
        !           844:                                        dfree(ia, MDL);
        !           845:                                        return result;
        !           846:                                }
        !           847:                        }
        !           848: 
        !           849:                        while (*pia != NULL)
        !           850:                                pia = &(*pia)->next;
        !           851:                        *pia = ia;
        !           852:                        pia = &ia->next;
        !           853:                } else {
        !           854:                        log_error("Invalid IA_TA option cache.");
        !           855:                        dfree(ia, MDL);
        !           856:                        if (ds.len != 0)
        !           857:                                data_string_forget(&ds, MDL);
        !           858:                        return ISC_R_UNEXPECTED;
        !           859:                }
        !           860:        }
        !           861:        delete_option(&dhcpv6_universe, options, D6O_IA_TA);
        !           862: 
        !           863:        return ISC_R_SUCCESS;
        !           864: }
        !           865: 
        !           866: static isc_result_t
        !           867: dhc6_parse_ia_pd(struct dhc6_ia **pia, struct packet *packet,
        !           868:                 struct option_state *options)
        !           869: {
        !           870:        struct data_string ds;
        !           871:        struct dhc6_ia *ia;
        !           872:        struct option_cache *oc;
        !           873:        isc_result_t result;
        !           874: 
        !           875:        memset(&ds, 0, sizeof(ds));
        !           876: 
        !           877:        oc = lookup_option(&dhcpv6_universe, options, D6O_IA_PD);
        !           878:        for ( ; oc != NULL ; oc = oc->next) {
        !           879:                ia = dmalloc(sizeof(*ia), MDL);
        !           880:                if (ia == NULL) {
        !           881:                        log_error("Out of memory allocating IA_PD structure.");
        !           882:                        return ISC_R_NOMEMORY;
        !           883:                } else if (evaluate_option_cache(&ds, packet, NULL, NULL,
        !           884:                                                 options, NULL,
        !           885:                                                 &global_scope, oc, MDL) &&
        !           886:                           ds.len >= 12) {
        !           887:                        memcpy(ia->iaid, ds.data, 4);
        !           888:                        ia->ia_type = D6O_IA_PD;
        !           889:                        ia->starts = cur_time;
        !           890:                        ia->renew = getULong(ds.data + 4);
        !           891:                        ia->rebind = getULong(ds.data + 8);
        !           892: 
        !           893:                        log_debug("RCV:  X-- IA_PD %s",
        !           894:                                  print_hex_1(4, ia->iaid, 59));
        !           895:                        /* XXX: This should be the printed time I think. */
        !           896:                        log_debug("RCV:  | X-- starts %u",
        !           897:                                  (unsigned)ia->starts);
        !           898:                        log_debug("RCV:  | X-- t1 - renew  +%u", ia->renew);
        !           899:                        log_debug("RCV:  | X-- t2 - rebind +%u", ia->rebind);
        !           900: 
        !           901:                        /*
        !           902:                         * RFC3633 section 9, discard IA_PD's that
        !           903:                         * have t1 greater than t2, and both not zero.
        !           904:                         * Since RFC3633 defines this behaviour, it is not
        !           905:                         * an error - just normal operation.
        !           906:                         */
        !           907:                        if ((ia->renew > 0) && (ia->rebind > 0) &&
        !           908:                            (ia->renew > ia->rebind)) {
        !           909:                                log_debug("RCV:  | !-- INVALID renew/rebind "
        !           910:                                          "times, IA_PD discarded.");
        !           911:                                dfree(ia, MDL);
        !           912:                                data_string_forget(&ds, MDL);
        !           913:                                continue;
        !           914:                        }
        !           915: 
        !           916:                        if (ds.len > 12) {
        !           917:                                log_debug("RCV:  | X-- [Options]");
        !           918: 
        !           919:                                if (!option_state_allocate(&ia->options,
        !           920:                                                           MDL)) {
        !           921:                                        log_error("Out of memory allocating "
        !           922:                                                  "IA_PD option state.");
        !           923:                                        dfree(ia, MDL);
        !           924:                                        data_string_forget(&ds, MDL);
        !           925:                                        return ISC_R_NOMEMORY;
        !           926:                                }
        !           927: 
        !           928:                                if (!parse_option_buffer(ia->options,
        !           929:                                                         ds.data + 12,
        !           930:                                                         ds.len - 12,
        !           931:                                                         &dhcpv6_universe)) {
        !           932:                                        log_error("Corrupt IA_PD options.");
        !           933:                                        option_state_dereference(&ia->options,
        !           934:                                                                 MDL);
        !           935:                                        dfree(ia, MDL);
        !           936:                                        data_string_forget(&ds, MDL);
        !           937:                                        return ISC_R_BADPARSE;
        !           938:                                }
        !           939:                        }
        !           940:                        data_string_forget(&ds, MDL);
        !           941: 
        !           942:                        if (ia->options != NULL) {
        !           943:                                result = dhc6_parse_prefixes(&ia->addrs,
        !           944:                                                             packet,
        !           945:                                                             ia->options);
        !           946:                                if (result != ISC_R_SUCCESS) {
        !           947:                                        option_state_dereference(&ia->options,
        !           948:                                                                 MDL);
        !           949:                                        dfree(ia, MDL);
        !           950:                                        return result;
        !           951:                                }
        !           952:                        }
        !           953: 
        !           954:                        while (*pia != NULL)
        !           955:                                pia = &(*pia)->next;
        !           956:                        *pia = ia;
        !           957:                        pia = &ia->next;
        !           958:                } else {
        !           959:                        log_error("Invalid IA_PD option cache.");
        !           960:                        dfree(ia, MDL);
        !           961:                        if (ds.len != 0)
        !           962:                                data_string_forget(&ds, MDL);
        !           963:                        return ISC_R_UNEXPECTED;
        !           964:                }
        !           965:        }
        !           966:        delete_option(&dhcpv6_universe, options, D6O_IA_PD);
        !           967: 
        !           968:        return ISC_R_SUCCESS;
        !           969: }
        !           970: 
        !           971: 
        !           972: static isc_result_t
        !           973: dhc6_parse_addrs(struct dhc6_addr **paddr, struct packet *packet,
        !           974:                 struct option_state *options)
        !           975: {
        !           976:        struct data_string ds;
        !           977:        struct option_cache *oc;
        !           978:        struct dhc6_addr *addr;
        !           979: 
        !           980:        memset(&ds, 0, sizeof(ds));
        !           981: 
        !           982:        oc = lookup_option(&dhcpv6_universe, options, D6O_IAADDR);
        !           983:        for ( ; oc != NULL ; oc = oc->next) {
        !           984:                addr = dmalloc(sizeof(*addr), MDL);
        !           985:                if (addr == NULL) {
        !           986:                        log_error("Out of memory allocating "
        !           987:                                  "address structure.");
        !           988:                        return ISC_R_NOMEMORY;
        !           989:                } else if (evaluate_option_cache(&ds, packet, NULL, NULL,
        !           990:                                                 options, NULL, &global_scope,
        !           991:                                                 oc, MDL) &&
        !           992:                           (ds.len >= 24)) {
        !           993: 
        !           994:                        addr->address.len = 16;
        !           995:                        memcpy(addr->address.iabuf, ds.data, 16);
        !           996:                        addr->starts = cur_time;
        !           997:                        addr->preferred_life = getULong(ds.data + 16);
        !           998:                        addr->max_life = getULong(ds.data + 20);
        !           999: 
        !          1000:                        log_debug("RCV:  | | X-- IAADDR %s",
        !          1001:                                  piaddr(addr->address));
        !          1002:                        log_debug("RCV:  | | | X-- Preferred lifetime %u.",
        !          1003:                                  addr->preferred_life);
        !          1004:                        log_debug("RCV:  | | | X-- Max lifetime %u.",
        !          1005:                                  addr->max_life);
        !          1006: 
        !          1007:                        /*
        !          1008:                         * RFC 3315 section 22.6 says we must discard
        !          1009:                         * addresses whose pref is later than valid.
        !          1010:                         */
        !          1011:                        if ((addr->preferred_life > addr->max_life)) {
        !          1012:                                log_debug("RCV:  | | | !-- INVALID lifetimes, "
        !          1013:                                          "IAADDR discarded.  Check your "
        !          1014:                                          "server configuration.");
        !          1015:                                dfree(addr, MDL);
        !          1016:                                data_string_forget(&ds, MDL);
        !          1017:                                continue;
        !          1018:                        }
        !          1019: 
        !          1020:                        /*
        !          1021:                         * Fortunately this is the last recursion in the
        !          1022:                         * protocol.
        !          1023:                         */
        !          1024:                        if (ds.len > 24) {
        !          1025:                                if (!option_state_allocate(&addr->options,
        !          1026:                                                           MDL)) {
        !          1027:                                        log_error("Out of memory allocating "
        !          1028:                                                  "IAADDR option state.");
        !          1029:                                        dfree(addr, MDL);
        !          1030:                                        data_string_forget(&ds, MDL);
        !          1031:                                        return ISC_R_NOMEMORY;
        !          1032:                                }
        !          1033: 
        !          1034:                                if (!parse_option_buffer(addr->options,
        !          1035:                                                         ds.data + 24,
        !          1036:                                                         ds.len - 24,
        !          1037:                                                         &dhcpv6_universe)) {
        !          1038:                                        log_error("Corrupt IAADDR options.");
        !          1039:                                        option_state_dereference(&addr->options,
        !          1040:                                                                 MDL);
        !          1041:                                        dfree(addr, MDL);
        !          1042:                                        data_string_forget(&ds, MDL);
        !          1043:                                        return ISC_R_BADPARSE;
        !          1044:                                }
        !          1045:                        }
        !          1046: 
        !          1047:                        if (addr->options != NULL)
        !          1048:                                log_debug("RCV:  | | | X-- "
        !          1049:                                          "[Options]");
        !          1050: 
        !          1051:                        data_string_forget(&ds, MDL);
        !          1052: 
        !          1053:                        *paddr = addr;
        !          1054:                        paddr = &addr->next;
        !          1055:                } else {
        !          1056:                        log_error("Invalid IAADDR option cache.");
        !          1057:                        dfree(addr, MDL);
        !          1058:                        if (ds.len != 0)
        !          1059:                                data_string_forget(&ds, MDL);
        !          1060:                        return ISC_R_UNEXPECTED;
        !          1061:                }
        !          1062:        }
        !          1063:        delete_option(&dhcpv6_universe, options, D6O_IAADDR);
        !          1064: 
        !          1065:        return ISC_R_SUCCESS;
        !          1066: }
        !          1067: 
        !          1068: static isc_result_t
        !          1069: dhc6_parse_prefixes(struct dhc6_addr **ppfx, struct packet *packet,
        !          1070:                    struct option_state *options)
        !          1071: {
        !          1072:        struct data_string ds;
        !          1073:        struct option_cache *oc;
        !          1074:        struct dhc6_addr *pfx;
        !          1075: 
        !          1076:        memset(&ds, 0, sizeof(ds));
        !          1077: 
        !          1078:        oc = lookup_option(&dhcpv6_universe, options, D6O_IAPREFIX);
        !          1079:        for ( ; oc != NULL ; oc = oc->next) {
        !          1080:                pfx = dmalloc(sizeof(*pfx), MDL);
        !          1081:                if (pfx == NULL) {
        !          1082:                        log_error("Out of memory allocating "
        !          1083:                                  "prefix structure.");
        !          1084:                        return ISC_R_NOMEMORY;
        !          1085:                } else if (evaluate_option_cache(&ds, packet, NULL, NULL,
        !          1086:                                                 options, NULL, &global_scope,
        !          1087:                                                 oc, MDL) &&
        !          1088:                           (ds.len >= 25)) {
        !          1089: 
        !          1090:                        pfx->preferred_life = getULong(ds.data);
        !          1091:                        pfx->max_life = getULong(ds.data + 4);
        !          1092:                        pfx->plen = getUChar(ds.data + 8);
        !          1093:                        pfx->address.len = 16;
        !          1094:                        memcpy(pfx->address.iabuf, ds.data + 9, 16);
        !          1095:                        pfx->starts = cur_time;
        !          1096: 
        !          1097:                        log_debug("RCV:  | | X-- IAPREFIX %s/%d",
        !          1098:                                  piaddr(pfx->address), (int)pfx->plen);
        !          1099:                        log_debug("RCV:  | | | X-- Preferred lifetime %u.",
        !          1100:                                  pfx->preferred_life);
        !          1101:                        log_debug("RCV:  | | | X-- Max lifetime %u.",
        !          1102:                                  pfx->max_life);
        !          1103: 
        !          1104:                        /* Sanity check over the prefix length */
        !          1105:                        if ((pfx->plen < 4) || (pfx->plen > 128)) {
        !          1106:                                log_debug("RCV:  | | | !-- INVALID prefix "
        !          1107:                                          "length, IAPREFIX discarded.  "
        !          1108:                                          "Check your server configuration.");
        !          1109:                                dfree(pfx, MDL);
        !          1110:                                data_string_forget(&ds, MDL);
        !          1111:                                continue;
        !          1112:                        }
        !          1113:                        /*
        !          1114:                         * RFC 3633 section 10 says we must discard
        !          1115:                         * prefixes whose pref is later than valid.
        !          1116:                         */
        !          1117:                        if ((pfx->preferred_life > pfx->max_life)) {
        !          1118:                                log_debug("RCV:  | | | !-- INVALID lifetimes, "
        !          1119:                                          "IAPREFIX discarded.  Check your "
        !          1120:                                          "server configuration.");
        !          1121:                                dfree(pfx, MDL);
        !          1122:                                data_string_forget(&ds, MDL);
        !          1123:                                continue;
        !          1124:                        }
        !          1125: 
        !          1126:                        /*
        !          1127:                         * Fortunately this is the last recursion in the
        !          1128:                         * protocol.
        !          1129:                         */
        !          1130:                        if (ds.len > 25) {
        !          1131:                                if (!option_state_allocate(&pfx->options,
        !          1132:                                                           MDL)) {
        !          1133:                                        log_error("Out of memory allocating "
        !          1134:                                                  "IAPREFIX option state.");
        !          1135:                                        dfree(pfx, MDL);
        !          1136:                                        data_string_forget(&ds, MDL);
        !          1137:                                        return ISC_R_NOMEMORY;
        !          1138:                                }
        !          1139: 
        !          1140:                                if (!parse_option_buffer(pfx->options,
        !          1141:                                                         ds.data + 25,
        !          1142:                                                         ds.len - 25,
        !          1143:                                                         &dhcpv6_universe)) {
        !          1144:                                        log_error("Corrupt IAPREFIX options.");
        !          1145:                                        option_state_dereference(&pfx->options,
        !          1146:                                                                 MDL);
        !          1147:                                        dfree(pfx, MDL);
        !          1148:                                        data_string_forget(&ds, MDL);
        !          1149:                                        return ISC_R_BADPARSE;
        !          1150:                                }
        !          1151:                        }
        !          1152: 
        !          1153:                        if (pfx->options != NULL)
        !          1154:                                log_debug("RCV:  | | | X-- "
        !          1155:                                          "[Options]");
        !          1156: 
        !          1157:                        data_string_forget(&ds, MDL);
        !          1158: 
        !          1159:                        *ppfx = pfx;
        !          1160:                        ppfx = &pfx->next;
        !          1161:                } else {
        !          1162:                        log_error("Invalid IAPREFIX option cache.");
        !          1163:                        dfree(pfx, MDL);
        !          1164:                        if (ds.len != 0)
        !          1165:                                data_string_forget(&ds, MDL);
        !          1166:                        return ISC_R_UNEXPECTED;
        !          1167:                }
        !          1168:        }
        !          1169:        delete_option(&dhcpv6_universe, options, D6O_IAPREFIX);
        !          1170: 
        !          1171:        return ISC_R_SUCCESS;
        !          1172: }
        !          1173: 
        !          1174: /* Clean up a lease object, deallocate all its parts, and set it to NULL. */
        !          1175: void
        !          1176: dhc6_lease_destroy(struct dhc6_lease **src, const char *file, int line)
        !          1177: {
        !          1178:        struct dhc6_ia *ia, *nia;
        !          1179:        struct dhc6_lease *lease;
        !          1180: 
        !          1181:        if (src == NULL || *src == NULL) {
        !          1182:                log_error("Attempt to destroy null lease.");
        !          1183:                return;
        !          1184:        }
        !          1185:        lease = *src;
        !          1186: 
        !          1187:        if (lease->server_id.len != 0)
        !          1188:                data_string_forget(&lease->server_id, file, line);
        !          1189: 
        !          1190:        for (ia = lease->bindings ; ia != NULL ; ia = nia) {
        !          1191:                nia = ia->next;
        !          1192: 
        !          1193:                dhc6_ia_destroy(&ia, file, line);
        !          1194:        }
        !          1195: 
        !          1196:        if (lease->options != NULL)
        !          1197:                option_state_dereference(&lease->options, file, line);
        !          1198: 
        !          1199:        dfree(lease, file, line);
        !          1200:        *src = NULL;
        !          1201: }
        !          1202: 
        !          1203: /*
        !          1204:  * Traverse the addresses list, and destroy their contents, and NULL the
        !          1205:  * list pointer.
        !          1206:  */
        !          1207: static void
        !          1208: dhc6_ia_destroy(struct dhc6_ia **src, const char *file, int line)
        !          1209: {
        !          1210:        struct dhc6_addr *addr, *naddr;
        !          1211:        struct dhc6_ia *ia;
        !          1212: 
        !          1213:        if (src == NULL || *src == NULL) {
        !          1214:                log_error("Attempt to destroy null IA.");
        !          1215:                return;
        !          1216:        }
        !          1217:        ia = *src;
        !          1218: 
        !          1219:        for (addr = ia->addrs ; addr != NULL ; addr = naddr) {
        !          1220:                naddr = addr->next;
        !          1221: 
        !          1222:                if (addr->options != NULL)
        !          1223:                        option_state_dereference(&addr->options, file, line);
        !          1224: 
        !          1225:                dfree(addr, file, line);
        !          1226:        }
        !          1227: 
        !          1228:        if (ia->options != NULL)
        !          1229:                option_state_dereference(&ia->options, file, line);
        !          1230: 
        !          1231:        dfree(ia, file, line);
        !          1232:        *src = NULL;
        !          1233: }
        !          1234: 
        !          1235: /*
        !          1236:  * For a given lease, insert it into the tail of the lease list.  Upon
        !          1237:  * finding a duplicate by server id, remove it and take over its position.
        !          1238:  */
        !          1239: static void
        !          1240: insert_lease(struct dhc6_lease **head, struct dhc6_lease *new)
        !          1241: {
        !          1242:        while (*head != NULL) {
        !          1243:                if ((*head)->server_id.len == new->server_id.len &&
        !          1244:                    memcmp((*head)->server_id.data, new->server_id.data,
        !          1245:                           new->server_id.len) == 0) {
        !          1246:                        new->next = (*head)->next;
        !          1247:                        dhc6_lease_destroy(head, MDL);
        !          1248:                        break;
        !          1249:                }
        !          1250: 
        !          1251:                head= &(*head)->next;
        !          1252:        }
        !          1253: 
        !          1254:        *head = new;
        !          1255:        return;
        !          1256: }
        !          1257: 
        !          1258: /*
        !          1259:  * Not really clear what to do here yet.
        !          1260:  */
        !          1261: static int
        !          1262: dhc6_score_lease(struct client_state *client, struct dhc6_lease *lease)
        !          1263: {
        !          1264:        struct dhc6_ia *ia;
        !          1265:        struct dhc6_addr *addr;
        !          1266:        struct option **req;
        !          1267:        int i;
        !          1268: 
        !          1269:        if (lease->score)
        !          1270:                return lease->score;
        !          1271: 
        !          1272:        lease->score = 1;
        !          1273: 
        !          1274:        /* If this lease lacks a required option, dump it. */
        !          1275:        /* XXX: we should be able to cache the failure... */
        !          1276:        req = client->config->required_options;
        !          1277:        if (req != NULL) {
        !          1278:                for (i = 0 ; req[i] != NULL ; i++) {
        !          1279:                        if (lookup_option(&dhcpv6_universe, lease->options,
        !          1280:                                          req[i]->code) == NULL) {
        !          1281:                                lease->score = 0;
        !          1282:                                return lease->score;
        !          1283:                        }
        !          1284:                }
        !          1285:        }
        !          1286: 
        !          1287:        /* If this lease contains a requested option, improve its score. */
        !          1288:        req = client->config->requested_options;
        !          1289:        if (req != NULL) {
        !          1290:                for (i = 0 ; req[i] != NULL ; i++) {
        !          1291:                        if (lookup_option(&dhcpv6_universe, lease->options,
        !          1292:                                          req[i]->code) != NULL)
        !          1293:                                lease->score++;
        !          1294:                }
        !          1295:        }
        !          1296: 
        !          1297:        for (ia = lease->bindings ; ia != NULL ; ia = ia->next) {
        !          1298:                lease->score += 50;
        !          1299: 
        !          1300:                for (addr = ia->addrs ; addr != NULL ; addr = addr->next) {
        !          1301:                        lease->score += 100;
        !          1302:                }
        !          1303:        }
        !          1304: 
        !          1305:        return lease->score;
        !          1306: }
        !          1307: 
        !          1308: /*
        !          1309:  * start_init6() kicks off the process, transmitting a packet and
        !          1310:  * scheduling a retransmission event.
        !          1311:  */
        !          1312: void
        !          1313: start_init6(struct client_state *client)
        !          1314: {
        !          1315:        struct timeval tv;
        !          1316: 
        !          1317:        log_debug("PRC: Soliciting for leases (INIT).");
        !          1318:        client->state = S_INIT;
        !          1319: 
        !          1320:        /* Initialize timers, RFC3315 section 17.1.2. */
        !          1321:        client->IRT = SOL_TIMEOUT * 100;
        !          1322:        client->MRT = SOL_MAX_RT * 100;
        !          1323:        client->MRC = 0;
        !          1324:        /* Default is 0 (no max) but -1 changes this. */
        !          1325:        if (!onetry)
        !          1326:                client->MRD = 0;
        !          1327:        else
        !          1328:                client->MRD = client->config->timeout;
        !          1329: 
        !          1330:        dhc6_retrans_init(client);
        !          1331: 
        !          1332:        /*
        !          1333:         * RFC3315 section 17.1.2 goes out of its way:
        !          1334:         * Also, the first RT MUST be selected to be strictly greater than IRT
        !          1335:         * by choosing RAND to be strictly greater than 0.
        !          1336:         */
        !          1337:        /* if RAND < 0 then RAND = -RAND */
        !          1338:        if (client->RT <= client->IRT)
        !          1339:                client->RT = client->IRT + (client->IRT - client->RT);
        !          1340:        /* if RAND == 0 then RAND = 1 */
        !          1341:        if (client->RT <= client->IRT)
        !          1342:                client->RT = client->IRT + 1;
        !          1343: 
        !          1344:        client->v6_handler = init_handler;
        !          1345: 
        !          1346:        /*
        !          1347:         * RFC3315 section 17.1.2 says we MUST start the first packet
        !          1348:         * between 0 and SOL_MAX_DELAY seconds.  The good news is
        !          1349:         * SOL_MAX_DELAY is 1.
        !          1350:         */
        !          1351:        tv.tv_sec = cur_tv.tv_sec;
        !          1352:        tv.tv_usec = cur_tv.tv_usec;
        !          1353:        tv.tv_usec += (random() % (SOL_MAX_DELAY * 100)) * 10000;
        !          1354:        if (tv.tv_usec >= 1000000) {
        !          1355:                tv.tv_sec += 1;
        !          1356:                tv.tv_usec -= 1000000;
        !          1357:        }
        !          1358:        add_timeout(&tv, do_init6, client, NULL, NULL);
        !          1359: 
        !          1360:        if (nowait)
        !          1361:                go_daemon();
        !          1362: }
        !          1363: 
        !          1364: /*
        !          1365:  * start_info_request6() kicks off the process, transmitting an info
        !          1366:  * request packet and scheduling a retransmission event.
        !          1367:  */
        !          1368: void
        !          1369: start_info_request6(struct client_state *client)
        !          1370: {
        !          1371:        struct timeval tv;
        !          1372: 
        !          1373:        log_debug("PRC: Requesting information (INIT).");
        !          1374:        client->state = S_INIT;
        !          1375: 
        !          1376:        /* Initialize timers, RFC3315 section 18.1.5. */
        !          1377:        client->IRT = INF_TIMEOUT * 100;
        !          1378:        client->MRT = INF_MAX_RT * 100;
        !          1379:        client->MRC = 0;
        !          1380:        /* Default is 0 (no max) but -1 changes this. */
        !          1381:        if (!onetry)
        !          1382:                client->MRD = 0;
        !          1383:        else
        !          1384:                client->MRD = client->config->timeout;
        !          1385: 
        !          1386:        dhc6_retrans_init(client);
        !          1387: 
        !          1388:        client->v6_handler = info_request_handler;
        !          1389: 
        !          1390:        /*
        !          1391:         * RFC3315 section 18.1.5 says we MUST start the first packet
        !          1392:         * between 0 and INF_MAX_DELAY seconds.  The good news is
        !          1393:         * INF_MAX_DELAY is 1.
        !          1394:         */
        !          1395:        tv.tv_sec = cur_tv.tv_sec;
        !          1396:        tv.tv_usec = cur_tv.tv_usec;
        !          1397:        tv.tv_usec += (random() % (INF_MAX_DELAY * 100)) * 10000;
        !          1398:        if (tv.tv_usec >= 1000000) {
        !          1399:                tv.tv_sec += 1;
        !          1400:                tv.tv_usec -= 1000000;
        !          1401:        }
        !          1402:        add_timeout(&tv, do_info_request6, client, NULL, NULL);
        !          1403: 
        !          1404:        if (nowait)
        !          1405:                go_daemon();
        !          1406: }
        !          1407: 
        !          1408: /*
        !          1409:  * start_confirm6() kicks off an "init-reboot" version of the process, at
        !          1410:  * startup to find out if old bindings are 'fair' and at runtime whenever
        !          1411:  * a link cycles state we'll eventually want to do this.
        !          1412:  */
        !          1413: void
        !          1414: start_confirm6(struct client_state *client)
        !          1415: {
        !          1416:        struct timeval tv;
        !          1417: 
        !          1418:        /* If there is no active lease, there is nothing to check. */
        !          1419:        if ((client->active_lease == NULL) ||
        !          1420:            !active_prefix(client) ||
        !          1421:            client->active_lease->released) {
        !          1422:                start_init6(client);
        !          1423:                return;
        !          1424:        }
        !          1425: 
        !          1426:        log_debug("PRC: Confirming active lease (INIT-REBOOT).");
        !          1427:        client->state = S_REBOOTING;
        !          1428: 
        !          1429:        /* Initialize timers, RFC3315 section 17.1.3. */
        !          1430:        client->IRT = CNF_TIMEOUT * 100;
        !          1431:        client->MRT = CNF_MAX_RT * 100;
        !          1432:        client->MRC = 0;
        !          1433:        client->MRD = CNF_MAX_RD;
        !          1434: 
        !          1435:        dhc6_retrans_init(client);
        !          1436: 
        !          1437:        client->v6_handler = reply_handler;
        !          1438: 
        !          1439:        /*
        !          1440:         * RFC3315 section 18.1.2 says we MUST start the first packet
        !          1441:         * between 0 and CNF_MAX_DELAY seconds.  The good news is
        !          1442:         * CNF_MAX_DELAY is 1.
        !          1443:         */
        !          1444:        tv.tv_sec = cur_tv.tv_sec;
        !          1445:        tv.tv_usec = cur_tv.tv_usec;
        !          1446:        tv.tv_usec += (random() % (CNF_MAX_DELAY * 100)) * 10000;
        !          1447:        if (tv.tv_usec >= 1000000) {
        !          1448:                tv.tv_sec += 1;
        !          1449:                tv.tv_usec -= 1000000;
        !          1450:        }
        !          1451:        if (wanted_ia_pd != 0) {
        !          1452:                client->state = S_REBINDING;
        !          1453:                client->refresh_type = DHCPV6_REBIND;
        !          1454:                add_timeout(&tv, do_refresh6, client, NULL, NULL);
        !          1455:        } else
        !          1456:                add_timeout(&tv, do_confirm6, client, NULL, NULL);
        !          1457: }
        !          1458: 
        !          1459: /*
        !          1460:  * check_timing6() check on the timing for sending a v6 message
        !          1461:  * and then do the basic initialization for a v6 message.
        !          1462:  */
        !          1463: #define CHK_TIM_SUCCESS                0
        !          1464: #define CHK_TIM_MRC_EXCEEDED   1
        !          1465: #define CHK_TIM_MRD_EXCEEDED   2
        !          1466: #define CHK_TIM_ALLOC_FAILURE  3
        !          1467: 
        !          1468: int
        !          1469: check_timing6 (struct client_state *client, u_int8_t msg_type, 
        !          1470:               char *msg_str, struct dhc6_lease *lease,
        !          1471:               struct data_string *ds)
        !          1472: {
        !          1473:        struct timeval elapsed;
        !          1474: 
        !          1475:        /*
        !          1476:         * Start_time starts at the first transmission.
        !          1477:         */
        !          1478:        if (client->txcount == 0) {
        !          1479:                client->start_time.tv_sec = cur_tv.tv_sec;
        !          1480:                client->start_time.tv_usec = cur_tv.tv_usec;
        !          1481:        } else if ((client->MRC != 0) && (client->txcount > client->MRC)) {
        !          1482:                log_info("Max retransmission count exceeded.");
        !          1483:                return(CHK_TIM_MRC_EXCEEDED);
        !          1484:        }
        !          1485: 
        !          1486:        /* elapsed = cur - start */
        !          1487:        elapsed.tv_sec = cur_tv.tv_sec - client->start_time.tv_sec;
        !          1488:        elapsed.tv_usec = cur_tv.tv_usec - client->start_time.tv_usec;
        !          1489:        if (elapsed.tv_usec < 0) {
        !          1490:                elapsed.tv_sec -= 1;
        !          1491:                elapsed.tv_usec += 1000000;
        !          1492:        }
        !          1493: 
        !          1494:        /* Check if finished (-1 argument). */
        !          1495:        if ((client->MRD != 0) && (elapsed.tv_sec > client->MRD)) {
        !          1496:                log_info("Max retransmission duration exceeded.");
        !          1497:                return(CHK_TIM_MRD_EXCEEDED);
        !          1498:        }
        !          1499: 
        !          1500:        memset(ds, 0, sizeof(*ds));
        !          1501:        if (!buffer_allocate(&(ds->buffer), 4, MDL)) {
        !          1502:                log_error("Unable to allocate memory for %s.", msg_str);
        !          1503:                return(CHK_TIM_ALLOC_FAILURE);
        !          1504:        }
        !          1505:        ds->data = ds->buffer->data;
        !          1506:        ds->len = 4;
        !          1507: 
        !          1508:        ds->buffer->data[0] = msg_type;
        !          1509:        memcpy(ds->buffer->data + 1, client->dhcpv6_transaction_id, 3);
        !          1510: 
        !          1511:        /* Form an elapsed option. */
        !          1512:        /* Maximum value is 65535 1/100s coded as 0xffff. */
        !          1513:        if ((elapsed.tv_sec < 0) || (elapsed.tv_sec > 655) ||
        !          1514:            ((elapsed.tv_sec == 655) && (elapsed.tv_usec > 350000))) {
        !          1515:                client->elapsed = 0xffff;
        !          1516:        } else {
        !          1517:                client->elapsed = elapsed.tv_sec * 100;
        !          1518:                client->elapsed += elapsed.tv_usec / 10000;
        !          1519:        }
        !          1520: 
        !          1521:        if (client->elapsed == 0)
        !          1522:                log_debug("XMT: Forming %s, 0 ms elapsed.", msg_str);
        !          1523:        else
        !          1524:                log_debug("XMT: Forming %s, %u0 ms elapsed.", msg_str,
        !          1525:                          (unsigned)client->elapsed);
        !          1526: 
        !          1527:        client->elapsed = htons(client->elapsed);
        !          1528: 
        !          1529:        make_client6_options(client, &client->sent_options, lease, msg_type);
        !          1530: 
        !          1531:        return(CHK_TIM_SUCCESS);
        !          1532: }
        !          1533: 
        !          1534: /*
        !          1535:  * do_init6() marshals and transmits a solicit.
        !          1536:  */
        !          1537: void
        !          1538: do_init6(void *input)
        !          1539: {
        !          1540:        struct client_state *client;
        !          1541:        struct dhc6_ia *old_ia;
        !          1542:        struct dhc6_addr *old_addr;
        !          1543:        struct data_string ds;
        !          1544:        struct data_string ia;
        !          1545:        struct data_string addr;
        !          1546:        struct timeval tv;
        !          1547:        u_int32_t t1, t2;
        !          1548:        int i, idx, len, send_ret;
        !          1549: 
        !          1550:        client = input;
        !          1551: 
        !          1552:        /*
        !          1553:         * In RFC3315 section 17.1.2, the retransmission timer is
        !          1554:         * used as the selecting timer.
        !          1555:         */
        !          1556:        if (client->advertised_leases != NULL) {
        !          1557:                start_selecting6(client);
        !          1558:                return;
        !          1559:        }
        !          1560: 
        !          1561:        switch(check_timing6(client, DHCPV6_SOLICIT, "Solicit", NULL, &ds)) {
        !          1562:              case CHK_TIM_MRC_EXCEEDED:
        !          1563:              case CHK_TIM_ALLOC_FAILURE:
        !          1564:                return;
        !          1565:              case CHK_TIM_MRD_EXCEEDED:
        !          1566:                client->state = S_STOPPED;
        !          1567:                if (client->active_lease != NULL) {
        !          1568:                        dhc6_lease_destroy(&client->active_lease, MDL);
        !          1569:                        client->active_lease = NULL;
        !          1570:                }
        !          1571:                /* Stop if and only if this is the last client. */
        !          1572:                if (stopping_finished())
        !          1573:                        exit(2);
        !          1574:                return;
        !          1575:        }
        !          1576: 
        !          1577:        /*
        !          1578:         * Fetch any configured 'sent' options (includes DUID) in wire format.
        !          1579:         */
        !          1580:        dhcpv6_universe.encapsulate(&ds, NULL, NULL, client,
        !          1581:                                    NULL, client->sent_options, &global_scope,
        !          1582:                                    &dhcpv6_universe);
        !          1583: 
        !          1584:        /* Use a specific handler with rapid-commit. */
        !          1585:        if (lookup_option(&dhcpv6_universe, client->sent_options,
        !          1586:                          D6O_RAPID_COMMIT) != NULL) {
        !          1587:                client->v6_handler = rapid_commit_handler;
        !          1588:        }
        !          1589: 
        !          1590:        /* Append IA_NA. */
        !          1591:        for (i = 0; i < wanted_ia_na; i++) {
        !          1592:                /*
        !          1593:                 * XXX: maybe the IA_NA('s) should be put into the sent_options
        !          1594:                 * cache.  They'd have to be pulled down as they also contain
        !          1595:                 * different option caches in the same universe...
        !          1596:                 */
        !          1597:                memset(&ia, 0, sizeof(ia));
        !          1598:                if (!buffer_allocate(&ia.buffer, 12, MDL)) {
        !          1599:                        log_error("Unable to allocate memory for IA_NA.");
        !          1600:                        data_string_forget(&ds, MDL);
        !          1601:                        return;
        !          1602:                }
        !          1603:                ia.data = ia.buffer->data;
        !          1604:                ia.len = 12;
        !          1605: 
        !          1606:                /*
        !          1607:                 * A simple IAID is the last 4 bytes
        !          1608:                 * of the hardware address.
        !          1609:                 */
        !          1610:                if (client->interface->hw_address.hlen > 4) {
        !          1611:                        idx = client->interface->hw_address.hlen - 4;
        !          1612:                        len = 4;
        !          1613:                } else {
        !          1614:                        idx = 0;
        !          1615:                        len = client->interface->hw_address.hlen;
        !          1616:                }
        !          1617:                memcpy(ia.buffer->data,
        !          1618:                       client->interface->hw_address.hbuf + idx,
        !          1619:                       len);
        !          1620:                if (i)
        !          1621:                        ia.buffer->data[3] += i;
        !          1622: 
        !          1623:                t1 = client->config->requested_lease / 2;
        !          1624:                t2 = t1 + (t1 / 2);
        !          1625:                putULong(ia.buffer->data + 4, t1);
        !          1626:                putULong(ia.buffer->data + 8, t2);
        !          1627: 
        !          1628:                log_debug("XMT:  X-- IA_NA %s",
        !          1629:                          print_hex_1(4, ia.buffer->data, 55));
        !          1630:                log_debug("XMT:  | X-- Request renew in  +%u", (unsigned)t1);
        !          1631:                log_debug("XMT:  | X-- Request rebind in +%u", (unsigned)t2);
        !          1632: 
        !          1633:                if ((client->active_lease != NULL) &&
        !          1634:                    ((old_ia = find_ia(client->active_lease->bindings,
        !          1635:                                       D6O_IA_NA,
        !          1636:                                       (char *)ia.buffer->data)) != NULL)) {
        !          1637:                        /*
        !          1638:                         * For each address in the old IA_NA,
        !          1639:                         * request a binding.
        !          1640:                         */
        !          1641:                        memset(&addr, 0, sizeof(addr));
        !          1642:                        for (old_addr = old_ia->addrs ; old_addr != NULL ;
        !          1643:                             old_addr = old_addr->next) {
        !          1644:                                if (old_addr->address.len != 16) {
        !          1645:                                        log_error("Invalid IPv6 address "
        !          1646:                                                  "length %d.  "
        !          1647:                                                  "Ignoring.  (%s:%d)",
        !          1648:                                                  old_addr->address.len,
        !          1649:                                                  MDL);
        !          1650:                                        continue;
        !          1651:                                }
        !          1652: 
        !          1653:                                if (!buffer_allocate(&addr.buffer, 24, MDL)) {
        !          1654:                                        log_error("Unable to allocate memory "
        !          1655:                                                  "for IAADDR.");
        !          1656:                                        data_string_forget(&ia, MDL);
        !          1657:                                        data_string_forget(&ds, MDL);
        !          1658:                                        return;
        !          1659:                                }
        !          1660:                                addr.data = addr.buffer->data;
        !          1661:                                addr.len = 24;
        !          1662: 
        !          1663:                                memcpy(addr.buffer->data,
        !          1664:                                       old_addr->address.iabuf,
        !          1665:                                       16);
        !          1666: 
        !          1667:                                t1 = client->config->requested_lease;
        !          1668:                                t2 = t1 + (t1 / 2);
        !          1669:                                putULong(addr.buffer->data + 16, t1);
        !          1670:                                putULong(addr.buffer->data + 20, t2);
        !          1671: 
        !          1672:                                log_debug("XMT:  | X-- Request address %s.",
        !          1673:                                          piaddr(old_addr->address));
        !          1674:                                log_debug("XMT:  | | X-- Request "
        !          1675:                                          "preferred in +%u",
        !          1676:                                          (unsigned)t1);
        !          1677:                                log_debug("XMT:  | | X-- Request valid "
        !          1678:                                          "in     +%u",
        !          1679:                                          (unsigned)t2);
        !          1680: 
        !          1681:                                append_option(&ia, &dhcpv6_universe,
        !          1682:                                              iaaddr_option,
        !          1683:                                              &addr);
        !          1684: 
        !          1685:                                data_string_forget(&addr, MDL);
        !          1686:                        }
        !          1687:                }
        !          1688: 
        !          1689:                append_option(&ds, &dhcpv6_universe, ia_na_option, &ia);
        !          1690:                data_string_forget(&ia, MDL);
        !          1691:        }
        !          1692: 
        !          1693:        /* Append IA_TA. */
        !          1694:        for (i = 0; i < wanted_ia_ta; i++) {
        !          1695:                /*
        !          1696:                 * XXX: maybe the IA_TA('s) should be put into the sent_options
        !          1697:                 * cache.  They'd have to be pulled down as they also contain
        !          1698:                 * different option caches in the same universe...
        !          1699:                 */
        !          1700:                memset(&ia, 0, sizeof(ia));
        !          1701:                if (!buffer_allocate(&ia.buffer, 4, MDL)) {
        !          1702:                        log_error("Unable to allocate memory for IA_TA.");
        !          1703:                        data_string_forget(&ds, MDL);
        !          1704:                        return;
        !          1705:                }
        !          1706:                ia.data = ia.buffer->data;
        !          1707:                ia.len = 4;
        !          1708: 
        !          1709:                /*
        !          1710:                 * A simple IAID is the last 4 bytes
        !          1711:                 * of the hardware address.
        !          1712:                 */
        !          1713:                if (client->interface->hw_address.hlen > 4) {
        !          1714:                        idx = client->interface->hw_address.hlen - 4;
        !          1715:                        len = 4;
        !          1716:                } else {
        !          1717:                        idx = 0;
        !          1718:                        len = client->interface->hw_address.hlen;
        !          1719:                }
        !          1720:                memcpy(ia.buffer->data,
        !          1721:                       client->interface->hw_address.hbuf + idx,
        !          1722:                       len);
        !          1723:                if (i)
        !          1724:                        ia.buffer->data[3] += i;
        !          1725: 
        !          1726:                log_debug("XMT:  X-- IA_TA %s",
        !          1727:                          print_hex_1(4, ia.buffer->data, 55));
        !          1728: 
        !          1729:                if ((client->active_lease != NULL) &&
        !          1730:                    ((old_ia = find_ia(client->active_lease->bindings,
        !          1731:                                       D6O_IA_TA,
        !          1732:                                       (char *)ia.buffer->data)) != NULL)) {
        !          1733:                        /*
        !          1734:                         * For each address in the old IA_TA,
        !          1735:                         * request a binding.
        !          1736:                         */
        !          1737:                        memset(&addr, 0, sizeof(addr));
        !          1738:                        for (old_addr = old_ia->addrs ; old_addr != NULL ;
        !          1739:                             old_addr = old_addr->next) {
        !          1740:                                if (old_addr->address.len != 16) {
        !          1741:                                        log_error("Invalid IPv6 address "
        !          1742:                                                  "length %d.  "
        !          1743:                                                  "Ignoring.  (%s:%d)",
        !          1744:                                                  old_addr->address.len,
        !          1745:                                                  MDL);
        !          1746:                                        continue;
        !          1747:                                }
        !          1748: 
        !          1749:                                if (!buffer_allocate(&addr.buffer, 24, MDL)) {
        !          1750:                                        log_error("Unable to allocate memory "
        !          1751:                                                  "for IAADDR.");
        !          1752:                                        data_string_forget(&ia, MDL);
        !          1753:                                        data_string_forget(&ds, MDL);
        !          1754:                                        return;
        !          1755:                                }
        !          1756:                                addr.data = addr.buffer->data;
        !          1757:                                addr.len = 24;
        !          1758: 
        !          1759:                                memcpy(addr.buffer->data,
        !          1760:                                       old_addr->address.iabuf,
        !          1761:                                       16);
        !          1762: 
        !          1763:                                t1 = client->config->requested_lease;
        !          1764:                                t2 = t1 + (t1 / 2);
        !          1765:                                putULong(addr.buffer->data + 16, t1);
        !          1766:                                putULong(addr.buffer->data + 20, t2);
        !          1767: 
        !          1768:                                log_debug("XMT:  | X-- Request address %s.",
        !          1769:                                          piaddr(old_addr->address));
        !          1770:                                log_debug("XMT:  | | X-- Request "
        !          1771:                                          "preferred in +%u",
        !          1772:                                          (unsigned)t1);
        !          1773:                                log_debug("XMT:  | | X-- Request valid "
        !          1774:                                          "in     +%u",
        !          1775:                                          (unsigned)t2);
        !          1776: 
        !          1777:                                append_option(&ia, &dhcpv6_universe,
        !          1778:                                              iaaddr_option,
        !          1779:                                              &addr);
        !          1780: 
        !          1781:                                data_string_forget(&addr, MDL);
        !          1782:                        }
        !          1783:                }
        !          1784: 
        !          1785:                append_option(&ds, &dhcpv6_universe, ia_ta_option, &ia);
        !          1786:                data_string_forget(&ia, MDL);
        !          1787:        }
        !          1788: 
        !          1789:        /* Append IA_PD. */
        !          1790:        for (i = 0; i < wanted_ia_pd; i++) {
        !          1791:                /*
        !          1792:                 * XXX: maybe the IA_PD('s) should be put into the sent_options
        !          1793:                 * cache.  They'd have to be pulled down as they also contain
        !          1794:                 * different option caches in the same universe...
        !          1795:                 */
        !          1796:                memset(&ia, 0, sizeof(ia));
        !          1797:                if (!buffer_allocate(&ia.buffer, 12, MDL)) {
        !          1798:                        log_error("Unable to allocate memory for IA_PD.");
        !          1799:                        data_string_forget(&ds, MDL);
        !          1800:                        return;
        !          1801:                }
        !          1802:                ia.data = ia.buffer->data;
        !          1803:                ia.len = 12;
        !          1804: 
        !          1805:                /*
        !          1806:                 * A simple IAID is the last 4 bytes
        !          1807:                 * of the hardware address.
        !          1808:                 */
        !          1809:                if (client->interface->hw_address.hlen > 4) {
        !          1810:                        idx = client->interface->hw_address.hlen - 4;
        !          1811:                        len = 4;
        !          1812:                } else {
        !          1813:                        idx = 0;
        !          1814:                        len = client->interface->hw_address.hlen;
        !          1815:                }
        !          1816:                memcpy(ia.buffer->data,
        !          1817:                       client->interface->hw_address.hbuf + idx,
        !          1818:                       len);
        !          1819:                if (i)
        !          1820:                        ia.buffer->data[3] += i;
        !          1821: 
        !          1822:                t1 = client->config->requested_lease / 2;
        !          1823:                t2 = t1 + (t1 / 2);
        !          1824:                putULong(ia.buffer->data + 4, t1);
        !          1825:                putULong(ia.buffer->data + 8, t2);
        !          1826: 
        !          1827:                log_debug("XMT:  X-- IA_PD %s",
        !          1828:                          print_hex_1(4, ia.buffer->data, 55));
        !          1829:                log_debug("XMT:  | X-- Request renew in  +%u", (unsigned)t1);
        !          1830:                log_debug("XMT:  | X-- Request rebind in +%u", (unsigned)t2);
        !          1831: 
        !          1832:                if ((client->active_lease != NULL) &&
        !          1833:                    ((old_ia = find_ia(client->active_lease->bindings,
        !          1834:                                       D6O_IA_PD,
        !          1835:                                       (char *)ia.buffer->data)) != NULL)) {
        !          1836:                        /*
        !          1837:                         * For each prefix in the old IA_PD,
        !          1838:                         * request a binding.
        !          1839:                         */
        !          1840:                        memset(&addr, 0, sizeof(addr));
        !          1841:                        for (old_addr = old_ia->addrs ; old_addr != NULL ;
        !          1842:                             old_addr = old_addr->next) {
        !          1843:                                if (old_addr->address.len != 16) {
        !          1844:                                        log_error("Invalid IPv6 prefix, "
        !          1845:                                                  "Ignoring.  (%s:%d)",
        !          1846:                                                  MDL);
        !          1847:                                        continue;
        !          1848:                                }
        !          1849: 
        !          1850:                                if (!buffer_allocate(&addr.buffer, 25, MDL)) {
        !          1851:                                        log_error("Unable to allocate memory "
        !          1852:                                                  "for IAPREFIX.");
        !          1853:                                        data_string_forget(&ia, MDL);
        !          1854:                                        data_string_forget(&ds, MDL);
        !          1855:                                        return;
        !          1856:                                }
        !          1857:                                addr.data = addr.buffer->data;
        !          1858:                                addr.len = 25;
        !          1859: 
        !          1860:                                t1 = client->config->requested_lease;
        !          1861:                                t2 = t1 + (t1 / 2);
        !          1862:                                putULong(addr.buffer->data, t1);
        !          1863:                                putULong(addr.buffer->data + 4, t2);
        !          1864: 
        !          1865:                                putUChar(addr.buffer->data + 8,
        !          1866:                                         old_addr->plen);
        !          1867:                                memcpy(addr.buffer->data + 9,
        !          1868:                                       old_addr->address.iabuf,
        !          1869:                                       16);
        !          1870: 
        !          1871:                                log_debug("XMT:  | X-- Request prefix %s/%u.",
        !          1872:                                          piaddr(old_addr->address),
        !          1873:                                          (unsigned) old_addr->plen);
        !          1874:                                log_debug("XMT:  | | X-- Request "
        !          1875:                                          "preferred in +%u",
        !          1876:                                          (unsigned)t1);
        !          1877:                                log_debug("XMT:  | | X-- Request valid "
        !          1878:                                          "in     +%u",
        !          1879:                                          (unsigned)t2);
        !          1880: 
        !          1881:                                append_option(&ia, &dhcpv6_universe,
        !          1882:                                              iaprefix_option,
        !          1883:                                              &addr);
        !          1884: 
        !          1885:                                data_string_forget(&addr, MDL);
        !          1886:                        }
        !          1887:                }
        !          1888: 
        !          1889:                append_option(&ds, &dhcpv6_universe, ia_pd_option, &ia);
        !          1890:                data_string_forget(&ia, MDL);
        !          1891:        }
        !          1892: 
        !          1893:        /* Transmit and wait. */
        !          1894: 
        !          1895:        log_info("XMT: Solicit on %s, interval %ld0ms.",
        !          1896:                 client->name ? client->name : client->interface->name,
        !          1897:                 (long int)client->RT);
        !          1898: 
        !          1899:        send_ret = send_packet6(client->interface,
        !          1900:                                ds.data, ds.len, &DHCPv6DestAddr);
        !          1901:        if (send_ret != ds.len) {
        !          1902:                log_error("dhc6: send_packet6() sent %d of %d bytes",
        !          1903:                          send_ret, ds.len);
        !          1904:        }
        !          1905: 
        !          1906:        data_string_forget(&ds, MDL);
        !          1907: 
        !          1908:        /* Wait RT */
        !          1909:        tv.tv_sec = cur_tv.tv_sec + client->RT / 100;
        !          1910:        tv.tv_usec = cur_tv.tv_usec + (client->RT % 100) * 10000;
        !          1911:        if (tv.tv_usec >= 1000000) {
        !          1912:                tv.tv_sec += 1;
        !          1913:                tv.tv_usec -= 1000000;
        !          1914:        }
        !          1915:        add_timeout(&tv, do_init6, client, NULL, NULL);
        !          1916: 
        !          1917:        dhc6_retrans_advance(client);
        !          1918: }
        !          1919: 
        !          1920: /* do_info_request6() marshals and transmits an information-request. */
        !          1921: void
        !          1922: do_info_request6(void *input)
        !          1923: {
        !          1924:        struct client_state *client;
        !          1925:        struct data_string ds;
        !          1926:        struct timeval tv;
        !          1927:        int send_ret;
        !          1928: 
        !          1929:        client = input;
        !          1930: 
        !          1931:        switch(check_timing6(client, DHCPV6_INFORMATION_REQUEST,
        !          1932:                             "Info-Request", NULL, &ds)) {
        !          1933:              case CHK_TIM_MRC_EXCEEDED:
        !          1934:              case CHK_TIM_ALLOC_FAILURE:
        !          1935:                return;
        !          1936:              case CHK_TIM_MRD_EXCEEDED:
        !          1937:                exit(2);
        !          1938:              case CHK_TIM_SUCCESS:
        !          1939:                break;
        !          1940:        }
        !          1941: 
        !          1942:        /* Fetch any configured 'sent' options (includes DUID) in wire format.
        !          1943:         */
        !          1944:        dhcpv6_universe.encapsulate(&ds, NULL, NULL, client,
        !          1945:                                    NULL, client->sent_options, &global_scope,
        !          1946:                                    &dhcpv6_universe);
        !          1947: 
        !          1948:        /* Transmit and wait. */
        !          1949: 
        !          1950:        log_info("XMT: Info-Request on %s, interval %ld0ms.",
        !          1951:                 client->name ? client->name : client->interface->name,
        !          1952:                 (long int)client->RT);
        !          1953: 
        !          1954:        send_ret = send_packet6(client->interface,
        !          1955:                                ds.data, ds.len, &DHCPv6DestAddr);
        !          1956:        if (send_ret != ds.len) {
        !          1957:                log_error("dhc6: send_packet6() sent %d of %d bytes",
        !          1958:                          send_ret, ds.len);
        !          1959:        }
        !          1960: 
        !          1961:        data_string_forget(&ds, MDL);
        !          1962: 
        !          1963:        /* Wait RT */
        !          1964:        tv.tv_sec = cur_tv.tv_sec + client->RT / 100;
        !          1965:        tv.tv_usec = cur_tv.tv_usec + (client->RT % 100) * 10000;
        !          1966:        if (tv.tv_usec >= 1000000) {
        !          1967:                tv.tv_sec += 1;
        !          1968:                tv.tv_usec -= 1000000;
        !          1969:        }
        !          1970:        add_timeout(&tv, do_info_request6, client, NULL, NULL);
        !          1971: 
        !          1972:        dhc6_retrans_advance(client);
        !          1973: }
        !          1974: 
        !          1975: /* do_confirm6() creates a Confirm packet and transmits it.  This function
        !          1976:  * is called on every timeout to (re)transmit.
        !          1977:  */
        !          1978: void
        !          1979: do_confirm6(void *input)
        !          1980: {
        !          1981:        struct client_state *client;
        !          1982:        struct data_string ds;
        !          1983:        int send_ret;
        !          1984:        struct timeval tv;
        !          1985: 
        !          1986:        client = input;
        !          1987: 
        !          1988:        if (client->active_lease == NULL)
        !          1989:                log_fatal("Impossible condition at %s:%d.", MDL);
        !          1990: 
        !          1991:        /* In section 17.1.3, it is said:
        !          1992:         *
        !          1993:         *   If the client receives no responses before the message
        !          1994:         *   transmission process terminates, as described in section 14,
        !          1995:         *   the client SHOULD continue to use any IP addresses, using the
        !          1996:         *   last known lifetimes for those addresses, and SHOULD continue
        !          1997:         *   to use any other previously obtained configuration parameters.
        !          1998:         *
        !          1999:         * So if confirm times out, we go active.
        !          2000:         *
        !          2001:         * XXX: Should we reduce all IA's t1 to 0, so that we renew and
        !          2002:         * stick there until we get a reply?
        !          2003:         */
        !          2004: 
        !          2005:        switch(check_timing6(client, DHCPV6_CONFIRM, "Confirm",
        !          2006:                             client->active_lease, &ds)) {
        !          2007:              case CHK_TIM_MRC_EXCEEDED:
        !          2008:              case CHK_TIM_MRD_EXCEEDED:
        !          2009:                start_bound(client);
        !          2010:                return;
        !          2011:              case CHK_TIM_ALLOC_FAILURE:
        !          2012:                return;
        !          2013:              case CHK_TIM_SUCCESS:
        !          2014:                break;
        !          2015:        }
        !          2016: 
        !          2017:        /* Fetch any configured 'sent' options (includes DUID') in wire format.
        !          2018:         */
        !          2019:        dhcpv6_universe.encapsulate(&ds, NULL, NULL, client, NULL,
        !          2020:                                    client->sent_options, &global_scope,
        !          2021:                                    &dhcpv6_universe);
        !          2022: 
        !          2023:        /* Append IA's. */
        !          2024:        if (wanted_ia_na &&
        !          2025:            dhc6_add_ia_na(client, &ds, client->active_lease,
        !          2026:                           DHCPV6_CONFIRM) != ISC_R_SUCCESS) {
        !          2027:                data_string_forget(&ds, MDL);
        !          2028:                return;
        !          2029:        }
        !          2030:        if (wanted_ia_ta &&
        !          2031:            dhc6_add_ia_ta(client, &ds, client->active_lease,
        !          2032:                           DHCPV6_CONFIRM) != ISC_R_SUCCESS) {
        !          2033:                data_string_forget(&ds, MDL);
        !          2034:                return;
        !          2035:        }
        !          2036: 
        !          2037:        /* Transmit and wait. */
        !          2038: 
        !          2039:        log_info("XMT: Confirm on %s, interval %ld0ms.",
        !          2040:                 client->name ? client->name : client->interface->name,
        !          2041:                 (long int)client->RT);
        !          2042: 
        !          2043:        send_ret = send_packet6(client->interface, ds.data, ds.len,
        !          2044:                                &DHCPv6DestAddr);
        !          2045:        if (send_ret != ds.len) {
        !          2046:                log_error("dhc6: sendpacket6() sent %d of %d bytes",
        !          2047:                          send_ret, ds.len);
        !          2048:        }
        !          2049: 
        !          2050:        data_string_forget(&ds, MDL);
        !          2051: 
        !          2052:        /* Wait RT */
        !          2053:        tv.tv_sec = cur_tv.tv_sec + client->RT / 100;
        !          2054:        tv.tv_usec = cur_tv.tv_usec + (client->RT % 100) * 10000;
        !          2055:        if (tv.tv_usec >= 1000000) {
        !          2056:                tv.tv_sec += 1;
        !          2057:                tv.tv_usec -= 1000000;
        !          2058:        }
        !          2059:        add_timeout(&tv, do_confirm6, client, NULL, NULL);
        !          2060: 
        !          2061:        dhc6_retrans_advance(client);
        !          2062: }
        !          2063: 
        !          2064: /*
        !          2065:  * Release addresses.
        !          2066:  */
        !          2067: void
        !          2068: start_release6(struct client_state *client)
        !          2069: {
        !          2070:        /* Cancel any pending transmissions */
        !          2071:        cancel_timeout(do_confirm6, client);
        !          2072:        cancel_timeout(do_select6, client);
        !          2073:        cancel_timeout(do_refresh6, client);
        !          2074:        cancel_timeout(do_release6, client);
        !          2075:        client->state = S_STOPPED;
        !          2076: 
        !          2077:        /*
        !          2078:         * It is written:  "The client MUST NOT use any of the addresses it
        !          2079:         * is releasing as the source address in the Release message or in
        !          2080:         * any subsequently transmitted message."  So unconfigure now.
        !          2081:         */
        !          2082:        unconfigure6(client, "RELEASE6");
        !          2083: 
        !          2084:        /* Note this in the lease file. */
        !          2085:        if (client->active_lease == NULL)
        !          2086:                return;
        !          2087:        client->active_lease->released = ISC_TRUE;
        !          2088:        write_client6_lease(client, client->active_lease, 0, 1);
        !          2089: 
        !          2090:        /* Set timers per RFC3315 section 18.1.6. */
        !          2091:        client->IRT = REL_TIMEOUT * 100;
        !          2092:        client->MRT = 0;
        !          2093:        client->MRC = REL_MAX_RC;
        !          2094:        client->MRD = 0;
        !          2095: 
        !          2096:        dhc6_retrans_init(client);
        !          2097:        client->v6_handler = reply_handler;
        !          2098: 
        !          2099:        do_release6(client);
        !          2100: }
        !          2101: /*
        !          2102:  * do_release6() creates a Release packet and transmits it.
        !          2103:  */
        !          2104: static void
        !          2105: do_release6(void *input)
        !          2106: {
        !          2107:        struct client_state *client;
        !          2108:        struct data_string ds;
        !          2109:        int send_ret;
        !          2110:        struct timeval tv;
        !          2111: 
        !          2112:        client = input;
        !          2113: 
        !          2114:        if ((client->active_lease == NULL) || !active_prefix(client))
        !          2115:                return;
        !          2116: 
        !          2117:        switch(check_timing6(client, DHCPV6_RELEASE, "Release", 
        !          2118:                             client->active_lease, &ds)) {
        !          2119:              case CHK_TIM_MRC_EXCEEDED:
        !          2120:              case CHK_TIM_ALLOC_FAILURE:
        !          2121:              case CHK_TIM_MRD_EXCEEDED:
        !          2122:                goto release_done;
        !          2123:              case CHK_TIM_SUCCESS:
        !          2124:                break;
        !          2125:        }
        !          2126: 
        !          2127:        /*
        !          2128:         * Don't use unicast as we don't know if we still have an
        !          2129:         * available address with enough scope.
        !          2130:         */
        !          2131: 
        !          2132:        dhcpv6_universe.encapsulate(&ds, NULL, NULL, client, NULL,
        !          2133:                                    client->sent_options, &global_scope,
        !          2134:                                    &dhcpv6_universe);
        !          2135: 
        !          2136:        /* Append IA's (but don't release temporary addresses). */
        !          2137:        if (wanted_ia_na &&
        !          2138:            dhc6_add_ia_na(client, &ds, client->active_lease,
        !          2139:                           DHCPV6_RELEASE) != ISC_R_SUCCESS) {
        !          2140:                data_string_forget(&ds, MDL);
        !          2141:                goto release_done;
        !          2142:        }
        !          2143:        if (wanted_ia_pd &&
        !          2144:            dhc6_add_ia_pd(client, &ds, client->active_lease,
        !          2145:                           DHCPV6_RELEASE) != ISC_R_SUCCESS) {
        !          2146:                data_string_forget(&ds, MDL);
        !          2147:                goto release_done;
        !          2148:        }
        !          2149: 
        !          2150:        /* Transmit and wait. */
        !          2151:        log_info("XMT: Release on %s, interval %ld0ms.",
        !          2152:                 client->name ? client->name : client->interface->name,
        !          2153:                 (long int)client->RT);
        !          2154: 
        !          2155:        send_ret = send_packet6(client->interface, ds.data, ds.len,
        !          2156:                                &DHCPv6DestAddr);
        !          2157:        if (send_ret != ds.len) {
        !          2158:                log_error("dhc6: sendpacket6() sent %d of %d bytes",
        !          2159:                          send_ret, ds.len);
        !          2160:        }
        !          2161: 
        !          2162:        data_string_forget(&ds, MDL);
        !          2163: 
        !          2164:        /* Wait RT */
        !          2165:        tv.tv_sec = cur_tv.tv_sec + client->RT / 100;
        !          2166:        tv.tv_usec = cur_tv.tv_usec + (client->RT % 100) * 10000;
        !          2167:        if (tv.tv_usec >= 1000000) {
        !          2168:                tv.tv_sec += 1;
        !          2169:                tv.tv_usec -= 1000000;
        !          2170:        }
        !          2171:        add_timeout(&tv, do_release6, client, NULL, NULL);
        !          2172:        dhc6_retrans_advance(client);
        !          2173:        return;
        !          2174: 
        !          2175:       release_done:
        !          2176:        dhc6_lease_destroy(&client->active_lease, MDL);
        !          2177:        client->active_lease = NULL;
        !          2178:        if (stopping_finished())
        !          2179:                exit(0);
        !          2180: }
        !          2181: 
        !          2182: /* status_log() just puts a status code into displayable form and logs it
        !          2183:  * to info level.
        !          2184:  */
        !          2185: static void
        !          2186: status_log(int code, const char *scope, const char *additional, int len)
        !          2187: {
        !          2188:        const char *msg = NULL;
        !          2189: 
        !          2190:        switch(code) {
        !          2191:              case STATUS_Success:
        !          2192:                msg = "Success";
        !          2193:                break;
        !          2194: 
        !          2195:              case STATUS_UnspecFail:
        !          2196:                msg = "UnspecFail";
        !          2197:                break;
        !          2198: 
        !          2199:              case STATUS_NoAddrsAvail:
        !          2200:                msg = "NoAddrsAvail";
        !          2201:                break;
        !          2202: 
        !          2203:              case STATUS_NoBinding:
        !          2204:                msg = "NoBinding";
        !          2205:                break;
        !          2206: 
        !          2207:              case STATUS_NotOnLink:
        !          2208:                msg = "NotOnLink";
        !          2209:                break;
        !          2210: 
        !          2211:              case STATUS_UseMulticast:
        !          2212:                msg = "UseMulticast";
        !          2213:                break;
        !          2214: 
        !          2215:              case STATUS_NoPrefixAvail:
        !          2216:                msg = "NoPrefixAvail";
        !          2217:                break;
        !          2218: 
        !          2219:              default:
        !          2220:                msg = "UNKNOWN";
        !          2221:                break;
        !          2222:        }
        !          2223: 
        !          2224:        if (len > 0)
        !          2225:                log_info("%s status code %s: %s", scope, msg,
        !          2226:                         print_hex_1(len,
        !          2227:                                     (const unsigned char *)additional, 50));
        !          2228:        else
        !          2229:                log_info("%s status code %s.", scope, msg);
        !          2230: }
        !          2231: 
        !          2232: /* Acquire a status code.
        !          2233:  */
        !          2234: static isc_result_t
        !          2235: dhc6_get_status_code(struct option_state *options, unsigned *code,
        !          2236:                     struct data_string *msg)
        !          2237: {
        !          2238:        struct option_cache *oc;
        !          2239:        struct data_string ds;
        !          2240:        isc_result_t rval = ISC_R_SUCCESS;
        !          2241: 
        !          2242:        if ((options == NULL) || (code == NULL))
        !          2243:                return ISC_R_INVALIDARG;
        !          2244: 
        !          2245:        if ((msg != NULL) && (msg->len != 0))
        !          2246:                return ISC_R_INVALIDARG;
        !          2247: 
        !          2248:        memset(&ds, 0, sizeof(ds));
        !          2249: 
        !          2250:        /* Assume success if there is no option. */
        !          2251:        *code = STATUS_Success;
        !          2252: 
        !          2253:        oc = lookup_option(&dhcpv6_universe, options, D6O_STATUS_CODE);
        !          2254:        if ((oc != NULL) &&
        !          2255:            evaluate_option_cache(&ds, NULL, NULL, NULL, options,
        !          2256:                                  NULL, &global_scope, oc, MDL)) {
        !          2257:                if (ds.len < 2) {
        !          2258:                        log_error("Invalid status code length %d.", ds.len);
        !          2259:                        rval = ISC_R_FORMERR;
        !          2260:                } else
        !          2261:                        *code = getUShort(ds.data);
        !          2262: 
        !          2263:                if ((msg != NULL) && (ds.len > 2)) {
        !          2264:                        data_string_copy(msg, &ds, MDL);
        !          2265:                        msg->data += 2;
        !          2266:                        msg->len -= 2;
        !          2267:                }
        !          2268: 
        !          2269:                data_string_forget(&ds, MDL);
        !          2270:                return rval;
        !          2271:        }
        !          2272: 
        !          2273:        return ISC_R_NOTFOUND;
        !          2274: }
        !          2275: 
        !          2276: /* Look at status codes in an advertise, and reform the return value.
        !          2277:  */
        !          2278: static isc_result_t
        !          2279: dhc6_check_status(isc_result_t rval, struct option_state *options,
        !          2280:                  const char *scope, unsigned *code)
        !          2281: {
        !          2282:        struct data_string msg;
        !          2283:        isc_result_t status;
        !          2284: 
        !          2285:        if ((scope == NULL) || (code == NULL))
        !          2286:                return ISC_R_INVALIDARG;
        !          2287: 
        !          2288:        /* If we don't find a code, we assume success. */
        !          2289:        *code = STATUS_Success;
        !          2290: 
        !          2291:        /* If there is no options cache, then there is no code. */
        !          2292:        if (options != NULL) {
        !          2293:                memset(&msg, 0, sizeof(msg));
        !          2294:                status = dhc6_get_status_code(options, code, &msg);
        !          2295: 
        !          2296:                if (status == ISC_R_SUCCESS) {
        !          2297:                        status_log(*code, scope, (char *)msg.data, msg.len);
        !          2298:                        data_string_forget(&msg, MDL);
        !          2299: 
        !          2300:                        if (*code != STATUS_Success)
        !          2301:                                rval = ISC_R_FAILURE;
        !          2302: 
        !          2303:                } else if (status != ISC_R_NOTFOUND)
        !          2304:                        rval = status;
        !          2305:        }
        !          2306: 
        !          2307:        return rval;
        !          2308: }
        !          2309: 
        !          2310: /* Look in the packet, any IA's, and any IAADDR's within those IA's to find
        !          2311:  * status code options that are not SUCCESS.
        !          2312:  */
        !          2313: static isc_result_t
        !          2314: dhc6_check_advertise(struct dhc6_lease *lease)
        !          2315: {
        !          2316:        struct dhc6_ia *ia;
        !          2317:        struct dhc6_addr *addr;
        !          2318:        isc_result_t rval = ISC_R_SUCCESS;
        !          2319:        int have_addrs = ISC_FALSE;
        !          2320:        unsigned code;
        !          2321:        const char *scope;
        !          2322: 
        !          2323:        rval = dhc6_check_status(rval, lease->options, "message", &code);
        !          2324: 
        !          2325:        for (ia = lease->bindings ; ia != NULL ; ia = ia->next) {
        !          2326:                switch (ia->ia_type) {
        !          2327:                        case D6O_IA_NA:
        !          2328:                                scope = "IA_NA";
        !          2329:                                break;
        !          2330:                        case D6O_IA_TA:
        !          2331:                                scope = "IA_TA";
        !          2332:                                break;
        !          2333:                        case D6O_IA_PD:
        !          2334:                                scope = "IA_PD";
        !          2335:                                break;
        !          2336:                        default:
        !          2337:                                log_error("dhc6_check_advertise: no type.");
        !          2338:                                return ISC_R_FAILURE;
        !          2339:                }
        !          2340:                rval = dhc6_check_status(rval, ia->options, scope, &code);
        !          2341: 
        !          2342:                for (addr = ia->addrs ; addr != NULL ; addr = addr->next) {
        !          2343:                        if (ia->ia_type != D6O_IA_PD)
        !          2344:                                scope = "IAADDR";
        !          2345:                        else
        !          2346:                                scope = "IAPREFIX";
        !          2347:                        rval = dhc6_check_status(rval, addr->options,
        !          2348:                                                 scope, &code);
        !          2349:                        have_addrs = ISC_TRUE;
        !          2350:                }
        !          2351:        }
        !          2352: 
        !          2353:        if (have_addrs != ISC_TRUE)
        !          2354:                rval = ISC_R_ADDRNOTAVAIL;
        !          2355: 
        !          2356:        return rval;
        !          2357: }
        !          2358: 
        !          2359: /* status code <-> action matrix for the client in INIT state
        !          2360:  * (rapid/commit).  Returns always false as no action is defined.
        !          2361:  */
        !          2362: static isc_boolean_t
        !          2363: dhc6_init_action(struct client_state *client, isc_result_t *rvalp,
        !          2364:                 unsigned code)
        !          2365: {
        !          2366:        if (rvalp == NULL)
        !          2367:                log_fatal("Impossible condition at %s:%d.", MDL);
        !          2368: 
        !          2369:        if (client == NULL) {
        !          2370:                *rvalp = ISC_R_INVALIDARG;
        !          2371:                return ISC_FALSE;
        !          2372:        }
        !          2373: 
        !          2374:        if (*rvalp == ISC_R_SUCCESS)
        !          2375:                return ISC_FALSE;
        !          2376: 
        !          2377:        /* No possible action in any case... */
        !          2378:        return ISC_FALSE;
        !          2379: }
        !          2380: 
        !          2381: /* status code <-> action matrix for the client in SELECT state
        !          2382:  * (request/reply).  Returns true if action was taken (and the
        !          2383:  * packet should be ignored), or false if no action was taken.
        !          2384:  */
        !          2385: static isc_boolean_t
        !          2386: dhc6_select_action(struct client_state *client, isc_result_t *rvalp,
        !          2387:                   unsigned code)
        !          2388: {
        !          2389:        struct dhc6_lease *lease;
        !          2390:        isc_result_t rval;
        !          2391: 
        !          2392:        if (rvalp == NULL)
        !          2393:                log_fatal("Impossible condition at %s:%d.", MDL);
        !          2394: 
        !          2395:        if (client == NULL) {
        !          2396:                *rvalp = ISC_R_INVALIDARG;
        !          2397:                return ISC_FALSE;
        !          2398:        }
        !          2399:        rval = *rvalp;
        !          2400: 
        !          2401:        if (rval == ISC_R_SUCCESS)
        !          2402:                return ISC_FALSE;
        !          2403: 
        !          2404:        switch (code) {
        !          2405:                /* We may have an earlier failure status code (so no
        !          2406:                 * success rval), and a success code now.  This
        !          2407:                 * doesn't upgrade the rval to success, but it does
        !          2408:                 * mean we take no action here.
        !          2409:                 */
        !          2410:              case STATUS_Success:
        !          2411:                /* Gimpy server, or possibly an attacker. */
        !          2412:              case STATUS_NoBinding:
        !          2413:              case STATUS_UseMulticast:
        !          2414:                /* Take no action. */
        !          2415:                return ISC_FALSE;
        !          2416: 
        !          2417:                /* If the server can't deal with us, either try the
        !          2418:                 * next advertised server, or continue retrying if there
        !          2419:                 * weren't any.
        !          2420:                 */
        !          2421:              default:
        !          2422:              case STATUS_UnspecFail:
        !          2423:                if (client->advertised_leases != NULL) {
        !          2424:                        dhc6_lease_destroy(&client->selected_lease, MDL);
        !          2425:                        client->selected_lease = NULL;
        !          2426: 
        !          2427:                        start_selecting6(client);
        !          2428: 
        !          2429:                        break;
        !          2430:                } else /* Take no action - continue to retry. */
        !          2431:                        return ISC_FALSE;
        !          2432: 
        !          2433:                /* If the server has no addresses, try other servers if
        !          2434:                 * we got some, otherwise go to INIT to hope for more
        !          2435:                 * servers.
        !          2436:                 */
        !          2437:              case STATUS_NoAddrsAvail:
        !          2438:              case STATUS_NoPrefixAvail:
        !          2439:                if (client->state == S_REBOOTING)
        !          2440:                        return ISC_FALSE;
        !          2441: 
        !          2442:                if (client->selected_lease == NULL)
        !          2443:                        log_fatal("Impossible case at %s:%d.", MDL);
        !          2444: 
        !          2445:                dhc6_lease_destroy(&client->selected_lease, MDL);
        !          2446:                client->selected_lease = NULL;
        !          2447: 
        !          2448:                if (client->advertised_leases != NULL)
        !          2449:                        start_selecting6(client);
        !          2450:                else
        !          2451:                        start_init6(client);
        !          2452: 
        !          2453:                break;
        !          2454: 
        !          2455:                /* If we got a NotOnLink from a Confirm, then we're not
        !          2456:                 * on link.  Kill the old-active binding and start over.
        !          2457:                 *
        !          2458:                 * If we got a NotOnLink from our Request, something weird
        !          2459:                 * happened.  Start over from scratch anyway.
        !          2460:                 */
        !          2461:              case STATUS_NotOnLink:
        !          2462:                if (client->state == S_REBOOTING) {
        !          2463:                        if (client->active_lease == NULL)
        !          2464:                                log_fatal("Impossible case at %s:%d.", MDL);
        !          2465: 
        !          2466:                        dhc6_lease_destroy(&client->active_lease, MDL);
        !          2467:                } else {
        !          2468:                        if (client->selected_lease == NULL)
        !          2469:                                log_fatal("Impossible case at %s:%d.", MDL);
        !          2470: 
        !          2471:                        dhc6_lease_destroy(&client->selected_lease, MDL);
        !          2472:                        client->selected_lease = NULL;
        !          2473: 
        !          2474:                        while (client->advertised_leases != NULL) {
        !          2475:                                lease = client->advertised_leases;
        !          2476:                                client->advertised_leases = lease->next;
        !          2477: 
        !          2478:                                dhc6_lease_destroy(&lease, MDL);
        !          2479:                        }
        !          2480:                }
        !          2481: 
        !          2482:                start_init6(client);
        !          2483:                break;
        !          2484:        }
        !          2485: 
        !          2486:        return ISC_TRUE;
        !          2487: }
        !          2488: 
        !          2489: static void
        !          2490: dhc6_withdraw_lease(struct client_state *client)
        !          2491: {
        !          2492:        struct dhc6_ia *ia;
        !          2493:        struct dhc6_addr *addr;
        !          2494: 
        !          2495:        if ((client == NULL) || (client->active_lease == NULL))
        !          2496:                return;
        !          2497: 
        !          2498:        for (ia = client->active_lease->bindings ; ia != NULL ;
        !          2499:             ia = ia->next) {
        !          2500:                for (addr = ia->addrs ; addr != NULL ; addr = addr->next) {
        !          2501:                        addr->max_life = addr->preferred_life = 0;
        !          2502:                }
        !          2503:        }
        !          2504: 
        !          2505:        /* Perform expiry. */
        !          2506:        do_expire(client);
        !          2507: }
        !          2508: 
        !          2509: /* status code <-> action matrix for the client in BOUND state
        !          2510:  * (request/reply).  Returns true if action was taken (and the
        !          2511:  * packet should be ignored), or false if no action was taken.
        !          2512:  */
        !          2513: static isc_boolean_t
        !          2514: dhc6_reply_action(struct client_state *client, isc_result_t *rvalp,
        !          2515:                  unsigned code)
        !          2516: {
        !          2517:        isc_result_t rval;
        !          2518: 
        !          2519:        if (rvalp == NULL)
        !          2520:                log_fatal("Impossible condition at %s:%d.", MDL);
        !          2521: 
        !          2522:        if (client == NULL) {
        !          2523:                *rvalp = ISC_R_INVALIDARG;
        !          2524:                return ISC_FALSE;
        !          2525:        }
        !          2526:        rval = *rvalp;
        !          2527: 
        !          2528:        if (rval == ISC_R_SUCCESS)
        !          2529:                return ISC_FALSE;
        !          2530: 
        !          2531:        switch (code) {
        !          2532:                /* It's possible an earlier status code set rval to a failure
        !          2533:                 * code, and we've encountered a later success.
        !          2534:                 */
        !          2535:              case STATUS_Success:
        !          2536:                /* In "refreshes" (where we get replies), we probably
        !          2537:                 * still have a valid lease.  So "take no action" and
        !          2538:                 * the upper levels will keep retrying until the lease
        !          2539:                 * expires (or we rebind).
        !          2540:                 */
        !          2541:              case STATUS_UnspecFail:
        !          2542:                /* For unknown codes...it's a soft (retryable) error. */
        !          2543:              default:
        !          2544:                return ISC_FALSE;
        !          2545: 
        !          2546:                /* The server is telling us to use a multicast address, so
        !          2547:                 * we have to delete the unicast option from the active
        !          2548:                 * lease, then allow retransmission to occur normally.
        !          2549:                 * (XXX: It might be preferable in this case to retransmit
        !          2550:                 * sooner than the current interval, but for now we don't.)
        !          2551:                 */
        !          2552:              case STATUS_UseMulticast:
        !          2553:                if (client->active_lease != NULL)
        !          2554:                        delete_option(&dhcp_universe,
        !          2555:                                      client->active_lease->options,
        !          2556:                                      D6O_UNICAST);
        !          2557:                return ISC_FALSE;
        !          2558: 
        !          2559:                /* "When the client receives a NotOnLink status from the
        !          2560:                 *  server in response to a Request, the client can either
        !          2561:                 *  re-issue the Request without specifying any addresses
        !          2562:                 *  or restart the DHCP server discovery process."
        !          2563:                 *
        !          2564:                 * This is strange.  If competing server evaluation is
        !          2565:                 * useful (and therefore in the protocol), then why would
        !          2566:                 * a client's first reaction be to request from the same
        !          2567:                 * server on a different link?  Surely you'd want to
        !          2568:                 * re-evaluate your server selection.
        !          2569:                 *
        !          2570:                 * Well, I guess that's the answer.
        !          2571:                 */
        !          2572:              case STATUS_NotOnLink:
        !          2573:                /* In this case, we need to rescind all current active
        !          2574:                 * bindings (just 'expire' them all normally, if early).
        !          2575:                 * They're no use to us on the wrong link.  Then head back
        !          2576:                 * to init, redo server selection and get new addresses.
        !          2577:                 */
        !          2578:                dhc6_withdraw_lease(client);
        !          2579:                break;
        !          2580: 
        !          2581:                /* "If the status code is NoAddrsAvail, the client has
        !          2582:                 *  received no usable addresses in the IA and may choose
        !          2583:                 *  to try obtaining addresses for the IA from another
        !          2584:                 *  server."
        !          2585:                 */
        !          2586:              case STATUS_NoAddrsAvail:
        !          2587:              case STATUS_NoPrefixAvail:
        !          2588:                /* Head back to init, keeping any active bindings (!). */
        !          2589:                start_init6(client);
        !          2590:                break;
        !          2591: 
        !          2592:                /* -  sends a Request message if the IA contained a Status
        !          2593:                 *    Code option with the NoBinding status (and does not
        !          2594:                 *    send any additional Renew/Rebind messages)
        !          2595:                 */
        !          2596:              case STATUS_NoBinding:
        !          2597:                if (client->advertised_leases != NULL)
        !          2598:                        log_fatal("Impossible condition at %s:%d.", MDL);
        !          2599: 
        !          2600:                client->advertised_leases =
        !          2601:                                dhc6_dup_lease(client->active_lease, MDL);
        !          2602:                start_selecting6(client);
        !          2603:                break;
        !          2604:        }
        !          2605: 
        !          2606:        return ISC_TRUE;
        !          2607: }
        !          2608: 
        !          2609: /* status code <-> action matrix for the client in STOPPED state
        !          2610:  * (release/decline).  Returns true if action was taken (and the
        !          2611:  * packet should be ignored), or false if no action was taken.
        !          2612:  * NoBinding is translated into Success.
        !          2613:  */
        !          2614: static isc_boolean_t
        !          2615: dhc6_stop_action(struct client_state *client, isc_result_t *rvalp,
        !          2616:                  unsigned code)
        !          2617: {
        !          2618:        isc_result_t rval;
        !          2619: 
        !          2620:        if (rvalp == NULL)
        !          2621:                log_fatal("Impossible condition at %s:%d.", MDL);
        !          2622: 
        !          2623:        if (client == NULL) {
        !          2624:                *rvalp = ISC_R_INVALIDARG;
        !          2625:                return ISC_FALSE;
        !          2626:        }
        !          2627:        rval = *rvalp;
        !          2628: 
        !          2629:        if (rval == ISC_R_SUCCESS)
        !          2630:                return ISC_FALSE;
        !          2631: 
        !          2632:        switch (code) {
        !          2633:                /* It's possible an earlier status code set rval to a failure
        !          2634:                 * code, and we've encountered a later success.
        !          2635:                 */
        !          2636:              case STATUS_Success:
        !          2637:                /* For unknown codes...it's a soft (retryable) error. */
        !          2638:              case STATUS_UnspecFail:
        !          2639:              default:
        !          2640:                return ISC_FALSE;
        !          2641: 
        !          2642:                /* NoBinding is not an error */
        !          2643:              case STATUS_NoBinding:
        !          2644:                if (rval == ISC_R_FAILURE)
        !          2645:                        *rvalp = ISC_R_SUCCESS;
        !          2646:                return ISC_FALSE;
        !          2647: 
        !          2648:                /* Should not happen */
        !          2649:              case STATUS_NoAddrsAvail:
        !          2650:              case STATUS_NoPrefixAvail:
        !          2651:                break;
        !          2652: 
        !          2653:                /* Give up on it */
        !          2654:              case STATUS_NotOnLink:
        !          2655:                break;
        !          2656: 
        !          2657:                /* The server is telling us to use a multicast address, so
        !          2658:                 * we have to delete the unicast option from the active
        !          2659:                 * lease, then allow retransmission to occur normally.
        !          2660:                 * (XXX: It might be preferable in this case to retransmit
        !          2661:                 * sooner than the current interval, but for now we don't.)
        !          2662:                 */
        !          2663:              case STATUS_UseMulticast:
        !          2664:                if (client->active_lease != NULL)
        !          2665:                        delete_option(&dhcp_universe,
        !          2666:                                      client->active_lease->options,
        !          2667:                                      D6O_UNICAST);
        !          2668:                return ISC_FALSE;
        !          2669:        }
        !          2670: 
        !          2671:        return ISC_TRUE;
        !          2672: }
        !          2673: 
        !          2674: /* Look at a new and old lease, and make sure the new information is not
        !          2675:  * losing us any state.
        !          2676:  */
        !          2677: static isc_result_t
        !          2678: dhc6_check_reply(struct client_state *client, struct dhc6_lease *new)
        !          2679: {
        !          2680:        isc_boolean_t (*action)(struct client_state *,
        !          2681:                                isc_result_t *, unsigned);
        !          2682:        struct dhc6_ia *ia;
        !          2683:        struct dhc6_addr *addr;
        !          2684:        isc_result_t rval = ISC_R_SUCCESS;
        !          2685:        unsigned code;
        !          2686:        const char *scope;
        !          2687:        int nscore, sscore;
        !          2688: 
        !          2689:        if ((client == NULL) || (new == NULL))
        !          2690:                return ISC_R_INVALIDARG;
        !          2691: 
        !          2692:        switch (client->state) {
        !          2693:              case S_INIT:
        !          2694:                action = dhc6_init_action;
        !          2695:                break;
        !          2696: 
        !          2697:              case S_SELECTING:
        !          2698:              case S_REBOOTING:
        !          2699:                action = dhc6_select_action;
        !          2700:                break;
        !          2701: 
        !          2702:              case S_RENEWING:
        !          2703:              case S_REBINDING:
        !          2704:                action = dhc6_reply_action;
        !          2705:                break;
        !          2706: 
        !          2707:              case S_STOPPED:
        !          2708:                action = dhc6_stop_action;
        !          2709:                break;
        !          2710: 
        !          2711:              default:
        !          2712:                log_fatal("Impossible condition at %s:%d.", MDL);
        !          2713:                return ISC_R_CANCELED;
        !          2714:        }
        !          2715: 
        !          2716:        /* If there is a code to extract, and if there is some
        !          2717:         * action to take based on that code, then take the action
        !          2718:         * and do not continue.
        !          2719:         */
        !          2720:        rval = dhc6_check_status(rval, new->options, "message", &code);
        !          2721:        if (action(client, &rval, code))
        !          2722:                return ISC_R_CANCELED;
        !          2723: 
        !          2724:        for (ia = new->bindings ; ia != NULL ; ia = ia->next) {
        !          2725:                switch (ia->ia_type) {
        !          2726:                        case D6O_IA_NA:
        !          2727:                                scope = "IA_NA";
        !          2728:                                break;
        !          2729:                        case D6O_IA_TA:
        !          2730:                                scope = "IA_TA";
        !          2731:                                break;
        !          2732:                        case D6O_IA_PD:
        !          2733:                                scope = "IA_PD";
        !          2734:                                break;
        !          2735:                        default:
        !          2736:                                log_error("dhc6_check_reply: no type.");
        !          2737:                                return ISC_R_INVALIDARG;
        !          2738:                }
        !          2739:                rval = dhc6_check_status(rval, ia->options,
        !          2740:                                         scope, &code);
        !          2741:                if (action(client, &rval, code))
        !          2742:                        return ISC_R_CANCELED;
        !          2743: 
        !          2744:                for (addr = ia->addrs ; addr != NULL ;
        !          2745:                     addr = addr->next) {
        !          2746:                        if (ia->ia_type != D6O_IA_PD)
        !          2747:                                scope = "IAADDR";
        !          2748:                        else
        !          2749:                                scope = "IAPREFIX";
        !          2750:                        rval = dhc6_check_status(rval, addr->options,
        !          2751:                                                 scope, &code);
        !          2752:                        if (action(client, &rval, code))
        !          2753:                                return ISC_R_CANCELED;
        !          2754:                }
        !          2755:        }
        !          2756: 
        !          2757:        /* A Confirm->Reply is unsuitable for comparison to the old lease. */
        !          2758:        if (client->state == S_REBOOTING)
        !          2759:                return rval;
        !          2760: 
        !          2761:        /* No old lease in rapid-commit. */
        !          2762:        if (client->state == S_INIT)
        !          2763:                return rval;
        !          2764: 
        !          2765:        switch (client->state) {
        !          2766:              case S_SELECTING:
        !          2767:                /* Compare the new lease with the selected lease to make
        !          2768:                 * sure there is no risky business.
        !          2769:                 */
        !          2770:                nscore = dhc6_score_lease(client, new);
        !          2771:                sscore = dhc6_score_lease(client, client->selected_lease);
        !          2772:                if ((client->advertised_leases != NULL) &&
        !          2773:                    (nscore < (sscore / 2))) {
        !          2774:                        /* XXX: An attacker might reply this way to make
        !          2775:                         * XXX: sure we latch onto their configuration.
        !          2776:                         * XXX: We might want to ignore the packet and
        !          2777:                         * XXX: schedule re-selection at the next timeout?
        !          2778:                         */
        !          2779:                        log_error("PRC: BAIT AND SWITCH detected.  Score of "
        !          2780:                                  "supplied lease (%d) is substantially "
        !          2781:                                  "smaller than the advertised score (%d).  "
        !          2782:                                  "Trying other servers.",
        !          2783:                                  nscore, sscore);
        !          2784: 
        !          2785:                        dhc6_lease_destroy(&client->selected_lease, MDL);
        !          2786:                        client->selected_lease = NULL;
        !          2787: 
        !          2788:                        start_selecting6(client);
        !          2789: 
        !          2790:                        return ISC_R_CANCELED;
        !          2791:                }
        !          2792:                break;
        !          2793: 
        !          2794:              case S_RENEWING:
        !          2795:              case S_REBINDING:
        !          2796:                /* This leaves one RFC3315 status check unimplemented:
        !          2797:                 *
        !          2798:                 * -  sends a Renew/Rebind if the IA is not in the Reply
        !          2799:                 *    message
        !          2800:                 *
        !          2801:                 * We rely on the scheduling system to note that the IA has
        !          2802:                 * not left Renewal/Rebinding/whatever since it still carries
        !          2803:                 * old times from the last successful binding.  So this is
        !          2804:                 * implemented actually, just not explicitly.
        !          2805:                 */
        !          2806:                break;
        !          2807: 
        !          2808:              case S_STOPPED:
        !          2809:                /* Nothing critical to do at this stage. */
        !          2810:                break;
        !          2811: 
        !          2812:              default:
        !          2813:                log_fatal("REALLY impossible condition at %s:%d.", MDL);
        !          2814:                return ISC_R_CANCELED;
        !          2815:        }
        !          2816: 
        !          2817:        return rval;
        !          2818: }
        !          2819: 
        !          2820: /* While in init state, we only collect advertisements.  If there happens
        !          2821:  * to be an advertisement with a preference option of 255, that's an
        !          2822:  * automatic exit.  Otherwise, we collect advertisements until our timeout
        !          2823:  * expires (client->RT).
        !          2824:  */
        !          2825: void
        !          2826: init_handler(struct packet *packet, struct client_state *client)
        !          2827: {
        !          2828:        struct dhc6_lease *lease;
        !          2829: 
        !          2830:        /* In INIT state, we send solicits, we only expect to get
        !          2831:         * advertises (rapid commit has its own handler).
        !          2832:         */
        !          2833:        if (packet->dhcpv6_msg_type != DHCPV6_ADVERTISE)
        !          2834:                return;
        !          2835: 
        !          2836:        /* RFC3315 section 15.3 validation (same as 15.10 since we
        !          2837:         * always include a client id).
        !          2838:         */
        !          2839:        if (!valid_reply(packet, client)) {
        !          2840:                log_error("Invalid Advertise - rejecting.");
        !          2841:                return;
        !          2842:        }
        !          2843: 
        !          2844:        lease = dhc6_leaseify(packet);
        !          2845: 
        !          2846:        if (dhc6_check_advertise(lease) != ISC_R_SUCCESS) {
        !          2847:                log_debug("PRC: Lease failed to satisfy.");
        !          2848:                dhc6_lease_destroy(&lease, MDL);
        !          2849:                return;
        !          2850:        }
        !          2851: 
        !          2852:        insert_lease(&client->advertised_leases, lease);
        !          2853: 
        !          2854:        /* According to RFC3315 section 17.1.2, the client MUST wait for
        !          2855:         * the first RT before selecting a lease.  But on the 400th RT,
        !          2856:         * we dont' want to wait the full timeout if we finally get an
        !          2857:         * advertise.  We could probably wait a second, but ohwell,
        !          2858:         * RFC3315 doesn't say so.
        !          2859:         *
        !          2860:         * If the lease is highest possible preference, 255, RFC3315 claims
        !          2861:         * we should continue immediately even on the first RT.  We probably
        !          2862:         * should not if the advertise contains less than one IA and address.
        !          2863:         */
        !          2864:        if ((client->txcount > 1) ||
        !          2865:            ((lease->pref == 255) &&
        !          2866:            (dhc6_score_lease(client, lease) > 150))) {
        !          2867:                log_debug("RCV:  Advertisement immediately selected.");
        !          2868:                cancel_timeout(do_init6, client);
        !          2869:                start_selecting6(client);
        !          2870:        } else
        !          2871:                log_debug("RCV:  Advertisement recorded.");
        !          2872: }
        !          2873: 
        !          2874: /* info_request_handler() accepts a Reply to an Info-request.
        !          2875:  */
        !          2876: void
        !          2877: info_request_handler(struct packet *packet, struct client_state *client)
        !          2878: {
        !          2879:        isc_result_t check_status;
        !          2880:        unsigned code;
        !          2881: 
        !          2882:        if (packet->dhcpv6_msg_type != DHCPV6_REPLY)
        !          2883:                return;
        !          2884: 
        !          2885:        /* RFC3315 section 15.10 validation (same as 15.3 since we
        !          2886:         * always include a client id).
        !          2887:         */
        !          2888:        if (!valid_reply(packet, client)) {
        !          2889:                log_error("Invalid Reply - rejecting.");
        !          2890:                return;
        !          2891:        }
        !          2892: 
        !          2893:        check_status = dhc6_check_status(ISC_R_SUCCESS, packet->options,
        !          2894:                                         "message", &code);
        !          2895:        if (check_status != ISC_R_SUCCESS) {
        !          2896:                /* If no action was taken, but there is an error, then
        !          2897:                 * we wait for a retransmission.
        !          2898:                 */
        !          2899:                if (check_status != ISC_R_CANCELED)
        !          2900:                        return;
        !          2901:        }
        !          2902: 
        !          2903:        /* We're done retransmitting at this point. */
        !          2904:        cancel_timeout(do_info_request6, client);
        !          2905: 
        !          2906:        /* Action was taken, so now that we've torn down our scheduled
        !          2907:         * retransmissions, return.
        !          2908:         */
        !          2909:        if (check_status == ISC_R_CANCELED)
        !          2910:                return;
        !          2911: 
        !          2912:        /* Cleanup if a previous attempt to go bound failed. */
        !          2913:        if (client->old_lease != NULL) {
        !          2914:                dhc6_lease_destroy(&client->old_lease, MDL);
        !          2915:                client->old_lease = NULL;
        !          2916:        }
        !          2917: 
        !          2918:        /* Cache options in the active_lease. */
        !          2919:        if (client->active_lease != NULL)
        !          2920:                client->old_lease = client->active_lease;
        !          2921:        client->active_lease = dmalloc(sizeof(struct dhc6_lease), MDL);
        !          2922:        if (client->active_lease == NULL)
        !          2923:                log_fatal("Out of memory for v6 lease structure.");
        !          2924:        option_state_reference(&client->active_lease->options,
        !          2925:                               packet->options, MDL);
        !          2926: 
        !          2927:        start_informed(client);
        !          2928: }
        !          2929: 
        !          2930: /* Specific version of init_handler() for rapid-commit.
        !          2931:  */
        !          2932: void
        !          2933: rapid_commit_handler(struct packet *packet, struct client_state *client)
        !          2934: {
        !          2935:        struct dhc6_lease *lease;
        !          2936:        isc_result_t check_status;
        !          2937: 
        !          2938:        /* On ADVERTISE just fall back to the init_handler().
        !          2939:         */
        !          2940:        if (packet->dhcpv6_msg_type == DHCPV6_ADVERTISE) {
        !          2941:                init_handler(packet, client);
        !          2942:                return;
        !          2943:        } else if (packet->dhcpv6_msg_type != DHCPV6_REPLY)
        !          2944:                return;
        !          2945: 
        !          2946:        /* RFC3315 section 15.10 validation (same as 15.3 since we
        !          2947:         * always include a client id).
        !          2948:         */
        !          2949:        if (!valid_reply(packet, client)) {
        !          2950:                log_error("Invalid Reply - rejecting.");
        !          2951:                return;
        !          2952:        }
        !          2953: 
        !          2954:        /* A rapid-commit option MUST be here. */
        !          2955:        if (lookup_option(&dhcpv6_universe, packet->options,
        !          2956:                          D6O_RAPID_COMMIT) == 0) {
        !          2957:                log_error("Reply without Rapid-Commit - rejecting.");
        !          2958:                return;
        !          2959:        }
        !          2960: 
        !          2961:        lease = dhc6_leaseify(packet);
        !          2962: 
        !          2963:        /* This is an out of memory condition...hopefully a temporary
        !          2964:         * problem.  Returning now makes us try to retransmit later.
        !          2965:         */
        !          2966:        if (lease == NULL)
        !          2967:                return;
        !          2968: 
        !          2969:        check_status = dhc6_check_reply(client, lease);
        !          2970:        if (check_status != ISC_R_SUCCESS) {
        !          2971:                dhc6_lease_destroy(&lease, MDL);
        !          2972:                return;
        !          2973:        }
        !          2974: 
        !          2975:        /* Jump to the selecting state. */
        !          2976:        cancel_timeout(do_init6, client);
        !          2977:        client->state = S_SELECTING;
        !          2978: 
        !          2979:        /* Merge any bindings in the active lease (if there is one) into
        !          2980:         * the new active lease.
        !          2981:         */
        !          2982:        dhc6_merge_lease(client->active_lease, lease);
        !          2983: 
        !          2984:        /* Cleanup if a previous attempt to go bound failed. */
        !          2985:        if (client->old_lease != NULL) {
        !          2986:                dhc6_lease_destroy(&client->old_lease, MDL);
        !          2987:                client->old_lease = NULL;
        !          2988:        }
        !          2989: 
        !          2990:        /* Make this lease active and BIND to it. */
        !          2991:        if (client->active_lease != NULL)
        !          2992:                client->old_lease = client->active_lease;
        !          2993:        client->active_lease = lease;
        !          2994: 
        !          2995:        /* We're done with the ADVERTISEd leases, if any. */
        !          2996:        while(client->advertised_leases != NULL) {
        !          2997:                lease = client->advertised_leases;
        !          2998:                client->advertised_leases = lease->next;
        !          2999: 
        !          3000:                dhc6_lease_destroy(&lease, MDL);
        !          3001:        }
        !          3002: 
        !          3003:        start_bound(client);
        !          3004: }
        !          3005: 
        !          3006: /* Find the 'best' lease in the cache of advertised leases (usually).  From
        !          3007:  * RFC3315 Section 17.1.3:
        !          3008:  *
        !          3009:  *   Upon receipt of one or more valid Advertise messages, the client
        !          3010:  *   selects one or more Advertise messages based upon the following
        !          3011:  *   criteria.
        !          3012:  *
        !          3013:  *   -  Those Advertise messages with the highest server preference value
        !          3014:  *      are preferred over all other Advertise messages.
        !          3015:  *
        !          3016:  *   -  Within a group of Advertise messages with the same server
        !          3017:  *      preference value, a client MAY select those servers whose
        !          3018:  *      Advertise messages advertise information of interest to the
        !          3019:  *      client.  For example, the client may choose a server that returned
        !          3020:  *      an advertisement with configuration options of interest to the
        !          3021:  *      client.
        !          3022:  *
        !          3023:  *   -  The client MAY choose a less-preferred server if that server has a
        !          3024:  *      better set of advertised parameters, such as the available
        !          3025:  *      addresses advertised in IAs.
        !          3026:  *
        !          3027:  * Note that the first and third contradict each other.  The third should
        !          3028:  * probably be taken to mean that the client should prefer answers that
        !          3029:  * offer bindings, even if that violates the preference rule.
        !          3030:  *
        !          3031:  * The above also isn't deterministic where there are ties.  So the final
        !          3032:  * tiebreaker we add, if all other values are equal, is to compare the
        !          3033:  * server identifiers and to select the numerically lower one.
        !          3034:  */
        !          3035: static struct dhc6_lease *
        !          3036: dhc6_best_lease(struct client_state *client, struct dhc6_lease **head)
        !          3037: {
        !          3038:        struct dhc6_lease **rpos, *rval, **candp, *cand;
        !          3039:        int cscore, rscore;
        !          3040: 
        !          3041:        if (head == NULL || *head == NULL)
        !          3042:                return NULL;
        !          3043: 
        !          3044:        rpos = head;
        !          3045:        rval = *rpos;
        !          3046:        rscore = dhc6_score_lease(client, rval);
        !          3047:        candp = &rval->next;
        !          3048:        cand = *candp;
        !          3049: 
        !          3050:        log_debug("PRC: Considering best lease.");
        !          3051:        log_debug("PRC:  X-- Initial candidate %s (s: %d, p: %u).",
        !          3052:                  print_hex_1(rval->server_id.len,
        !          3053:                              rval->server_id.data, 48),
        !          3054:                  rscore, (unsigned)rval->pref);
        !          3055: 
        !          3056:        for (; cand != NULL ; candp = &cand->next, cand = *candp) {
        !          3057:                cscore = dhc6_score_lease(client, cand);
        !          3058: 
        !          3059:                log_debug("PRC:  X-- Candidate %s (s: %d, p: %u).",
        !          3060:                          print_hex_1(cand->server_id.len,
        !          3061:                                      cand->server_id.data, 48),
        !          3062:                          cscore, (unsigned)cand->pref);
        !          3063: 
        !          3064:                /* Above you'll find quoted RFC3315 Section 17.1.3.
        !          3065:                 *
        !          3066:                 * The third clause tells us to give up on leases that
        !          3067:                 * have no bindings even if their preference is better.
        !          3068:                 * So where our 'selected' lease's score is less than 150
        !          3069:                 * (1 ia + 1 addr), choose any candidate >= 150.
        !          3070:                 *
        !          3071:                 * The first clause tells us to make preference the primary
        !          3072:                 * deciding factor.  So if it's lower, reject, if it's
        !          3073:                 * higher, select.
        !          3074:                 *
        !          3075:                 * The second clause tells us where the preference is
        !          3076:                 * equal, we should use 'our judgement' of what we like
        !          3077:                 * to see in an advertisement primarily.
        !          3078:                 *
        !          3079:                 * But there can still be a tie.  To make this deterministic,
        !          3080:                 * we compare the server identifiers and select the binary
        !          3081:                 * lowest.
        !          3082:                 *
        !          3083:                 * Since server id's are unique in this list, there is
        !          3084:                 * no further tie to break.
        !          3085:                 */
        !          3086:                if ((rscore < 150) && (cscore >= 150)) {
        !          3087:                        log_debug("PRC:  | X-- Selected, has bindings.");
        !          3088:                } else if (cand->pref < rval->pref) {
        !          3089:                        log_debug("PRC:  | X-- Rejected, lower preference.");
        !          3090:                        continue;
        !          3091:                } else if (cand->pref > rval->pref) {
        !          3092:                        log_debug("PRC:  | X-- Selected, higher preference.");
        !          3093:                } else if (cscore > rscore) {
        !          3094:                        log_debug("PRC:  | X-- Selected, equal preference, "
        !          3095:                                  "higher score.");
        !          3096:                } else if (cscore < rscore) {
        !          3097:                        log_debug("PRC:  | X-- Rejected, equal preference, "
        !          3098:                                  "lower score.");
        !          3099:                        continue;
        !          3100:                } else if ((cand->server_id.len < rval->server_id.len) ||
        !          3101:                           ((cand->server_id.len == rval->server_id.len) &&
        !          3102:                            (memcmp(cand->server_id.data,
        !          3103:                                    rval->server_id.data,
        !          3104:                                    cand->server_id.len) < 0))) {
        !          3105:                        log_debug("PRC:  | X-- Selected, equal preference, "
        !          3106:                                  "equal score, binary lesser server ID.");
        !          3107:                } else {
        !          3108:                        log_debug("PRC:  | X-- Rejected, equal preference, "
        !          3109:                                  "equal score, binary greater server ID.");
        !          3110:                        continue;
        !          3111:                }
        !          3112: 
        !          3113:                rpos = candp;
        !          3114:                rval = cand;
        !          3115:                rscore = cscore;
        !          3116:        }
        !          3117: 
        !          3118:        /* Remove the selected lease from the chain. */
        !          3119:        *rpos = rval->next;
        !          3120: 
        !          3121:        return rval;
        !          3122: }
        !          3123: 
        !          3124: /* Select a lease out of the advertised leases and setup state to try and
        !          3125:  * acquire that lease.
        !          3126:  */
        !          3127: void
        !          3128: start_selecting6(struct client_state *client)
        !          3129: {
        !          3130:        struct dhc6_lease *lease;
        !          3131: 
        !          3132:        if (client->advertised_leases == NULL) {
        !          3133:                log_error("Can not enter DHCPv6 SELECTING state with no "
        !          3134:                          "leases to select from!");
        !          3135:                return;
        !          3136:        }
        !          3137: 
        !          3138:        log_debug("PRC: Selecting best advertised lease.");
        !          3139:        client->state = S_SELECTING;
        !          3140: 
        !          3141:        lease = dhc6_best_lease(client, &client->advertised_leases);
        !          3142: 
        !          3143:        if (lease == NULL)
        !          3144:                log_fatal("Impossible error at %s:%d.", MDL);
        !          3145: 
        !          3146:        client->selected_lease = lease;
        !          3147: 
        !          3148:        /* Set timers per RFC3315 section 18.1.1. */
        !          3149:        client->IRT = REQ_TIMEOUT * 100;
        !          3150:        client->MRT = REQ_MAX_RT * 100;
        !          3151:        client->MRC = REQ_MAX_RC;
        !          3152:        client->MRD = 0;
        !          3153: 
        !          3154:        dhc6_retrans_init(client);
        !          3155: 
        !          3156:        client->v6_handler = reply_handler;
        !          3157: 
        !          3158:        /* ("re")transmit the first packet. */
        !          3159:        do_select6(client);
        !          3160: }
        !          3161: 
        !          3162: /* Transmit a Request to select a lease offered in Advertisements.  In
        !          3163:  * the event of failure, either move on to the next-best advertised lease,
        !          3164:  * or head back to INIT state if there are none.
        !          3165:  */
        !          3166: void
        !          3167: do_select6(void *input)
        !          3168: {
        !          3169:        struct client_state *client;
        !          3170:        struct dhc6_lease *lease;
        !          3171:        struct data_string ds;
        !          3172:        struct timeval tv;
        !          3173:        int send_ret;
        !          3174: 
        !          3175:        client = input;
        !          3176: 
        !          3177:        /* 'lease' is fewer characters to type. */
        !          3178:        lease = client->selected_lease;
        !          3179:        if (lease == NULL || lease->bindings == NULL) {
        !          3180:                log_error("Illegal to attempt selection without selecting "
        !          3181:                          "a lease.");
        !          3182:                return;
        !          3183:        }
        !          3184: 
        !          3185:        switch(check_timing6(client, DHCPV6_REQUEST, "Request", lease, &ds)) {
        !          3186:              case CHK_TIM_MRC_EXCEEDED:
        !          3187:              case CHK_TIM_MRD_EXCEEDED:
        !          3188:                log_debug("PRC: Lease %s failed.",
        !          3189:                          print_hex_1(lease->server_id.len,
        !          3190:                                      lease->server_id.data, 56));
        !          3191: 
        !          3192:                /* Get rid of the lease that timed/counted out. */
        !          3193:                dhc6_lease_destroy(&lease, MDL);
        !          3194:                client->selected_lease = NULL;
        !          3195: 
        !          3196:                /* If there are more leases great.  If not, get more. */
        !          3197:                if (client->advertised_leases != NULL)
        !          3198:                        start_selecting6(client);
        !          3199:                else
        !          3200:                        start_init6(client);
        !          3201:                return;
        !          3202:              case CHK_TIM_ALLOC_FAILURE:
        !          3203:                return;
        !          3204:              case CHK_TIM_SUCCESS:
        !          3205:                break;
        !          3206:        }
        !          3207: 
        !          3208:        /* Now make a packet that looks suspiciously like the one we
        !          3209:         * got from the server.  But different.
        !          3210:         *
        !          3211:         * XXX: I guess IAID is supposed to be something the client
        !          3212:         * indicates and uses as a key to its internal state.  It is
        !          3213:         * kind of odd to ask the server for IA's whose IAID the client
        !          3214:         * did not manufacture.  We first need a formal dhclient.conf
        !          3215:         * construct for the iaid, then we can delve into this matter
        !          3216:         * more properly.  In the time being, this will work.
        !          3217:         */
        !          3218: 
        !          3219:        /* Fetch any configured 'sent' options (includes DUID) in wire format.
        !          3220:         */
        !          3221:        dhcpv6_universe.encapsulate(&ds, NULL, NULL, client,
        !          3222:                                    NULL, client->sent_options, &global_scope,
        !          3223:                                    &dhcpv6_universe);
        !          3224: 
        !          3225:        /* Now append any IA's, and within them any IAADDR/IAPREFIXs. */
        !          3226:        if (wanted_ia_na &&
        !          3227:            dhc6_add_ia_na(client, &ds, lease,
        !          3228:                           DHCPV6_REQUEST) != ISC_R_SUCCESS) {
        !          3229:                data_string_forget(&ds, MDL);
        !          3230:                return;
        !          3231:        }
        !          3232:        if (wanted_ia_ta &&
        !          3233:            dhc6_add_ia_ta(client, &ds, lease,
        !          3234:                           DHCPV6_REQUEST) != ISC_R_SUCCESS) {
        !          3235:                data_string_forget(&ds, MDL);
        !          3236:                return;
        !          3237:        }
        !          3238:        if (wanted_ia_pd &&
        !          3239:            dhc6_add_ia_pd(client, &ds, lease,
        !          3240:                           DHCPV6_REQUEST) != ISC_R_SUCCESS) {
        !          3241:                data_string_forget(&ds, MDL);
        !          3242:                return;
        !          3243:        }
        !          3244: 
        !          3245:        log_info("XMT: Request on %s, interval %ld0ms.",
        !          3246:                 client->name ? client->name : client->interface->name,
        !          3247:                 (long int)client->RT);
        !          3248: 
        !          3249:        send_ret = send_packet6(client->interface,
        !          3250:                                ds.data, ds.len, &DHCPv6DestAddr);
        !          3251:        if (send_ret != ds.len) {
        !          3252:                log_error("dhc6: send_packet6() sent %d of %d bytes",
        !          3253:                          send_ret, ds.len);
        !          3254:        }
        !          3255: 
        !          3256:        data_string_forget(&ds, MDL);
        !          3257: 
        !          3258:        /* Wait RT */
        !          3259:        tv.tv_sec = cur_tv.tv_sec + client->RT / 100;
        !          3260:        tv.tv_usec = cur_tv.tv_usec + (client->RT % 100) * 10000;
        !          3261:        if (tv.tv_usec >= 1000000) {
        !          3262:                tv.tv_sec += 1;
        !          3263:                tv.tv_usec -= 1000000;
        !          3264:        }
        !          3265:        add_timeout(&tv, do_select6, client, NULL, NULL);
        !          3266: 
        !          3267:        dhc6_retrans_advance(client);
        !          3268: }
        !          3269: 
        !          3270: /* For each IA_NA in the lease, for each address in the IA_NA,
        !          3271:  * append that information onto the packet-so-far.
        !          3272:  */
        !          3273: static isc_result_t
        !          3274: dhc6_add_ia_na(struct client_state *client, struct data_string *packet,
        !          3275:               struct dhc6_lease *lease, u_int8_t message)
        !          3276: {
        !          3277:        struct data_string iads;
        !          3278:        struct data_string addrds;
        !          3279:        struct dhc6_addr *addr;
        !          3280:        struct dhc6_ia *ia;
        !          3281:        isc_result_t rval = ISC_R_SUCCESS;
        !          3282:        TIME t1, t2;
        !          3283: 
        !          3284:        memset(&iads, 0, sizeof(iads));
        !          3285:        memset(&addrds, 0, sizeof(addrds));
        !          3286:        for (ia = lease->bindings;
        !          3287:             ia != NULL && rval == ISC_R_SUCCESS;
        !          3288:             ia = ia->next) {
        !          3289:                if (ia->ia_type != D6O_IA_NA)
        !          3290:                        continue;
        !          3291: 
        !          3292:                if (!buffer_allocate(&iads.buffer, 12, MDL)) {
        !          3293:                        log_error("Unable to allocate memory for IA_NA.");
        !          3294:                        rval = ISC_R_NOMEMORY;
        !          3295:                        break;
        !          3296:                }
        !          3297: 
        !          3298:                /* Copy the IAID into the packet buffer. */
        !          3299:                memcpy(iads.buffer->data, ia->iaid, 4);
        !          3300:                iads.data = iads.buffer->data;
        !          3301:                iads.len = 12;
        !          3302: 
        !          3303:                switch (message) {
        !          3304:                      case DHCPV6_REQUEST:
        !          3305:                      case DHCPV6_RENEW:
        !          3306:                      case DHCPV6_REBIND:
        !          3307: 
        !          3308:                        t1 = client->config->requested_lease / 2;
        !          3309:                        t2 = t1 + (t1 / 2);
        !          3310: #if MAX_TIME > 0xffffffff
        !          3311:                        if (t1 > 0xffffffff)
        !          3312:                                t1 = 0xffffffff;
        !          3313:                        if (t2 > 0xffffffff)
        !          3314:                                t2 = 0xffffffff;
        !          3315: #endif
        !          3316:                        putULong(iads.buffer->data + 4, t1);
        !          3317:                        putULong(iads.buffer->data + 8, t2);
        !          3318: 
        !          3319:                        log_debug("XMT:  X-- IA_NA %s",
        !          3320:                                  print_hex_1(4, iads.data, 59));
        !          3321:                        log_debug("XMT:  | X-- Requested renew  +%u",
        !          3322:                                  (unsigned) t1);
        !          3323:                        log_debug("XMT:  | X-- Requested rebind +%u",
        !          3324:                                  (unsigned) t2);
        !          3325:                        break;
        !          3326: 
        !          3327:                      case DHCPV6_CONFIRM:
        !          3328:                      case DHCPV6_RELEASE:
        !          3329:                      case DHCPV6_DECLINE:
        !          3330:                        /* Set t1 and t2 to zero; server will ignore them */
        !          3331:                        memset(iads.buffer->data + 4, 0, 8);
        !          3332:                        log_debug("XMT:  X-- IA_NA %s",
        !          3333:                                  print_hex_1(4, iads.buffer->data, 55));
        !          3334: 
        !          3335:                        break;
        !          3336: 
        !          3337:                      default:
        !          3338:                        log_fatal("Impossible condition at %s:%d.", MDL);
        !          3339:                }
        !          3340: 
        !          3341:                for (addr = ia->addrs ; addr != NULL ; addr = addr->next) {
        !          3342:                        /*
        !          3343:                         * Do not confirm expired addresses, do not request
        !          3344:                         * expired addresses (but we keep them around for
        !          3345:                         * solicit).
        !          3346:                         */
        !          3347:                        if (addr->flags & DHC6_ADDR_EXPIRED)
        !          3348:                                continue;
        !          3349: 
        !          3350:                        if (addr->address.len != 16) {
        !          3351:                                log_error("Illegal IPv6 address length (%d), "
        !          3352:                                          "ignoring.  (%s:%d)",
        !          3353:                                          addr->address.len, MDL);
        !          3354:                                continue;
        !          3355:                        }
        !          3356: 
        !          3357:                        if (!buffer_allocate(&addrds.buffer, 24, MDL)) {
        !          3358:                                log_error("Unable to allocate memory for "
        !          3359:                                          "IAADDR.");
        !          3360:                                rval = ISC_R_NOMEMORY;
        !          3361:                                break;
        !          3362:                        }
        !          3363: 
        !          3364:                        addrds.data = addrds.buffer->data;
        !          3365:                        addrds.len = 24;
        !          3366: 
        !          3367:                        /* Copy the address into the packet buffer. */
        !          3368:                        memcpy(addrds.buffer->data, addr->address.iabuf, 16);
        !          3369: 
        !          3370:                        /* Copy in additional information as appropriate */
        !          3371:                        switch (message) {
        !          3372:                              case DHCPV6_REQUEST:
        !          3373:                              case DHCPV6_RENEW:
        !          3374:                              case DHCPV6_REBIND:
        !          3375:                                t1 = client->config->requested_lease;
        !          3376:                                t2 = t1 + 300;
        !          3377:                                putULong(addrds.buffer->data + 16, t1);
        !          3378:                                putULong(addrds.buffer->data + 20, t2);
        !          3379: 
        !          3380:                                log_debug("XMT:  | | X-- IAADDR %s",
        !          3381:                                          piaddr(addr->address));
        !          3382:                                log_debug("XMT:  | | | X-- Preferred "
        !          3383:                                          "lifetime +%u", (unsigned)t1);
        !          3384:                                log_debug("XMT:  | | | X-- Max lifetime +%u",
        !          3385:                                          (unsigned)t2);
        !          3386: 
        !          3387:                                break;
        !          3388: 
        !          3389:                              case DHCPV6_CONFIRM:
        !          3390:                                /*
        !          3391:                                 * Set preferred and max life to zero,
        !          3392:                                 * per 17.1.3.
        !          3393:                                 */
        !          3394:                                memset(addrds.buffer->data + 16, 0, 8);
        !          3395:                                log_debug("XMT:  | X-- Confirm Address %s",
        !          3396:                                          piaddr(addr->address));
        !          3397:                                break;
        !          3398: 
        !          3399:                              case DHCPV6_RELEASE:
        !          3400:                                /* Preferred and max life are irrelevant */
        !          3401:                                memset(addrds.buffer->data + 16, 0, 8);
        !          3402:                                log_debug("XMT:  | X-- Release Address %s",
        !          3403:                                          piaddr(addr->address));
        !          3404:                                break;
        !          3405: 
        !          3406:                              case DHCPV6_DECLINE:
        !          3407:                                /* Preferred and max life are irrelevant */
        !          3408:                                memset(addrds.buffer->data + 16, 0, 8);
        !          3409:                                log_debug("XMT:  | X-- Decline Address %s",
        !          3410:                                          piaddr(addr->address));
        !          3411:                                break;
        !          3412: 
        !          3413:                              default:
        !          3414:                                log_fatal("Impossible condition at %s:%d.",
        !          3415:                                          MDL);
        !          3416:                        }
        !          3417: 
        !          3418:                        append_option(&iads, &dhcpv6_universe, iaaddr_option,
        !          3419:                                      &addrds);
        !          3420:                        data_string_forget(&addrds, MDL);
        !          3421:                }
        !          3422: 
        !          3423:                /*
        !          3424:                 * It doesn't make sense to make a request without an
        !          3425:                 * address.
        !          3426:                 */
        !          3427:                if (ia->addrs == NULL) {
        !          3428:                        log_debug("!!!:  V IA_NA has no IAADDRs - removed.");
        !          3429:                        rval = ISC_R_FAILURE;
        !          3430:                } else if (rval == ISC_R_SUCCESS) {
        !          3431:                        log_debug("XMT:  V IA_NA appended.");
        !          3432:                        append_option(packet, &dhcpv6_universe, ia_na_option,
        !          3433:                                      &iads);
        !          3434:                }
        !          3435: 
        !          3436:                data_string_forget(&iads, MDL);
        !          3437:        }
        !          3438: 
        !          3439:        return rval;
        !          3440: }
        !          3441: 
        !          3442: /* For each IA_TA in the lease, for each address in the IA_TA,
        !          3443:  * append that information onto the packet-so-far.
        !          3444:  */
        !          3445: static isc_result_t
        !          3446: dhc6_add_ia_ta(struct client_state *client, struct data_string *packet,
        !          3447:               struct dhc6_lease *lease, u_int8_t message)
        !          3448: {
        !          3449:        struct data_string iads;
        !          3450:        struct data_string addrds;
        !          3451:        struct dhc6_addr *addr;
        !          3452:        struct dhc6_ia *ia;
        !          3453:        isc_result_t rval = ISC_R_SUCCESS;
        !          3454:        TIME t1, t2;
        !          3455: 
        !          3456:        memset(&iads, 0, sizeof(iads));
        !          3457:        memset(&addrds, 0, sizeof(addrds));
        !          3458:        for (ia = lease->bindings;
        !          3459:             ia != NULL && rval == ISC_R_SUCCESS;
        !          3460:             ia = ia->next) {
        !          3461:                if (ia->ia_type != D6O_IA_TA)
        !          3462:                        continue;
        !          3463: 
        !          3464:                if (!buffer_allocate(&iads.buffer, 4, MDL)) {
        !          3465:                        log_error("Unable to allocate memory for IA_TA.");
        !          3466:                        rval = ISC_R_NOMEMORY;
        !          3467:                        break;
        !          3468:                }
        !          3469: 
        !          3470:                /* Copy the IAID into the packet buffer. */
        !          3471:                memcpy(iads.buffer->data, ia->iaid, 4);
        !          3472:                iads.data = iads.buffer->data;
        !          3473:                iads.len = 4;
        !          3474: 
        !          3475:                log_debug("XMT:  X-- IA_TA %s",
        !          3476:                          print_hex_1(4, iads.buffer->data, 55));
        !          3477: 
        !          3478:                for (addr = ia->addrs ; addr != NULL ; addr = addr->next) {
        !          3479:                        /*
        !          3480:                         * Do not confirm expired addresses, do not request
        !          3481:                         * expired addresses (but we keep them around for
        !          3482:                         * solicit).
        !          3483:                         */
        !          3484:                        if (addr->flags & DHC6_ADDR_EXPIRED)
        !          3485:                                continue;
        !          3486: 
        !          3487:                        if (addr->address.len != 16) {
        !          3488:                                log_error("Illegal IPv6 address length (%d), "
        !          3489:                                          "ignoring.  (%s:%d)",
        !          3490:                                          addr->address.len, MDL);
        !          3491:                                continue;
        !          3492:                        }
        !          3493: 
        !          3494:                        if (!buffer_allocate(&addrds.buffer, 24, MDL)) {
        !          3495:                                log_error("Unable to allocate memory for "
        !          3496:                                          "IAADDR.");
        !          3497:                                rval = ISC_R_NOMEMORY;
        !          3498:                                break;
        !          3499:                        }
        !          3500: 
        !          3501:                        addrds.data = addrds.buffer->data;
        !          3502:                        addrds.len = 24;
        !          3503: 
        !          3504:                        /* Copy the address into the packet buffer. */
        !          3505:                        memcpy(addrds.buffer->data, addr->address.iabuf, 16);
        !          3506: 
        !          3507:                        /* Copy in additional information as appropriate */
        !          3508:                        switch (message) {
        !          3509:                              case DHCPV6_REQUEST:
        !          3510:                              case DHCPV6_RENEW:
        !          3511:                              case DHCPV6_REBIND:
        !          3512:                                t1 = client->config->requested_lease;
        !          3513:                                t2 = t1 + 300;
        !          3514:                                putULong(addrds.buffer->data + 16, t1);
        !          3515:                                putULong(addrds.buffer->data + 20, t2);
        !          3516: 
        !          3517:                                log_debug("XMT:  | | X-- IAADDR %s",
        !          3518:                                          piaddr(addr->address));
        !          3519:                                log_debug("XMT:  | | | X-- Preferred "
        !          3520:                                          "lifetime +%u", (unsigned)t1);
        !          3521:                                log_debug("XMT:  | | | X-- Max lifetime +%u",
        !          3522:                                          (unsigned)t2);
        !          3523: 
        !          3524:                                break;
        !          3525: 
        !          3526:                              case DHCPV6_CONFIRM:
        !          3527:                                /*
        !          3528:                                 * Set preferred and max life to zero,
        !          3529:                                 * per 17.1.3.
        !          3530:                                 */
        !          3531:                                memset(addrds.buffer->data + 16, 0, 8);
        !          3532:                                log_debug("XMT:  | X-- Confirm Address %s",
        !          3533:                                          piaddr(addr->address));
        !          3534:                                break;
        !          3535: 
        !          3536:                              case DHCPV6_RELEASE:
        !          3537:                                /* Preferred and max life are irrelevant */
        !          3538:                                memset(addrds.buffer->data + 16, 0, 8);
        !          3539:                                log_debug("XMT:  | X-- Release Address %s",
        !          3540:                                          piaddr(addr->address));
        !          3541:                                break;
        !          3542: 
        !          3543:                              default:
        !          3544:                                log_fatal("Impossible condition at %s:%d.",
        !          3545:                                          MDL);
        !          3546:                        }
        !          3547: 
        !          3548:                        append_option(&iads, &dhcpv6_universe, iaaddr_option,
        !          3549:                                      &addrds);
        !          3550:                        data_string_forget(&addrds, MDL);
        !          3551:                }
        !          3552: 
        !          3553:                /*
        !          3554:                 * It doesn't make sense to make a request without an
        !          3555:                 * address.
        !          3556:                 */
        !          3557:                if (ia->addrs == NULL) {
        !          3558:                        log_debug("!!!:  V IA_TA has no IAADDRs - removed.");
        !          3559:                        rval = ISC_R_FAILURE;
        !          3560:                } else if (rval == ISC_R_SUCCESS) {
        !          3561:                        log_debug("XMT:  V IA_TA appended.");
        !          3562:                        append_option(packet, &dhcpv6_universe, ia_ta_option,
        !          3563:                                      &iads);
        !          3564:                }
        !          3565: 
        !          3566:                data_string_forget(&iads, MDL);
        !          3567:        }
        !          3568: 
        !          3569:        return rval;
        !          3570: }
        !          3571: 
        !          3572: /* For each IA_PD in the lease, for each prefix in the IA_PD,
        !          3573:  * append that information onto the packet-so-far.
        !          3574:  */
        !          3575: static isc_result_t
        !          3576: dhc6_add_ia_pd(struct client_state *client, struct data_string *packet,
        !          3577:               struct dhc6_lease *lease, u_int8_t message)
        !          3578: {
        !          3579:        struct data_string iads;
        !          3580:        struct data_string prefds;
        !          3581:        struct dhc6_addr *pref;
        !          3582:        struct dhc6_ia *ia;
        !          3583:        isc_result_t rval = ISC_R_SUCCESS;
        !          3584:        TIME t1, t2;
        !          3585: 
        !          3586:        memset(&iads, 0, sizeof(iads));
        !          3587:        memset(&prefds, 0, sizeof(prefds));
        !          3588:        for (ia = lease->bindings;
        !          3589:             ia != NULL && rval == ISC_R_SUCCESS;
        !          3590:             ia = ia->next) {
        !          3591:                if (ia->ia_type != D6O_IA_PD)
        !          3592:                        continue;
        !          3593: 
        !          3594:                if (!buffer_allocate(&iads.buffer, 12, MDL)) {
        !          3595:                        log_error("Unable to allocate memory for IA_PD.");
        !          3596:                        rval = ISC_R_NOMEMORY;
        !          3597:                        break;
        !          3598:                }
        !          3599: 
        !          3600:                /* Copy the IAID into the packet buffer. */
        !          3601:                memcpy(iads.buffer->data, ia->iaid, 4);
        !          3602:                iads.data = iads.buffer->data;
        !          3603:                iads.len = 12;
        !          3604: 
        !          3605:                switch (message) {
        !          3606:                      case DHCPV6_REQUEST:
        !          3607:                      case DHCPV6_RENEW:
        !          3608:                      case DHCPV6_REBIND:
        !          3609: 
        !          3610:                        t1 = client->config->requested_lease / 2;
        !          3611:                        t2 = t1 + (t1 / 2);
        !          3612: #if MAX_TIME > 0xffffffff
        !          3613:                        if (t1 > 0xffffffff)
        !          3614:                                t1 = 0xffffffff;
        !          3615:                        if (t2 > 0xffffffff)
        !          3616:                                t2 = 0xffffffff;
        !          3617: #endif
        !          3618:                        putULong(iads.buffer->data + 4, t1);
        !          3619:                        putULong(iads.buffer->data + 8, t2);
        !          3620: 
        !          3621:                        log_debug("XMT:  X-- IA_PD %s",
        !          3622:                                  print_hex_1(4, iads.data, 59));
        !          3623:                        log_debug("XMT:  | X-- Requested renew  +%u",
        !          3624:                                  (unsigned) t1);
        !          3625:                        log_debug("XMT:  | X-- Requested rebind +%u",
        !          3626:                                  (unsigned) t2);
        !          3627:                        break;
        !          3628: 
        !          3629:                      case DHCPV6_RELEASE:
        !          3630:                        /* Set t1 and t2 to zero; server will ignore them */
        !          3631:                        memset(iads.buffer->data + 4, 0, 8);
        !          3632:                        log_debug("XMT:  X-- IA_PD %s",
        !          3633:                                  print_hex_1(4, iads.buffer->data, 55));
        !          3634: 
        !          3635:                        break;
        !          3636: 
        !          3637:                      default:
        !          3638:                        log_fatal("Impossible condition at %s:%d.", MDL);
        !          3639:                }
        !          3640: 
        !          3641:                for (pref = ia->addrs ; pref != NULL ; pref = pref->next) {
        !          3642:                        /*
        !          3643:                         * Do not confirm expired prefixes, do not request
        !          3644:                         * expired prefixes (but we keep them around for
        !          3645:                         * solicit).
        !          3646:                         */
        !          3647:                        if (pref->flags & DHC6_ADDR_EXPIRED)
        !          3648:                                continue;
        !          3649: 
        !          3650:                        if (pref->address.len != 16) {
        !          3651:                                log_error("Illegal IPv6 prefix "
        !          3652:                                          "ignoring.  (%s:%d)",
        !          3653:                                          MDL);
        !          3654:                                continue;
        !          3655:                        }
        !          3656: 
        !          3657:                        if (pref->plen == 0) {
        !          3658:                                log_info("Null IPv6 prefix, "
        !          3659:                                         "ignoring. (%s:%d)",
        !          3660:                                         MDL);
        !          3661:                        }
        !          3662: 
        !          3663:                        if (!buffer_allocate(&prefds.buffer, 25, MDL)) {
        !          3664:                                log_error("Unable to allocate memory for "
        !          3665:                                          "IAPREFIX.");
        !          3666:                                rval = ISC_R_NOMEMORY;
        !          3667:                                break;
        !          3668:                        }
        !          3669: 
        !          3670:                        prefds.data = prefds.buffer->data;
        !          3671:                        prefds.len = 25;
        !          3672: 
        !          3673:                        /* Copy the prefix into the packet buffer. */
        !          3674:                        putUChar(prefds.buffer->data + 8, pref->plen);
        !          3675:                        memcpy(prefds.buffer->data + 9,
        !          3676:                               pref->address.iabuf,
        !          3677:                               16);
        !          3678: 
        !          3679:                        /* Copy in additional information as appropriate */
        !          3680:                        switch (message) {
        !          3681:                              case DHCPV6_REQUEST:
        !          3682:                              case DHCPV6_RENEW:
        !          3683:                              case DHCPV6_REBIND:
        !          3684:                                t1 = client->config->requested_lease;
        !          3685:                                t2 = t1 + 300;
        !          3686:                                putULong(prefds.buffer->data, t1);
        !          3687:                                putULong(prefds.buffer->data + 4, t2);
        !          3688: 
        !          3689:                                log_debug("XMT:  | | X-- IAPREFIX %s/%u",
        !          3690:                                          piaddr(pref->address),
        !          3691:                                          (unsigned) pref->plen);
        !          3692:                                log_debug("XMT:  | | | X-- Preferred "
        !          3693:                                          "lifetime +%u", (unsigned)t1);
        !          3694:                                log_debug("XMT:  | | | X-- Max lifetime +%u",
        !          3695:                                          (unsigned)t2);
        !          3696: 
        !          3697:                                break;
        !          3698: 
        !          3699:                              case DHCPV6_RELEASE:
        !          3700:                                /* Preferred and max life are irrelevant */
        !          3701:                                memset(prefds.buffer->data, 0, 8);
        !          3702:                                log_debug("XMT:  | X-- Release Prefix %s/%u",
        !          3703:                                          piaddr(pref->address),
        !          3704:                                          (unsigned) pref->plen);
        !          3705:                                break;
        !          3706: 
        !          3707:                              default:
        !          3708:                                log_fatal("Impossible condition at %s:%d.",
        !          3709:                                          MDL);
        !          3710:                        }
        !          3711: 
        !          3712:                        append_option(&iads, &dhcpv6_universe,
        !          3713:                                      iaprefix_option, &prefds);
        !          3714:                        data_string_forget(&prefds, MDL);
        !          3715:                }
        !          3716: 
        !          3717:                /*
        !          3718:                 * It doesn't make sense to make a request without an
        !          3719:                 * address.
        !          3720:                 */
        !          3721:                if (ia->addrs == NULL) {
        !          3722:                        log_debug("!!!:  V IA_PD has no IAPREFIXs - removed.");
        !          3723:                        rval = ISC_R_FAILURE;
        !          3724:                } else if (rval == ISC_R_SUCCESS) {
        !          3725:                        log_debug("XMT:  V IA_PD appended.");
        !          3726:                        append_option(packet, &dhcpv6_universe,
        !          3727:                                      ia_pd_option, &iads);
        !          3728:                }
        !          3729: 
        !          3730:                data_string_forget(&iads, MDL);
        !          3731:        }
        !          3732: 
        !          3733:        return rval;
        !          3734: }
        !          3735: 
        !          3736: /* stopping_finished() checks if there is a remaining work to do.
        !          3737:  */
        !          3738: static isc_boolean_t
        !          3739: stopping_finished(void)
        !          3740: {
        !          3741:        struct interface_info *ip;
        !          3742:        struct client_state *client;
        !          3743: 
        !          3744:        for (ip = interfaces; ip; ip = ip -> next) {
        !          3745:                for (client = ip -> client; client; client = client -> next) {
        !          3746:                        if (client->state != S_STOPPED)
        !          3747:                                return ISC_FALSE;
        !          3748:                        if (client->active_lease != NULL)
        !          3749:                                return ISC_FALSE;
        !          3750:                }
        !          3751:        }
        !          3752:        return ISC_TRUE;
        !          3753: }
        !          3754: 
        !          3755: /* reply_handler() accepts a Reply while we're attempting Select or Renew or
        !          3756:  * Rebind.  Basically any Reply packet.
        !          3757:  */
        !          3758: void
        !          3759: reply_handler(struct packet *packet, struct client_state *client)
        !          3760: {
        !          3761:        struct dhc6_lease *lease;
        !          3762:        isc_result_t check_status;
        !          3763: 
        !          3764:        if (packet->dhcpv6_msg_type != DHCPV6_REPLY)
        !          3765:                return;
        !          3766: 
        !          3767:        /* RFC3315 section 15.10 validation (same as 15.3 since we
        !          3768:         * always include a client id).
        !          3769:         */
        !          3770:        if (!valid_reply(packet, client)) {
        !          3771:                log_error("Invalid Reply - rejecting.");
        !          3772:                return;
        !          3773:        }
        !          3774: 
        !          3775:        lease = dhc6_leaseify(packet);
        !          3776: 
        !          3777:        /* This is an out of memory condition...hopefully a temporary
        !          3778:         * problem.  Returning now makes us try to retransmit later.
        !          3779:         */
        !          3780:        if (lease == NULL)
        !          3781:                return;
        !          3782: 
        !          3783:        check_status = dhc6_check_reply(client, lease);
        !          3784:        if (check_status != ISC_R_SUCCESS) {
        !          3785:                dhc6_lease_destroy(&lease, MDL);
        !          3786: 
        !          3787:                /* If no action was taken, but there is an error, then
        !          3788:                 * we wait for a retransmission.
        !          3789:                 */
        !          3790:                if (check_status != ISC_R_CANCELED)
        !          3791:                        return;
        !          3792:        }
        !          3793: 
        !          3794:        /* We're done retransmitting at this point. */
        !          3795:        cancel_timeout(do_confirm6, client);
        !          3796:        cancel_timeout(do_select6, client);
        !          3797:        cancel_timeout(do_refresh6, client);
        !          3798:        cancel_timeout(do_release6, client);
        !          3799: 
        !          3800:        /* If this is in response to a Release/Decline, clean up and return. */
        !          3801:        if (client->state == S_STOPPED) {
        !          3802:                if (client->active_lease == NULL)
        !          3803:                        return;
        !          3804: 
        !          3805:                dhc6_lease_destroy(&client->active_lease, MDL);
        !          3806:                client->active_lease = NULL;
        !          3807:                /* We should never wait for nothing!? */
        !          3808:                if (stopping_finished())
        !          3809:                        exit(0);
        !          3810:                return;
        !          3811:        }
        !          3812: 
        !          3813:        /* Action was taken, so now that we've torn down our scheduled
        !          3814:         * retransmissions, return.
        !          3815:         */
        !          3816:        if (check_status == ISC_R_CANCELED)
        !          3817:                return;
        !          3818: 
        !          3819:        if (client->selected_lease != NULL) {
        !          3820:                dhc6_lease_destroy(&client->selected_lease, MDL);
        !          3821:                client->selected_lease = NULL;
        !          3822:        }
        !          3823: 
        !          3824:        /* If this is in response to a confirm, we use the lease we've
        !          3825:         * already got, not the reply we were sent.
        !          3826:         */
        !          3827:        if (client->state == S_REBOOTING) {
        !          3828:                if (client->active_lease == NULL)
        !          3829:                        log_fatal("Impossible condition at %s:%d.", MDL);
        !          3830: 
        !          3831:                dhc6_lease_destroy(&lease, MDL);
        !          3832:                start_bound(client);
        !          3833:                return;
        !          3834:        }
        !          3835: 
        !          3836:        /* Merge any bindings in the active lease (if there is one) into
        !          3837:         * the new active lease.
        !          3838:         */
        !          3839:        dhc6_merge_lease(client->active_lease, lease);
        !          3840: 
        !          3841:        /* Cleanup if a previous attempt to go bound failed. */
        !          3842:        if (client->old_lease != NULL) {
        !          3843:                dhc6_lease_destroy(&client->old_lease, MDL);
        !          3844:                client->old_lease = NULL;
        !          3845:        }
        !          3846: 
        !          3847:        /* Make this lease active and BIND to it. */
        !          3848:        if (client->active_lease != NULL)
        !          3849:                client->old_lease = client->active_lease;
        !          3850:        client->active_lease = lease;
        !          3851: 
        !          3852:        /* We're done with the ADVERTISEd leases, if any. */
        !          3853:        while(client->advertised_leases != NULL) {
        !          3854:                lease = client->advertised_leases;
        !          3855:                client->advertised_leases = lease->next;
        !          3856: 
        !          3857:                dhc6_lease_destroy(&lease, MDL);
        !          3858:        }
        !          3859: 
        !          3860:        start_bound(client);
        !          3861: }
        !          3862: 
        !          3863: /* DHCPv6 packets are a little sillier than they needed to be - the root
        !          3864:  * packet contains options, then IA's which contain options, then within
        !          3865:  * that IAADDR's which contain options.
        !          3866:  *
        !          3867:  * To sort this out at dhclient-script time (which fetches config parameters
        !          3868:  * in environment variables), start_bound() iterates over each IAADDR, and
        !          3869:  * calls this function to marshall an environment variable set that includes
        !          3870:  * the most-specific option values related to that IAADDR in particular.
        !          3871:  *
        !          3872:  * To achieve this, we load environment variables for the root options space,
        !          3873:  * then the IA, then the IAADDR.  Any duplicate option names will be
        !          3874:  * over-written by the later versions.
        !          3875:  */
        !          3876: static void
        !          3877: dhc6_marshall_values(const char *prefix, struct client_state *client,
        !          3878:                     struct dhc6_lease *lease, struct dhc6_ia *ia,
        !          3879:                     struct dhc6_addr *addr)
        !          3880: {
        !          3881:        /* Option cache contents, in descending order of
        !          3882:         * scope.
        !          3883:         */
        !          3884:        if ((lease != NULL) && (lease->options != NULL))
        !          3885:                script_write_params6(client, prefix, lease->options);
        !          3886:        if ((ia != NULL) && (ia->options != NULL))
        !          3887:                script_write_params6(client, prefix, ia->options);
        !          3888:        if ((addr != NULL) && (addr->options != NULL))
        !          3889:                script_write_params6(client, prefix, addr->options);
        !          3890: 
        !          3891:        /* addr fields. */
        !          3892:        if (addr != NULL) {
        !          3893:                if ((ia != NULL) && (ia->ia_type == D6O_IA_PD)) {
        !          3894:                        client_envadd(client, prefix,
        !          3895:                                      "ip6_prefix", "%s/%u",
        !          3896:                                      piaddr(addr->address),
        !          3897:                                      (unsigned) addr->plen);
        !          3898:                } else {
        !          3899:                        /* Current practice is that all subnets are /64's, but
        !          3900:                         * some suspect this may not be permanent.
        !          3901:                         */
        !          3902:                        client_envadd(client, prefix, "ip6_prefixlen",
        !          3903:                                      "%d", 64);
        !          3904:                        client_envadd(client, prefix, "ip6_address",
        !          3905:                                      "%s", piaddr(addr->address));
        !          3906:                }
        !          3907:                if ((ia != NULL) && (ia->ia_type == D6O_IA_TA)) {
        !          3908:                        client_envadd(client, prefix,
        !          3909:                                      "ip6_type", "temporary");
        !          3910:                }
        !          3911:                client_envadd(client, prefix, "life_starts", "%d",
        !          3912:                              (int)(addr->starts));
        !          3913:                client_envadd(client, prefix, "preferred_life", "%d",
        !          3914:                              (int)(addr->preferred_life));
        !          3915:                client_envadd(client, prefix, "max_life", "%d",
        !          3916:                              (int)(addr->max_life));
        !          3917:        }
        !          3918: 
        !          3919:        /* ia fields. */
        !          3920:        if (ia != NULL) {
        !          3921:                client_envadd(client, prefix, "iaid", "%s",
        !          3922:                              print_hex_1(4, ia->iaid, 12));
        !          3923:                client_envadd(client, prefix, "starts", "%d",
        !          3924:                              (int)(ia->starts));
        !          3925:                client_envadd(client, prefix, "renew", "%u", ia->renew);
        !          3926:                client_envadd(client, prefix, "rebind", "%u", ia->rebind);
        !          3927:        }
        !          3928: }
        !          3929: 
        !          3930: /* Look at where the client's active lease is sitting.  If it's looking to
        !          3931:  * time out on renew, rebind, depref, or expiration, do those things.
        !          3932:  */
        !          3933: static void
        !          3934: dhc6_check_times(struct client_state *client)
        !          3935: {
        !          3936:        struct dhc6_lease *lease;
        !          3937:        struct dhc6_ia *ia;
        !          3938:        struct dhc6_addr *addr;
        !          3939:        TIME renew=MAX_TIME, rebind=MAX_TIME, depref=MAX_TIME,
        !          3940:             lo_expire=MAX_TIME, hi_expire=0, tmp;
        !          3941:        int has_addrs = ISC_FALSE;
        !          3942:        struct timeval tv;
        !          3943: 
        !          3944:        lease = client->active_lease;
        !          3945: 
        !          3946:        /* Bit spammy.  We should probably keep record of scheduled
        !          3947:         * events instead.
        !          3948:         */
        !          3949:        cancel_timeout(start_renew6, client);
        !          3950:        cancel_timeout(start_rebind6, client);
        !          3951:        cancel_timeout(do_depref, client);
        !          3952:        cancel_timeout(do_expire, client);
        !          3953: 
        !          3954:        for(ia = lease->bindings ; ia != NULL ; ia = ia->next) {
        !          3955:                TIME this_ia_lo_expire, this_ia_hi_expire, use_expire;
        !          3956: 
        !          3957:                this_ia_lo_expire = MAX_TIME;
        !          3958:                this_ia_hi_expire = 0;
        !          3959: 
        !          3960:                for (addr = ia->addrs ; addr != NULL ; addr = addr->next) {
        !          3961:                        if(!(addr->flags & DHC6_ADDR_DEPREFFED)) {
        !          3962:                                if (addr->preferred_life == 0xffffffff)
        !          3963:                                        tmp = MAX_TIME;
        !          3964:                                else
        !          3965:                                        tmp = addr->starts +
        !          3966:                                              addr->preferred_life;
        !          3967: 
        !          3968:                                if (tmp < depref)
        !          3969:                                        depref = tmp;
        !          3970:                        }
        !          3971: 
        !          3972:                        if (!(addr->flags & DHC6_ADDR_EXPIRED)) {
        !          3973:                                /* Find EPOCH-relative expiration. */
        !          3974:                                if (addr->max_life == 0xffffffff)
        !          3975:                                        tmp = MAX_TIME;
        !          3976:                                else
        !          3977:                                        tmp = addr->starts + addr->max_life;
        !          3978: 
        !          3979:                                /* Make the times ia->starts relative. */
        !          3980:                                tmp -= ia->starts;
        !          3981: 
        !          3982:                                if (tmp > this_ia_hi_expire)
        !          3983:                                        this_ia_hi_expire = tmp;
        !          3984:                                if (tmp < this_ia_lo_expire)
        !          3985:                                        this_ia_lo_expire = tmp;
        !          3986: 
        !          3987:                                has_addrs = ISC_TRUE;
        !          3988:                        }
        !          3989:                }
        !          3990: 
        !          3991:                /* These times are ia->starts relative. */
        !          3992:                if (this_ia_lo_expire <= (this_ia_hi_expire / 2))
        !          3993:                        use_expire = this_ia_hi_expire;
        !          3994:                else
        !          3995:                        use_expire = this_ia_lo_expire;
        !          3996: 
        !          3997:                /*
        !          3998:                 * If the auto-selected expiration time is "infinite", or
        !          3999:                 * zero, assert a reasonable default.
        !          4000:                 */
        !          4001:                if ((use_expire == MAX_TIME) || (use_expire <= 1))
        !          4002:                        use_expire = client->config->requested_lease / 2;
        !          4003:                else
        !          4004:                        use_expire /= 2;
        !          4005: 
        !          4006:                /* Don't renew/rebind temporary addresses. */
        !          4007:                if (ia->ia_type != D6O_IA_TA) {
        !          4008: 
        !          4009:                        if (ia->renew == 0) {
        !          4010:                                tmp = ia->starts + use_expire;
        !          4011:                        } else if (ia->renew == 0xffffffff)
        !          4012:                                tmp = MAX_TIME;
        !          4013:                        else
        !          4014:                                tmp = ia->starts + ia->renew;
        !          4015: 
        !          4016:                        if (tmp < renew)
        !          4017:                                renew = tmp;
        !          4018: 
        !          4019:                        if (ia->rebind == 0) {
        !          4020:                                /* Set rebind to 3/4 expiration interval. */
        !          4021:                                tmp = ia->starts;
        !          4022:                                tmp += use_expire + (use_expire / 2);
        !          4023:                        } else if (ia->renew == 0xffffffff)
        !          4024:                                tmp = MAX_TIME;
        !          4025:                        else
        !          4026:                                tmp = ia->starts + ia->rebind;
        !          4027: 
        !          4028:                        if (tmp < rebind)
        !          4029:                                rebind = tmp;
        !          4030:                }
        !          4031: 
        !          4032:                /*
        !          4033:                 * Return expiration ranges to EPOCH relative for event
        !          4034:                 * scheduling (add_timeout()).
        !          4035:                 */
        !          4036:                this_ia_hi_expire += ia->starts;
        !          4037:                this_ia_lo_expire += ia->starts;
        !          4038: 
        !          4039:                if (this_ia_hi_expire > hi_expire)
        !          4040:                        hi_expire = this_ia_hi_expire;
        !          4041:                if (this_ia_lo_expire < lo_expire)
        !          4042:                        lo_expire = this_ia_lo_expire;
        !          4043:        }
        !          4044: 
        !          4045:        /* If there are no addresses, give up, go to INIT.
        !          4046:         * Note that if an address is unexpired with a date in the past,
        !          4047:         * we're scheduling an expiration event to ocurr in the past.  We
        !          4048:         * could probably optimize this to expire now (but then there's
        !          4049:         * recursion).
        !          4050:         *
        !          4051:         * In the future, we may decide that we're done here, or to
        !          4052:         * schedule a future request (using 4-pkt info-request model).
        !          4053:         */
        !          4054:        if (has_addrs == ISC_FALSE) {
        !          4055:                dhc6_lease_destroy(&client->active_lease, MDL);
        !          4056:                client->active_lease = NULL;
        !          4057: 
        !          4058:                /* Go back to the beginning. */
        !          4059:                start_init6(client);
        !          4060:                return;
        !          4061:        }
        !          4062: 
        !          4063:        switch(client->state) {
        !          4064:              case S_BOUND:
        !          4065:                /* We'd like to hit renewing, but if rebinding has already
        !          4066:                 * passed (time warp), head straight there.
        !          4067:                 */
        !          4068:                if ((rebind > cur_time) && (renew < rebind)) {
        !          4069:                        log_debug("PRC: Renewal event scheduled in %d seconds, "
        !          4070:                                  "to run for %u seconds.",
        !          4071:                                  (int)(renew - cur_time),
        !          4072:                                  (unsigned)(rebind - renew));
        !          4073:                        client->next_MRD = rebind;
        !          4074:                        tv.tv_sec = renew;
        !          4075:                        tv.tv_usec = 0;
        !          4076:                        add_timeout(&tv, start_renew6, client, NULL, NULL);
        !          4077: 
        !          4078:                        break;
        !          4079:                }
        !          4080:                /* FALL THROUGH */
        !          4081:              case S_RENEWING:
        !          4082:                /* While actively renewing, MRD is bounded by the time
        !          4083:                 * we stop renewing and start rebinding.  This helps us
        !          4084:                 * process the state change on time.
        !          4085:                 */
        !          4086:                client->MRD = rebind - cur_time;
        !          4087:                if (rebind != MAX_TIME) {
        !          4088:                        log_debug("PRC: Rebind event scheduled in %d seconds, "
        !          4089:                                  "to run for %d seconds.",
        !          4090:                                  (int)(rebind - cur_time),
        !          4091:                                  (int)(hi_expire - rebind));
        !          4092:                        client->next_MRD = hi_expire;
        !          4093:                        tv.tv_sec = rebind;
        !          4094:                        tv.tv_usec = 0;
        !          4095:                        add_timeout(&tv, start_rebind6, client, NULL, NULL);
        !          4096:                }
        !          4097:                break;
        !          4098: 
        !          4099:              case S_REBINDING:
        !          4100:                /* For now, we rebind up until the last lease expires.  In
        !          4101:                 * the future, we might want to start SOLICITing when we've
        !          4102:                 * depreffed an address.
        !          4103:                 */
        !          4104:                client->MRD = hi_expire - cur_time;
        !          4105:                break;
        !          4106: 
        !          4107:              default:
        !          4108:                log_fatal("Impossible condition at %s:%d.", MDL);
        !          4109:        }
        !          4110: 
        !          4111:        /* Separately, set a time at which we will depref and expire
        !          4112:         * leases.  This might happen with multiple addresses while we
        !          4113:         * keep trying to refresh.
        !          4114:         */
        !          4115:        if (depref != MAX_TIME) {
        !          4116:                log_debug("PRC: Depreference scheduled in %d seconds.",
        !          4117:                          (int)(depref - cur_time));
        !          4118:                tv.tv_sec = depref;
        !          4119:                tv.tv_usec = 0;
        !          4120:                add_timeout(&tv, do_depref, client, NULL, NULL);
        !          4121:        }
        !          4122:        if (lo_expire != MAX_TIME) {
        !          4123:                log_debug("PRC: Expiration scheduled in %d seconds.",
        !          4124:                          (int)(lo_expire - cur_time));
        !          4125:                tv.tv_sec = lo_expire;
        !          4126:                tv.tv_usec = 0;
        !          4127:                add_timeout(&tv, do_expire, client, NULL, NULL);
        !          4128:        }
        !          4129: }
        !          4130: 
        !          4131: /* In a given IA chain, find the IA with the same type and 'iaid'. */
        !          4132: static struct dhc6_ia *
        !          4133: find_ia(struct dhc6_ia *head, u_int16_t type, const char *id)
        !          4134: {
        !          4135:        struct dhc6_ia *ia;
        !          4136: 
        !          4137:        for (ia = head ; ia != NULL ; ia = ia->next) {
        !          4138:                if (ia->ia_type != type)
        !          4139:                        continue;
        !          4140:                if (memcmp(ia->iaid, id, 4) == 0)
        !          4141:                        return ia;
        !          4142:        }
        !          4143: 
        !          4144:        return NULL;
        !          4145: }
        !          4146: 
        !          4147: /* In a given address chain, find a matching address. */
        !          4148: static struct dhc6_addr *
        !          4149: find_addr(struct dhc6_addr *head, struct iaddr *address)
        !          4150: {
        !          4151:        struct dhc6_addr *addr;
        !          4152: 
        !          4153:        for (addr = head ; addr != NULL ; addr = addr->next) {
        !          4154:                if ((addr->address.len == address->len) &&
        !          4155:                    (memcmp(addr->address.iabuf, address->iabuf,
        !          4156:                            address->len) == 0))
        !          4157:                        return addr;
        !          4158:        }
        !          4159: 
        !          4160:        return NULL;
        !          4161: }
        !          4162: 
        !          4163: /* In a given prefix chain, find a matching prefix. */
        !          4164: static struct dhc6_addr *
        !          4165: find_pref(struct dhc6_addr *head, struct iaddr *prefix, u_int8_t plen)
        !          4166: {
        !          4167:        struct dhc6_addr *pref;
        !          4168: 
        !          4169:        for (pref = head ; pref != NULL ; pref = pref->next) {
        !          4170:                if ((pref->address.len == prefix->len) &&
        !          4171:                    (pref->plen == plen) &&
        !          4172:                    (memcmp(pref->address.iabuf, prefix->iabuf,
        !          4173:                            prefix->len) == 0))
        !          4174:                        return pref;
        !          4175:        }
        !          4176: 
        !          4177:        return NULL;
        !          4178: }
        !          4179: 
        !          4180: /* Merge the bindings from the source lease into the destination lease
        !          4181:  * structure, where they are missing.  We have to copy the stateful
        !          4182:  * objects rather than move them over, because later code needs to be
        !          4183:  * able to compare new versus old if they contain any bindings.
        !          4184:  */
        !          4185: static void
        !          4186: dhc6_merge_lease(struct dhc6_lease *src, struct dhc6_lease *dst)
        !          4187: {
        !          4188:        struct dhc6_ia *sia, *dia, *tia;
        !          4189:        struct dhc6_addr *saddr, *daddr, *taddr;
        !          4190:        int changes = 0;
        !          4191: 
        !          4192:        if ((dst == NULL) || (src == NULL))
        !          4193:                return;
        !          4194: 
        !          4195:        for (sia = src->bindings ; sia != NULL ; sia = sia->next) {
        !          4196:                dia = find_ia(dst->bindings, sia->ia_type, (char *)sia->iaid);
        !          4197: 
        !          4198:                if (dia == NULL) {
        !          4199:                        tia = dhc6_dup_ia(sia, MDL);
        !          4200: 
        !          4201:                        if (tia == NULL)
        !          4202:                                log_fatal("Out of memory merging lease - "
        !          4203:                                          "Unable to continue without losing "
        !          4204:                                          "state! (%s:%d)", MDL);
        !          4205: 
        !          4206:                        /* XXX: consider sorting? */
        !          4207:                        tia->next = dst->bindings;
        !          4208:                        dst->bindings = tia;
        !          4209:                        changes = 1;
        !          4210:                } else {
        !          4211:                        for (saddr = sia->addrs ; saddr != NULL ;
        !          4212:                             saddr = saddr->next) {
        !          4213:                                if (sia->ia_type != D6O_IA_PD)
        !          4214:                                        daddr = find_addr(dia->addrs,
        !          4215:                                                          &saddr->address);
        !          4216:                                else
        !          4217:                                        daddr = find_pref(dia->addrs,
        !          4218:                                                          &saddr->address,
        !          4219:                                                          saddr->plen);
        !          4220: 
        !          4221:                                if (daddr == NULL) {
        !          4222:                                        taddr = dhc6_dup_addr(saddr, MDL);
        !          4223: 
        !          4224:                                        if (taddr == NULL)
        !          4225:                                                log_fatal("Out of memory "
        !          4226:                                                          "merging lease - "
        !          4227:                                                          "Unable to continue "
        !          4228:                                                          "without losing "
        !          4229:                                                          "state! (%s:%d)",
        !          4230:                                                          MDL);
        !          4231: 
        !          4232:                                        /* XXX: consider sorting? */
        !          4233:                                        taddr->next = dia->addrs;
        !          4234:                                        dia->addrs = taddr;
        !          4235:                                        changes = 1;
        !          4236:                                }
        !          4237:                        }
        !          4238:                }
        !          4239:        }
        !          4240: 
        !          4241:        /* If we made changes, reset the score to 0 so it is recalculated. */
        !          4242:        if (changes)
        !          4243:                dst->score = 0;
        !          4244: }
        !          4245: 
        !          4246: /* We've either finished selecting or succeeded in Renew or Rebinding our
        !          4247:  * lease.  In all cases we got a Reply.  Give dhclient-script a tickle
        !          4248:  * to inform it about the new values, and then lay in wait for the next
        !          4249:  * event.
        !          4250:  */
        !          4251: static void
        !          4252: start_bound(struct client_state *client)
        !          4253: {
        !          4254:        struct dhc6_ia *ia, *oldia;
        !          4255:        struct dhc6_addr *addr, *oldaddr;
        !          4256:        struct dhc6_lease *lease, *old;
        !          4257:        const char *reason;
        !          4258:        TIME dns_update_offset = 1;
        !          4259: 
        !          4260:        lease = client->active_lease;
        !          4261:        if (lease == NULL) {
        !          4262:                log_error("Cannot enter bound state unless an active lease "
        !          4263:                          "is selected.");
        !          4264:                return;
        !          4265:        }
        !          4266:        lease->released = ISC_FALSE;
        !          4267:        old = client->old_lease;
        !          4268: 
        !          4269:        client->v6_handler = bound_handler;
        !          4270: 
        !          4271:        switch (client->state) {
        !          4272:              case S_SELECTING:
        !          4273:              case S_REBOOTING: /* Pretend we got bound. */
        !          4274:                reason = "BOUND6";
        !          4275:                break;
        !          4276: 
        !          4277:              case S_RENEWING:
        !          4278:                reason = "RENEW6";
        !          4279:                break;
        !          4280: 
        !          4281:              case S_REBINDING:
        !          4282:                reason = "REBIND6";
        !          4283:                break;
        !          4284: 
        !          4285:              default:
        !          4286:                log_fatal("Impossible condition at %s:%d.", MDL);
        !          4287:                /* Silence compiler warnings. */
        !          4288:                return;
        !          4289:        }
        !          4290: 
        !          4291:        log_debug("PRC: Bound to lease %s.",
        !          4292:                  print_hex_1(client->active_lease->server_id.len,
        !          4293:                              client->active_lease->server_id.data, 55));
        !          4294:        client->state = S_BOUND;
        !          4295: 
        !          4296:        write_client6_lease(client, lease, 0, 1);
        !          4297: 
        !          4298:        oldia = NULL;
        !          4299:        for (ia = lease->bindings ; ia != NULL ; ia = ia->next) {
        !          4300:                if (old != NULL)
        !          4301:                        oldia = find_ia(old->bindings,
        !          4302:                                        ia->ia_type,
        !          4303:                                        (char *)ia->iaid);
        !          4304:                else
        !          4305:                        oldia = NULL;
        !          4306: 
        !          4307:                for (addr = ia->addrs ; addr != NULL ; addr = addr->next) {
        !          4308:                        if (oldia != NULL) {
        !          4309:                                if (ia->ia_type != D6O_IA_PD)
        !          4310:                                        oldaddr = find_addr(oldia->addrs,
        !          4311:                                                            &addr->address);
        !          4312:                                else
        !          4313:                                        oldaddr = find_pref(oldia->addrs,
        !          4314:                                                            &addr->address,
        !          4315:                                                            addr->plen);
        !          4316:                        } else
        !          4317:                                oldaddr = NULL;
        !          4318: 
        !          4319:                        if ((oldaddr == NULL) && (ia->ia_type == D6O_IA_NA))
        !          4320:                                dhclient_schedule_updates(client,
        !          4321:                                                          &addr->address,
        !          4322:                                                          dns_update_offset++);
        !          4323: 
        !          4324:                        /* Shell out to setup the new binding. */
        !          4325:                        script_init(client, reason, NULL);
        !          4326: 
        !          4327:                        if (old != NULL)
        !          4328:                                dhc6_marshall_values("old_", client, old,
        !          4329:                                                     oldia, oldaddr);
        !          4330:                        dhc6_marshall_values("new_", client, lease, ia, addr);
        !          4331: 
        !          4332:                        script_go(client);
        !          4333:                }
        !          4334: 
        !          4335:                /* XXX: maybe we should loop on the old values instead? */
        !          4336:                if (ia->addrs == NULL) {
        !          4337:                        script_init(client, reason, NULL);
        !          4338: 
        !          4339:                        if (old != NULL)
        !          4340:                                dhc6_marshall_values("old_", client, old,
        !          4341:                                                     oldia,
        !          4342:                                                     oldia != NULL ?
        !          4343:                                                         oldia->addrs : NULL);
        !          4344: 
        !          4345:                        dhc6_marshall_values("new_", client, lease, ia,
        !          4346:                                             NULL);
        !          4347: 
        !          4348:                        script_go(client);
        !          4349:                }
        !          4350:        }
        !          4351: 
        !          4352:        /* XXX: maybe we should loop on the old values instead? */
        !          4353:        if (lease->bindings == NULL) {
        !          4354:                script_init(client, reason, NULL);
        !          4355: 
        !          4356:                if (old != NULL)
        !          4357:                        dhc6_marshall_values("old_", client, old,
        !          4358:                                             old->bindings,
        !          4359:                                             (old->bindings != NULL) ?
        !          4360:                                                old->bindings->addrs : NULL);
        !          4361: 
        !          4362:                dhc6_marshall_values("new_", client, lease, NULL, NULL);
        !          4363: 
        !          4364:                script_go(client);
        !          4365:        }
        !          4366: 
        !          4367:        go_daemon();
        !          4368: 
        !          4369:        if (client->old_lease != NULL) {
        !          4370:                dhc6_lease_destroy(&client->old_lease, MDL);
        !          4371:                client->old_lease = NULL;
        !          4372:        }
        !          4373: 
        !          4374:        /* Schedule events. */
        !          4375:        dhc6_check_times(client);
        !          4376: }
        !          4377: 
        !          4378: /* While bound, ignore packets.  In the future we'll want to answer
        !          4379:  * Reconfigure-Request messages and the like.
        !          4380:  */
        !          4381: void
        !          4382: bound_handler(struct packet *packet, struct client_state *client)
        !          4383: {
        !          4384:        log_debug("RCV: Input packets are ignored once bound.");
        !          4385: }
        !          4386: 
        !          4387: /* start_renew6() gets us all ready to go to start transmitting Renew packets.
        !          4388:  * Note that client->next_MRD must be set before entering this function -
        !          4389:  * it must be set to the time at which the client should start Rebinding.
        !          4390:  */
        !          4391: void
        !          4392: start_renew6(void *input)
        !          4393: {
        !          4394:        struct client_state *client;
        !          4395: 
        !          4396:        client = (struct client_state *)input;
        !          4397: 
        !          4398:        log_info("PRC: Renewing lease on %s.",
        !          4399:                 client->name ? client->name : client->interface->name);
        !          4400:        client->state = S_RENEWING;
        !          4401: 
        !          4402:        client->v6_handler = reply_handler;
        !          4403: 
        !          4404:        /* Times per RFC3315 section 18.1.3. */
        !          4405:        client->IRT = REN_TIMEOUT * 100;
        !          4406:        client->MRT = REN_MAX_RT * 100;
        !          4407:        client->MRC = 0;
        !          4408:        /* MRD is special in renew - we need to set it by checking timer
        !          4409:         * state.
        !          4410:         */
        !          4411:        client->MRD = client->next_MRD - cur_time;
        !          4412: 
        !          4413:        dhc6_retrans_init(client);
        !          4414: 
        !          4415:        client->refresh_type = DHCPV6_RENEW;
        !          4416:        do_refresh6(client);
        !          4417: }
        !          4418: 
        !          4419: /* do_refresh6() transmits one DHCPv6 packet, be it a Renew or Rebind, and
        !          4420:  * gives the retransmission state a bump for the next time.  Note that
        !          4421:  * client->refresh_type must be set before entering this function.
        !          4422:  */
        !          4423: void
        !          4424: do_refresh6(void *input)
        !          4425: {
        !          4426:        struct option_cache *oc;
        !          4427:        struct sockaddr_in6 unicast, *dest_addr = &DHCPv6DestAddr;
        !          4428:        struct data_string ds;
        !          4429:        struct client_state *client;
        !          4430:        struct dhc6_lease *lease;
        !          4431:        struct timeval elapsed, tv;
        !          4432:        int send_ret;
        !          4433: 
        !          4434:        client = (struct client_state *)input;
        !          4435:        memset(&ds, 0, sizeof(ds));
        !          4436: 
        !          4437:        lease = client->active_lease;
        !          4438:        if (lease == NULL) {
        !          4439:                log_error("Cannot renew without an active binding.");
        !          4440:                return;
        !          4441:        }
        !          4442: 
        !          4443:        /* Ensure we're emitting a valid message type. */
        !          4444:        switch (client->refresh_type) {
        !          4445:              case DHCPV6_RENEW:
        !          4446:              case DHCPV6_REBIND:
        !          4447:                break;
        !          4448: 
        !          4449:              default:
        !          4450:                log_fatal("Internal inconsistency (%d) at %s:%d.",
        !          4451:                          client->refresh_type, MDL);
        !          4452:        }
        !          4453: 
        !          4454:        /*
        !          4455:         * Start_time starts at the first transmission.
        !          4456:         */
        !          4457:        if (client->txcount == 0) {
        !          4458:                client->start_time.tv_sec = cur_tv.tv_sec;
        !          4459:                client->start_time.tv_usec = cur_tv.tv_usec;
        !          4460:        }
        !          4461: 
        !          4462:        /* elapsed = cur - start */
        !          4463:        elapsed.tv_sec = cur_tv.tv_sec - client->start_time.tv_sec;
        !          4464:        elapsed.tv_usec = cur_tv.tv_usec - client->start_time.tv_usec;
        !          4465:        if (elapsed.tv_usec < 0) {
        !          4466:                elapsed.tv_sec -= 1;
        !          4467:                elapsed.tv_usec += 1000000;
        !          4468:        }
        !          4469:        if (((client->MRC != 0) && (client->txcount > client->MRC)) ||
        !          4470:            ((client->MRD != 0) && (elapsed.tv_sec >= client->MRD))) {
        !          4471:                /* We're done.  Move on to the next phase, if any. */
        !          4472:                dhc6_check_times(client);
        !          4473:                return;
        !          4474:        }
        !          4475: 
        !          4476:        /*
        !          4477:         * Check whether the server has sent a unicast option; if so, we can
        !          4478:         * use the address it specified for RENEWs.
        !          4479:         */
        !          4480:        oc = lookup_option(&dhcpv6_universe, lease->options, D6O_UNICAST);
        !          4481:        if (oc && evaluate_option_cache(&ds, NULL, NULL, NULL,
        !          4482:                                        lease->options, NULL, &global_scope,
        !          4483:                                        oc, MDL)) {
        !          4484:                if (ds.len < 16) {
        !          4485:                        log_error("Invalid unicast option length %d.", ds.len);
        !          4486:                } else {
        !          4487:                        memset(&unicast, 0, sizeof(DHCPv6DestAddr));
        !          4488:                        unicast.sin6_family = AF_INET6;
        !          4489:                        unicast.sin6_port = remote_port;
        !          4490:                        memcpy(&unicast.sin6_addr, ds.data, 16);
        !          4491:                        if (client->refresh_type == DHCPV6_RENEW) {
        !          4492:                                dest_addr = &unicast;
        !          4493:                        }
        !          4494:                }
        !          4495: 
        !          4496:                data_string_forget(&ds, MDL);
        !          4497:        }
        !          4498: 
        !          4499:        /* Commence forming a renew packet. */
        !          4500:        memset(&ds, 0, sizeof(ds));
        !          4501:        if (!buffer_allocate(&ds.buffer, 4, MDL)) {
        !          4502:                log_error("Unable to allocate memory for packet.");
        !          4503:                return;
        !          4504:        }
        !          4505:        ds.data = ds.buffer->data;
        !          4506:        ds.len = 4;
        !          4507: 
        !          4508:        ds.buffer->data[0] = client->refresh_type;
        !          4509:        memcpy(ds.buffer->data + 1, client->dhcpv6_transaction_id, 3);
        !          4510: 
        !          4511:        /* Form an elapsed option. */
        !          4512:        /* Maximum value is 65535 1/100s coded as 0xffff. */
        !          4513:        if ((elapsed.tv_sec < 0) || (elapsed.tv_sec > 655) ||
        !          4514:            ((elapsed.tv_sec == 655) && (elapsed.tv_usec > 350000))) {
        !          4515:                client->elapsed = 0xffff;
        !          4516:        } else {
        !          4517:                client->elapsed = elapsed.tv_sec * 100;
        !          4518:                client->elapsed += elapsed.tv_usec / 10000;
        !          4519:        }
        !          4520: 
        !          4521:        if (client->elapsed == 0)
        !          4522:                log_debug("XMT: Forming %s, 0 ms elapsed.",
        !          4523:                          dhcpv6_type_names[client->refresh_type]);
        !          4524:        else
        !          4525:                log_debug("XMT: Forming %s, %u0 ms elapsed.",
        !          4526:                          dhcpv6_type_names[client->refresh_type],
        !          4527:                          (unsigned)client->elapsed);
        !          4528: 
        !          4529:        client->elapsed = htons(client->elapsed);
        !          4530: 
        !          4531:        make_client6_options(client, &client->sent_options, lease,
        !          4532:                             client->refresh_type);
        !          4533: 
        !          4534:        /* Put in any options from the sent cache. */
        !          4535:        dhcpv6_universe.encapsulate(&ds, NULL, NULL, client, NULL,
        !          4536:                                    client->sent_options, &global_scope,
        !          4537:                                    &dhcpv6_universe);
        !          4538: 
        !          4539:        /* Append IA's */
        !          4540:        if (wanted_ia_na &&
        !          4541:            dhc6_add_ia_na(client, &ds, lease,
        !          4542:                           client->refresh_type) != ISC_R_SUCCESS) {
        !          4543:                data_string_forget(&ds, MDL);
        !          4544:                return;
        !          4545:        }
        !          4546:        if (wanted_ia_pd &&
        !          4547:            dhc6_add_ia_pd(client, &ds, lease,
        !          4548:                           client->refresh_type) != ISC_R_SUCCESS) {
        !          4549:                data_string_forget(&ds, MDL);
        !          4550:                return;
        !          4551:        }
        !          4552: 
        !          4553:        log_info("XMT: %s on %s, interval %ld0ms.",
        !          4554:                 dhcpv6_type_names[client->refresh_type],
        !          4555:                 client->name ? client->name : client->interface->name,
        !          4556:                 (long int)client->RT);
        !          4557: 
        !          4558:        send_ret = send_packet6(client->interface, ds.data, ds.len, dest_addr);
        !          4559: 
        !          4560:        if (send_ret != ds.len) {
        !          4561:                log_error("dhc6: send_packet6() sent %d of %d bytes",
        !          4562:                          send_ret, ds.len);
        !          4563:        }
        !          4564: 
        !          4565:        data_string_forget(&ds, MDL);
        !          4566: 
        !          4567:        /* Wait RT */
        !          4568:        tv.tv_sec = cur_tv.tv_sec + client->RT / 100;
        !          4569:        tv.tv_usec = cur_tv.tv_usec + (client->RT % 100) * 10000;
        !          4570:        if (tv.tv_usec >= 1000000) {
        !          4571:                tv.tv_sec += 1;
        !          4572:                tv.tv_usec -= 1000000;
        !          4573:        }
        !          4574:        add_timeout(&tv, do_refresh6, client, NULL, NULL);
        !          4575: 
        !          4576:        dhc6_retrans_advance(client);
        !          4577: }
        !          4578: 
        !          4579: /* start_rebind6() gets us all set up to go and rebind a lease.  Note that
        !          4580:  * client->next_MRD must be set before entering this function.  In this case,
        !          4581:  * MRD must be set to the maximum time any address in the packet will
        !          4582:  * expire.
        !          4583:  */
        !          4584: void
        !          4585: start_rebind6(void *input)
        !          4586: {
        !          4587:        struct client_state *client;
        !          4588: 
        !          4589:        client = (struct client_state *)input;
        !          4590: 
        !          4591:        log_info("PRC: Rebinding lease on %s.",
        !          4592:                 client->name ? client->name : client->interface->name);
        !          4593:        client->state = S_REBINDING;
        !          4594: 
        !          4595:        client->v6_handler = reply_handler;
        !          4596: 
        !          4597:        /* Times per RFC3315 section 18.1.4. */
        !          4598:        client->IRT = REB_TIMEOUT * 100;
        !          4599:        client->MRT = REB_MAX_RT * 100;
        !          4600:        client->MRC = 0;
        !          4601:        /* MRD is special in rebind - it's determined by the timer
        !          4602:         * state.
        !          4603:         */
        !          4604:        client->MRD = client->next_MRD - cur_time;
        !          4605: 
        !          4606:        dhc6_retrans_init(client);
        !          4607: 
        !          4608:        client->refresh_type = DHCPV6_REBIND;
        !          4609:        do_refresh6(client);
        !          4610: }
        !          4611: 
        !          4612: /* do_depref() runs through a given lease's addresses, for each that has
        !          4613:  * not yet been depreffed, shells out to the dhclient-script to inform it
        !          4614:  * of the status change.  The dhclient-script should then do...something...
        !          4615:  * to encourage applications to move off the address and onto one of the
        !          4616:  * remaining 'preferred' addresses.
        !          4617:  */
        !          4618: void
        !          4619: do_depref(void *input)
        !          4620: {
        !          4621:        struct client_state *client;
        !          4622:        struct dhc6_lease *lease;
        !          4623:        struct dhc6_ia *ia;
        !          4624:        struct dhc6_addr *addr;
        !          4625: 
        !          4626:        client = (struct client_state *)input;
        !          4627: 
        !          4628:        lease = client->active_lease;
        !          4629:        if (lease == NULL)
        !          4630:                return;
        !          4631: 
        !          4632:        for (ia = lease->bindings ; ia != NULL ; ia = ia->next) {
        !          4633:                for (addr = ia->addrs ; addr != NULL ; addr = addr->next) {
        !          4634:                        if (addr->flags & DHC6_ADDR_DEPREFFED)
        !          4635:                                continue;
        !          4636: 
        !          4637:                        if (addr->starts + addr->preferred_life <= cur_time) {
        !          4638:                                script_init(client, "DEPREF6", NULL);
        !          4639:                                dhc6_marshall_values("cur_", client, lease,
        !          4640:                                                     ia, addr);
        !          4641:                                script_go(client);
        !          4642: 
        !          4643:                                addr->flags |= DHC6_ADDR_DEPREFFED;
        !          4644: 
        !          4645:                                if (ia->ia_type != D6O_IA_PD)
        !          4646:                                    log_info("PRC: Address %s depreferred.",
        !          4647:                                             piaddr(addr->address));
        !          4648:                                else
        !          4649:                                    log_info("PRC: Prefix %s/%u depreferred.",
        !          4650:                                             piaddr(addr->address),
        !          4651:                                             (unsigned) addr->plen);
        !          4652: 
        !          4653:                                /* Remove DDNS bindings at depref time. */
        !          4654:                                if ((ia->ia_type == D6O_IA_NA) &&
        !          4655:                                    client->config->do_forward_update)
        !          4656:                                        client_dns_update(client, 0, 0,
        !          4657:                                                          &addr->address);
        !          4658:                        }
        !          4659:                }
        !          4660:        }
        !          4661: 
        !          4662:        dhc6_check_times(client);
        !          4663: }
        !          4664: 
        !          4665: /* do_expire() searches through all the addresses on a given lease, and
        !          4666:  * expires/removes any addresses that are no longer valid.
        !          4667:  */
        !          4668: void
        !          4669: do_expire(void *input)
        !          4670: {
        !          4671:        struct client_state *client;
        !          4672:        struct dhc6_lease *lease;
        !          4673:        struct dhc6_ia *ia;
        !          4674:        struct dhc6_addr *addr;
        !          4675:        int has_addrs = ISC_FALSE;
        !          4676: 
        !          4677:        client = (struct client_state *)input;
        !          4678: 
        !          4679:        lease = client->active_lease;
        !          4680:        if (lease == NULL)
        !          4681:                return;
        !          4682: 
        !          4683:        for (ia = lease->bindings ; ia != NULL ; ia = ia->next) {
        !          4684:                for (addr = ia->addrs ; addr != NULL ; addr = addr->next) {
        !          4685:                        if (addr->flags & DHC6_ADDR_EXPIRED)
        !          4686:                                continue;
        !          4687: 
        !          4688:                        if (addr->starts + addr->max_life <= cur_time) {
        !          4689:                                script_init(client, "EXPIRE6", NULL);
        !          4690:                                dhc6_marshall_values("old_", client, lease,
        !          4691:                                                     ia, addr);
        !          4692:                                script_go(client);
        !          4693: 
        !          4694:                                addr->flags |= DHC6_ADDR_EXPIRED;
        !          4695: 
        !          4696:                                if (ia->ia_type != D6O_IA_PD)
        !          4697:                                    log_info("PRC: Address %s expired.",
        !          4698:                                             piaddr(addr->address));
        !          4699:                                else
        !          4700:                                    log_info("PRC: Prefix %s/%u expired.",
        !          4701:                                             piaddr(addr->address),
        !          4702:                                             (unsigned) addr->plen);
        !          4703: 
        !          4704:                                /* We remove DNS records at depref time, but
        !          4705:                                 * it is possible that we might get here
        !          4706:                                 * without depreffing.
        !          4707:                                 */
        !          4708:                                if ((ia->ia_type == D6O_IA_NA) &&
        !          4709:                                    client->config->do_forward_update &&
        !          4710:                                    !(addr->flags & DHC6_ADDR_DEPREFFED))
        !          4711:                                        client_dns_update(client, 0, 0,
        !          4712:                                                          &addr->address);
        !          4713: 
        !          4714:                                continue;
        !          4715:                        }
        !          4716: 
        !          4717:                        has_addrs = ISC_TRUE;
        !          4718:                }
        !          4719:        }
        !          4720: 
        !          4721:        /* Clean up empty leases. */
        !          4722:        if (has_addrs == ISC_FALSE) {
        !          4723:                log_info("PRC: Bound lease is devoid of active addresses."
        !          4724:                         "  Re-initializing.");
        !          4725: 
        !          4726:                dhc6_lease_destroy(&lease, MDL);
        !          4727:                client->active_lease = NULL;
        !          4728: 
        !          4729:                start_init6(client);
        !          4730:                return;
        !          4731:        }
        !          4732: 
        !          4733:        /* Schedule the next run through. */
        !          4734:        dhc6_check_times(client);
        !          4735: }
        !          4736: 
        !          4737: /*
        !          4738:  * Run client script to unconfigure interface.
        !          4739:  * Called with reason STOP6 when dhclient -x is run, or with reason
        !          4740:  * RELEASE6 when server has replied to a Release message.
        !          4741:  * Stateless is a special case.
        !          4742:  */
        !          4743: void
        !          4744: unconfigure6(struct client_state *client, const char *reason)
        !          4745: {
        !          4746:        struct dhc6_ia *ia;
        !          4747:        struct dhc6_addr *addr;
        !          4748: 
        !          4749:        if (stateless) {
        !          4750:                script_init(client, reason, NULL);
        !          4751:                if (client->active_lease != NULL)
        !          4752:                        script_write_params6(client, "old_",
        !          4753:                                             client->active_lease->options);
        !          4754:                script_go(client);
        !          4755:                return;
        !          4756:        }
        !          4757: 
        !          4758:        if (client->active_lease == NULL)
        !          4759:                return;
        !          4760: 
        !          4761:        for (ia = client->active_lease->bindings ; ia != NULL ; ia = ia->next) {
        !          4762:                if (ia->ia_type == D6O_IA_TA)
        !          4763:                        continue;
        !          4764: 
        !          4765:                for (addr = ia->addrs ; addr != NULL ; addr = addr->next) {
        !          4766:                        script_init(client, reason, NULL);
        !          4767:                        dhc6_marshall_values("old_", client,
        !          4768:                                             client->active_lease, ia, addr);
        !          4769:                        script_go(client);
        !          4770: 
        !          4771:                        if ((ia->ia_type == D6O_IA_NA) &&
        !          4772:                            client->config->do_forward_update)
        !          4773:                                client_dns_update(client, 0, 0, &addr->address);
        !          4774:                }
        !          4775:        }
        !          4776: }
        !          4777: 
        !          4778: void
        !          4779: refresh_info_request6(void *input)
        !          4780: {
        !          4781:        struct client_state *client;
        !          4782: 
        !          4783:        client = (struct client_state *)input;
        !          4784:        start_info_request6(client);
        !          4785: }
        !          4786: 
        !          4787: /* Timeout for Information-Request (using the IRT option).
        !          4788:  */
        !          4789: static void
        !          4790: dhc6_check_irt(struct client_state *client)
        !          4791: {
        !          4792:        struct option **req;
        !          4793:        struct option_cache *oc;
        !          4794:        TIME expire = MAX_TIME;
        !          4795:        struct timeval tv;
        !          4796:        int i;
        !          4797:        isc_boolean_t found = ISC_FALSE;
        !          4798: 
        !          4799:        cancel_timeout(refresh_info_request6, client);
        !          4800: 
        !          4801:        req = client->config->requested_options;
        !          4802:        for (i = 0; req[i] != NULL; i++) {
        !          4803:                if (req[i] == irt_option) {
        !          4804:                        found = ISC_TRUE;
        !          4805:                        break;
        !          4806:                }
        !          4807:        }
        !          4808:        /* Simply return gives a endless loop waiting for nothing. */
        !          4809:        if (!found)
        !          4810:                exit(0);
        !          4811: 
        !          4812:        oc = lookup_option(&dhcpv6_universe, client->active_lease->options,
        !          4813:                           D6O_INFORMATION_REFRESH_TIME);
        !          4814:        if (oc != NULL) {
        !          4815:                struct data_string irt;
        !          4816: 
        !          4817:                memset(&irt, 0, sizeof(irt));
        !          4818:                if (!evaluate_option_cache(&irt, NULL, NULL, client,
        !          4819:                                           client->active_lease->options,
        !          4820:                                           NULL, &global_scope, oc, MDL) ||
        !          4821:                    (irt.len < 4)) {
        !          4822:                        log_error("Can't evaluate IRT.");
        !          4823:                } else {
        !          4824:                        expire = getULong(irt.data);
        !          4825:                        if (expire < IRT_MINIMUM)
        !          4826:                                expire = IRT_MINIMUM;
        !          4827:                        if (expire == 0xffffffff)
        !          4828:                                expire = MAX_TIME;
        !          4829:                }
        !          4830:                data_string_forget(&irt, MDL);
        !          4831:        } else
        !          4832:                expire = IRT_DEFAULT;
        !          4833: 
        !          4834:        if (expire != MAX_TIME) {
        !          4835:                log_debug("PRC: Refresh event scheduled in %u seconds.",
        !          4836:                          (unsigned) expire);
        !          4837:                tv.tv_sec = cur_time + expire;
        !          4838:                tv.tv_usec = 0;
        !          4839:                add_timeout(&tv, refresh_info_request6, client, NULL, NULL);
        !          4840:        }
        !          4841: }
        !          4842: 
        !          4843: /* We got a Reply. Give dhclient-script a tickle to inform it about
        !          4844:  * the new values, and then lay in wait for the next event.
        !          4845:  */
        !          4846: static void
        !          4847: start_informed(struct client_state *client)
        !          4848: {
        !          4849:        client->v6_handler = informed_handler;
        !          4850: 
        !          4851:        log_debug("PRC: Done.");
        !          4852: 
        !          4853:        client->state = S_BOUND;
        !          4854: 
        !          4855:        script_init(client, "RENEW6", NULL);
        !          4856:        if (client->old_lease != NULL)
        !          4857:                script_write_params6(client, "old_",
        !          4858:                                     client->old_lease->options);
        !          4859:        script_write_params6(client, "new_", client->active_lease->options);
        !          4860:        script_go(client);
        !          4861: 
        !          4862:        go_daemon();
        !          4863: 
        !          4864:        if (client->old_lease != NULL) {
        !          4865:                dhc6_lease_destroy(&client->old_lease, MDL);
        !          4866:                client->old_lease = NULL;
        !          4867:        }
        !          4868: 
        !          4869:        /* Schedule events. */
        !          4870:        dhc6_check_irt(client);
        !          4871: }
        !          4872: 
        !          4873: /* While informed, ignore packets.
        !          4874:  */
        !          4875: void
        !          4876: informed_handler(struct packet *packet, struct client_state *client)
        !          4877: {
        !          4878:        log_debug("RCV: Input packets are ignored once bound.");
        !          4879: }
        !          4880: 
        !          4881: /* make_client6_options() fetches option caches relevant to the client's
        !          4882:  * scope and places them into the sent_options cache.  This cache is later
        !          4883:  * used to populate DHCPv6 output packets with options.
        !          4884:  */
        !          4885: static void
        !          4886: make_client6_options(struct client_state *client, struct option_state **op,
        !          4887:                     struct dhc6_lease *lease, u_int8_t message)
        !          4888: {
        !          4889:        struct option_cache *oc;
        !          4890:        struct option **req;
        !          4891:        struct buffer *buffer;
        !          4892:        int buflen, i, oro_len;
        !          4893: 
        !          4894:        if ((op == NULL) || (client == NULL))
        !          4895:                return;
        !          4896: 
        !          4897:        if (*op)
        !          4898:                option_state_dereference(op, MDL);
        !          4899: 
        !          4900:        /* Create a cache to carry options to transmission. */
        !          4901:        option_state_allocate(op, MDL);
        !          4902: 
        !          4903:        /* Create and store an 'elapsed time' option in the cache. */
        !          4904:        oc = NULL;
        !          4905:        if (option_cache_allocate(&oc, MDL)) {
        !          4906:                const unsigned char *cdata;
        !          4907: 
        !          4908:                cdata = (unsigned char *)&client->elapsed;
        !          4909: 
        !          4910:                if (make_const_data(&oc->expression, cdata, 2, 0, 0, MDL)) {
        !          4911:                        option_reference(&oc->option, elapsed_option, MDL);
        !          4912:                        save_option(&dhcpv6_universe, *op, oc);
        !          4913:                }
        !          4914: 
        !          4915:                option_cache_dereference(&oc, MDL);
        !          4916:        }
        !          4917: 
        !          4918:        /* Bring in any configured options to send. */
        !          4919:        if (client->config->on_transmission)
        !          4920:                execute_statements_in_scope(NULL, NULL, NULL, client,
        !          4921:                                            lease ? lease->options : NULL,
        !          4922:                                            *op, &global_scope,
        !          4923:                                            client->config->on_transmission,
        !          4924:                                            NULL);
        !          4925: 
        !          4926:        /* Rapid-commit is only for SOLICITs. */
        !          4927:        if (message != DHCPV6_SOLICIT)
        !          4928:                delete_option(&dhcpv6_universe, *op, D6O_RAPID_COMMIT);
        !          4929: 
        !          4930:        /* See if the user configured a DUID in a relevant scope.  If not,
        !          4931:         * introduce our default manufactured id.
        !          4932:         */
        !          4933:        if ((oc = lookup_option(&dhcpv6_universe, *op,
        !          4934:                                D6O_CLIENTID)) == NULL) {
        !          4935:                if (!option_cache(&oc, &default_duid, NULL, clientid_option,
        !          4936:                                  MDL))
        !          4937:                        log_fatal("Failure assembling a DUID.");
        !          4938: 
        !          4939:                save_option(&dhcpv6_universe, *op, oc);
        !          4940:                option_cache_dereference(&oc, MDL);
        !          4941:        }
        !          4942: 
        !          4943:        /* In cases where we're responding to a single server, put the
        !          4944:         * server's id in the response.
        !          4945:         *
        !          4946:         * Note that lease is NULL for SOLICIT or INFO request messages,
        !          4947:         * and otherwise MUST be present.
        !          4948:         */
        !          4949:        if (lease == NULL) {
        !          4950:                if ((message != DHCPV6_SOLICIT) &&
        !          4951:                    (message != DHCPV6_INFORMATION_REQUEST))
        !          4952:                        log_fatal("Impossible condition at %s:%d.", MDL);
        !          4953:        } else if ((message != DHCPV6_REBIND) &&
        !          4954:                   (message != DHCPV6_CONFIRM)) {
        !          4955:                oc = lookup_option(&dhcpv6_universe, lease->options,
        !          4956:                                   D6O_SERVERID);
        !          4957:                if (oc != NULL)
        !          4958:                        save_option(&dhcpv6_universe, *op, oc);
        !          4959:        }
        !          4960: 
        !          4961:        /* 'send dhcp6.oro foo;' syntax we used in 4.0.0a1/a2 has been
        !          4962:         * deprecated by adjustments to the 'request' syntax also used for
        !          4963:         * DHCPv4.
        !          4964:         */
        !          4965:        if (lookup_option(&dhcpv6_universe, *op, D6O_ORO) != NULL)
        !          4966:                log_error("'send dhcp6.oro' syntax is deprecated, please "
        !          4967:                          "use the 'request' syntax (\"man dhclient.conf\").");
        !          4968: 
        !          4969:        /* Construct and store an ORO (Option Request Option).  It is a
        !          4970:         * fatal error to fail to send an ORO (of at least zero length).
        !          4971:         *
        !          4972:         * Discussion:  RFC3315 appears to be inconsistent in its statements
        !          4973:         * of whether or not the ORO is mandatory.  In section 18.1.1
        !          4974:         * ("Creation and Transmission of Request Messages"):
        !          4975:         *
        !          4976:         *    The client MUST include an Option Request option (see section
        !          4977:         *    22.7) to indicate the options the client is interested in
        !          4978:         *    receiving.  The client MAY include options with data values as
        !          4979:         *    hints to the server about parameter values the client would like
        !          4980:         *    to have returned.
        !          4981:         *
        !          4982:         * This MUST is missing from the creation/transmission of other
        !          4983:         * messages (such as Renew and Rebind), and the section 22.7 ("Option
        !          4984:         * Request Option" format and definition):
        !          4985:         *
        !          4986:         *    A client MAY include an Option Request option in a Solicit,
        !          4987:         *    Request, Renew, Rebind, Confirm or Information-request message to
        !          4988:         *    inform the server about options the client wants the server to
        !          4989:         *    send to the client.  A server MAY include an Option Request
        !          4990:         *    option in a Reconfigure option to indicate which options the
        !          4991:         *    client should request from the server.
        !          4992:         *
        !          4993:         * seems to relax the requirement from MUST to MAY (and still other
        !          4994:         * language in RFC3315 supports this).
        !          4995:         *
        !          4996:         * In lieu of a clarification of RFC3315, we will conform with the
        !          4997:         * MUST.  Instead of an absent ORO, we will if there are no options
        !          4998:         * to request supply an empty ORO.  Theoretically, an absent ORO is
        !          4999:         * difficult to interpret (does the client want all options or no
        !          5000:         * options?).  A zero-length ORO is intuitively clear: requesting
        !          5001:         * nothing.
        !          5002:         */
        !          5003:        buffer = NULL;
        !          5004:        oro_len = 0;
        !          5005:        buflen = 32;
        !          5006:        if (!buffer_allocate(&buffer, buflen, MDL))
        !          5007:                log_fatal("Out of memory constructing DHCPv6 ORO.");
        !          5008:        req = client->config->requested_options;
        !          5009:        if (req != NULL) {
        !          5010:                for (i = 0 ; req[i] != NULL ; i++) {
        !          5011:                        if (buflen == oro_len) {
        !          5012:                                struct buffer *tmpbuf = NULL;
        !          5013: 
        !          5014:                                buflen += 32;
        !          5015: 
        !          5016:                                /* Shell game. */
        !          5017:                                buffer_reference(&tmpbuf, buffer, MDL);
        !          5018:                                buffer_dereference(&buffer, MDL);
        !          5019: 
        !          5020:                                if (!buffer_allocate(&buffer, buflen, MDL))
        !          5021:                                        log_fatal("Out of memory resizing "
        !          5022:                                                  "DHCPv6 ORO buffer.");
        !          5023: 
        !          5024:                                memcpy(buffer->data, tmpbuf->data, oro_len);
        !          5025: 
        !          5026:                                buffer_dereference(&tmpbuf, MDL);
        !          5027:                        }
        !          5028: 
        !          5029:                        if (req[i]->universe == &dhcpv6_universe) {
        !          5030:                                /* Append the code to the ORO. */
        !          5031:                                putUShort(buffer->data + oro_len,
        !          5032:                                          req[i]->code);
        !          5033:                                oro_len += 2;
        !          5034:                        }
        !          5035:                }
        !          5036:        }
        !          5037: 
        !          5038:        oc = NULL;
        !          5039:        if (make_const_option_cache(&oc, &buffer, NULL, oro_len,
        !          5040:                                    oro_option, MDL)) {
        !          5041:                save_option(&dhcpv6_universe, *op, oc);
        !          5042:        } else {
        !          5043:                log_fatal("Unable to create ORO option cache.");
        !          5044:        }
        !          5045: 
        !          5046:        /*
        !          5047:         * Note: make_const_option_cache() consumes the buffer, we do not
        !          5048:         * need to dereference it (XXX).
        !          5049:         */
        !          5050:        option_cache_dereference(&oc, MDL);
        !          5051: }
        !          5052: 
        !          5053: /* A clone of the DHCPv4 script_write_params() minus the DHCPv4-specific
        !          5054:  * filename, server-name, etc specifics.
        !          5055:  *
        !          5056:  * Simply, store all values present in all universes of the option state
        !          5057:  * (probably derived from a DHCPv6 packet) into environment variables
        !          5058:  * named after the option names (and universe names) but with the 'prefix'
        !          5059:  * prepended.
        !          5060:  *
        !          5061:  * Later, dhclient-script may compare for example "new_time_servers" and
        !          5062:  * "old_time_servers" for differences, and only upon detecting a change
        !          5063:  * bother to rewrite ntp.conf and restart it.  Or something along those
        !          5064:  * generic lines.
        !          5065:  */
        !          5066: static void
        !          5067: script_write_params6(struct client_state *client, const char *prefix,
        !          5068:                     struct option_state *options)
        !          5069: {
        !          5070:        struct envadd_state es;
        !          5071:        int i;
        !          5072: 
        !          5073:        if (options == NULL)
        !          5074:                return;
        !          5075: 
        !          5076:        es.client = client;
        !          5077:        es.prefix = prefix;
        !          5078: 
        !          5079:        for (i = 0 ; i < options->universe_count ; i++) {
        !          5080:                option_space_foreach(NULL, NULL, client, NULL, options,
        !          5081:                                     &global_scope, universes[i], &es,
        !          5082:                                     client_option_envadd);
        !          5083:        }
        !          5084: }
        !          5085: 
        !          5086: /*
        !          5087:  * Check if there is something not fully defined in the active lease.
        !          5088:  */
        !          5089: static isc_boolean_t
        !          5090: active_prefix(struct client_state *client)
        !          5091: {
        !          5092:        struct dhc6_lease *lease;
        !          5093:        struct dhc6_ia *ia;
        !          5094:        struct dhc6_addr *pref;
        !          5095:        char zeros[16];
        !          5096: 
        !          5097:        lease = client->active_lease;
        !          5098:        if (lease == NULL)
        !          5099:                return ISC_FALSE;
        !          5100:        memset(zeros, 0, 16);
        !          5101:        for (ia = lease->bindings; ia != NULL; ia = ia->next) {
        !          5102:                if (ia->ia_type != D6O_IA_PD)
        !          5103:                        continue;
        !          5104:                for (pref = ia->addrs; pref != NULL; pref = pref->next) {
        !          5105:                        if (pref->plen == 0)
        !          5106:                                return ISC_FALSE;
        !          5107:                        if (pref->address.len != 16)
        !          5108:                                return ISC_FALSE;
        !          5109:                        if (memcmp(pref->address.iabuf, zeros, 16) == 0)
        !          5110:                                return ISC_FALSE;
        !          5111:                }
        !          5112:        }
        !          5113:        return ISC_TRUE;
        !          5114: }
        !          5115: #endif /* DHCPv6 */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>