Annotation of embedaddon/dhcp/server/dhcpv6.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * Copyright (C) 2006-2011 by Internet Systems Consortium, Inc. ("ISC")
        !             3:  *
        !             4:  * Permission to use, copy, modify, and distribute this software for any
        !             5:  * purpose with or without fee is hereby granted, provided that the above
        !             6:  * copyright notice and this permission notice appear in all copies.
        !             7:  *
        !             8:  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
        !             9:  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
        !            10:  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
        !            11:  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
        !            12:  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
        !            13:  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
        !            14:  * PERFORMANCE OF THIS SOFTWARE.
        !            15:  */
        !            16: 
        !            17: #include "dhcpd.h"
        !            18: 
        !            19: #ifdef DHCPv6
        !            20: 
        !            21: /*
        !            22:  * We use print_hex_1() to output DUID values. We could actually output 
        !            23:  * the DUID with more information... MAC address if using type 1 or 3, 
        !            24:  * and so on. However, RFC 3315 contains Grave Warnings against actually 
        !            25:  * attempting to understand a DUID.
        !            26:  */
        !            27: 
        !            28: /* 
        !            29:  * TODO: gettext() or other method of localization for the messages
        !            30:  *       for status codes (and probably for log formats eventually)
        !            31:  * TODO: refactoring (simplify, simplify, simplify)
        !            32:  * TODO: support multiple shared_networks on each interface (this 
        !            33:  *       will allow the server to issue multiple IPv6 addresses to 
        !            34:  *       a single interface)
        !            35:  */
        !            36: 
        !            37: /*
        !            38:  * DHCPv6 Reply workflow assist.  A Reply packet is built by various
        !            39:  * different functions; this gives us one location where we keep state
        !            40:  * regarding a reply.
        !            41:  */
        !            42: struct reply_state {
        !            43:        /* root level persistent state */
        !            44:        struct shared_network *shared;
        !            45:        struct host_decl *host;
        !            46:        struct subnet *subnet; /* Used to match fixed-addrs to subnet scopes. */
        !            47:        struct option_state *opt_state;
        !            48:        struct packet *packet;
        !            49:        struct data_string client_id;
        !            50: 
        !            51:        /* IA level persistent state */
        !            52:        unsigned ia_count;
        !            53:        unsigned pd_count;
        !            54:        unsigned client_resources;
        !            55:        isc_boolean_t resources_included;
        !            56:        isc_boolean_t static_lease;
        !            57:        unsigned static_prefixes;
        !            58:        struct ia_xx *ia;
        !            59:        struct ia_xx *old_ia;
        !            60:        struct option_state *reply_ia;
        !            61:        struct data_string fixed;
        !            62: 
        !            63:        /* IAADDR/PREFIX level persistent state */
        !            64:        struct iasubopt *lease;
        !            65: 
        !            66:        /*
        !            67:         * "t1", "t2", preferred, and valid lifetimes records for calculating
        !            68:         * t1 and t2 (min/max).
        !            69:         */
        !            70:        u_int32_t renew, rebind, prefer, valid;
        !            71: 
        !            72:        /* Client-requested valid and preferred lifetimes. */
        !            73:        u_int32_t client_valid, client_prefer;
        !            74: 
        !            75:        /* Chosen values to transmit for valid and preferred lifetimes. */
        !            76:        u_int32_t send_valid, send_prefer;
        !            77: 
        !            78:        /* Preferred prefix length (-1 is any). */
        !            79:        int preflen;
        !            80: 
        !            81:        /* Index into the data field that has been consumed. */
        !            82:        unsigned cursor;
        !            83: 
        !            84:        union reply_buffer {
        !            85:                unsigned char data[65536];
        !            86:                struct dhcpv6_packet reply;
        !            87:        } buf;
        !            88: };
        !            89: 
        !            90: /* 
        !            91:  * Prototypes local to this file.
        !            92:  */
        !            93: static int get_encapsulated_IA_state(struct option_state **enc_opt_state,
        !            94:                                     struct data_string *enc_opt_data,
        !            95:                                     struct packet *packet,
        !            96:                                     struct option_cache *oc,
        !            97:                                     int offset);
        !            98: static void build_dhcpv6_reply(struct data_string *, struct packet *);
        !            99: static isc_result_t shared_network_from_packet6(struct shared_network **shared,
        !           100:                                                struct packet *packet);
        !           101: static void seek_shared_host(struct host_decl **hp,
        !           102:                             struct shared_network *shared);
        !           103: static isc_boolean_t fixed_matches_shared(struct host_decl *host,
        !           104:                                          struct shared_network *shared);
        !           105: static isc_result_t reply_process_ia_na(struct reply_state *reply,
        !           106:                                        struct option_cache *ia);
        !           107: static isc_result_t reply_process_ia_ta(struct reply_state *reply,
        !           108:                                        struct option_cache *ia);
        !           109: static isc_result_t reply_process_addr(struct reply_state *reply,
        !           110:                                       struct option_cache *addr);
        !           111: static isc_boolean_t address_is_owned(struct reply_state *reply,
        !           112:                                      struct iaddr *addr);
        !           113: static isc_boolean_t temporary_is_available(struct reply_state *reply,
        !           114:                                            struct iaddr *addr);
        !           115: static isc_result_t find_client_temporaries(struct reply_state *reply);
        !           116: static isc_result_t reply_process_try_addr(struct reply_state *reply,
        !           117:                                           struct iaddr *addr);
        !           118: static isc_result_t find_client_address(struct reply_state *reply);
        !           119: static isc_result_t reply_process_is_addressed(struct reply_state *reply,
        !           120:                                               struct binding_scope **scope,
        !           121:                                               struct group *group);
        !           122: static isc_result_t reply_process_send_addr(struct reply_state *reply,
        !           123:                                            struct iaddr *addr);
        !           124: static struct iasubopt *lease_compare(struct iasubopt *alpha,
        !           125:                                      struct iasubopt *beta);
        !           126: static isc_result_t reply_process_ia_pd(struct reply_state *reply,
        !           127:                                        struct option_cache *ia_pd);
        !           128: static isc_result_t reply_process_prefix(struct reply_state *reply,
        !           129:                                         struct option_cache *pref);
        !           130: static isc_boolean_t prefix_is_owned(struct reply_state *reply,
        !           131:                                     struct iaddrcidrnet *pref);
        !           132: static isc_result_t find_client_prefix(struct reply_state *reply);
        !           133: static isc_result_t reply_process_try_prefix(struct reply_state *reply,
        !           134:                                             struct iaddrcidrnet *pref);
        !           135: static isc_result_t reply_process_is_prefixed(struct reply_state *reply,
        !           136:                                              struct binding_scope **scope,
        !           137:                                              struct group *group);
        !           138: static isc_result_t reply_process_send_prefix(struct reply_state *reply,
        !           139:                                              struct iaddrcidrnet *pref);
        !           140: static struct iasubopt *prefix_compare(struct reply_state *reply,
        !           141:                                       struct iasubopt *alpha,
        !           142:                                       struct iasubopt *beta);
        !           143: 
        !           144: /*
        !           145:  * This function returns the time since DUID time start for the
        !           146:  * given time_t value.
        !           147:  */
        !           148: static u_int32_t
        !           149: duid_time(time_t when) {
        !           150:        /*
        !           151:         * This time is modulo 2^32.
        !           152:         */
        !           153:        while ((when - DUID_TIME_EPOCH) > 4294967295u) {
        !           154:                /* use 2^31 to avoid spurious compiler warnings */
        !           155:                when -= 2147483648u;
        !           156:                when -= 2147483648u;
        !           157:        }
        !           158: 
        !           159:        return when - DUID_TIME_EPOCH;
        !           160: }
        !           161: 
        !           162: 
        !           163: /* 
        !           164:  * Server DUID.
        !           165:  *
        !           166:  * This must remain the same for the lifetime of this server, because
        !           167:  * clients return the server DUID that we sent them in Request packets.
        !           168:  *
        !           169:  * We pick the server DUID like this:
        !           170:  *
        !           171:  * 1. Check dhcpd.conf - any value the administrator has configured 
        !           172:  *    overrides any possible values.
        !           173:  * 2. Check the leases.txt - we want to use the previous value if 
        !           174:  *    possible.
        !           175:  * 3. Check if dhcpd.conf specifies a type of server DUID to use,
        !           176:  *    and generate that type.
        !           177:  * 4. Generate a type 1 (time + hardware address) DUID.
        !           178:  */
        !           179: static struct data_string server_duid;
        !           180: 
        !           181: /*
        !           182:  * Check if the server_duid has been set.
        !           183:  */
        !           184: isc_boolean_t
        !           185: server_duid_isset(void) {
        !           186:        return (server_duid.data != NULL);
        !           187: }
        !           188: 
        !           189: /*
        !           190:  * Return the server_duid.
        !           191:  */
        !           192: void
        !           193: copy_server_duid(struct data_string *ds, const char *file, int line) {
        !           194:        data_string_copy(ds, &server_duid, file, line);
        !           195: }
        !           196: 
        !           197: /*
        !           198:  * Set the server DUID to a specified value. This is used when
        !           199:  * the server DUID is stored in persistent memory (basically the
        !           200:  * leases.txt file).
        !           201:  */
        !           202: void
        !           203: set_server_duid(struct data_string *new_duid) {
        !           204:        /* INSIST(new_duid != NULL); */
        !           205:        /* INSIST(new_duid->data != NULL); */
        !           206: 
        !           207:        if (server_duid_isset()) {
        !           208:                data_string_forget(&server_duid, MDL);
        !           209:        }
        !           210:        data_string_copy(&server_duid, new_duid, MDL);
        !           211: }
        !           212: 
        !           213: 
        !           214: /*
        !           215:  * Set the server DUID based on the D6O_SERVERID option. This handles
        !           216:  * the case where the administrator explicitly put it in the dhcpd.conf 
        !           217:  * file.
        !           218:  */
        !           219: isc_result_t
        !           220: set_server_duid_from_option(void) {
        !           221:        struct option_state *opt_state;
        !           222:        struct option_cache *oc;
        !           223:        struct data_string option_duid;
        !           224:        isc_result_t ret_val;
        !           225: 
        !           226:        opt_state = NULL;
        !           227:        if (!option_state_allocate(&opt_state, MDL)) {
        !           228:                log_fatal("No memory for server DUID.");
        !           229:        }
        !           230: 
        !           231:        execute_statements_in_scope(NULL, NULL, NULL, NULL, NULL,
        !           232:                                    opt_state, &global_scope, root_group, NULL);
        !           233: 
        !           234:        oc = lookup_option(&dhcpv6_universe, opt_state, D6O_SERVERID);
        !           235:        if (oc == NULL) {
        !           236:                ret_val = ISC_R_NOTFOUND;
        !           237:        } else {
        !           238:                memset(&option_duid, 0, sizeof(option_duid));
        !           239:                if (!evaluate_option_cache(&option_duid, NULL, NULL, NULL,
        !           240:                                           opt_state, NULL, &global_scope,
        !           241:                                           oc, MDL)) {
        !           242:                        ret_val = ISC_R_UNEXPECTED;
        !           243:                } else {
        !           244:                        set_server_duid(&option_duid);
        !           245:                        data_string_forget(&option_duid, MDL);
        !           246:                        ret_val = ISC_R_SUCCESS;
        !           247:                }
        !           248:        }
        !           249: 
        !           250:        option_state_dereference(&opt_state, MDL);
        !           251: 
        !           252:        return ret_val;
        !           253: }
        !           254: 
        !           255: /*
        !           256:  * DUID layout, as defined in RFC 3315, section 9.
        !           257:  * 
        !           258:  * We support type 1 (hardware address plus time) and type 3 (hardware
        !           259:  * address).
        !           260:  *
        !           261:  * We can support type 2 for specific vendors in the future, if they 
        !           262:  * publish the specification. And of course there may be additional
        !           263:  * types later.
        !           264:  */
        !           265: static int server_duid_type = DUID_LLT;
        !           266: 
        !           267: /* 
        !           268:  * Set the DUID type.
        !           269:  */
        !           270: void
        !           271: set_server_duid_type(int type) {
        !           272:        server_duid_type = type;
        !           273: }
        !           274: 
        !           275: /*
        !           276:  * Generate a new server DUID. This is done if there was no DUID in 
        !           277:  * the leases.txt or in the dhcpd.conf file.
        !           278:  */
        !           279: isc_result_t
        !           280: generate_new_server_duid(void) {
        !           281:        struct interface_info *p;
        !           282:        u_int32_t time_val;
        !           283:        struct data_string generated_duid;
        !           284: 
        !           285:        /*
        !           286:         * Verify we have a type that we support.
        !           287:         */
        !           288:        if ((server_duid_type != DUID_LL) && (server_duid_type != DUID_LLT)) {
        !           289:                log_error("Invalid DUID type %d specified, "
        !           290:                          "only LL and LLT types supported", server_duid_type);
        !           291:                return ISC_R_INVALIDARG;
        !           292:        }
        !           293: 
        !           294:        /*
        !           295:         * Find an interface with a hardware address.
        !           296:         * Any will do. :)
        !           297:         */
        !           298:        for (p = interfaces; p != NULL; p = p->next) {
        !           299:                if (p->hw_address.hlen > 0) {
        !           300:                        break;
        !           301:                }
        !           302:        }
        !           303:        if (p == NULL) {
        !           304:                return ISC_R_UNEXPECTED;
        !           305:        }
        !           306: 
        !           307:        /*
        !           308:         * Build our DUID.
        !           309:         */
        !           310:        memset(&generated_duid, 0, sizeof(generated_duid));
        !           311:        if (server_duid_type == DUID_LLT) {
        !           312:                time_val = duid_time(time(NULL));
        !           313:                generated_duid.len = 8 + p->hw_address.hlen - 1;
        !           314:                if (!buffer_allocate(&generated_duid.buffer,
        !           315:                                     generated_duid.len, MDL)) {
        !           316:                        log_fatal("No memory for server DUID.");
        !           317:                }
        !           318:                generated_duid.data = generated_duid.buffer->data;
        !           319:                putUShort(generated_duid.buffer->data, DUID_LLT);
        !           320:                putUShort(generated_duid.buffer->data + 2,
        !           321:                          p->hw_address.hbuf[0]);
        !           322:                putULong(generated_duid.buffer->data + 4, time_val);
        !           323:                memcpy(generated_duid.buffer->data + 8,
        !           324:                       p->hw_address.hbuf+1, p->hw_address.hlen-1);
        !           325:        } else if (server_duid_type == DUID_LL) {
        !           326:                generated_duid.len = 4 + p->hw_address.hlen - 1;
        !           327:                if (!buffer_allocate(&generated_duid.buffer,
        !           328:                                     generated_duid.len, MDL)) {
        !           329:                        log_fatal("No memory for server DUID.");
        !           330:                }
        !           331:                generated_duid.data = generated_duid.buffer->data;
        !           332:                putUShort(generated_duid.buffer->data, DUID_LL);
        !           333:                putUShort(generated_duid.buffer->data + 2,
        !           334:                          p->hw_address.hbuf[0]);
        !           335:                memcpy(generated_duid.buffer->data + 4,
        !           336:                       p->hw_address.hbuf+1, p->hw_address.hlen-1);
        !           337:        } else {
        !           338:                log_fatal("Unsupported server DUID type %d.", server_duid_type);
        !           339:        }
        !           340: 
        !           341:        set_server_duid(&generated_duid);
        !           342:        data_string_forget(&generated_duid, MDL);
        !           343: 
        !           344:        return ISC_R_SUCCESS;
        !           345: }
        !           346: 
        !           347: /*
        !           348:  * Get the client identifier from the packet.
        !           349:  */
        !           350: isc_result_t
        !           351: get_client_id(struct packet *packet, struct data_string *client_id) {
        !           352:        struct option_cache *oc;
        !           353: 
        !           354:        /*
        !           355:         * Verify our client_id structure is empty.
        !           356:         */
        !           357:        if ((client_id->data != NULL) || (client_id->len != 0)) {
        !           358:                return ISC_R_INVALIDARG;
        !           359:        }
        !           360: 
        !           361:        oc = lookup_option(&dhcpv6_universe, packet->options, D6O_CLIENTID);
        !           362:        if (oc == NULL) {
        !           363:                return ISC_R_NOTFOUND;
        !           364:        }
        !           365: 
        !           366:        if (!evaluate_option_cache(client_id, packet, NULL, NULL,
        !           367:                                   packet->options, NULL,
        !           368:                                   &global_scope, oc, MDL)) {
        !           369:                return ISC_R_FAILURE;
        !           370:        }
        !           371: 
        !           372:        return ISC_R_SUCCESS;
        !           373: }
        !           374: 
        !           375: /*
        !           376:  * Message validation, defined in RFC 3315, sections 15.2, 15.5, 15.7:
        !           377:  *
        !           378:  *    Servers MUST discard any Solicit messages that do not include a
        !           379:  *    Client Identifier option or that do include a Server Identifier
        !           380:  *    option.
        !           381:  */
        !           382: int
        !           383: valid_client_msg(struct packet *packet, struct data_string *client_id) {
        !           384:        int ret_val;
        !           385:        struct option_cache *oc;
        !           386:        struct data_string data;
        !           387: 
        !           388:        ret_val = 0;
        !           389:        memset(client_id, 0, sizeof(*client_id));
        !           390:        memset(&data, 0, sizeof(data));
        !           391: 
        !           392:        switch (get_client_id(packet, client_id)) {
        !           393:                case ISC_R_SUCCESS:
        !           394:                        break;
        !           395:                case ISC_R_NOTFOUND:
        !           396:                        log_debug("Discarding %s from %s; "
        !           397:                                  "client identifier missing",
        !           398:                                  dhcpv6_type_names[packet->dhcpv6_msg_type],
        !           399:                                  piaddr(packet->client_addr));
        !           400:                        goto exit;
        !           401:                default:
        !           402:                        log_error("Error processing %s from %s; "
        !           403:                                  "unable to evaluate Client Identifier",
        !           404:                                  dhcpv6_type_names[packet->dhcpv6_msg_type],
        !           405:                                  piaddr(packet->client_addr));
        !           406:                        goto exit;
        !           407:        }
        !           408: 
        !           409:        /*
        !           410:         * Required by RFC 3315, section 15.
        !           411:         */
        !           412:        if (packet->unicast) {
        !           413:                log_debug("Discarding %s from %s; packet sent unicast "
        !           414:                          "(CLIENTID %s)",
        !           415:                          dhcpv6_type_names[packet->dhcpv6_msg_type],
        !           416:                          piaddr(packet->client_addr),
        !           417:                          print_hex_1(client_id->len, client_id->data, 60));
        !           418:                goto exit;
        !           419:        }
        !           420: 
        !           421: 
        !           422:        oc = lookup_option(&dhcpv6_universe, packet->options, D6O_SERVERID);
        !           423:        if (oc != NULL) {
        !           424:                if (evaluate_option_cache(&data, packet, NULL, NULL,
        !           425:                                          packet->options, NULL,
        !           426:                                          &global_scope, oc, MDL)) {
        !           427:                        log_debug("Discarding %s from %s; "
        !           428:                                  "server identifier found "
        !           429:                                  "(CLIENTID %s, SERVERID %s)",
        !           430:                                  dhcpv6_type_names[packet->dhcpv6_msg_type],
        !           431:                                  piaddr(packet->client_addr),
        !           432:                                  print_hex_1(client_id->len,
        !           433:                                              client_id->data, 60),
        !           434:                                  print_hex_2(data.len,
        !           435:                                              data.data, 60));
        !           436:                } else {
        !           437:                        log_debug("Discarding %s from %s; "
        !           438:                                  "server identifier found "
        !           439:                                  "(CLIENTID %s)",
        !           440:                                  dhcpv6_type_names[packet->dhcpv6_msg_type],
        !           441:                                  print_hex_1(client_id->len,
        !           442:                                              client_id->data, 60),
        !           443:                                  piaddr(packet->client_addr));
        !           444:                }
        !           445:                goto exit;
        !           446:        }
        !           447: 
        !           448:        /* looks good */
        !           449:        ret_val = 1;
        !           450: 
        !           451: exit:
        !           452:        if (data.len > 0) {
        !           453:                data_string_forget(&data, MDL);
        !           454:        }
        !           455:        if (!ret_val) {
        !           456:                if (client_id->len > 0) {
        !           457:                        data_string_forget(client_id, MDL);
        !           458:                }
        !           459:        }
        !           460:        return ret_val;
        !           461: }
        !           462: 
        !           463: /*
        !           464:  * Response validation, defined in RFC 3315, sections 15.4, 15.6, 15.8, 
        !           465:  * 15.9 (slightly different wording, but same meaning):
        !           466:  *
        !           467:  *   Servers MUST discard any received Request message that meet any of
        !           468:  *   the following conditions:
        !           469:  *
        !           470:  *   -  the message does not include a Server Identifier option.
        !           471:  *   -  the contents of the Server Identifier option do not match the
        !           472:  *      server's DUID.
        !           473:  *   -  the message does not include a Client Identifier option.
        !           474:  */
        !           475: int
        !           476: valid_client_resp(struct packet *packet,
        !           477:                  struct data_string *client_id,
        !           478:                  struct data_string *server_id)
        !           479: {
        !           480:        int ret_val;
        !           481:        struct option_cache *oc;
        !           482: 
        !           483:        /* INSIST((duid.data != NULL) && (duid.len > 0)); */
        !           484: 
        !           485:        ret_val = 0;
        !           486:        memset(client_id, 0, sizeof(*client_id));
        !           487:        memset(server_id, 0, sizeof(*server_id));
        !           488: 
        !           489:        switch (get_client_id(packet, client_id)) {
        !           490:                case ISC_R_SUCCESS:
        !           491:                        break;
        !           492:                case ISC_R_NOTFOUND:
        !           493:                        log_debug("Discarding %s from %s; "
        !           494:                                  "client identifier missing",
        !           495:                                  dhcpv6_type_names[packet->dhcpv6_msg_type],
        !           496:                                  piaddr(packet->client_addr));
        !           497:                        goto exit;
        !           498:                default:
        !           499:                        log_error("Error processing %s from %s; "
        !           500:                                  "unable to evaluate Client Identifier",
        !           501:                                  dhcpv6_type_names[packet->dhcpv6_msg_type],
        !           502:                                  piaddr(packet->client_addr));
        !           503:                        goto exit;
        !           504:        }
        !           505: 
        !           506:        oc = lookup_option(&dhcpv6_universe, packet->options, D6O_SERVERID);
        !           507:        if (oc == NULL) {
        !           508:                log_debug("Discarding %s from %s: "
        !           509:                          "server identifier missing (CLIENTID %s)",
        !           510:                          dhcpv6_type_names[packet->dhcpv6_msg_type],
        !           511:                          piaddr(packet->client_addr),
        !           512:                          print_hex_1(client_id->len, client_id->data, 60));
        !           513:                goto exit;
        !           514:        }
        !           515:        if (!evaluate_option_cache(server_id, packet, NULL, NULL,
        !           516:                                   packet->options, NULL,
        !           517:                                   &global_scope, oc, MDL)) {
        !           518:                log_error("Error processing %s from %s; "
        !           519:                          "unable to evaluate Server Identifier (CLIENTID %s)",
        !           520:                          dhcpv6_type_names[packet->dhcpv6_msg_type],
        !           521:                          piaddr(packet->client_addr),
        !           522:                          print_hex_1(client_id->len, client_id->data, 60));
        !           523:                goto exit;
        !           524:        }
        !           525:        if ((server_duid.len != server_id->len) ||
        !           526:            (memcmp(server_duid.data, server_id->data, server_duid.len) != 0)) {
        !           527:                log_debug("Discarding %s from %s; "
        !           528:                          "not our server identifier "
        !           529:                          "(CLIENTID %s, SERVERID %s, server DUID %s)",
        !           530:                          dhcpv6_type_names[packet->dhcpv6_msg_type],
        !           531:                          piaddr(packet->client_addr),
        !           532:                          print_hex_1(client_id->len, client_id->data, 60),
        !           533:                          print_hex_2(server_id->len, server_id->data, 60),
        !           534:                          print_hex_3(server_duid.len, server_duid.data, 60));
        !           535:                goto exit;
        !           536:        }
        !           537: 
        !           538:        /* looks good */
        !           539:        ret_val = 1;
        !           540: 
        !           541: exit:
        !           542:        if (!ret_val) {
        !           543:                if (server_id->len > 0) {
        !           544:                        data_string_forget(server_id, MDL);
        !           545:                }
        !           546:                if (client_id->len > 0) {
        !           547:                        data_string_forget(client_id, MDL);
        !           548:                }
        !           549:        }
        !           550:        return ret_val;
        !           551: }
        !           552: 
        !           553: /*
        !           554:  * Information request validation, defined in RFC 3315, section 15.12:
        !           555:  *
        !           556:  *   Servers MUST discard any received Information-request message that
        !           557:  *   meets any of the following conditions:
        !           558:  *
        !           559:  *   -  The message includes a Server Identifier option and the DUID in
        !           560:  *      the option does not match the server's DUID.
        !           561:  *
        !           562:  *   -  The message includes an IA option.
        !           563:  */
        !           564: int
        !           565: valid_client_info_req(struct packet *packet, struct data_string *server_id) {
        !           566:        int ret_val;
        !           567:        struct option_cache *oc;
        !           568:        struct data_string client_id;
        !           569:        char client_id_str[80]; /* print_hex_1() uses maximum 60 characters,
        !           570:                                   plus a few more for extra information */
        !           571: 
        !           572:        ret_val = 0;
        !           573:        memset(server_id, 0, sizeof(*server_id));
        !           574: 
        !           575:        /*
        !           576:         * Make a string that we can print out to give more 
        !           577:         * information about the client if we need to.
        !           578:         *
        !           579:         * By RFC 3315, Section 18.1.5 clients SHOULD have a 
        !           580:         * client-id on an Information-request packet, but it 
        !           581:         * is not strictly necessary.
        !           582:         */
        !           583:        if (get_client_id(packet, &client_id) == ISC_R_SUCCESS) {
        !           584:                snprintf(client_id_str, sizeof(client_id_str), " (CLIENTID %s)",
        !           585:                         print_hex_1(client_id.len, client_id.data, 60));
        !           586:                data_string_forget(&client_id, MDL);
        !           587:        } else {
        !           588:                client_id_str[0] = '\0';
        !           589:        }
        !           590: 
        !           591:        /*
        !           592:         * Required by RFC 3315, section 15.
        !           593:         */
        !           594:        if (packet->unicast) {
        !           595:                log_debug("Discarding %s from %s; packet sent unicast%s",
        !           596:                          dhcpv6_type_names[packet->dhcpv6_msg_type],
        !           597:                          piaddr(packet->client_addr), client_id_str);
        !           598:                goto exit;
        !           599:        }
        !           600: 
        !           601:        oc = lookup_option(&dhcpv6_universe, packet->options, D6O_IA_NA);
        !           602:        if (oc != NULL) {
        !           603:                log_debug("Discarding %s from %s; "
        !           604:                          "IA_NA option present%s",
        !           605:                          dhcpv6_type_names[packet->dhcpv6_msg_type],
        !           606:                          piaddr(packet->client_addr), client_id_str);
        !           607:                goto exit;
        !           608:        }
        !           609:        oc = lookup_option(&dhcpv6_universe, packet->options, D6O_IA_TA);
        !           610:        if (oc != NULL) {
        !           611:                log_debug("Discarding %s from %s; "
        !           612:                          "IA_TA option present%s",
        !           613:                          dhcpv6_type_names[packet->dhcpv6_msg_type],
        !           614:                          piaddr(packet->client_addr), client_id_str);
        !           615:                goto exit;
        !           616:        }
        !           617:        oc = lookup_option(&dhcpv6_universe, packet->options, D6O_IA_PD);
        !           618:        if (oc != NULL) {
        !           619:                log_debug("Discarding %s from %s; "
        !           620:                          "IA_PD option present%s",
        !           621:                          dhcpv6_type_names[packet->dhcpv6_msg_type],
        !           622:                          piaddr(packet->client_addr), client_id_str);
        !           623:                goto exit;
        !           624:        }
        !           625: 
        !           626:        oc = lookup_option(&dhcpv6_universe, packet->options, D6O_SERVERID);
        !           627:        if (oc != NULL) {
        !           628:                if (!evaluate_option_cache(server_id, packet, NULL, NULL,
        !           629:                                           packet->options, NULL,
        !           630:                                           &global_scope, oc, MDL)) {
        !           631:                        log_error("Error processing %s from %s; "
        !           632:                                  "unable to evaluate Server Identifier%s",
        !           633:                                  dhcpv6_type_names[packet->dhcpv6_msg_type],
        !           634:                                  piaddr(packet->client_addr), client_id_str);
        !           635:                        goto exit;
        !           636:                }
        !           637:                if ((server_duid.len != server_id->len) ||
        !           638:                    (memcmp(server_duid.data, server_id->data,
        !           639:                            server_duid.len) != 0)) {
        !           640:                        log_debug("Discarding %s from %s; "
        !           641:                                  "not our server identifier "
        !           642:                                  "(SERVERID %s, server DUID %s)%s",
        !           643:                                  dhcpv6_type_names[packet->dhcpv6_msg_type],
        !           644:                                  piaddr(packet->client_addr),
        !           645:                                  print_hex_1(server_id->len,
        !           646:                                              server_id->data, 60),
        !           647:                                  print_hex_2(server_duid.len,
        !           648:                                              server_duid.data, 60),
        !           649:                                  client_id_str);
        !           650:                        goto exit;
        !           651:                }
        !           652:        }
        !           653: 
        !           654:        /* looks good */
        !           655:        ret_val = 1;
        !           656: 
        !           657: exit:
        !           658:        if (!ret_val) {
        !           659:                if (server_id->len > 0) {
        !           660:                        data_string_forget(server_id, MDL);
        !           661:                }
        !           662:        }
        !           663:        return ret_val;
        !           664: }
        !           665: 
        !           666: /* 
        !           667:  * Options that we want to send, in addition to what was requested
        !           668:  * via the ORO.
        !           669:  */
        !           670: static const int required_opts[] = {
        !           671:        D6O_CLIENTID,
        !           672:        D6O_SERVERID,
        !           673:        D6O_STATUS_CODE,
        !           674:        D6O_PREFERENCE,
        !           675:        0
        !           676: };
        !           677: static const int required_opts_NAA[] = {
        !           678:        D6O_CLIENTID,
        !           679:        D6O_SERVERID,
        !           680:        D6O_STATUS_CODE,
        !           681:        0
        !           682: };
        !           683: static const int required_opts_solicit[] = {
        !           684:        D6O_CLIENTID,
        !           685:        D6O_SERVERID,
        !           686:        D6O_IA_NA,
        !           687:        D6O_IA_TA,
        !           688:        D6O_IA_PD,
        !           689:        D6O_RAPID_COMMIT,
        !           690:        D6O_STATUS_CODE,
        !           691:        D6O_RECONF_ACCEPT,
        !           692:        D6O_PREFERENCE,
        !           693:        0
        !           694: };
        !           695: static const int required_opts_agent[] = {
        !           696:        D6O_INTERFACE_ID,
        !           697:        D6O_RELAY_MSG,
        !           698:        0
        !           699: };
        !           700: static const int required_opts_IA[] = {
        !           701:        D6O_IAADDR,
        !           702:        D6O_STATUS_CODE,
        !           703:        0
        !           704: };
        !           705: static const int required_opts_IA_PD[] = {
        !           706:        D6O_IAPREFIX,
        !           707:        D6O_STATUS_CODE,
        !           708:        0
        !           709: };
        !           710: static const int required_opts_STATUS_CODE[] = {
        !           711:        D6O_STATUS_CODE,
        !           712:        0
        !           713: };
        !           714: 
        !           715: /*
        !           716:  * Extracts from packet contents an IA_* option, storing the IA structure
        !           717:  * in its entirety in enc_opt_data, and storing any decoded DHCPv6 options
        !           718:  * in enc_opt_state for later lookup and evaluation.  The 'offset' indicates
        !           719:  * where in the IA_* the DHCPv6 options commence.
        !           720:  */
        !           721: static int
        !           722: get_encapsulated_IA_state(struct option_state **enc_opt_state,
        !           723:                          struct data_string *enc_opt_data,
        !           724:                          struct packet *packet,
        !           725:                          struct option_cache *oc,
        !           726:                          int offset)
        !           727: {
        !           728:        /* 
        !           729:         * Get the raw data for the encapsulated options.
        !           730:         */
        !           731:        memset(enc_opt_data, 0, sizeof(*enc_opt_data));
        !           732:        if (!evaluate_option_cache(enc_opt_data, packet,
        !           733:                                   NULL, NULL, packet->options, NULL,
        !           734:                                   &global_scope, oc, MDL)) {
        !           735:                log_error("get_encapsulated_IA_state: "
        !           736:                          "error evaluating raw option.");
        !           737:                return 0;
        !           738:        }
        !           739:        if (enc_opt_data->len < offset) {
        !           740:                log_error("get_encapsulated_IA_state: raw option too small.");
        !           741:                data_string_forget(enc_opt_data, MDL);
        !           742:                return 0;
        !           743:        }
        !           744: 
        !           745:        /*
        !           746:         * Now create the option state structure, and pass it to the 
        !           747:         * function that parses options.
        !           748:         */
        !           749:        *enc_opt_state = NULL;
        !           750:        if (!option_state_allocate(enc_opt_state, MDL)) {
        !           751:                log_error("get_encapsulated_IA_state: no memory for options.");
        !           752:                data_string_forget(enc_opt_data, MDL);
        !           753:                return 0;
        !           754:        }
        !           755:        if (!parse_option_buffer(*enc_opt_state,
        !           756:                                 enc_opt_data->data + offset, 
        !           757:                                 enc_opt_data->len - offset,
        !           758:                                 &dhcpv6_universe)) {
        !           759:                log_error("get_encapsulated_IA_state: error parsing options.");
        !           760:                option_state_dereference(enc_opt_state, MDL);
        !           761:                data_string_forget(enc_opt_data, MDL);
        !           762:                return 0;
        !           763:        }
        !           764: 
        !           765:        return 1;
        !           766: }
        !           767: 
        !           768: static int
        !           769: set_status_code(u_int16_t status_code, const char *status_message,
        !           770:                struct option_state *opt_state)
        !           771: {
        !           772:        struct data_string d;
        !           773:        int ret_val;
        !           774: 
        !           775:        memset(&d, 0, sizeof(d));
        !           776:        d.len = sizeof(status_code) + strlen(status_message);
        !           777:        if (!buffer_allocate(&d.buffer, d.len, MDL)) {
        !           778:                log_fatal("set_status_code: no memory for status code.");
        !           779:        }
        !           780:        d.data = d.buffer->data;
        !           781:        putUShort(d.buffer->data, status_code);
        !           782:        memcpy(d.buffer->data + sizeof(status_code), 
        !           783:               status_message, d.len - sizeof(status_code));
        !           784:        if (!save_option_buffer(&dhcpv6_universe, opt_state, 
        !           785:                                d.buffer, (unsigned char *)d.data, d.len, 
        !           786:                                D6O_STATUS_CODE, 0)) {
        !           787:                log_error("set_status_code: error saving status code.");
        !           788:                ret_val = 0;
        !           789:        } else {
        !           790:                ret_val = 1;
        !           791:        }
        !           792:        data_string_forget(&d, MDL);
        !           793:        return ret_val;
        !           794: }
        !           795: 
        !           796: /*
        !           797:  * We have a set of operations we do to set up the reply packet, which
        !           798:  * is the same for many message types.
        !           799:  */
        !           800: static int
        !           801: start_reply(struct packet *packet,
        !           802:            const struct data_string *client_id, 
        !           803:            const struct data_string *server_id,
        !           804:            struct option_state **opt_state,
        !           805:            struct dhcpv6_packet *reply)
        !           806: {
        !           807:        struct option_cache *oc;
        !           808:        const unsigned char *server_id_data;
        !           809:        int server_id_len;
        !           810: 
        !           811:        /*
        !           812:         * Build our option state for reply.
        !           813:         */
        !           814:        *opt_state = NULL;
        !           815:        if (!option_state_allocate(opt_state, MDL)) {
        !           816:                log_error("start_reply: no memory for option_state.");
        !           817:                return 0;
        !           818:        }
        !           819:        execute_statements_in_scope(NULL, packet, NULL, NULL,
        !           820:                                    packet->options, *opt_state,
        !           821:                                    &global_scope, root_group, NULL);
        !           822: 
        !           823:        /*
        !           824:         * A small bit of special handling for Solicit messages.
        !           825:         *
        !           826:         * We could move the logic into a flag, but for now just check
        !           827:         * explicitly.
        !           828:         */
        !           829:        if (packet->dhcpv6_msg_type == DHCPV6_SOLICIT) {
        !           830:                reply->msg_type = DHCPV6_ADVERTISE;
        !           831: 
        !           832:                /*
        !           833:                 * If:
        !           834:                 * - this message type supports rapid commit (Solicit), and
        !           835:                 * - the server is configured to supply a rapid commit, and
        !           836:                 * - the client requests a rapid commit,
        !           837:                 * Then we add a rapid commit option, and send Reply (instead
        !           838:                 * of an Advertise).
        !           839:                 */
        !           840:                oc = lookup_option(&dhcpv6_universe,
        !           841:                                   *opt_state, D6O_RAPID_COMMIT);
        !           842:                if (oc != NULL) {
        !           843:                        oc = lookup_option(&dhcpv6_universe,
        !           844:                                           packet->options, D6O_RAPID_COMMIT);
        !           845:                        if (oc != NULL) {
        !           846:                                /* Rapid-commit in action. */
        !           847:                                reply->msg_type = DHCPV6_REPLY;
        !           848:                        } else {
        !           849:                                /* Don't want a rapid-commit in advertise. */
        !           850:                                delete_option(&dhcpv6_universe,
        !           851:                                              *opt_state, D6O_RAPID_COMMIT);
        !           852:                        }
        !           853:                }
        !           854:        } else {
        !           855:                reply->msg_type = DHCPV6_REPLY;
        !           856:                /* Delete the rapid-commit from the sent options. */
        !           857:                oc = lookup_option(&dhcpv6_universe,
        !           858:                                   *opt_state, D6O_RAPID_COMMIT);
        !           859:                if (oc != NULL) {
        !           860:                        delete_option(&dhcpv6_universe,
        !           861:                                      *opt_state, D6O_RAPID_COMMIT);
        !           862:                }
        !           863:        }
        !           864: 
        !           865:        /* 
        !           866:         * Use the client's transaction identifier for the reply.
        !           867:         */
        !           868:        memcpy(reply->transaction_id, packet->dhcpv6_transaction_id, 
        !           869:               sizeof(reply->transaction_id));
        !           870: 
        !           871:        /* 
        !           872:         * RFC 3315, section 18.2 says we need server identifier and
        !           873:         * client identifier.
        !           874:         *
        !           875:         * If the server ID is defined via the configuration file, then
        !           876:         * it will already be present in the option state at this point, 
        !           877:         * so we don't need to set it.
        !           878:         *
        !           879:         * If we have a server ID passed in from the caller, 
        !           880:         * use that, otherwise use the global DUID.
        !           881:         */
        !           882:        oc = lookup_option(&dhcpv6_universe, *opt_state, D6O_SERVERID);
        !           883:        if (oc == NULL) {
        !           884:                if (server_id == NULL) {
        !           885:                        server_id_data = server_duid.data;
        !           886:                        server_id_len = server_duid.len;
        !           887:                } else {
        !           888:                        server_id_data = server_id->data;
        !           889:                        server_id_len = server_id->len;
        !           890:                }
        !           891:                if (!save_option_buffer(&dhcpv6_universe, *opt_state, 
        !           892:                                        NULL, (unsigned char *)server_id_data,
        !           893:                                        server_id_len, D6O_SERVERID, 0)) {
        !           894:                                log_error("start_reply: "
        !           895:                                          "error saving server identifier.");
        !           896:                                return 0;
        !           897:                }
        !           898:        }
        !           899: 
        !           900:        if (client_id->buffer != NULL) {
        !           901:                if (!save_option_buffer(&dhcpv6_universe, *opt_state, 
        !           902:                                        client_id->buffer, 
        !           903:                                        (unsigned char *)client_id->data, 
        !           904:                                        client_id->len, 
        !           905:                                        D6O_CLIENTID, 0)) {
        !           906:                        log_error("start_reply: error saving "
        !           907:                                  "client identifier.");
        !           908:                        return 0;
        !           909:                }
        !           910:        }
        !           911: 
        !           912:        /*
        !           913:         * If the client accepts reconfiguration, let it know that we
        !           914:         * will send them.
        !           915:         *
        !           916:         * Note: we don't actually do this yet, but DOCSIS requires we
        !           917:         *       claim to.
        !           918:         */
        !           919:        oc = lookup_option(&dhcpv6_universe, packet->options,
        !           920:                           D6O_RECONF_ACCEPT);
        !           921:        if (oc != NULL) {
        !           922:                if (!save_option_buffer(&dhcpv6_universe, *opt_state,
        !           923:                                        NULL, (unsigned char *)"", 0, 
        !           924:                                        D6O_RECONF_ACCEPT, 0)) {
        !           925:                        log_error("start_reply: "
        !           926:                                  "error saving RECONF_ACCEPT option.");
        !           927:                        option_state_dereference(opt_state, MDL);
        !           928:                        return 0;
        !           929:                }
        !           930:        }
        !           931: 
        !           932:        return 1;
        !           933: }
        !           934: 
        !           935: /*
        !           936:  * Try to get the IPv6 address the client asked for from the
        !           937:  * pool.
        !           938:  *
        !           939:  * addr is the result (should be a pointer to NULL on entry)
        !           940:  * pool is the pool to search in
        !           941:  * requested_addr is the address the client wants
        !           942:  */
        !           943: static isc_result_t
        !           944: try_client_v6_address(struct iasubopt **addr,
        !           945:                      struct ipv6_pool *pool,
        !           946:                      const struct data_string *requested_addr)
        !           947: {
        !           948:        struct in6_addr tmp_addr;
        !           949:        isc_result_t result;
        !           950: 
        !           951:        if (requested_addr->len < sizeof(tmp_addr)) {
        !           952:                return ISC_R_INVALIDARG;
        !           953:        }
        !           954:        memcpy(&tmp_addr, requested_addr->data, sizeof(tmp_addr));
        !           955:        if (IN6_IS_ADDR_UNSPECIFIED(&tmp_addr)) {
        !           956:                return ISC_R_FAILURE;
        !           957:        }
        !           958: 
        !           959:        /*
        !           960:         * The address is not covered by this (or possibly any) dynamic
        !           961:         * range.
        !           962:         */
        !           963:        if (!ipv6_in_pool(&tmp_addr, pool)) {
        !           964:                return ISC_R_ADDRNOTAVAIL;
        !           965:        }
        !           966: 
        !           967:        if (lease6_exists(pool, &tmp_addr)) {
        !           968:                return ISC_R_ADDRINUSE;
        !           969:        }
        !           970: 
        !           971:        result = iasubopt_allocate(addr, MDL);
        !           972:        if (result != ISC_R_SUCCESS) {
        !           973:                return result;
        !           974:        }
        !           975:        (*addr)->addr = tmp_addr;
        !           976:        (*addr)->plen = 0;
        !           977: 
        !           978:        /* Default is soft binding for 2 minutes. */
        !           979:        result = add_lease6(pool, *addr, cur_time + 120);
        !           980:        if (result != ISC_R_SUCCESS) {
        !           981:                iasubopt_dereference(addr, MDL);
        !           982:        }
        !           983:        return result;
        !           984: }
        !           985: 
        !           986: /*
        !           987:  * Get an IPv6 address for the client.
        !           988:  *
        !           989:  * addr is the result (should be a pointer to NULL on entry)
        !           990:  * packet is the information about the packet from the client
        !           991:  * requested_iaaddr is a hint from the client
        !           992:  * client_id is the DUID for the client
        !           993:  */
        !           994: static isc_result_t 
        !           995: pick_v6_address(struct iasubopt **addr, struct shared_network *shared_network,
        !           996:                const struct data_string *client_id)
        !           997: {
        !           998:        struct ipv6_pool *p;
        !           999:        int i;
        !          1000:        int start_pool;
        !          1001:        unsigned int attempts;
        !          1002:        char tmp_buf[INET6_ADDRSTRLEN];
        !          1003: 
        !          1004:        /*
        !          1005:         * No address pools, we're done.
        !          1006:         */
        !          1007:        if (shared_network->ipv6_pools == NULL) {
        !          1008:                log_debug("Unable to pick client address: "
        !          1009:                          "no IPv6 pools on this shared network");
        !          1010:                return ISC_R_NORESOURCES;
        !          1011:        }
        !          1012:        for (i = 0;; i++) {
        !          1013:                p = shared_network->ipv6_pools[i];
        !          1014:                if (p == NULL) {
        !          1015:                        log_debug("Unable to pick client address: "
        !          1016:                                  "no IPv6 address pools "
        !          1017:                                  "on this shared network");
        !          1018:                        return ISC_R_NORESOURCES;
        !          1019:                }
        !          1020:                if (p->pool_type == D6O_IA_NA) {
        !          1021:                        break;
        !          1022:                }
        !          1023:        }
        !          1024: 
        !          1025:        /*
        !          1026:         * Otherwise try to get a lease from the first subnet possible.
        !          1027:         *
        !          1028:         * We start looking at the last pool we allocated from, unless
        !          1029:         * it had a collision trying to allocate an address. This will
        !          1030:         * tend to move us into less-filled pools.
        !          1031:         */
        !          1032:        start_pool = shared_network->last_ipv6_pool;
        !          1033:        i = start_pool;
        !          1034:        do {
        !          1035: 
        !          1036:                p = shared_network->ipv6_pools[i];
        !          1037:                if ((p->pool_type == D6O_IA_NA) &&
        !          1038:                    (create_lease6(p, addr, &attempts, client_id,
        !          1039:                                   cur_time + 120) == ISC_R_SUCCESS)) {
        !          1040:                        /*
        !          1041:                         * Record the pool used (or next one if there 
        !          1042:                         * was a collision).
        !          1043:                         */
        !          1044:                        if (attempts > 1) {
        !          1045:                                i++;
        !          1046:                                if (shared_network->ipv6_pools[i] == NULL) {
        !          1047:                                        i = 0;
        !          1048:                                }
        !          1049:                        }
        !          1050:                        shared_network->last_ipv6_pool = i;
        !          1051: 
        !          1052:                        log_debug("Picking pool address %s",
        !          1053:                                  inet_ntop(AF_INET6, &((*addr)->addr),
        !          1054:                                            tmp_buf, sizeof(tmp_buf)));
        !          1055:                        return ISC_R_SUCCESS;
        !          1056:                }
        !          1057: 
        !          1058:                i++;
        !          1059:                if (shared_network->ipv6_pools[i] == NULL) {
        !          1060:                        i = 0;
        !          1061:                }
        !          1062:        } while (i != start_pool);
        !          1063: 
        !          1064:        /*
        !          1065:         * If we failed to pick an IPv6 address from any of the subnets.
        !          1066:         * Presumably that means we have no addresses for the client.
        !          1067:         */
        !          1068:        log_debug("Unable to pick client address: no addresses available");
        !          1069:        return ISC_R_NORESOURCES;
        !          1070: }
        !          1071: 
        !          1072: /*
        !          1073:  * Try to get the IPv6 prefix the client asked for from the
        !          1074:  * prefix pool.
        !          1075:  *
        !          1076:  * pref is the result (should be a pointer to NULL on entry)
        !          1077:  * pool is the prefix pool to search in
        !          1078:  * requested_pref is the address the client wants
        !          1079:  */
        !          1080: static isc_result_t
        !          1081: try_client_v6_prefix(struct iasubopt **pref,
        !          1082:                     struct ipv6_pool *pool,
        !          1083:                     const struct data_string *requested_pref)
        !          1084: {
        !          1085:        u_int8_t tmp_plen;
        !          1086:        struct in6_addr tmp_pref;
        !          1087:        struct iaddr ia;
        !          1088:        isc_result_t result;
        !          1089: 
        !          1090:        if (requested_pref->len < sizeof(tmp_plen) + sizeof(tmp_pref)) {
        !          1091:                return ISC_R_INVALIDARG;
        !          1092:        }
        !          1093:        tmp_plen = (int) requested_pref->data[0];
        !          1094:        if ((tmp_plen < 3) || (tmp_plen > 128)) {
        !          1095:                return ISC_R_FAILURE;
        !          1096:        }
        !          1097:        memcpy(&tmp_pref, requested_pref->data + 1, sizeof(tmp_pref));
        !          1098:        if (IN6_IS_ADDR_UNSPECIFIED(&tmp_pref)) {
        !          1099:                return ISC_R_FAILURE;
        !          1100:        }
        !          1101:        ia.len = 16;
        !          1102:        memcpy(&ia.iabuf, &tmp_pref, 16);
        !          1103:        if (!is_cidr_mask_valid(&ia, (int) tmp_plen)) {
        !          1104:                return ISC_R_FAILURE;
        !          1105:        }
        !          1106: 
        !          1107:        if (((int)tmp_plen != pool->units) ||
        !          1108:            !ipv6_in_pool(&tmp_pref, pool)) {
        !          1109:                return ISC_R_FAILURE;
        !          1110:        }
        !          1111: 
        !          1112:        if (prefix6_exists(pool, &tmp_pref, tmp_plen)) {
        !          1113:                return ISC_R_ADDRINUSE;
        !          1114:        }
        !          1115: 
        !          1116:        result = iasubopt_allocate(pref, MDL);
        !          1117:        if (result != ISC_R_SUCCESS) {
        !          1118:                return result;
        !          1119:        }
        !          1120:        (*pref)->addr = tmp_pref;
        !          1121:        (*pref)->plen = tmp_plen;
        !          1122: 
        !          1123:        /* Default is soft binding for 2 minutes. */
        !          1124:        result = add_lease6(pool, *pref, cur_time + 120);
        !          1125:        if (result != ISC_R_SUCCESS) {
        !          1126:                iasubopt_dereference(pref, MDL);
        !          1127:        }
        !          1128:        return result;
        !          1129: }
        !          1130: 
        !          1131: /*
        !          1132:  * Get an IPv6 prefix for the client.
        !          1133:  *
        !          1134:  * pref is the result (should be a pointer to NULL on entry)
        !          1135:  * packet is the information about the packet from the client
        !          1136:  * requested_iaprefix is a hint from the client
        !          1137:  * plen is -1 or the requested prefix length
        !          1138:  * client_id is the DUID for the client
        !          1139:  */
        !          1140: static isc_result_t 
        !          1141: pick_v6_prefix(struct iasubopt **pref, int plen,
        !          1142:               struct shared_network *shared_network,
        !          1143:               const struct data_string *client_id)
        !          1144: {
        !          1145:        struct ipv6_pool *p;
        !          1146:        int i;
        !          1147:        unsigned int attempts;
        !          1148:        char tmp_buf[INET6_ADDRSTRLEN];
        !          1149: 
        !          1150:        /*
        !          1151:         * No prefix pools, we're done.
        !          1152:         */
        !          1153:        if (shared_network->ipv6_pools == NULL) {
        !          1154:                log_debug("Unable to pick client prefix: "
        !          1155:                          "no IPv6 pools on this shared network");
        !          1156:                return ISC_R_NORESOURCES;
        !          1157:        }
        !          1158:        for (i = 0;; i++) {
        !          1159:                p = shared_network->ipv6_pools[i];
        !          1160:                if (p == NULL) {
        !          1161:                        log_debug("Unable to pick client prefix: "
        !          1162:                                  "no IPv6 prefix pools "
        !          1163:                                  "on this shared network");
        !          1164:                        return ISC_R_NORESOURCES;
        !          1165:                }
        !          1166:                if (p->pool_type == D6O_IA_PD) {
        !          1167:                        break;
        !          1168:                }
        !          1169:        }
        !          1170: 
        !          1171:        /*
        !          1172:         * Otherwise try to get a prefix.
        !          1173:         */
        !          1174:        for (i = 0;; i++) {
        !          1175:                p = shared_network->ipv6_pools[i];
        !          1176:                if (p == NULL) {
        !          1177:                        break;
        !          1178:                }
        !          1179:                if (p->pool_type != D6O_IA_PD) {
        !          1180:                        continue;
        !          1181:                }
        !          1182: 
        !          1183:                /*
        !          1184:                 * Try only pools with the requested prefix length if any.
        !          1185:                 */
        !          1186:                if ((plen >= 0) && (p->units != plen)) {
        !          1187:                        continue;
        !          1188:                }
        !          1189: 
        !          1190:                if (create_prefix6(p, pref, &attempts, client_id,
        !          1191:                                   cur_time + 120) == ISC_R_SUCCESS) {
        !          1192:                        log_debug("Picking pool prefix %s/%u",
        !          1193:                                  inet_ntop(AF_INET6, &((*pref)->addr),
        !          1194:                                            tmp_buf, sizeof(tmp_buf)),
        !          1195:                                  (unsigned) (*pref)->plen);
        !          1196:                        return ISC_R_SUCCESS;
        !          1197:                }
        !          1198:        }
        !          1199: 
        !          1200:        /*
        !          1201:         * If we failed to pick an IPv6 prefix
        !          1202:         * Presumably that means we have no prefixes for the client.
        !          1203:         */
        !          1204:        log_debug("Unable to pick client prefix: no prefixes available");
        !          1205:        return ISC_R_NORESOURCES;
        !          1206: }
        !          1207: 
        !          1208: /*
        !          1209:  * lease_to_client() is called from several messages to construct a
        !          1210:  * reply that contains all that we know about the client's correct lease
        !          1211:  * (or projected lease).
        !          1212:  *
        !          1213:  * Solicit - "Soft" binding, ignore unknown addresses or bindings, just
        !          1214:  *          send what we "may" give them on a request.
        !          1215:  *
        !          1216:  * Request - "Hard" binding, but ignore supplied addresses (just provide what
        !          1217:  *          the client should really use).
        !          1218:  *
        !          1219:  * Renew   - "Hard" binding, but client-supplied addresses are 'real'.  Error
        !          1220:  * Rebind    out any "wrong" addresses the client sends.  This means we send
        !          1221:  *          an empty IA_NA with a status code of NoBinding or NotOnLink or
        !          1222:  *          possibly send the address with zeroed lifetimes.
        !          1223:  *
        !          1224:  * Information-Request - No binding.
        !          1225:  *
        !          1226:  * The basic structure is to traverse the client-supplied data first, and
        !          1227:  * validate and echo back any contents that can be.  If the client-supplied
        !          1228:  * data does not error out (on renew/rebind as above), but we did not send
        !          1229:  * any addresses, attempt to allocate one.
        !          1230:  */
        !          1231: /* TODO: look at client hints for lease times */
        !          1232: static void
        !          1233: lease_to_client(struct data_string *reply_ret,
        !          1234:                struct packet *packet, 
        !          1235:                const struct data_string *client_id,
        !          1236:                const struct data_string *server_id)
        !          1237: {
        !          1238:        static struct reply_state reply;
        !          1239:        struct option_cache *oc;
        !          1240:        struct data_string packet_oro;
        !          1241:        isc_boolean_t no_resources_avail;
        !          1242: 
        !          1243:        /* Locate the client.  */
        !          1244:        if (shared_network_from_packet6(&reply.shared,
        !          1245:                                        packet) != ISC_R_SUCCESS)
        !          1246:                goto exit;
        !          1247: 
        !          1248:        /* 
        !          1249:         * Initialize the reply.
        !          1250:         */
        !          1251:        packet_reference(&reply.packet, packet, MDL);
        !          1252:        data_string_copy(&reply.client_id, client_id, MDL);
        !          1253: 
        !          1254:        if (!start_reply(packet, client_id, server_id, &reply.opt_state,
        !          1255:                         &reply.buf.reply))
        !          1256:                goto exit;
        !          1257: 
        !          1258:        /* Set the write cursor to just past the reply header. */
        !          1259:        reply.cursor = REPLY_OPTIONS_INDEX;
        !          1260: 
        !          1261:        /*
        !          1262:         * Get the ORO from the packet, if any.
        !          1263:         */
        !          1264:        oc = lookup_option(&dhcpv6_universe, packet->options, D6O_ORO);
        !          1265:        memset(&packet_oro, 0, sizeof(packet_oro));
        !          1266:        if (oc != NULL) {
        !          1267:                if (!evaluate_option_cache(&packet_oro, packet, 
        !          1268:                                           NULL, NULL, 
        !          1269:                                           packet->options, NULL,
        !          1270:                                           &global_scope, oc, MDL)) {
        !          1271:                        log_error("lease_to_client: error evaluating ORO.");
        !          1272:                        goto exit;
        !          1273:                }
        !          1274:        }
        !          1275: 
        !          1276:        /* 
        !          1277:         * Find a host record that matches from the packet, if any, and is
        !          1278:         * valid for the shared network the client is on.
        !          1279:         */
        !          1280:        if (find_hosts_by_option(&reply.host, packet, packet->options, MDL)) {
        !          1281:                seek_shared_host(&reply.host, reply.shared);
        !          1282:        }
        !          1283: 
        !          1284:        if ((reply.host == NULL) &&
        !          1285:            find_hosts_by_uid(&reply.host, client_id->data, client_id->len,
        !          1286:                              MDL)) {
        !          1287:                seek_shared_host(&reply.host, reply.shared);
        !          1288:        }
        !          1289: 
        !          1290:        /* Process the client supplied IA's onto the reply buffer. */
        !          1291:        reply.ia_count = 0;
        !          1292:        oc = lookup_option(&dhcpv6_universe, packet->options, D6O_IA_NA);
        !          1293:        no_resources_avail = ISC_FALSE;
        !          1294:        for (; oc != NULL ; oc = oc->next) {
        !          1295:                isc_result_t status;
        !          1296: 
        !          1297:                /* Start counting resources (addresses) offered. */
        !          1298:                reply.client_resources = 0;
        !          1299:                reply.resources_included = ISC_FALSE;
        !          1300: 
        !          1301:                status = reply_process_ia_na(&reply, oc);
        !          1302: 
        !          1303:                /*
        !          1304:                 * We continue to try other IA's whether we can address
        !          1305:                 * this one or not.  Any other result is an immediate fail.
        !          1306:                 */
        !          1307:                if ((status != ISC_R_SUCCESS) &&
        !          1308:                    (status != ISC_R_NORESOURCES))
        !          1309:                        goto exit;
        !          1310: 
        !          1311:                /*
        !          1312:                 * If any address cannot be given to any IA, then set the
        !          1313:                 * NoAddrsAvail status code.
        !          1314:                 */
        !          1315:                if (reply.client_resources == 0)
        !          1316:                        no_resources_avail = ISC_TRUE;
        !          1317:        }
        !          1318:        oc = lookup_option(&dhcpv6_universe, packet->options, D6O_IA_TA);
        !          1319:        for (; oc != NULL ; oc = oc->next) {
        !          1320:                isc_result_t status;
        !          1321: 
        !          1322:                /* Start counting resources (addresses) offered. */
        !          1323:                reply.client_resources = 0;
        !          1324:                reply.resources_included = ISC_FALSE;
        !          1325: 
        !          1326:                status = reply_process_ia_ta(&reply, oc);
        !          1327: 
        !          1328:                /*
        !          1329:                 * We continue to try other IA's whether we can address
        !          1330:                 * this one or not.  Any other result is an immediate fail.
        !          1331:                 */
        !          1332:                if ((status != ISC_R_SUCCESS) &&
        !          1333:                    (status != ISC_R_NORESOURCES))
        !          1334:                        goto exit;
        !          1335: 
        !          1336:                /*
        !          1337:                 * If any address cannot be given to any IA, then set the
        !          1338:                 * NoAddrsAvail status code.
        !          1339:                 */
        !          1340:                if (reply.client_resources == 0)
        !          1341:                        no_resources_avail = ISC_TRUE;
        !          1342:        }
        !          1343: 
        !          1344:        /* Same for IA_PD's. */
        !          1345:        reply.pd_count = 0;
        !          1346:        oc = lookup_option(&dhcpv6_universe, packet->options, D6O_IA_PD);
        !          1347:        for (; oc != NULL ; oc = oc->next) {
        !          1348:                isc_result_t status;
        !          1349: 
        !          1350:                /* Start counting resources (prefixes) offered. */
        !          1351:                reply.client_resources = 0;
        !          1352:                reply.resources_included = ISC_FALSE;
        !          1353: 
        !          1354:                status = reply_process_ia_pd(&reply, oc);
        !          1355: 
        !          1356:                /*
        !          1357:                 * We continue to try other IA_PD's whether we can address
        !          1358:                 * this one or not.  Any other result is an immediate fail.
        !          1359:                 */
        !          1360:                if ((status != ISC_R_SUCCESS) &&
        !          1361:                    (status != ISC_R_NORESOURCES))
        !          1362:                        goto exit;
        !          1363: 
        !          1364:                /*
        !          1365:                 * If any prefix cannot be given to any IA_PD, then
        !          1366:                 * set the NoPrefixAvail status code.
        !          1367:                 */
        !          1368:                if (reply.client_resources == 0)
        !          1369:                        no_resources_avail = ISC_TRUE;
        !          1370:        }
        !          1371: 
        !          1372:        /*
        !          1373:         * Make no reply if we gave no resources and is not
        !          1374:         * for Information-Request.
        !          1375:         */
        !          1376:        if ((reply.ia_count == 0) && (reply.pd_count == 0)) {
        !          1377:                if (reply.packet->dhcpv6_msg_type !=
        !          1378:                                            DHCPV6_INFORMATION_REQUEST)
        !          1379:                        goto exit;
        !          1380: 
        !          1381:                /*
        !          1382:                 * Because we only execute statements on a per-IA basis,
        !          1383:                 * we need to execute statements in any non-IA reply to
        !          1384:                 * source configuration.
        !          1385:                 */
        !          1386:                execute_statements_in_scope(NULL, reply.packet, NULL, NULL,
        !          1387:                                            reply.packet->options,
        !          1388:                                            reply.opt_state, &global_scope,
        !          1389:                                            reply.shared->group, root_group);
        !          1390: 
        !          1391:                /* Bring in any configuration from a host record. */
        !          1392:                if (reply.host != NULL)
        !          1393:                        execute_statements_in_scope(NULL, reply.packet, NULL,
        !          1394:                                                    NULL, reply.packet->options,
        !          1395:                                                    reply.opt_state,
        !          1396:                                                    &global_scope,
        !          1397:                                                    reply.host->group,
        !          1398:                                                    reply.shared->group);
        !          1399:        }
        !          1400: 
        !          1401:        /*
        !          1402:         * RFC3315 section 17.2.2 (Solicit):
        !          1403:         *
        !          1404:         * If the server will not assign any addresses to any IAs in a
        !          1405:         * subsequent Request from the client, the server MUST send an
        !          1406:         * Advertise message to the client that includes only a Status
        !          1407:         * Code option with code NoAddrsAvail and a status message for
        !          1408:         * the user, a Server Identifier option with the server's DUID,
        !          1409:         * and a Client Identifier option with the client's DUID.
        !          1410:         *
        !          1411:         * Section 18.2.1 (Request):
        !          1412:         *
        !          1413:         * If the server cannot assign any addresses to an IA in the
        !          1414:         * message from the client, the server MUST include the IA in
        !          1415:         * the Reply message with no addresses in the IA and a Status
        !          1416:         * Code option in the IA containing status code NoAddrsAvail.
        !          1417:         *
        !          1418:         * Section 18.1.8 (Client Behavior):
        !          1419:         *
        !          1420:         * Leave unchanged any information about addresses the client has
        !          1421:         * recorded in the IA but that were not included in the IA from
        !          1422:         * the server.
        !          1423:         * Sends a Renew/Rebind if the IA is not in the Reply message.
        !          1424:         */
        !          1425:        if (no_resources_avail && (reply.ia_count != 0) &&
        !          1426:            (reply.packet->dhcpv6_msg_type == DHCPV6_SOLICIT))
        !          1427:        {
        !          1428:                /* Set the NoAddrsAvail status code. */
        !          1429:                if (!set_status_code(STATUS_NoAddrsAvail,
        !          1430:                                     "No addresses available for this "
        !          1431:                                     "interface.", reply.opt_state)) {
        !          1432:                        log_error("lease_to_client: Unable to set "
        !          1433:                                  "NoAddrsAvail status code.");
        !          1434:                        goto exit;
        !          1435:                }
        !          1436: 
        !          1437:                /* Rewind the cursor to the start. */
        !          1438:                reply.cursor = REPLY_OPTIONS_INDEX;
        !          1439: 
        !          1440:                /*
        !          1441:                 * Produce an advertise that includes only:
        !          1442:                 *
        !          1443:                 * Status code.
        !          1444:                 * Server DUID.
        !          1445:                 * Client DUID.
        !          1446:                 */
        !          1447:                reply.buf.reply.msg_type = DHCPV6_ADVERTISE;
        !          1448:                reply.cursor += store_options6((char *)reply.buf.data +
        !          1449:                                                        reply.cursor,
        !          1450:                                               sizeof(reply.buf) -
        !          1451:                                                        reply.cursor,
        !          1452:                                               reply.opt_state, reply.packet,
        !          1453:                                               required_opts_NAA,
        !          1454:                                               NULL);
        !          1455:        } else if (no_resources_avail && (reply.ia_count == 0) &&
        !          1456:                   (reply.packet->dhcpv6_msg_type == DHCPV6_SOLICIT))
        !          1457:        {
        !          1458:                /* Set the NoPrefixAvail status code. */
        !          1459:                if (!set_status_code(STATUS_NoPrefixAvail,
        !          1460:                                     "No prefixes available for this "
        !          1461:                                     "interface.", reply.opt_state)) {
        !          1462:                        log_error("lease_to_client: Unable to set "
        !          1463:                                  "NoPrefixAvail status code.");
        !          1464:                        goto exit;
        !          1465:                }
        !          1466: 
        !          1467:                /* Rewind the cursor to the start. */
        !          1468:                reply.cursor = REPLY_OPTIONS_INDEX;
        !          1469: 
        !          1470:                /*
        !          1471:                 * Produce an advertise that includes only:
        !          1472:                 *
        !          1473:                 * Status code.
        !          1474:                 * Server DUID.
        !          1475:                 * Client DUID.
        !          1476:                 */
        !          1477:                reply.buf.reply.msg_type = DHCPV6_ADVERTISE;
        !          1478:                reply.cursor += store_options6((char *)reply.buf.data +
        !          1479:                                                        reply.cursor,
        !          1480:                                               sizeof(reply.buf) -
        !          1481:                                                        reply.cursor,
        !          1482:                                               reply.opt_state, reply.packet,
        !          1483:                                               required_opts_NAA,
        !          1484:                                               NULL);
        !          1485:        } else {
        !          1486:                /*
        !          1487:                 * Having stored the client's IA's, store any options that
        !          1488:                 * will fit in the remaining space.
        !          1489:                 */
        !          1490:                reply.cursor += store_options6((char *)reply.buf.data +
        !          1491:                                                        reply.cursor,
        !          1492:                                               sizeof(reply.buf) -
        !          1493:                                                        reply.cursor,
        !          1494:                                               reply.opt_state, reply.packet,
        !          1495:                                               required_opts_solicit,
        !          1496:                                               &packet_oro);
        !          1497:        }
        !          1498: 
        !          1499:        /* Return our reply to the caller. */
        !          1500:        reply_ret->len = reply.cursor;
        !          1501:        reply_ret->buffer = NULL;
        !          1502:        if (!buffer_allocate(&reply_ret->buffer, reply.cursor, MDL)) {
        !          1503:                log_fatal("No memory to store Reply.");
        !          1504:        }
        !          1505:        memcpy(reply_ret->buffer->data, reply.buf.data, reply.cursor);
        !          1506:        reply_ret->data = reply_ret->buffer->data;
        !          1507: 
        !          1508:       exit:
        !          1509:        /* Cleanup. */
        !          1510:        if (reply.shared != NULL)
        !          1511:                shared_network_dereference(&reply.shared, MDL);
        !          1512:        if (reply.host != NULL)
        !          1513:                host_dereference(&reply.host, MDL);
        !          1514:        if (reply.opt_state != NULL)
        !          1515:                option_state_dereference(&reply.opt_state, MDL);
        !          1516:        if (reply.packet != NULL)
        !          1517:                packet_dereference(&reply.packet, MDL);
        !          1518:        if (reply.client_id.data != NULL)
        !          1519:                data_string_forget(&reply.client_id, MDL);
        !          1520:        reply.renew = reply.rebind = reply.prefer = reply.valid = 0;
        !          1521:        reply.cursor = 0;
        !          1522: }
        !          1523: 
        !          1524: /* Process a client-supplied IA_NA.  This may append options to the tail of
        !          1525:  * the reply packet being built in the reply_state structure.
        !          1526:  */
        !          1527: static isc_result_t
        !          1528: reply_process_ia_na(struct reply_state *reply, struct option_cache *ia) {
        !          1529:        isc_result_t status = ISC_R_SUCCESS;
        !          1530:        u_int32_t iaid;
        !          1531:        unsigned ia_cursor;
        !          1532:        struct option_state *packet_ia;
        !          1533:        struct option_cache *oc;
        !          1534:        struct data_string ia_data, data;
        !          1535: 
        !          1536:        /* Initialize values that will get cleaned up on return. */
        !          1537:        packet_ia = NULL;
        !          1538:        memset(&ia_data, 0, sizeof(ia_data));
        !          1539:        memset(&data, 0, sizeof(data));
        !          1540:        /* 
        !          1541:         * Note that find_client_address() may set reply->lease. 
        !          1542:         */
        !          1543: 
        !          1544:        /* Make sure there is at least room for the header. */
        !          1545:        if ((reply->cursor + IA_NA_OFFSET + 4) > sizeof(reply->buf)) {
        !          1546:                log_error("reply_process_ia_na: Reply too long for IA.");
        !          1547:                return ISC_R_NOSPACE;
        !          1548:        }
        !          1549: 
        !          1550: 
        !          1551:        /* Fetch the IA_NA contents. */
        !          1552:        if (!get_encapsulated_IA_state(&packet_ia, &ia_data, reply->packet,
        !          1553:                                       ia, IA_NA_OFFSET)) {
        !          1554:                log_error("reply_process_ia_na: error evaluating ia");
        !          1555:                status = ISC_R_FAILURE;
        !          1556:                goto cleanup;
        !          1557:        }
        !          1558: 
        !          1559:        /* Extract IA_NA header contents. */
        !          1560:        iaid = getULong(ia_data.data);
        !          1561:        reply->renew = getULong(ia_data.data + 4);
        !          1562:        reply->rebind = getULong(ia_data.data + 8);
        !          1563: 
        !          1564:        /* Create an IA_NA structure. */
        !          1565:        if (ia_allocate(&reply->ia, iaid, (char *)reply->client_id.data, 
        !          1566:                        reply->client_id.len, MDL) != ISC_R_SUCCESS) {
        !          1567:                log_error("reply_process_ia_na: no memory for ia.");
        !          1568:                status = ISC_R_NOMEMORY;
        !          1569:                goto cleanup;
        !          1570:        }
        !          1571:        reply->ia->ia_type = D6O_IA_NA;
        !          1572: 
        !          1573:        /* Cache pre-existing IA, if any. */
        !          1574:        ia_hash_lookup(&reply->old_ia, ia_na_active,
        !          1575:                       (unsigned char *)reply->ia->iaid_duid.data,
        !          1576:                       reply->ia->iaid_duid.len, MDL);
        !          1577: 
        !          1578:        /*
        !          1579:         * Create an option cache to carry the IA_NA option contents, and
        !          1580:         * execute any user-supplied values into it.
        !          1581:         */
        !          1582:        if (!option_state_allocate(&reply->reply_ia, MDL)) {
        !          1583:                status = ISC_R_NOMEMORY;
        !          1584:                goto cleanup;
        !          1585:        }
        !          1586: 
        !          1587:        /* Check & cache the fixed host record. */
        !          1588:        if ((reply->host != NULL) && (reply->host->fixed_addr != NULL)) {
        !          1589:                struct iaddr tmp_addr;
        !          1590: 
        !          1591:                if (!evaluate_option_cache(&reply->fixed, NULL, NULL, NULL,
        !          1592:                                           NULL, NULL, &global_scope,
        !          1593:                                           reply->host->fixed_addr, MDL)) {
        !          1594:                        log_error("reply_process_ia_na: unable to evaluate "
        !          1595:                                  "fixed address.");
        !          1596:                        status = ISC_R_FAILURE;
        !          1597:                        goto cleanup;
        !          1598:                }
        !          1599: 
        !          1600:                if (reply->fixed.len < 16) {
        !          1601:                        log_error("reply_process_ia_na: invalid fixed address.");
        !          1602:                        status = ISC_R_INVALIDARG;
        !          1603:                        goto cleanup;
        !          1604:                }
        !          1605: 
        !          1606:                /* Find the static lease's subnet. */
        !          1607:                tmp_addr.len = 16;
        !          1608:                memcpy(tmp_addr.iabuf, reply->fixed.data, 16);
        !          1609: 
        !          1610:                if (find_grouped_subnet(&reply->subnet, reply->shared,
        !          1611:                                        tmp_addr, MDL) == 0)
        !          1612:                        log_fatal("Impossible condition at %s:%d.", MDL);
        !          1613: 
        !          1614:                reply->static_lease = ISC_TRUE;
        !          1615:        } else
        !          1616:                reply->static_lease = ISC_FALSE;
        !          1617: 
        !          1618:        /*
        !          1619:         * Save the cursor position at the start of the IA, so we can
        !          1620:         * set length and adjust t1/t2 values later.  We write a temporary
        !          1621:         * header out now just in case we decide to adjust the packet
        !          1622:         * within sub-process functions.
        !          1623:         */
        !          1624:        ia_cursor = reply->cursor;
        !          1625: 
        !          1626:        /* Initialize the IA_NA header.  First the code. */
        !          1627:        putUShort(reply->buf.data + reply->cursor, (unsigned)D6O_IA_NA);
        !          1628:        reply->cursor += 2;
        !          1629: 
        !          1630:        /* Then option length. */
        !          1631:        putUShort(reply->buf.data + reply->cursor, 0x0Cu);
        !          1632:        reply->cursor += 2;
        !          1633: 
        !          1634:        /* Then IA_NA header contents; IAID. */
        !          1635:        putULong(reply->buf.data + reply->cursor, iaid);
        !          1636:        reply->cursor += 4;
        !          1637: 
        !          1638:        /* We store the client's t1 for now, and may over-ride it later. */
        !          1639:        putULong(reply->buf.data + reply->cursor, reply->renew);
        !          1640:        reply->cursor += 4;
        !          1641: 
        !          1642:        /* We store the client's t2 for now, and may over-ride it later. */
        !          1643:        putULong(reply->buf.data + reply->cursor, reply->rebind);
        !          1644:        reply->cursor += 4;
        !          1645: 
        !          1646:        /* 
        !          1647:         * For each address in this IA_NA, decide what to do about it.
        !          1648:         *
        !          1649:         * Guidelines:
        !          1650:         *
        !          1651:         * The client leaves unchanged any infomation about addresses
        !          1652:         * it has recorded but are not included ("cancel/break" below).
        !          1653:         * A not included IA ("cleanup" below) could give a Renew/Rebind.
        !          1654:         */
        !          1655:        oc = lookup_option(&dhcpv6_universe, packet_ia, D6O_IAADDR);
        !          1656:        reply->valid = reply->prefer = 0xffffffff;
        !          1657:        reply->client_valid = reply->client_prefer = 0;
        !          1658:        for (; oc != NULL ; oc = oc->next) {
        !          1659:                status = reply_process_addr(reply, oc);
        !          1660: 
        !          1661:                /*
        !          1662:                 * Canceled means we did not allocate addresses to the
        !          1663:                 * client, but we're "done" with this IA - we set a status
        !          1664:                 * code.  So transmit this reply, e.g., move on to the next
        !          1665:                 * IA.
        !          1666:                 */
        !          1667:                if (status == ISC_R_CANCELED)
        !          1668:                        break;
        !          1669: 
        !          1670:                if ((status != ISC_R_SUCCESS) &&
        !          1671:                    (status != ISC_R_ADDRINUSE) &&
        !          1672:                    (status != ISC_R_ADDRNOTAVAIL))
        !          1673:                        goto cleanup;
        !          1674:        }
        !          1675: 
        !          1676:        reply->ia_count++;
        !          1677: 
        !          1678:        /*
        !          1679:         * If we fell through the above and never gave the client
        !          1680:         * an address, give it one now.
        !          1681:         */
        !          1682:        if ((status != ISC_R_CANCELED) && (reply->client_resources == 0)) {
        !          1683:                status = find_client_address(reply);
        !          1684: 
        !          1685:                if (status == ISC_R_NORESOURCES) {
        !          1686:                        switch (reply->packet->dhcpv6_msg_type) {
        !          1687:                              case DHCPV6_SOLICIT:
        !          1688:                                /*
        !          1689:                                 * No address for any IA is handled
        !          1690:                                 * by the caller.
        !          1691:                                 */
        !          1692:                                /* FALL THROUGH */
        !          1693: 
        !          1694:                              case DHCPV6_REQUEST:
        !          1695:                                /* Section 18.2.1 (Request):
        !          1696:                                 *
        !          1697:                                 * If the server cannot assign any addresses to
        !          1698:                                 * an IA in the message from the client, the
        !          1699:                                 * server MUST include the IA in the Reply
        !          1700:                                 * message with no addresses in the IA and a
        !          1701:                                 * Status Code option in the IA containing
        !          1702:                                 * status code NoAddrsAvail.
        !          1703:                                 */
        !          1704:                                option_state_dereference(&reply->reply_ia, MDL);
        !          1705:                                if (!option_state_allocate(&reply->reply_ia,
        !          1706:                                                           MDL))
        !          1707:                                {
        !          1708:                                        log_error("reply_process_ia_na: No "
        !          1709:                                                  "memory for option state "
        !          1710:                                                  "wipe.");
        !          1711:                                        status = ISC_R_NOMEMORY;
        !          1712:                                        goto cleanup;
        !          1713:                                }
        !          1714: 
        !          1715:                                if (!set_status_code(STATUS_NoAddrsAvail,
        !          1716:                                                     "No addresses available "
        !          1717:                                                     "for this interface.",
        !          1718:                                                      reply->reply_ia)) {
        !          1719:                                        log_error("reply_process_ia_na: Unable "
        !          1720:                                                  "to set NoAddrsAvail status "
        !          1721:                                                  "code.");
        !          1722:                                        status = ISC_R_FAILURE;
        !          1723:                                        goto cleanup;
        !          1724:                                }
        !          1725: 
        !          1726:                                status = ISC_R_SUCCESS;
        !          1727:                                break;
        !          1728: 
        !          1729:                              default:
        !          1730:                                /*
        !          1731:                                 * RFC 3315 does not tell us to emit a status
        !          1732:                                 * code in this condition, or anything else.
        !          1733:                                 *
        !          1734:                                 * If we included non-allocated addresses
        !          1735:                                 * (zeroed lifetimes) in an IA, then the client
        !          1736:                                 * will deconfigure them.
        !          1737:                                 *
        !          1738:                                 * So we want to include the IA even if we
        !          1739:                                 * can't give it a new address if it includes
        !          1740:                                 * zeroed lifetime addresses.
        !          1741:                                 *
        !          1742:                                 * We don't want to include the IA if we
        !          1743:                                 * provide zero addresses including zeroed
        !          1744:                                 * lifetimes.
        !          1745:                                 */
        !          1746:                                if (reply->resources_included)
        !          1747:                                        status = ISC_R_SUCCESS;
        !          1748:                                else
        !          1749:                                        goto cleanup;
        !          1750:                                break;
        !          1751:                        }
        !          1752:                }
        !          1753: 
        !          1754:                if (status != ISC_R_SUCCESS)
        !          1755:                        goto cleanup;
        !          1756:        }
        !          1757: 
        !          1758:        reply->cursor += store_options6((char *)reply->buf.data + reply->cursor,
        !          1759:                                        sizeof(reply->buf) - reply->cursor,
        !          1760:                                        reply->reply_ia, reply->packet,
        !          1761:                                        required_opts_IA, NULL);
        !          1762: 
        !          1763:        /* Reset the length of this IA to match what was just written. */
        !          1764:        putUShort(reply->buf.data + ia_cursor + 2,
        !          1765:                  reply->cursor - (ia_cursor + 4));
        !          1766: 
        !          1767:        /*
        !          1768:         * T1/T2 time selection is kind of weird.  We actually use DHCP
        !          1769:         * (v4) scoped options as handy existing places where these might
        !          1770:         * be configured by an administrator.  A value of zero tells the
        !          1771:         * client it may choose its own renewal time.
        !          1772:         */
        !          1773:        reply->renew = 0;
        !          1774:        oc = lookup_option(&dhcp_universe, reply->opt_state,
        !          1775:                           DHO_DHCP_RENEWAL_TIME);
        !          1776:        if (oc != NULL) {
        !          1777:                if (!evaluate_option_cache(&data, reply->packet, NULL, NULL,
        !          1778:                                           reply->packet->options,
        !          1779:                                           reply->opt_state, &global_scope,
        !          1780:                                           oc, MDL) ||
        !          1781:                    (data.len != 4)) {
        !          1782:                        log_error("Invalid renewal time.");
        !          1783:                } else {
        !          1784:                        reply->renew = getULong(data.data);
        !          1785:                }
        !          1786: 
        !          1787:                if (data.data != NULL)
        !          1788:                        data_string_forget(&data, MDL);
        !          1789:        }
        !          1790:        putULong(reply->buf.data + ia_cursor + 8, reply->renew);
        !          1791: 
        !          1792:        /* Now T2. */
        !          1793:        reply->rebind = 0;
        !          1794:        oc = lookup_option(&dhcp_universe, reply->opt_state,
        !          1795:                           DHO_DHCP_REBINDING_TIME);
        !          1796:        if (oc != NULL) {
        !          1797:                if (!evaluate_option_cache(&data, reply->packet, NULL, NULL,
        !          1798:                                           reply->packet->options,
        !          1799:                                           reply->opt_state, &global_scope,
        !          1800:                                           oc, MDL) ||
        !          1801:                    (data.len != 4)) {
        !          1802:                        log_error("Invalid rebinding time.");
        !          1803:                } else {
        !          1804:                        reply->rebind = getULong(data.data);
        !          1805:                }
        !          1806: 
        !          1807:                if (data.data != NULL)
        !          1808:                        data_string_forget(&data, MDL);
        !          1809:        }
        !          1810:        putULong(reply->buf.data + ia_cursor + 12, reply->rebind);
        !          1811: 
        !          1812:        /*
        !          1813:         * If this is not a 'soft' binding, consume the new changes into
        !          1814:         * the database (if any have been attached to the ia_na).
        !          1815:         *
        !          1816:         * Loop through the assigned dynamic addresses, referencing the
        !          1817:         * leases onto this IA_NA rather than any old ones, and updating
        !          1818:         * pool timers for each (if any).
        !          1819:         */
        !          1820:        if ((status != ISC_R_CANCELED) && !reply->static_lease &&
        !          1821:            (reply->buf.reply.msg_type == DHCPV6_REPLY) &&
        !          1822:            (reply->ia->num_iasubopt != 0)) {
        !          1823:                struct iasubopt *tmp;
        !          1824:                struct data_string *ia_id;
        !          1825:                int i;
        !          1826: 
        !          1827:                for (i = 0 ; i < reply->ia->num_iasubopt ; i++) {
        !          1828:                        tmp = reply->ia->iasubopt[i];
        !          1829: 
        !          1830:                        if (tmp->ia != NULL)
        !          1831:                                ia_dereference(&tmp->ia, MDL);
        !          1832:                        ia_reference(&tmp->ia, reply->ia, MDL);
        !          1833: 
        !          1834:                        /* Commit 'hard' bindings. */
        !          1835:                        tmp->hard_lifetime_end_time =
        !          1836:                                tmp->soft_lifetime_end_time;
        !          1837:                        tmp->soft_lifetime_end_time = 0;
        !          1838:                        renew_lease6(tmp->ipv6_pool, tmp);
        !          1839:                        schedule_lease_timeout(tmp->ipv6_pool);
        !          1840: 
        !          1841:                        /*
        !          1842:                         * Perform ddns updates.
        !          1843:                         */
        !          1844:                        oc = lookup_option(&server_universe, reply->opt_state,
        !          1845:                                           SV_DDNS_UPDATES);
        !          1846:                        if ((oc == NULL) ||
        !          1847:                            evaluate_boolean_option_cache(NULL, reply->packet,
        !          1848:                                                          NULL, NULL,
        !          1849:                                                        reply->packet->options,
        !          1850:                                                          reply->opt_state,
        !          1851:                                                          &tmp->scope,
        !          1852:                                                          oc, MDL)) {
        !          1853:                                ddns_updates(reply->packet, NULL, NULL,
        !          1854:                                             tmp, NULL, reply->opt_state);
        !          1855:                        }
        !          1856:                }
        !          1857: 
        !          1858:                /* Remove any old ia from the hash. */
        !          1859:                if (reply->old_ia != NULL) {
        !          1860:                        ia_id = &reply->old_ia->iaid_duid;
        !          1861:                        ia_hash_delete(ia_na_active,
        !          1862:                                       (unsigned char *)ia_id->data,
        !          1863:                                       ia_id->len, MDL);
        !          1864:                        ia_dereference(&reply->old_ia, MDL);
        !          1865:                }
        !          1866: 
        !          1867:                /* Put new ia into the hash. */
        !          1868:                reply->ia->cltt = cur_time;
        !          1869:                ia_id = &reply->ia->iaid_duid;
        !          1870:                ia_hash_add(ia_na_active, (unsigned char *)ia_id->data,
        !          1871:                            ia_id->len, reply->ia, MDL);
        !          1872: 
        !          1873:                write_ia(reply->ia);
        !          1874:        }
        !          1875: 
        !          1876:       cleanup:
        !          1877:        if (packet_ia != NULL)
        !          1878:                option_state_dereference(&packet_ia, MDL);
        !          1879:        if (reply->reply_ia != NULL)
        !          1880:                option_state_dereference(&reply->reply_ia, MDL);
        !          1881:        if (ia_data.data != NULL)
        !          1882:                data_string_forget(&ia_data, MDL);
        !          1883:        if (data.data != NULL)
        !          1884:                data_string_forget(&data, MDL);
        !          1885:        if (reply->ia != NULL)
        !          1886:                ia_dereference(&reply->ia, MDL);
        !          1887:        if (reply->old_ia != NULL)
        !          1888:                ia_dereference(&reply->old_ia, MDL);
        !          1889:        if (reply->lease != NULL)
        !          1890:                iasubopt_dereference(&reply->lease, MDL);
        !          1891:        if (reply->fixed.data != NULL)
        !          1892:                data_string_forget(&reply->fixed, MDL);
        !          1893:        if (reply->subnet != NULL)
        !          1894:                subnet_dereference(&reply->subnet, MDL);
        !          1895: 
        !          1896:        /*
        !          1897:         * ISC_R_CANCELED is a status code used by the addr processing to
        !          1898:         * indicate we're replying with a status code.  This is still a
        !          1899:         * success at higher layers.
        !          1900:         */
        !          1901:        return((status == ISC_R_CANCELED) ? ISC_R_SUCCESS : status);
        !          1902: }
        !          1903: 
        !          1904: /*
        !          1905:  * Process an IAADDR within a given IA_xA, storing any IAADDR reply contents
        !          1906:  * into the reply's current ia-scoped option cache.  Returns ISC_R_CANCELED
        !          1907:  * in the event we are replying with a status code and do not wish to process
        !          1908:  * more IAADDRs within this IA.
        !          1909:  */
        !          1910: static isc_result_t
        !          1911: reply_process_addr(struct reply_state *reply, struct option_cache *addr) {
        !          1912:        u_int32_t pref_life, valid_life;
        !          1913:        struct binding_scope **scope;
        !          1914:        struct group *group;
        !          1915:        struct subnet *subnet;
        !          1916:        struct iaddr tmp_addr;
        !          1917:        struct option_cache *oc;
        !          1918:        struct data_string iaaddr, data;
        !          1919:        isc_result_t status = ISC_R_SUCCESS;
        !          1920: 
        !          1921:        /* Initializes values that will be cleaned up. */
        !          1922:        memset(&iaaddr, 0, sizeof(iaaddr));
        !          1923:        memset(&data, 0, sizeof(data));
        !          1924:        /* Note that reply->lease may be set by address_is_owned() */
        !          1925: 
        !          1926:        /*
        !          1927:         * There is no point trying to process an incoming address if there
        !          1928:         * is no room for an outgoing address.
        !          1929:         */
        !          1930:        if ((reply->cursor + 28) > sizeof(reply->buf)) {
        !          1931:                log_error("reply_process_addr: Out of room for address.");
        !          1932:                return ISC_R_NOSPACE;
        !          1933:        }
        !          1934: 
        !          1935:        /* Extract this IAADDR option. */
        !          1936:        if (!evaluate_option_cache(&iaaddr, reply->packet, NULL, NULL, 
        !          1937:                                   reply->packet->options, NULL, &global_scope,
        !          1938:                                   addr, MDL) ||
        !          1939:            (iaaddr.len < IAADDR_OFFSET)) {
        !          1940:                log_error("reply_process_addr: error evaluating IAADDR.");
        !          1941:                status = ISC_R_FAILURE;
        !          1942:                goto cleanup;
        !          1943:        }
        !          1944: 
        !          1945:        /* The first 16 bytes are the IPv6 address. */
        !          1946:        pref_life = getULong(iaaddr.data + 16);
        !          1947:        valid_life = getULong(iaaddr.data + 20);
        !          1948: 
        !          1949:        if ((reply->client_valid == 0) ||
        !          1950:            (reply->client_valid > valid_life))
        !          1951:                reply->client_valid = valid_life;
        !          1952: 
        !          1953:        if ((reply->client_prefer == 0) ||
        !          1954:            (reply->client_prefer > pref_life))
        !          1955:                reply->client_prefer = pref_life;
        !          1956: 
        !          1957:        /* 
        !          1958:         * Clients may choose to send :: as an address, with the idea to give
        !          1959:         * hints about preferred-lifetime or valid-lifetime.
        !          1960:         */
        !          1961:        tmp_addr.len = 16;
        !          1962:        memset(tmp_addr.iabuf, 0, 16);
        !          1963:        if (!memcmp(iaaddr.data, tmp_addr.iabuf, 16)) {
        !          1964:                /* Status remains success; we just ignore this one. */
        !          1965:                goto cleanup;
        !          1966:        }
        !          1967: 
        !          1968:        /* tmp_addr len remains 16 */
        !          1969:        memcpy(tmp_addr.iabuf, iaaddr.data, 16);
        !          1970: 
        !          1971:        /*
        !          1972:         * Verify that this address is on the client's network.
        !          1973:         */
        !          1974:        for (subnet = reply->shared->subnets ; subnet != NULL ;
        !          1975:             subnet = subnet->next_sibling) {
        !          1976:                if (addr_eq(subnet_number(tmp_addr, subnet->netmask),
        !          1977:                            subnet->net))
        !          1978:                        break;
        !          1979:        }
        !          1980: 
        !          1981:        /* Address not found on shared network. */
        !          1982:        if (subnet == NULL) {
        !          1983:                /* Ignore this address on 'soft' bindings. */
        !          1984:                if (reply->packet->dhcpv6_msg_type == DHCPV6_SOLICIT) {
        !          1985:                        /* disable rapid commit */
        !          1986:                        reply->buf.reply.msg_type = DHCPV6_ADVERTISE;
        !          1987:                        delete_option(&dhcpv6_universe,
        !          1988:                                      reply->opt_state,
        !          1989:                                      D6O_RAPID_COMMIT);
        !          1990:                        /* status remains success */
        !          1991:                        goto cleanup;
        !          1992:                }
        !          1993: 
        !          1994:                /*
        !          1995:                 * RFC3315 section 18.2.1:
        !          1996:                 *
        !          1997:                 * If the server finds that the prefix on one or more IP
        !          1998:                 * addresses in any IA in the message from the client is not
        !          1999:                 * appropriate for the link to which the client is connected,
        !          2000:                 * the server MUST return the IA to the client with a Status
        !          2001:                 * Code option with the value NotOnLink.
        !          2002:                 */
        !          2003:                if (reply->packet->dhcpv6_msg_type == DHCPV6_REQUEST) {
        !          2004:                        /* Rewind the IA_NA to empty. */
        !          2005:                        option_state_dereference(&reply->reply_ia, MDL);
        !          2006:                        if (!option_state_allocate(&reply->reply_ia, MDL)) {
        !          2007:                                log_error("reply_process_addr: No memory for "
        !          2008:                                          "option state wipe.");
        !          2009:                                status = ISC_R_NOMEMORY;
        !          2010:                                goto cleanup;
        !          2011:                        }
        !          2012: 
        !          2013:                        /* Append a NotOnLink status code. */
        !          2014:                        if (!set_status_code(STATUS_NotOnLink,
        !          2015:                                             "Address not for use on this "
        !          2016:                                             "link.", reply->reply_ia)) {
        !          2017:                                log_error("reply_process_addr: Failure "
        !          2018:                                          "setting status code.");
        !          2019:                                status = ISC_R_FAILURE;
        !          2020:                                goto cleanup;
        !          2021:                        }
        !          2022: 
        !          2023:                        /* Fin (no more IAADDRs). */
        !          2024:                        status = ISC_R_CANCELED;
        !          2025:                        goto cleanup;
        !          2026:                }
        !          2027: 
        !          2028:                /*
        !          2029:                 * RFC3315 sections 18.2.3 and 18.2.4 have identical language:
        !          2030:                 *
        !          2031:                 * If the server finds that any of the addresses are not
        !          2032:                 * appropriate for the link to which the client is attached,
        !          2033:                 * the server returns the address to the client with lifetimes
        !          2034:                 * of 0.
        !          2035:                 */
        !          2036:                if ((reply->packet->dhcpv6_msg_type != DHCPV6_RENEW) &&
        !          2037:                    (reply->packet->dhcpv6_msg_type != DHCPV6_REBIND)) {
        !          2038:                        log_error("It is impossible to lease a client that is "
        !          2039:                                  "not sending a solicit, request, renew, or "
        !          2040:                                  "rebind.");
        !          2041:                        status = ISC_R_FAILURE;
        !          2042:                        goto cleanup;
        !          2043:                }
        !          2044: 
        !          2045:                reply->send_prefer = reply->send_valid = 0;
        !          2046:                goto send_addr;
        !          2047:        }
        !          2048: 
        !          2049:        /* Verify the address belongs to the client. */
        !          2050:        if (!address_is_owned(reply, &tmp_addr)) {
        !          2051:                /*
        !          2052:                 * For solicit and request, any addresses included are
        !          2053:                 * 'requested' addresses.  For rebind, we actually have
        !          2054:                 * no direction on what to do from 3315 section 18.2.4!
        !          2055:                 * So I think the best bet is to try and give it out, and if
        !          2056:                 * we can't, zero lifetimes.
        !          2057:                 */
        !          2058:                if ((reply->packet->dhcpv6_msg_type == DHCPV6_SOLICIT) ||
        !          2059:                    (reply->packet->dhcpv6_msg_type == DHCPV6_REQUEST) ||
        !          2060:                    (reply->packet->dhcpv6_msg_type == DHCPV6_REBIND)) {
        !          2061:                        status = reply_process_try_addr(reply, &tmp_addr);
        !          2062: 
        !          2063:                        /*
        !          2064:                         * If the address is in use, or isn't in any dynamic
        !          2065:                         * range, continue as normal.  If any other error was
        !          2066:                         * found, error out.
        !          2067:                         */
        !          2068:                        if ((status != ISC_R_SUCCESS) && 
        !          2069:                            (status != ISC_R_ADDRINUSE) &&
        !          2070:                            (status != ISC_R_ADDRNOTAVAIL))
        !          2071:                                goto cleanup;
        !          2072: 
        !          2073:                        /*
        !          2074:                         * If we didn't honor this lease, for solicit and
        !          2075:                         * request we simply omit it from our answer.  For
        !          2076:                         * rebind, we send it with zeroed lifetimes.
        !          2077:                         */
        !          2078:                        if (reply->lease == NULL) {
        !          2079:                                if (reply->packet->dhcpv6_msg_type ==
        !          2080:                                                        DHCPV6_REBIND) {
        !          2081:                                        reply->send_prefer = 0;
        !          2082:                                        reply->send_valid = 0;
        !          2083:                                        goto send_addr;
        !          2084:                                }
        !          2085: 
        !          2086:                                /* status remains success - ignore */
        !          2087:                                goto cleanup;
        !          2088:                        }
        !          2089:                /*
        !          2090:                 * RFC3315 section 18.2.3:
        !          2091:                 *
        !          2092:                 * If the server cannot find a client entry for the IA the
        !          2093:                 * server returns the IA containing no addresses with a Status
        !          2094:                 * Code option set to NoBinding in the Reply message.
        !          2095:                 *
        !          2096:                 * On mismatch we (ab)use this pretending we have not the IA
        !          2097:                 * as soon as we have not an address.
        !          2098:                 */
        !          2099:                } else if (reply->packet->dhcpv6_msg_type == DHCPV6_RENEW) {
        !          2100:                        /* Rewind the IA_NA to empty. */
        !          2101:                        option_state_dereference(&reply->reply_ia, MDL);
        !          2102:                        if (!option_state_allocate(&reply->reply_ia, MDL)) {
        !          2103:                                log_error("reply_process_addr: No memory for "
        !          2104:                                          "option state wipe.");
        !          2105:                                status = ISC_R_NOMEMORY;
        !          2106:                                goto cleanup;
        !          2107:                        }
        !          2108: 
        !          2109:                        /* Append a NoBinding status code.  */
        !          2110:                        if (!set_status_code(STATUS_NoBinding,
        !          2111:                                             "Address not bound to this "
        !          2112:                                             "interface.", reply->reply_ia)) {
        !          2113:                                log_error("reply_process_addr: Unable to "
        !          2114:                                          "attach status code.");
        !          2115:                                status = ISC_R_FAILURE;
        !          2116:                                goto cleanup;
        !          2117:                        }
        !          2118: 
        !          2119:                        /* Fin (no more IAADDRs). */
        !          2120:                        status = ISC_R_CANCELED;
        !          2121:                        goto cleanup;
        !          2122:                } else {
        !          2123:                        log_error("It is impossible to lease a client that is "
        !          2124:                                  "not sending a solicit, request, renew, or "
        !          2125:                                  "rebind message.");
        !          2126:                        status = ISC_R_FAILURE;
        !          2127:                        goto cleanup;
        !          2128:                }
        !          2129:        }
        !          2130: 
        !          2131:        if (reply->static_lease) {
        !          2132:                if (reply->host == NULL)
        !          2133:                        log_fatal("Impossible condition at %s:%d.", MDL);
        !          2134: 
        !          2135:                scope = &global_scope;
        !          2136:                group = reply->subnet->group;
        !          2137:        } else {
        !          2138:                if (reply->lease == NULL)
        !          2139:                        log_fatal("Impossible condition at %s:%d.", MDL);
        !          2140: 
        !          2141:                scope = &reply->lease->scope;
        !          2142:                group = reply->lease->ipv6_pool->subnet->group;
        !          2143:        }
        !          2144: 
        !          2145:        /*
        !          2146:         * If client_resources is nonzero, then the reply_process_is_addressed
        !          2147:         * function has executed configuration state into the reply option
        !          2148:         * cache.  We will use that valid cache to derive configuration for
        !          2149:         * whether or not to engage in additional addresses, and similar.
        !          2150:         */
        !          2151:        if (reply->client_resources != 0) {
        !          2152:                unsigned limit = 1;
        !          2153: 
        !          2154:                /*
        !          2155:                 * Does this client have "enough" addresses already?  Default
        !          2156:                 * to one.  Everybody gets one, and one should be enough for
        !          2157:                 * anybody.
        !          2158:                 */
        !          2159:                oc = lookup_option(&server_universe, reply->opt_state,
        !          2160:                                   SV_LIMIT_ADDRS_PER_IA);
        !          2161:                if (oc != NULL) {
        !          2162:                        if (!evaluate_option_cache(&data, reply->packet,
        !          2163:                                                   NULL, NULL,
        !          2164:                                                   reply->packet->options,
        !          2165:                                                   reply->opt_state,
        !          2166:                                                   scope, oc, MDL) ||
        !          2167:                            (data.len != 4)) {
        !          2168:                                log_error("reply_process_addr: unable to "
        !          2169:                                          "evaluate addrs-per-ia value.");
        !          2170:                                status = ISC_R_FAILURE;
        !          2171:                                goto cleanup;
        !          2172:                        }
        !          2173: 
        !          2174:                        limit = getULong(data.data);
        !          2175:                        data_string_forget(&data, MDL);
        !          2176:                }
        !          2177: 
        !          2178:                /*
        !          2179:                 * If we wish to limit the client to a certain number of
        !          2180:                 * addresses, then omit the address from the reply.
        !          2181:                 */
        !          2182:                if (reply->client_resources >= limit)
        !          2183:                        goto cleanup;
        !          2184:        }
        !          2185: 
        !          2186:        status = reply_process_is_addressed(reply, scope, group);
        !          2187:        if (status != ISC_R_SUCCESS)
        !          2188:                goto cleanup;
        !          2189: 
        !          2190:       send_addr:
        !          2191:        status = reply_process_send_addr(reply, &tmp_addr);
        !          2192: 
        !          2193:       cleanup:
        !          2194:        if (iaaddr.data != NULL)
        !          2195:                data_string_forget(&iaaddr, MDL);
        !          2196:        if (data.data != NULL)
        !          2197:                data_string_forget(&data, MDL);
        !          2198:        if (reply->lease != NULL)
        !          2199:                iasubopt_dereference(&reply->lease, MDL);
        !          2200: 
        !          2201:        return status;
        !          2202: }
        !          2203: 
        !          2204: /*
        !          2205:  * Verify the address belongs to the client.  If we've got a host
        !          2206:  * record with a fixed address, it has to be the assigned address
        !          2207:  * (fault out all else).  Otherwise it's a dynamic address, so lookup
        !          2208:  * that address and make sure it belongs to this DUID:IAID pair.
        !          2209:  */
        !          2210: static isc_boolean_t
        !          2211: address_is_owned(struct reply_state *reply, struct iaddr *addr) {
        !          2212:        int i;
        !          2213: 
        !          2214:        /*
        !          2215:         * This faults out addresses that don't match fixed addresses.
        !          2216:         */
        !          2217:        if (reply->static_lease) {
        !          2218:                if (reply->fixed.data == NULL)
        !          2219:                        log_fatal("Impossible condition at %s:%d.", MDL);
        !          2220: 
        !          2221:                if (memcmp(addr->iabuf, reply->fixed.data, 16) == 0)
        !          2222:                        return ISC_TRUE;
        !          2223: 
        !          2224:                return ISC_FALSE;
        !          2225:        }
        !          2226: 
        !          2227:        if ((reply->old_ia == NULL) || (reply->old_ia->num_iasubopt == 0))
        !          2228:                return ISC_FALSE;
        !          2229: 
        !          2230:        for (i = 0 ; i < reply->old_ia->num_iasubopt ; i++) {
        !          2231:                struct iasubopt *tmp;
        !          2232: 
        !          2233:                tmp = reply->old_ia->iasubopt[i];
        !          2234: 
        !          2235:                if (memcmp(addr->iabuf, &tmp->addr, 16) == 0) {
        !          2236:                        iasubopt_reference(&reply->lease, tmp, MDL);
        !          2237:                        return ISC_TRUE;
        !          2238:                }
        !          2239:        }
        !          2240: 
        !          2241:        return ISC_FALSE;
        !          2242: }
        !          2243: 
        !          2244: /* Process a client-supplied IA_TA.  This may append options to the tail of
        !          2245:  * the reply packet being built in the reply_state structure.
        !          2246:  */
        !          2247: static isc_result_t
        !          2248: reply_process_ia_ta(struct reply_state *reply, struct option_cache *ia) {
        !          2249:        isc_result_t status = ISC_R_SUCCESS;
        !          2250:        u_int32_t iaid;
        !          2251:        unsigned ia_cursor;
        !          2252:        struct option_state *packet_ia;
        !          2253:        struct option_cache *oc;
        !          2254:        struct data_string ia_data, data;
        !          2255:        struct data_string iaaddr;
        !          2256:        u_int32_t pref_life, valid_life;
        !          2257:        struct iaddr tmp_addr;
        !          2258: 
        !          2259:        /* Initialize values that will get cleaned up on return. */
        !          2260:        packet_ia = NULL;
        !          2261:        memset(&ia_data, 0, sizeof(ia_data));
        !          2262:        memset(&data, 0, sizeof(data));
        !          2263:        memset(&iaaddr, 0, sizeof(iaaddr));
        !          2264: 
        !          2265:        /* Make sure there is at least room for the header. */
        !          2266:        if ((reply->cursor + IA_TA_OFFSET + 4) > sizeof(reply->buf)) {
        !          2267:                log_error("reply_process_ia_ta: Reply too long for IA.");
        !          2268:                return ISC_R_NOSPACE;
        !          2269:        }
        !          2270: 
        !          2271: 
        !          2272:        /* Fetch the IA_TA contents. */
        !          2273:        if (!get_encapsulated_IA_state(&packet_ia, &ia_data, reply->packet,
        !          2274:                                       ia, IA_TA_OFFSET)) {
        !          2275:                log_error("reply_process_ia_ta: error evaluating ia");
        !          2276:                status = ISC_R_FAILURE;
        !          2277:                goto cleanup;
        !          2278:        }
        !          2279: 
        !          2280:        /* Extract IA_TA header contents. */
        !          2281:        iaid = getULong(ia_data.data);
        !          2282: 
        !          2283:        /* Create an IA_TA structure. */
        !          2284:        if (ia_allocate(&reply->ia, iaid, (char *)reply->client_id.data,
        !          2285:                        reply->client_id.len, MDL) != ISC_R_SUCCESS) {
        !          2286:                log_error("reply_process_ia_ta: no memory for ia.");
        !          2287:                status = ISC_R_NOMEMORY;
        !          2288:                goto cleanup;
        !          2289:        }
        !          2290:        reply->ia->ia_type = D6O_IA_TA;
        !          2291: 
        !          2292:        /* Cache pre-existing IA, if any. */
        !          2293:        ia_hash_lookup(&reply->old_ia, ia_ta_active,
        !          2294:                       (unsigned char *)reply->ia->iaid_duid.data,
        !          2295:                       reply->ia->iaid_duid.len, MDL);
        !          2296: 
        !          2297:        /*
        !          2298:         * Create an option cache to carry the IA_TA option contents, and
        !          2299:         * execute any user-supplied values into it.
        !          2300:         */
        !          2301:        if (!option_state_allocate(&reply->reply_ia, MDL)) {
        !          2302:                status = ISC_R_NOMEMORY;
        !          2303:                goto cleanup;
        !          2304:        }
        !          2305: 
        !          2306:        /*
        !          2307:         * Temporary leases are dynamic by definition.
        !          2308:         */
        !          2309:        reply->static_lease = ISC_FALSE;
        !          2310: 
        !          2311:        /*
        !          2312:         * Save the cursor position at the start of the IA, so we can
        !          2313:         * set length later.  We write a temporary
        !          2314:         * header out now just in case we decide to adjust the packet
        !          2315:         * within sub-process functions.
        !          2316:         */
        !          2317:        ia_cursor = reply->cursor;
        !          2318: 
        !          2319:        /* Initialize the IA_TA header.  First the code. */
        !          2320:        putUShort(reply->buf.data + reply->cursor, (unsigned)D6O_IA_TA);
        !          2321:        reply->cursor += 2;
        !          2322: 
        !          2323:        /* Then option length. */
        !          2324:        putUShort(reply->buf.data + reply->cursor, 0x04u);
        !          2325:        reply->cursor += 2;
        !          2326: 
        !          2327:        /* Then IA_TA header contents; IAID. */
        !          2328:        putULong(reply->buf.data + reply->cursor, iaid);
        !          2329:        reply->cursor += 4;
        !          2330: 
        !          2331:        /* 
        !          2332:         * Deal with an IAADDR for lifetimes.
        !          2333:         * For all or none, process IAADDRs as hints.
        !          2334:         */
        !          2335:        reply->valid = reply->prefer = 0xffffffff;
        !          2336:        reply->client_valid = reply->client_prefer = 0;
        !          2337:        oc = lookup_option(&dhcpv6_universe, packet_ia, D6O_IAADDR);
        !          2338:        for (; oc != NULL; oc = oc->next) {
        !          2339:                memset(&iaaddr, 0, sizeof(iaaddr));
        !          2340:                if (!evaluate_option_cache(&iaaddr, reply->packet,
        !          2341:                                           NULL, NULL,
        !          2342:                                           reply->packet->options, NULL,
        !          2343:                                           &global_scope, oc, MDL) ||
        !          2344:                    (iaaddr.len < IAADDR_OFFSET)) {
        !          2345:                        log_error("reply_process_ia_ta: error "
        !          2346:                                  "evaluating IAADDR.");
        !          2347:                        status = ISC_R_FAILURE;
        !          2348:                        goto cleanup;
        !          2349:                }
        !          2350:                /* The first 16 bytes are the IPv6 address. */
        !          2351:                pref_life = getULong(iaaddr.data + 16);
        !          2352:                valid_life = getULong(iaaddr.data + 20);
        !          2353: 
        !          2354:                if ((reply->client_valid == 0) ||
        !          2355:                    (reply->client_valid > valid_life))
        !          2356:                        reply->client_valid = valid_life;
        !          2357: 
        !          2358:                if ((reply->client_prefer == 0) ||
        !          2359:                    (reply->client_prefer > pref_life))
        !          2360:                        reply->client_prefer = pref_life;
        !          2361: 
        !          2362:                /* Nothing more if something has failed. */
        !          2363:                if (status == ISC_R_CANCELED)
        !          2364:                        continue;
        !          2365: 
        !          2366:                tmp_addr.len = 16;
        !          2367:                memcpy(tmp_addr.iabuf, iaaddr.data, 16);
        !          2368:                if (!temporary_is_available(reply, &tmp_addr))
        !          2369:                        goto bad_temp;
        !          2370:                status = reply_process_is_addressed(reply,
        !          2371:                                                    &reply->lease->scope,
        !          2372:                                                    reply->shared->group);
        !          2373:                if (status != ISC_R_SUCCESS)
        !          2374:                        goto bad_temp;
        !          2375:                status = reply_process_send_addr(reply, &tmp_addr);
        !          2376:                if (status != ISC_R_SUCCESS)
        !          2377:                        goto bad_temp;
        !          2378:                if (reply->lease != NULL)
        !          2379:                        iasubopt_dereference(&reply->lease, MDL);
        !          2380:                continue;
        !          2381: 
        !          2382:        bad_temp:
        !          2383:                /* Rewind the IA_TA to empty. */
        !          2384:                option_state_dereference(&reply->reply_ia, MDL);
        !          2385:                if (!option_state_allocate(&reply->reply_ia, MDL)) {
        !          2386:                        status = ISC_R_NOMEMORY;
        !          2387:                        goto cleanup;
        !          2388:                }
        !          2389:                status = ISC_R_CANCELED;
        !          2390:                reply->client_resources = 0;
        !          2391:                reply->resources_included = ISC_FALSE;
        !          2392:                if (reply->lease != NULL)
        !          2393:                        iasubopt_dereference(&reply->lease, MDL);
        !          2394:        }
        !          2395:        reply->ia_count++;
        !          2396: 
        !          2397:        /*
        !          2398:         * Give the client temporary addresses.
        !          2399:         */
        !          2400:        if (reply->client_resources != 0)
        !          2401:                goto store;
        !          2402:        status = find_client_temporaries(reply);
        !          2403:        if (status == ISC_R_NORESOURCES) {
        !          2404:                switch (reply->packet->dhcpv6_msg_type) {
        !          2405:                      case DHCPV6_SOLICIT:
        !          2406:                        /*
        !          2407:                         * No address for any IA is handled
        !          2408:                         * by the caller.
        !          2409:                         */
        !          2410:                        /* FALL THROUGH */
        !          2411: 
        !          2412:                      case DHCPV6_REQUEST:
        !          2413:                        /* Section 18.2.1 (Request):
        !          2414:                         *
        !          2415:                         * If the server cannot assign any addresses to
        !          2416:                         * an IA in the message from the client, the
        !          2417:                         * server MUST include the IA in the Reply
        !          2418:                         * message with no addresses in the IA and a
        !          2419:                         * Status Code option in the IA containing
        !          2420:                         * status code NoAddrsAvail.
        !          2421:                         */
        !          2422:                        option_state_dereference(&reply->reply_ia, MDL);
        !          2423:                        if (!option_state_allocate(&reply->reply_ia,  MDL)) {
        !          2424:                                log_error("reply_process_ia_ta: No "
        !          2425:                                          "memory for option state wipe.");
        !          2426:                                status = ISC_R_NOMEMORY;
        !          2427:                                goto cleanup;
        !          2428:                        }
        !          2429: 
        !          2430:                        if (!set_status_code(STATUS_NoAddrsAvail,
        !          2431:                                             "No addresses available "
        !          2432:                                             "for this interface.",
        !          2433:                                              reply->reply_ia)) {
        !          2434:                                log_error("reply_process_ia_ta: Unable "
        !          2435:                                          "to set NoAddrsAvail status code.");
        !          2436:                                status = ISC_R_FAILURE;
        !          2437:                                goto cleanup;
        !          2438:                        }
        !          2439: 
        !          2440:                        status = ISC_R_SUCCESS;
        !          2441:                        break;
        !          2442: 
        !          2443:                      default:
        !          2444:                        /*
        !          2445:                         * We don't want to include the IA if we
        !          2446:                         * provide zero addresses including zeroed
        !          2447:                         * lifetimes.
        !          2448:                         */
        !          2449:                        if (reply->resources_included)
        !          2450:                                status = ISC_R_SUCCESS;
        !          2451:                        else
        !          2452:                                goto cleanup;
        !          2453:                        break;
        !          2454:                }
        !          2455:        } else if (status != ISC_R_SUCCESS)
        !          2456:                goto cleanup;
        !          2457: 
        !          2458:       store:
        !          2459:        reply->cursor += store_options6((char *)reply->buf.data + reply->cursor,
        !          2460:                                        sizeof(reply->buf) - reply->cursor,
        !          2461:                                        reply->reply_ia, reply->packet,
        !          2462:                                        required_opts_IA, NULL);
        !          2463: 
        !          2464:        /* Reset the length of this IA to match what was just written. */
        !          2465:        putUShort(reply->buf.data + ia_cursor + 2,
        !          2466:                  reply->cursor - (ia_cursor + 4));
        !          2467: 
        !          2468:        /*
        !          2469:         * Consume the new changes into the database (if any have been
        !          2470:         * attached to the ia_ta).
        !          2471:         *
        !          2472:         * Loop through the assigned dynamic addresses, referencing the
        !          2473:         * leases onto this IA_TA rather than any old ones, and updating
        !          2474:         * pool timers for each (if any).
        !          2475:         */
        !          2476:        if ((status != ISC_R_CANCELED) &&
        !          2477:            (reply->buf.reply.msg_type == DHCPV6_REPLY) &&
        !          2478:            (reply->ia->num_iasubopt != 0)) {
        !          2479:                struct iasubopt *tmp;
        !          2480:                struct data_string *ia_id;
        !          2481:                int i;
        !          2482: 
        !          2483:                for (i = 0 ; i < reply->ia->num_iasubopt ; i++) {
        !          2484:                        tmp = reply->ia->iasubopt[i];
        !          2485: 
        !          2486:                        if (tmp->ia != NULL)
        !          2487:                                ia_dereference(&tmp->ia, MDL);
        !          2488:                        ia_reference(&tmp->ia, reply->ia, MDL);
        !          2489: 
        !          2490:                        /* Commit 'hard' bindings. */
        !          2491:                        tmp->hard_lifetime_end_time =
        !          2492:                                tmp->soft_lifetime_end_time;
        !          2493:                        tmp->soft_lifetime_end_time = 0;
        !          2494:                        renew_lease6(tmp->ipv6_pool, tmp);
        !          2495:                        schedule_lease_timeout(tmp->ipv6_pool);
        !          2496: 
        !          2497:                        /*
        !          2498:                         * Perform ddns updates.
        !          2499:                         */
        !          2500:                        oc = lookup_option(&server_universe, reply->opt_state,
        !          2501:                                           SV_DDNS_UPDATES);
        !          2502:                        if ((oc == NULL) ||
        !          2503:                            evaluate_boolean_option_cache(NULL, reply->packet,
        !          2504:                                                          NULL, NULL,
        !          2505:                                                        reply->packet->options,
        !          2506:                                                          reply->opt_state,
        !          2507:                                                          &tmp->scope,
        !          2508:                                                          oc, MDL)) {
        !          2509:                                ddns_updates(reply->packet, NULL, NULL,
        !          2510:                                             tmp, NULL, reply->opt_state);
        !          2511:                        }
        !          2512:                }
        !          2513: 
        !          2514:                /* Remove any old ia from the hash. */
        !          2515:                if (reply->old_ia != NULL) {
        !          2516:                        ia_id = &reply->old_ia->iaid_duid;
        !          2517:                        ia_hash_delete(ia_ta_active,
        !          2518:                                       (unsigned char *)ia_id->data,
        !          2519:                                       ia_id->len, MDL);
        !          2520:                        ia_dereference(&reply->old_ia, MDL);
        !          2521:                }
        !          2522: 
        !          2523:                /* Put new ia into the hash. */
        !          2524:                reply->ia->cltt = cur_time;
        !          2525:                ia_id = &reply->ia->iaid_duid;
        !          2526:                ia_hash_add(ia_ta_active, (unsigned char *)ia_id->data,
        !          2527:                            ia_id->len, reply->ia, MDL);
        !          2528: 
        !          2529:                write_ia(reply->ia);
        !          2530:        }
        !          2531: 
        !          2532:       cleanup:
        !          2533:        if (packet_ia != NULL)
        !          2534:                option_state_dereference(&packet_ia, MDL);
        !          2535:        if (iaaddr.data != NULL)
        !          2536:                data_string_forget(&iaaddr, MDL);
        !          2537:        if (reply->reply_ia != NULL)
        !          2538:                option_state_dereference(&reply->reply_ia, MDL);
        !          2539:        if (ia_data.data != NULL)
        !          2540:                data_string_forget(&ia_data, MDL);
        !          2541:        if (data.data != NULL)
        !          2542:                data_string_forget(&data, MDL);
        !          2543:        if (reply->ia != NULL)
        !          2544:                ia_dereference(&reply->ia, MDL);
        !          2545:        if (reply->old_ia != NULL)
        !          2546:                ia_dereference(&reply->old_ia, MDL);
        !          2547:        if (reply->lease != NULL)
        !          2548:                iasubopt_dereference(&reply->lease, MDL);
        !          2549: 
        !          2550:        /*
        !          2551:         * ISC_R_CANCELED is a status code used by the addr processing to
        !          2552:         * indicate we're replying with other addresses.  This is still a
        !          2553:         * success at higher layers.
        !          2554:         */
        !          2555:        return((status == ISC_R_CANCELED) ? ISC_R_SUCCESS : status);
        !          2556: }
        !          2557: 
        !          2558: /*
        !          2559:  * Verify the temporary address is available.
        !          2560:  */
        !          2561: static isc_boolean_t
        !          2562: temporary_is_available(struct reply_state *reply, struct iaddr *addr) {
        !          2563:        struct in6_addr tmp_addr;
        !          2564:        struct subnet *subnet;
        !          2565:        struct ipv6_pool *pool;
        !          2566:        int i;
        !          2567: 
        !          2568:        memcpy(&tmp_addr, addr->iabuf, sizeof(tmp_addr));
        !          2569:        /*
        !          2570:         * Clients may choose to send :: as an address, with the idea to give
        !          2571:         * hints about preferred-lifetime or valid-lifetime.
        !          2572:         * So this is not a request for this address.
        !          2573:         */
        !          2574:        if (IN6_IS_ADDR_UNSPECIFIED(&tmp_addr))
        !          2575:                return ISC_FALSE;
        !          2576: 
        !          2577:        /*
        !          2578:         * Verify that this address is on the client's network.
        !          2579:         */
        !          2580:        for (subnet = reply->shared->subnets ; subnet != NULL ;
        !          2581:             subnet = subnet->next_sibling) {
        !          2582:                if (addr_eq(subnet_number(*addr, subnet->netmask),
        !          2583:                            subnet->net))
        !          2584:                        break;
        !          2585:        }
        !          2586: 
        !          2587:        /* Address not found on shared network. */
        !          2588:        if (subnet == NULL)
        !          2589:                return ISC_FALSE;
        !          2590: 
        !          2591:        /*
        !          2592:         * Check if this address is owned (must be before next step).
        !          2593:         */
        !          2594:        if (address_is_owned(reply, addr))
        !          2595:                return ISC_TRUE;
        !          2596: 
        !          2597:        /*
        !          2598:         * Verify that this address is in a temporary pool and try to get it.
        !          2599:         */
        !          2600:        if (reply->shared->ipv6_pools == NULL)
        !          2601:                return ISC_FALSE;
        !          2602:        for (i = 0 ; (pool = reply->shared->ipv6_pools[i]) != NULL ; i++) {
        !          2603:                if (pool->pool_type != D6O_IA_TA)
        !          2604:                        continue;
        !          2605:                if (ipv6_in_pool(&tmp_addr, pool))
        !          2606:                        break;
        !          2607:        }
        !          2608:        if (pool == NULL)
        !          2609:                return ISC_FALSE;
        !          2610:        if (lease6_exists(pool, &tmp_addr))
        !          2611:                return ISC_FALSE;
        !          2612:        if (iasubopt_allocate(&reply->lease, MDL) != ISC_R_SUCCESS)
        !          2613:                return ISC_FALSE;
        !          2614:        reply->lease->addr = tmp_addr;
        !          2615:        reply->lease->plen = 0;
        !          2616:        /* Default is soft binding for 2 minutes. */
        !          2617:        if (add_lease6(pool, reply->lease, cur_time + 120) != ISC_R_SUCCESS)
        !          2618:                return ISC_FALSE;
        !          2619: 
        !          2620:        return ISC_TRUE;
        !          2621: }
        !          2622: 
        !          2623: /*
        !          2624:  * Get a temporary address per prefix.
        !          2625:  */
        !          2626: static isc_result_t
        !          2627: find_client_temporaries(struct reply_state *reply) {
        !          2628:        struct shared_network *shared;
        !          2629:        int i;
        !          2630:        struct ipv6_pool *p;
        !          2631:        isc_result_t status;
        !          2632:        unsigned int attempts;
        !          2633:        struct iaddr send_addr;
        !          2634: 
        !          2635:        /*
        !          2636:         * No pools, we're done.
        !          2637:         */
        !          2638:        shared = reply->shared;
        !          2639:        if (shared->ipv6_pools == NULL) {
        !          2640:                log_debug("Unable to get client addresses: "
        !          2641:                          "no IPv6 pools on this shared network");
        !          2642:                return ISC_R_NORESOURCES;
        !          2643:        }
        !          2644: 
        !          2645:        status = ISC_R_NORESOURCES;
        !          2646:        for (i = 0;; i++) {
        !          2647:                p = shared->ipv6_pools[i];
        !          2648:                if (p == NULL) {
        !          2649:                        break;
        !          2650:                }
        !          2651:                if (p->pool_type != D6O_IA_TA) {
        !          2652:                        continue;
        !          2653:                }
        !          2654: 
        !          2655:                /*
        !          2656:                 * Get an address in this temporary pool.
        !          2657:                 */
        !          2658:                status = create_lease6(p, &reply->lease, &attempts,
        !          2659:                                       &reply->client_id, cur_time + 120);
        !          2660:                if (status != ISC_R_SUCCESS) {
        !          2661:                        log_debug("Unable to get a temporary address.");
        !          2662:                        goto cleanup;
        !          2663:                }
        !          2664: 
        !          2665:                status = reply_process_is_addressed(reply,
        !          2666:                                                    &reply->lease->scope,
        !          2667:                                      reply->lease->ipv6_pool->subnet->group);
        !          2668:                if (status != ISC_R_SUCCESS) {
        !          2669:                        goto cleanup;
        !          2670:                }
        !          2671:                send_addr.len = 16;
        !          2672:                memcpy(send_addr.iabuf, &reply->lease->addr, 16);
        !          2673:                status = reply_process_send_addr(reply, &send_addr);
        !          2674:                if (status != ISC_R_SUCCESS) {
        !          2675:                        goto cleanup;
        !          2676:                }
        !          2677:                if (reply->lease != NULL) {
        !          2678:                        iasubopt_dereference(&reply->lease, MDL);
        !          2679:                }
        !          2680:        }
        !          2681: 
        !          2682:       cleanup:
        !          2683:        if (reply->lease != NULL) {
        !          2684:                iasubopt_dereference(&reply->lease, MDL);
        !          2685:        }
        !          2686:        return status;
        !          2687: }
        !          2688: 
        !          2689: /*
        !          2690:  * This function only returns failure on 'hard' failures.  If it succeeds,
        !          2691:  * it will leave a lease structure behind.
        !          2692:  */
        !          2693: static isc_result_t
        !          2694: reply_process_try_addr(struct reply_state *reply, struct iaddr *addr) {
        !          2695:        isc_result_t status = ISC_R_NORESOURCES;
        !          2696:        struct ipv6_pool *pool;
        !          2697:        int i;
        !          2698:        struct data_string data_addr;
        !          2699: 
        !          2700:        if ((reply == NULL) || (reply->shared == NULL) ||
        !          2701:            (reply->shared->ipv6_pools == NULL) || (addr == NULL) ||
        !          2702:            (reply->lease != NULL))
        !          2703:                return ISC_R_INVALIDARG;
        !          2704: 
        !          2705:        memset(&data_addr, 0, sizeof(data_addr));
        !          2706:        data_addr.len = addr->len;
        !          2707:        data_addr.data = addr->iabuf;
        !          2708: 
        !          2709:        for (i = 0 ; (pool = reply->shared->ipv6_pools[i]) != NULL ; i++) {
        !          2710:                if (pool->pool_type != D6O_IA_NA)
        !          2711:                        continue;
        !          2712:                status = try_client_v6_address(&reply->lease, pool,
        !          2713:                                               &data_addr);
        !          2714:                if (status == ISC_R_SUCCESS)
        !          2715:                        break;
        !          2716:        }
        !          2717: 
        !          2718:        /* Note that this is just pedantry.  There is no allocation to free. */
        !          2719:        data_string_forget(&data_addr, MDL);
        !          2720:        /* Return just the most recent status... */
        !          2721:        return status;
        !          2722: }
        !          2723: 
        !          2724: /* Look around for an address to give the client.  First, look through the
        !          2725:  * old IA for addresses we can extend.  Second, try to allocate a new address.
        !          2726:  * Finally, actually add that address into the current reply IA.
        !          2727:  */
        !          2728: static isc_result_t
        !          2729: find_client_address(struct reply_state *reply) {
        !          2730:        struct iaddr send_addr;
        !          2731:        isc_result_t status = ISC_R_NORESOURCES;
        !          2732:        struct iasubopt *lease, *best_lease = NULL;
        !          2733:        struct binding_scope **scope;
        !          2734:        struct group *group;
        !          2735:        int i;
        !          2736: 
        !          2737:        if (reply->static_lease) {
        !          2738:                if (reply->host == NULL)
        !          2739:                        return ISC_R_INVALIDARG;
        !          2740: 
        !          2741:                send_addr.len = 16;
        !          2742:                memcpy(send_addr.iabuf, reply->fixed.data, 16);
        !          2743: 
        !          2744:                status = ISC_R_SUCCESS;
        !          2745:                scope = &global_scope;
        !          2746:                group = reply->subnet->group;
        !          2747:                goto send_addr;
        !          2748:        }
        !          2749: 
        !          2750:        if (reply->old_ia != NULL)  {
        !          2751:                for (i = 0 ; i < reply->old_ia->num_iasubopt ; i++) {
        !          2752:                        struct shared_network *candidate_shared;
        !          2753: 
        !          2754:                        lease = reply->old_ia->iasubopt[i];
        !          2755:                        candidate_shared = lease->ipv6_pool->shared_network;
        !          2756: 
        !          2757:                        /*
        !          2758:                         * Look for the best lease on the client's shared
        !          2759:                         * network.
        !          2760:                         */
        !          2761:                        if (candidate_shared == reply->shared) {
        !          2762:                                best_lease = lease_compare(lease, best_lease);
        !          2763:                        }
        !          2764:                }
        !          2765:        }
        !          2766: 
        !          2767:        /* Try to pick a new address if we didn't find one, or if we found an
        !          2768:         * abandoned lease.
        !          2769:         */
        !          2770:        if ((best_lease == NULL) || (best_lease->state == FTS_ABANDONED)) {
        !          2771:                status = pick_v6_address(&reply->lease, reply->shared,
        !          2772:                                         &reply->client_id);
        !          2773:        } else if (best_lease != NULL) {
        !          2774:                iasubopt_reference(&reply->lease, best_lease, MDL);
        !          2775:                status = ISC_R_SUCCESS;
        !          2776:        }
        !          2777: 
        !          2778:        /* Pick the abandoned lease as a last resort. */
        !          2779:        if ((status == ISC_R_NORESOURCES) && (best_lease != NULL)) {
        !          2780:                /* I don't see how this is supposed to be done right now. */
        !          2781:                log_error("Reclaiming abandoned addresses is not yet "
        !          2782:                          "supported.  Treating this as an out of space "
        !          2783:                          "condition.");
        !          2784:                /* iasubopt_reference(&reply->lease, best_lease, MDL); */
        !          2785:        }
        !          2786: 
        !          2787:        /* Give up now if we didn't find a lease. */
        !          2788:        if (status != ISC_R_SUCCESS)
        !          2789:                return status;
        !          2790: 
        !          2791:        if (reply->lease == NULL)
        !          2792:                log_fatal("Impossible condition at %s:%d.", MDL);
        !          2793: 
        !          2794:        /* Draw binding scopes from the lease's binding scope, and config
        !          2795:         * from the lease's containing subnet and higher.  Note that it may
        !          2796:         * be desirable to place the group attachment directly in the pool.
        !          2797:         */
        !          2798:        scope = &reply->lease->scope;
        !          2799:        group = reply->lease->ipv6_pool->subnet->group;
        !          2800: 
        !          2801:        send_addr.len = 16;
        !          2802:        memcpy(send_addr.iabuf, &reply->lease->addr, 16);
        !          2803: 
        !          2804:       send_addr:
        !          2805:        status = reply_process_is_addressed(reply, scope, group);
        !          2806:        if (status != ISC_R_SUCCESS)
        !          2807:                return status;
        !          2808: 
        !          2809:        status = reply_process_send_addr(reply, &send_addr);
        !          2810:        return status;
        !          2811: }
        !          2812: 
        !          2813: /* Once an address is found for a client, perform several common functions;
        !          2814:  * Calculate and store valid and preferred lease times, draw client options
        !          2815:  * into the option state.
        !          2816:  */
        !          2817: static isc_result_t
        !          2818: reply_process_is_addressed(struct reply_state *reply,
        !          2819:                           struct binding_scope **scope, struct group *group)
        !          2820: {
        !          2821:        isc_result_t status = ISC_R_SUCCESS;
        !          2822:        struct data_string data;
        !          2823:        struct option_cache *oc;
        !          2824: 
        !          2825:        /* Initialize values we will cleanup. */
        !          2826:        memset(&data, 0, sizeof(data));
        !          2827: 
        !          2828:        /*
        !          2829:         * Bring configured options into the root packet level cache - start
        !          2830:         * with the lease's closest enclosing group (passed in by the caller
        !          2831:         * as 'group').
        !          2832:         */
        !          2833:        execute_statements_in_scope(NULL, reply->packet, NULL, NULL,
        !          2834:                                    reply->packet->options, reply->opt_state,
        !          2835:                                    scope, group, root_group);
        !          2836: 
        !          2837:        /*
        !          2838:         * If there is a host record, over-ride with values configured there,
        !          2839:         * without re-evaluating configuration from the previously executed
        !          2840:         * group or its common enclosers.
        !          2841:         */
        !          2842:        if (reply->host != NULL)
        !          2843:                execute_statements_in_scope(NULL, reply->packet, NULL, NULL,
        !          2844:                                            reply->packet->options,
        !          2845:                                            reply->opt_state, scope,
        !          2846:                                            reply->host->group, group);
        !          2847: 
        !          2848:        /* Determine valid lifetime. */
        !          2849:        if (reply->client_valid == 0)
        !          2850:                reply->send_valid = DEFAULT_DEFAULT_LEASE_TIME;
        !          2851:        else
        !          2852:                reply->send_valid = reply->client_valid;
        !          2853: 
        !          2854:        oc = lookup_option(&server_universe, reply->opt_state,
        !          2855:                           SV_DEFAULT_LEASE_TIME);
        !          2856:        if (oc != NULL) {
        !          2857:                if (!evaluate_option_cache(&data, reply->packet, NULL, NULL,
        !          2858:                                           reply->packet->options,
        !          2859:                                           reply->opt_state,
        !          2860:                                           scope, oc, MDL) ||
        !          2861:                    (data.len != 4)) {
        !          2862:                        log_error("reply_process_is_addressed: unable to "
        !          2863:                                  "evaluate default lease time");
        !          2864:                        status = ISC_R_FAILURE;
        !          2865:                        goto cleanup;
        !          2866:                }
        !          2867: 
        !          2868:                reply->send_valid = getULong(data.data);
        !          2869:                data_string_forget(&data, MDL);
        !          2870:        }
        !          2871: 
        !          2872:        if (reply->client_prefer == 0)
        !          2873:                reply->send_prefer = reply->send_valid;
        !          2874:        else
        !          2875:                reply->send_prefer = reply->client_prefer;
        !          2876: 
        !          2877:        if (reply->send_prefer >= reply->send_valid)
        !          2878:                reply->send_prefer = (reply->send_valid / 2) +
        !          2879:                                     (reply->send_valid / 8);
        !          2880: 
        !          2881:        oc = lookup_option(&server_universe, reply->opt_state,
        !          2882:                           SV_PREFER_LIFETIME);
        !          2883:        if (oc != NULL) {
        !          2884:                if (!evaluate_option_cache(&data, reply->packet, NULL, NULL,
        !          2885:                                           reply->packet->options,
        !          2886:                                           reply->opt_state,
        !          2887:                                           scope, oc, MDL) ||
        !          2888:                    (data.len != 4)) {
        !          2889:                        log_error("reply_process_is_addressed: unable to "
        !          2890:                                  "evaluate preferred lease time");
        !          2891:                        status = ISC_R_FAILURE;
        !          2892:                        goto cleanup;
        !          2893:                }
        !          2894: 
        !          2895:                reply->send_prefer = getULong(data.data);
        !          2896:                data_string_forget(&data, MDL);
        !          2897:        }
        !          2898: 
        !          2899:        /* Note lowest values for later calculation of renew/rebind times. */
        !          2900:        if (reply->prefer > reply->send_prefer)
        !          2901:                reply->prefer = reply->send_prefer;
        !          2902: 
        !          2903:        if (reply->valid > reply->send_valid)
        !          2904:                reply->valid = reply->send_valid;
        !          2905: 
        !          2906: #if 0
        !          2907:        /*
        !          2908:         * XXX: Old 4.0.0 alpha code would change the host {} record
        !          2909:         * XXX: uid upon lease assignment.  This was intended to cover the
        !          2910:         * XXX: case where a client first identifies itself using vendor
        !          2911:         * XXX: options in a solicit, or request, but later neglects to include
        !          2912:         * XXX: these options in a Renew or Rebind.  It is not clear that this
        !          2913:         * XXX: is required, and has some startling ramifications (such as
        !          2914:         * XXX: how to recover this dynamic host {} state across restarts).
        !          2915:         */
        !          2916:        if (reply->host != NULL)
        !          2917:                change_host_uid(host, reply->client_id->data,
        !          2918:                                reply->client_id->len);
        !          2919: #endif /* 0 */
        !          2920: 
        !          2921:        /* Perform dynamic lease related update work. */
        !          2922:        if (reply->lease != NULL) {
        !          2923:                /* Cached lifetimes */
        !          2924:                reply->lease->prefer = reply->send_prefer;
        !          2925:                reply->lease->valid = reply->send_valid;
        !          2926: 
        !          2927:                /* Advance (or rewind) the valid lifetime. */
        !          2928:                if (reply->buf.reply.msg_type == DHCPV6_REPLY) {
        !          2929:                        reply->lease->soft_lifetime_end_time =
        !          2930:                                cur_time + reply->send_valid;
        !          2931:                        /* Wait before renew! */
        !          2932:                }
        !          2933: 
        !          2934:                status = ia_add_iasubopt(reply->ia, reply->lease, MDL);
        !          2935:                if (status != ISC_R_SUCCESS) {
        !          2936:                        log_fatal("reply_process_is_addressed: Unable to "
        !          2937:                                  "attach lease to new IA: %s",
        !          2938:                                  isc_result_totext(status));
        !          2939:                }
        !          2940: 
        !          2941:                /*
        !          2942:                 * If this is a new lease, make sure it is attached somewhere.
        !          2943:                 */
        !          2944:                if (reply->lease->ia == NULL) {
        !          2945:                        ia_reference(&reply->lease->ia, reply->ia, MDL);
        !          2946:                }
        !          2947:        }
        !          2948: 
        !          2949:        /* Bring a copy of the relevant options into the IA scope. */
        !          2950:        execute_statements_in_scope(NULL, reply->packet, NULL, NULL,
        !          2951:                                    reply->packet->options, reply->reply_ia,
        !          2952:                                    scope, group, root_group);
        !          2953: 
        !          2954:        /*
        !          2955:         * And bring in host record configuration, if any, but not to overlap
        !          2956:         * the previous group or its common enclosers.
        !          2957:         */
        !          2958:        if (reply->host != NULL)
        !          2959:                execute_statements_in_scope(NULL, reply->packet, NULL, NULL,
        !          2960:                                            reply->packet->options,
        !          2961:                                            reply->reply_ia, scope,
        !          2962:                                            reply->host->group, group);
        !          2963: 
        !          2964:       cleanup:
        !          2965:        if (data.data != NULL)
        !          2966:                data_string_forget(&data, MDL);
        !          2967: 
        !          2968:        if (status == ISC_R_SUCCESS)
        !          2969:                reply->client_resources++;
        !          2970: 
        !          2971:        return status;
        !          2972: }
        !          2973: 
        !          2974: /* Simply send an IAADDR within the IA scope as described. */
        !          2975: static isc_result_t
        !          2976: reply_process_send_addr(struct reply_state *reply, struct iaddr *addr) {
        !          2977:        isc_result_t status = ISC_R_SUCCESS;
        !          2978:        struct data_string data;
        !          2979: 
        !          2980:        memset(&data, 0, sizeof(data));
        !          2981: 
        !          2982:        /* Now append the lease. */
        !          2983:        data.len = IAADDR_OFFSET;
        !          2984:        if (!buffer_allocate(&data.buffer, data.len, MDL)) {
        !          2985:                log_error("reply_process_send_addr: out of memory"
        !          2986:                          "allocating new IAADDR buffer.");
        !          2987:                status = ISC_R_NOMEMORY;
        !          2988:                goto cleanup;
        !          2989:        }
        !          2990:        data.data = data.buffer->data;
        !          2991: 
        !          2992:        memcpy(data.buffer->data, addr->iabuf, 16);
        !          2993:        putULong(data.buffer->data + 16, reply->send_prefer);
        !          2994:        putULong(data.buffer->data + 20, reply->send_valid);
        !          2995: 
        !          2996:        if (!append_option_buffer(&dhcpv6_universe, reply->reply_ia,
        !          2997:                                  data.buffer, data.buffer->data,
        !          2998:                                  data.len, D6O_IAADDR, 0)) {
        !          2999:                log_error("reply_process_send_addr: unable "
        !          3000:                          "to save IAADDR option");
        !          3001:                status = ISC_R_FAILURE;
        !          3002:                goto cleanup;
        !          3003:        }
        !          3004: 
        !          3005:        reply->resources_included = ISC_TRUE;
        !          3006: 
        !          3007:       cleanup:
        !          3008:        if (data.data != NULL)
        !          3009:                data_string_forget(&data, MDL);
        !          3010: 
        !          3011:        return status;
        !          3012: }
        !          3013: 
        !          3014: /* Choose the better of two leases. */
        !          3015: static struct iasubopt *
        !          3016: lease_compare(struct iasubopt *alpha, struct iasubopt *beta) {
        !          3017:        if (alpha == NULL)
        !          3018:                return beta;
        !          3019:        if (beta == NULL)
        !          3020:                return alpha;
        !          3021: 
        !          3022:        switch(alpha->state) {
        !          3023:              case FTS_ACTIVE:
        !          3024:                switch(beta->state) {
        !          3025:                      case FTS_ACTIVE:
        !          3026:                        /* Choose the lease with the longest lifetime (most
        !          3027:                         * likely the most recently allocated).
        !          3028:                         */
        !          3029:                        if (alpha->hard_lifetime_end_time < 
        !          3030:                            beta->hard_lifetime_end_time)
        !          3031:                                return beta;
        !          3032:                        else
        !          3033:                                return alpha;
        !          3034: 
        !          3035:                      case FTS_EXPIRED:
        !          3036:                      case FTS_ABANDONED:
        !          3037:                        return alpha;
        !          3038: 
        !          3039:                      default:
        !          3040:                        log_fatal("Impossible condition at %s:%d.", MDL);
        !          3041:                }
        !          3042:                break;
        !          3043: 
        !          3044:              case FTS_EXPIRED:
        !          3045:                switch (beta->state) {
        !          3046:                      case FTS_ACTIVE:
        !          3047:                        return beta;
        !          3048: 
        !          3049:                      case FTS_EXPIRED:
        !          3050:                        /* Choose the most recently expired lease. */
        !          3051:                        if (alpha->hard_lifetime_end_time <
        !          3052:                            beta->hard_lifetime_end_time)
        !          3053:                                return beta;
        !          3054:                        else if ((alpha->hard_lifetime_end_time ==
        !          3055:                                  beta->hard_lifetime_end_time) &&
        !          3056:                                 (alpha->soft_lifetime_end_time <
        !          3057:                                  beta->soft_lifetime_end_time))
        !          3058:                                return beta;
        !          3059:                        else
        !          3060:                                return alpha;
        !          3061: 
        !          3062:                      case FTS_ABANDONED:
        !          3063:                        return alpha;
        !          3064: 
        !          3065:                      default:
        !          3066:                        log_fatal("Impossible condition at %s:%d.", MDL);
        !          3067:                }
        !          3068:                break;
        !          3069: 
        !          3070:              case FTS_ABANDONED:
        !          3071:                switch (beta->state) {
        !          3072:                      case FTS_ACTIVE:
        !          3073:                      case FTS_EXPIRED:
        !          3074:                        return alpha;
        !          3075: 
        !          3076:                      case FTS_ABANDONED:
        !          3077:                        /* Choose the lease that was abandoned longest ago. */
        !          3078:                        if (alpha->hard_lifetime_end_time <
        !          3079:                            beta->hard_lifetime_end_time)
        !          3080:                                return alpha;
        !          3081: 
        !          3082:                      default:
        !          3083:                        log_fatal("Impossible condition at %s:%d.", MDL);
        !          3084:                }
        !          3085:                break;
        !          3086: 
        !          3087:              default:
        !          3088:                log_fatal("Impossible condition at %s:%d.", MDL);
        !          3089:        }
        !          3090: 
        !          3091:        log_fatal("Triple impossible condition at %s:%d.", MDL);
        !          3092:        return NULL;
        !          3093: }
        !          3094: 
        !          3095: /* Process a client-supplied IA_PD.  This may append options to the tail of
        !          3096:  * the reply packet being built in the reply_state structure.
        !          3097:  */
        !          3098: static isc_result_t
        !          3099: reply_process_ia_pd(struct reply_state *reply, struct option_cache *ia) {
        !          3100:        isc_result_t status = ISC_R_SUCCESS;
        !          3101:        u_int32_t iaid;
        !          3102:        unsigned ia_cursor;
        !          3103:        struct option_state *packet_ia;
        !          3104:        struct option_cache *oc;
        !          3105:        struct data_string ia_data, data;
        !          3106: 
        !          3107:        /* Initialize values that will get cleaned up on return. */
        !          3108:        packet_ia = NULL;
        !          3109:        memset(&ia_data, 0, sizeof(ia_data));
        !          3110:        memset(&data, 0, sizeof(data));
        !          3111:        /* 
        !          3112:         * Note that find_client_prefix() may set reply->lease.
        !          3113:         */
        !          3114: 
        !          3115:        /* Make sure there is at least room for the header. */
        !          3116:        if ((reply->cursor + IA_PD_OFFSET + 4) > sizeof(reply->buf)) {
        !          3117:                log_error("reply_process_ia_pd: Reply too long for IA.");
        !          3118:                return ISC_R_NOSPACE;
        !          3119:        }
        !          3120: 
        !          3121: 
        !          3122:        /* Fetch the IA_PD contents. */
        !          3123:        if (!get_encapsulated_IA_state(&packet_ia, &ia_data, reply->packet,
        !          3124:                                       ia, IA_PD_OFFSET)) {
        !          3125:                log_error("reply_process_ia_pd: error evaluating ia");
        !          3126:                status = ISC_R_FAILURE;
        !          3127:                goto cleanup;
        !          3128:        }
        !          3129: 
        !          3130:        /* Extract IA_PD header contents. */
        !          3131:        iaid = getULong(ia_data.data);
        !          3132:        reply->renew = getULong(ia_data.data + 4);
        !          3133:        reply->rebind = getULong(ia_data.data + 8);
        !          3134: 
        !          3135:        /* Create an IA_PD structure. */
        !          3136:        if (ia_allocate(&reply->ia, iaid, (char *)reply->client_id.data, 
        !          3137:                        reply->client_id.len, MDL) != ISC_R_SUCCESS) {
        !          3138:                log_error("reply_process_ia_pd: no memory for ia.");
        !          3139:                status = ISC_R_NOMEMORY;
        !          3140:                goto cleanup;
        !          3141:        }
        !          3142:        reply->ia->ia_type = D6O_IA_PD;
        !          3143: 
        !          3144:        /* Cache pre-existing IA_PD, if any. */
        !          3145:        ia_hash_lookup(&reply->old_ia, ia_pd_active,
        !          3146:                       (unsigned char *)reply->ia->iaid_duid.data,
        !          3147:                       reply->ia->iaid_duid.len, MDL);
        !          3148: 
        !          3149:        /*
        !          3150:         * Create an option cache to carry the IA_PD option contents, and
        !          3151:         * execute any user-supplied values into it.
        !          3152:         */
        !          3153:        if (!option_state_allocate(&reply->reply_ia, MDL)) {
        !          3154:                status = ISC_R_NOMEMORY;
        !          3155:                goto cleanup;
        !          3156:        }
        !          3157: 
        !          3158:        /* Check & count the fixed prefix host records. */
        !          3159:        reply->static_prefixes = 0;
        !          3160:        if ((reply->host != NULL) && (reply->host->fixed_prefix != NULL)) {
        !          3161:                struct iaddrcidrnetlist *fp;
        !          3162: 
        !          3163:                for (fp = reply->host->fixed_prefix; fp != NULL;
        !          3164:                     fp = fp->next) {
        !          3165:                        reply->static_prefixes += 1;
        !          3166:                }
        !          3167:        }
        !          3168: 
        !          3169:        /*
        !          3170:         * Save the cursor position at the start of the IA_PD, so we can
        !          3171:         * set length and adjust t1/t2 values later.  We write a temporary
        !          3172:         * header out now just in case we decide to adjust the packet
        !          3173:         * within sub-process functions.
        !          3174:         */
        !          3175:        ia_cursor = reply->cursor;
        !          3176: 
        !          3177:        /* Initialize the IA_PD header.  First the code. */
        !          3178:        putUShort(reply->buf.data + reply->cursor, (unsigned)D6O_IA_PD);
        !          3179:        reply->cursor += 2;
        !          3180: 
        !          3181:        /* Then option length. */
        !          3182:        putUShort(reply->buf.data + reply->cursor, 0x0Cu);
        !          3183:        reply->cursor += 2;
        !          3184: 
        !          3185:        /* Then IA_PD header contents; IAID. */
        !          3186:        putULong(reply->buf.data + reply->cursor, iaid);
        !          3187:        reply->cursor += 4;
        !          3188: 
        !          3189:        /* We store the client's t1 for now, and may over-ride it later. */
        !          3190:        putULong(reply->buf.data + reply->cursor, reply->renew);
        !          3191:        reply->cursor += 4;
        !          3192: 
        !          3193:        /* We store the client's t2 for now, and may over-ride it later. */
        !          3194:        putULong(reply->buf.data + reply->cursor, reply->rebind);
        !          3195:        reply->cursor += 4;
        !          3196: 
        !          3197:        /* 
        !          3198:         * For each prefix in this IA_PD, decide what to do about it.
        !          3199:         */
        !          3200:        oc = lookup_option(&dhcpv6_universe, packet_ia, D6O_IAPREFIX);
        !          3201:        reply->valid = reply->prefer = 0xffffffff;
        !          3202:        reply->client_valid = reply->client_prefer = 0;
        !          3203:        reply->preflen = -1;
        !          3204:        for (; oc != NULL ; oc = oc->next) {
        !          3205:                status = reply_process_prefix(reply, oc);
        !          3206: 
        !          3207:                /*
        !          3208:                 * Canceled means we did not allocate prefixes to the
        !          3209:                 * client, but we're "done" with this IA - we set a status
        !          3210:                 * code.  So transmit this reply, e.g., move on to the next
        !          3211:                 * IA.
        !          3212:                 */
        !          3213:                if (status == ISC_R_CANCELED)
        !          3214:                        break;
        !          3215: 
        !          3216:                if ((status != ISC_R_SUCCESS) && (status != ISC_R_ADDRINUSE))
        !          3217:                        goto cleanup;
        !          3218:        }
        !          3219: 
        !          3220:        reply->pd_count++;
        !          3221: 
        !          3222:        /*
        !          3223:         * If we fell through the above and never gave the client
        !          3224:         * a prefix, give it one now.
        !          3225:         */
        !          3226:        if ((status != ISC_R_CANCELED) && (reply->client_resources == 0)) {
        !          3227:                status = find_client_prefix(reply);
        !          3228: 
        !          3229:                if (status == ISC_R_NORESOURCES) {
        !          3230:                        switch (reply->packet->dhcpv6_msg_type) {
        !          3231:                              case DHCPV6_SOLICIT:
        !          3232:                                /*
        !          3233:                                 * No prefix for any IA is handled
        !          3234:                                 * by the caller.
        !          3235:                                 */
        !          3236:                                /* FALL THROUGH */
        !          3237: 
        !          3238:                              case DHCPV6_REQUEST:
        !          3239:                                /* Same than for addresses. */
        !          3240:                                option_state_dereference(&reply->reply_ia, MDL);
        !          3241:                                if (!option_state_allocate(&reply->reply_ia,
        !          3242:                                                           MDL))
        !          3243:                                {
        !          3244:                                        log_error("reply_process_ia_pd: No "
        !          3245:                                                  "memory for option state "
        !          3246:                                                  "wipe.");
        !          3247:                                        status = ISC_R_NOMEMORY;
        !          3248:                                        goto cleanup;
        !          3249:                                }
        !          3250: 
        !          3251:                                if (!set_status_code(STATUS_NoPrefixAvail,
        !          3252:                                                     "No prefixes available "
        !          3253:                                                     "for this interface.",
        !          3254:                                                      reply->reply_ia)) {
        !          3255:                                        log_error("reply_process_ia_pd: "
        !          3256:                                                  "Unable to set "
        !          3257:                                                  "NoPrefixAvail status "
        !          3258:                                                  "code.");
        !          3259:                                        status = ISC_R_FAILURE;
        !          3260:                                        goto cleanup;
        !          3261:                                }
        !          3262: 
        !          3263:                                status = ISC_R_SUCCESS;
        !          3264:                                break;
        !          3265: 
        !          3266:                              default:
        !          3267:                                if (reply->resources_included)
        !          3268:                                        status = ISC_R_SUCCESS;
        !          3269:                                else
        !          3270:                                        goto cleanup;
        !          3271:                                break;
        !          3272:                        }
        !          3273:                }
        !          3274: 
        !          3275:                if (status != ISC_R_SUCCESS)
        !          3276:                        goto cleanup;
        !          3277:        }
        !          3278: 
        !          3279:        reply->cursor += store_options6((char *)reply->buf.data + reply->cursor,
        !          3280:                                        sizeof(reply->buf) - reply->cursor,
        !          3281:                                        reply->reply_ia, reply->packet,
        !          3282:                                        required_opts_IA_PD, NULL);
        !          3283: 
        !          3284:        /* Reset the length of this IA_PD to match what was just written. */
        !          3285:        putUShort(reply->buf.data + ia_cursor + 2,
        !          3286:                  reply->cursor - (ia_cursor + 4));
        !          3287: 
        !          3288:        /*
        !          3289:         * T1/T2 time selection is kind of weird.  We actually use DHCP
        !          3290:         * (v4) scoped options as handy existing places where these might
        !          3291:         * be configured by an administrator.  A value of zero tells the
        !          3292:         * client it may choose its own renewal time.
        !          3293:         */
        !          3294:        reply->renew = 0;
        !          3295:        oc = lookup_option(&dhcp_universe, reply->opt_state,
        !          3296:                           DHO_DHCP_RENEWAL_TIME);
        !          3297:        if (oc != NULL) {
        !          3298:                if (!evaluate_option_cache(&data, reply->packet, NULL, NULL,
        !          3299:                                           reply->packet->options,
        !          3300:                                           reply->opt_state, &global_scope,
        !          3301:                                           oc, MDL) ||
        !          3302:                    (data.len != 4)) {
        !          3303:                        log_error("Invalid renewal time.");
        !          3304:                } else {
        !          3305:                        reply->renew = getULong(data.data);
        !          3306:                }
        !          3307: 
        !          3308:                if (data.data != NULL)
        !          3309:                        data_string_forget(&data, MDL);
        !          3310:        }
        !          3311:        putULong(reply->buf.data + ia_cursor + 8, reply->renew);
        !          3312: 
        !          3313:        /* Now T2. */
        !          3314:        reply->rebind = 0;
        !          3315:        oc = lookup_option(&dhcp_universe, reply->opt_state,
        !          3316:                           DHO_DHCP_REBINDING_TIME);
        !          3317:        if (oc != NULL) {
        !          3318:                if (!evaluate_option_cache(&data, reply->packet, NULL, NULL,
        !          3319:                                           reply->packet->options,
        !          3320:                                           reply->opt_state, &global_scope,
        !          3321:                                           oc, MDL) ||
        !          3322:                    (data.len != 4)) {
        !          3323:                        log_error("Invalid rebinding time.");
        !          3324:                } else {
        !          3325:                        reply->rebind = getULong(data.data);
        !          3326:                }
        !          3327: 
        !          3328:                if (data.data != NULL)
        !          3329:                        data_string_forget(&data, MDL);
        !          3330:        }
        !          3331:        putULong(reply->buf.data + ia_cursor + 12, reply->rebind);
        !          3332: 
        !          3333:        /*
        !          3334:         * If this is not a 'soft' binding, consume the new changes into
        !          3335:         * the database (if any have been attached to the ia_pd).
        !          3336:         *
        !          3337:         * Loop through the assigned dynamic prefixes, referencing the
        !          3338:         * prefixes onto this IA_PD rather than any old ones, and updating
        !          3339:         * prefix pool timers for each (if any).
        !          3340:         */
        !          3341:        if ((status != ISC_R_CANCELED) && (reply->static_prefixes == 0) &&
        !          3342:            (reply->buf.reply.msg_type == DHCPV6_REPLY) &&
        !          3343:            (reply->ia->num_iasubopt != 0)) {
        !          3344:                struct iasubopt *tmp;
        !          3345:                struct data_string *ia_id;
        !          3346:                int i;
        !          3347: 
        !          3348:                for (i = 0 ; i < reply->ia->num_iasubopt ; i++) {
        !          3349:                        tmp = reply->ia->iasubopt[i];
        !          3350: 
        !          3351:                        if (tmp->ia != NULL)
        !          3352:                                ia_dereference(&tmp->ia, MDL);
        !          3353:                        ia_reference(&tmp->ia, reply->ia, MDL);
        !          3354: 
        !          3355:                        /* Commit 'hard' bindings. */
        !          3356:                        tmp->hard_lifetime_end_time =
        !          3357:                                tmp->soft_lifetime_end_time;
        !          3358:                        tmp->soft_lifetime_end_time = 0;
        !          3359:                        renew_lease6(tmp->ipv6_pool, tmp);
        !          3360:                        schedule_lease_timeout(tmp->ipv6_pool);
        !          3361:                }
        !          3362: 
        !          3363:                /* Remove any old ia from the hash. */
        !          3364:                if (reply->old_ia != NULL) {
        !          3365:                        ia_id = &reply->old_ia->iaid_duid;
        !          3366:                        ia_hash_delete(ia_pd_active,
        !          3367:                                       (unsigned char *)ia_id->data,
        !          3368:                                       ia_id->len, MDL);
        !          3369:                        ia_dereference(&reply->old_ia, MDL);
        !          3370:                }
        !          3371: 
        !          3372:                /* Put new ia into the hash. */
        !          3373:                reply->ia->cltt = cur_time;
        !          3374:                ia_id = &reply->ia->iaid_duid;
        !          3375:                ia_hash_add(ia_pd_active, (unsigned char *)ia_id->data,
        !          3376:                            ia_id->len, reply->ia, MDL);
        !          3377: 
        !          3378:                write_ia(reply->ia);
        !          3379:        }
        !          3380: 
        !          3381:       cleanup:
        !          3382:        if (packet_ia != NULL)
        !          3383:                option_state_dereference(&packet_ia, MDL);
        !          3384:        if (reply->reply_ia != NULL)
        !          3385:                option_state_dereference(&reply->reply_ia, MDL);
        !          3386:        if (ia_data.data != NULL)
        !          3387:                data_string_forget(&ia_data, MDL);
        !          3388:        if (data.data != NULL)
        !          3389:                data_string_forget(&data, MDL);
        !          3390:        if (reply->ia != NULL)
        !          3391:                ia_dereference(&reply->ia, MDL);
        !          3392:        if (reply->old_ia != NULL)
        !          3393:                ia_dereference(&reply->old_ia, MDL);
        !          3394:        if (reply->lease != NULL)
        !          3395:                iasubopt_dereference(&reply->lease, MDL);
        !          3396: 
        !          3397:        /*
        !          3398:         * ISC_R_CANCELED is a status code used by the prefix processing to
        !          3399:         * indicate we're replying with a status code.  This is still a
        !          3400:         * success at higher layers.
        !          3401:         */
        !          3402:        return((status == ISC_R_CANCELED) ? ISC_R_SUCCESS : status);
        !          3403: }
        !          3404: 
        !          3405: /*
        !          3406:  * Process an IAPREFIX within a given IA_PD, storing any IAPREFIX reply
        !          3407:  * contents into the reply's current ia_pd-scoped option cache.  Returns
        !          3408:  * ISC_R_CANCELED in the event we are replying with a status code and do
        !          3409:  * not wish to process more IAPREFIXes within this IA_PD.
        !          3410:  */
        !          3411: static isc_result_t
        !          3412: reply_process_prefix(struct reply_state *reply, struct option_cache *pref) {
        !          3413:        u_int32_t pref_life, valid_life;
        !          3414:        struct binding_scope **scope;
        !          3415:        struct iaddrcidrnet tmp_pref;
        !          3416:        struct option_cache *oc;
        !          3417:        struct data_string iapref, data;
        !          3418:        isc_result_t status = ISC_R_SUCCESS;
        !          3419: 
        !          3420:        /* Initializes values that will be cleaned up. */
        !          3421:        memset(&iapref, 0, sizeof(iapref));
        !          3422:        memset(&data, 0, sizeof(data));
        !          3423:        /* Note that reply->lease may be set by prefix_is_owned() */
        !          3424: 
        !          3425:        /*
        !          3426:         * There is no point trying to process an incoming prefix if there
        !          3427:         * is no room for an outgoing prefix.
        !          3428:         */
        !          3429:        if ((reply->cursor + 29) > sizeof(reply->buf)) {
        !          3430:                log_error("reply_process_prefix: Out of room for prefix.");
        !          3431:                return ISC_R_NOSPACE;
        !          3432:        }
        !          3433: 
        !          3434:        /* Extract this IAPREFIX option. */
        !          3435:        if (!evaluate_option_cache(&iapref, reply->packet, NULL, NULL, 
        !          3436:                                   reply->packet->options, NULL, &global_scope,
        !          3437:                                   pref, MDL) ||
        !          3438:            (iapref.len < IAPREFIX_OFFSET)) {
        !          3439:                log_error("reply_process_prefix: error evaluating IAPREFIX.");
        !          3440:                status = ISC_R_FAILURE;
        !          3441:                goto cleanup;
        !          3442:        }
        !          3443: 
        !          3444:        /*
        !          3445:         * Layout: preferred and valid lifetimes followed by the prefix
        !          3446:         * length and the IPv6 address.
        !          3447:         */
        !          3448:        pref_life = getULong(iapref.data);
        !          3449:        valid_life = getULong(iapref.data + 4);
        !          3450: 
        !          3451:        if ((reply->client_valid == 0) ||
        !          3452:            (reply->client_valid > valid_life))
        !          3453:                reply->client_valid = valid_life;
        !          3454: 
        !          3455:        if ((reply->client_prefer == 0) ||
        !          3456:            (reply->client_prefer > pref_life))
        !          3457:                reply->client_prefer = pref_life;
        !          3458: 
        !          3459:        /* 
        !          3460:         * Clients may choose to send ::/0 as a prefix, with the idea to give
        !          3461:         * hints about preferred-lifetime or valid-lifetime.
        !          3462:         */
        !          3463:        tmp_pref.lo_addr.len = 16;
        !          3464:        memset(tmp_pref.lo_addr.iabuf, 0, 16);
        !          3465:        if ((iapref.data[8] == 0) &&
        !          3466:            (memcmp(iapref.data + 9, tmp_pref.lo_addr.iabuf, 16) == 0)) {
        !          3467:                /* Status remains success; we just ignore this one. */
        !          3468:                goto cleanup;
        !          3469:        }
        !          3470: 
        !          3471:        /*
        !          3472:         * Clients may choose to send ::/X as a prefix to specify a
        !          3473:         * preferred/requested prefix length. Note X is never zero here.
        !          3474:         */
        !          3475:        tmp_pref.bits = (int) iapref.data[8];
        !          3476:        if (reply->preflen < 0) {
        !          3477:                /* Cache the first preferred prefix length. */
        !          3478:                reply->preflen = tmp_pref.bits;
        !          3479:        }
        !          3480:        if (memcmp(iapref.data + 9, tmp_pref.lo_addr.iabuf, 16) == 0) {
        !          3481:                goto cleanup;
        !          3482:        }
        !          3483: 
        !          3484:        memcpy(tmp_pref.lo_addr.iabuf, iapref.data + 9, 16);
        !          3485: 
        !          3486:        /* Verify the prefix belongs to the client. */
        !          3487:        if (!prefix_is_owned(reply, &tmp_pref)) {
        !          3488:                /* Same than for addresses. */
        !          3489:                if ((reply->packet->dhcpv6_msg_type == DHCPV6_SOLICIT) ||
        !          3490:                    (reply->packet->dhcpv6_msg_type == DHCPV6_REQUEST) ||
        !          3491:                    (reply->packet->dhcpv6_msg_type == DHCPV6_REBIND)) {
        !          3492:                        status = reply_process_try_prefix(reply, &tmp_pref);
        !          3493: 
        !          3494:                        /* Either error out or skip this prefix. */
        !          3495:                        if ((status != ISC_R_SUCCESS) && 
        !          3496:                            (status != ISC_R_ADDRINUSE)) 
        !          3497:                                goto cleanup;
        !          3498: 
        !          3499:                        if (reply->lease == NULL) {
        !          3500:                                if (reply->packet->dhcpv6_msg_type ==
        !          3501:                                                        DHCPV6_REBIND) {
        !          3502:                                        reply->send_prefer = 0;
        !          3503:                                        reply->send_valid = 0;
        !          3504:                                        goto send_pref;
        !          3505:                                }
        !          3506: 
        !          3507:                                /* status remains success - ignore */
        !          3508:                                goto cleanup;
        !          3509:                        }
        !          3510:                /*
        !          3511:                 * RFC3633 section 18.2.3:
        !          3512:                 *
        !          3513:                 * If the delegating router cannot find a binding
        !          3514:                 * for the requesting router's IA_PD the delegating
        !          3515:                 * router returns the IA_PD containing no prefixes
        !          3516:                 * with a Status Code option set to NoBinding in the
        !          3517:                 * Reply message.
        !          3518:                 *
        !          3519:                 * On mismatch we (ab)use this pretending we have not the IA
        !          3520:                 * as soon as we have not a prefix.
        !          3521:                 */
        !          3522:                } else if (reply->packet->dhcpv6_msg_type == DHCPV6_RENEW) {
        !          3523:                        /* Rewind the IA_PD to empty. */
        !          3524:                        option_state_dereference(&reply->reply_ia, MDL);
        !          3525:                        if (!option_state_allocate(&reply->reply_ia, MDL)) {
        !          3526:                                log_error("reply_process_prefix: No memory "
        !          3527:                                          "for option state wipe.");
        !          3528:                                status = ISC_R_NOMEMORY;
        !          3529:                                goto cleanup;
        !          3530:                        }
        !          3531: 
        !          3532:                        /* Append a NoBinding status code.  */
        !          3533:                        if (!set_status_code(STATUS_NoBinding,
        !          3534:                                             "Prefix not bound to this "
        !          3535:                                             "interface.", reply->reply_ia)) {
        !          3536:                                log_error("reply_process_prefix: Unable to "
        !          3537:                                          "attach status code.");
        !          3538:                                status = ISC_R_FAILURE;
        !          3539:                                goto cleanup;
        !          3540:                        }
        !          3541: 
        !          3542:                        /* Fin (no more IAPREFIXes). */
        !          3543:                        status = ISC_R_CANCELED;
        !          3544:                        goto cleanup;
        !          3545:                } else {
        !          3546:                        log_error("It is impossible to lease a client that is "
        !          3547:                                  "not sending a solicit, request, renew, or "
        !          3548:                                  "rebind message.");
        !          3549:                        status = ISC_R_FAILURE;
        !          3550:                        goto cleanup;
        !          3551:                }
        !          3552:        }
        !          3553: 
        !          3554:        if (reply->static_prefixes > 0) {
        !          3555:                if (reply->host == NULL)
        !          3556:                        log_fatal("Impossible condition at %s:%d.", MDL);
        !          3557: 
        !          3558:                scope = &global_scope;
        !          3559:        } else {
        !          3560:                if (reply->lease == NULL)
        !          3561:                        log_fatal("Impossible condition at %s:%d.", MDL);
        !          3562: 
        !          3563:                scope = &reply->lease->scope;
        !          3564:        }
        !          3565: 
        !          3566:        /*
        !          3567:         * If client_resources is nonzero, then the reply_process_is_prefixed
        !          3568:         * function has executed configuration state into the reply option
        !          3569:         * cache.  We will use that valid cache to derive configuration for
        !          3570:         * whether or not to engage in additional prefixes, and similar.
        !          3571:         */
        !          3572:        if (reply->client_resources != 0) {
        !          3573:                unsigned limit = 1;
        !          3574: 
        !          3575:                /*
        !          3576:                 * Does this client have "enough" prefixes already?  Default
        !          3577:                 * to one.  Everybody gets one, and one should be enough for
        !          3578:                 * anybody.
        !          3579:                 */
        !          3580:                oc = lookup_option(&server_universe, reply->opt_state,
        !          3581:                                   SV_LIMIT_PREFS_PER_IA);
        !          3582:                if (oc != NULL) {
        !          3583:                        if (!evaluate_option_cache(&data, reply->packet,
        !          3584:                                                   NULL, NULL,
        !          3585:                                                   reply->packet->options,
        !          3586:                                                   reply->opt_state,
        !          3587:                                                   scope, oc, MDL) ||
        !          3588:                            (data.len != 4)) {
        !          3589:                                log_error("reply_process_prefix: unable to "
        !          3590:                                          "evaluate prefs-per-ia value.");
        !          3591:                                status = ISC_R_FAILURE;
        !          3592:                                goto cleanup;
        !          3593:                        }
        !          3594: 
        !          3595:                        limit = getULong(data.data);
        !          3596:                        data_string_forget(&data, MDL);
        !          3597:                }
        !          3598: 
        !          3599:                /*
        !          3600:                 * If we wish to limit the client to a certain number of
        !          3601:                 * prefixes, then omit the prefix from the reply.
        !          3602:                 */
        !          3603:                if (reply->client_resources >= limit)
        !          3604:                        goto cleanup;
        !          3605:        }
        !          3606: 
        !          3607:        status = reply_process_is_prefixed(reply, scope, reply->shared->group);
        !          3608:        if (status != ISC_R_SUCCESS)
        !          3609:                goto cleanup;
        !          3610: 
        !          3611:       send_pref:
        !          3612:        status = reply_process_send_prefix(reply, &tmp_pref);
        !          3613: 
        !          3614:       cleanup:
        !          3615:        if (iapref.data != NULL)
        !          3616:                data_string_forget(&iapref, MDL);
        !          3617:        if (data.data != NULL)
        !          3618:                data_string_forget(&data, MDL);
        !          3619:        if (reply->lease != NULL)
        !          3620:                iasubopt_dereference(&reply->lease, MDL);
        !          3621: 
        !          3622:        return status;
        !          3623: }
        !          3624: 
        !          3625: /*
        !          3626:  * Verify the prefix belongs to the client.  If we've got a host
        !          3627:  * record with fixed prefixes, it has to be an assigned prefix
        !          3628:  * (fault out all else).  Otherwise it's a dynamic prefix, so lookup
        !          3629:  * that prefix and make sure it belongs to this DUID:IAID pair.
        !          3630:  */
        !          3631: static isc_boolean_t
        !          3632: prefix_is_owned(struct reply_state *reply, struct iaddrcidrnet *pref) {
        !          3633:        struct iaddrcidrnetlist *l;
        !          3634:        int i;
        !          3635: 
        !          3636:        /*
        !          3637:         * This faults out prefixes that don't match fixed prefixes.
        !          3638:         */
        !          3639:        if (reply->static_prefixes > 0) {
        !          3640:                for (l = reply->host->fixed_prefix; l != NULL; l = l->next) {
        !          3641:                        if ((pref->bits == l->cidrnet.bits) &&
        !          3642:                            (memcmp(pref->lo_addr.iabuf,
        !          3643:                                    l->cidrnet.lo_addr.iabuf, 16) == 0))
        !          3644:                                return ISC_TRUE;
        !          3645:                }
        !          3646:                return ISC_FALSE;
        !          3647:        }
        !          3648: 
        !          3649:        if ((reply->old_ia == NULL) ||
        !          3650:            (reply->old_ia->num_iasubopt == 0))
        !          3651:                return ISC_FALSE;
        !          3652: 
        !          3653:        for (i = 0 ; i < reply->old_ia->num_iasubopt ; i++) {
        !          3654:                struct iasubopt *tmp;
        !          3655: 
        !          3656:                tmp = reply->old_ia->iasubopt[i];
        !          3657: 
        !          3658:                if ((pref->bits == (int) tmp->plen) &&
        !          3659:                    memcmp(pref->lo_addr.iabuf, &tmp->addr, 16) == 0) {
        !          3660:                        iasubopt_reference(&reply->lease, tmp, MDL);
        !          3661:                        return ISC_TRUE;
        !          3662:                }
        !          3663:        }
        !          3664: 
        !          3665:        return ISC_FALSE;
        !          3666: }
        !          3667: 
        !          3668: /*
        !          3669:  * This function only returns failure on 'hard' failures.  If it succeeds,
        !          3670:  * it will leave a prefix structure behind.
        !          3671:  */
        !          3672: static isc_result_t
        !          3673: reply_process_try_prefix(struct reply_state *reply,
        !          3674:                         struct iaddrcidrnet *pref) {
        !          3675:        isc_result_t status = ISC_R_NORESOURCES;
        !          3676:        struct ipv6_pool *pool;
        !          3677:        int i;
        !          3678:        struct data_string data_pref;
        !          3679: 
        !          3680:        if ((reply == NULL) || (reply->shared == NULL) ||
        !          3681:            (reply->shared->ipv6_pools == NULL) || (pref == NULL) ||
        !          3682:            (reply->lease != NULL))
        !          3683:                return ISC_R_INVALIDARG;
        !          3684: 
        !          3685:        memset(&data_pref, 0, sizeof(data_pref));
        !          3686:        data_pref.len = 17;
        !          3687:        if (!buffer_allocate(&data_pref.buffer, data_pref.len, MDL)) {
        !          3688:                log_error("reply_process_try_prefix: out of memory.");
        !          3689:                return ISC_R_NOMEMORY;
        !          3690:        }
        !          3691:        data_pref.data = data_pref.buffer->data;
        !          3692:        data_pref.buffer->data[0] = (u_int8_t) pref->bits;
        !          3693:        memcpy(data_pref.buffer->data + 1, pref->lo_addr.iabuf, 16);
        !          3694: 
        !          3695:        for (i = 0 ; (pool = reply->shared->ipv6_pools[i]) != NULL ; i++) {
        !          3696:                if (pool->pool_type != D6O_IA_PD)
        !          3697:                        continue;
        !          3698:                status = try_client_v6_prefix(&reply->lease, pool,
        !          3699:                                              &data_pref);
        !          3700:                 /* If we found it in this pool (either in use or available), 
        !          3701:                    there is no need to look further. */
        !          3702:                if ( (status == ISC_R_SUCCESS) || (status == ISC_R_ADDRINUSE) )
        !          3703:                        break;
        !          3704:        }
        !          3705: 
        !          3706:        data_string_forget(&data_pref, MDL);
        !          3707:        /* Return just the most recent status... */
        !          3708:        return status;
        !          3709: }
        !          3710: 
        !          3711: /* Look around for a prefix to give the client.  First, look through the old
        !          3712:  * IA_PD for prefixes we can extend.  Second, try to allocate a new prefix.
        !          3713:  * Finally, actually add that prefix into the current reply IA_PD.
        !          3714:  */
        !          3715: static isc_result_t
        !          3716: find_client_prefix(struct reply_state *reply) {
        !          3717:        struct iaddrcidrnet send_pref;
        !          3718:        isc_result_t status = ISC_R_NORESOURCES;
        !          3719:        struct iasubopt *prefix, *best_prefix = NULL;
        !          3720:        struct binding_scope **scope;
        !          3721:        int i;
        !          3722: 
        !          3723:        if (reply->static_prefixes > 0) {
        !          3724:                struct iaddrcidrnetlist *l;
        !          3725: 
        !          3726:                if (reply->host == NULL)
        !          3727:                        return ISC_R_INVALIDARG;
        !          3728: 
        !          3729:                for (l = reply->host->fixed_prefix; l != NULL; l = l->next) {
        !          3730:                        if (l->cidrnet.bits == reply->preflen)
        !          3731:                                break;
        !          3732:                }
        !          3733:                if (l == NULL) {
        !          3734:                        /*
        !          3735:                         * If no fixed prefix has the preferred length,
        !          3736:                         * get the first one.
        !          3737:                         */
        !          3738:                        l = reply->host->fixed_prefix;
        !          3739:                }
        !          3740:                memcpy(&send_pref, &l->cidrnet, sizeof(send_pref));
        !          3741: 
        !          3742:                status = ISC_R_SUCCESS;
        !          3743:                scope = &global_scope;
        !          3744:                goto send_pref;
        !          3745:        }
        !          3746: 
        !          3747:        if (reply->old_ia != NULL)  {
        !          3748:                for (i = 0 ; i < reply->old_ia->num_iasubopt ; i++) {
        !          3749:                        struct shared_network *candidate_shared;
        !          3750: 
        !          3751:                        prefix = reply->old_ia->iasubopt[i];
        !          3752:                        candidate_shared = prefix->ipv6_pool->shared_network;
        !          3753: 
        !          3754:                        /*
        !          3755:                         * Consider this prefix if it is in a global pool or
        !          3756:                         * if it is scoped in a pool under the client's shared
        !          3757:                         * network.
        !          3758:                         */
        !          3759:                        if (candidate_shared == NULL ||
        !          3760:                            candidate_shared == reply->shared) {
        !          3761:                                best_prefix = prefix_compare(reply, prefix,
        !          3762:                                                             best_prefix);
        !          3763:                        }
        !          3764:                }
        !          3765:        }
        !          3766: 
        !          3767:        /* Try to pick a new prefix if we didn't find one, or if we found an
        !          3768:         * abandoned prefix.
        !          3769:         */
        !          3770:        if ((best_prefix == NULL) || (best_prefix->state == FTS_ABANDONED)) {
        !          3771:                status = pick_v6_prefix(&reply->lease, reply->preflen,
        !          3772:                                        reply->shared, &reply->client_id);
        !          3773:        } else if (best_prefix != NULL) {
        !          3774:                iasubopt_reference(&reply->lease, best_prefix, MDL);
        !          3775:                status = ISC_R_SUCCESS;
        !          3776:        }
        !          3777: 
        !          3778:        /* Pick the abandoned prefix as a last resort. */
        !          3779:        if ((status == ISC_R_NORESOURCES) && (best_prefix != NULL)) {
        !          3780:                /* I don't see how this is supposed to be done right now. */
        !          3781:                log_error("Reclaiming abandoned prefixes is not yet "
        !          3782:                          "supported.  Treating this as an out of space "
        !          3783:                          "condition.");
        !          3784:                /* iasubopt_reference(&reply->lease, best_prefix, MDL); */
        !          3785:        }
        !          3786: 
        !          3787:        /* Give up now if we didn't find a prefix. */
        !          3788:        if (status != ISC_R_SUCCESS)
        !          3789:                return status;
        !          3790: 
        !          3791:        if (reply->lease == NULL)
        !          3792:                log_fatal("Impossible condition at %s:%d.", MDL);
        !          3793: 
        !          3794:        scope = &reply->lease->scope;
        !          3795: 
        !          3796:        send_pref.lo_addr.len = 16;
        !          3797:        memcpy(send_pref.lo_addr.iabuf, &reply->lease->addr, 16);
        !          3798:        send_pref.bits = (int) reply->lease->plen;
        !          3799: 
        !          3800:       send_pref:
        !          3801:        status = reply_process_is_prefixed(reply, scope, reply->shared->group);
        !          3802:        if (status != ISC_R_SUCCESS)
        !          3803:                return status;
        !          3804: 
        !          3805:        status = reply_process_send_prefix(reply, &send_pref);
        !          3806:        return status;
        !          3807: }
        !          3808: 
        !          3809: /* Once a prefix is found for a client, perform several common functions;
        !          3810:  * Calculate and store valid and preferred prefix times, draw client options
        !          3811:  * into the option state.
        !          3812:  */
        !          3813: static isc_result_t
        !          3814: reply_process_is_prefixed(struct reply_state *reply,
        !          3815:                          struct binding_scope **scope, struct group *group)
        !          3816: {
        !          3817:        isc_result_t status = ISC_R_SUCCESS;
        !          3818:        struct data_string data;
        !          3819:        struct option_cache *oc;
        !          3820: 
        !          3821:        /* Initialize values we will cleanup. */
        !          3822:        memset(&data, 0, sizeof(data));
        !          3823: 
        !          3824:        /*
        !          3825:         * Bring configured options into the root packet level cache - start
        !          3826:         * with the lease's closest enclosing group (passed in by the caller
        !          3827:         * as 'group').
        !          3828:         */
        !          3829:        execute_statements_in_scope(NULL, reply->packet, NULL, NULL,
        !          3830:                                    reply->packet->options, reply->opt_state,
        !          3831:                                    scope, group, root_group);
        !          3832: 
        !          3833:        /*
        !          3834:         * If there is a host record, over-ride with values configured there,
        !          3835:         * without re-evaluating configuration from the previously executed
        !          3836:         * group or its common enclosers.
        !          3837:         */
        !          3838:        if (reply->host != NULL)
        !          3839:                execute_statements_in_scope(NULL, reply->packet, NULL, NULL,
        !          3840:                                            reply->packet->options,
        !          3841:                                            reply->opt_state, scope,
        !          3842:                                            reply->host->group, group);
        !          3843: 
        !          3844:        /* Determine valid lifetime. */
        !          3845:        if (reply->client_valid == 0)
        !          3846:                reply->send_valid = DEFAULT_DEFAULT_LEASE_TIME;
        !          3847:        else
        !          3848:                reply->send_valid = reply->client_valid;
        !          3849: 
        !          3850:        oc = lookup_option(&server_universe, reply->opt_state,
        !          3851:                           SV_DEFAULT_LEASE_TIME);
        !          3852:        if (oc != NULL) {
        !          3853:                if (!evaluate_option_cache(&data, reply->packet, NULL, NULL,
        !          3854:                                           reply->packet->options,
        !          3855:                                           reply->opt_state,
        !          3856:                                           scope, oc, MDL) ||
        !          3857:                    (data.len != 4)) {
        !          3858:                        log_error("reply_process_is_prefixed: unable to "
        !          3859:                                  "evaluate default prefix time");
        !          3860:                        status = ISC_R_FAILURE;
        !          3861:                        goto cleanup;
        !          3862:                }
        !          3863: 
        !          3864:                reply->send_valid = getULong(data.data);
        !          3865:                data_string_forget(&data, MDL);
        !          3866:        }
        !          3867: 
        !          3868:        if (reply->client_prefer == 0)
        !          3869:                reply->send_prefer = reply->send_valid;
        !          3870:        else
        !          3871:                reply->send_prefer = reply->client_prefer;
        !          3872: 
        !          3873:        if (reply->send_prefer >= reply->send_valid)
        !          3874:                reply->send_prefer = (reply->send_valid / 2) +
        !          3875:                                     (reply->send_valid / 8);
        !          3876: 
        !          3877:        oc = lookup_option(&server_universe, reply->opt_state,
        !          3878:                           SV_PREFER_LIFETIME);
        !          3879:        if (oc != NULL) {
        !          3880:                if (!evaluate_option_cache(&data, reply->packet, NULL, NULL,
        !          3881:                                           reply->packet->options,
        !          3882:                                           reply->opt_state,
        !          3883:                                           scope, oc, MDL) ||
        !          3884:                    (data.len != 4)) {
        !          3885:                        log_error("reply_process_is_prefixed: unable to "
        !          3886:                                  "evaluate preferred prefix time");
        !          3887:                        status = ISC_R_FAILURE;
        !          3888:                        goto cleanup;
        !          3889:                }
        !          3890: 
        !          3891:                reply->send_prefer = getULong(data.data);
        !          3892:                data_string_forget(&data, MDL);
        !          3893:        }
        !          3894: 
        !          3895:        /* Note lowest values for later calculation of renew/rebind times. */
        !          3896:        if (reply->prefer > reply->send_prefer)
        !          3897:                reply->prefer = reply->send_prefer;
        !          3898: 
        !          3899:        if (reply->valid > reply->send_valid)
        !          3900:                reply->valid = reply->send_valid;
        !          3901: 
        !          3902:        /* Perform dynamic prefix related update work. */
        !          3903:        if (reply->lease != NULL) {
        !          3904:                /* Cached lifetimes */
        !          3905:                reply->lease->prefer = reply->send_prefer;
        !          3906:                reply->lease->valid = reply->send_valid;
        !          3907: 
        !          3908:                /* Advance (or rewind) the valid lifetime. */
        !          3909:                if (reply->buf.reply.msg_type == DHCPV6_REPLY) {
        !          3910:                        reply->lease->soft_lifetime_end_time =
        !          3911:                                cur_time + reply->send_valid;
        !          3912:                        /* Wait before renew! */
        !          3913:                }
        !          3914: 
        !          3915:                status = ia_add_iasubopt(reply->ia, reply->lease, MDL);
        !          3916:                if (status != ISC_R_SUCCESS) {
        !          3917:                        log_fatal("reply_process_is_prefixed: Unable to "
        !          3918:                                  "attach prefix to new IA_PD: %s",
        !          3919:                                  isc_result_totext(status));
        !          3920:                }
        !          3921: 
        !          3922:                /*
        !          3923:                 * If this is a new prefix, make sure it is attached somewhere.
        !          3924:                 */
        !          3925:                if (reply->lease->ia == NULL) {
        !          3926:                        ia_reference(&reply->lease->ia, reply->ia, MDL);
        !          3927:                }
        !          3928:        }
        !          3929: 
        !          3930:        /* Bring a copy of the relevant options into the IA_PD scope. */
        !          3931:        execute_statements_in_scope(NULL, reply->packet, NULL, NULL,
        !          3932:                                    reply->packet->options, reply->reply_ia,
        !          3933:                                    scope, group, root_group);
        !          3934: 
        !          3935:        /*
        !          3936:         * And bring in host record configuration, if any, but not to overlap
        !          3937:         * the previous group or its common enclosers.
        !          3938:         */
        !          3939:        if (reply->host != NULL)
        !          3940:                execute_statements_in_scope(NULL, reply->packet, NULL, NULL,
        !          3941:                                            reply->packet->options,
        !          3942:                                            reply->reply_ia, scope,
        !          3943:                                            reply->host->group, group);
        !          3944: 
        !          3945:       cleanup:
        !          3946:        if (data.data != NULL)
        !          3947:                data_string_forget(&data, MDL);
        !          3948: 
        !          3949:        if (status == ISC_R_SUCCESS)
        !          3950:                reply->client_resources++;
        !          3951: 
        !          3952:        return status;
        !          3953: }
        !          3954: 
        !          3955: /* Simply send an IAPREFIX within the IA_PD scope as described. */
        !          3956: static isc_result_t
        !          3957: reply_process_send_prefix(struct reply_state *reply,
        !          3958:                          struct iaddrcidrnet *pref) {
        !          3959:        isc_result_t status = ISC_R_SUCCESS;
        !          3960:        struct data_string data;
        !          3961: 
        !          3962:        memset(&data, 0, sizeof(data));
        !          3963: 
        !          3964:        /* Now append the prefix. */
        !          3965:        data.len = IAPREFIX_OFFSET;
        !          3966:        if (!buffer_allocate(&data.buffer, data.len, MDL)) {
        !          3967:                log_error("reply_process_send_prefix: out of memory"
        !          3968:                          "allocating new IAPREFIX buffer.");
        !          3969:                status = ISC_R_NOMEMORY;
        !          3970:                goto cleanup;
        !          3971:        }
        !          3972:        data.data = data.buffer->data;
        !          3973: 
        !          3974:        putULong(data.buffer->data, reply->send_prefer);
        !          3975:        putULong(data.buffer->data + 4, reply->send_valid);
        !          3976:        data.buffer->data[8] = pref->bits;
        !          3977:        memcpy(data.buffer->data + 9, pref->lo_addr.iabuf, 16);
        !          3978: 
        !          3979:        if (!append_option_buffer(&dhcpv6_universe, reply->reply_ia,
        !          3980:                                  data.buffer, data.buffer->data,
        !          3981:                                  data.len, D6O_IAPREFIX, 0)) {
        !          3982:                log_error("reply_process_send_prefix: unable "
        !          3983:                          "to save IAPREFIX option");
        !          3984:                status = ISC_R_FAILURE;
        !          3985:                goto cleanup;
        !          3986:        }
        !          3987: 
        !          3988:        reply->resources_included = ISC_TRUE;
        !          3989: 
        !          3990:       cleanup:
        !          3991:        if (data.data != NULL)
        !          3992:                data_string_forget(&data, MDL);
        !          3993: 
        !          3994:        return status;
        !          3995: }
        !          3996: 
        !          3997: /* Choose the better of two prefixes. */
        !          3998: static struct iasubopt *
        !          3999: prefix_compare(struct reply_state *reply,
        !          4000:               struct iasubopt *alpha, struct iasubopt *beta) {
        !          4001:        if (alpha == NULL)
        !          4002:                return beta;
        !          4003:        if (beta == NULL)
        !          4004:                return alpha;
        !          4005: 
        !          4006:        if (reply->preflen >= 0) {
        !          4007:                if ((alpha->plen == reply->preflen) &&
        !          4008:                    (beta->plen != reply->preflen))
        !          4009:                        return alpha;
        !          4010:                if ((beta->plen == reply->preflen) &&
        !          4011:                    (alpha->plen != reply->preflen))
        !          4012:                        return beta;
        !          4013:        }
        !          4014: 
        !          4015:        switch(alpha->state) {
        !          4016:              case FTS_ACTIVE:
        !          4017:                switch(beta->state) {
        !          4018:                      case FTS_ACTIVE:
        !          4019:                        /* Choose the prefix with the longest lifetime (most
        !          4020:                         * likely the most recently allocated).
        !          4021:                         */
        !          4022:                        if (alpha->hard_lifetime_end_time < 
        !          4023:                            beta->hard_lifetime_end_time)
        !          4024:                                return beta;
        !          4025:                        else
        !          4026:                                return alpha;
        !          4027: 
        !          4028:                      case FTS_EXPIRED:
        !          4029:                      case FTS_ABANDONED:
        !          4030:                        return alpha;
        !          4031: 
        !          4032:                      default:
        !          4033:                        log_fatal("Impossible condition at %s:%d.", MDL);
        !          4034:                }
        !          4035:                break;
        !          4036: 
        !          4037:              case FTS_EXPIRED:
        !          4038:                switch (beta->state) {
        !          4039:                      case FTS_ACTIVE:
        !          4040:                        return beta;
        !          4041: 
        !          4042:                      case FTS_EXPIRED:
        !          4043:                        /* Choose the most recently expired prefix. */
        !          4044:                        if (alpha->hard_lifetime_end_time <
        !          4045:                            beta->hard_lifetime_end_time)
        !          4046:                                return beta;
        !          4047:                        else if ((alpha->hard_lifetime_end_time ==
        !          4048:                                  beta->hard_lifetime_end_time) &&
        !          4049:                                 (alpha->soft_lifetime_end_time <
        !          4050:                                  beta->soft_lifetime_end_time))
        !          4051:                                return beta;
        !          4052:                        else
        !          4053:                                return alpha;
        !          4054: 
        !          4055:                      case FTS_ABANDONED:
        !          4056:                        return alpha;
        !          4057: 
        !          4058:                      default:
        !          4059:                        log_fatal("Impossible condition at %s:%d.", MDL);
        !          4060:                }
        !          4061:                break;
        !          4062: 
        !          4063:              case FTS_ABANDONED:
        !          4064:                switch (beta->state) {
        !          4065:                      case FTS_ACTIVE:
        !          4066:                      case FTS_EXPIRED:
        !          4067:                        return alpha;
        !          4068: 
        !          4069:                      case FTS_ABANDONED:
        !          4070:                        /* Choose the prefix that was abandoned longest ago. */
        !          4071:                        if (alpha->hard_lifetime_end_time <
        !          4072:                            beta->hard_lifetime_end_time)
        !          4073:                                return alpha;
        !          4074: 
        !          4075:                      default:
        !          4076:                        log_fatal("Impossible condition at %s:%d.", MDL);
        !          4077:                }
        !          4078:                break;
        !          4079: 
        !          4080:              default:
        !          4081:                log_fatal("Impossible condition at %s:%d.", MDL);
        !          4082:        }
        !          4083: 
        !          4084:        log_fatal("Triple impossible condition at %s:%d.", MDL);
        !          4085:        return NULL;
        !          4086: }
        !          4087: 
        !          4088: /*
        !          4089:  * Solicit is how a client starts requesting addresses.
        !          4090:  *
        !          4091:  * If the client asks for rapid commit, and we support it, we will 
        !          4092:  * allocate the addresses and reply.
        !          4093:  *
        !          4094:  * Otherwise we will send an advertise message.
        !          4095:  */
        !          4096: 
        !          4097: static void
        !          4098: dhcpv6_solicit(struct data_string *reply_ret, struct packet *packet) {
        !          4099:        struct data_string client_id;
        !          4100: 
        !          4101:        /* 
        !          4102:         * Validate our input.
        !          4103:         */
        !          4104:        if (!valid_client_msg(packet, &client_id)) {
        !          4105:                return;
        !          4106:        }
        !          4107: 
        !          4108:        lease_to_client(reply_ret, packet, &client_id, NULL);
        !          4109: 
        !          4110:        /*
        !          4111:         * Clean up.
        !          4112:         */
        !          4113:        data_string_forget(&client_id, MDL);
        !          4114: }
        !          4115: 
        !          4116: /*
        !          4117:  * Request is how a client actually requests addresses.
        !          4118:  *
        !          4119:  * Very similar to Solicit handling, except the server DUID is required.
        !          4120:  */
        !          4121: 
        !          4122: /* TODO: reject unicast messages, unless we set unicast option */
        !          4123: static void
        !          4124: dhcpv6_request(struct data_string *reply_ret, struct packet *packet) {
        !          4125:        struct data_string client_id;
        !          4126:        struct data_string server_id;
        !          4127: 
        !          4128:        /*
        !          4129:         * Validate our input.
        !          4130:         */
        !          4131:        if (!valid_client_resp(packet, &client_id, &server_id)) {
        !          4132:                return;
        !          4133:        }
        !          4134: 
        !          4135:        /*
        !          4136:         * Issue our lease.
        !          4137:         */
        !          4138:        lease_to_client(reply_ret, packet, &client_id, &server_id);
        !          4139: 
        !          4140:        /*
        !          4141:         * Cleanup.
        !          4142:         */
        !          4143:        data_string_forget(&client_id, MDL);
        !          4144:        data_string_forget(&server_id, MDL);
        !          4145: }
        !          4146: 
        !          4147: /* Find a DHCPv6 packet's shared network from hints in the packet.
        !          4148:  */
        !          4149: static isc_result_t
        !          4150: shared_network_from_packet6(struct shared_network **shared,
        !          4151:                            struct packet *packet)
        !          4152: {
        !          4153:        const struct packet *chk_packet;
        !          4154:        const struct in6_addr *link_addr, *first_link_addr;
        !          4155:        struct iaddr tmp_addr;
        !          4156:        struct subnet *subnet;
        !          4157:        isc_result_t status;
        !          4158: 
        !          4159:        if ((shared == NULL) || (*shared != NULL) || (packet == NULL))
        !          4160:                return ISC_R_INVALIDARG;
        !          4161: 
        !          4162:        /*
        !          4163:         * First, find the link address where the packet from the client
        !          4164:         * first appeared (if this packet was relayed).
        !          4165:         */
        !          4166:        first_link_addr = NULL;
        !          4167:        chk_packet = packet->dhcpv6_container_packet;
        !          4168:        while (chk_packet != NULL) {
        !          4169:                link_addr = &chk_packet->dhcpv6_link_address;
        !          4170:                if (!IN6_IS_ADDR_UNSPECIFIED(link_addr) &&
        !          4171:                    !IN6_IS_ADDR_LINKLOCAL(link_addr)) {
        !          4172:                        first_link_addr = link_addr;
        !          4173:                        break;
        !          4174:                }
        !          4175:                chk_packet = chk_packet->dhcpv6_container_packet;
        !          4176:        }
        !          4177: 
        !          4178:        /*
        !          4179:         * If there is a relayed link address, find the subnet associated
        !          4180:         * with that, and use that to get the appropriate
        !          4181:         * shared_network.
        !          4182:         */
        !          4183:        if (first_link_addr != NULL) {
        !          4184:                tmp_addr.len = sizeof(*first_link_addr);
        !          4185:                memcpy(tmp_addr.iabuf,
        !          4186:                       first_link_addr, sizeof(*first_link_addr));
        !          4187:                subnet = NULL;
        !          4188:                if (!find_subnet(&subnet, tmp_addr, MDL)) {
        !          4189:                        log_debug("No subnet found for link-address %s.",
        !          4190:                                  piaddr(tmp_addr));
        !          4191:                        return ISC_R_NOTFOUND;
        !          4192:                }
        !          4193:                status = shared_network_reference(shared,
        !          4194:                                                  subnet->shared_network, MDL);
        !          4195:                subnet_dereference(&subnet, MDL);
        !          4196: 
        !          4197:        /*
        !          4198:         * If there is no link address, we will use the interface
        !          4199:         * that this packet came in on to pick the shared_network.
        !          4200:         */
        !          4201:        } else if (packet->interface != NULL) {
        !          4202:                status = shared_network_reference(shared,
        !          4203:                                         packet->interface->shared_network,
        !          4204:                                         MDL);
        !          4205:                 if (packet->dhcpv6_container_packet != NULL) {
        !          4206:                        log_info("[L2 Relay] No link address in relay packet "
        !          4207:                                 "assuming L2 relay and using receiving "
        !          4208:                                 "interface");
        !          4209:                 }
        !          4210: 
        !          4211:        } else {
        !          4212:                /*
        !          4213:                 * We shouldn't be able to get here but if there is no link
        !          4214:                 * address and no interface we don't know where to get the
        !          4215:                 * pool from log an error and return an error.
        !          4216:                 */
        !          4217:                log_error("No interface and no link address " 
        !          4218:                          "can't determine pool");
        !          4219:                status = ISC_R_INVALIDARG;
        !          4220:        }
        !          4221: 
        !          4222:        return status;
        !          4223: }
        !          4224: 
        !          4225: /*
        !          4226:  * When a client thinks it might be on a new link, it sends a 
        !          4227:  * Confirm message.
        !          4228:  *
        !          4229:  * From RFC3315 section 18.2.2:
        !          4230:  *
        !          4231:  *   When the server receives a Confirm message, the server determines
        !          4232:  *   whether the addresses in the Confirm message are appropriate for the
        !          4233:  *   link to which the client is attached.  If all of the addresses in the
        !          4234:  *   Confirm message pass this test, the server returns a status of
        !          4235:  *   Success.  If any of the addresses do not pass this test, the server
        !          4236:  *   returns a status of NotOnLink.  If the server is unable to perform
        !          4237:  *   this test (for example, the server does not have information about
        !          4238:  *   prefixes on the link to which the client is connected), or there were
        !          4239:  *   no addresses in any of the IAs sent by the client, the server MUST
        !          4240:  *   NOT send a reply to the client.
        !          4241:  */
        !          4242: 
        !          4243: static void
        !          4244: dhcpv6_confirm(struct data_string *reply_ret, struct packet *packet) {
        !          4245:        struct shared_network *shared;
        !          4246:        struct subnet *subnet;
        !          4247:        struct option_cache *ia, *ta, *oc;
        !          4248:        struct data_string cli_enc_opt_data, iaaddr, client_id, packet_oro;
        !          4249:        struct option_state *cli_enc_opt_state, *opt_state;
        !          4250:        struct iaddr cli_addr;
        !          4251:        int pass;
        !          4252:        isc_boolean_t inappropriate, has_addrs;
        !          4253:        char reply_data[65536];
        !          4254:        struct dhcpv6_packet *reply = (struct dhcpv6_packet *)reply_data;
        !          4255:        int reply_ofs = (int)(offsetof(struct dhcpv6_packet, options));
        !          4256: 
        !          4257:        /* 
        !          4258:         * Basic client message validation.
        !          4259:         */
        !          4260:        memset(&client_id, 0, sizeof(client_id));
        !          4261:        if (!valid_client_msg(packet, &client_id)) {
        !          4262:                return;
        !          4263:        }
        !          4264: 
        !          4265:        /*
        !          4266:         * Do not process Confirms that do not have IA's we do not recognize.
        !          4267:         */
        !          4268:        ia = lookup_option(&dhcpv6_universe, packet->options, D6O_IA_NA);
        !          4269:        ta = lookup_option(&dhcpv6_universe, packet->options, D6O_IA_TA);
        !          4270:        if ((ia == NULL) && (ta == NULL))
        !          4271:                return;
        !          4272: 
        !          4273:        /*
        !          4274:         * IA_PD's are simply ignored.
        !          4275:         */
        !          4276:        delete_option(&dhcpv6_universe, packet->options, D6O_IA_PD);
        !          4277: 
        !          4278:        /* 
        !          4279:         * Bit of variable initialization.
        !          4280:         */
        !          4281:        opt_state = cli_enc_opt_state = NULL;
        !          4282:        memset(&cli_enc_opt_data, 0, sizeof(cli_enc_opt_data));
        !          4283:        memset(&iaaddr, 0, sizeof(iaaddr));
        !          4284:        memset(&packet_oro, 0, sizeof(packet_oro));
        !          4285: 
        !          4286:        /* Determine what shared network the client is connected to.  We
        !          4287:         * must not respond if we don't have any information about the
        !          4288:         * network the client is on.
        !          4289:         */
        !          4290:        shared = NULL;
        !          4291:        if ((shared_network_from_packet6(&shared, packet) != ISC_R_SUCCESS) ||
        !          4292:            (shared == NULL))
        !          4293:                goto exit;
        !          4294: 
        !          4295:        /* If there are no recorded subnets, then we have no
        !          4296:         * information about this subnet - ignore Confirms.
        !          4297:         */
        !          4298:        subnet = shared->subnets;
        !          4299:        if (subnet == NULL)
        !          4300:                goto exit;
        !          4301: 
        !          4302:        /* Are the addresses in all the IA's appropriate for that link? */
        !          4303:        has_addrs = inappropriate = ISC_FALSE;
        !          4304:        pass = D6O_IA_NA;
        !          4305:        while(!inappropriate) {
        !          4306:                /* If we've reached the end of the IA_NA pass, move to the
        !          4307:                 * IA_TA pass.
        !          4308:                 */
        !          4309:                if ((pass == D6O_IA_NA) && (ia == NULL)) {
        !          4310:                        pass = D6O_IA_TA;
        !          4311:                        ia = ta;
        !          4312:                }
        !          4313: 
        !          4314:                /* If we've reached the end of all passes, we're done. */
        !          4315:                if (ia == NULL)
        !          4316:                        break;
        !          4317: 
        !          4318:                if (((pass == D6O_IA_NA) &&
        !          4319:                     !get_encapsulated_IA_state(&cli_enc_opt_state,
        !          4320:                                                &cli_enc_opt_data,
        !          4321:                                                packet, ia, IA_NA_OFFSET)) ||
        !          4322:                    ((pass == D6O_IA_TA) &&
        !          4323:                     !get_encapsulated_IA_state(&cli_enc_opt_state,
        !          4324:                                                &cli_enc_opt_data,
        !          4325:                                                packet, ia, IA_TA_OFFSET))) {
        !          4326:                        goto exit;
        !          4327:                }
        !          4328: 
        !          4329:                oc = lookup_option(&dhcpv6_universe, cli_enc_opt_state,
        !          4330:                                   D6O_IAADDR);
        !          4331: 
        !          4332:                for ( ; oc != NULL ; oc = oc->next) {
        !          4333:                        if (!evaluate_option_cache(&iaaddr, packet, NULL, NULL,
        !          4334:                                                   packet->options, NULL,
        !          4335:                                                   &global_scope, oc, MDL) ||
        !          4336:                            (iaaddr.len < IAADDR_OFFSET)) {
        !          4337:                                log_error("dhcpv6_confirm: "
        !          4338:                                          "error evaluating IAADDR.");
        !          4339:                                goto exit;
        !          4340:                        }
        !          4341: 
        !          4342:                        /* Copy out the IPv6 address for processing. */
        !          4343:                        cli_addr.len = 16;
        !          4344:                        memcpy(cli_addr.iabuf, iaaddr.data, 16);
        !          4345: 
        !          4346:                        data_string_forget(&iaaddr, MDL);
        !          4347: 
        !          4348:                        /* Record that we've processed at least one address. */
        !          4349:                        has_addrs = ISC_TRUE;
        !          4350: 
        !          4351:                        /* Find out if any subnets cover this address. */
        !          4352:                        for (subnet = shared->subnets ; subnet != NULL ;
        !          4353:                             subnet = subnet->next_sibling) {
        !          4354:                                if (addr_eq(subnet_number(cli_addr,
        !          4355:                                                          subnet->netmask),
        !          4356:                                            subnet->net))
        !          4357:                                        break;
        !          4358:                        }
        !          4359: 
        !          4360:                        /* If we reach the end of the subnet list, and no
        !          4361:                         * subnet matches the client address, then it must
        !          4362:                         * be inappropriate to the link (so far as our
        !          4363:                         * configuration says).  Once we've found one
        !          4364:                         * inappropriate address, there is no reason to
        !          4365:                         * continue searching.
        !          4366:                         */
        !          4367:                        if (subnet == NULL) {
        !          4368:                                inappropriate = ISC_TRUE;
        !          4369:                                break;
        !          4370:                        }
        !          4371:                }
        !          4372: 
        !          4373:                option_state_dereference(&cli_enc_opt_state, MDL);
        !          4374:                data_string_forget(&cli_enc_opt_data, MDL);
        !          4375: 
        !          4376:                /* Advance to the next IA_*. */
        !          4377:                ia = ia->next;
        !          4378:        }
        !          4379: 
        !          4380:        /* If the client supplied no addresses, do not reply. */
        !          4381:        if (!has_addrs)
        !          4382:                goto exit;
        !          4383: 
        !          4384:        /* 
        !          4385:         * Set up reply.
        !          4386:         */
        !          4387:        if (!start_reply(packet, &client_id, NULL, &opt_state, reply)) {
        !          4388:                goto exit;
        !          4389:        }
        !          4390: 
        !          4391:        /* 
        !          4392:         * Set our status.
        !          4393:         */
        !          4394:        if (inappropriate) {
        !          4395:                if (!set_status_code(STATUS_NotOnLink, 
        !          4396:                                     "Some of the addresses are not on link.",
        !          4397:                                     opt_state)) {
        !          4398:                        goto exit;
        !          4399:                }
        !          4400:        } else {
        !          4401:                if (!set_status_code(STATUS_Success, 
        !          4402:                                     "All addresses still on link.",
        !          4403:                                     opt_state)) {
        !          4404:                        goto exit;
        !          4405:                }
        !          4406:        }
        !          4407: 
        !          4408:        /* 
        !          4409:         * Only one option: add it.
        !          4410:         */
        !          4411:        reply_ofs += store_options6(reply_data+reply_ofs,
        !          4412:                                    sizeof(reply_data)-reply_ofs, 
        !          4413:                                    opt_state, packet,
        !          4414:                                    required_opts, &packet_oro);
        !          4415: 
        !          4416:        /* 
        !          4417:         * Return our reply to the caller.
        !          4418:         */
        !          4419:        reply_ret->len = reply_ofs;
        !          4420:        reply_ret->buffer = NULL;
        !          4421:        if (!buffer_allocate(&reply_ret->buffer, reply_ofs, MDL)) {
        !          4422:                log_fatal("No memory to store reply.");
        !          4423:        }
        !          4424:        reply_ret->data = reply_ret->buffer->data;
        !          4425:        memcpy(reply_ret->buffer->data, reply, reply_ofs);
        !          4426: 
        !          4427: exit:
        !          4428:        /* Cleanup any stale data strings. */
        !          4429:        if (cli_enc_opt_data.buffer != NULL)
        !          4430:                data_string_forget(&cli_enc_opt_data, MDL);
        !          4431:        if (iaaddr.buffer != NULL)
        !          4432:                data_string_forget(&iaaddr, MDL);
        !          4433:        if (client_id.buffer != NULL)
        !          4434:                data_string_forget(&client_id, MDL);
        !          4435:        if (packet_oro.buffer != NULL)
        !          4436:                data_string_forget(&packet_oro, MDL);
        !          4437: 
        !          4438:        /* Release any stale option states. */
        !          4439:        if (cli_enc_opt_state != NULL)
        !          4440:                option_state_dereference(&cli_enc_opt_state, MDL);
        !          4441:        if (opt_state != NULL)
        !          4442:                option_state_dereference(&opt_state, MDL);
        !          4443: }
        !          4444: 
        !          4445: /*
        !          4446:  * Renew is when a client wants to extend its lease/prefix, at time T1.
        !          4447:  *
        !          4448:  * We handle this the same as if the client wants a new lease/prefix,
        !          4449:  * except for the error code of when addresses don't match.
        !          4450:  */
        !          4451: 
        !          4452: /* TODO: reject unicast messages, unless we set unicast option */
        !          4453: static void
        !          4454: dhcpv6_renew(struct data_string *reply, struct packet *packet) {
        !          4455:        struct data_string client_id;
        !          4456:        struct data_string server_id;
        !          4457: 
        !          4458:        /* 
        !          4459:         * Validate the request.
        !          4460:         */
        !          4461:        if (!valid_client_resp(packet, &client_id, &server_id)) {
        !          4462:                return;
        !          4463:        }
        !          4464: 
        !          4465:        /*
        !          4466:         * Renew our lease.
        !          4467:         */
        !          4468:        lease_to_client(reply, packet, &client_id, &server_id);
        !          4469: 
        !          4470:        /*
        !          4471:         * Cleanup.
        !          4472:         */
        !          4473:        data_string_forget(&server_id, MDL);
        !          4474:        data_string_forget(&client_id, MDL);
        !          4475: }
        !          4476: 
        !          4477: /*
        !          4478:  * Rebind is when a client wants to extend its lease, at time T2.
        !          4479:  *
        !          4480:  * We handle this the same as if the client wants a new lease, except
        !          4481:  * for the error code of when addresses don't match.
        !          4482:  */
        !          4483: 
        !          4484: static void
        !          4485: dhcpv6_rebind(struct data_string *reply, struct packet *packet) {
        !          4486:        struct data_string client_id;
        !          4487: 
        !          4488:        if (!valid_client_msg(packet, &client_id)) {
        !          4489:                return;
        !          4490:        }
        !          4491: 
        !          4492:        lease_to_client(reply, packet, &client_id, NULL);
        !          4493: 
        !          4494:        data_string_forget(&client_id, MDL);
        !          4495: }
        !          4496: 
        !          4497: static void
        !          4498: ia_na_match_decline(const struct data_string *client_id,
        !          4499:                    const struct data_string *iaaddr,
        !          4500:                    struct iasubopt *lease)
        !          4501: {
        !          4502:        char tmp_addr[INET6_ADDRSTRLEN];
        !          4503: 
        !          4504:        log_error("Client %s reports address %s is "
        !          4505:                  "already in use by another host!",
        !          4506:                  print_hex_1(client_id->len, client_id->data, 60),
        !          4507:                  inet_ntop(AF_INET6, iaaddr->data, 
        !          4508:                            tmp_addr, sizeof(tmp_addr)));
        !          4509:        if (lease != NULL) {
        !          4510:                decline_lease6(lease->ipv6_pool, lease);
        !          4511:                lease->ia->cltt = cur_time;
        !          4512:                write_ia(lease->ia);
        !          4513:        }
        !          4514: }
        !          4515: 
        !          4516: static void
        !          4517: ia_na_nomatch_decline(const struct data_string *client_id,
        !          4518:                      const struct data_string *iaaddr,
        !          4519:                      u_int32_t *ia_na_id,
        !          4520:                      struct packet *packet,
        !          4521:                      char *reply_data,
        !          4522:                      int *reply_ofs,
        !          4523:                      int reply_len)
        !          4524: {
        !          4525:        char tmp_addr[INET6_ADDRSTRLEN];
        !          4526:        struct option_state *host_opt_state;
        !          4527:        int len;
        !          4528: 
        !          4529:        log_info("Client %s declines address %s, which is not offered to it.",
        !          4530:                 print_hex_1(client_id->len, client_id->data, 60),
        !          4531:                 inet_ntop(AF_INET6, iaaddr->data, tmp_addr, sizeof(tmp_addr)));
        !          4532: 
        !          4533:        /*
        !          4534:         * Create state for this IA_NA.
        !          4535:         */
        !          4536:        host_opt_state = NULL;
        !          4537:        if (!option_state_allocate(&host_opt_state, MDL)) {
        !          4538:                log_error("ia_na_nomatch_decline: out of memory "
        !          4539:                          "allocating option_state.");
        !          4540:                goto exit;
        !          4541:        }
        !          4542: 
        !          4543:        if (!set_status_code(STATUS_NoBinding, "Decline for unknown address.",
        !          4544:                             host_opt_state)) {
        !          4545:                goto exit;
        !          4546:        }
        !          4547: 
        !          4548:        /*
        !          4549:         * Insure we have enough space
        !          4550:         */
        !          4551:        if (reply_len < (*reply_ofs + 16)) {
        !          4552:                log_error("ia_na_nomatch_decline: "
        !          4553:                          "out of space for reply packet.");
        !          4554:                goto exit;
        !          4555:        }
        !          4556: 
        !          4557:        /*
        !          4558:         * Put our status code into the reply packet.
        !          4559:         */
        !          4560:        len = store_options6(reply_data+(*reply_ofs)+16,
        !          4561:                             reply_len-(*reply_ofs)-16,
        !          4562:                             host_opt_state, packet,
        !          4563:                             required_opts_STATUS_CODE, NULL);
        !          4564: 
        !          4565:        /*
        !          4566:         * Store the non-encapsulated option data for this 
        !          4567:         * IA_NA into our reply packet. Defined in RFC 3315, 
        !          4568:         * section 22.4.  
        !          4569:         */
        !          4570:        /* option number */
        !          4571:        putUShort((unsigned char *)reply_data+(*reply_ofs), D6O_IA_NA);
        !          4572:        /* option length */
        !          4573:        putUShort((unsigned char *)reply_data+(*reply_ofs)+2, len + 12);
        !          4574:        /* IA_NA, copied from the client */
        !          4575:        memcpy(reply_data+(*reply_ofs)+4, ia_na_id, 4);
        !          4576:        /* t1 and t2, odd that we need them, but here it is */
        !          4577:        putULong((unsigned char *)reply_data+(*reply_ofs)+8, 0);
        !          4578:        putULong((unsigned char *)reply_data+(*reply_ofs)+12, 0);
        !          4579: 
        !          4580:        /*
        !          4581:         * Get ready for next IA_NA.
        !          4582:         */
        !          4583:        *reply_ofs += (len + 16);
        !          4584: 
        !          4585: exit:
        !          4586:        option_state_dereference(&host_opt_state, MDL);
        !          4587: }
        !          4588: 
        !          4589: static void
        !          4590: iterate_over_ia_na(struct data_string *reply_ret, 
        !          4591:                   struct packet *packet,
        !          4592:                   const struct data_string *client_id,
        !          4593:                   const struct data_string *server_id,
        !          4594:                   const char *packet_type,
        !          4595:                   void (*ia_na_match)(),
        !          4596:                   void (*ia_na_nomatch)())
        !          4597: {
        !          4598:        struct option_state *opt_state;
        !          4599:        struct host_decl *packet_host;
        !          4600:        struct option_cache *ia;
        !          4601:        struct option_cache *oc;
        !          4602:        /* cli_enc_... variables come from the IA_NA/IA_TA options */
        !          4603:        struct data_string cli_enc_opt_data;
        !          4604:        struct option_state *cli_enc_opt_state;
        !          4605:        struct host_decl *host;
        !          4606:        struct option_state *host_opt_state;
        !          4607:        struct data_string iaaddr;
        !          4608:        struct data_string fixed_addr;
        !          4609:        int iaaddr_is_found;
        !          4610:        char reply_data[65536];
        !          4611:        struct dhcpv6_packet *reply = (struct dhcpv6_packet *)reply_data;
        !          4612:        int reply_ofs = (int)(offsetof(struct dhcpv6_packet, options));
        !          4613:        char status_msg[32];
        !          4614:        struct iasubopt *lease;
        !          4615:        struct ia_xx *existing_ia_na;
        !          4616:        int i;
        !          4617:        struct data_string key;
        !          4618:        u_int32_t iaid;
        !          4619: 
        !          4620:        /*
        !          4621:         * Initialize to empty values, in case we have to exit early.
        !          4622:         */
        !          4623:        opt_state = NULL;
        !          4624:        memset(&cli_enc_opt_data, 0, sizeof(cli_enc_opt_data));
        !          4625:        cli_enc_opt_state = NULL;
        !          4626:        memset(&iaaddr, 0, sizeof(iaaddr));
        !          4627:        memset(&fixed_addr, 0, sizeof(fixed_addr));
        !          4628:        host_opt_state = NULL;
        !          4629:        lease = NULL;
        !          4630: 
        !          4631:        /* 
        !          4632:         * Find the host record that matches from the packet, if any.
        !          4633:         */
        !          4634:        packet_host = NULL;
        !          4635:        if (!find_hosts_by_uid(&packet_host, 
        !          4636:                               client_id->data, client_id->len, MDL)) {
        !          4637:                packet_host = NULL;
        !          4638:                /* 
        !          4639:                 * Note: In general, we don't expect a client to provide
        !          4640:                 *       enough information to match by option for these
        !          4641:                 *       types of messages, but if we don't have a UID
        !          4642:                 *       match we can check anyway.
        !          4643:                 */
        !          4644:                if (!find_hosts_by_option(&packet_host, 
        !          4645:                                          packet, packet->options, MDL)) {
        !          4646:                        packet_host = NULL;
        !          4647:                }
        !          4648:        }
        !          4649: 
        !          4650:        /* 
        !          4651:         * Set our reply information.
        !          4652:         */
        !          4653:        reply->msg_type = DHCPV6_REPLY;
        !          4654:        memcpy(reply->transaction_id, packet->dhcpv6_transaction_id, 
        !          4655:               sizeof(reply->transaction_id));
        !          4656: 
        !          4657:        /*
        !          4658:         * Build our option state for reply.
        !          4659:         */
        !          4660:        opt_state = NULL;
        !          4661:        if (!option_state_allocate(&opt_state, MDL)) {
        !          4662:                log_error("iterate_over_ia_na: no memory for option_state.");
        !          4663:                goto exit;
        !          4664:        }
        !          4665:        execute_statements_in_scope(NULL, packet, NULL, NULL, 
        !          4666:                                    packet->options, opt_state, 
        !          4667:                                    &global_scope, root_group, NULL);
        !          4668: 
        !          4669:        /* 
        !          4670:         * RFC 3315, section 18.2.7 tells us which options to include.
        !          4671:         */
        !          4672:        oc = lookup_option(&dhcpv6_universe, opt_state, D6O_SERVERID);
        !          4673:        if (oc == NULL) {
        !          4674:                if (!save_option_buffer(&dhcpv6_universe, opt_state, NULL, 
        !          4675:                                        (unsigned char *)server_duid.data, 
        !          4676:                                        server_duid.len, D6O_SERVERID, 0)) {
        !          4677:                        log_error("iterate_over_ia_na: "
        !          4678:                                  "error saving server identifier.");
        !          4679:                        goto exit;
        !          4680:                }
        !          4681:        }
        !          4682: 
        !          4683:        if (!save_option_buffer(&dhcpv6_universe, opt_state, 
        !          4684:                                client_id->buffer, 
        !          4685:                                (unsigned char *)client_id->data,
        !          4686:                                client_id->len, 
        !          4687:                                D6O_CLIENTID, 0)) {
        !          4688:                log_error("iterate_over_ia_na: "
        !          4689:                          "error saving client identifier.");
        !          4690:                goto exit;
        !          4691:        }
        !          4692: 
        !          4693:        snprintf(status_msg, sizeof(status_msg), "%s received.", packet_type);
        !          4694:        if (!set_status_code(STATUS_Success, status_msg, opt_state)) {
        !          4695:                goto exit;
        !          4696:        }
        !          4697: 
        !          4698:        /* 
        !          4699:         * Add our options that are not associated with any IA_NA or IA_TA. 
        !          4700:         */
        !          4701:        reply_ofs += store_options6(reply_data+reply_ofs,
        !          4702:                                    sizeof(reply_data)-reply_ofs, 
        !          4703:                                    opt_state, packet,
        !          4704:                                    required_opts, NULL);
        !          4705: 
        !          4706:        /*
        !          4707:         * Loop through the IA_NA reported by the client, and deal with
        !          4708:         * addresses reported as already in use.
        !          4709:         */
        !          4710:        for (ia = lookup_option(&dhcpv6_universe, packet->options, D6O_IA_NA);
        !          4711:             ia != NULL; ia = ia->next) {
        !          4712:                iaaddr_is_found = 0;
        !          4713: 
        !          4714:                if (!get_encapsulated_IA_state(&cli_enc_opt_state,
        !          4715:                                               &cli_enc_opt_data,
        !          4716:                                               packet, ia, IA_NA_OFFSET)) {
        !          4717:                        goto exit;
        !          4718:                }
        !          4719: 
        !          4720:                iaid = getULong(cli_enc_opt_data.data);
        !          4721: 
        !          4722:                /* 
        !          4723:                 * XXX: It is possible that we can get multiple addresses
        !          4724:                 *      sent by the client. We don't send multiple 
        !          4725:                 *      addresses, so this indicates a client error. 
        !          4726:                 *      We should check for multiple IAADDR options, log
        !          4727:                 *      if found, and set as an error.
        !          4728:                 */
        !          4729:                oc = lookup_option(&dhcpv6_universe, cli_enc_opt_state, 
        !          4730:                                   D6O_IAADDR);
        !          4731:                if (oc == NULL) {
        !          4732:                        /* no address given for this IA, ignore */
        !          4733:                        option_state_dereference(&cli_enc_opt_state, MDL);
        !          4734:                        data_string_forget(&cli_enc_opt_data, MDL);
        !          4735:                        continue;
        !          4736:                }
        !          4737: 
        !          4738:                memset(&iaaddr, 0, sizeof(iaaddr));
        !          4739:                if (!evaluate_option_cache(&iaaddr, packet, NULL, NULL, 
        !          4740:                                           packet->options, NULL,
        !          4741:                                           &global_scope, oc, MDL)) {
        !          4742:                        log_error("iterate_over_ia_na: "
        !          4743:                                  "error evaluating IAADDR.");
        !          4744:                        goto exit;
        !          4745:                }
        !          4746: 
        !          4747:                /* 
        !          4748:                 * Now we need to figure out which host record matches
        !          4749:                 * this IA_NA and IAADDR.
        !          4750:                 *
        !          4751:                 * XXX: We don't currently track IA_NA separately, but
        !          4752:                 *      we will need to do this!
        !          4753:                 */
        !          4754:                host = NULL;
        !          4755:                if (!find_hosts_by_option(&host, packet, 
        !          4756:                                          cli_enc_opt_state, MDL)) { 
        !          4757:                        if (packet_host != NULL) {
        !          4758:                                host = packet_host;
        !          4759:                        } else {
        !          4760:                                host = NULL;
        !          4761:                        }
        !          4762:                }
        !          4763:                while (host != NULL) {
        !          4764:                        if (host->fixed_addr != NULL) {
        !          4765:                                if (!evaluate_option_cache(&fixed_addr, NULL, 
        !          4766:                                                           NULL, NULL, NULL, 
        !          4767:                                                           NULL, &global_scope,
        !          4768:                                                           host->fixed_addr, 
        !          4769:                                                           MDL)) {
        !          4770:                                        log_error("iterate_over_ia_na: error "
        !          4771:                                                  "evaluating host address.");
        !          4772:                                        goto exit;
        !          4773:                                }
        !          4774:                                if ((iaaddr.len >= 16) &&
        !          4775:                                    !memcmp(fixed_addr.data, iaaddr.data, 16)) {
        !          4776:                                        data_string_forget(&fixed_addr, MDL);
        !          4777:                                        break;
        !          4778:                                }
        !          4779:                                data_string_forget(&fixed_addr, MDL);
        !          4780:                        }
        !          4781:                        host = host->n_ipaddr;
        !          4782:                }
        !          4783: 
        !          4784:                if ((host == NULL) && (iaaddr.len >= IAADDR_OFFSET)) {
        !          4785:                        /*
        !          4786:                         * Find existing IA_NA.
        !          4787:                         */
        !          4788:                        if (ia_make_key(&key, iaid, 
        !          4789:                                        (char *)client_id->data,
        !          4790:                                        client_id->len, 
        !          4791:                                        MDL) != ISC_R_SUCCESS) {
        !          4792:                                log_fatal("iterate_over_ia_na: no memory for "
        !          4793:                                          "key.");
        !          4794:                        }
        !          4795: 
        !          4796:                        existing_ia_na = NULL;
        !          4797:                        if (ia_hash_lookup(&existing_ia_na, ia_na_active, 
        !          4798:                                           (unsigned char *)key.data, 
        !          4799:                                           key.len, MDL)) {
        !          4800:                                /* 
        !          4801:                                 * Make sure this address is in the IA_NA.
        !          4802:                                 */
        !          4803:                                for (i=0; i<existing_ia_na->num_iasubopt; i++) {
        !          4804:                                        struct iasubopt *tmp;
        !          4805:                                        struct in6_addr *in6_addr;
        !          4806: 
        !          4807:                                        tmp = existing_ia_na->iasubopt[i];
        !          4808:                                        in6_addr = &tmp->addr;
        !          4809:                                        if (memcmp(in6_addr, 
        !          4810:                                                   iaaddr.data, 16) == 0) {
        !          4811:                                                iasubopt_reference(&lease,
        !          4812:                                                                   tmp, MDL);
        !          4813:                                                break;
        !          4814:                                        }
        !          4815:                                }
        !          4816:                        }
        !          4817: 
        !          4818:                        data_string_forget(&key, MDL);
        !          4819:                }
        !          4820: 
        !          4821:                if ((host != NULL) || (lease != NULL)) {
        !          4822:                        ia_na_match(client_id, &iaaddr, lease);
        !          4823:                } else {
        !          4824:                        ia_na_nomatch(client_id, &iaaddr, 
        !          4825:                                      (u_int32_t *)cli_enc_opt_data.data, 
        !          4826:                                      packet, reply_data, &reply_ofs, 
        !          4827:                                      sizeof(reply_data));
        !          4828:                }
        !          4829: 
        !          4830:                if (lease != NULL) {
        !          4831:                        iasubopt_dereference(&lease, MDL);
        !          4832:                }
        !          4833: 
        !          4834:                data_string_forget(&iaaddr, MDL);
        !          4835:                option_state_dereference(&cli_enc_opt_state, MDL);
        !          4836:                data_string_forget(&cli_enc_opt_data, MDL);
        !          4837:        }
        !          4838: 
        !          4839:        /* 
        !          4840:         * Return our reply to the caller.
        !          4841:         */
        !          4842:        reply_ret->len = reply_ofs;
        !          4843:        reply_ret->buffer = NULL;
        !          4844:        if (!buffer_allocate(&reply_ret->buffer, reply_ofs, MDL)) {
        !          4845:                log_fatal("No memory to store reply.");
        !          4846:        }
        !          4847:        reply_ret->data = reply_ret->buffer->data;
        !          4848:        memcpy(reply_ret->buffer->data, reply, reply_ofs);
        !          4849: 
        !          4850: exit:
        !          4851:        if (lease != NULL) {
        !          4852:                iasubopt_dereference(&lease, MDL);
        !          4853:        }
        !          4854:        if (host_opt_state != NULL) {
        !          4855:                option_state_dereference(&host_opt_state, MDL);
        !          4856:        }
        !          4857:        if (fixed_addr.buffer != NULL) {
        !          4858:                data_string_forget(&fixed_addr, MDL);
        !          4859:        }
        !          4860:        if (iaaddr.buffer != NULL) {
        !          4861:                data_string_forget(&iaaddr, MDL);
        !          4862:        }
        !          4863:        if (cli_enc_opt_state != NULL) {
        !          4864:                option_state_dereference(&cli_enc_opt_state, MDL);
        !          4865:        }
        !          4866:        if (cli_enc_opt_data.buffer != NULL) {
        !          4867:                data_string_forget(&cli_enc_opt_data, MDL);
        !          4868:        }
        !          4869:        if (opt_state != NULL) {
        !          4870:                option_state_dereference(&opt_state, MDL);
        !          4871:        }
        !          4872: }
        !          4873: 
        !          4874: /*
        !          4875:  * Decline means a client has detected that something else is using an
        !          4876:  * address we gave it.
        !          4877:  *
        !          4878:  * Since we're only dealing with fixed leases for now, there's not
        !          4879:  * much we can do, other that log the occurrence.
        !          4880:  * 
        !          4881:  * When we start issuing addresses from pools, then we will have to
        !          4882:  * record our declined addresses and issue another. In general with
        !          4883:  * IPv6 there is no worry about DoS by clients exhausting space, but
        !          4884:  * we still need to be aware of this possibility.
        !          4885:  */
        !          4886: 
        !          4887: /* TODO: reject unicast messages, unless we set unicast option */
        !          4888: /* TODO: IA_TA */
        !          4889: static void
        !          4890: dhcpv6_decline(struct data_string *reply, struct packet *packet) {
        !          4891:        struct data_string client_id;
        !          4892:        struct data_string server_id;
        !          4893: 
        !          4894:        /* 
        !          4895:         * Validate our input.
        !          4896:         */
        !          4897:        if (!valid_client_resp(packet, &client_id, &server_id)) {
        !          4898:                return;
        !          4899:        }
        !          4900: 
        !          4901:        /*
        !          4902:         * Undefined for IA_PD.
        !          4903:         */
        !          4904:        delete_option(&dhcpv6_universe, packet->options, D6O_IA_PD);
        !          4905: 
        !          4906:        /*
        !          4907:         * And operate on each IA_NA in this packet.
        !          4908:         */
        !          4909:        iterate_over_ia_na(reply, packet, &client_id, &server_id, "Decline", 
        !          4910:                           ia_na_match_decline, ia_na_nomatch_decline);
        !          4911: 
        !          4912:        data_string_forget(&server_id, MDL);
        !          4913:        data_string_forget(&client_id, MDL);
        !          4914: }
        !          4915: 
        !          4916: static void
        !          4917: ia_na_match_release(const struct data_string *client_id,
        !          4918:                    const struct data_string *iaaddr,
        !          4919:                    struct iasubopt *lease)
        !          4920: {
        !          4921:        char tmp_addr[INET6_ADDRSTRLEN];
        !          4922: 
        !          4923:        log_info("Client %s releases address %s",
        !          4924:                 print_hex_1(client_id->len, client_id->data, 60),
        !          4925:                 inet_ntop(AF_INET6, iaaddr->data, tmp_addr, sizeof(tmp_addr)));
        !          4926:        if (lease != NULL) {
        !          4927:                release_lease6(lease->ipv6_pool, lease);
        !          4928:                lease->ia->cltt = cur_time;
        !          4929:                write_ia(lease->ia);
        !          4930:        }
        !          4931: }
        !          4932: 
        !          4933: static void
        !          4934: ia_na_nomatch_release(const struct data_string *client_id,
        !          4935:                      const struct data_string *iaaddr,
        !          4936:                      u_int32_t *ia_na_id,
        !          4937:                      struct packet *packet,
        !          4938:                      char *reply_data,
        !          4939:                      int *reply_ofs,
        !          4940:                      int reply_len)
        !          4941: {
        !          4942:        char tmp_addr[INET6_ADDRSTRLEN];
        !          4943:        struct option_state *host_opt_state;
        !          4944:        int len;
        !          4945: 
        !          4946:        log_info("Client %s releases address %s, which is not leased to it.",
        !          4947:                 print_hex_1(client_id->len, client_id->data, 60),
        !          4948:                 inet_ntop(AF_INET6, iaaddr->data, tmp_addr, sizeof(tmp_addr)));
        !          4949: 
        !          4950:        /*
        !          4951:         * Create state for this IA_NA.
        !          4952:         */
        !          4953:        host_opt_state = NULL;
        !          4954:        if (!option_state_allocate(&host_opt_state, MDL)) {
        !          4955:                log_error("ia_na_nomatch_release: out of memory "
        !          4956:                          "allocating option_state.");
        !          4957:                goto exit;
        !          4958:        }
        !          4959: 
        !          4960:        if (!set_status_code(STATUS_NoBinding, 
        !          4961:                             "Release for non-leased address.",
        !          4962:                             host_opt_state)) {
        !          4963:                goto exit;
        !          4964:        }
        !          4965: 
        !          4966:        /*
        !          4967:         * Insure we have enough space
        !          4968:         */
        !          4969:        if (reply_len < (*reply_ofs + 16)) {
        !          4970:                log_error("ia_na_nomatch_release: "
        !          4971:                          "out of space for reply packet.");
        !          4972:                goto exit;
        !          4973:        }
        !          4974: 
        !          4975:        /*
        !          4976:         * Put our status code into the reply packet.
        !          4977:         */
        !          4978:        len = store_options6(reply_data+(*reply_ofs)+16,
        !          4979:                             reply_len-(*reply_ofs)-16,
        !          4980:                             host_opt_state, packet,
        !          4981:                             required_opts_STATUS_CODE, NULL);
        !          4982: 
        !          4983:        /*
        !          4984:         * Store the non-encapsulated option data for this 
        !          4985:         * IA_NA into our reply packet. Defined in RFC 3315, 
        !          4986:         * section 22.4.  
        !          4987:         */
        !          4988:        /* option number */
        !          4989:        putUShort((unsigned char *)reply_data+(*reply_ofs), D6O_IA_NA);
        !          4990:        /* option length */
        !          4991:        putUShort((unsigned char *)reply_data+(*reply_ofs)+2, len + 12);
        !          4992:        /* IA_NA, copied from the client */
        !          4993:        memcpy(reply_data+(*reply_ofs)+4, ia_na_id, 4);
        !          4994:        /* t1 and t2, odd that we need them, but here it is */
        !          4995:        putULong((unsigned char *)reply_data+(*reply_ofs)+8, 0);
        !          4996:        putULong((unsigned char *)reply_data+(*reply_ofs)+12, 0);
        !          4997: 
        !          4998:        /*
        !          4999:         * Get ready for next IA_NA.
        !          5000:         */
        !          5001:        *reply_ofs += (len + 16);
        !          5002: 
        !          5003: exit:
        !          5004:        option_state_dereference(&host_opt_state, MDL);
        !          5005: }
        !          5006: 
        !          5007: static void
        !          5008: ia_pd_match_release(const struct data_string *client_id,
        !          5009:                    const struct data_string *iapref,
        !          5010:                    struct iasubopt *prefix)
        !          5011: {
        !          5012:        char tmp_addr[INET6_ADDRSTRLEN];
        !          5013: 
        !          5014:        log_info("Client %s releases prefix %s/%u",
        !          5015:                 print_hex_1(client_id->len, client_id->data, 60),
        !          5016:                 inet_ntop(AF_INET6, iapref->data + 9,
        !          5017:                           tmp_addr, sizeof(tmp_addr)),
        !          5018:                 (unsigned) getUChar(iapref->data + 8));
        !          5019:        if (prefix != NULL) {
        !          5020:                release_lease6(prefix->ipv6_pool, prefix);
        !          5021:                prefix->ia->cltt = cur_time;
        !          5022:                write_ia(prefix->ia);
        !          5023:        }
        !          5024: }
        !          5025: 
        !          5026: static void
        !          5027: ia_pd_nomatch_release(const struct data_string *client_id,
        !          5028:                      const struct data_string *iapref,
        !          5029:                      u_int32_t *ia_pd_id,
        !          5030:                      struct packet *packet,
        !          5031:                      char *reply_data,
        !          5032:                      int *reply_ofs,
        !          5033:                      int reply_len)
        !          5034: {
        !          5035:        char tmp_addr[INET6_ADDRSTRLEN];
        !          5036:        struct option_state *host_opt_state;
        !          5037:        int len;
        !          5038: 
        !          5039:        log_info("Client %s releases prefix %s/%u, which is not leased to it.",
        !          5040:                 print_hex_1(client_id->len, client_id->data, 60),
        !          5041:                 inet_ntop(AF_INET6, iapref->data + 9,
        !          5042:                           tmp_addr, sizeof(tmp_addr)),
        !          5043:                 (unsigned) getUChar(iapref->data + 8));
        !          5044: 
        !          5045:        /*
        !          5046:         * Create state for this IA_PD.
        !          5047:         */
        !          5048:        host_opt_state = NULL;
        !          5049:        if (!option_state_allocate(&host_opt_state, MDL)) {
        !          5050:                log_error("ia_pd_nomatch_release: out of memory "
        !          5051:                          "allocating option_state.");
        !          5052:                goto exit;
        !          5053:        }
        !          5054: 
        !          5055:        if (!set_status_code(STATUS_NoBinding, 
        !          5056:                             "Release for non-leased prefix.",
        !          5057:                             host_opt_state)) {
        !          5058:                goto exit;
        !          5059:        }
        !          5060: 
        !          5061:        /*
        !          5062:         * Insure we have enough space
        !          5063:         */
        !          5064:        if (reply_len < (*reply_ofs + 16)) {
        !          5065:                log_error("ia_pd_nomatch_release: "
        !          5066:                          "out of space for reply packet.");
        !          5067:                goto exit;
        !          5068:        }
        !          5069: 
        !          5070:        /*
        !          5071:         * Put our status code into the reply packet.
        !          5072:         */
        !          5073:        len = store_options6(reply_data+(*reply_ofs)+16,
        !          5074:                             reply_len-(*reply_ofs)-16,
        !          5075:                             host_opt_state, packet,
        !          5076:                             required_opts_STATUS_CODE, NULL);
        !          5077: 
        !          5078:        /*
        !          5079:         * Store the non-encapsulated option data for this 
        !          5080:         * IA_PD into our reply packet. Defined in RFC 3315, 
        !          5081:         * section 22.4.  
        !          5082:         */
        !          5083:        /* option number */
        !          5084:        putUShort((unsigned char *)reply_data+(*reply_ofs), D6O_IA_PD);
        !          5085:        /* option length */
        !          5086:        putUShort((unsigned char *)reply_data+(*reply_ofs)+2, len + 12);
        !          5087:        /* IA_PD, copied from the client */
        !          5088:        memcpy(reply_data+(*reply_ofs)+4, ia_pd_id, 4);
        !          5089:        /* t1 and t2, odd that we need them, but here it is */
        !          5090:        putULong((unsigned char *)reply_data+(*reply_ofs)+8, 0);
        !          5091:        putULong((unsigned char *)reply_data+(*reply_ofs)+12, 0);
        !          5092: 
        !          5093:        /*
        !          5094:         * Get ready for next IA_PD.
        !          5095:         */
        !          5096:        *reply_ofs += (len + 16);
        !          5097: 
        !          5098: exit:
        !          5099:        option_state_dereference(&host_opt_state, MDL);
        !          5100: }
        !          5101: 
        !          5102: static void
        !          5103: iterate_over_ia_pd(struct data_string *reply_ret, 
        !          5104:                   struct packet *packet,
        !          5105:                   const struct data_string *client_id,
        !          5106:                   const struct data_string *server_id,
        !          5107:                   const char *packet_type,
        !          5108:                   void (*ia_pd_match)(),
        !          5109:                   void (*ia_pd_nomatch)())
        !          5110: {
        !          5111:        struct data_string reply_new;
        !          5112:        int reply_len;
        !          5113:        struct option_state *opt_state;
        !          5114:        struct host_decl *packet_host;
        !          5115:        struct option_cache *ia;
        !          5116:        struct option_cache *oc;
        !          5117:        /* cli_enc_... variables come from the IA_PD options */
        !          5118:        struct data_string cli_enc_opt_data;
        !          5119:        struct option_state *cli_enc_opt_state;
        !          5120:        struct host_decl *host;
        !          5121:        struct option_state *host_opt_state;
        !          5122:        struct data_string iaprefix;
        !          5123:        int iaprefix_is_found;
        !          5124:        char reply_data[65536];
        !          5125:        int reply_ofs;
        !          5126:        struct iasubopt *prefix;
        !          5127:        struct ia_xx *existing_ia_pd;
        !          5128:        int i;
        !          5129:        struct data_string key;
        !          5130:        u_int32_t iaid;
        !          5131: 
        !          5132:        /*
        !          5133:         * Initialize to empty values, in case we have to exit early.
        !          5134:         */
        !          5135:        memset(&reply_new, 0, sizeof(reply_new));
        !          5136:        opt_state = NULL;
        !          5137:        memset(&cli_enc_opt_data, 0, sizeof(cli_enc_opt_data));
        !          5138:        cli_enc_opt_state = NULL;
        !          5139:        memset(&iaprefix, 0, sizeof(iaprefix));
        !          5140:        host_opt_state = NULL;
        !          5141:        prefix = NULL;
        !          5142: 
        !          5143:        /*
        !          5144:         * Compute the available length for the reply.
        !          5145:         */
        !          5146:        reply_len = sizeof(reply_data) - reply_ret->len;
        !          5147:        reply_ofs = 0;
        !          5148: 
        !          5149:        /* 
        !          5150:         * Find the host record that matches from the packet, if any.
        !          5151:         */
        !          5152:        packet_host = NULL;
        !          5153:        if (!find_hosts_by_uid(&packet_host, 
        !          5154:                               client_id->data, client_id->len, MDL)) {
        !          5155:                packet_host = NULL;
        !          5156:                /* 
        !          5157:                 * Note: In general, we don't expect a client to provide
        !          5158:                 *       enough information to match by option for these
        !          5159:                 *       types of messages, but if we don't have a UID
        !          5160:                 *       match we can check anyway.
        !          5161:                 */
        !          5162:                if (!find_hosts_by_option(&packet_host, 
        !          5163:                                          packet, packet->options, MDL)) {
        !          5164:                        packet_host = NULL;
        !          5165:                }
        !          5166:        }
        !          5167: 
        !          5168:        /*
        !          5169:         * Build our option state for reply.
        !          5170:         */
        !          5171:        opt_state = NULL;
        !          5172:        if (!option_state_allocate(&opt_state, MDL)) {
        !          5173:                log_error("iterate_over_ia_pd: no memory for option_state.");
        !          5174:                goto exit;
        !          5175:        }
        !          5176:        execute_statements_in_scope(NULL, packet, NULL, NULL, 
        !          5177:                                    packet->options, opt_state, 
        !          5178:                                    &global_scope, root_group, NULL);
        !          5179: 
        !          5180:        /*
        !          5181:         * Loop through the IA_PD reported by the client, and deal with
        !          5182:         * prefixes reported as already in use.
        !          5183:         */
        !          5184:        for (ia = lookup_option(&dhcpv6_universe, packet->options, D6O_IA_PD);
        !          5185:             ia != NULL; ia = ia->next) {
        !          5186:            iaprefix_is_found = 0;
        !          5187: 
        !          5188:            if (!get_encapsulated_IA_state(&cli_enc_opt_state,
        !          5189:                                           &cli_enc_opt_data,
        !          5190:                                           packet, ia, IA_PD_OFFSET)) {
        !          5191:                goto exit;
        !          5192:            }
        !          5193: 
        !          5194:            iaid = getULong(cli_enc_opt_data.data);
        !          5195: 
        !          5196:            oc = lookup_option(&dhcpv6_universe, cli_enc_opt_state, 
        !          5197:                               D6O_IAPREFIX);
        !          5198:            if (oc == NULL) {
        !          5199:                /* no prefix given for this IA_PD, ignore */
        !          5200:                option_state_dereference(&cli_enc_opt_state, MDL);
        !          5201:                data_string_forget(&cli_enc_opt_data, MDL);
        !          5202:                continue;
        !          5203:            }
        !          5204: 
        !          5205:            for (; oc != NULL; oc = oc->next) {
        !          5206:                memset(&iaprefix, 0, sizeof(iaprefix));
        !          5207:                if (!evaluate_option_cache(&iaprefix, packet, NULL, NULL, 
        !          5208:                                           packet->options, NULL,
        !          5209:                                           &global_scope, oc, MDL)) {
        !          5210:                        log_error("iterate_over_ia_pd: "
        !          5211:                                  "error evaluating IAPREFIX.");
        !          5212:                        goto exit;
        !          5213:                }
        !          5214: 
        !          5215:                /* 
        !          5216:                 * Now we need to figure out which host record matches
        !          5217:                 * this IA_PD and IAPREFIX.
        !          5218:                 *
        !          5219:                 * XXX: We don't currently track IA_PD separately, but
        !          5220:                 *      we will need to do this!
        !          5221:                 */
        !          5222:                host = NULL;
        !          5223:                if (!find_hosts_by_option(&host, packet, 
        !          5224:                                          cli_enc_opt_state, MDL)) { 
        !          5225:                        if (packet_host != NULL) {
        !          5226:                                host = packet_host;
        !          5227:                        } else {
        !          5228:                                host = NULL;
        !          5229:                        }
        !          5230:                }
        !          5231:                while (host != NULL) {
        !          5232:                        if (host->fixed_prefix != NULL) {
        !          5233:                                struct iaddrcidrnetlist *l;
        !          5234:                                int plen = (int) getUChar(iaprefix.data + 8);
        !          5235: 
        !          5236:                                for (l = host->fixed_prefix; l != NULL;
        !          5237:                                     l = l->next) {
        !          5238:                                        if (plen != l->cidrnet.bits)
        !          5239:                                                continue;
        !          5240:                                        if (memcmp(iaprefix.data + 9,
        !          5241:                                                   l->cidrnet.lo_addr.iabuf,
        !          5242:                                                   16) == 0)
        !          5243:                                                break;
        !          5244:                                }
        !          5245:                                if ((l != NULL) && (iaprefix.len >= 17))
        !          5246:                                        break;
        !          5247:                        }
        !          5248:                        host = host->n_ipaddr;
        !          5249:                }
        !          5250: 
        !          5251:                if ((host == NULL) && (iaprefix.len >= IAPREFIX_OFFSET)) {
        !          5252:                        /*
        !          5253:                         * Find existing IA_PD.
        !          5254:                         */
        !          5255:                        if (ia_make_key(&key, iaid, 
        !          5256:                                        (char *)client_id->data,
        !          5257:                                        client_id->len, 
        !          5258:                                        MDL) != ISC_R_SUCCESS) {
        !          5259:                                log_fatal("iterate_over_ia_pd: no memory for "
        !          5260:                                          "key.");
        !          5261:                        }
        !          5262: 
        !          5263:                        existing_ia_pd = NULL;
        !          5264:                        if (ia_hash_lookup(&existing_ia_pd, ia_pd_active, 
        !          5265:                                           (unsigned char *)key.data, 
        !          5266:                                           key.len, MDL)) {
        !          5267:                                /* 
        !          5268:                                 * Make sure this prefix is in the IA_PD.
        !          5269:                                 */
        !          5270:                                for (i = 0;
        !          5271:                                     i < existing_ia_pd->num_iasubopt;
        !          5272:                                     i++) {
        !          5273:                                        struct iasubopt *tmp;
        !          5274:                                        u_int8_t plen;
        !          5275: 
        !          5276:                                        plen = getUChar(iaprefix.data + 8);
        !          5277:                                        tmp = existing_ia_pd->iasubopt[i];
        !          5278:                                        if ((tmp->plen == plen) &&
        !          5279:                                            (memcmp(&tmp->addr,
        !          5280:                                                    iaprefix.data + 9,
        !          5281:                                                    16) == 0)) {
        !          5282:                                                iasubopt_reference(&prefix,
        !          5283:                                                                   tmp, MDL);
        !          5284:                                                break;
        !          5285:                                        }
        !          5286:                                }
        !          5287:                        }
        !          5288: 
        !          5289:                        data_string_forget(&key, MDL);
        !          5290:                }
        !          5291: 
        !          5292:                if ((host != NULL) || (prefix != NULL)) {
        !          5293:                        ia_pd_match(client_id, &iaprefix, prefix);
        !          5294:                } else {
        !          5295:                        ia_pd_nomatch(client_id, &iaprefix, 
        !          5296:                                      (u_int32_t *)cli_enc_opt_data.data, 
        !          5297:                                      packet, reply_data, &reply_ofs, 
        !          5298:                                      reply_len - reply_ofs);
        !          5299:                }
        !          5300: 
        !          5301:                if (prefix != NULL) {
        !          5302:                        iasubopt_dereference(&prefix, MDL);
        !          5303:                }
        !          5304: 
        !          5305:                data_string_forget(&iaprefix, MDL);
        !          5306:            }
        !          5307: 
        !          5308:            option_state_dereference(&cli_enc_opt_state, MDL);
        !          5309:            data_string_forget(&cli_enc_opt_data, MDL);
        !          5310:        }
        !          5311: 
        !          5312:        /* 
        !          5313:         * Return our reply to the caller.
        !          5314:         * The IA_NA routine has already filled at least the header.
        !          5315:         */
        !          5316:        reply_new.len = reply_ret->len + reply_ofs;
        !          5317:        if (!buffer_allocate(&reply_new.buffer, reply_new.len, MDL)) {
        !          5318:                log_fatal("No memory to store reply.");
        !          5319:        }
        !          5320:        reply_new.data = reply_new.buffer->data;
        !          5321:        memcpy(reply_new.buffer->data,
        !          5322:               reply_ret->buffer->data, reply_ret->len);
        !          5323:        memcpy(reply_new.buffer->data + reply_ret->len,
        !          5324:               reply_data, reply_ofs);
        !          5325:        data_string_forget(reply_ret, MDL);
        !          5326:        data_string_copy(reply_ret, &reply_new, MDL);
        !          5327:        data_string_forget(&reply_new, MDL);
        !          5328: 
        !          5329: exit:
        !          5330:        if (prefix != NULL) {
        !          5331:                iasubopt_dereference(&prefix, MDL);
        !          5332:        }
        !          5333:        if (host_opt_state != NULL) {
        !          5334:                option_state_dereference(&host_opt_state, MDL);
        !          5335:        }
        !          5336:        if (iaprefix.buffer != NULL) {
        !          5337:                data_string_forget(&iaprefix, MDL);
        !          5338:        }
        !          5339:        if (cli_enc_opt_state != NULL) {
        !          5340:                option_state_dereference(&cli_enc_opt_state, MDL);
        !          5341:        }
        !          5342:        if (cli_enc_opt_data.buffer != NULL) {
        !          5343:                data_string_forget(&cli_enc_opt_data, MDL);
        !          5344:        }
        !          5345:        if (opt_state != NULL) {
        !          5346:                option_state_dereference(&opt_state, MDL);
        !          5347:        }
        !          5348: }
        !          5349: 
        !          5350: /*
        !          5351:  * Release means a client is done with the leases.
        !          5352:  */
        !          5353: 
        !          5354: /* TODO: reject unicast messages, unless we set unicast option */
        !          5355: static void
        !          5356: dhcpv6_release(struct data_string *reply, struct packet *packet) {
        !          5357:        struct data_string client_id;
        !          5358:        struct data_string server_id;
        !          5359: 
        !          5360:        /* 
        !          5361:         * Validate our input.
        !          5362:         */
        !          5363:        if (!valid_client_resp(packet, &client_id, &server_id)) {
        !          5364:                return;
        !          5365:        }
        !          5366: 
        !          5367:        /*
        !          5368:         * And operate on each IA_NA in this packet.
        !          5369:         */
        !          5370:        iterate_over_ia_na(reply, packet, &client_id, &server_id, "Release", 
        !          5371:                           ia_na_match_release, ia_na_nomatch_release);
        !          5372: 
        !          5373:        /*
        !          5374:         * And operate on each IA_PD in this packet.
        !          5375:         */
        !          5376:        iterate_over_ia_pd(reply, packet, &client_id, &server_id, "Release",
        !          5377:                           ia_pd_match_release, ia_pd_nomatch_release);
        !          5378: 
        !          5379:        data_string_forget(&server_id, MDL);
        !          5380:        data_string_forget(&client_id, MDL);
        !          5381: }
        !          5382: 
        !          5383: /*
        !          5384:  * Information-Request is used by clients who have obtained an address
        !          5385:  * from other means, but want configuration information from the server.
        !          5386:  */
        !          5387: 
        !          5388: static void
        !          5389: dhcpv6_information_request(struct data_string *reply, struct packet *packet) {
        !          5390:        struct data_string client_id;
        !          5391:        struct data_string server_id;
        !          5392: 
        !          5393:        /*
        !          5394:         * Validate our input.
        !          5395:         */
        !          5396:        if (!valid_client_info_req(packet, &server_id)) {
        !          5397:                return;
        !          5398:        }
        !          5399: 
        !          5400:        /*
        !          5401:         * Get our client ID, if there is one.
        !          5402:         */
        !          5403:        memset(&client_id, 0, sizeof(client_id));
        !          5404:        if (get_client_id(packet, &client_id) != ISC_R_SUCCESS) {
        !          5405:                data_string_forget(&client_id, MDL);
        !          5406:        }
        !          5407: 
        !          5408:        /*
        !          5409:         * Use the lease_to_client() function. This will work fine, 
        !          5410:         * because the valid_client_info_req() insures that we 
        !          5411:         * don't have any IA that would cause us to allocate
        !          5412:         * resources to the client.
        !          5413:         */
        !          5414:        lease_to_client(reply, packet, &client_id,
        !          5415:                        server_id.data != NULL ? &server_id : NULL);
        !          5416: 
        !          5417:        /*
        !          5418:         * Cleanup.
        !          5419:         */
        !          5420:        if (client_id.data != NULL) {
        !          5421:                data_string_forget(&client_id, MDL);
        !          5422:        }
        !          5423:        data_string_forget(&server_id, MDL);
        !          5424: }
        !          5425: 
        !          5426: /* 
        !          5427:  * The Relay-forw message is sent by relays. It typically contains a
        !          5428:  * single option, which encapsulates an entire packet.
        !          5429:  *
        !          5430:  * We need to build an encapsulated reply.
        !          5431:  */
        !          5432: 
        !          5433: /* XXX: this is very, very similar to do_packet6(), and should probably
        !          5434:        be combined in a clever way */
        !          5435: static void
        !          5436: dhcpv6_relay_forw(struct data_string *reply_ret, struct packet *packet) {
        !          5437:        struct option_cache *oc;
        !          5438:        struct data_string enc_opt_data;
        !          5439:        struct packet *enc_packet;
        !          5440:        unsigned char msg_type;
        !          5441:        const struct dhcpv6_packet *msg;
        !          5442:        const struct dhcpv6_relay_packet *relay;
        !          5443:        struct data_string enc_reply;
        !          5444:        char link_addr[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
        !          5445:        char peer_addr[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
        !          5446:        struct data_string a_opt, packet_ero;
        !          5447:        struct option_state *opt_state;
        !          5448:        static char reply_data[65536];
        !          5449:        struct dhcpv6_relay_packet *reply;
        !          5450:        int reply_ofs;
        !          5451: 
        !          5452:        /* 
        !          5453:         * Initialize variables for early exit.
        !          5454:         */
        !          5455:        opt_state = NULL;
        !          5456:        memset(&a_opt, 0, sizeof(a_opt));
        !          5457:        memset(&packet_ero, 0, sizeof(packet_ero));
        !          5458:        memset(&enc_reply, 0, sizeof(enc_reply));
        !          5459:        memset(&enc_opt_data, 0, sizeof(enc_opt_data));
        !          5460:        enc_packet = NULL;
        !          5461: 
        !          5462:        /*
        !          5463:         * Get our encapsulated relay message.
        !          5464:         */
        !          5465:        oc = lookup_option(&dhcpv6_universe, packet->options, D6O_RELAY_MSG);
        !          5466:        if (oc == NULL) {
        !          5467:                inet_ntop(AF_INET6, &packet->dhcpv6_link_address,
        !          5468:                          link_addr, sizeof(link_addr));
        !          5469:                inet_ntop(AF_INET6, &packet->dhcpv6_peer_address,
        !          5470:                          peer_addr, sizeof(peer_addr));
        !          5471:                log_info("Relay-forward from %s with link address=%s and "
        !          5472:                         "peer address=%s missing Relay Message option.",
        !          5473:                          piaddr(packet->client_addr), link_addr, peer_addr);
        !          5474:                goto exit;
        !          5475:        }
        !          5476: 
        !          5477:        if (!evaluate_option_cache(&enc_opt_data, NULL, NULL, NULL, 
        !          5478:                                   NULL, NULL, &global_scope, oc, MDL)) {
        !          5479:                log_error("dhcpv6_forw_relay: error evaluating "
        !          5480:                          "relayed message.");
        !          5481:                goto exit;
        !          5482:        }
        !          5483: 
        !          5484:        if (!packet6_len_okay((char *)enc_opt_data.data, enc_opt_data.len)) {
        !          5485:                log_error("dhcpv6_forw_relay: encapsulated packet too short.");
        !          5486:                goto exit;
        !          5487:        }
        !          5488: 
        !          5489:        /*
        !          5490:         * Build a packet structure from this encapsulated packet.
        !          5491:         */
        !          5492:        enc_packet = NULL;
        !          5493:        if (!packet_allocate(&enc_packet, MDL)) {
        !          5494:                log_error("dhcpv6_forw_relay: "
        !          5495:                          "no memory for encapsulated packet.");
        !          5496:                goto exit;
        !          5497:        }
        !          5498: 
        !          5499:        if (!option_state_allocate(&enc_packet->options, MDL)) {
        !          5500:                log_error("dhcpv6_forw_relay: "
        !          5501:                          "no memory for encapsulated packet's options.");
        !          5502:                goto exit;
        !          5503:        }
        !          5504: 
        !          5505:        enc_packet->client_port = packet->client_port;
        !          5506:        enc_packet->client_addr = packet->client_addr;
        !          5507:        interface_reference(&enc_packet->interface, packet->interface, MDL);
        !          5508:        enc_packet->dhcpv6_container_packet = packet;
        !          5509: 
        !          5510:        msg_type = enc_opt_data.data[0];
        !          5511:        if ((msg_type == DHCPV6_RELAY_FORW) ||
        !          5512:            (msg_type == DHCPV6_RELAY_REPL)) {
        !          5513:                relay = (struct dhcpv6_relay_packet *)enc_opt_data.data;
        !          5514:                enc_packet->dhcpv6_msg_type = relay->msg_type;
        !          5515: 
        !          5516:                /* relay-specific data */
        !          5517:                enc_packet->dhcpv6_hop_count = relay->hop_count;
        !          5518:                memcpy(&enc_packet->dhcpv6_link_address,
        !          5519:                       relay->link_address, sizeof(relay->link_address));
        !          5520:                memcpy(&enc_packet->dhcpv6_peer_address,
        !          5521:                       relay->peer_address, sizeof(relay->peer_address));
        !          5522: 
        !          5523:                if (!parse_option_buffer(enc_packet->options,
        !          5524:                                         relay->options, 
        !          5525:                                         enc_opt_data.len-sizeof(*relay),
        !          5526:                                         &dhcpv6_universe)) {
        !          5527:                        /* no logging here, as parse_option_buffer() logs all
        !          5528:                           cases where it fails */
        !          5529:                        goto exit;
        !          5530:                }
        !          5531:        } else {
        !          5532:                msg = (struct dhcpv6_packet *)enc_opt_data.data;
        !          5533:                enc_packet->dhcpv6_msg_type = msg->msg_type;
        !          5534: 
        !          5535:                /* message-specific data */
        !          5536:                memcpy(enc_packet->dhcpv6_transaction_id,
        !          5537:                       msg->transaction_id,
        !          5538:                       sizeof(enc_packet->dhcpv6_transaction_id));
        !          5539: 
        !          5540:                if (!parse_option_buffer(enc_packet->options,
        !          5541:                                         msg->options, 
        !          5542:                                         enc_opt_data.len-sizeof(*msg),
        !          5543:                                         &dhcpv6_universe)) {
        !          5544:                        /* no logging here, as parse_option_buffer() logs all
        !          5545:                           cases where it fails */
        !          5546:                        goto exit;
        !          5547:                }
        !          5548:        }
        !          5549: 
        !          5550:        /*
        !          5551:         * This is recursive. It is possible to exceed maximum packet size.
        !          5552:         * XXX: This will cause the packet send to fail.
        !          5553:         */
        !          5554:        build_dhcpv6_reply(&enc_reply, enc_packet);
        !          5555: 
        !          5556:        /*
        !          5557:         * If we got no encapsulated data, then it is discarded, and
        !          5558:         * our reply-forw is also discarded.
        !          5559:         */
        !          5560:        if (enc_reply.data == NULL) {
        !          5561:                goto exit;
        !          5562:        }
        !          5563: 
        !          5564:        /*
        !          5565:         * Now we can use the reply_data buffer.
        !          5566:         * Packet header stuff all comes from the forward message.
        !          5567:         */
        !          5568:        reply = (struct dhcpv6_relay_packet *)reply_data;
        !          5569:        reply->msg_type = DHCPV6_RELAY_REPL;
        !          5570:        reply->hop_count = packet->dhcpv6_hop_count;
        !          5571:        memcpy(reply->link_address, &packet->dhcpv6_link_address,
        !          5572:               sizeof(reply->link_address));
        !          5573:        memcpy(reply->peer_address, &packet->dhcpv6_peer_address,
        !          5574:               sizeof(reply->peer_address));
        !          5575:        reply_ofs = (int)(offsetof(struct dhcpv6_relay_packet, options));
        !          5576: 
        !          5577:        /*
        !          5578:         * Get the reply option state.
        !          5579:         */
        !          5580:        opt_state = NULL;
        !          5581:        if (!option_state_allocate(&opt_state, MDL)) {
        !          5582:                log_error("dhcpv6_relay_forw: no memory for option state.");
        !          5583:                goto exit;
        !          5584:        }
        !          5585: 
        !          5586:        /*
        !          5587:         * Append the interface-id if present.
        !          5588:         */
        !          5589:        oc = lookup_option(&dhcpv6_universe, packet->options,
        !          5590:                           D6O_INTERFACE_ID);
        !          5591:        if (oc != NULL) {
        !          5592:                if (!evaluate_option_cache(&a_opt, packet,
        !          5593:                                           NULL, NULL, 
        !          5594:                                           packet->options, NULL,
        !          5595:                                           &global_scope, oc, MDL)) {
        !          5596:                        log_error("dhcpv6_relay_forw: error evaluating "
        !          5597:                                  "Interface ID.");
        !          5598:                        goto exit;
        !          5599:                }
        !          5600:                if (!save_option_buffer(&dhcpv6_universe, opt_state, NULL,
        !          5601:                                        (unsigned char *)a_opt.data,
        !          5602:                                        a_opt.len,
        !          5603:                                        D6O_INTERFACE_ID, 0)) {
        !          5604:                        log_error("dhcpv6_relay_forw: error saving "
        !          5605:                                  "Interface ID.");
        !          5606:                        goto exit;
        !          5607:                }
        !          5608:                data_string_forget(&a_opt, MDL);
        !          5609:        }
        !          5610: 
        !          5611:        /* 
        !          5612:         * Append our encapsulated stuff for caller.
        !          5613:         */
        !          5614:        if (!save_option_buffer(&dhcpv6_universe, opt_state, NULL,
        !          5615:                                (unsigned char *)enc_reply.data,
        !          5616:                                enc_reply.len,
        !          5617:                                D6O_RELAY_MSG, 0)) {
        !          5618:                log_error("dhcpv6_relay_forw: error saving Relay MSG.");
        !          5619:                goto exit;
        !          5620:        }
        !          5621: 
        !          5622:        /*
        !          5623:         * Get the ERO if any.
        !          5624:         */
        !          5625:        oc = lookup_option(&dhcpv6_universe, packet->options, D6O_ERO);
        !          5626:        if (oc != NULL) {
        !          5627:                unsigned req;
        !          5628:                int i;
        !          5629: 
        !          5630:                if (!evaluate_option_cache(&packet_ero, packet,
        !          5631:                                           NULL, NULL,
        !          5632:                                           packet->options, NULL,
        !          5633:                                           &global_scope, oc, MDL) ||
        !          5634:                        (packet_ero.len & 1)) {
        !          5635:                        log_error("dhcpv6_relay_forw: error evaluating ERO.");
        !          5636:                        goto exit;
        !          5637:                }
        !          5638: 
        !          5639:                /* Decode and apply the ERO. */
        !          5640:                for (i = 0; i < packet_ero.len; i += 2) {
        !          5641:                        req = getUShort(packet_ero.data + i);
        !          5642:                        /* Already in the reply? */
        !          5643:                        oc = lookup_option(&dhcpv6_universe, opt_state, req);
        !          5644:                        if (oc != NULL)
        !          5645:                                continue;
        !          5646:                        /* Get it from the packet if present. */
        !          5647:                        oc = lookup_option(&dhcpv6_universe,
        !          5648:                                           packet->options,
        !          5649:                                           req);
        !          5650:                        if (oc == NULL)
        !          5651:                                continue;
        !          5652:                        if (!evaluate_option_cache(&a_opt, packet,
        !          5653:                                                   NULL, NULL,
        !          5654:                                                   packet->options, NULL,
        !          5655:                                                   &global_scope, oc, MDL)) {
        !          5656:                                log_error("dhcpv6_relay_forw: error "
        !          5657:                                          "evaluating option %u.", req);
        !          5658:                                goto exit;
        !          5659:                        }
        !          5660:                        if (!save_option_buffer(&dhcpv6_universe,
        !          5661:                                                opt_state,
        !          5662:                                                NULL,
        !          5663:                                                (unsigned char *)a_opt.data,
        !          5664:                                                a_opt.len,
        !          5665:                                                req,
        !          5666:                                                0)) {
        !          5667:                                log_error("dhcpv6_relay_forw: error saving "
        !          5668:                                          "option %u.", req);
        !          5669:                                goto exit;
        !          5670:                        }
        !          5671:                        data_string_forget(&a_opt, MDL);
        !          5672:                }
        !          5673:        }
        !          5674: 
        !          5675:        reply_ofs += store_options6(reply_data + reply_ofs,
        !          5676:                                    sizeof(reply_data) - reply_ofs,
        !          5677:                                    opt_state, packet,
        !          5678:                                    required_opts_agent, &packet_ero);
        !          5679: 
        !          5680:        /*
        !          5681:         * Return our reply to the caller.
        !          5682:         */
        !          5683:        reply_ret->len = reply_ofs;
        !          5684:        reply_ret->buffer = NULL;
        !          5685:        if (!buffer_allocate(&reply_ret->buffer, reply_ret->len, MDL)) {
        !          5686:                log_fatal("No memory to store reply.");
        !          5687:        }
        !          5688:        reply_ret->data = reply_ret->buffer->data;
        !          5689:        memcpy(reply_ret->buffer->data, reply_data, reply_ofs);
        !          5690: 
        !          5691: exit:
        !          5692:        if (opt_state != NULL)
        !          5693:                option_state_dereference(&opt_state, MDL);
        !          5694:        if (a_opt.data != NULL) {
        !          5695:                data_string_forget(&a_opt, MDL);
        !          5696:        }
        !          5697:        if (packet_ero.data != NULL) {
        !          5698:                data_string_forget(&packet_ero, MDL);
        !          5699:        }
        !          5700:        if (enc_reply.data != NULL) {
        !          5701:                data_string_forget(&enc_reply, MDL);
        !          5702:        }
        !          5703:        if (enc_opt_data.data != NULL) {
        !          5704:                data_string_forget(&enc_opt_data, MDL);
        !          5705:        }
        !          5706:        if (enc_packet != NULL) {
        !          5707:                packet_dereference(&enc_packet, MDL);
        !          5708:        }
        !          5709: }
        !          5710: 
        !          5711: static void
        !          5712: dhcpv6_discard(struct packet *packet) {
        !          5713:        /* INSIST(packet->msg_type > 0); */
        !          5714:        /* INSIST(packet->msg_type < dhcpv6_type_name_max); */
        !          5715: 
        !          5716:        log_debug("Discarding %s from %s; message type not handled by server", 
        !          5717:                  dhcpv6_type_names[packet->dhcpv6_msg_type],
        !          5718:                  piaddr(packet->client_addr));
        !          5719: }
        !          5720: 
        !          5721: static void 
        !          5722: build_dhcpv6_reply(struct data_string *reply, struct packet *packet) {
        !          5723:        memset(reply, 0, sizeof(*reply));
        !          5724:        switch (packet->dhcpv6_msg_type) {
        !          5725:                case DHCPV6_SOLICIT:
        !          5726:                        dhcpv6_solicit(reply, packet);
        !          5727:                        break;
        !          5728:                case DHCPV6_ADVERTISE:
        !          5729:                        dhcpv6_discard(packet);
        !          5730:                        break;
        !          5731:                case DHCPV6_REQUEST:
        !          5732:                        dhcpv6_request(reply, packet);
        !          5733:                        break;
        !          5734:                case DHCPV6_CONFIRM:
        !          5735:                        dhcpv6_confirm(reply, packet);
        !          5736:                        break;
        !          5737:                case DHCPV6_RENEW:
        !          5738:                        dhcpv6_renew(reply, packet);
        !          5739:                        break;
        !          5740:                case DHCPV6_REBIND:
        !          5741:                        dhcpv6_rebind(reply, packet);
        !          5742:                        break;
        !          5743:                case DHCPV6_REPLY:
        !          5744:                        dhcpv6_discard(packet);
        !          5745:                        break;
        !          5746:                case DHCPV6_RELEASE:
        !          5747:                        dhcpv6_release(reply, packet);
        !          5748:                        break;
        !          5749:                case DHCPV6_DECLINE:
        !          5750:                        dhcpv6_decline(reply, packet);
        !          5751:                        break;
        !          5752:                case DHCPV6_RECONFIGURE:
        !          5753:                        dhcpv6_discard(packet);
        !          5754:                        break;
        !          5755:                case DHCPV6_INFORMATION_REQUEST:
        !          5756:                        dhcpv6_information_request(reply, packet);
        !          5757:                        break;
        !          5758:                case DHCPV6_RELAY_FORW:
        !          5759:                        dhcpv6_relay_forw(reply, packet);
        !          5760:                        break;
        !          5761:                case DHCPV6_RELAY_REPL:
        !          5762:                        dhcpv6_discard(packet);
        !          5763:                        break;
        !          5764:                case DHCPV6_LEASEQUERY:
        !          5765:                        dhcpv6_leasequery(reply, packet);
        !          5766:                        break;
        !          5767:                case DHCPV6_LEASEQUERY_REPLY:
        !          5768:                        dhcpv6_discard(packet);
        !          5769:                        break;
        !          5770:                default:
        !          5771:                        /* XXX: would be nice if we had "notice" level, 
        !          5772:                                as syslog, for this */
        !          5773:                        log_info("Discarding unknown DHCPv6 message type %d "
        !          5774:                                 "from %s", packet->dhcpv6_msg_type, 
        !          5775:                                 piaddr(packet->client_addr));
        !          5776:        }
        !          5777: }
        !          5778: 
        !          5779: static void
        !          5780: log_packet_in(const struct packet *packet) {
        !          5781:        struct data_string s;
        !          5782:        u_int32_t tid;
        !          5783:        char tmp_addr[INET6_ADDRSTRLEN];
        !          5784:        const void *addr;
        !          5785: 
        !          5786:        memset(&s, 0, sizeof(s));
        !          5787: 
        !          5788:        if (packet->dhcpv6_msg_type < dhcpv6_type_name_max) {
        !          5789:                data_string_sprintfa(&s, "%s message from %s port %d",
        !          5790:                                     dhcpv6_type_names[packet->dhcpv6_msg_type],
        !          5791:                                     piaddr(packet->client_addr),
        !          5792:                                     ntohs(packet->client_port));
        !          5793:        } else {
        !          5794:                data_string_sprintfa(&s, 
        !          5795:                                     "Unknown message type %d from %s port %d",
        !          5796:                                     packet->dhcpv6_msg_type,
        !          5797:                                     piaddr(packet->client_addr),
        !          5798:                                     ntohs(packet->client_port));
        !          5799:        }
        !          5800:        if ((packet->dhcpv6_msg_type == DHCPV6_RELAY_FORW) || 
        !          5801:            (packet->dhcpv6_msg_type == DHCPV6_RELAY_REPL)) {
        !          5802:                addr = &packet->dhcpv6_link_address;
        !          5803:                data_string_sprintfa(&s, ", link address %s", 
        !          5804:                                     inet_ntop(AF_INET6, addr, 
        !          5805:                                               tmp_addr, sizeof(tmp_addr)));
        !          5806:                addr = &packet->dhcpv6_peer_address;
        !          5807:                data_string_sprintfa(&s, ", peer address %s", 
        !          5808:                                     inet_ntop(AF_INET6, addr, 
        !          5809:                                               tmp_addr, sizeof(tmp_addr)));
        !          5810:        } else {
        !          5811:                tid = 0;
        !          5812:                memcpy(((char *)&tid)+1, packet->dhcpv6_transaction_id, 3);
        !          5813:                data_string_sprintfa(&s, ", transaction ID 0x%06X", tid);
        !          5814: 
        !          5815: /*
        !          5816:                oc = lookup_option(&dhcpv6_universe, packet->options, 
        !          5817:                                   D6O_CLIENTID);
        !          5818:                if (oc != NULL) {
        !          5819:                        memset(&tmp_ds, 0, sizeof(tmp_ds_));
        !          5820:                        if (!evaluate_option_cache(&tmp_ds, packet, NULL, NULL, 
        !          5821:                                                   packet->options, NULL,
        !          5822:                                                   &global_scope, oc, MDL)) {
        !          5823:                                log_error("Error evaluating Client Identifier");
        !          5824:                        } else {
        !          5825:                                data_strint_sprintf(&s, ", client ID %s",
        !          5826: 
        !          5827:                                data_string_forget(&tmp_ds, MDL);
        !          5828:                        }
        !          5829:                }
        !          5830: */
        !          5831: 
        !          5832:        }
        !          5833:        log_info("%s", s.data);
        !          5834: 
        !          5835:        data_string_forget(&s, MDL);
        !          5836: }
        !          5837: 
        !          5838: void 
        !          5839: dhcpv6(struct packet *packet) {
        !          5840:        struct data_string reply;
        !          5841:        struct sockaddr_in6 to_addr;
        !          5842:        int send_ret;
        !          5843: 
        !          5844:        /* 
        !          5845:         * Log a message that we received this packet.
        !          5846:         */
        !          5847:        log_packet_in(packet); 
        !          5848: 
        !          5849:        /*
        !          5850:         * Build our reply packet.
        !          5851:         */
        !          5852:        build_dhcpv6_reply(&reply, packet);
        !          5853: 
        !          5854:        if (reply.data != NULL) {
        !          5855:                /* 
        !          5856:                 * Send our reply, if we have one.
        !          5857:                 */
        !          5858:                memset(&to_addr, 0, sizeof(to_addr));
        !          5859:                to_addr.sin6_family = AF_INET6;
        !          5860:                if ((packet->dhcpv6_msg_type == DHCPV6_RELAY_FORW) || 
        !          5861:                    (packet->dhcpv6_msg_type == DHCPV6_RELAY_REPL)) {
        !          5862:                        to_addr.sin6_port = local_port;
        !          5863:                } else {
        !          5864:                        to_addr.sin6_port = remote_port;
        !          5865:                }
        !          5866: 
        !          5867: #if defined (REPLY_TO_SOURCE_PORT)
        !          5868:                /*
        !          5869:                 * This appears to have been included for testing so we would
        !          5870:                 * not need a root client, but was accidently left in the
        !          5871:                 * final code.  We continue to include it in case
        !          5872:                 * some users have come to rely upon it, but leave
        !          5873:                 * it off by default as it's a bad idea.
        !          5874:                 */
        !          5875:                to_addr.sin6_port = packet->client_port;
        !          5876: #endif
        !          5877: 
        !          5878:                memcpy(&to_addr.sin6_addr, packet->client_addr.iabuf, 
        !          5879:                       sizeof(to_addr.sin6_addr));
        !          5880: 
        !          5881:                log_info("Sending %s to %s port %d", 
        !          5882:                         dhcpv6_type_names[reply.data[0]],
        !          5883:                         piaddr(packet->client_addr),
        !          5884:                         ntohs(to_addr.sin6_port));
        !          5885: 
        !          5886:                send_ret = send_packet6(packet->interface, 
        !          5887:                                        reply.data, reply.len, &to_addr);
        !          5888:                if (send_ret != reply.len) {
        !          5889:                        log_error("dhcpv6: send_packet6() sent %d of %d bytes",
        !          5890:                                  send_ret, reply.len);
        !          5891:                }
        !          5892:                data_string_forget(&reply, MDL);
        !          5893:        }
        !          5894: }
        !          5895: 
        !          5896: static void
        !          5897: seek_shared_host(struct host_decl **hp, struct shared_network *shared) {
        !          5898:        struct host_decl *nofixed = NULL;
        !          5899:        struct host_decl *seek, *hold = NULL;
        !          5900: 
        !          5901:        /*
        !          5902:         * Seek forward through fixed addresses for the right link.
        !          5903:         *
        !          5904:         * Note: how to do this for fixed prefixes???
        !          5905:         */
        !          5906:        host_reference(&hold, *hp, MDL);
        !          5907:        host_dereference(hp, MDL);
        !          5908:        seek = hold;
        !          5909:        while (seek != NULL) {
        !          5910:                if (seek->fixed_addr == NULL)
        !          5911:                        nofixed = seek;
        !          5912:                else if (fixed_matches_shared(seek, shared))
        !          5913:                        break;
        !          5914: 
        !          5915:                seek = seek->n_ipaddr;
        !          5916:        }
        !          5917: 
        !          5918:        if ((seek == NULL) && (nofixed != NULL))
        !          5919:                seek = nofixed;
        !          5920: 
        !          5921:        if (seek != NULL)
        !          5922:                host_reference(hp, seek, MDL);
        !          5923: }
        !          5924: 
        !          5925: static isc_boolean_t
        !          5926: fixed_matches_shared(struct host_decl *host, struct shared_network *shared) {
        !          5927:        struct subnet *subnet;
        !          5928:        struct data_string addr;
        !          5929:        isc_boolean_t matched;
        !          5930:        struct iaddr fixed;
        !          5931: 
        !          5932:        if (host->fixed_addr == NULL)
        !          5933:                return ISC_FALSE;
        !          5934: 
        !          5935:        memset(&addr, 0, sizeof(addr));
        !          5936:        if (!evaluate_option_cache(&addr, NULL, NULL, NULL, NULL, NULL,
        !          5937:                                   &global_scope, host->fixed_addr, MDL))
        !          5938:                return ISC_FALSE;
        !          5939: 
        !          5940:        if (addr.len < 16) {
        !          5941:                data_string_forget(&addr, MDL);
        !          5942:                return ISC_FALSE;
        !          5943:        }
        !          5944: 
        !          5945:        fixed.len = 16;
        !          5946:        memcpy(fixed.iabuf, addr.data, 16);
        !          5947: 
        !          5948:        matched = ISC_FALSE;
        !          5949:        for (subnet = shared->subnets ; subnet != NULL ;
        !          5950:             subnet = subnet->next_sibling) {
        !          5951:                if (addr_eq(subnet_number(fixed, subnet->netmask),
        !          5952:                            subnet->net)) {
        !          5953:                        matched = ISC_TRUE;
        !          5954:                        break;
        !          5955:                }
        !          5956:        }
        !          5957: 
        !          5958:        data_string_forget(&addr, MDL);
        !          5959:        return matched;
        !          5960: }
        !          5961: 
        !          5962: #endif /* DHCPv6 */
        !          5963: 

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