Annotation of embedaddon/dhcp/server/dhcpleasequery.c, revision 1.1.1.1

1.1       misho       1: /*
1.1.1.1 ! misho       2:  * Copyright (C) 2012 by Internet Systems Consortium, Inc. ("ISC")
1.1       misho       3:  * Copyright (C) 2006-2007 by Internet Systems Consortium, Inc. ("ISC")
                      4:  *
                      5:  * Permission to use, copy, modify, and distribute this software for any
                      6:  * purpose with or without fee is hereby granted, provided that the above
                      7:  * copyright notice and this permission notice appear in all copies.
                      8:  *
                      9:  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
                     10:  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
                     11:  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
                     12:  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
                     13:  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
                     14:  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
                     15:  * PERFORMANCE OF THIS SOFTWARE.
                     16:  */
                     17: 
                     18: #include "dhcpd.h"
                     19: 
                     20: /*
                     21:  * TODO: RFC4388 specifies that the server SHOULD return the same
                     22:  *       options it would for a DHCREQUEST message, if no Parameter
                     23:  *       Request List option (option 55) is passed. We do not do that.
                     24:  *
                     25:  * TODO: RFC4388 specifies the creation of a "non-sensitive options"
                     26:  *       configuration list, and that these SHOULD be returned. We
                     27:  *       have no such list.
                     28:  *
                     29:  * TODO: RFC4388 says the server SHOULD use RFC3118, "Authentication
                     30:  *       for DHCP Messages".
                     31:  *
                     32:  * TODO: RFC4388 specifies that you SHOULD insure that you cannot be
                     33:  *       DoS'ed by DHCPLEASEQUERY message.
                     34:  */
                     35: 
                     36: /* 
                     37:  * If you query by hardware address or by client ID, then you may have
                     38:  * more than one IP address for your query argument. We need to do two
                     39:  * things:
                     40:  *
                     41:  *   1. Find the most recent lease.
                     42:  *   2. Find all additional IP addresses for the query argument.
                     43:  *
                     44:  * We do this by looking through all of the leases associated with a
                     45:  * given hardware address or client ID. We use the cltt (client last
                     46:  * transaction time) of the lease, which only has a resolution of one
                     47:  * second, so we might not actually give the very latest IP.
                     48:  */
                     49: 
                     50: static struct lease*
                     51: next_hw(const struct lease *lease) {
                     52:        /* INSIST(lease != NULL); */
                     53:        return lease->n_hw;
                     54: }
                     55: 
                     56: static struct lease*
                     57: next_uid(const struct lease *lease) {
                     58:        /* INSIST(lease != NULL); */
                     59:        return lease->n_uid;
                     60: }
                     61: 
                     62: void
                     63: get_newest_lease(struct lease **retval,
                     64:                 struct lease *lease,
                     65:                 struct lease *(*next)(const struct lease *)) {
                     66: 
                     67:        struct lease *p;
                     68:        struct lease *newest;
                     69: 
                     70:        /* INSIST(newest != NULL); */
                     71:        /* INSIST(next != NULL); */
                     72: 
                     73:        *retval = NULL;
                     74: 
                     75:        if (lease == NULL) {
                     76:                return;
                     77:        }
                     78: 
                     79:        newest = lease;
                     80:        for (p=next(lease); p != NULL; p=next(p)) {
                     81:                if (newest->binding_state == FTS_ACTIVE) {
                     82:                        if ((p->binding_state == FTS_ACTIVE) && 
                     83:                        (p->cltt > newest->cltt)) {
                     84:                                newest = p;
                     85:                        }
                     86:                } else {
                     87:                        if (p->ends > newest->ends) {
                     88:                                newest = p;
                     89:                        }
                     90:                }
                     91:        }
                     92: 
                     93:        lease_reference(retval, newest, MDL);
                     94: }
                     95: 
                     96: static int
                     97: get_associated_ips(const struct lease *lease,
                     98:                   struct lease *(*next)(const struct lease *), 
                     99:                   const struct lease *newest,
                    100:                   u_int32_t *associated_ips,
                    101:                   unsigned int associated_ips_size) {
                    102: 
                    103:        const struct lease *p;
                    104:        int cnt;
                    105: 
                    106:        /* INSIST(next != NULL); */
                    107:        /* INSIST(associated_ips != NULL); */
                    108: 
                    109:        if (lease == NULL) {
                    110:                return 0;
                    111:        }
                    112: 
                    113:        cnt = 0;
                    114:        for (p=lease; p != NULL; p=next(p)) {
                    115:                if ((p->binding_state == FTS_ACTIVE) && (p != newest)) {
                    116:                        if (cnt < associated_ips_size) {
                    117:                                memcpy(&associated_ips[cnt],
                    118:                                       p->ip_addr.iabuf,
                    119:                                       sizeof(associated_ips[cnt]));
                    120:                        }
                    121:                        cnt++;
                    122:                }
                    123:        }
                    124:        return cnt;
                    125: }
                    126: 
                    127: 
                    128: void 
                    129: dhcpleasequery(struct packet *packet, int ms_nulltp) {
                    130:        char msgbuf[256];
                    131:        char dbg_info[128];
                    132:        struct iaddr cip;
                    133:        struct iaddr gip;
                    134:        struct data_string uid;
                    135:        struct hardware h;
                    136:        struct lease *tmp_lease;
                    137:        struct lease *lease;
                    138:        int want_associated_ip;
                    139:        int assoc_ip_cnt;
                    140:        u_int32_t assoc_ips[40];  /* XXXSK: arbitrary maximum number of IPs */
                    141:        const int nassoc_ips = sizeof(assoc_ips) / sizeof(assoc_ips[0]);
                    142: 
                    143:        unsigned char dhcpMsgType;
                    144:        const char *dhcp_msg_type_name;
                    145:        struct subnet *subnet;
                    146:        struct group *relay_group;
                    147:        struct option_state *options;
                    148:        struct option_cache *oc;
                    149:        int allow_leasequery;
                    150:        int ignorep;
                    151:        u_int32_t lease_duration;
                    152:        u_int32_t time_renewal;
                    153:        u_int32_t time_rebinding;
                    154:        u_int32_t time_expiry;
                    155:        u_int32_t client_last_transaction_time;
                    156:        struct sockaddr_in to;
                    157:        struct in_addr siaddr;
                    158:        struct data_string prl;
                    159:        struct data_string *prl_ptr;
                    160: 
                    161:        int i;
                    162:        struct interface_info *interface;
                    163: 
                    164:        /* INSIST(packet != NULL); */
                    165: 
                    166:        /*
                    167:         * Prepare log information.
                    168:         */
                    169:        snprintf(msgbuf, sizeof(msgbuf), 
                    170:                "DHCPLEASEQUERY from %s", inet_ntoa(packet->raw->giaddr));
                    171: 
                    172:        /* 
                    173:         * We can't reply if there is no giaddr field.
                    174:         */
                    175:        if (!packet->raw->giaddr.s_addr) {
                    176:                log_info("%s: missing giaddr, ciaddr is %s, no reply sent", 
                    177:                         msgbuf, inet_ntoa(packet->raw->ciaddr));
                    178:                return;
                    179:        }
                    180: 
                    181:        /* 
                    182:         * Initially we use the 'giaddr' subnet options scope to determine if
                    183:         * the giaddr-identified relay agent is permitted to perform a
                    184:         * leasequery.  The subnet is not required, and may be omitted, in
                    185:         * which case we are essentially interrogating the root options class
                    186:         * to find a globally permit.
                    187:         */
                    188:        gip.len = sizeof(packet->raw->giaddr);
                    189:        memcpy(gip.iabuf, &packet->raw->giaddr, sizeof(packet->raw->giaddr));
                    190: 
                    191:        subnet = NULL;
                    192:        find_subnet(&subnet, gip, MDL);
                    193:        if (subnet != NULL)
                    194:                relay_group = subnet->group;
                    195:        else
                    196:                relay_group = root_group;
                    197: 
                    198:        subnet_dereference(&subnet, MDL);
                    199: 
                    200:        options = NULL;
                    201:        if (!option_state_allocate(&options, MDL)) {
                    202:                log_error("No memory for option state.");
                    203:                log_info("%s: out of memory, no reply sent", msgbuf);
                    204:                return;
                    205:        }
                    206: 
                    207:        execute_statements_in_scope(NULL,
                    208:                                    packet,
                    209:                                    NULL,
                    210:                                    NULL,
                    211:                                    packet->options,
                    212:                                    options,
                    213:                                    &global_scope,
                    214:                                    relay_group,
                    215:                                    NULL);
                    216: 
                    217:        for (i=packet->class_count-1; i>=0; i--) {
                    218:                execute_statements_in_scope(NULL,
                    219:                                            packet,
                    220:                                            NULL,
                    221:                                            NULL,
                    222:                                            packet->options,
                    223:                                            options,
                    224:                                            &global_scope,
                    225:                                            packet->classes[i]->group,
                    226:                                            relay_group);
                    227:        }
                    228: 
                    229:        /* 
                    230:         * Because LEASEQUERY has some privacy concerns, default to deny.
                    231:         */
                    232:        allow_leasequery = 0;
                    233: 
                    234:        /*
                    235:         * See if we are authorized to do LEASEQUERY.
                    236:         */
                    237:        oc = lookup_option(&server_universe, options, SV_LEASEQUERY);
                    238:        if (oc != NULL) {
                    239:                allow_leasequery = evaluate_boolean_option_cache(&ignorep,
                    240:                                         packet, NULL, NULL, packet->options,
                    241:                                         options, &global_scope, oc, MDL);
                    242:        }
                    243: 
                    244:        if (!allow_leasequery) {
                    245:                log_info("%s: LEASEQUERY not allowed, query ignored", msgbuf);
                    246:                option_state_dereference(&options, MDL);
                    247:                return;
                    248:        }
                    249: 
                    250: 
                    251:        /* 
                    252:         * Copy out the client IP address.
                    253:         */
                    254:        cip.len = sizeof(packet->raw->ciaddr);
                    255:        memcpy(cip.iabuf, &packet->raw->ciaddr, sizeof(packet->raw->ciaddr));
                    256: 
                    257:        /* 
                    258:         * If the client IP address is valid (not all zero), then we 
                    259:         * are looking for information about that IP address.
                    260:         */
                    261:        assoc_ip_cnt = 0;
                    262:        lease = tmp_lease = NULL;
                    263:        if (memcmp(cip.iabuf, "\0\0\0", 4)) {
                    264: 
                    265:                want_associated_ip = 0;
                    266: 
                    267:                snprintf(dbg_info, sizeof(dbg_info), "IP %s", piaddr(cip));
                    268:                find_lease_by_ip_addr(&lease, cip, MDL);
                    269: 
                    270: 
                    271:        } else {
                    272: 
                    273:                want_associated_ip = 1;
                    274: 
                    275:                /*
                    276:                 * If the client IP address is all zero, then we will
                    277:                 * either look up by the client identifier (if we have
                    278:                 * one), or by the MAC address.
                    279:                 */
                    280: 
                    281:                memset(&uid, 0, sizeof(uid));
                    282:                if (get_option(&uid, 
                    283:                               &dhcp_universe,
                    284:                               packet,
                    285:                               NULL,
                    286:                               NULL,
                    287:                               packet->options,
                    288:                               NULL,
                    289:                               packet->options, 
                    290:                               &global_scope,
                    291:                               DHO_DHCP_CLIENT_IDENTIFIER,
                    292:                               MDL)) {
                    293: 
                    294:                        snprintf(dbg_info, 
                    295:                                 sizeof(dbg_info), 
                    296:                                 "client-id %s",
                    297:                                 print_hex_1(uid.len, uid.data, 60));
                    298: 
                    299:                        find_lease_by_uid(&tmp_lease, uid.data, uid.len, MDL);
                    300:                        data_string_forget(&uid, MDL);
                    301:                        get_newest_lease(&lease, tmp_lease, next_uid);
                    302:                        assoc_ip_cnt = get_associated_ips(tmp_lease,
                    303:                                                          next_uid, 
                    304:                                                          lease,
                    305:                                                          assoc_ips, 
                    306:                                                          nassoc_ips);
                    307: 
                    308:                } else {
                    309: 
                    310:                        if (packet->raw->hlen+1 > sizeof(h.hbuf)) {
                    311:                                log_info("%s: hardware length too long, "
                    312:                                         "no reply sent", msgbuf);
                    313:                                option_state_dereference(&options, MDL);
                    314:                                return;
                    315:                        }
                    316: 
                    317:                        h.hlen = packet->raw->hlen + 1;
                    318:                        h.hbuf[0] = packet->raw->htype;
                    319:                        memcpy(&h.hbuf[1], 
                    320:                               packet->raw->chaddr, 
                    321:                               packet->raw->hlen);
                    322: 
                    323:                        snprintf(dbg_info, 
                    324:                                 sizeof(dbg_info), 
                    325:                                 "MAC address %s",
                    326:                                 print_hw_addr(h.hbuf[0], 
                    327:                                               h.hlen - 1, 
                    328:                                               &h.hbuf[1]));
                    329: 
                    330:                        find_lease_by_hw_addr(&tmp_lease, h.hbuf, h.hlen, MDL);
                    331:                        get_newest_lease(&lease, tmp_lease, next_hw);
                    332:                        assoc_ip_cnt = get_associated_ips(tmp_lease,
                    333:                                                          next_hw, 
                    334:                                                          lease,
                    335:                                                          assoc_ips, 
                    336:                                                          nassoc_ips);
                    337: 
                    338:                }
                    339: 
                    340:                lease_dereference(&tmp_lease, MDL);
                    341: 
                    342:                if (lease != NULL) {
                    343:                        memcpy(&packet->raw->ciaddr, 
                    344:                               lease->ip_addr.iabuf,
                    345:                               sizeof(packet->raw->ciaddr));
                    346:                }
                    347: 
                    348:                /*
                    349:                 * Log if we have too many IP addresses associated
                    350:                 * with this client.
                    351:                 */
                    352:                if (want_associated_ip && (assoc_ip_cnt > nassoc_ips)) {
                    353:                        log_info("%d IP addresses associated with %s, "
                    354:                                 "only %d sent in reply.",
                    355:                                 assoc_ip_cnt, dbg_info, nassoc_ips);
                    356:                }
                    357:        }
                    358: 
                    359:        /*
                    360:         * We now know the query target too, so can report this in 
                    361:         * our log message.
                    362:         */
                    363:        snprintf(msgbuf, sizeof(msgbuf), 
                    364:                "DHCPLEASEQUERY from %s for %s",
                    365:                inet_ntoa(packet->raw->giaddr), dbg_info);
                    366: 
                    367:        /*
                    368:         * Figure our our return type.
                    369:         */
                    370:        if (lease == NULL) {
                    371:                dhcpMsgType = DHCPLEASEUNKNOWN;
                    372:                dhcp_msg_type_name = "DHCPLEASEUNKNOWN";
                    373:        } else {
                    374:                if (lease->binding_state == FTS_ACTIVE) {
                    375:                        dhcpMsgType = DHCPLEASEACTIVE;
                    376:                        dhcp_msg_type_name = "DHCPLEASEACTIVE";
                    377:                } else {
                    378:                        dhcpMsgType = DHCPLEASEUNASSIGNED;
                    379:                        dhcp_msg_type_name = "DHCPLEASEUNASSIGNED";
                    380:                }
                    381:        }
                    382: 
                    383:        /* 
                    384:         * Set options that only make sense if we have an active lease.
                    385:         */
                    386: 
                    387:        if (dhcpMsgType == DHCPLEASEACTIVE)
                    388:        {
                    389:                /*
                    390:                 * RFC 4388 uses the PRL to request options for the agent to
                    391:                 * receive that are "about" the client.  It is confusing
                    392:                 * because in some cases it wants to know what was sent to
                    393:                 * the client (lease times, adjusted), and in others it wants
                    394:                 * to know information the client sent.  You're supposed to
                    395:                 * know this on a case-by-case basis.
                    396:                 *
                    397:                 * "Name servers", "domain name", and the like from the relay
                    398:                 * agent's scope seems less than useful.  Our options are to
                    399:                 * restart the option cache from the lease's best point of view
                    400:                 * (execute statements from the lease pool's group), or to
                    401:                 * simply restart the option cache from empty.
                    402:                 *
                    403:                 * I think restarting the option cache from empty best
                    404:                 * approaches RFC 4388's intent; specific options are included.
                    405:                 */
                    406:                option_state_dereference(&options, MDL);
                    407: 
                    408:                if (!option_state_allocate(&options, MDL)) {
                    409:                        log_error("%s: out of memory, no reply sent", msgbuf);
                    410:                        lease_dereference(&lease, MDL);
                    411:                        return;
                    412:                }
                    413: 
                    414:                /* 
                    415:                 * Set the hardware address fields.
                    416:                 */
                    417: 
                    418:                packet->raw->hlen = lease->hardware_addr.hlen - 1;
                    419:                packet->raw->htype = lease->hardware_addr.hbuf[0];
                    420:                memcpy(packet->raw->chaddr, 
                    421:                       &lease->hardware_addr.hbuf[1], 
                    422:                       sizeof(packet->raw->chaddr));
                    423: 
                    424:                /*
                    425:                 * Set client identifier option.
                    426:                 */
                    427:                if (lease->uid_len > 0) {
                    428:                        if (!add_option(options,
                    429:                                        DHO_DHCP_CLIENT_IDENTIFIER,
                    430:                                        lease->uid,
                    431:                                        lease->uid_len)) {
                    432:                                option_state_dereference(&options, MDL);
                    433:                                lease_dereference(&lease, MDL);
                    434:                                log_info("%s: out of memory, no reply sent",
                    435:                                         msgbuf);
                    436:                                return;
                    437:                        }
                    438:                }
                    439: 
                    440: 
                    441:                /*
                    442:                 * Calculate T1 and T2, the times when the client
                    443:                 * tries to extend its lease on its networking
                    444:                 * address.
                    445:                 * These seem to be hard-coded in ISC DHCP, to 0.5 and
                    446:                 * 0.875 of the lease time.
                    447:                 */
                    448: 
                    449:                lease_duration = lease->ends - lease->starts;
                    450:                time_renewal = lease->starts + 
                    451:                        (lease_duration / 2);
                    452:                time_rebinding = lease->starts + 
                    453:                        (lease_duration / 2) +
                    454:                        (lease_duration / 4) +
                    455:                        (lease_duration / 8);
                    456: 
                    457:                if (time_renewal > cur_time) {
1.1.1.1 ! misho     458:                        time_renewal = htonl(time_renewal - cur_time);
1.1       misho     459: 
                    460:                        if (!add_option(options, 
                    461:                                        DHO_DHCP_RENEWAL_TIME,
                    462:                                        &time_renewal, 
                    463:                                        sizeof(time_renewal))) {
                    464:                                option_state_dereference(&options, MDL);
                    465:                                lease_dereference(&lease, MDL);
                    466:                                log_info("%s: out of memory, no reply sent",
                    467:                                         msgbuf);
                    468:                                return;
                    469:                        }
                    470:                }
                    471: 
                    472:                if (time_rebinding > cur_time) {
                    473:                        time_rebinding = htonl(time_rebinding - cur_time);
                    474: 
                    475:                        if (!add_option(options, 
                    476:                                        DHO_DHCP_REBINDING_TIME,
                    477:                                        &time_rebinding, 
                    478:                                        sizeof(time_rebinding))) {
                    479:                                option_state_dereference(&options, MDL);
                    480:                                lease_dereference(&lease, MDL);
                    481:                                log_info("%s: out of memory, no reply sent",
                    482:                                         msgbuf);
                    483:                                return;
                    484:                        }
                    485:                }
                    486: 
                    487:                if (lease->ends > cur_time) {
                    488:                        time_expiry = htonl(lease->ends - cur_time);
1.1.1.1 ! misho     489: 
1.1       misho     490:                        if (!add_option(options, 
                    491:                                        DHO_DHCP_LEASE_TIME,
                    492:                                        &time_expiry, 
                    493:                                        sizeof(time_expiry))) {
                    494:                                option_state_dereference(&options, MDL);
                    495:                                lease_dereference(&lease, MDL);
                    496:                                log_info("%s: out of memory, no reply sent",
                    497:                                         msgbuf);
                    498:                                return;
                    499:                        }
                    500:                }
                    501: 
                    502:                /* Supply the Vendor-Class-Identifier. */
                    503:                if (lease->scope != NULL) {
                    504:                        struct data_string vendor_class;
                    505: 
                    506:                        memset(&vendor_class, 0, sizeof(vendor_class));
                    507: 
                    508:                        if (find_bound_string(&vendor_class, lease->scope,
                    509:                                              "vendor-class-identifier")) {
                    510:                                if (!add_option(options,
                    511:                                                DHO_VENDOR_CLASS_IDENTIFIER,
                    512:                                                (void *)vendor_class.data,
                    513:                                                vendor_class.len)) {
                    514:                                        option_state_dereference(&options,
                    515:                                                                 MDL);
                    516:                                        lease_dereference(&lease, MDL);
                    517:                                        log_error("%s: error adding vendor "
                    518:                                                  "class identifier, no reply "
                    519:                                                  "sent", msgbuf);
                    520:                                        data_string_forget(&vendor_class, MDL);
                    521:                                        return;
                    522:                                }
                    523:                                data_string_forget(&vendor_class, MDL);
                    524:                        }
                    525:                }
                    526: 
                    527:                /*
                    528:                 * Set the relay agent info.
                    529:                 *
                    530:                 * Note that because agent info is appended without regard
                    531:                 * to the PRL in cons_options(), this will be sent as the
                    532:                 * last option in the packet whether it is listed on PRL or
                    533:                 * not.
                    534:                 */
                    535: 
                    536:                if (lease->agent_options != NULL) {
                    537:                        int idx = agent_universe.index;
                    538:                        struct option_chain_head **tmp1 = 
                    539:                                (struct option_chain_head **)
                    540:                                &(options->universes[idx]);
                    541:                                struct option_chain_head *tmp2 = 
                    542:                                (struct option_chain_head *)
                    543:                                lease->agent_options;
                    544: 
                    545:                        option_chain_head_reference(tmp1, tmp2, MDL);
                    546:                }
                    547: 
                    548:                /* 
                    549:                 * Set the client last transaction time.
                    550:                 * We check to make sure we have a timestamp. For
                    551:                 * lease files that were saved before running a 
                    552:                 * timestamp-aware version of the server, this may
                    553:                 * not be set.
                    554:                 */
                    555: 
                    556:                if (lease->cltt != MIN_TIME) {
                    557:                        if (cur_time > lease->cltt) {
                    558:                                client_last_transaction_time = 
                    559:                                        htonl(cur_time - lease->cltt);
                    560:                        } else {
                    561:                                client_last_transaction_time = htonl(0);
                    562:                        }
                    563:                        if (!add_option(options, 
                    564:                                        DHO_CLIENT_LAST_TRANSACTION_TIME,
                    565:                                        &client_last_transaction_time,
                    566:                                        sizeof(client_last_transaction_time))) {
                    567:                                option_state_dereference(&options, MDL);
                    568:                                lease_dereference(&lease, MDL);
                    569:                                log_info("%s: out of memory, no reply sent",
                    570:                                         msgbuf);
                    571:                                return;
                    572:                        }
                    573:                }
                    574: 
                    575:                /*
                    576:                 * Set associated IPs, if requested and there are some.
                    577:                 */
                    578:                if (want_associated_ip && (assoc_ip_cnt > 0)) {
                    579:                        if (!add_option(options, 
                    580:                                        DHO_ASSOCIATED_IP,
                    581:                                        assoc_ips,
                    582:                                        assoc_ip_cnt * sizeof(assoc_ips[0]))) {
                    583:                                option_state_dereference(&options, MDL);
                    584:                                lease_dereference(&lease, MDL);
                    585:                                log_info("%s: out of memory, no reply sent",
                    586:                                         msgbuf);
                    587:                                return;
                    588:                        }
                    589:                }
                    590:        }
                    591: 
                    592:        /* 
                    593:         * Set the message type.
                    594:         */
                    595: 
                    596:        packet->raw->op = BOOTREPLY;
                    597: 
                    598:        /*
                    599:         * Set DHCP message type.
                    600:         */
                    601:        if (!add_option(options, 
                    602:                        DHO_DHCP_MESSAGE_TYPE,
                    603:                        &dhcpMsgType, 
                    604:                        sizeof(dhcpMsgType))) {
                    605:                option_state_dereference(&options, MDL);
                    606:                lease_dereference(&lease, MDL);
                    607:                log_info("%s: error adding option, no reply sent", msgbuf);
                    608:                return;
                    609:        }
                    610: 
                    611:        /*
                    612:         * Log the message we've received.
                    613:         */
                    614:        log_info("%s", msgbuf);
                    615: 
                    616:        /*
                    617:         * Figure out which address to use to send from.
                    618:         */
                    619:        get_server_source_address(&siaddr, options, packet);
                    620: 
                    621:        /* 
                    622:         * Set up the option buffer.
                    623:         */
                    624: 
                    625:        memset(&prl, 0, sizeof(prl));
                    626:        oc = lookup_option(&dhcp_universe, options, 
                    627:                           DHO_DHCP_PARAMETER_REQUEST_LIST);
                    628:        if (oc != NULL) {
                    629:                evaluate_option_cache(&prl, 
                    630:                                      packet, 
                    631:                                      NULL,
                    632:                                      NULL,
                    633:                                      packet->options,
                    634:                                      options,
                    635:                                      &global_scope,
                    636:                                      oc,
                    637:                                      MDL);
                    638:        }
                    639:        if (prl.len > 0) {
                    640:                prl_ptr = &prl;
                    641:        } else {
                    642:                prl_ptr = NULL;
                    643:        }
                    644: 
                    645:        packet->packet_length = cons_options(packet, 
                    646:                                             packet->raw, 
                    647:                                             lease,
                    648:                                             NULL,
                    649:                                             0,
                    650:                                             packet->options,
                    651:                                             options,
                    652:                                             &global_scope,
                    653:                                             0,
                    654:                                             0,
                    655:                                             0, 
                    656:                                             prl_ptr,
                    657:                                             NULL);
                    658: 
                    659:        data_string_forget(&prl, MDL);  /* SK: safe, even if empty */
                    660:        option_state_dereference(&options, MDL);
                    661:        lease_dereference(&lease, MDL);
                    662: 
                    663:        to.sin_family = AF_INET;
                    664: #ifdef HAVE_SA_LEN
                    665:        to.sin_len = sizeof(to);
                    666: #endif
                    667:        memset(to.sin_zero, 0, sizeof(to.sin_zero));
                    668: 
                    669:        /* 
                    670:         * Leasequery packets are be sent to the gateway address.
                    671:         */
                    672:        to.sin_addr = packet->raw->giaddr;
                    673:        if (packet->raw->giaddr.s_addr != htonl(INADDR_LOOPBACK)) {
                    674:                to.sin_port = local_port;
                    675:        } else {
                    676:                to.sin_port = remote_port; /* XXXSK: For debugging. */
                    677:        }
                    678: 
                    679:        /* 
                    680:         * The fallback_interface lets us send with a real IP
                    681:         * address. The packet interface sends from all-zeros.
                    682:         */
                    683:        if (fallback_interface != NULL) {
                    684:                interface = fallback_interface;
                    685:        } else {
                    686:                interface = packet->interface;
                    687:        }
                    688: 
                    689:        /*
                    690:         * Report what we're sending.
                    691:         */
                    692:        log_info("%s to %s for %s (%d associated IPs)",
                    693:                dhcp_msg_type_name, 
                    694:                inet_ntoa(to.sin_addr), dbg_info, assoc_ip_cnt);
                    695: 
                    696:        send_packet(interface,
                    697:                    NULL,
                    698:                    packet->raw, 
                    699:                    packet->packet_length,
                    700:                    siaddr,
                    701:                    &to,
                    702:                    NULL);
                    703: }
                    704: 
                    705: #ifdef DHCPv6
                    706: 
                    707: /*
                    708:  * TODO: RFC5007 query-by-clientid.
                    709:  *
                    710:  * TODO: RFC5007 look at the pools according to the link-address.
                    711:  *
                    712:  * TODO: get fixed leases too.
                    713:  *
                    714:  * TODO: RFC5007 ORO in query-options.
                    715:  *
                    716:  * TODO: RFC5007 lq-relay-data.
                    717:  *
                    718:  * TODO: RFC5007 lq-client-link.
                    719:  *
                    720:  * Note: the code is still nearly compliant and usable for the target
                    721:  * case with these missing features!
                    722:  */
                    723: 
                    724: /*
                    725:  * The structure to handle a leasequery.
                    726:  */
                    727: struct lq6_state {
                    728:        struct packet *packet;
                    729:        struct data_string client_id;
                    730:        struct data_string server_id;
                    731:        struct data_string lq_query;
                    732:        uint8_t query_type;
                    733:        struct in6_addr link_addr;
                    734:        struct option_state *query_opts;
                    735: 
                    736:        struct option_state *reply_opts;
                    737:        unsigned cursor;
                    738:        union reply_buffer {
                    739:                unsigned char data[65536];
                    740:                struct dhcpv6_packet reply;
                    741:        } buf;
                    742: };
                    743: 
                    744: /*
                    745:  * Options that we want to send.
                    746:  */
                    747: static const int required_opts_lq[] = {
                    748:        D6O_CLIENTID,
                    749:        D6O_SERVERID,
                    750:        D6O_STATUS_CODE,
                    751:        D6O_CLIENT_DATA,
                    752:        D6O_LQ_RELAY_DATA,
                    753:        D6O_LQ_CLIENT_LINK,
                    754:        0
                    755: };
                    756: static const int required_opt_CLIENT_DATA[] = {
                    757:        D6O_CLIENTID,
                    758:        D6O_IAADDR,
                    759:        D6O_IAPREFIX,
                    760:        D6O_CLT_TIME,
                    761:        0
                    762: };
                    763: 
                    764: /*
                    765:  * Get the lq-query option from the packet.
                    766:  */
                    767: static isc_result_t
                    768: get_lq_query(struct lq6_state *lq)
                    769: {
                    770:        struct data_string *lq_query = &lq->lq_query;
                    771:        struct packet *packet = lq->packet;
                    772:        struct option_cache *oc;
                    773: 
                    774:        /*
                    775:         * Verify our lq_query structure is empty.
                    776:         */
                    777:        if ((lq_query->data != NULL) || (lq_query->len != 0)) {
                    778:                return ISC_R_INVALIDARG;
                    779:        }
                    780: 
                    781:        oc = lookup_option(&dhcpv6_universe, packet->options, D6O_LQ_QUERY);
                    782:        if (oc == NULL) {
                    783:                return ISC_R_NOTFOUND;
                    784:        }
                    785: 
                    786:        if (!evaluate_option_cache(lq_query, packet, NULL, NULL,
                    787:                                   packet->options, NULL,
                    788:                                   &global_scope, oc, MDL)) {
                    789:                return ISC_R_FAILURE;
                    790:        }
                    791: 
                    792:        return ISC_R_SUCCESS;
                    793: }
                    794: 
                    795: /*
                    796:  * Message validation, RFC 5007 section 4.2.1:
                    797:  *  dhcpv6.c:valid_client_msg() - unicast + lq-query option.
                    798:  */
                    799: static int
                    800: valid_query_msg(struct lq6_state *lq) {
                    801:        struct packet *packet = lq->packet;
                    802:        int ret_val = 0;
                    803:        struct option_cache *oc;
                    804: 
                    805:        /* INSIST((lq != NULL) || (packet != NULL)); */
                    806: 
                    807:        switch (get_client_id(packet, &lq->client_id)) {
                    808:                case ISC_R_SUCCESS:
                    809:                        break;
                    810:                case ISC_R_NOTFOUND:
                    811:                        log_debug("Discarding %s from %s; "
                    812:                                  "client identifier missing", 
                    813:                                  dhcpv6_type_names[packet->dhcpv6_msg_type],
                    814:                                  piaddr(packet->client_addr));
                    815:                        goto exit;
                    816:                default:
                    817:                        log_error("Error processing %s from %s; "
                    818:                                  "unable to evaluate Client Identifier",
                    819:                                  dhcpv6_type_names[packet->dhcpv6_msg_type],
                    820:                                  piaddr(packet->client_addr));
                    821:                        goto exit;
                    822:        }
                    823: 
                    824:        oc = lookup_option(&dhcpv6_universe, packet->options, D6O_SERVERID);
                    825:        if (oc != NULL) {
                    826:                if (evaluate_option_cache(&lq->server_id, packet, NULL, NULL,
                    827:                                          packet->options, NULL, 
                    828:                                          &global_scope, oc, MDL)) {
                    829:                        log_debug("Discarding %s from %s; " 
                    830:                                  "server identifier found "
                    831:                                  "(CLIENTID %s, SERVERID %s)", 
                    832:                                  dhcpv6_type_names[packet->dhcpv6_msg_type],
                    833:                                  piaddr(packet->client_addr),
                    834:                                  print_hex_1(lq->client_id.len, 
                    835:                                              lq->client_id.data, 60),
                    836:                                  print_hex_2(lq->server_id.len,
                    837:                                              lq->server_id.data, 60));
                    838:                } else {
                    839:                        log_debug("Discarding %s from %s; " 
                    840:                                  "server identifier found "
                    841:                                  "(CLIENTID %s)", 
                    842:                                  dhcpv6_type_names[packet->dhcpv6_msg_type],
                    843:                                  print_hex_1(lq->client_id.len, 
                    844:                                              lq->client_id.data, 60),
                    845:                                  piaddr(packet->client_addr));
                    846:                }
                    847:                goto exit;
                    848:        }
                    849: 
                    850:        switch (get_lq_query(lq)) {
                    851:                case ISC_R_SUCCESS:
                    852:                        break;
                    853:                case ISC_R_NOTFOUND:
                    854:                        log_debug("Discarding %s from %s; lq-query missing",
                    855:                                  dhcpv6_type_names[packet->dhcpv6_msg_type],
                    856:                                  piaddr(packet->client_addr));
                    857:                        goto exit;
                    858:                default:
                    859:                        log_error("Error processing %s from %s; "
                    860:                                  "unable to evaluate LQ-Query",
                    861:                                  dhcpv6_type_names[packet->dhcpv6_msg_type],
                    862:                                  piaddr(packet->client_addr));
                    863:                        goto exit;
                    864:        }
                    865: 
                    866:        /* looks good */
                    867:        ret_val = 1;
                    868: 
                    869: exit:
                    870:        if (!ret_val) {
                    871:                if (lq->client_id.len > 0) {
                    872:                        data_string_forget(&lq->client_id, MDL);
                    873:                }
                    874:                if (lq->server_id.len > 0) {
                    875:                        data_string_forget(&lq->server_id, MDL);
                    876:                }
                    877:                if (lq->lq_query.len > 0) {
                    878:                        data_string_forget(&lq->lq_query, MDL);
                    879:                }
                    880:        }
                    881:        return ret_val;
                    882: }
                    883: 
                    884: /*
                    885:  * Set an error in a status-code option (from set_status_code).
                    886:  */
                    887: static int
                    888: set_error(struct lq6_state *lq, u_int16_t code, const char *message) {
                    889:        struct data_string d;
                    890:        int ret_val;
                    891: 
                    892:        memset(&d, 0, sizeof(d));
                    893:        d.len = sizeof(code) + strlen(message);
                    894:        if (!buffer_allocate(&d.buffer, d.len, MDL)) {
                    895:                log_fatal("set_error: no memory for status code.");
                    896:        }
                    897:        d.data = d.buffer->data;
                    898:        putUShort(d.buffer->data, code);
                    899:        memcpy(d.buffer->data + sizeof(code), message, d.len - sizeof(code));
                    900:        if (!save_option_buffer(&dhcpv6_universe, lq->reply_opts,
                    901:                                d.buffer, (unsigned char *)d.data, d.len, 
                    902:                                D6O_STATUS_CODE, 0)) {
                    903:                log_error("set_error: error saving status code.");
                    904:                ret_val = 0;
                    905:        } else {
                    906:                ret_val = 1;
                    907:        }
                    908:        data_string_forget(&d, MDL);
                    909:        return ret_val;
                    910: }
                    911: 
                    912: /*
                    913:  * Process a by-address lease query.
                    914:  */
                    915: static int
                    916: process_lq_by_address(struct lq6_state *lq) {
                    917:        struct packet *packet = lq->packet;
                    918:        struct option_cache *oc;
                    919:        struct ipv6_pool *pool = NULL;
                    920:        struct data_string data;
                    921:        struct in6_addr addr;
                    922:        struct iasubopt *iaaddr = NULL;
                    923:        struct option_state *opt_state = NULL;
                    924:        u_int32_t lifetime;
                    925:        unsigned opt_cursor;
                    926:        int ret_val = 0;
                    927: 
                    928:        /*
                    929:         * Get the IAADDR.
                    930:         */
                    931:        oc = lookup_option(&dhcpv6_universe, lq->query_opts, D6O_IAADDR);
                    932:        if (oc == NULL) {
                    933:                if (!set_error(lq, STATUS_MalformedQuery,
                    934:                               "No OPTION_IAADDR.")) {
                    935:                        log_error("process_lq_by_address: unable "
                    936:                                  "to set MalformedQuery status code.");
                    937:                        return 0;
                    938:                }
                    939:                return 1;
                    940:        }
                    941:        memset(&data, 0, sizeof(data));
                    942:        if (!evaluate_option_cache(&data, packet,
                    943:                                   NULL, NULL,
                    944:                                   lq->query_opts, NULL,
                    945:                                   &global_scope, oc, MDL) ||
                    946:            (data.len < IAADDR_OFFSET)) {
                    947:                log_error("process_lq_by_address: error evaluating IAADDR.");
                    948:                goto exit;
                    949:        }
                    950:        memcpy(&addr, data.data, sizeof(addr));
                    951:        data_string_forget(&data, MDL);
                    952: 
                    953:        /*
                    954:         * Find the lease.
                    955:         * Note the RFC 5007 says to use the link-address to find the link
                    956:         * or the ia-aadr when it is :: but in any case the ia-addr has
                    957:         * to be on the link, so we ignore the link-address here.
                    958:         */
                    959:        if (find_ipv6_pool(&pool, D6O_IA_NA, &addr) != ISC_R_SUCCESS) {
                    960:                if (!set_error(lq, STATUS_NotConfigured,
                    961:                               "Address not in a pool.")) {
                    962:                        log_error("process_lq_by_address: unable "
                    963:                                  "to set NotConfigured status code.");
                    964:                        goto exit;
                    965:                }
                    966:                ret_val = 1;
                    967:                goto exit;
                    968:        }
                    969:        if (iasubopt_hash_lookup(&iaaddr, pool->leases, &addr,
                    970:                                 sizeof(addr), MDL) == 0) {
                    971:                ret_val = 1;
                    972:                goto exit;
                    973:        }
                    974:        if ((iaaddr == NULL) || (iaaddr->state != FTS_ACTIVE) ||
                    975:            (iaaddr->ia == NULL) || (iaaddr->ia->iaid_duid.len <= 4)) {
                    976:                ret_val = 1;
                    977:                goto exit;
                    978:        }
                    979: 
                    980:        /*
                    981:         * Build the client-data option (with client-id, ia-addr and clt-time).
                    982:         */
                    983:        if (!option_state_allocate(&opt_state, MDL)) {
                    984:                log_error("process_lq_by_address: "
                    985:                          "no memory for option state.");
                    986:                goto exit;
                    987:        }
                    988: 
                    989:        data_string_copy(&data, &iaaddr->ia->iaid_duid, MDL);
                    990:        data.data += 4;
                    991:        data.len -= 4;
                    992:        if (!save_option_buffer(&dhcpv6_universe, opt_state,
                    993:                                NULL, (unsigned char *)data.data, data.len,
                    994:                                D6O_CLIENTID, 0)) {
                    995:                log_error("process_lq_by_address: error saving client ID.");
                    996:                goto exit;
                    997:        }
                    998:        data_string_forget(&data, MDL);
                    999: 
                   1000:        data.len = IAADDR_OFFSET;
                   1001:        if (!buffer_allocate(&data.buffer, data.len, MDL)) {
                   1002:                log_error("process_lq_by_address: no memory for ia-addr.");
                   1003:                goto exit;
                   1004:        }
                   1005:        data.data = data.buffer->data;
                   1006:        memcpy(data.buffer->data, &iaaddr->addr, 16);
                   1007:        lifetime = iaaddr->prefer;
                   1008:        putULong(data.buffer->data + 16, lifetime);
                   1009:        lifetime = iaaddr->valid;
                   1010:        putULong(data.buffer->data + 20, lifetime);
                   1011:        if (!save_option_buffer(&dhcpv6_universe, opt_state,
                   1012:                                NULL, (unsigned char *)data.data, data.len,
                   1013:                                D6O_IAADDR, 0)) {
                   1014:                log_error("process_lq_by_address: error saving ia-addr.");
                   1015:                goto exit;
                   1016:        }
                   1017:        data_string_forget(&data, MDL);
                   1018: 
                   1019:        lifetime = htonl(iaaddr->ia->cltt);
                   1020:        if (!save_option_buffer(&dhcpv6_universe, opt_state,
                   1021:                                NULL, (unsigned char *)&lifetime, 4,
                   1022:                                D6O_CLT_TIME, 0)) {
                   1023:                log_error("process_lq_by_address: error saving clt time.");
                   1024:                goto exit;
                   1025:        }
                   1026: 
                   1027:        /*
                   1028:         * Store the client-data option.
                   1029:         */
                   1030:        opt_cursor = lq->cursor;
                   1031:        putUShort(lq->buf.data + lq->cursor, (unsigned)D6O_CLIENT_DATA);
                   1032:        lq->cursor += 2;
                   1033:        /* Skip option length. */
                   1034:        lq->cursor += 2;
                   1035: 
                   1036:        lq->cursor += store_options6((char *)lq->buf.data + lq->cursor,
                   1037:                                     sizeof(lq->buf) - lq->cursor,
                   1038:                                     opt_state, lq->packet,
                   1039:                                     required_opt_CLIENT_DATA, NULL);
                   1040:        /* Reset the length. */
                   1041:        putUShort(lq->buf.data + opt_cursor + 2,
                   1042:                  lq->cursor - (opt_cursor + 4));
                   1043: 
                   1044:        /* Done. */
                   1045:        ret_val = 1;
                   1046: 
                   1047:      exit:
                   1048:        if (data.data != NULL)
                   1049:                data_string_forget(&data, MDL);
                   1050:        if (pool != NULL)
                   1051:                ipv6_pool_dereference(&pool, MDL);
                   1052:        if (iaaddr != NULL)
                   1053:                iasubopt_dereference(&iaaddr, MDL);
                   1054:        if (opt_state != NULL)
                   1055:                option_state_dereference(&opt_state, MDL);
                   1056:        return ret_val;
                   1057: }
                   1058: 
                   1059: 
                   1060: /*
                   1061:  * Process a lease query.
                   1062:  */
                   1063: void
                   1064: dhcpv6_leasequery(struct data_string *reply_ret, struct packet *packet) {
                   1065:        static struct lq6_state lq;
                   1066:        struct option_cache *oc;
                   1067:        int allow_lq;
                   1068: 
                   1069:        /*
                   1070:         * Initialize the lease query state.
                   1071:         */
                   1072:        lq.packet = NULL;
                   1073:        memset(&lq.client_id, 0, sizeof(lq.client_id));
                   1074:        memset(&lq.server_id, 0, sizeof(lq.server_id));
                   1075:        memset(&lq.lq_query, 0, sizeof(lq.lq_query));
                   1076:        lq.query_opts = NULL;
                   1077:        lq.reply_opts = NULL;
                   1078:        packet_reference(&lq.packet, packet, MDL);
                   1079: 
                   1080:        /*
                   1081:         * Validate our input.
                   1082:         */
                   1083:        if (!valid_query_msg(&lq)) {
                   1084:                goto exit;
                   1085:        }
                   1086: 
                   1087:        /*
                   1088:         * Prepare our reply.
                   1089:         */
                   1090:        if (!option_state_allocate(&lq.reply_opts, MDL)) {
                   1091:                log_error("dhcpv6_leasequery: no memory for option state.");
                   1092:                goto exit;
                   1093:        }
                   1094:        execute_statements_in_scope(NULL, lq.packet, NULL, NULL,
                   1095:                                    lq.packet->options, lq.reply_opts,
                   1096:                                    &global_scope, root_group, NULL);
                   1097: 
                   1098:        lq.buf.reply.msg_type = DHCPV6_LEASEQUERY_REPLY;
                   1099: 
                   1100:        memcpy(lq.buf.reply.transaction_id,
                   1101:               lq.packet->dhcpv6_transaction_id,
                   1102:               sizeof(lq.buf.reply.transaction_id));
                   1103: 
                   1104:        /* 
                   1105:         * Because LEASEQUERY has some privacy concerns, default to deny.
                   1106:         */
                   1107:        allow_lq = 0;
                   1108: 
                   1109:        /*
                   1110:         * See if we are authorized to do LEASEQUERY.
                   1111:         */
                   1112:        oc = lookup_option(&server_universe, lq.reply_opts, SV_LEASEQUERY);
                   1113:        if (oc != NULL) {
                   1114:                allow_lq = evaluate_boolean_option_cache(NULL,
                   1115:                                                         lq.packet,
                   1116:                                                         NULL, NULL,
                   1117:                                                         lq.packet->options,
                   1118:                                                         lq.reply_opts,
                   1119:                                                         &global_scope,
                   1120:                                                         oc, MDL);
                   1121:        }
                   1122: 
                   1123:        if (!allow_lq) {
                   1124:                log_info("dhcpv6_leasequery: not allowed, query ignored.");
                   1125:                goto exit;
                   1126:        }
                   1127:            
                   1128:        /*
                   1129:         * Same than transmission of REPLY message in RFC 3315:
                   1130:         *  server-id
                   1131:         *  client-id
                   1132:         */
                   1133: 
                   1134:        oc = lookup_option(&dhcpv6_universe, lq.reply_opts, D6O_SERVERID);
                   1135:        if (oc == NULL) {
                   1136:                /* If not already in options, get from query then global. */
                   1137:                if (lq.server_id.data == NULL)
                   1138:                        copy_server_duid(&lq.server_id, MDL);
                   1139:                if (!save_option_buffer(&dhcpv6_universe,
                   1140:                                        lq.reply_opts,
                   1141:                                        NULL,
                   1142:                                        (unsigned char *)lq.server_id.data,
                   1143:                                        lq.server_id.len, 
                   1144:                                        D6O_SERVERID,
                   1145:                                        0)) {
                   1146:                        log_error("dhcpv6_leasequery: "
                   1147:                                  "error saving server identifier.");
                   1148:                        goto exit;
                   1149:                }
                   1150:        }
                   1151: 
                   1152:        if (!save_option_buffer(&dhcpv6_universe,
                   1153:                                lq.reply_opts,
                   1154:                                lq.client_id.buffer,
                   1155:                                (unsigned char *)lq.client_id.data,
                   1156:                                lq.client_id.len,
                   1157:                                D6O_CLIENTID,
                   1158:                                0)) {
                   1159:                log_error("dhcpv6_leasequery: "
                   1160:                          "error saving client identifier.");
                   1161:                goto exit;
                   1162:        }
                   1163: 
                   1164:        lq.cursor = 4;
                   1165: 
                   1166:        /*
                   1167:         * Decode the lq-query option.
                   1168:         */
                   1169: 
                   1170:        if (lq.lq_query.len <= LQ_QUERY_OFFSET) {
                   1171:                if (!set_error(&lq, STATUS_MalformedQuery,
                   1172:                               "OPTION_LQ_QUERY too short.")) {
                   1173:                        log_error("dhcpv6_leasequery: unable "
                   1174:                                  "to set MalformedQuery status code.");
                   1175:                        goto exit;
                   1176:                }
                   1177:                goto done;
                   1178:        }
                   1179: 
                   1180:        lq.query_type = lq.lq_query.data [0];
                   1181:        memcpy(&lq.link_addr, lq.lq_query.data + 1, sizeof(lq.link_addr));
                   1182:        switch (lq.query_type) {
                   1183:                case LQ6QT_BY_ADDRESS:
                   1184:                        break;
                   1185:                case LQ6QT_BY_CLIENTID:
                   1186:                        if (!set_error(&lq, STATUS_UnknownQueryType,
                   1187:                                       "QUERY_BY_CLIENTID not supported.")) {
                   1188:                                log_error("dhcpv6_leasequery: unable to "
                   1189:                                          "set UnknownQueryType status code.");
                   1190:                                goto exit;
                   1191:                        }
                   1192:                        goto done;
                   1193:                default:
                   1194:                        if (!set_error(&lq, STATUS_UnknownQueryType,
                   1195:                                       "Unknown query-type.")) {
                   1196:                                log_error("dhcpv6_leasequery: unable to "
                   1197:                                          "set UnknownQueryType status code.");
                   1198:                                goto exit;
                   1199:                        }
                   1200:                        goto done;
                   1201:        }
                   1202: 
                   1203:        if (!option_state_allocate(&lq.query_opts, MDL)) {
                   1204:                log_error("dhcpv6_leasequery: no memory for option state.");
                   1205:                goto exit;
                   1206:        }
                   1207:        if (!parse_option_buffer(lq.query_opts,
                   1208:                                 lq.lq_query.data + LQ_QUERY_OFFSET,
                   1209:                                 lq.lq_query.len - LQ_QUERY_OFFSET,
                   1210:                                 &dhcpv6_universe)) {
                   1211:                log_error("dhcpv6_leasequery: error parsing query-options.");
                   1212:                if (!set_error(&lq, STATUS_MalformedQuery,
                   1213:                               "Bad query-options.")) {
                   1214:                        log_error("dhcpv6_leasequery: unable "
                   1215:                                  "to set MalformedQuery status code.");
                   1216:                        goto exit;
                   1217:                }
                   1218:                goto done;
                   1219:        }
                   1220: 
                   1221:        /* Do it. */
                   1222:        if (!process_lq_by_address(&lq))
                   1223:                goto exit;
                   1224: 
                   1225:       done:
                   1226:        /* Store the options. */
                   1227:        lq.cursor += store_options6((char *)lq.buf.data + lq.cursor,
                   1228:                                    sizeof(lq.buf) - lq.cursor,
                   1229:                                    lq.reply_opts,
                   1230:                                    lq.packet,
                   1231:                                    required_opts_lq,
                   1232:                                    NULL);
                   1233: 
                   1234:        /* Return our reply to the caller. */
                   1235:        reply_ret->len = lq.cursor;
                   1236:        reply_ret->buffer = NULL;
                   1237:        if (!buffer_allocate(&reply_ret->buffer, lq.cursor, MDL)) {
                   1238:                log_fatal("dhcpv6_leasequery: no memory to store Reply.");
                   1239:        }
                   1240:        memcpy(reply_ret->buffer->data, lq.buf.data, lq.cursor);
                   1241:        reply_ret->data = reply_ret->buffer->data;
                   1242: 
                   1243:       exit:
                   1244:        /* Cleanup. */
                   1245:        if (lq.packet != NULL)
                   1246:                packet_dereference(&lq.packet, MDL);
                   1247:        if (lq.client_id.data != NULL)
                   1248:                data_string_forget(&lq.client_id, MDL);
                   1249:        if (lq.server_id.data != NULL)
                   1250:                data_string_forget(&lq.server_id, MDL);
                   1251:        if (lq.lq_query.data != NULL)
                   1252:                data_string_forget(&lq.lq_query, MDL);
                   1253:        if (lq.query_opts != NULL)
                   1254:                option_state_dereference(&lq.query_opts, MDL);
                   1255:        if (lq.reply_opts != NULL)
                   1256:                option_state_dereference(&lq.reply_opts, MDL);
                   1257: }
                   1258: 
                   1259: #endif /* DHCPv6 */

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