Annotation of embedaddon/dhcp/common/options.c, revision 1.1.1.1

1.1       misho       1: /* options.c
                      2: 
                      3:    DHCP options parsing and reassembly. */
                      4: 
                      5: /*
1.1.1.1 ! misho       6:  * Copyright (c) 2004-2012 by Internet Systems Consortium, Inc. ("ISC")
1.1       misho       7:  * Copyright (c) 1995-2003 by Internet Software Consortium
                      8:  *
                      9:  * Permission to use, copy, modify, and distribute this software for any
                     10:  * purpose with or without fee is hereby granted, provided that the above
                     11:  * copyright notice and this permission notice appear in all copies.
                     12:  *
                     13:  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
                     14:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     15:  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
                     16:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     17:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
                     18:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
                     19:  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
                     20:  *
                     21:  *   Internet Systems Consortium, Inc.
                     22:  *   950 Charter Street
                     23:  *   Redwood City, CA 94063
                     24:  *   <info@isc.org>
                     25:  *   https://www.isc.org/
                     26:  *
                     27:  * This software has been written for Internet Systems Consortium
                     28:  * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
                     29:  * To learn more about Internet Systems Consortium, see
                     30:  * ``https://www.isc.org/''.  To learn more about Vixie Enterprises,
                     31:  * see ``http://www.vix.com''.   To learn more about Nominum, Inc., see
                     32:  * ``http://www.nominum.com''.
                     33:  */
                     34: 
                     35: #define DHCP_OPTION_DATA
                     36: #include "dhcpd.h"
                     37: #include <omapip/omapip_p.h>
                     38: #include <limits.h>
                     39: 
                     40: struct option *vendor_cfg_option;
                     41: 
                     42: static int pretty_text(char **, char *, const unsigned char **,
                     43:                         const unsigned char *, int);
                     44: static int pretty_domain(char **, char *, const unsigned char **,
                     45:                         const unsigned char *);
                     46: static int prepare_option_buffer(struct universe *universe, struct buffer *bp,
                     47:                                 unsigned char *buffer, unsigned length,
                     48:                                 unsigned code, int terminatep,
                     49:                                 struct option_cache **opp);
                     50: 
                     51: /* Parse all available options out of the specified packet. */
                     52: 
                     53: int parse_options (packet)
                     54:        struct packet *packet;
                     55: {
                     56:        struct option_cache *op = (struct option_cache *)0;
                     57: 
                     58:        /* Allocate a new option state. */
                     59:        if (!option_state_allocate (&packet -> options, MDL)) {
                     60:                packet -> options_valid = 0;
                     61:                return 0;
                     62:        }
                     63: 
                     64:        /* If we don't see the magic cookie, there's nothing to parse. */
                     65:        if (memcmp (packet -> raw -> options, DHCP_OPTIONS_COOKIE, 4)) {
                     66:                packet -> options_valid = 0;
                     67:                return 1;
                     68:        }
                     69: 
                     70:        /* Go through the options field, up to the end of the packet
                     71:           or the End field. */
                     72:        if (!parse_option_buffer (packet -> options,
                     73:                                  &packet -> raw -> options [4],
                     74:                                  (packet -> packet_length -
                     75:                                   DHCP_FIXED_NON_UDP - 4),
                     76:                                  &dhcp_universe)) {
                     77: 
                     78:                /* STSN servers have a bug where they send a mangled
                     79:                   domain-name option, and whatever is beyond that in
                     80:                   the packet is junk.   Microsoft clients accept this,
                     81:                   which is probably why whoever implemented the STSN
                     82:                   server isn't aware of the problem yet.   To work around
                     83:                   this, we will accept corrupt packets from the server if
                     84:                   they contain a valid DHCP_MESSAGE_TYPE option, but
                     85:                   will not accept any corrupt client packets (the ISC DHCP
                     86:                   server is sufficiently widely used that it is probably
                     87:                   beneficial for it to be picky) and will not accept
                     88:                   packets whose type can't be determined. */
                     89: 
                     90:                if ((op = lookup_option (&dhcp_universe, packet -> options,
                     91:                                         DHO_DHCP_MESSAGE_TYPE))) {
                     92:                        if (!op -> data.data ||
                     93:                            (op -> data.data [0] != DHCPOFFER &&
                     94:                             op -> data.data [0] != DHCPACK &&
                     95:                             op -> data.data [0] != DHCPNAK))
                     96:                                return 0;
                     97:                } else
                     98:                        return 0;
                     99:        }
                    100: 
                    101:        /* If we parsed a DHCP Option Overload option, parse more
                    102:           options out of the buffer(s) containing them. */
                    103:        if ((op = lookup_option (&dhcp_universe, packet -> options,
                    104:                                 DHO_DHCP_OPTION_OVERLOAD))) {
                    105:                if (op -> data.data [0] & 1) {
                    106:                        if (!parse_option_buffer
                    107:                            (packet -> options,
                    108:                             (unsigned char *)packet -> raw -> file,
                    109:                             sizeof packet -> raw -> file,
                    110:                             &dhcp_universe))
                    111:                                return 0;
                    112:                }
                    113:                if (op -> data.data [0] & 2) {
                    114:                        if (!parse_option_buffer
                    115:                            (packet -> options,
                    116:                             (unsigned char *)packet -> raw -> sname,
                    117:                             sizeof packet -> raw -> sname,
                    118:                             &dhcp_universe))
                    119:                                return 0;
                    120:                }
                    121:        }
                    122:        packet -> options_valid = 1;
                    123:        return 1;
                    124: }
                    125: 
                    126: /* Parse options out of the specified buffer, storing addresses of option
                    127:  * values in packet->options.
                    128:  */
                    129: int parse_option_buffer (options, buffer, length, universe)
                    130:        struct option_state *options;
                    131:        const unsigned char *buffer;
                    132:        unsigned length;
                    133:        struct universe *universe;
                    134: {
                    135:        unsigned len, offset;
                    136:        unsigned code;
                    137:        struct option_cache *op = NULL, *nop = NULL;
                    138:        struct buffer *bp = (struct buffer *)0;
                    139:        struct option *option = NULL;
                    140:        char *reason = "general failure";
                    141: 
                    142:        if (!buffer_allocate (&bp, length, MDL)) {
                    143:                log_error ("no memory for option buffer.");
                    144:                return 0;
                    145:        }
                    146:        memcpy (bp -> data, buffer, length);
                    147: 
                    148:        for (offset = 0;
                    149:             (offset + universe->tag_size) <= length &&
                    150:             (code = universe->get_tag(buffer + offset)) != universe->end; ) {
                    151:                offset += universe->tag_size;
                    152: 
                    153:                /* Pad options don't have a length - just skip them. */
                    154:                if (code == DHO_PAD)
                    155:                        continue;
                    156: 
                    157:                /* Don't look for length if the buffer isn't that big. */
                    158:                if ((offset + universe->length_size) > length) {
                    159:                        reason = "code tag at end of buffer - missing "
                    160:                                 "length field";
                    161:                        goto bogus;
                    162:                }
                    163: 
                    164:                /* All other fields (except PAD and END handled above)
                    165:                 * have a length field, unless it's a DHCPv6 zero-length
                    166:                 * options space (eg any of the enterprise-id'd options).
                    167:                 *
                    168:                 * Zero-length-size option spaces basically consume the
                    169:                 * entire options buffer, so have at it.
                    170:                 */
                    171:                if (universe->get_length != NULL)
                    172:                        len = universe->get_length(buffer + offset);
                    173:                else if (universe->length_size == 0)
                    174:                        len = length - universe->tag_size;
                    175:                else {
                    176:                        log_fatal("Improperly configured option space(%s): "
                    177:                                  "may not have a nonzero length size "
                    178:                                  "AND a NULL get_length function.",
                    179:                                  universe->name);
                    180: 
                    181:                        /* Silence compiler warnings. */
                    182:                        return 0;
                    183:                }
                    184: 
                    185:                offset += universe->length_size;
                    186: 
                    187:                option_code_hash_lookup(&option, universe->code_hash, &code,
                    188:                                        0, MDL);
                    189: 
                    190:                /* If the length is outrageous, the options are bad. */
                    191:                if (offset + len > length) {
                    192:                        reason = "option length exceeds option buffer length";
                    193:                      bogus:
                    194:                        log_error("parse_option_buffer: malformed option "
                    195:                                  "%s.%s (code %u): %s.", universe->name,
                    196:                                  option ? option->name : "<unknown>",
                    197:                                  code, reason);
                    198:                        buffer_dereference (&bp, MDL);
                    199:                        return 0;
                    200:                }
                    201: 
                    202:                /* If the option contains an encapsulation, parse it.   If
                    203:                   the parse fails, or the option isn't an encapsulation (by
                    204:                   far the most common case), or the option isn't entirely
                    205:                   an encapsulation, keep the raw data as well. */
                    206:                if (!(option &&
                    207:                      (option->format[0] == 'e' ||
                    208:                       option->format[0] == 'E') &&
                    209:                      (parse_encapsulated_suboptions(options, option,
                    210:                                                     bp->data + offset, len,
                    211:                                                     universe, NULL)))) {
                    212:                        op = lookup_option(universe, options, code);
                    213: 
                    214:                        if (op != NULL && universe->concat_duplicates) {
                    215:                                struct data_string new;
                    216:                                memset(&new, 0, sizeof new);
                    217:                                if (!buffer_allocate(&new.buffer,
                    218:                                                     op->data.len + len,
                    219:                                                     MDL)) {
                    220:                                        log_error("parse_option_buffer: "
                    221:                                                  "No memory.");
                    222:                                        buffer_dereference(&bp, MDL);
                    223:                                        return 0;
                    224:                                }
                    225:                                /* Copy old option to new data object. */
                    226:                                memcpy(new.buffer->data, op->data.data,
                    227:                                        op->data.len);
                    228:                                /* Concat new option behind old. */
                    229:                                memcpy(new.buffer->data + op->data.len,
                    230:                                        bp->data + offset, len);
                    231:                                new.len = op->data.len + len;
                    232:                                new.data = new.buffer->data;
                    233:                                /* Save new concat'd object. */
                    234:                                data_string_forget(&op->data, MDL);
                    235:                                data_string_copy(&op->data, &new, MDL);
                    236:                                data_string_forget(&new, MDL);
                    237:                        } else if (op != NULL) {
                    238:                                /* We must append this statement onto the
                    239:                                 * end of the list.
                    240:                                 */
                    241:                                while (op->next != NULL)
                    242:                                        op = op->next;
                    243: 
                    244:                                if (!option_cache_allocate(&nop, MDL)) {
                    245:                                        log_error("parse_option_buffer: "
                    246:                                                  "No memory.");
                    247:                                        buffer_dereference(&bp, MDL);
                    248:                                        return 0;
                    249:                                }
                    250: 
                    251:                                option_reference(&nop->option, op->option, MDL);
                    252: 
                    253:                                nop->data.buffer = NULL;
                    254:                                buffer_reference(&nop->data.buffer, bp, MDL);
                    255:                                nop->data.data = bp->data + offset;
                    256:                                nop->data.len = len;
                    257: 
                    258:                                option_cache_reference(&op->next, nop, MDL);
                    259:                                option_cache_dereference(&nop, MDL);
                    260:                        } else {
                    261:                                save_option_buffer(universe, options, bp,
                    262:                                                   bp->data + offset, len,
                    263:                                                   code, 1);
                    264:                        }
                    265:                }
                    266:                option_dereference(&option, MDL);
                    267:                offset += len;
                    268:        }
                    269:        buffer_dereference (&bp, MDL);
                    270:        return 1;
                    271: }
                    272: 
                    273: /* If an option in an option buffer turns out to be an encapsulation,
                    274:    figure out what to do.   If we don't know how to de-encapsulate it,
                    275:    or it's not well-formed, return zero; otherwise, return 1, indicating
                    276:    that we succeeded in de-encapsulating it. */
                    277: 
                    278: struct universe *find_option_universe (struct option *eopt, const char *uname)
                    279: {
                    280:        int i;
                    281:        char *s, *t;
                    282:        struct universe *universe = (struct universe *)0;
                    283: 
                    284:        /* Look for the E option in the option format. */
                    285:        s = strchr (eopt -> format, 'E');
                    286:        if (!s) {
                    287:                log_error ("internal encapsulation format error 1.");
                    288:                return 0;
                    289:        }
                    290:        /* Look for the universe name in the option format. */
                    291:        t = strchr (++s, '.');
                    292:        /* If there was no trailing '.', or there's something after the
                    293:           trailing '.', the option is bogus and we can't use it. */
                    294:        if (!t || t [1]) {
                    295:                log_error ("internal encapsulation format error 2.");
                    296:                return 0;
                    297:        }
                    298:        if (t == s && uname) {
                    299:                for (i = 0; i < universe_count; i++) {
                    300:                        if (!strcmp (universes [i] -> name, uname)) {
                    301:                                universe = universes [i];
                    302:                                break;
                    303:                        }
                    304:                }
                    305:        } else if (t != s) {
                    306:                for (i = 0; i < universe_count; i++) {
                    307:                        if (strlen (universes [i] -> name) == t - s &&
                    308:                            !memcmp (universes [i] -> name,
                    309:                                     s, (unsigned)(t - s))) {
                    310:                                universe = universes [i];
                    311:                                break;
                    312:                        }
                    313:                }
                    314:        }
                    315:        return universe;
                    316: }
                    317: 
                    318: /* If an option in an option buffer turns out to be an encapsulation,
                    319:    figure out what to do.   If we don't know how to de-encapsulate it,
                    320:    or it's not well-formed, return zero; otherwise, return 1, indicating
                    321:    that we succeeded in de-encapsulating it. */
                    322: 
                    323: int parse_encapsulated_suboptions (struct option_state *options,
                    324:                                   struct option *eopt,
                    325:                                   const unsigned char *buffer,
                    326:                                   unsigned len, struct universe *eu,
                    327:                                   const char *uname)
                    328: {
                    329:        int i;
                    330:        struct universe *universe = find_option_universe (eopt, uname);
                    331: 
                    332:        /* If we didn't find the universe, we can't do anything with it
                    333:           right now (e.g., we can't decode vendor options until we've
                    334:           decoded the packet and executed the scopes that it matches). */
                    335:        if (!universe)
                    336:                return 0;
                    337:                
                    338:        /* If we don't have a decoding function for it, we can't decode
                    339:           it. */
                    340:        if (!universe -> decode)
                    341:                return 0;
                    342: 
                    343:        i = (*universe -> decode) (options, buffer, len, universe);
                    344: 
                    345:        /* If there is stuff before the suboptions, we have to keep it. */
                    346:        if (eopt -> format [0] != 'E')
                    347:                return 0;
                    348:        /* Otherwise, return the status of the decode function. */
                    349:        return i;
                    350: }
                    351: 
                    352: int fqdn_universe_decode (struct option_state *options,
                    353:                          const unsigned char *buffer,
                    354:                          unsigned length, struct universe *u)
                    355: {
                    356:        struct buffer *bp = (struct buffer *)0;
                    357: 
                    358:        /* FQDN options have to be at least four bytes long. */
                    359:        if (length < 3)
                    360:                return 0;
                    361: 
                    362:        /* Save the contents of the option in a buffer. */
                    363:        if (!buffer_allocate (&bp, length + 4, MDL)) {
                    364:                log_error ("no memory for option buffer.");
                    365:                return 0;
                    366:        }
                    367:        memcpy (&bp -> data [3], buffer + 1, length - 1);
                    368: 
                    369:        if (buffer [0] & 4)     /* encoded */
                    370:                bp -> data [0] = 1;
                    371:        else
                    372:                bp -> data [0] = 0;
                    373:        if (!save_option_buffer(&fqdn_universe, options, bp,
                    374:                                bp->data, 1, FQDN_ENCODED, 0)) {
                    375:              bad:
                    376:                buffer_dereference (&bp, MDL);
                    377:                return 0;
                    378:        }
                    379: 
                    380:        if (buffer [0] & 1)     /* server-update */
                    381:                bp -> data [2] = 1;
                    382:        else
                    383:                bp -> data [2] = 0;
                    384:        if (buffer [0] & 2)     /* no-client-update */
                    385:                bp -> data [1] = 1;
                    386:        else
                    387:                bp -> data [1] = 0;
                    388: 
                    389:        /* XXX Ideally we should store the name in DNS format, so if the
                    390:           XXX label isn't in DNS format, we convert it to DNS format,
                    391:           XXX rather than converting labels specified in DNS format to
                    392:           XXX the plain ASCII representation.   But that's hard, so
                    393:           XXX not now. */
                    394: 
                    395:        /* Not encoded using DNS format? */
                    396:        if (!bp -> data [0]) {
                    397:                unsigned i;
                    398: 
                    399:                /* Some broken clients NUL-terminate this option. */
                    400:                if (buffer [length - 1] == 0) {
                    401:                        --length;
                    402:                        bp -> data [1] = 1;
                    403:                }
                    404: 
                    405:                /* Determine the length of the hostname component of the
                    406:                   name.  If the name contains no '.' character, it
                    407:                   represents a non-qualified label. */
                    408:                for (i = 3; i < length && buffer [i] != '.'; i++);
                    409:                i -= 3;
                    410: 
                    411:                /* Note: If the client sends a FQDN, the first '.' will
                    412:                   be used as a NUL terminator for the hostname. */
                    413:                if (i && (!save_option_buffer(&fqdn_universe, options, bp,
                    414:                                              &bp->data[5], i,
                    415:                                              FQDN_HOSTNAME, 0)))
                    416:                        goto bad;
                    417:                /* Note: If the client sends a single label, the
                    418:                   FQDN_DOMAINNAME option won't be set. */
                    419:                if (length > 4 + i &&
                    420:                    (!save_option_buffer(&fqdn_universe, options, bp,
                    421:                                         &bp -> data[6 + i], length - 4 - i,
                    422:                                         FQDN_DOMAINNAME, 1)))
                    423:                        goto bad;
                    424:                /* Also save the whole name. */
                    425:                if (length > 3) {
                    426:                        if (!save_option_buffer(&fqdn_universe, options, bp,
                    427:                                                &bp -> data [5], length - 3,
                    428:                                                FQDN_FQDN, 1))
                    429:                                goto bad;
                    430:                }
                    431:        } else {
                    432:                unsigned len;
                    433:                unsigned total_len = 0;
                    434:                unsigned first_len = 0;
                    435:                int terminated = 0;
                    436:                unsigned char *s;
                    437: 
                    438:                s = &bp -> data[5];
                    439: 
                    440:                while (s < &bp -> data[0] + length + 2) {
                    441:                        len = *s;
                    442:                        if (len > 63) {
                    443:                                log_info ("fancy bits in fqdn option");
                    444:                                return 0;
                    445:                        }       
                    446:                        if (len == 0) {
                    447:                                terminated = 1;
                    448:                                break;
                    449:                        }
                    450:                        if (s + len > &bp -> data [0] + length + 3) {
                    451:                                log_info ("fqdn tag longer than buffer");
                    452:                                return 0;
                    453:                        }
                    454: 
                    455:                        if (first_len == 0) {
                    456:                                first_len = len;
                    457:                        }
                    458: 
                    459:                        *s = '.';
                    460:                        s += len + 1;
                    461:                        total_len += len + 1;
                    462:                }
                    463: 
                    464:                /* We wind up with a length that's one too many because
                    465:                   we shouldn't increment for the last label, but there's
                    466:                   no way to tell we're at the last label until we exit
                    467:                   the loop.   :'*/
                    468:                if (total_len > 0)
                    469:                        total_len--;
                    470: 
                    471:                if (!terminated) {
                    472:                        first_len = total_len;
                    473:                }
                    474: 
                    475:                if (first_len > 0 &&
                    476:                    !save_option_buffer(&fqdn_universe, options, bp,
                    477:                                        &bp -> data[6], first_len,
                    478:                                        FQDN_HOSTNAME, 0))
                    479:                        goto bad;
                    480:                if (total_len > 0 && first_len != total_len) {
                    481:                        if (!save_option_buffer(&fqdn_universe, options, bp,
                    482:                                                &bp->data[6 + first_len],
                    483:                                                total_len - first_len,
                    484:                                                FQDN_DOMAINNAME, 1))
                    485:                                goto bad;
                    486:                }
                    487:                if (total_len > 0)
                    488:                        if (!save_option_buffer (&fqdn_universe, options, bp,
                    489:                                                 &bp -> data [6], total_len,
                    490:                                                 FQDN_FQDN, 1))
                    491:                                goto bad;
                    492:        }
                    493: 
                    494:        if (!save_option_buffer (&fqdn_universe, options, bp,
                    495:                                 &bp -> data [1], 1,
                    496:                                 FQDN_NO_CLIENT_UPDATE, 0))
                    497:            goto bad;
                    498:        if (!save_option_buffer (&fqdn_universe, options, bp,
                    499:                                 &bp -> data [2], 1,
                    500:                                 FQDN_SERVER_UPDATE, 0))
                    501:                goto bad;
                    502: 
                    503:        if (!save_option_buffer (&fqdn_universe, options, bp,
                    504:                                 &bp -> data [3], 1,
                    505:                                 FQDN_RCODE1, 0))
                    506:                goto bad;
                    507:        if (!save_option_buffer (&fqdn_universe, options, bp,
                    508:                                 &bp -> data [4], 1,
                    509:                                 FQDN_RCODE2, 0))
                    510:                goto bad;
                    511: 
                    512:        buffer_dereference (&bp, MDL);
                    513:        return 1;
                    514: }
                    515: 
                    516: /*
                    517:  * Load all options into a buffer, and then split them out into the three
                    518:  * separate fields in the dhcp packet (options, file, and sname) where
                    519:  * options can be stored.
                    520:  */
                    521: int
                    522: cons_options(struct packet *inpacket, struct dhcp_packet *outpacket,
                    523:             struct lease *lease, struct client_state *client_state,
                    524:             int mms, struct option_state *in_options,
                    525:             struct option_state *cfg_options,
                    526:             struct binding_scope **scope,
                    527:             int overload_avail, int terminate, int bootpp,
                    528:             struct data_string *prl, const char *vuname)
                    529: {
                    530: #define PRIORITY_COUNT 300
                    531:        unsigned priority_list[PRIORITY_COUNT];
                    532:        int priority_len;
                    533:        unsigned char buffer[4096], agentopts[1024];
                    534:        unsigned index = 0;
                    535:        unsigned mb_size = 0, mb_max = 0;
                    536:        unsigned option_size = 0, agent_size = 0;
                    537:        unsigned length;
                    538:        int i;
                    539:        struct option_cache *op;
                    540:        struct data_string ds;
                    541:        pair pp, *hash;
                    542:        int overload_used = 0;
                    543:        int of1 = 0, of2 = 0;
                    544: 
                    545:        memset(&ds, 0, sizeof ds);
                    546: 
                    547:        /*
                    548:         * If there's a Maximum Message Size option in the incoming packet
                    549:         * and no alternate maximum message size has been specified, or
                    550:         * if the one specified in the packet is shorter than the
                    551:         * alternative, take the one in the packet.
                    552:         */
                    553: 
                    554:        if (inpacket &&
                    555:            (op = lookup_option(&dhcp_universe, inpacket->options,
                    556:                                 DHO_DHCP_MAX_MESSAGE_SIZE))) {
                    557:                evaluate_option_cache(&ds, inpacket,
                    558:                                       lease, client_state, in_options,
                    559:                                       cfg_options, scope, op, MDL);
                    560:                if (ds.len >= sizeof (u_int16_t)) {
                    561:                        i = getUShort(ds.data);
                    562:                        if(!mms || (i < mms))
                    563:                                mms = i;
                    564:                }
                    565:                data_string_forget(&ds, MDL);
                    566:        }
                    567: 
                    568:        /*
                    569:         * If the client has provided a maximum DHCP message size,
                    570:         * use that, up to the MTU limit.  Otherwise, if it's BOOTP,
                    571:         * only 64 bytes; otherwise use up to the minimum IP MTU size
                    572:         * (576 bytes).
                    573:         *
                    574:         * XXX if a BOOTP client specifies a max message size, we will
                    575:         * honor it.
                    576:         */
                    577:        if (mms) {
                    578:                if (mms < DHCP_MTU_MIN)
                    579:                        /* Enforce minimum packet size, per RFC 2132 */
                    580:                        mb_size = DHCP_MIN_OPTION_LEN;
                    581:                else if (mms > DHCP_MTU_MAX)
                    582:                        /*
                    583:                         * TODO: Packets longer than 1500 bytes really
                    584:                         * should be allowed, but it requires upstream
                    585:                         * changes to the way the packet is allocated.  For
                    586:                         * now, we forbid them.  They won't be needed very
                    587:                         * often anyway.
                    588:                         */
                    589:                        mb_size = DHCP_MAX_OPTION_LEN;
                    590:                else
                    591:                        mb_size = mms - DHCP_FIXED_LEN;
                    592:        } else if (bootpp) {
                    593:                mb_size = 64;
                    594:                if (inpacket != NULL &&
                    595:                    (inpacket->packet_length >= 64 + DHCP_FIXED_NON_UDP))
                    596:                        mb_size = inpacket->packet_length - DHCP_FIXED_NON_UDP;
                    597:        } else
                    598:                mb_size = DHCP_MIN_OPTION_LEN;
                    599: 
                    600:        /*
                    601:         * If answering a client message, see whether any relay agent
                    602:         * options were included with the message.  If so, save them
                    603:         * to copy back in later, and make space in the main buffer
                    604:         * to accommodate them
                    605:         */
                    606:        if (client_state == NULL) {
                    607:                priority_list[0] = DHO_DHCP_AGENT_OPTIONS;
                    608:                priority_len = 1;
                    609:                agent_size = store_options(NULL, agentopts, 0,
                    610:                                           sizeof(agentopts),
                    611:                                           inpacket, lease, client_state,
                    612:                                           in_options, cfg_options, scope,
                    613:                                           priority_list, priority_len,
                    614:                                           0, 0, 0, NULL);
                    615: 
                    616:                mb_size += agent_size;
                    617:                if (mb_size > DHCP_MAX_OPTION_LEN)
                    618:                        mb_size = DHCP_MAX_OPTION_LEN;
                    619:        }
                    620: 
                    621:        /*
                    622:         * Set offsets for buffer data to be copied into filename
                    623:         * and servername fields 
                    624:         */
                    625:        mb_max = mb_size;
                    626: 
                    627:        if (overload_avail & 1) {
                    628:                of1 = mb_max;
                    629:                mb_max += DHCP_FILE_LEN;
                    630:        }
                    631: 
                    632:        if (overload_avail & 2) {
                    633:                of2 = mb_max;
                    634:                mb_max += DHCP_SNAME_LEN;
                    635:        }
                    636:                
                    637:        /*
                    638:         * Preload the option priority list with protocol-mandatory options.
                    639:         * This effectively gives these options the highest priority.
                    640:         * This provides the order for any available options, the option
                    641:         * must be in the option cache in order to actually be included.
                    642:         */
                    643:        priority_len = 0;
                    644:        priority_list[priority_len++] = DHO_DHCP_MESSAGE_TYPE;
                    645:        priority_list[priority_len++] = DHO_DHCP_SERVER_IDENTIFIER;
                    646:        priority_list[priority_len++] = DHO_DHCP_LEASE_TIME;
                    647:        priority_list[priority_len++] = DHO_DHCP_MESSAGE;
                    648:        priority_list[priority_len++] = DHO_DHCP_REQUESTED_ADDRESS;
                    649:        priority_list[priority_len++] = DHO_ASSOCIATED_IP;
                    650: 
                    651:        if (prl != NULL && prl->len > 0) {
                    652:                if ((op = lookup_option(&dhcp_universe, cfg_options,
                    653:                                         DHO_SUBNET_SELECTION))) {
                    654:                        if (priority_len < PRIORITY_COUNT)
                    655:                                priority_list[priority_len++] =
                    656:                                        DHO_SUBNET_SELECTION;
                    657:                }
                    658: 
                    659:                data_string_truncate(prl, (PRIORITY_COUNT - priority_len));
                    660: 
                    661:                for (i = 0; i < prl->len; i++) {
                    662:                        /*
                    663:                         * Prevent client from changing order of delivery
                    664:                         * of relay agent information option.
                    665:                         */
                    666:                        if (prl->data[i] != DHO_DHCP_AGENT_OPTIONS)
                    667:                                priority_list[priority_len++] = prl->data[i];
                    668:                }
                    669: 
                    670:                /*
                    671:                 * If the client doesn't request the FQDN option explicitly,
                    672:                 * to indicate priority, consider it lowest priority.  Fit
                    673:                 * in the packet if there is space.  Note that the option
                    674:                 * may only be included if the client supplied one.
                    675:                 */
                    676:                if ((priority_len < PRIORITY_COUNT) &&
                    677:                    (lookup_option(&fqdn_universe, inpacket->options,
                    678:                                   FQDN_ENCODED) != NULL))
                    679:                        priority_list[priority_len++] = DHO_FQDN;
                    680: 
                    681:                /*
                    682:                 * Some DHCP Servers will give the subnet-mask option if
                    683:                 * it is not on the parameter request list - so some client
                    684:                 * implementations have come to rely on this - so we will
                    685:                 * also make sure we supply this, at lowest priority.
                    686:                 *
                    687:                 * This is only done in response to DHCPDISCOVER or
                    688:                 * DHCPREQUEST messages, to avoid providing the option on
                    689:                 * DHCPINFORM or DHCPLEASEQUERY responses (if the client
                    690:                 * didn't request it).
                    691:                 */
                    692:                if ((priority_len < PRIORITY_COUNT) &&
                    693:                    ((inpacket->packet_type == DHCPDISCOVER) ||
                    694:                     (inpacket->packet_type == DHCPREQUEST)))
                    695:                        priority_list[priority_len++] = DHO_SUBNET_MASK;
                    696:        } else {
                    697:                /*
                    698:                 * First, hardcode some more options that ought to be
                    699:                 * sent first...these are high priority to have in the
                    700:                 * packet.
                    701:                 */
                    702:                priority_list[priority_len++] = DHO_SUBNET_MASK;
                    703:                priority_list[priority_len++] = DHO_ROUTERS;
                    704:                priority_list[priority_len++] = DHO_DOMAIN_NAME_SERVERS;
                    705:                priority_list[priority_len++] = DHO_HOST_NAME;
                    706:                priority_list[priority_len++] = DHO_FQDN;
                    707: 
                    708:                /*
                    709:                 * Append a list of the standard DHCP options from the
                    710:                 * standard DHCP option space.  Actually, if a site
                    711:                 * option space hasn't been specified, we wind up
                    712:                 * treating the dhcp option space as the site option
                    713:                 * space, and the first for loop is skipped, because
                    714:                 * it's slightly more general to do it this way,
                    715:                 * taking the 1Q99 DHCP futures work into account.
                    716:                 */
                    717:                if (cfg_options->site_code_min) {
                    718:                    for (i = 0; i < OPTION_HASH_SIZE; i++) {
                    719:                        hash = cfg_options->universes[dhcp_universe.index];
                    720:                        if (hash) {
                    721:                            for (pp = hash[i]; pp; pp = pp->cdr) {
                    722:                                op = (struct option_cache *)(pp->car);
                    723:                                if (op->option->code <
                    724:                                     cfg_options->site_code_min &&
                    725:                                    priority_len < PRIORITY_COUNT &&
                    726:                                    op->option->code != DHO_DHCP_AGENT_OPTIONS)
                    727:                                        priority_list[priority_len++] =
                    728:                                                op->option->code;
                    729:                            }
                    730:                        }
                    731:                    }
                    732:                }
                    733: 
                    734:                /*
                    735:                 * Now cycle through the site option space, or if there
                    736:                 * is no site option space, we'll be cycling through the
                    737:                 * dhcp option space.
                    738:                 */
                    739:                for (i = 0; i < OPTION_HASH_SIZE; i++) {
                    740:                    hash = cfg_options->universes[cfg_options->site_universe];
                    741:                    if (hash != NULL)
                    742:                        for (pp = hash[i]; pp; pp = pp->cdr) {
                    743:                                op = (struct option_cache *)(pp->car);
                    744:                                if (op->option->code >=
                    745:                                     cfg_options->site_code_min &&
                    746:                                    priority_len < PRIORITY_COUNT &&
                    747:                                    op->option->code != DHO_DHCP_AGENT_OPTIONS)
                    748:                                        priority_list[priority_len++] =
                    749:                                                op->option->code;
                    750:                        }
                    751:                }
                    752: 
                    753:                /*
                    754:                 * Put any spaces that are encapsulated on the list,
                    755:                 * sort out whether they contain values later.
                    756:                 */
                    757:                for (i = 0; i < cfg_options->universe_count; i++) {
                    758:                    if (universes[i]->enc_opt &&
                    759:                        priority_len < PRIORITY_COUNT &&
                    760:                        universes[i]->enc_opt->universe == &dhcp_universe) {
                    761:                            if (universes[i]->enc_opt->code !=
                    762:                                DHO_DHCP_AGENT_OPTIONS)
                    763:                                    priority_list[priority_len++] =
                    764:                                            universes[i]->enc_opt->code;
                    765:                    }
                    766:                }
                    767: 
                    768:                /*
                    769:                 * The vendor option space can't stand on its own, so always
                    770:                 * add it to the list.
                    771:                 */
                    772:                if (priority_len < PRIORITY_COUNT)
                    773:                        priority_list[priority_len++] =
                    774:                                DHO_VENDOR_ENCAPSULATED_OPTIONS;
                    775:        }
                    776: 
                    777:        /* Put the cookie up front... */
                    778:        memcpy(buffer, DHCP_OPTIONS_COOKIE, 4);
                    779:        index += 4;
                    780: 
                    781:        /* Copy the options into the big buffer... */
                    782:        option_size = store_options(&overload_used, buffer, index, mb_max,
                    783:                                    inpacket, lease, client_state,
                    784:                                    in_options, cfg_options, scope,
                    785:                                    priority_list, priority_len,
                    786:                                    of1, of2, terminate, vuname);
                    787: 
                    788:        /* If store_options() failed */
                    789:        if (option_size == 0)
                    790:                return 0;
                    791: 
                    792:        /* How much was stored in the main buffer? */
                    793:        index += option_size;
                    794: 
                    795:        /*
                    796:         * If we're going to have to overload, store the overload
                    797:         * option first.
                    798:         */
                    799:        if (overload_used) {
                    800:                if (mb_size - agent_size - index < 3)
                    801:                        return 0;
                    802: 
                    803:                buffer[index++] = DHO_DHCP_OPTION_OVERLOAD;
                    804:                buffer[index++] = 1;
                    805:                buffer[index++] = overload_used;
                    806: 
                    807:                if (overload_used & 1)
                    808:                        memcpy(outpacket->file, &buffer[of1], DHCP_FILE_LEN);
                    809: 
                    810:                if (overload_used & 2)
                    811:                        memcpy(outpacket->sname, &buffer[of2], DHCP_SNAME_LEN);
                    812:        }
                    813: 
                    814:        /* Now copy in preserved agent options, if any */
                    815:        if (agent_size) {
                    816:                if (mb_size - index >= agent_size) {
                    817:                        memcpy(&buffer[index], agentopts, agent_size);
                    818:                        index += agent_size;
                    819:                } else
                    820:                        log_error("Unable to store relay agent information "
                    821:                                  "in reply packet.");
                    822:        }
                    823: 
                    824:        /* Tack a DHO_END option onto the packet if we need to. */
                    825:        if (index < mb_size)
                    826:                buffer[index++] = DHO_END;
                    827: 
                    828:        /* Copy main buffer into the options buffer of the packet */
                    829:        memcpy(outpacket->options, buffer, index);
                    830: 
                    831:        /* Figure out the length. */
                    832:        length = DHCP_FIXED_NON_UDP + index;
                    833:        return length;
                    834: }
                    835: 
                    836: /*
                    837:  * XXX: We currently special case collecting VSIO options.
                    838:  *      We should be able to handle this in a more generic fashion, by
                    839:  *      including any encapsulated options that are present and desired.
                    840:  *      This will look something like the VSIO handling VSIO code.
                    841:  *      We may also consider handling the ORO-like options within
                    842:  *      encapsulated spaces.
                    843:  */
                    844: 
                    845: struct vsio_state {
                    846:        char *buf;
                    847:        int buflen;
                    848:        int bufpos;
                    849: };
                    850: 
                    851: static void
                    852: vsio_options(struct option_cache *oc,
                    853:             struct packet *packet,
                    854:             struct lease *dummy_lease, 
                    855:             struct client_state *dummy_client_state,
                    856:             struct option_state *dummy_opt_state,
                    857:             struct option_state *opt_state,
                    858:             struct binding_scope **dummy_binding_scope,
                    859:             struct universe *universe, 
                    860:             void *void_vsio_state) {
                    861:        struct vsio_state *vs = (struct vsio_state *)void_vsio_state;
                    862:        struct data_string ds;
                    863:        int total_len;
                    864: 
                    865:        memset(&ds, 0, sizeof(ds));
                    866:        if (evaluate_option_cache(&ds, packet, NULL,
                    867:                                  NULL, opt_state, NULL, 
                    868:                                  &global_scope, oc, MDL)) {
                    869:                total_len = ds.len + universe->tag_size + universe->length_size;
                    870:                if (total_len <= (vs->buflen - vs->bufpos)) {
                    871:                        if (universe->tag_size == 1) {
                    872:                                vs->buf[vs->bufpos++] = oc->option->code;
                    873:                        } else if (universe->tag_size == 2) {
                    874:                                putUShort((unsigned char *)vs->buf+vs->bufpos,
                    875:                                          oc->option->code);
                    876:                                vs->bufpos += 2;
                    877:                        } else if (universe->tag_size == 4) {
                    878:                                putULong((unsigned char *)vs->buf+vs->bufpos,
                    879:                                         oc->option->code);
                    880:                                vs->bufpos += 4;
                    881:                        }
                    882:                        if (universe->length_size == 1) {
                    883:                                vs->buf[vs->bufpos++] = ds.len;
                    884:                        } else if (universe->length_size == 2) {
                    885:                                putUShort((unsigned char *)vs->buf+vs->bufpos, 
                    886:                                          ds.len);
                    887:                                vs->bufpos += 2;
                    888:                        } else if (universe->length_size == 4) {
                    889:                                putULong((unsigned char *)vs->buf+vs->bufpos, 
                    890:                                         ds.len);
                    891:                                vs->bufpos += 4;
                    892:                        }
                    893:                        memcpy(vs->buf + vs->bufpos, ds.data, ds.len);
                    894:                        vs->bufpos += ds.len;
                    895:                } else {
                    896:                        log_debug("No space for option %d in VSIO space %s.",
                    897:                                oc->option->code, universe->name);
                    898:                }
                    899:                data_string_forget(&ds, MDL);
                    900:        } else {
                    901:                log_error("Error evaluating option %d in VSIO space %s.",
                    902:                        oc->option->code, universe->name);
                    903:        }
                    904: }
                    905: 
                    906: /*
                    907:  * Stores the options from the DHCPv6 universe into the buffer given.
                    908:  *
                    909:  * Required options are given as a 0-terminated list of option codes.
                    910:  * Once those are added, the ORO is consulted.
                    911:  */
                    912: 
                    913: int
                    914: store_options6(char *buf, int buflen, 
                    915:               struct option_state *opt_state, 
                    916:               struct packet *packet,
                    917:               const int *required_opts,
                    918:               struct data_string *oro) {
                    919:        int i, j;
                    920:        struct option_cache *oc;
                    921:        struct option *o;
                    922:        struct data_string ds;
                    923:        int bufpos;
                    924:        int oro_size;
                    925:        u_int16_t code;
                    926:        int in_required_opts;
                    927:        int vsio_option_code;
                    928:        int vsio_wanted;
                    929:        struct vsio_state vs;
                    930:        unsigned char *tmp;
                    931: 
                    932:        bufpos = 0;
                    933:        vsio_wanted = 0;
                    934: 
                    935:        /*
                    936:         * Find the option code for the VSIO universe.
                    937:         */
                    938:        vsio_option_code = 0;
                    939:        o = vsio_universe.enc_opt;
                    940:        while (o != NULL) { 
                    941:                if (o->universe == &dhcpv6_universe) {
                    942:                        vsio_option_code = o->code;
                    943:                        break;
                    944:                } 
                    945:                o = o->universe->enc_opt;
                    946:        }
                    947:        if (vsio_option_code == 0) {
                    948:                log_fatal("No VSIO option code found.");
                    949:        }
                    950: 
                    951:        if (required_opts != NULL) {
                    952:                for (i=0; required_opts[i] != 0; i++) {
                    953:                        if (required_opts[i] == vsio_option_code) {
                    954:                                vsio_wanted = 1;
                    955:                        }
                    956: 
                    957:                        oc = lookup_option(&dhcpv6_universe, 
                    958:                                           opt_state, required_opts[i]);
                    959:                        if (oc == NULL) {
                    960:                                continue;
                    961:                        }
                    962:                        memset(&ds, 0, sizeof(ds));
                    963:                        for (; oc != NULL ; oc = oc->next) {
                    964:                                if (evaluate_option_cache(&ds, packet, NULL,
                    965:                                                          NULL, opt_state,
                    966:                                                          NULL, &global_scope,
                    967:                                                          oc, MDL)) {
                    968:                                        if ((ds.len + 4) <=
                    969:                                            (buflen - bufpos)) {
                    970:                                                tmp = (unsigned char *)buf;
                    971:                                                tmp += bufpos;
                    972:                                                /* option tag */
                    973:                                                putUShort(tmp,
                    974:                                                          required_opts[i]);
                    975:                                                /* option length */
                    976:                                                putUShort(tmp+2, ds.len);
                    977:                                                /* option data */
                    978:                                                memcpy(tmp+4, ds.data, ds.len);
                    979:                                                /* update position */
                    980:                                                bufpos += (4 + ds.len);
                    981:                                        } else {
                    982:                                                log_debug("No space for "
                    983:                                                          "option %d",
                    984:                                                          required_opts[i]);
                    985:                                        }
                    986:                                        data_string_forget(&ds, MDL);
                    987:                                } else {
                    988:                                        log_error("Error evaluating option %d",
                    989:                                                required_opts[i]);
                    990:                                }
                    991:                        }
                    992:                }
                    993:        }
                    994: 
                    995:        if (oro == NULL) {
                    996:                oro_size = 0;
                    997:        } else {
                    998:                oro_size = oro->len / 2;
                    999:        }
                   1000:        for (i=0; i<oro_size; i++) {
                   1001:                memcpy(&code, oro->data+(i*2), 2);
                   1002:                code = ntohs(code);
                   1003: 
                   1004:                /* 
                   1005:                 * See if we've already included this option because
                   1006:                 * it is required.
                   1007:                 */
                   1008:                in_required_opts = 0;
                   1009:                if (required_opts != NULL) {
                   1010:                        for (j=0; required_opts[j] != 0; j++) {
                   1011:                                if (required_opts[j] == code) {
                   1012:                                        in_required_opts = 1;
                   1013:                                        break;
                   1014:                                }
                   1015:                        }
                   1016:                }
                   1017:                if (in_required_opts) {
                   1018:                        continue;
                   1019:                }
                   1020: 
                   1021:                /*
                   1022:                 * See if this is the VSIO option.
                   1023:                 */
                   1024:                if (code == vsio_option_code) {
                   1025:                        vsio_wanted = 1;
                   1026:                }
                   1027: 
                   1028:                /* 
                   1029:                 * Not already added, find this option.
                   1030:                 */
                   1031:                oc = lookup_option(&dhcpv6_universe, opt_state, code);
                   1032:                memset(&ds, 0, sizeof(ds));
                   1033:                for (; oc != NULL ; oc = oc->next) {
                   1034:                        if (evaluate_option_cache(&ds, packet, NULL, NULL,
                   1035:                                                  opt_state, NULL,
                   1036:                                                  &global_scope, oc, MDL)) {
                   1037:                                if ((ds.len + 4) <= (buflen - bufpos)) {
                   1038:                                        tmp = (unsigned char *)buf + bufpos;
                   1039:                                        /* option tag */
                   1040:                                        putUShort(tmp, code);
                   1041:                                        /* option length */
                   1042:                                        putUShort(tmp+2, ds.len);
                   1043:                                        /* option data */
                   1044:                                        memcpy(tmp+4, ds.data, ds.len);
                   1045:                                        /* update position */
                   1046:                                        bufpos += (4 + ds.len);
                   1047:                                } else {
                   1048:                                        log_debug("No space for option %d",
                   1049:                                                  code);
                   1050:                                }
                   1051:                                data_string_forget(&ds, MDL);
                   1052:                        } else {
                   1053:                                log_error("Error evaluating option %d", code);
                   1054:                        }
                   1055:                }
                   1056:        }
                   1057: 
                   1058:        if (vsio_wanted) {
                   1059:                for (i=0; i < opt_state->universe_count; i++) {
                   1060:                        if (opt_state->universes[i] != NULL) {
                   1061:                                o = universes[i]->enc_opt;
                   1062:                                if ((o != NULL) && 
                   1063:                                    (o->universe == &vsio_universe)) {
                   1064:                                        /*
                   1065:                                         * Add the data from this VSIO option.
                   1066:                                         */
                   1067:                                        vs.buf = buf;
                   1068:                                        vs.buflen = buflen;
                   1069:                                        vs.bufpos = bufpos+8;
                   1070:                                        option_space_foreach(packet, NULL,
                   1071:                                                             NULL, 
                   1072:                                                             NULL, opt_state,
                   1073:                                                             NULL, 
                   1074:                                                             universes[i], 
                   1075:                                                             (void *)&vs,
                   1076:                                                             vsio_options);
                   1077: 
                   1078:                                        /* 
                   1079:                                         * If there was actually data here,
                   1080:                                         * add the "header".
                   1081:                                         */
                   1082:                                        if (vs.bufpos > bufpos+8) {
                   1083:                                                tmp = (unsigned char *)buf +
                   1084:                                                      bufpos;
                   1085:                                                putUShort(tmp,
                   1086:                                                          vsio_option_code);
                   1087:                                                putUShort(tmp+2,
                   1088:                                                          vs.bufpos-bufpos-4);
                   1089:                                                putULong(tmp+4, o->code);
                   1090: 
                   1091:                                                bufpos = vs.bufpos;
                   1092:                                        }
                   1093:                                }
                   1094:                        }
                   1095:                }
                   1096:        }
                   1097: 
                   1098:        return bufpos;
                   1099: }
                   1100: 
                   1101: /*
                   1102:  * Store all the requested options into the requested buffer.
                   1103:  * XXX: ought to be static
                   1104:  */
                   1105: int
                   1106: store_options(int *ocount,
                   1107:              unsigned char *buffer, unsigned index, unsigned buflen,
                   1108:              struct packet *packet, struct lease *lease,
                   1109:              struct client_state *client_state,
                   1110:              struct option_state *in_options,
                   1111:              struct option_state *cfg_options,
                   1112:              struct binding_scope **scope,
                   1113:              unsigned *priority_list, int priority_len,
                   1114:              unsigned first_cutoff, int second_cutoff, int terminate,
                   1115:              const char *vuname)
                   1116: {
                   1117:        int bufix = 0, six = 0, tix = 0;
                   1118:        int i;
                   1119:        int ix;
                   1120:        int tto;
                   1121:        int bufend, sbufend;
                   1122:        struct data_string od;
                   1123:        struct option_cache *oc;
                   1124:        struct option *option = NULL;
                   1125:        unsigned code;
                   1126: 
                   1127:        /*
                   1128:         * These arguments are relative to the start of the buffer, so 
                   1129:         * reduce them by the current buffer index, and advance the
                   1130:         * buffer pointer to where we're going to start writing.
                   1131:         */
                   1132:        buffer = &buffer[index];
                   1133:        buflen -= index;
                   1134:        if (first_cutoff)
                   1135:                first_cutoff -= index;
                   1136:        if (second_cutoff)
                   1137:                second_cutoff -= index;
                   1138: 
                   1139:        /* Calculate the start and end of each section of the buffer */
                   1140:        bufend = sbufend = buflen;
                   1141:        if (first_cutoff) {
                   1142:            if (first_cutoff >= buflen)
                   1143:                log_fatal("%s:%d:store_options: Invalid first cutoff.", MDL);
                   1144:            bufend = first_cutoff;
                   1145: 
                   1146:            if (second_cutoff) {
                   1147:                if (second_cutoff >= buflen)
                   1148:                    log_fatal("%s:%d:store_options: Invalid second cutoff.",
                   1149:                              MDL);
                   1150:                sbufend = second_cutoff;
                   1151:            }
                   1152:        } else if (second_cutoff) {
                   1153:            if (second_cutoff >= buflen)
                   1154:                log_fatal("%s:%d:store_options: Invalid second cutoff.", MDL);
                   1155:            bufend = second_cutoff;
                   1156:        }
                   1157: 
                   1158:        memset (&od, 0, sizeof od);
                   1159: 
                   1160:        /* Eliminate duplicate options from the parameter request list.
                   1161:         * Enforce RFC-mandated ordering of options that are present.
                   1162:         */
                   1163:        for (i = 0; i < priority_len - 1; i++) {
                   1164:                /* Eliminate duplicates. */
                   1165:                tto = 0;
                   1166:                for (ix = i + 1; ix < priority_len + tto; ix++) {
                   1167:                        if (tto)
                   1168:                                priority_list [ix - tto] =
                   1169:                                        priority_list [ix];
                   1170:                        if (priority_list [i] == priority_list [ix]) {
                   1171:                                tto++;
                   1172:                                priority_len--;
                   1173:                        }
                   1174:                }
                   1175: 
                   1176:                /* Enforce ordering of SUBNET_MASK options, according to
                   1177:                 * RFC2132 Section 3.3:
                   1178:                 *
                   1179:                 *   If both the subnet mask and the router option are
                   1180:                 *   specified in a DHCP reply, the subnet mask option MUST
                   1181:                 *   be first.
                   1182:                 *
                   1183:                 * This guidance does not specify what to do if the client
                   1184:                 * PRL explicitly requests the options out of order, it is
                   1185:                 * a general statement.
                   1186:                 */
                   1187:                if (priority_list[i] == DHO_SUBNET_MASK) {
                   1188:                        for (ix = i - 1 ; ix >= 0 ; ix--) {
                   1189:                                if (priority_list[ix] == DHO_ROUTERS) {
                   1190:                                         /* swap */
                   1191:                                        priority_list[ix] = DHO_SUBNET_MASK;
                   1192:                                        priority_list[i] = DHO_ROUTERS;
                   1193:                                        break;
                   1194:                                }
                   1195:                        }
                   1196:                }
                   1197:        }
                   1198: 
                   1199:        /* Copy out the options in the order that they appear in the
                   1200:           priority list... */
                   1201:        for (i = 0; i < priority_len; i++) {
                   1202:            /* Number of bytes left to store (some may already
                   1203:               have been stored by a previous pass). */
                   1204:            unsigned length;
                   1205:            int optstart, soptstart, toptstart;
                   1206:            struct universe *u;
                   1207:            int have_encapsulation = 0;
                   1208:            struct data_string encapsulation;
                   1209:            int splitup;
                   1210: 
                   1211:            memset (&encapsulation, 0, sizeof encapsulation);
                   1212:            have_encapsulation = 0;
                   1213: 
                   1214:            if (option != NULL)
                   1215:                option_dereference(&option, MDL);
                   1216: 
                   1217:            /* Code for next option to try to store. */
                   1218:            code = priority_list [i];
                   1219:            
                   1220:            /* Look up the option in the site option space if the code
                   1221:               is above the cutoff, otherwise in the DHCP option space. */
                   1222:            if (code >= cfg_options -> site_code_min)
                   1223:                    u = universes [cfg_options -> site_universe];
                   1224:            else
                   1225:                    u = &dhcp_universe;
                   1226: 
                   1227:            oc = lookup_option (u, cfg_options, code);
                   1228: 
                   1229:            if (oc && oc->option)
                   1230:                option_reference(&option, oc->option, MDL);
                   1231:            else
                   1232:                option_code_hash_lookup(&option, u->code_hash, &code, 0, MDL);
                   1233: 
                   1234:            /* If it's a straight encapsulation, and the user supplied a
                   1235:             * value for the entire option, use that.  Otherwise, search
                   1236:             * the encapsulated space.
                   1237:             *
                   1238:             * If it's a limited encapsulation with preceding data, and the
                   1239:             * user supplied values for the preceding bytes, search the
                   1240:             * encapsulated space.
                   1241:             */
                   1242:            if ((option != NULL) &&
                   1243:                (((oc == NULL) && (option->format[0] == 'E')) ||
                   1244:                 ((oc != NULL) && (option->format[0] == 'e')))) {
                   1245:                static char *s, *t;
                   1246:                struct option_cache *tmp;
                   1247:                struct data_string name;
                   1248: 
                   1249:                s = strchr (option->format, 'E');
                   1250:                if (s)
                   1251:                    t = strchr (++s, '.');
                   1252:                if (s && t) {
                   1253:                    memset (&name, 0, sizeof name);
                   1254: 
                   1255:                    /* A zero-length universe name means the vendor
                   1256:                       option space, if one is defined. */
                   1257:                    if (t == s) {
                   1258:                        if (vendor_cfg_option) {
                   1259:                            tmp = lookup_option (vendor_cfg_option -> universe,
                   1260:                                                 cfg_options,
                   1261:                                                 vendor_cfg_option -> code);
                   1262:                            if (tmp)
                   1263:                                evaluate_option_cache (&name, packet, lease,
                   1264:                                                       client_state,
                   1265:                                                       in_options,
                   1266:                                                       cfg_options,
                   1267:                                                       scope, tmp, MDL);
                   1268:                        } else if (vuname) {
                   1269:                            name.data = (unsigned char *)s;
                   1270:                            name.len = strlen (s);
                   1271:                        }
                   1272:                    } else {
                   1273:                        name.data = (unsigned char *)s;
                   1274:                        name.len = t - s;
                   1275:                    }
                   1276:                        
                   1277:                    /* If we found a universe, and there are options configured
                   1278:                       for that universe, try to encapsulate it. */
                   1279:                    if (name.len) {
                   1280:                        have_encapsulation =
                   1281:                                (option_space_encapsulate
                   1282:                                 (&encapsulation, packet, lease, client_state,
                   1283:                                  in_options, cfg_options, scope, &name));
                   1284:                        data_string_forget (&name, MDL);
                   1285:                    }
                   1286:                }
                   1287:            }
                   1288: 
                   1289:            /* In order to avoid memory leaks, we have to get to here
                   1290:               with any option cache that we allocated in tmp not being
                   1291:               referenced by tmp, and whatever option cache is referenced
                   1292:               by oc being an actual reference.   lookup_option doesn't
                   1293:               generate a reference (this needs to be fixed), so the
                   1294:               preceding goop ensures that if we *didn't* generate a new
                   1295:               option cache, oc still winds up holding an actual reference. */
                   1296: 
                   1297:            /* If no data is available for this option, skip it. */
                   1298:            if (!oc && !have_encapsulation) {
                   1299:                    continue;
                   1300:            }
                   1301:            
                   1302:            /* Find the value of the option... */
                   1303:            od.len = 0;
                   1304:            if (oc) {
                   1305:                evaluate_option_cache (&od, packet,
                   1306:                                       lease, client_state, in_options,
                   1307:                                       cfg_options, scope, oc, MDL);
                   1308: 
                   1309:                /* If we have encapsulation for this option, and an oc
                   1310:                 * lookup succeeded, but the evaluation failed, it is
                   1311:                 * either because this is a complex atom (atoms before
                   1312:                 * E on format list) and the top half of the option is
                   1313:                 * not configured, or this is a simple encapsulated
                   1314:                 * space and the evaluator is giving us a NULL.  Prefer
                   1315:                 * the evaluator's opinion over the subspace.
                   1316:                 */
                   1317:                if (!od.len) {
                   1318:                    data_string_forget (&encapsulation, MDL);
                   1319:                    data_string_forget (&od, MDL);
                   1320:                    continue;
                   1321:                }
                   1322:            }
                   1323: 
                   1324:            /* We should now have a constant length for the option. */
                   1325:            length = od.len;
                   1326:            if (have_encapsulation) {
                   1327:                    length += encapsulation.len;
                   1328: 
                   1329:                    /* od.len can be nonzero if we got here without an
                   1330:                     * oc (cache lookup failed), but did have an encapsulated
                   1331:                     * simple encapsulation space.
                   1332:                     */
                   1333:                    if (!od.len) {
                   1334:                            data_string_copy (&od, &encapsulation, MDL);
                   1335:                            data_string_forget (&encapsulation, MDL);
                   1336:                    } else {
                   1337:                            struct buffer *bp = (struct buffer *)0;
                   1338:                            if (!buffer_allocate (&bp, length, MDL)) {
                   1339:                                    option_cache_dereference (&oc, MDL);
                   1340:                                    data_string_forget (&od, MDL);
                   1341:                                    data_string_forget (&encapsulation, MDL);
                   1342:                                    continue;
                   1343:                            }
                   1344:                            memcpy (&bp -> data [0], od.data, od.len);
                   1345:                            memcpy (&bp -> data [od.len], encapsulation.data,
                   1346:                                    encapsulation.len);
                   1347:                            data_string_forget (&od, MDL);
                   1348:                            data_string_forget (&encapsulation, MDL);
                   1349:                            od.data = &bp -> data [0];
                   1350:                            buffer_reference (&od.buffer, bp, MDL);
                   1351:                            buffer_dereference (&bp, MDL);
                   1352:                            od.len = length;
                   1353:                            od.terminated = 0;
                   1354:                    }
                   1355:            }
                   1356: 
                   1357:            /* Do we add a NUL? */
                   1358:            if (terminate && option && format_has_text(option->format)) {
                   1359:                    length++;
                   1360:                    tto = 1;
                   1361:            } else {
                   1362:                    tto = 0;
                   1363:            }
                   1364: 
                   1365:            /* Try to store the option. */
                   1366:            
                   1367:            /* If the option's length is more than 255, we must store it
                   1368:               in multiple hunks.   Store 255-byte hunks first.  However,
                   1369:               in any case, if the option data will cross a buffer
                   1370:               boundary, split it across that boundary. */
                   1371: 
                   1372:            if (length > 255)
                   1373:                splitup = 1;
                   1374:            else
                   1375:                splitup = 0;
                   1376: 
                   1377:            ix = 0;
                   1378:            optstart = bufix;
                   1379:            soptstart = six;
                   1380:            toptstart = tix;
                   1381:            while (length) {
                   1382:                    unsigned incr = length;
                   1383:                    int *pix;
                   1384:                    unsigned char *base;
                   1385: 
                   1386:                    /* Try to fit it in the options buffer. */
                   1387:                    if (!splitup &&
                   1388:                        ((!six && !tix && (i == priority_len - 1) &&
                   1389:                          (bufix + 2 + length < bufend)) ||
                   1390:                         (bufix + 5 + length < bufend))) {
                   1391:                        base = buffer;
                   1392:                        pix = &bufix;
                   1393:                    /* Try to fit it in the second buffer. */
                   1394:                    } else if (!splitup && first_cutoff &&
                   1395:                               (first_cutoff + six + 3 + length < sbufend)) {
                   1396:                        base = &buffer[first_cutoff];
                   1397:                        pix = &six;
                   1398:                    /* Try to fit it in the third buffer. */
                   1399:                    } else if (!splitup && second_cutoff &&
                   1400:                               (second_cutoff + tix + 3 + length < buflen)) {
                   1401:                        base = &buffer[second_cutoff];
                   1402:                        pix = &tix;
                   1403:                    /* Split the option up into the remaining space. */
                   1404:                    } else {
                   1405:                        splitup = 1;
                   1406: 
                   1407:                        /* Use any remaining options space. */
                   1408:                        if (bufix + 6 < bufend) {
                   1409:                            incr = bufend - bufix - 5;
                   1410:                            base = buffer;
                   1411:                            pix = &bufix;
                   1412:                        /* Use any remaining first_cutoff space. */
                   1413:                        } else if (first_cutoff &&
                   1414:                                   (first_cutoff + six + 4 < sbufend)) {
                   1415:                            incr = sbufend - (first_cutoff + six) - 3;
                   1416:                            base = &buffer[first_cutoff];
                   1417:                            pix = &six;
                   1418:                        /* Use any remaining second_cutoff space. */
                   1419:                        } else if (second_cutoff &&
                   1420:                                   (second_cutoff + tix + 4 < buflen)) {
                   1421:                            incr = buflen - (second_cutoff + tix) - 3;
                   1422:                            base = &buffer[second_cutoff];
                   1423:                            pix = &tix;
                   1424:                        /* Give up, roll back this option. */
                   1425:                        } else {
                   1426:                            bufix = optstart;
                   1427:                            six = soptstart;
                   1428:                            tix = toptstart;
                   1429:                            break;
                   1430:                        }
                   1431:                    }
                   1432: 
                   1433:                    if (incr > length)
                   1434:                        incr = length;
                   1435:                    if (incr > 255)
                   1436:                        incr = 255;
                   1437: 
                   1438:                    /* Everything looks good - copy it in! */
                   1439:                    base [*pix] = code;
                   1440:                    base [*pix + 1] = (unsigned char)incr;
                   1441:                    if (tto && incr == length) {
                   1442:                            if (incr > 1)
                   1443:                                memcpy (base + *pix + 2,
                   1444:                                        od.data + ix, (unsigned)(incr - 1));
                   1445:                            base [*pix + 2 + incr - 1] = 0;
                   1446:                    } else {
                   1447:                            memcpy (base + *pix + 2,
                   1448:                                    od.data + ix, (unsigned)incr);
                   1449:                    }
                   1450:                    length -= incr;
                   1451:                    ix += incr;
                   1452:                    *pix += 2 + incr;
                   1453:            }
                   1454:            data_string_forget (&od, MDL);
                   1455:        }
                   1456: 
                   1457:        if (option != NULL)
                   1458:            option_dereference(&option, MDL);
                   1459: 
                   1460:        /* If we can overload, and we have, then PAD and END those spaces. */
                   1461:        if (first_cutoff && six) {
                   1462:            if ((first_cutoff + six + 1) < sbufend)
                   1463:                memset (&buffer[first_cutoff + six + 1], DHO_PAD,
                   1464:                        sbufend - (first_cutoff + six + 1));
                   1465:            else if (first_cutoff + six >= sbufend)
                   1466:                log_fatal("Second buffer overflow in overloaded options.");
                   1467: 
                   1468:            buffer[first_cutoff + six] = DHO_END;
                   1469:            if (ocount != NULL)
                   1470:                *ocount |= 1; /* So that caller knows there's data there. */
                   1471:        }
                   1472: 
                   1473:        if (second_cutoff && tix) {
                   1474:            if (second_cutoff + tix + 1 < buflen) {
                   1475:                memset (&buffer[second_cutoff + tix + 1], DHO_PAD,
                   1476:                        buflen - (second_cutoff + tix + 1));
                   1477:            } else if (second_cutoff + tix >= buflen)
                   1478:                log_fatal("Third buffer overflow in overloaded options.");
                   1479: 
                   1480:            buffer[second_cutoff + tix] = DHO_END;
                   1481:            if (ocount != NULL)
                   1482:                *ocount |= 2; /* So that caller knows there's data there. */
                   1483:        }
                   1484: 
                   1485:        if ((six || tix) && (bufix + 3 > bufend))
                   1486:            log_fatal("Not enough space for option overload option.");
                   1487: 
                   1488:        return bufix;
                   1489: }
                   1490: 
                   1491: /* Return true if the format string has a variable length text option
                   1492:  * ("t"), return false otherwise.
                   1493:  */
                   1494: 
                   1495: int
                   1496: format_has_text(format)
                   1497:        const char *format;
                   1498: {
                   1499:        const char *p;
                   1500: 
                   1501:        p = format;
                   1502:        while (*p != '\0') {
                   1503:                switch (*p++) {
                   1504:                    case 'd':
                   1505:                    case 't':
                   1506:                        return 1;
                   1507: 
                   1508:                        /* These symbols are arbitrary, not fixed or
                   1509:                         * determinable length...text options with them is
                   1510:                         * invalid (whatever the case, they are never NULL
                   1511:                         * terminated).
                   1512:                         */
                   1513:                    case 'A':
                   1514:                    case 'a':
                   1515:                    case 'X':
                   1516:                    case 'x':
                   1517:                    case 'D':
                   1518:                        return 0;
                   1519: 
                   1520:                    case 'c':
                   1521:                        /* 'c' only follows 'D' atoms, and indicates that
                   1522:                         * compression may be used.  If there was a 'D'
                   1523:                         * atom already, we would have returned.  So this
                   1524:                         * is an error, but continue looking for 't' anyway.
                   1525:                         */
                   1526:                        log_error("format_has_text(%s): 'c' atoms are illegal "
                   1527:                                  "except after 'D' atoms.", format);
                   1528:                        break;
                   1529: 
                   1530:                        /* 'E' is variable length, but not arbitrary...you
                   1531:                         * can find its length if you can find an END option.
                   1532:                         * N is (n)-byte in length but trails a name of a
                   1533:                         * space defining the enumeration values.  So treat
                   1534:                         * both the same - valid, fixed-length fields.
                   1535:                         */
                   1536:                    case 'E':
                   1537:                    case 'N':
                   1538:                        /* Consume the space name. */
                   1539:                        while ((*p != '\0') && (*p++ != '.'))
                   1540:                                ;
                   1541:                        break;
                   1542: 
                   1543:                    default:
                   1544:                        break;
                   1545:                }
                   1546:        }
                   1547: 
                   1548:        return 0;
                   1549: }
                   1550: 
                   1551: /* Determine the minimum length of a DHCP option prior to any variable
                   1552:  * or inconsistent length formats, according to its configured format
                   1553:  * variable (and possibly from supplied option cache contents for variable
                   1554:  * length format symbols).
                   1555:  */
                   1556: 
                   1557: int
                   1558: format_min_length(format, oc)
                   1559:        const char *format;
                   1560:        struct option_cache *oc;
                   1561: {
                   1562:        const char *p, *name;
                   1563:        int min_len = 0;
                   1564:        int last_size = 0;
                   1565:        struct enumeration *espace;
                   1566: 
                   1567:        p = format;
                   1568:        while (*p != '\0') {
                   1569:                switch (*p++) {
                   1570:                    case '6': /* IPv6 Address */
                   1571:                        min_len += 16;
                   1572:                        last_size = 16;
                   1573:                        break;
                   1574: 
                   1575:                    case 'I': /* IPv4 Address */
                   1576:                    case 'l': /* int32_t */
                   1577:                    case 'L': /* uint32_t */
                   1578:                    case 'T': /* Lease Time, uint32_t equivalent */
                   1579:                        min_len += 4;
                   1580:                        last_size = 4;
                   1581:                        break;
                   1582: 
                   1583:                    case 's': /* int16_t */
                   1584:                    case 'S': /* uint16_t */
                   1585:                        min_len += 2;
                   1586:                        last_size = 2;
                   1587:                        break;
                   1588: 
                   1589:                    case 'N': /* Enumeration value. */
                   1590:                        /* Consume space name. */
                   1591:                        name = p;
                   1592:                        p = strchr(p, '.');
                   1593:                        if (p == NULL)
                   1594:                                log_fatal("Corrupt format: %s", format);
                   1595: 
                   1596:                        espace = find_enumeration(name, p - name);
                   1597:                        if (espace == NULL) {
                   1598:                                log_error("Unknown enumeration: %s", format);
                   1599:                                /* Max is safest value to return. */
                   1600:                                return INT_MAX;
                   1601:                        }
                   1602: 
                   1603:                        min_len += espace->width;
                   1604:                        last_size = espace->width;
                   1605:                        p++;
                   1606: 
                   1607:                        break;
                   1608: 
                   1609:                    case 'b': /* int8_t */
                   1610:                    case 'B': /* uint8_t */
                   1611:                    case 'F': /* Flag that is always true. */
                   1612:                    case 'f': /* Flag */
                   1613:                        min_len++;
                   1614:                        last_size = 1;
                   1615:                        break;
                   1616: 
                   1617:                    case 'o': /* Last argument is optional. */
                   1618:                        min_len -= last_size;
                   1619: 
                   1620:                    /* XXX: It MAY be possible to sense the end of an
                   1621:                     * encapsulated space, but right now this is too
                   1622:                     * hard to support.  Return a safe value.
                   1623:                     */
                   1624:                    case 'e': /* Encapsulation hint (there is an 'E' later). */
                   1625:                    case 'E': /* Encapsulated options. */
                   1626:                        return min_len;
                   1627: 
                   1628:                    case 'd': /* "Domain name" */
                   1629:                    case 'D': /* "rfc1035 formatted names" */
                   1630:                    case 't': /* "ASCII Text" */
                   1631:                    case 'X': /* "ASCII or Hex Conditional */
                   1632:                    case 'x': /* "Hex" */
                   1633:                    case 'A': /* Array of all that precedes. */
                   1634:                    case 'a': /* Array of preceding symbol. */
                   1635:                    case 'Z': /* nothing. */
                   1636:                        return min_len;
                   1637: 
                   1638:                    case 'c': /* Compress flag for D atom. */
                   1639:                        log_error("format_min_length(%s): 'c' atom is illegal "
                   1640:                                  "except after 'D' atom.", format);
                   1641:                        return INT_MAX;
                   1642: 
                   1643:                    default:
                   1644:                        /* No safe value is known. */
                   1645:                        log_error("format_min_length(%s): No safe value "
                   1646:                                  "for unknown format symbols.", format);
                   1647:                        return INT_MAX;
                   1648:                }
                   1649:        }
                   1650: 
                   1651:        return min_len;
                   1652: }
                   1653: 
                   1654: 
                   1655: /* Format the specified option so that a human can easily read it. */
                   1656: 
                   1657: const char *pretty_print_option (option, data, len, emit_commas, emit_quotes)
                   1658:        struct option *option;
                   1659:        const unsigned char *data;
                   1660:        unsigned len;
                   1661:        int emit_commas;
                   1662:        int emit_quotes;
                   1663: {
                   1664:        static char optbuf [32768]; /* XXX */
                   1665:        static char *endbuf = &optbuf[sizeof(optbuf)];
                   1666:        int hunksize = 0;
                   1667:        int opthunk = 0;
                   1668:        int hunkinc = 0;
                   1669:        int numhunk = -1;
                   1670:        int numelem = 0;
                   1671:        int count;
                   1672:        int i, j, k, l;
                   1673:        char fmtbuf[32] = "";
                   1674:        struct iaddr iaddr;
                   1675:        struct enumeration *enumbuf[32]; /* MUST be same as fmtbuf */
                   1676:        char *op = optbuf;
                   1677:        const unsigned char *dp = data;
                   1678:        char comma;
                   1679:        unsigned long tval;
1.1.1.1 ! misho    1680:        isc_boolean_t a_array = ISC_FALSE;
        !          1681:        int len_used;
1.1       misho    1682: 
                   1683:        if (emit_commas)
                   1684:                comma = ',';
                   1685:        else
                   1686:                comma = ' ';
                   1687: 
                   1688:        memset (enumbuf, 0, sizeof enumbuf);
                   1689: 
                   1690:        /* Figure out the size of the data. */
                   1691:        for (l = i = 0; option -> format [i]; i++, l++) {
                   1692:                if (l >= sizeof(fmtbuf) - 1)
                   1693:                        log_fatal("Bounds failure on internal buffer at "
                   1694:                                  "%s:%d", MDL);
                   1695: 
                   1696:                if (!numhunk) {
                   1697:                        log_error ("%s: Extra codes in format string: %s",
                   1698:                                   option -> name,
                   1699:                                   &(option -> format [i]));
                   1700:                        break;
                   1701:                }
                   1702:                numelem++;
                   1703:                fmtbuf [l] = option -> format [i];
                   1704:                switch (option -> format [i]) {
                   1705:                      case 'a':
1.1.1.1 ! misho    1706:                        a_array = ISC_TRUE;
        !          1707:                        /* Fall through */
1.1       misho    1708:                      case 'A':
                   1709:                        --numelem;
                   1710:                        fmtbuf [l] = 0;
                   1711:                        numhunk = 0;
                   1712:                        break;
                   1713:                      case 'E':
                   1714:                        /* Skip the universe name. */
                   1715:                        while (option -> format [i] &&
                   1716:                               option -> format [i] != '.')
                   1717:                                i++;
                   1718:                        /* Fall Through! */
                   1719:                      case 'X':
                   1720:                        for (k = 0; k < len; k++) {
                   1721:                                if (!isascii (data [k]) ||
                   1722:                                    !isprint (data [k]))
                   1723:                                        break;
                   1724:                        }
                   1725:                        /* If we found no bogus characters, or the bogus
                   1726:                           character we found is a trailing NUL, it's
                   1727:                           okay to print this option as text. */
                   1728:                        if (k == len || (k + 1 == len && data [k] == 0)) {
                   1729:                                fmtbuf [l] = 't';
                   1730:                                numhunk = -2;
                   1731:                        } else {
                   1732:                                fmtbuf [l] = 'x';
                   1733:                                hunksize++;
                   1734:                                comma = ':';
                   1735:                                numhunk = 0;
1.1.1.1 ! misho    1736:                                a_array = ISC_TRUE;
        !          1737:                                hunkinc = 1;
1.1       misho    1738:                        }
                   1739:                        fmtbuf [l + 1] = 0;
                   1740:                        break;
                   1741:                      case 'c':
                   1742:                        /* The 'c' atom is a 'D' modifier only. */
                   1743:                        log_error("'c' atom not following D atom in format "
                   1744:                                  "string: %s", option->format);
                   1745:                        break;
                   1746:                      case 'D':
                   1747:                        /*
                   1748:                         * Skip the 'c' atom, if present.  It does not affect
                   1749:                         * how we convert wire->text format (if compression is
                   1750:                         * present either way, we still process it).
                   1751:                         */
                   1752:                        if (option->format[i+1] == 'c')
                   1753:                                i++;
                   1754:                        fmtbuf[l + 1] = 0;
                   1755:                        numhunk = -2;
                   1756:                        break;
                   1757:                      case 'd':
                   1758:                        fmtbuf[l] = 't';
                   1759:                        /* Fall Through ! */
                   1760:                      case 't':
                   1761:                        fmtbuf[l + 1] = 0;
                   1762:                        numhunk = -2;
                   1763:                        break;
                   1764:                      case 'N':
                   1765:                        k = i;
                   1766:                        while (option -> format [i] &&
                   1767:                               option -> format [i] != '.')
                   1768:                                i++;
                   1769:                        enumbuf [l] =
                   1770:                                find_enumeration (&option -> format [k] + 1,
                   1771:                                                  i - k - 1);
                   1772:                        if (enumbuf[l] == NULL) {
                   1773:                                hunksize += 1;
                   1774:                                hunkinc = 1;
                   1775:                        } else {
                   1776:                                hunksize += enumbuf[l]->width;
                   1777:                                hunkinc = enumbuf[l]->width;
                   1778:                        }
                   1779:                        break;
                   1780:                      case '6':
                   1781:                        hunksize += 16;
                   1782:                        hunkinc = 16;
                   1783:                        break;
                   1784:                      case 'I':
                   1785:                      case 'l':
                   1786:                      case 'L':
                   1787:                      case 'T':
                   1788:                        hunksize += 4;
                   1789:                        hunkinc = 4;
                   1790:                        break;
                   1791:                      case 's':
                   1792:                      case 'S':
                   1793:                        hunksize += 2;
                   1794:                        hunkinc = 2;
                   1795:                        break;
                   1796:                      case 'b':
                   1797:                      case 'B':
                   1798:                      case 'f':
                   1799:                      case 'F':
                   1800:                        hunksize++;
                   1801:                        hunkinc = 1;
                   1802:                        break;
                   1803:                      case 'e':
                   1804:                      case 'Z':
                   1805:                        break;
                   1806:                      case 'o':
                   1807:                        opthunk += hunkinc;
                   1808:                        break;
                   1809:                      default:
                   1810:                        log_error ("%s: garbage in format string: %s",
                   1811:                              option -> name,
                   1812:                              &(option -> format [i]));
                   1813:                        break;
                   1814:                } 
                   1815:        }
                   1816: 
                   1817:        /* Check for too few bytes... */
                   1818:        if (hunksize - opthunk > len) {
                   1819:                log_error ("%s: expecting at least %d bytes; got %d",
                   1820:                      option -> name,
                   1821:                      hunksize, len);
                   1822:                return "<error>";
                   1823:        }
                   1824:        /* Check for too many bytes... */
                   1825:        if (numhunk == -1 && hunksize < len)
                   1826:                log_error ("%s: %d extra bytes",
                   1827:                      option -> name,
                   1828:                      len - hunksize);
                   1829: 
                   1830:        /* If this is an array, compute its size. */
1.1.1.1 ! misho    1831:        if (numhunk == 0) {
        !          1832:                if (a_array == ISC_TRUE) {
        !          1833:                        /*
        !          1834:                         * It is an 'a' type array - we repeat the
        !          1835:                         * last format type.  A binary string for 'X'
        !          1836:                         * is also like this.  hunkinc is the size
        !          1837:                         * of the last format type and we add 1 to
        !          1838:                         * cover the entire first record.
        !          1839:                         */
        !          1840:                        numhunk = ((len - hunksize) / hunkinc) + 1;
        !          1841:                        len_used = hunksize + ((numhunk - 1) * hunkinc);
        !          1842:                } else {
        !          1843:                        /*
        !          1844:                         * It is an 'A' type array - we repeat the
        !          1845:                         * entire record
        !          1846:                         */
        !          1847:                        numhunk = len / hunksize;
        !          1848:                        len_used = numhunk * hunksize;
        !          1849:                }
        !          1850: 
        !          1851:                /* See if we got an exact number of hunks. */
        !          1852:                if (len_used < len) {
        !          1853:                        log_error ("%s: %d extra bytes at end of array\n",
        !          1854:                                   option -> name,
        !          1855:                                   len - len_used);
        !          1856:                }
        !          1857:        }
        !          1858: 
1.1       misho    1859: 
                   1860:        /* A one-hunk array prints the same as a single hunk. */
                   1861:        if (numhunk < 0)
                   1862:                numhunk = 1;
                   1863: 
                   1864:        /* Cycle through the array (or hunk) printing the data. */
                   1865:        for (i = 0; i < numhunk; i++) {
1.1.1.1 ! misho    1866:                if ((a_array == ISC_TRUE) && (i != 0) && (numelem > 0)) {
        !          1867:                        /*
        !          1868:                         * For 'a' type of arrays we repeat
        !          1869:                         * only the last format character
        !          1870:                         * We should never hit the case of numelem == 0
        !          1871:                         * but let's include the check to be safe.
        !          1872:                         */
        !          1873:                        j = numelem - 1;
        !          1874:                } else {
        !          1875:                        /*
        !          1876:                         * for other types of arrays or the first
        !          1877:                         * time through for 'a' types, we go through
        !          1878:                         * the entire set of format characters.
        !          1879:                         */
        !          1880:                        j = 0;
        !          1881:                }
        !          1882: 
        !          1883:                for (; j < numelem; j++) {
1.1       misho    1884:                        switch (fmtbuf [j]) {
                   1885:                              case 't':
                   1886:                                /* endbuf-1 leaves room for NULL. */
                   1887:                                k = pretty_text(&op, endbuf - 1, &dp,
                   1888:                                                data + len, emit_quotes);
                   1889:                                if (k == -1) {
                   1890:                                        log_error("Error printing text.");
                   1891:                                        break;
                   1892:                                }
                   1893:                                *op = 0;
                   1894:                                break;
                   1895:                              case 'D': /* RFC1035 format name list */
                   1896:                                for( ; dp < (data + len) ; dp += k) {
                   1897:                                        unsigned char nbuff[NS_MAXCDNAME];
                   1898:                                        const unsigned char *nbp, *nend;
                   1899: 
                   1900:                                        nend = &nbuff[sizeof(nbuff)];
                   1901: 
                   1902:                                        /* If this is for ISC DHCP consumption
                   1903:                                         * (emit_quotes), lay it out as a list
                   1904:                                         * of STRING tokens.  Otherwise, it is
                   1905:                                         * a space-separated list of DNS-
                   1906:                                         * escaped names as /etc/resolv.conf
                   1907:                                         * might digest.
                   1908:                                         */
                   1909:                                        if (dp != data) {
                   1910:                                                if (op + 2 > endbuf)
                   1911:                                                        break;
                   1912: 
                   1913:                                                if (emit_quotes)
                   1914:                                                        *op++ = ',';
                   1915:                                                *op++ = ' ';
                   1916:                                        }
                   1917: 
                   1918:                                        /* XXX: if fmtbuf[j+1] != 'c', we
                   1919:                                         * should warn if the data was
                   1920:                                         * compressed anyway.
                   1921:                                         */
                   1922:                                        k = MRns_name_unpack(data,
                   1923:                                                             data + len,
                   1924:                                                             dp, nbuff,
                   1925:                                                             sizeof(nbuff));
                   1926: 
                   1927:                                        if (k == -1) {
                   1928:                                                log_error("Invalid domain "
                   1929:                                                          "list.");
                   1930:                                                break;
                   1931:                                        }
                   1932: 
                   1933:                                        /* If emit_quotes, then use ISC DHCP
                   1934:                                         * escapes.  Otherwise, rely only on
                   1935:                                         * ns_name_ntop().
                   1936:                                         */
                   1937:                                        if (emit_quotes) {
                   1938:                                                nbp = nbuff;
                   1939:                                                pretty_domain(&op, endbuf-1,
                   1940:                                                              &nbp, nend);
                   1941:                                        } else {
                   1942:                                                /* ns_name_ntop() includes
                   1943:                                                 * a trailing NUL in its
                   1944:                                                 * count.
                   1945:                                                 */
                   1946:                                                count = MRns_name_ntop(
                   1947:                                                                nbuff, op, 
                   1948:                                                                (endbuf-op)-1);
                   1949: 
                   1950:                                                if (count <= 0) {
                   1951:                                                        log_error("Invalid "
                   1952:                                                                "domain name.");
                   1953:                                                        break;
                   1954:                                                }
                   1955: 
                   1956:                                                /* Consume all but the trailing
                   1957:                                                 * NUL.
                   1958:                                                 */
                   1959:                                                op += count - 1;
                   1960: 
                   1961:                                                /* Replace the trailing NUL
                   1962:                                                 * with the implicit root
                   1963:                                                 * (in the unlikely event the
                   1964:                                                 * domain name /is/ the root).
                   1965:                                                 */
                   1966:                                                *op++ = '.';
                   1967:                                        }
                   1968:                                }
                   1969:                                *op = '\0';
                   1970:                                break;
                   1971:                                /* pretty-printing an array of enums is
                   1972:                                   going to get ugly. */
                   1973:                              case 'N':
                   1974:                                if (!enumbuf [j]) {
                   1975:                                        tval = *dp++;
                   1976:                                        goto enum_as_num;
                   1977:                                }
                   1978: 
                   1979:                                switch (enumbuf[j]->width) {
                   1980:                                      case 1:
                   1981:                                        tval = getUChar(dp);
                   1982:                                        break;
                   1983: 
                   1984:                                     case 2:
                   1985:                                        tval = getUShort(dp);
                   1986:                                        break;
                   1987: 
                   1988:                                    case 4:
                   1989:                                        tval = getULong(dp);
                   1990:                                        break;
                   1991: 
                   1992:                                    default:
                   1993:                                        log_fatal("Impossible case at %s:%d.",
                   1994:                                                  MDL);
                   1995:                                        return "<double impossible condition>";
                   1996:                                }
                   1997: 
                   1998:                                for (i = 0; ;i++) {
                   1999:                                        if (!enumbuf [j] -> values [i].name)
                   2000:                                                goto enum_as_num;
                   2001:                                        if (enumbuf [j] -> values [i].value ==
                   2002:                                            tval)
                   2003:                                                break;
                   2004:                                }
                   2005:                                strcpy (op, enumbuf [j] -> values [i].name);
                   2006:                                dp += enumbuf[j]->width;
                   2007:                                break;
                   2008: 
                   2009:                              enum_as_num:
                   2010:                                sprintf(op, "%lu", tval);
                   2011:                                break;
                   2012: 
                   2013:                              case 'I':
                   2014:                                iaddr.len = 4;
                   2015:                                memcpy(iaddr.iabuf, dp, 4);
                   2016:                                strcpy(op, piaddr(iaddr));
                   2017:                                dp += 4;
                   2018:                                break;
                   2019:                              case '6':
                   2020:                                iaddr.len = 16;
                   2021:                                memcpy(iaddr.iabuf, dp, 16);
                   2022:                                strcpy(op, piaddr(iaddr));
                   2023:                                dp += 16;
                   2024:                                break;
                   2025:                              case 'l':
                   2026:                                sprintf (op, "%ld", (long)getLong (dp));
                   2027:                                dp += 4;
                   2028:                                break;
                   2029:                              case 'T':
                   2030:                                tval = getULong (dp);
                   2031:                                if (tval == -1)
                   2032:                                        sprintf (op, "%s", "infinite");
                   2033:                                else
                   2034:                                        sprintf(op, "%lu", tval);
                   2035:                                break;
                   2036:                              case 'L':
                   2037:                                sprintf(op, "%lu",
                   2038:                                        (unsigned long)getULong(dp));
                   2039:                                dp += 4;
                   2040:                                break;
                   2041:                              case 's':
                   2042:                                sprintf (op, "%d", (int)getShort (dp));
                   2043:                                dp += 2;
                   2044:                                break;
                   2045:                              case 'S':
                   2046:                                sprintf(op, "%u", (unsigned)getUShort(dp));
                   2047:                                dp += 2;
                   2048:                                break;
                   2049:                              case 'b':
                   2050:                                sprintf (op, "%d", *(const char *)dp++);
                   2051:                                break;
                   2052:                              case 'B':
                   2053:                                sprintf (op, "%d", *dp++);
                   2054:                                break;
                   2055:                              case 'X':
                   2056:                              case 'x':
                   2057:                                sprintf (op, "%x", *dp++);
                   2058:                                break;
                   2059:                              case 'f':
                   2060:                                strcpy (op, *dp++ ? "true" : "false");
                   2061:                                break;
                   2062:                              case 'F':
                   2063:                                strcpy (op, "true");
                   2064:                                break;
                   2065:                              case 'e':
                   2066:                              case 'Z':
                   2067:                                *op = '\0';
                   2068:                                break;
                   2069:                              default:
                   2070:                                log_error ("Unexpected format code %c",
                   2071:                                           fmtbuf [j]);
                   2072:                        }
                   2073:                        op += strlen (op);
                   2074:                        if (dp == data + len)
                   2075:                                break;
                   2076:                        if (j + 1 < numelem && comma != ':')
                   2077:                                *op++ = ' ';
                   2078:                }
                   2079:                if (i + 1 < numhunk) {
                   2080:                        *op++ = comma;
                   2081:                }
                   2082:                if (dp == data + len)
                   2083:                        break;
                   2084:        }
                   2085:        return optbuf;
                   2086: }
                   2087: 
                   2088: int get_option (result, universe, packet, lease, client_state,
                   2089:                in_options, cfg_options, options, scope, code, file, line)
                   2090:        struct data_string *result;
                   2091:        struct universe *universe;
                   2092:        struct packet *packet;
                   2093:        struct lease *lease;
                   2094:        struct client_state *client_state;
                   2095:        struct option_state *in_options;
                   2096:        struct option_state *cfg_options;
                   2097:        struct option_state *options;
                   2098:        struct binding_scope **scope;
                   2099:        unsigned code;
                   2100:        const char *file;
                   2101:        int line;
                   2102: {
                   2103:        struct option_cache *oc;
                   2104: 
                   2105:        if (!universe -> lookup_func)
                   2106:                return 0;
                   2107:        oc = ((*universe -> lookup_func) (universe, options, code));
                   2108:        if (!oc)
                   2109:                return 0;
                   2110:        if (!evaluate_option_cache (result, packet, lease, client_state,
                   2111:                                    in_options, cfg_options, scope, oc,
                   2112:                                    file, line))
                   2113:                return 0;
                   2114:        return 1;
                   2115: }
                   2116: 
                   2117: void set_option (universe, options, option, op)
                   2118:        struct universe *universe;
                   2119:        struct option_state *options;
                   2120:        struct option_cache *option;
                   2121:        enum statement_op op;
                   2122: {
                   2123:        struct option_cache *oc, *noc;
                   2124: 
                   2125:        switch (op) {
                   2126:              case if_statement:
                   2127:              case add_statement:
                   2128:              case eval_statement:
                   2129:              case break_statement:
                   2130:              default:
                   2131:                log_error ("bogus statement type in set_option.");
                   2132:                break;
                   2133: 
                   2134:              case default_option_statement:
                   2135:                oc = lookup_option (universe, options,
                   2136:                                    option -> option -> code);
                   2137:                if (oc)
                   2138:                        break;
                   2139:                save_option (universe, options, option);
                   2140:                break;
                   2141: 
                   2142:              case supersede_option_statement:
                   2143:              case send_option_statement:
                   2144:                /* Install the option, replacing any existing version. */
                   2145:                save_option (universe, options, option);
                   2146:                break;
                   2147: 
                   2148:              case append_option_statement:
                   2149:              case prepend_option_statement:
                   2150:                oc = lookup_option (universe, options,
                   2151:                                    option -> option -> code);
                   2152:                if (!oc) {
                   2153:                        save_option (universe, options, option);
                   2154:                        break;
                   2155:                }
                   2156:                /* If it's not an expression, make it into one. */
                   2157:                if (!oc -> expression && oc -> data.len) {
                   2158:                        if (!expression_allocate (&oc -> expression, MDL)) {
                   2159:                                log_error ("Can't allocate const expression.");
                   2160:                                break;
                   2161:                        }
                   2162:                        oc -> expression -> op = expr_const_data;
                   2163:                        data_string_copy
                   2164:                                (&oc -> expression -> data.const_data,
                   2165:                                 &oc -> data, MDL);
                   2166:                        data_string_forget (&oc -> data, MDL);
                   2167:                }
                   2168:                noc = (struct option_cache *)0;
                   2169:                if (!option_cache_allocate (&noc, MDL))
                   2170:                        break;
                   2171:                if (op == append_option_statement) {
                   2172:                        if (!make_concat (&noc -> expression,
                   2173:                                          oc -> expression,
                   2174:                                          option -> expression)) {
                   2175:                                option_cache_dereference (&noc, MDL);
                   2176:                                break;
                   2177:                        }
                   2178:                } else {
                   2179:                        if (!make_concat (&noc -> expression,
                   2180:                                          option -> expression,
                   2181:                                          oc -> expression)) {
                   2182:                                option_cache_dereference (&noc, MDL);
                   2183:                                break;
                   2184:                        }
                   2185:                }
                   2186:                option_reference(&(noc->option), oc->option, MDL);
                   2187:                save_option (universe, options, noc);
                   2188:                option_cache_dereference (&noc, MDL);
                   2189:                break;
                   2190:        }
                   2191: }
                   2192: 
                   2193: struct option_cache *lookup_option (universe, options, code)
                   2194:        struct universe *universe;
                   2195:        struct option_state *options;
                   2196:        unsigned code;
                   2197: {
                   2198:        if (!options)
                   2199:                return (struct option_cache *)0;
                   2200:        if (universe -> lookup_func)
                   2201:                return (*universe -> lookup_func) (universe, options, code);
                   2202:        else
                   2203:                log_error ("can't look up options in %s space.",
                   2204:                           universe -> name);
                   2205:        return (struct option_cache *)0;
                   2206: }
                   2207: 
                   2208: struct option_cache *lookup_hashed_option (universe, options, code)
                   2209:        struct universe *universe;
                   2210:        struct option_state *options;
                   2211:        unsigned code;
                   2212: {
                   2213:        int hashix;
                   2214:        pair bptr;
                   2215:        pair *hash;
                   2216: 
                   2217:        /* Make sure there's a hash table. */
                   2218:        if (universe -> index >= options -> universe_count ||
                   2219:            !(options -> universes [universe -> index]))
                   2220:                return (struct option_cache *)0;
                   2221: 
                   2222:        hash = options -> universes [universe -> index];
                   2223: 
                   2224:        hashix = compute_option_hash (code);
                   2225:        for (bptr = hash [hashix]; bptr; bptr = bptr -> cdr) {
                   2226:                if (((struct option_cache *)(bptr -> car)) -> option -> code ==
                   2227:                    code)
                   2228:                        return (struct option_cache *)(bptr -> car);
                   2229:        }
                   2230:        return (struct option_cache *)0;
                   2231: }
                   2232: 
                   2233: /* Save a specified buffer into an option cache. */
                   2234: int
                   2235: save_option_buffer(struct universe *universe, struct option_state *options,
                   2236:                   struct buffer *bp, unsigned char *buffer, unsigned length,
                   2237:                   unsigned code, int terminatep)
                   2238: {
                   2239:        struct option_cache *op = NULL;
                   2240:        int status = 1;
                   2241: 
                   2242:        status = prepare_option_buffer(universe, bp, buffer, length, code,
                   2243:                                       terminatep, &op);
                   2244: 
                   2245:        if (status == 0)
                   2246:                goto cleanup;
                   2247: 
                   2248:        save_option(universe, options, op);
                   2249: 
                   2250:     cleanup:
                   2251:        if (op != NULL)
                   2252:                option_cache_dereference(&op, MDL);
                   2253: 
                   2254:        return status;
                   2255: }
                   2256: 
                   2257: /* Append a specified buffer onto the tail of an option cache. */
                   2258: int
                   2259: append_option_buffer(struct universe *universe, struct option_state *options,
                   2260:                     struct buffer *bp, unsigned char *buffer, unsigned length,
                   2261:                     unsigned code, int terminatep)
                   2262: {
                   2263:        struct option_cache *op = NULL;
                   2264:        int status = 1;
                   2265: 
                   2266:        status = prepare_option_buffer(universe, bp, buffer, length, code,
                   2267:                                       terminatep, &op);
                   2268: 
                   2269:        if (status == 0)
                   2270:                goto cleanup;
                   2271: 
                   2272:        also_save_option(universe, options, op);
                   2273: 
                   2274:       cleanup:
                   2275:        if (op != NULL)
                   2276:                option_cache_dereference(&op, MDL);
                   2277: 
                   2278:        return status;
                   2279: }
                   2280: 
                   2281: /* Create/copy a buffer into a new option cache. */
                   2282: static int
                   2283: prepare_option_buffer(struct universe *universe, struct buffer *bp,
                   2284:                      unsigned char *buffer, unsigned length, unsigned code,
                   2285:                      int terminatep, struct option_cache **opp)
                   2286: {
                   2287:        struct buffer *lbp = NULL;
                   2288:        struct option *option = NULL;
                   2289:        struct option_cache *op;
                   2290:        int status = 1;
                   2291: 
                   2292:        /* Code sizes of 8, 16, and 32 bits are allowed. */
                   2293:        switch(universe->tag_size) {
                   2294:              case 1:
                   2295:                if (code > 0xff)
                   2296:                        return 0;
                   2297:                break;
                   2298:              case 2:
                   2299:                if (code > 0xffff)
                   2300:                        return 0;
                   2301:                break;
                   2302:              case 4:
                   2303:                if (code > 0xffffffff)
                   2304:                        return 0;
                   2305:                break;
                   2306: 
                   2307:              default:
                   2308:                log_fatal("Inconsistent universe tag size at %s:%d.", MDL);
                   2309:        }
                   2310: 
                   2311:        option_code_hash_lookup(&option, universe->code_hash, &code, 0, MDL);
                   2312: 
                   2313:        /* If we created an option structure for each option a client
                   2314:         * supplied, it's possible we may create > 2^32 option structures.
                   2315:         * That's not feasible.  So by failing to enter these option
                   2316:         * structures into the code and name hash tables, references will
                   2317:         * never be more than 1 - when the option cache is destroyed, this
                   2318:         * will be cleaned up.
                   2319:         */
                   2320:        if (!option) {
                   2321:                char nbuf[sizeof("unknown-4294967295")];
                   2322: 
                   2323:                sprintf(nbuf, "unknown-%u", code);
                   2324: 
                   2325:                option = new_option(nbuf, MDL);
                   2326: 
                   2327:                if (!option)
                   2328:                        return 0;
                   2329: 
                   2330:                option->format = default_option_format;
                   2331:                option->universe = universe;
                   2332:                option->code = code;
                   2333: 
                   2334:                /* new_option() doesn't set references, pretend. */
                   2335:                option->refcnt = 1;
                   2336:        }
                   2337: 
                   2338:        if (!option_cache_allocate (opp, MDL)) {
                   2339:                log_error("No memory for option code %s.%s.",
                   2340:                          universe->name, option->name);
                   2341:                status = 0;
                   2342:                goto cleanup;
                   2343:        }
                   2344: 
                   2345:        /* Pointer rather than double pointer makes for less parens. */
                   2346:        op = *opp;
                   2347: 
                   2348:        option_reference(&op->option, option, MDL);
                   2349: 
                   2350:        /* If we weren't passed a buffer in which the data are saved and
                   2351:           refcounted, allocate one now. */
                   2352:        if (!bp) {
                   2353:                if (!buffer_allocate (&lbp, length + terminatep, MDL)) {
                   2354:                        log_error ("no memory for option buffer.");
                   2355: 
                   2356:                        status = 0;
                   2357:                        goto cleanup;
                   2358:                }
                   2359:                memcpy (lbp -> data, buffer, length + terminatep);
                   2360:                bp = lbp;
                   2361:                buffer = &bp -> data [0]; /* Refer to saved buffer. */
                   2362:        }
                   2363: 
                   2364:        /* Reference buffer copy to option cache. */
                   2365:        op -> data.buffer = (struct buffer *)0;
                   2366:        buffer_reference (&op -> data.buffer, bp, MDL);
                   2367: 
                   2368:        /* Point option cache into buffer. */
                   2369:        op -> data.data = buffer;
                   2370:        op -> data.len = length;
                   2371: 
                   2372:        if (terminatep) {
                   2373:                /* NUL terminate (we can get away with this because we (or
                   2374:                   the caller!) allocated one more than the buffer size, and
                   2375:                   because the byte following the end of an option is always
                   2376:                   the code of the next option, which the caller is getting
                   2377:                   out of the *original* buffer. */
                   2378:                buffer [length] = 0;
                   2379:                op -> data.terminated = 1;
                   2380:        } else
                   2381:                op -> data.terminated = 0;
                   2382: 
                   2383:        /* If this option is ultimately a text option, null determinate to
                   2384:         * comply with RFC2132 section 2.  Mark a flag so this can be sensed
                   2385:         * later to echo NULLs back to clients that supplied them (they
                   2386:         * probably expect them).
                   2387:         */
                   2388:        if (format_has_text(option->format)) {
                   2389:                int min_len = format_min_length(option->format, op);
                   2390: 
                   2391:                while ((op->data.len > min_len) &&
                   2392:                       (op->data.data[op->data.len-1] == '\0')) {
                   2393:                        op->data.len--;
                   2394:                        op->flags |= OPTION_HAD_NULLS;
                   2395:                }
                   2396:        }
                   2397: 
                   2398:        /* And let go of our references. */
                   2399:       cleanup:
1.1.1.1 ! misho    2400:        if (lbp != NULL)
        !          2401:                buffer_dereference(&lbp, MDL);
1.1       misho    2402:        option_dereference(&option, MDL);
                   2403: 
1.1.1.1 ! misho    2404:        return status;
1.1       misho    2405: }
                   2406: 
                   2407: static void
                   2408: count_options(struct option_cache *dummy_oc,
                   2409:              struct packet *dummy_packet,
                   2410:              struct lease *dummy_lease, 
                   2411:              struct client_state *dummy_client_state,
                   2412:              struct option_state *dummy_opt_state,
                   2413:              struct option_state *opt_state,
                   2414:              struct binding_scope **dummy_binding_scope,
                   2415:              struct universe *dummy_universe, 
                   2416:              void *void_accumulator) {
                   2417:        int *accumulator = (int *)void_accumulator;
                   2418: 
                   2419:        *accumulator += 1;
                   2420: }
                   2421: 
                   2422: static void
                   2423: collect_oro(struct option_cache *oc,
                   2424:            struct packet *dummy_packet,
                   2425:            struct lease *dummy_lease, 
                   2426:            struct client_state *dummy_client_state,
                   2427:            struct option_state *dummy_opt_state,
                   2428:            struct option_state *opt_state,
                   2429:            struct binding_scope **dummy_binding_scope,
                   2430:            struct universe *dummy_universe, 
                   2431:            void *void_oro) {
                   2432:        struct data_string *oro = (struct data_string *)void_oro;
                   2433: 
                   2434:        putUShort(oro->buffer->data + oro->len, oc->option->code);
                   2435:        oro->len += 2;
                   2436: }
                   2437: 
                   2438: /* build_server_oro() is presently unusued, but may be used at a future date
                   2439:  * with support for Reconfigure messages (as a hint to the client about new
                   2440:  * option value contents).
                   2441:  */
                   2442: void
                   2443: build_server_oro(struct data_string *server_oro, 
                   2444:                 struct option_state *options,
                   2445:                 const char *file, int line) {
                   2446:        int num_opts;
                   2447:        int i;
                   2448:        struct option *o;
                   2449: 
                   2450:        /*
                   2451:         * Count the number of options, so we can allocate enough memory.
                   2452:         * We want to mention sub-options too, so check all universes.
                   2453:         */
                   2454:        num_opts = 0;
                   2455:        option_space_foreach(NULL, NULL, NULL, NULL, options,
                   2456:                             NULL, &dhcpv6_universe, (void *)&num_opts,
                   2457:                             count_options);
                   2458:        for (i=0; i < options->universe_count; i++) {
                   2459:                if (options->universes[i] != NULL) {
                   2460:                        o = universes[i]->enc_opt;
                   2461:                        while (o != NULL) {
                   2462:                                if (o->universe == &dhcpv6_universe) {
                   2463:                                        num_opts++;
                   2464:                                        break;
                   2465:                                }
                   2466:                                o = o->universe->enc_opt;
                   2467:                        }
                   2468:                }
                   2469:        }
                   2470: 
                   2471:        /*
                   2472:         * Allocate space.
                   2473:         */
                   2474:        memset(server_oro, 0, sizeof(*server_oro));
                   2475:        if (!buffer_allocate(&server_oro->buffer, num_opts * 2, MDL)) {
                   2476:                log_fatal("no memory to build server ORO");
                   2477:        }
                   2478:        server_oro->data = server_oro->buffer->data;
                   2479: 
                   2480:        /*
                   2481:         * Copy the data in.
                   2482:         * We want to mention sub-options too, so check all universes.
                   2483:         */
                   2484:        server_oro->len = 0;    /* gets set in collect_oro */
                   2485:        option_space_foreach(NULL, NULL, NULL, NULL, options,
                   2486:                             NULL, &dhcpv6_universe, (void *)server_oro,
                   2487:                             collect_oro);
                   2488:        for (i=0; i < options->universe_count; i++) {
                   2489:                if (options->universes[i] != NULL) {
                   2490:                        o = universes[i]->enc_opt;
                   2491:                        while (o != NULL) {
                   2492:                                if (o->universe == &dhcpv6_universe) {
                   2493:                                        unsigned char *tmp;
                   2494:                                        tmp = server_oro->buffer->data;
                   2495:                                        putUShort(tmp + server_oro->len,
                   2496:                                                  o->code);
                   2497:                                        server_oro->len += 2;
                   2498:                                        break;
                   2499:                                }
                   2500:                                o = o->universe->enc_opt;
                   2501:                        }
                   2502:                }
                   2503:        }
                   2504: }
                   2505: 
                   2506: /* Wrapper function to put an option cache into an option state. */
                   2507: void
                   2508: save_option(struct universe *universe, struct option_state *options,
                   2509:            struct option_cache *oc)
                   2510: {
                   2511:        if (universe->save_func)
                   2512:                (*universe->save_func)(universe, options, oc, ISC_FALSE);
                   2513:        else
                   2514:                log_error("can't store options in %s space.", universe->name);
                   2515: }
                   2516: 
                   2517: /* Wrapper function to append an option cache into an option state's list. */
                   2518: void
                   2519: also_save_option(struct universe *universe, struct option_state *options,
                   2520:                 struct option_cache *oc)
                   2521: {
                   2522:        if (universe->save_func)
                   2523:                (*universe->save_func)(universe, options, oc, ISC_TRUE);
                   2524:        else
                   2525:                log_error("can't store options in %s space.", universe->name);
                   2526: }
                   2527: 
                   2528: void
                   2529: save_hashed_option(struct universe *universe, struct option_state *options,
                   2530:                   struct option_cache *oc, isc_boolean_t appendp)
                   2531: {
                   2532:        int hashix;
                   2533:        pair bptr;
                   2534:        pair *hash = options -> universes [universe -> index];
                   2535:        struct option_cache **ocloc;
                   2536: 
                   2537:        if (oc -> refcnt == 0)
                   2538:                abort ();
                   2539: 
                   2540:        /* Compute the hash. */
                   2541:        hashix = compute_option_hash (oc -> option -> code);
                   2542: 
                   2543:        /* If there's no hash table, make one. */
                   2544:        if (!hash) {
                   2545:                hash = (pair *)dmalloc (OPTION_HASH_SIZE * sizeof *hash, MDL);
                   2546:                if (!hash) {
                   2547:                        log_error ("no memory to store %s.%s",
                   2548:                                   universe -> name, oc -> option -> name);
                   2549:                        return;
                   2550:                }
                   2551:                memset (hash, 0, OPTION_HASH_SIZE * sizeof *hash);
                   2552:                options -> universes [universe -> index] = (void *)hash;
                   2553:        } else {
                   2554:                /* Try to find an existing option matching the new one. */
                   2555:                for (bptr = hash [hashix]; bptr; bptr = bptr -> cdr) {
                   2556:                        if (((struct option_cache *)
                   2557:                             (bptr -> car)) -> option -> code ==
                   2558:                            oc -> option -> code)
                   2559:                                break;
                   2560:                }
                   2561: 
                   2562:                /* Deal with collisions on the hash list. */
                   2563:                if (bptr) {
                   2564:                        ocloc = (struct option_cache **)&bptr->car;
                   2565: 
                   2566:                        /*
                   2567:                         * If appendp is set, append it onto the tail of the
                   2568:                         * ->next list.  If it is not set, rotate it into
                   2569:                         * position at the head of the list.
                   2570:                         */
                   2571:                        if (appendp) {
                   2572:                                do {
                   2573:                                        ocloc = &(*ocloc)->next;
                   2574:                                } while (*ocloc != NULL);
                   2575:                        } else {
                   2576:                                option_cache_dereference(ocloc, MDL);
                   2577:                        }
                   2578: 
                   2579:                        option_cache_reference(ocloc, oc, MDL);
                   2580:                        return;
                   2581:                }
                   2582:        }
                   2583: 
                   2584:        /* Otherwise, just put the new one at the head of the list. */
                   2585:        bptr = new_pair (MDL);
                   2586:        if (!bptr) {
                   2587:                log_error ("No memory for option_cache reference.");
                   2588:                return;
                   2589:        }
                   2590:        bptr -> cdr = hash [hashix];
                   2591:        bptr -> car = 0;
                   2592:        option_cache_reference ((struct option_cache **)&bptr -> car, oc, MDL);
                   2593:        hash [hashix] = bptr;
                   2594: }
                   2595: 
                   2596: void delete_option (universe, options, code)
                   2597:        struct universe *universe;
                   2598:        struct option_state *options;
                   2599:        int code;
                   2600: {
                   2601:        if (universe -> delete_func)
                   2602:                (*universe -> delete_func) (universe, options, code);
                   2603:        else
                   2604:                log_error ("can't delete options from %s space.",
                   2605:                           universe -> name);
                   2606: }
                   2607: 
                   2608: void delete_hashed_option (universe, options, code)
                   2609:        struct universe *universe;
                   2610:        struct option_state *options;
                   2611:        int code;
                   2612: {
                   2613:        int hashix;
                   2614:        pair bptr, prev = (pair)0;
                   2615:        pair *hash = options -> universes [universe -> index];
                   2616: 
                   2617:        /* There may not be any options in this space. */
                   2618:        if (!hash)
                   2619:                return;
                   2620: 
                   2621:        /* Try to find an existing option matching the new one. */
                   2622:        hashix = compute_option_hash (code);
                   2623:        for (bptr = hash [hashix]; bptr; bptr = bptr -> cdr) {
                   2624:                if (((struct option_cache *)(bptr -> car)) -> option -> code
                   2625:                    == code)
                   2626:                        break;
                   2627:                prev = bptr;
                   2628:        }
                   2629:        /* If we found one, wipe it out... */
                   2630:        if (bptr) {
                   2631:                if (prev)
                   2632:                        prev -> cdr = bptr -> cdr;
                   2633:                else
                   2634:                        hash [hashix] = bptr -> cdr;
                   2635:                option_cache_dereference
                   2636:                        ((struct option_cache **)(&bptr -> car), MDL);
                   2637:                free_pair (bptr, MDL);
                   2638:        }
                   2639: }
                   2640: 
                   2641: extern struct option_cache *free_option_caches; /* XXX */
                   2642: 
                   2643: int option_cache_dereference (ptr, file, line)
                   2644:        struct option_cache **ptr;
                   2645:        const char *file;
                   2646:        int line;
                   2647: {
                   2648:        if (!ptr || !*ptr) {
                   2649:                log_error ("Null pointer in option_cache_dereference: %s(%d)",
                   2650:                           file, line);
                   2651: #if defined (POINTER_DEBUG)
                   2652:                abort ();
                   2653: #else
                   2654:                return 0;
                   2655: #endif
                   2656:        }
                   2657: 
                   2658:        (*ptr) -> refcnt--;
                   2659:        rc_register (file, line, ptr, *ptr, (*ptr) -> refcnt, 1, RC_MISC);
                   2660:        if (!(*ptr) -> refcnt) {
                   2661:                if ((*ptr) -> data.buffer)
                   2662:                        data_string_forget (&(*ptr) -> data, file, line);
                   2663:                if ((*ptr)->option)
                   2664:                        option_dereference(&(*ptr)->option, MDL);
                   2665:                if ((*ptr) -> expression)
                   2666:                        expression_dereference (&(*ptr) -> expression,
                   2667:                                                file, line);
                   2668:                if ((*ptr) -> next)
                   2669:                        option_cache_dereference (&((*ptr) -> next),
                   2670:                                                  file, line);
                   2671:                /* Put it back on the free list... */
                   2672:                (*ptr) -> expression = (struct expression *)free_option_caches;
                   2673:                free_option_caches = *ptr;
                   2674:                dmalloc_reuse (free_option_caches, (char *)0, 0, 0);
                   2675:        }
                   2676:        if ((*ptr) -> refcnt < 0) {
                   2677:                log_error ("%s(%d): negative refcnt!", file, line);
                   2678: #if defined (DEBUG_RC_HISTORY)
                   2679:                dump_rc_history (*ptr);
                   2680: #endif
                   2681: #if defined (POINTER_DEBUG)
                   2682:                abort ();
                   2683: #else
                   2684:                *ptr = (struct option_cache *)0;
                   2685:                return 0;
                   2686: #endif
                   2687:        }
                   2688:        *ptr = (struct option_cache *)0;
                   2689:        return 1;
                   2690: 
                   2691: }
                   2692: 
                   2693: int hashed_option_state_dereference (universe, state, file, line)
                   2694:        struct universe *universe;
                   2695:        struct option_state *state;
                   2696:        const char *file;
                   2697:        int line;
                   2698: {
                   2699:        pair *heads;
                   2700:        pair cp, next;
                   2701:        int i;
                   2702: 
                   2703:        /* Get the pointer to the array of hash table bucket heads. */
                   2704:        heads = (pair *)(state -> universes [universe -> index]);
                   2705:        if (!heads)
                   2706:                return 0;
                   2707: 
                   2708:        /* For each non-null head, loop through all the buckets dereferencing
                   2709:           the attached option cache structures and freeing the buckets. */
                   2710:        for (i = 0; i < OPTION_HASH_SIZE; i++) {
                   2711:                for (cp = heads [i]; cp; cp = next) {
                   2712:                        next = cp -> cdr;
                   2713:                        option_cache_dereference
                   2714:                                ((struct option_cache **)&cp -> car,
                   2715:                                 file, line);
                   2716:                        free_pair (cp, file, line);
                   2717:                }
                   2718:        }
                   2719: 
                   2720:        dfree (heads, file, line);
                   2721:        state -> universes [universe -> index] = (void *)0;
                   2722:        return 1;
                   2723: }
                   2724: 
                   2725: /* The 'data_string' primitive doesn't have an appension mechanism.
                   2726:  * This function must then append a new option onto an existing buffer
                   2727:  * by first duplicating the original buffer and appending the desired
                   2728:  * values, followed by coping the new value into place.
                   2729:  */
                   2730: int
                   2731: append_option(struct data_string *dst, struct universe *universe,
                   2732:              struct option *option, struct data_string *src)
                   2733: {
                   2734:        struct data_string tmp;
                   2735: 
                   2736:        if (src->len == 0 && option->format[0] != 'Z')
                   2737:                return 0;
                   2738: 
                   2739:        memset(&tmp, 0, sizeof(tmp));
                   2740: 
                   2741:        /* Allocate a buffer to hold existing data, the current option's
                   2742:         * tag and length, and the option's content.
                   2743:         */
                   2744:        if (!buffer_allocate(&tmp.buffer,
                   2745:                             (dst->len + universe->length_size +
                   2746:                              universe->tag_size + src->len), MDL)) {
                   2747:                /* XXX: This kills all options presently stored in the
                   2748:                 * destination buffer.  This is the way the original code
                   2749:                 * worked, and assumes an 'all or nothing' approach to
                   2750:                 * eg encapsulated option spaces.  It may or may not be
                   2751:                 * desirable.
                   2752:                 */
                   2753:                data_string_forget(dst, MDL);
                   2754:                return 0;
                   2755:        }
                   2756:        tmp.data = tmp.buffer->data;
                   2757: 
                   2758:        /* Copy the existing data off the destination. */
                   2759:        if (dst->len != 0)
                   2760:                memcpy(tmp.buffer->data, dst->data, dst->len);
                   2761:        tmp.len = dst->len;
                   2762: 
                   2763:        /* Place the new option tag and length. */
                   2764:        (*universe->store_tag)(tmp.buffer->data + tmp.len, option->code);
                   2765:        tmp.len += universe->tag_size;
                   2766:        (*universe->store_length)(tmp.buffer->data + tmp.len, src->len);
                   2767:        tmp.len += universe->length_size;
                   2768: 
                   2769:        /* Copy the option contents onto the end. */
                   2770:        memcpy(tmp.buffer->data + tmp.len, src->data, src->len);
                   2771:        tmp.len += src->len;
                   2772: 
                   2773:        /* Play the shell game. */
                   2774:        data_string_forget(dst, MDL);
                   2775:        data_string_copy(dst, &tmp, MDL);
                   2776:        data_string_forget(&tmp, MDL);
                   2777:        return 1;
                   2778: }
                   2779: 
                   2780: int
                   2781: store_option(struct data_string *result, struct universe *universe,
                   2782:             struct packet *packet, struct lease *lease,
                   2783:             struct client_state *client_state,
                   2784:             struct option_state *in_options, struct option_state *cfg_options,
                   2785:             struct binding_scope **scope, struct option_cache *oc)
                   2786: {
                   2787:        struct data_string tmp;
                   2788:        struct universe *subu=NULL;
                   2789:        int status;
                   2790:        char *start, *end;
                   2791: 
                   2792:        memset(&tmp, 0, sizeof(tmp));
                   2793: 
                   2794:        if (evaluate_option_cache(&tmp, packet, lease, client_state,
                   2795:                                  in_options, cfg_options, scope, oc, MDL)) {
                   2796:                /* If the option is an extended 'e'ncapsulation (not a
                   2797:                 * direct 'E'ncapsulation), append the encapsulated space
                   2798:                 * onto the currently prepared value.
                   2799:                 */
                   2800:                do {
                   2801:                        if (oc->option->format &&
                   2802:                            oc->option->format[0] == 'e') {
                   2803:                                /* Skip forward to the universe name. */
                   2804:                                start = strchr(oc->option->format, 'E');
                   2805:                                if (start == NULL)
                   2806:                                        break;
                   2807: 
                   2808:                                /* Locate the name-terminating '.'. */
                   2809:                                end = strchr(++start, '.');
                   2810: 
                   2811:                                /* A zero-length name is not allowed in
                   2812:                                 * these kinds of encapsulations.
                   2813:                                 */
                   2814:                                if (end == NULL || start == end)
                   2815:                                        break;
                   2816: 
                   2817:                                universe_hash_lookup(&subu, universe_hash,
                   2818:                                                     start, end - start, MDL);
                   2819: 
                   2820:                                if (subu == NULL) {
                   2821:                                        log_error("store_option: option %d "
                   2822:                                                  "refers to unknown "
                   2823:                                                  "option space '%.*s'.",
                   2824:                                                  oc->option->code,
                   2825:                                                  (int)(end - start), start);
                   2826:                                        break;
                   2827:                                }
                   2828: 
                   2829:                                /* Append encapsulations, if any.  We
                   2830:                                 * already have the prepended values, so
                   2831:                                 * we send those even if there are no
                   2832:                                 * encapsulated options (and ->encapsulate()
                   2833:                                 * returns zero).
                   2834:                                 */
                   2835:                                subu->encapsulate(&tmp, packet, lease,
                   2836:                                                  client_state, in_options,
                   2837:                                                  cfg_options, scope, subu);
                   2838:                                subu = NULL;
                   2839:                        }
                   2840:                } while (ISC_FALSE);
                   2841: 
                   2842:                status = append_option(result, universe, oc->option, &tmp);
                   2843:                data_string_forget(&tmp, MDL);
                   2844: 
                   2845:                return status;
                   2846:        }
                   2847: 
                   2848:        return 0;
                   2849: }
                   2850: 
                   2851: int option_space_encapsulate (result, packet, lease, client_state,
                   2852:                              in_options, cfg_options, scope, name)
                   2853:        struct data_string *result;
                   2854:        struct packet *packet;
                   2855:        struct lease *lease;
                   2856:        struct client_state *client_state;
                   2857:        struct option_state *in_options;
                   2858:        struct option_state *cfg_options;
                   2859:        struct binding_scope **scope;
                   2860:        struct data_string *name;
                   2861: {
                   2862:        struct universe *u = NULL;
                   2863:        int status = 0;
                   2864: 
                   2865:        universe_hash_lookup(&u, universe_hash, 
                   2866:                             (const char *)name->data, name->len, MDL);
                   2867:        if (u == NULL) {
                   2868:                log_error("option_space_encapsulate: option space '%.*s' does "
                   2869:                          "not exist, but is configured.",
                   2870:                          (int)name->len, name->data);
                   2871:                return status;
                   2872:        }
                   2873: 
                   2874:        if (u->encapsulate != NULL) {
                   2875:                if (u->encapsulate(result, packet, lease, client_state,
                   2876:                                   in_options, cfg_options, scope, u))
                   2877:                        status = 1;
                   2878:        } else
                   2879:                log_error("encapsulation requested for '%s' with no support.",
                   2880:                          name->data);
                   2881: 
                   2882:        return status;
                   2883: }
                   2884: 
                   2885: /* Attempt to store any 'E'ncapsulated options that have not yet been
                   2886:  * placed on the option buffer by the above (configuring a value in
                   2887:  * the space over-rides any values in the child universe).
                   2888:  *
                   2889:  * Note that there are far fewer universes than there will ever be
                   2890:  * options in any universe.  So it is faster to traverse the
                   2891:  * configured universes, checking if each is encapsulated in the
                   2892:  * current universe, and if so attempting to do so.
                   2893:  *
                   2894:  * For each configured universe for this configuration option space,
                   2895:  * which is encapsulated within the current universe, can not be found
                   2896:  * by the lookup function (the universe-specific encapsulation
                   2897:  * functions would already have stored such a value), and encapsulates
                   2898:  * at least one option, append it.
                   2899:  */
                   2900: static int
                   2901: search_subencapsulation(struct data_string *result, struct packet *packet,
                   2902:                        struct lease *lease, struct client_state *client_state,
                   2903:                        struct option_state *in_options,
                   2904:                        struct option_state *cfg_options,
                   2905:                        struct binding_scope **scope,
                   2906:                        struct universe *universe)
                   2907: {
                   2908:        struct data_string sub;
                   2909:        struct universe *subu;
                   2910:        int i, status = 0;
                   2911: 
                   2912:        memset(&sub, 0, sizeof(sub));
                   2913:        for (i = 0 ; i < cfg_options->universe_count ; i++) {
                   2914:                subu = universes[i];
                   2915: 
                   2916:                if (subu == NULL)
                   2917:                        log_fatal("Impossible condition at %s:%d.", MDL);
                   2918: 
                   2919:                if (subu->enc_opt != NULL &&
                   2920:                    subu->enc_opt->universe == universe &&
                   2921:                    subu->enc_opt->format != NULL &&
                   2922:                    subu->enc_opt->format[0] == 'E' &&
                   2923:                    lookup_option(universe, cfg_options,
                   2924:                                  subu->enc_opt->code) == NULL &&
                   2925:                    subu->encapsulate(&sub, packet, lease, client_state,
                   2926:                                      in_options, cfg_options,
                   2927:                                      scope, subu)) {
                   2928:                        if (append_option(result, universe,
                   2929:                                          subu->enc_opt, &sub))
                   2930:                                status = 1;
                   2931: 
                   2932:                        data_string_forget(&sub, MDL);
                   2933:                }
                   2934:        }
                   2935: 
                   2936:        return status;
                   2937: }
                   2938: 
                   2939: int hashed_option_space_encapsulate (result, packet, lease, client_state,
                   2940:                                     in_options, cfg_options, scope, universe)
                   2941:        struct data_string *result;
                   2942:        struct packet *packet;
                   2943:        struct lease *lease;
                   2944:        struct client_state *client_state;
                   2945:        struct option_state *in_options;
                   2946:        struct option_state *cfg_options;
                   2947:        struct binding_scope **scope;
                   2948:        struct universe *universe;
                   2949: {
                   2950:        pair p, *hash;
                   2951:        int status;
                   2952:        int i;
                   2953: 
                   2954:        if (universe -> index >= cfg_options -> universe_count)
                   2955:                return 0;
                   2956: 
                   2957:        hash = cfg_options -> universes [universe -> index];
                   2958:        if (!hash)
                   2959:                return 0;
                   2960: 
                   2961:        /* For each hash bucket, and each configured option cache within
                   2962:         * that bucket, append the option onto the buffer in encapsulated
                   2963:         * format appropriate to the universe.
                   2964:         */
                   2965:        status = 0;
                   2966:        for (i = 0; i < OPTION_HASH_SIZE; i++) {
                   2967:                for (p = hash [i]; p; p = p -> cdr) {
                   2968:                        if (store_option(result, universe, packet, lease,
                   2969:                                         client_state, in_options, cfg_options,
                   2970:                                         scope, (struct option_cache *)p->car))
                   2971:                                status = 1;
                   2972:                }
                   2973:        }
                   2974: 
                   2975:        if (search_subencapsulation(result, packet, lease, client_state,
                   2976:                                    in_options, cfg_options, scope, universe))
                   2977:                status = 1;
                   2978: 
                   2979:        return status;
                   2980: }
                   2981: 
                   2982: int nwip_option_space_encapsulate (result, packet, lease, client_state,
                   2983:                                   in_options, cfg_options, scope, universe)
                   2984:        struct data_string *result;
                   2985:        struct packet *packet;
                   2986:        struct lease *lease;
                   2987:        struct client_state *client_state;
                   2988:        struct option_state *in_options;
                   2989:        struct option_state *cfg_options;
                   2990:        struct binding_scope **scope;
                   2991:        struct universe *universe;
                   2992: {
                   2993:        pair ocp;
                   2994:        int status;
                   2995:        static struct option_cache *no_nwip;
                   2996:        struct data_string ds;
                   2997:        struct option_chain_head *head;
                   2998: 
                   2999:        if (universe -> index >= cfg_options -> universe_count)
                   3000:                return 0;
                   3001:        head = ((struct option_chain_head *)
                   3002:                cfg_options -> universes [nwip_universe.index]);
                   3003:        if (!head)
                   3004:                return 0;
                   3005: 
                   3006:        status = 0;
                   3007:        for (ocp = head -> first; ocp; ocp = ocp -> cdr) {
                   3008:                if (store_option (result, universe, packet,
                   3009:                                  lease, client_state, in_options,
                   3010:                                  cfg_options, scope,
                   3011:                                  (struct option_cache *)ocp -> car))
                   3012:                        status = 1;
                   3013:        }
                   3014: 
                   3015:        /* If there's no data, the nwip suboption is supposed to contain
                   3016:           a suboption saying there's no data. */
                   3017:        if (!status) {
                   3018:                if (!no_nwip) {
                   3019:                        unsigned one = 1;
                   3020:                        static unsigned char nni [] = { 1, 0 };
                   3021: 
                   3022:                        memset (&ds, 0, sizeof ds);
                   3023:                        ds.data = nni;
                   3024:                        ds.len = 2;
                   3025:                        if (option_cache_allocate (&no_nwip, MDL))
                   3026:                                data_string_copy (&no_nwip -> data, &ds, MDL);
                   3027:                        if (!option_code_hash_lookup(&no_nwip->option,
                   3028:                                                     nwip_universe.code_hash,
                   3029:                                                     &one, 0, MDL))
                   3030:                                log_fatal("Nwip option hash does not contain "
                   3031:                                          "1 (%s:%d).", MDL);
                   3032:                }
                   3033:                if (no_nwip) {
                   3034:                        if (store_option (result, universe, packet, lease,
                   3035:                                          client_state, in_options,
                   3036:                                          cfg_options, scope, no_nwip))
                   3037:                                status = 1;
                   3038:                }
                   3039:        } else {
                   3040:                memset (&ds, 0, sizeof ds);
                   3041: 
                   3042:                /* If we have nwip options, the first one has to be the
                   3043:                   nwip-exists-in-option-area option. */
                   3044:                if (!buffer_allocate (&ds.buffer, result -> len + 2, MDL)) {
                   3045:                        data_string_forget (result, MDL);
                   3046:                        return 0;
                   3047:                }
                   3048:                ds.data = &ds.buffer -> data [0];
                   3049:                ds.buffer -> data [0] = 2;
                   3050:                ds.buffer -> data [1] = 0;
                   3051:                memcpy (&ds.buffer -> data [2], result -> data, result -> len);
                   3052:                data_string_forget (result, MDL);
                   3053:                data_string_copy (result, &ds, MDL);
                   3054:                data_string_forget (&ds, MDL);
                   3055:        }
                   3056: 
                   3057:        return status;
                   3058: }
                   3059: 
                   3060: /* We don't want to use ns_name_pton()...it doesn't tell us how many bytes
                   3061:  * it has consumed, and it plays havoc with our escapes.
                   3062:  *
                   3063:  * So this function does DNS encoding, and returns either the number of
                   3064:  * octects consumed (on success), or -1 on failure.
                   3065:  */
                   3066: static int
                   3067: fqdn_encode(unsigned char *dst, int dstlen, const unsigned char *src,
                   3068:            int srclen)
                   3069: {
                   3070:        unsigned char *out;
                   3071:        int i, j, len, outlen=0;
                   3072: 
                   3073:        out = dst;
                   3074:        for (i = 0, j = 0 ; i < srclen ; i = j) {
                   3075:                while ((j < srclen) && (src[j] != '.') && (src[j] != '\0'))
                   3076:                        j++;
                   3077: 
                   3078:                len = j - i;
                   3079:                if ((outlen + 1 + len) > dstlen)
                   3080:                        return -1;
                   3081: 
                   3082:                *out++ = len;
                   3083:                outlen++;
                   3084: 
                   3085:                /* We only do one FQDN, ending in one root label. */
                   3086:                if (len == 0)
                   3087:                        return outlen;
                   3088: 
                   3089:                memcpy(out, src + i, len);
                   3090:                out += len;
                   3091:                outlen += len;
                   3092: 
                   3093:                /* Advance past the root label. */
                   3094:                j++;
                   3095:        }
                   3096: 
                   3097:        if ((outlen + 1) > dstlen)
                   3098:                return -1;
                   3099: 
                   3100:        /* Place the root label. */
                   3101:        *out++ = 0;
                   3102:        outlen++;
                   3103: 
                   3104:        return outlen;
                   3105: }
                   3106: 
                   3107: int fqdn_option_space_encapsulate (result, packet, lease, client_state,
                   3108:                                   in_options, cfg_options, scope, universe)
                   3109:        struct data_string *result;
                   3110:        struct packet *packet;
                   3111:        struct lease *lease;
                   3112:        struct client_state *client_state;
                   3113:        struct option_state *in_options;
                   3114:        struct option_state *cfg_options;
                   3115:        struct binding_scope **scope;
                   3116:        struct universe *universe;
                   3117: {
                   3118:        pair ocp;
                   3119:        struct data_string results [FQDN_SUBOPTION_COUNT + 1];
                   3120:        int status = 1;
                   3121:        int i;
                   3122:        unsigned len;
                   3123:        struct buffer *bp = (struct buffer *)0;
                   3124:        struct option_chain_head *head;
                   3125: 
                   3126:        /* If there's no FQDN universe, don't encapsulate. */
                   3127:        if (fqdn_universe.index >= cfg_options -> universe_count)
                   3128:                return 0;
                   3129:        head = ((struct option_chain_head *)
                   3130:                cfg_options -> universes [fqdn_universe.index]);
                   3131:        if (!head)
                   3132:                return 0;
                   3133: 
                   3134:        /* Figure out the values of all the suboptions. */
                   3135:        memset (results, 0, sizeof results);
                   3136:        for (ocp = head -> first; ocp; ocp = ocp -> cdr) {
                   3137:                struct option_cache *oc = (struct option_cache *)(ocp -> car);
                   3138:                if (oc -> option -> code > FQDN_SUBOPTION_COUNT)
                   3139:                        continue;
                   3140:                evaluate_option_cache (&results [oc -> option -> code],
                   3141:                                       packet, lease, client_state, in_options,
                   3142:                                       cfg_options, scope,  oc, MDL);
                   3143:        }
                   3144:        /* We add a byte for the flags field.
                   3145:         * We add two bytes for the two RCODE fields.
                   3146:         * We add a byte because we will prepend a label count.
                   3147:         * We add a byte because the input len doesn't count null termination,
                   3148:         * and we will add a root label.
                   3149:         */
                   3150:        len = 5 + results [FQDN_FQDN].len;
                   3151:        /* Save the contents of the option in a buffer. */
                   3152:        if (!buffer_allocate (&bp, len, MDL)) {
                   3153:                log_error ("no memory for option buffer.");
                   3154:                status = 0;
                   3155:                goto exit;
                   3156:        }
                   3157:        buffer_reference (&result -> buffer, bp, MDL);
                   3158:        result -> len = 3;
                   3159:        result -> data = &bp -> data [0];
                   3160: 
                   3161:        memset (&bp -> data [0], 0, len);
                   3162:        /* XXX: The server should set bit 4 (yes, 4, not 3) to 1 if it is
                   3163:         * not going to perform any ddns updates.  The client should set the
                   3164:         * bit if it doesn't want the server to perform any updates.
                   3165:         * The problem is at this layer of abstraction we have no idea if
                   3166:         * the caller is a client or server.
                   3167:         *
                   3168:         * See RFC4702, Section 3.1, 'The "N" bit'.
                   3169:         *
                   3170:         * if (?)
                   3171:         *      bp->data[0] |= 8;
                   3172:         */
                   3173:        if (results [FQDN_NO_CLIENT_UPDATE].len &&
                   3174:            results [FQDN_NO_CLIENT_UPDATE].data [0])
                   3175:                bp -> data [0] |= 2;
                   3176:        if (results [FQDN_SERVER_UPDATE].len &&
                   3177:            results [FQDN_SERVER_UPDATE].data [0])
                   3178:                bp -> data [0] |= 1;
                   3179:        if (results [FQDN_RCODE1].len)
                   3180:                bp -> data [1] = results [FQDN_RCODE1].data [0];
                   3181:        if (results [FQDN_RCODE2].len)
                   3182:                bp -> data [2] = results [FQDN_RCODE2].data [0];
                   3183: 
                   3184:        if (results [FQDN_ENCODED].len &&
                   3185:            results [FQDN_ENCODED].data [0]) {
                   3186:                bp->data[0] |= 4;
                   3187:                if (results [FQDN_FQDN].len) {
                   3188:                        i = fqdn_encode(&bp->data[3], len - 3,
                   3189:                                        results[FQDN_FQDN].data,
                   3190:                                        results[FQDN_FQDN].len);
                   3191: 
                   3192:                        if (i < 0) {
                   3193:                                status = 0;
                   3194:                                goto exit;
                   3195:                        }
                   3196: 
                   3197:                        result->len += i;
                   3198:                        result->terminated = 0;
                   3199:                }
                   3200:        } else {
                   3201:                if (results [FQDN_FQDN].len) {
                   3202:                        memcpy (&bp -> data [3], results [FQDN_FQDN].data,
                   3203:                                results [FQDN_FQDN].len);
                   3204:                        result -> len += results [FQDN_FQDN].len;
                   3205:                        result -> terminated = 0;
                   3206:                }
                   3207:        }
                   3208:       exit:
                   3209:        for (i = 1; i <= FQDN_SUBOPTION_COUNT; i++) {
                   3210:                if (results [i].len)
                   3211:                        data_string_forget (&results [i], MDL);
                   3212:        }
                   3213:        buffer_dereference (&bp, MDL);
                   3214:        if (!status)
                   3215:                data_string_forget(result, MDL);
                   3216:        return status;
                   3217: }
                   3218: 
                   3219: /*
                   3220:  * Trap invalid attempts to inspect FQND6 contents.
                   3221:  */
                   3222: struct option_cache *
                   3223: lookup_fqdn6_option(struct universe *universe, struct option_state *options,
                   3224:                    unsigned code)
                   3225: {
                   3226:        log_fatal("Impossible condition at %s:%d.", MDL);
                   3227:        return NULL;
                   3228: }
                   3229: 
                   3230: /*
                   3231:  * Trap invalid attempts to save options directly to FQDN6 rather than FQDN.
                   3232:  */
                   3233: void
                   3234: save_fqdn6_option(struct universe *universe, struct option_state *options,
                   3235:                  struct option_cache *oc, isc_boolean_t appendp)
                   3236: {
                   3237:        log_fatal("Impossible condition at %s:%d.", MDL);
                   3238: }
                   3239: 
                   3240: /*
                   3241:  * Trap invalid attempts to delete an option out of the FQDN6 universe.
                   3242:  */
                   3243: void
                   3244: delete_fqdn6_option(struct universe *universe, struct option_state *options,
                   3245:                    int code)
                   3246: {
                   3247:        log_fatal("Impossible condition at %s:%d.", MDL);
                   3248: }
                   3249: 
                   3250: /* Shill to the DHCPv4 fqdn option cache any attempts to traverse the
                   3251:  * V6's option cache entry.
                   3252:  *
                   3253:  * This function is called speculatively by dhclient to setup
                   3254:  * environment variables.  But it would have already called the
                   3255:  * foreach on the normal fqdn universe, so this is superfluous.
                   3256:  */
                   3257: void
                   3258: fqdn6_option_space_foreach(struct packet *packet, struct lease *lease,
                   3259:                           struct client_state *client_state,
                   3260:                           struct option_state *in_options,
                   3261:                           struct option_state *cfg_options,
                   3262:                           struct binding_scope **scope,
                   3263:                           struct universe *u, void *stuff,
                   3264:                           void (*func)(struct option_cache *,
                   3265:                                        struct packet *,
                   3266:                                        struct lease *,
                   3267:                                        struct client_state *,
                   3268:                                        struct option_state *,
                   3269:                                        struct option_state *,
                   3270:                                        struct binding_scope **,
                   3271:                                        struct universe *, void *))
                   3272: {
                   3273:        /* Pretend it is empty. */
                   3274:        return;
                   3275: }
                   3276: 
                   3277: /* Turn the FQDN option space into a DHCPv6 FQDN option buffer.
                   3278:  */
                   3279: int
                   3280: fqdn6_option_space_encapsulate(struct data_string *result,
                   3281:                               struct packet *packet, struct lease *lease,
                   3282:                               struct client_state *client_state,
                   3283:                               struct option_state *in_options,
                   3284:                               struct option_state *cfg_options,
                   3285:                               struct binding_scope **scope,
                   3286:                               struct universe *universe)
                   3287: {
                   3288:        pair ocp;
                   3289:        struct option_chain_head *head;
                   3290:        struct option_cache *oc;
                   3291:        unsigned char *data;
                   3292:        int i, len, rval = 0, count;
                   3293:        struct data_string results[FQDN_SUBOPTION_COUNT + 1];
                   3294: 
                   3295:        if (fqdn_universe.index >= cfg_options->universe_count)
                   3296:                return 0;
                   3297:        head = ((struct option_chain_head *)
                   3298:                cfg_options->universes[fqdn_universe.index]);
                   3299:        if (head == NULL)
                   3300:                return 0;
                   3301: 
                   3302:        memset(results, 0, sizeof(results));
                   3303:        for (ocp = head->first ; ocp != NULL ; ocp = ocp->cdr) {
                   3304:                oc = (struct option_cache *)(ocp->car);
                   3305:                if (oc->option->code > FQDN_SUBOPTION_COUNT)
                   3306:                        log_fatal("Impossible condition at %s:%d.", MDL);
                   3307: 
                   3308:                evaluate_option_cache(&results[oc->option->code], packet,
                   3309:                                      lease, client_state, in_options,
                   3310:                                      cfg_options, scope, oc, MDL);
                   3311:        }
                   3312: 
                   3313:        /* We add a byte for the flags field at the start of the option.
                   3314:         * We add a byte because we will prepend a label count.
                   3315:         * We add a byte because the input length doesn't include a trailing
                   3316:         * NULL, and we will add a root label.
                   3317:         */
                   3318:        len = results[FQDN_FQDN].len + 3;
                   3319:        if (!buffer_allocate(&result->buffer, len, MDL)) {
                   3320:                log_error("No memory for virtual option buffer.");
                   3321:                goto exit;
                   3322:        }
                   3323:        data = result->buffer->data;
                   3324:        result->data = data;
                   3325: 
                   3326:        /* The first byte is the flags field. */
                   3327:        result->len = 1;
                   3328:        data[0] = 0;
                   3329:        /* XXX: The server should set bit 3 (yes, 3, not 4) to 1 if we
                   3330:         * are not going to perform any DNS updates.  The problem is
                   3331:         * that at this layer of abstraction, we do not know if the caller
                   3332:         * is the client or the server.
                   3333:         *
                   3334:         * See RFC4704 Section 4.1, 'The "N" bit'.
                   3335:         *
                   3336:         * if (?)
                   3337:         *      data[0] |= 4;
                   3338:         */
                   3339:        if (results[FQDN_NO_CLIENT_UPDATE].len &&
                   3340:            results[FQDN_NO_CLIENT_UPDATE].data[0])
                   3341:                data[0] |= 2;
                   3342:        if (results[FQDN_SERVER_UPDATE].len &&
                   3343:            results[FQDN_SERVER_UPDATE].data[0])
                   3344:                data[0] |= 1;
                   3345: 
                   3346:        /* If there is no name, we're done. */
                   3347:        if (results[FQDN_FQDN].len == 0) {
                   3348:                rval = 1;
                   3349:                goto exit;
                   3350:        }
                   3351: 
                   3352:        /* Convert textual representation to DNS format. */
                   3353:        count = fqdn_encode(data + 1, len - 1,
                   3354:                            results[FQDN_FQDN].data, results[FQDN_FQDN].len);
                   3355: 
                   3356:        if (count < 0) {
                   3357:                rval = 0;
                   3358:                data_string_forget(result, MDL);
                   3359:                goto exit;
                   3360:        }
                   3361: 
                   3362:        result->len += count;
                   3363:        result->terminated = 0;
                   3364: 
                   3365:        /* Success! */
                   3366:        rval = 1;
                   3367: 
                   3368:       exit:
                   3369:        for (i = 1 ; i <= FQDN_SUBOPTION_COUNT ; i++) {
                   3370:                if (result[i].len)
                   3371:                        data_string_forget(&results[i], MDL);
                   3372:        }
                   3373: 
                   3374:        return rval;
                   3375: }
                   3376: 
                   3377: /* Read the DHCPv6 FQDN option's contents into the FQDN virtual space.
                   3378:  */
                   3379: int
                   3380: fqdn6_universe_decode(struct option_state *options,
                   3381:                      const unsigned char *buffer, unsigned length,
                   3382:                      struct universe *u)
                   3383: {
                   3384:        struct buffer *bp = NULL;
                   3385:        unsigned char *first_dot;
                   3386:        int len, hlen, dlen;
                   3387: 
                   3388:        /* The FQDN option has to be at least 1 byte long. */
                   3389:        if (length < 1)
                   3390:                return 0;
                   3391: 
                   3392:        /* Save the contents of the option in a buffer.  There are 3
                   3393:         * one-byte values we record from the packet, so we go ahead
                   3394:         * and allocate a bigger buffer to accommodate them.  But the
                   3395:         * 'length' we got (because it is a DNS encoded string) is
                   3396:         * one longer than we need...so we only add two extra octets.
                   3397:         */
                   3398:        if (!buffer_allocate(&bp, length + 2, MDL)) {
                   3399:                log_error("No memory for dhcp6.fqdn option buffer.");
                   3400:                return 0;
                   3401:        }
                   3402: 
                   3403:        /* The v6 FQDN is always 'encoded' per DNS. */
                   3404:        bp->data[0] = 1;
                   3405:        if (!save_option_buffer(&fqdn_universe, options, bp,
                   3406:                                bp->data, 1, FQDN_ENCODED, 0))
                   3407:                goto error;
                   3408: 
                   3409:        /* XXX: We need to process 'The "N" bit'. */
                   3410: 
                   3411:        if (buffer[0] & 1) /* server-update. */
                   3412:                bp->data[2] = 1;
                   3413:        else
                   3414:                bp->data[2] = 0;
                   3415: 
                   3416:        if (!save_option_buffer(&fqdn_universe, options, bp, bp->data + 2, 1,
                   3417:                                FQDN_SERVER_UPDATE, 0))
                   3418:                goto error;
                   3419: 
                   3420:        if (buffer[0] & 2) /* no-client-update. */
                   3421:                bp->data[1] = 1;
                   3422:        else
                   3423:                bp->data[1] = 0;
                   3424: 
                   3425:        if (!save_option_buffer(&fqdn_universe, options, bp, bp->data + 1, 1,
                   3426:                                FQDN_NO_CLIENT_UPDATE, 0))
                   3427:                goto error;
                   3428: 
                   3429:        /* Convert the domain name to textual representation for config. */
                   3430:        len = MRns_name_ntop(buffer + 1, (char *)bp->data + 3, length - 1);
                   3431:        if (len == -1) {
                   3432:                log_error("Unable to convert dhcp6.fqdn domain name to "
                   3433:                          "printable form.");
                   3434:                goto error;
                   3435:        }
                   3436: 
                   3437:        /* Save the domain name. */
                   3438:        if (len > 0) {
                   3439:                unsigned char *fqdn_start = bp->data + 3;
                   3440: 
                   3441:                if (!save_option_buffer(&fqdn_universe, options, bp,
                   3442:                                        fqdn_start, len, FQDN_FQDN, 1))
                   3443:                        goto error;
                   3444: 
                   3445:                first_dot = (unsigned char *)strchr((char *)fqdn_start, '.');
                   3446: 
                   3447:                if (first_dot != NULL) {
                   3448:                        hlen = first_dot - fqdn_start;
                   3449:                        dlen = len - hlen;
                   3450:                } else {
                   3451:                        hlen = len;
                   3452:                        dlen = 0;
                   3453:                }
                   3454: 
                   3455:                if (!save_option_buffer(&fqdn_universe, options, bp,
                   3456:                                        fqdn_start, len, FQDN_FQDN, 1) ||
                   3457:                    ((hlen > 0) &&
                   3458:                     !save_option_buffer(&fqdn_universe, options, bp,
                   3459:                                         fqdn_start, hlen,
                   3460:                                         FQDN_HOSTNAME, 0)) ||
                   3461:                    ((dlen > 0) &&
                   3462:                     !save_option_buffer(&fqdn_universe, options, bp,
                   3463:                                         first_dot, dlen, FQDN_DOMAINNAME, 0)))
                   3464:                                goto error;
                   3465:        }
                   3466: 
                   3467:        buffer_dereference(&bp, MDL);
                   3468:        return 1;
                   3469: 
                   3470:       error:
                   3471:        buffer_dereference(&bp, MDL);
                   3472:        return 0;
                   3473: }
                   3474: 
                   3475: void option_space_foreach (struct packet *packet, struct lease *lease,
                   3476:                           struct client_state *client_state,
                   3477:                           struct option_state *in_options,
                   3478:                           struct option_state *cfg_options,
                   3479:                           struct binding_scope **scope,
                   3480:                           struct universe *u, void *stuff,
                   3481:                           void (*func) (struct option_cache *,
                   3482:                                         struct packet *,
                   3483:                                         struct lease *, struct client_state *,
                   3484:                                         struct option_state *,
                   3485:                                         struct option_state *,
                   3486:                                         struct binding_scope **,
                   3487:                                         struct universe *, void *))
                   3488: {
                   3489:        if (u -> foreach)
                   3490:                (*u -> foreach) (packet, lease, client_state, in_options,
                   3491:                                 cfg_options, scope, u, stuff, func);
                   3492: }
                   3493: 
                   3494: void suboption_foreach (struct packet *packet, struct lease *lease,
                   3495:                        struct client_state *client_state,
                   3496:                        struct option_state *in_options,
                   3497:                        struct option_state *cfg_options,
                   3498:                        struct binding_scope **scope,
                   3499:                        struct universe *u, void *stuff,
                   3500:                        void (*func) (struct option_cache *,
                   3501:                                      struct packet *,
                   3502:                                      struct lease *, struct client_state *,
                   3503:                                      struct option_state *,
                   3504:                                      struct option_state *,
                   3505:                                      struct binding_scope **,
                   3506:                                      struct universe *, void *),
                   3507:                        struct option_cache *oc,
                   3508:                        const char *vsname)
                   3509: {
                   3510:        struct universe *universe = find_option_universe (oc -> option,
                   3511:                                                          vsname);
                   3512:        if (universe -> foreach)
                   3513:                (*universe -> foreach) (packet, lease, client_state,
                   3514:                                        in_options, cfg_options,
                   3515:                                        scope, universe, stuff, func);
                   3516: }
                   3517: 
                   3518: void hashed_option_space_foreach (struct packet *packet, struct lease *lease,
                   3519:                                  struct client_state *client_state,
                   3520:                                  struct option_state *in_options,
                   3521:                                  struct option_state *cfg_options,
                   3522:                                  struct binding_scope **scope,
                   3523:                                  struct universe *u, void *stuff,
                   3524:                                  void (*func) (struct option_cache *,
                   3525:                                                struct packet *,
                   3526:                                                struct lease *,
                   3527:                                                struct client_state *,
                   3528:                                                struct option_state *,
                   3529:                                                struct option_state *,
                   3530:                                                struct binding_scope **,
                   3531:                                                struct universe *, void *))
                   3532: {
                   3533:        pair *hash;
                   3534:        int i;
                   3535:        struct option_cache *oc;
                   3536: 
                   3537:        if (cfg_options -> universe_count <= u -> index)
                   3538:                return;
                   3539: 
                   3540:        hash = cfg_options -> universes [u -> index];
                   3541:        if (!hash)
                   3542:                return;
                   3543:        for (i = 0; i < OPTION_HASH_SIZE; i++) {
                   3544:                pair p;
                   3545:                /* XXX save _all_ options! XXX */
                   3546:                for (p = hash [i]; p; p = p -> cdr) {
                   3547:                        oc = (struct option_cache *)p -> car;
                   3548:                        (*func) (oc, packet, lease, client_state,
                   3549:                                 in_options, cfg_options, scope, u, stuff);
                   3550:                }
                   3551:        }
                   3552: }
                   3553: 
                   3554: void
                   3555: save_linked_option(struct universe *universe, struct option_state *options,
                   3556:                   struct option_cache *oc, isc_boolean_t appendp)
                   3557: {
                   3558:        pair *tail;
                   3559:        struct option_chain_head *head;
                   3560:        struct option_cache **ocloc;
                   3561: 
                   3562:        if (universe -> index >= options -> universe_count)
                   3563:                return;
                   3564:        head = ((struct option_chain_head *)
                   3565:                options -> universes [universe -> index]);
                   3566:        if (!head) {
                   3567:                if (!option_chain_head_allocate (((struct option_chain_head **)
                   3568:                                                  &options -> universes
                   3569:                                                  [universe -> index]), MDL))
                   3570:                        return;
                   3571:                head = ((struct option_chain_head *)
                   3572:                        options -> universes [universe -> index]);
                   3573:        }
                   3574: 
                   3575:        /* Find the tail of the list. */
                   3576:        for (tail = &head -> first; *tail; tail = &((*tail) -> cdr)) {
                   3577:                ocloc = (struct option_cache **)&(*tail)->car;
                   3578: 
                   3579:                if (oc->option->code == (*ocloc)->option->code) {
                   3580:                        if (appendp) {
                   3581:                                do {
                   3582:                                        ocloc = &(*ocloc)->next;
                   3583:                                } while (*ocloc != NULL);
                   3584:                        } else {
                   3585:                                option_cache_dereference(ocloc, MDL);
                   3586:                        }
                   3587:                        option_cache_reference(ocloc, oc, MDL);
                   3588:                        return;
                   3589:                }
                   3590:        }
                   3591: 
                   3592:        *tail = cons (0, 0);
                   3593:        if (*tail) {
                   3594:                option_cache_reference ((struct option_cache **)
                   3595:                                        (&(*tail) -> car), oc, MDL);
                   3596:        }
                   3597: }
                   3598: 
                   3599: int linked_option_space_encapsulate (result, packet, lease, client_state,
                   3600:                                    in_options, cfg_options, scope, universe)
                   3601:        struct data_string *result;
                   3602:        struct packet *packet;
                   3603:        struct lease *lease;
                   3604:        struct client_state *client_state;
                   3605:        struct option_state *in_options;
                   3606:        struct option_state *cfg_options;
                   3607:        struct binding_scope **scope;
                   3608:        struct universe *universe;
                   3609: {
                   3610:        int status = 0;
                   3611:        pair oc;
                   3612:        struct option_chain_head *head;
                   3613: 
                   3614:        if (universe -> index >= cfg_options -> universe_count)
                   3615:                return status;
                   3616:        head = ((struct option_chain_head *)
                   3617:                cfg_options -> universes [universe -> index]);
                   3618:        if (!head)
                   3619:                return status;
                   3620: 
                   3621:        for (oc = head -> first; oc; oc = oc -> cdr) {
                   3622:                if (store_option (result, universe, packet,
                   3623:                                  lease, client_state, in_options, cfg_options,
                   3624:                                  scope, (struct option_cache *)(oc -> car)))
                   3625:                        status = 1;
                   3626:        }
                   3627: 
                   3628:        if (search_subencapsulation(result, packet, lease, client_state,
                   3629:                                    in_options, cfg_options, scope, universe))
                   3630:                status = 1;
                   3631: 
                   3632:        return status;
                   3633: }
                   3634: 
                   3635: void delete_linked_option (universe, options, code)
                   3636:        struct universe *universe;
                   3637:        struct option_state *options;
                   3638:        int code;
                   3639: {
                   3640:        pair *tail, tmp = (pair)0;
                   3641:        struct option_chain_head *head;
                   3642: 
                   3643:        if (universe -> index >= options -> universe_count)
                   3644:                return;
                   3645:        head = ((struct option_chain_head *)
                   3646:                options -> universes [universe -> index]);
                   3647:        if (!head)
                   3648:                return;
                   3649: 
                   3650:        for (tail = &head -> first; *tail; tail = &((*tail) -> cdr)) {
                   3651:                if (code ==
                   3652:                    ((struct option_cache *)(*tail) -> car) -> option -> code)
                   3653:                {
                   3654:                        tmp = (*tail) -> cdr;
                   3655:                        option_cache_dereference ((struct option_cache **)
                   3656:                                                  (&(*tail) -> car), MDL);
                   3657:                        dfree (*tail, MDL);
                   3658:                        (*tail) = tmp;
                   3659:                        break;
                   3660:                }
                   3661:        }
                   3662: }
                   3663: 
                   3664: struct option_cache *lookup_linked_option (universe, options, code)
                   3665:        struct universe *universe;
                   3666:        struct option_state *options;
                   3667:        unsigned code;
                   3668: {
                   3669:        pair oc;
                   3670:        struct option_chain_head *head;
                   3671: 
                   3672:        if (universe -> index >= options -> universe_count)
                   3673:                return 0;
                   3674:        head = ((struct option_chain_head *)
                   3675:                options -> universes [universe -> index]);
                   3676:        if (!head)
                   3677:                return 0;
                   3678: 
                   3679:        for (oc = head -> first; oc; oc = oc -> cdr) {
                   3680:                if (code ==
                   3681:                    ((struct option_cache *)(oc -> car)) -> option -> code) {
                   3682:                        return (struct option_cache *)(oc -> car);
                   3683:                }
                   3684:        }
                   3685: 
                   3686:        return (struct option_cache *)0;
                   3687: }
                   3688: 
                   3689: int linked_option_state_dereference (universe, state, file, line)
                   3690:        struct universe *universe;
                   3691:        struct option_state *state;
                   3692:        const char *file;
                   3693:        int line;
                   3694: {
                   3695:        return (option_chain_head_dereference
                   3696:                ((struct option_chain_head **)
                   3697:                 (&state -> universes [universe -> index]), MDL));
                   3698: }
                   3699: 
                   3700: void linked_option_space_foreach (struct packet *packet, struct lease *lease,
                   3701:                                  struct client_state *client_state,
                   3702:                                  struct option_state *in_options,
                   3703:                                  struct option_state *cfg_options,
                   3704:                                  struct binding_scope **scope,
                   3705:                                  struct universe *u, void *stuff,
                   3706:                                  void (*func) (struct option_cache *,
                   3707:                                                struct packet *,
                   3708:                                                struct lease *,
                   3709:                                                struct client_state *,
                   3710:                                                struct option_state *,
                   3711:                                                struct option_state *,
                   3712:                                                struct binding_scope **,
                   3713:                                                struct universe *, void *))
                   3714: {
                   3715:        pair car;
                   3716:        struct option_chain_head *head;
                   3717: 
                   3718:        if (u -> index >= cfg_options -> universe_count)
                   3719:                return;
                   3720:        head = ((struct option_chain_head *)
                   3721:                cfg_options -> universes [u -> index]);
                   3722:        if (!head)
                   3723:                return;
                   3724:        for (car = head -> first; car; car = car -> cdr) {
                   3725:                (*func) ((struct option_cache *)(car -> car),
                   3726:                         packet, lease, client_state,
                   3727:                         in_options, cfg_options, scope, u, stuff);
                   3728:        }
                   3729: }
                   3730: 
                   3731: void do_packet (interface, packet, len, from_port, from, hfrom)
                   3732:        struct interface_info *interface;
                   3733:        struct dhcp_packet *packet;
                   3734:        unsigned len;
                   3735:        unsigned int from_port;
                   3736:        struct iaddr from;
                   3737:        struct hardware *hfrom;
                   3738: {
                   3739:        struct option_cache *op;
                   3740:        struct packet *decoded_packet;
                   3741: #if defined (DEBUG_MEMORY_LEAKAGE)
                   3742:        unsigned long previous_outstanding = dmalloc_outstanding;
                   3743: #endif
                   3744: 
                   3745: #if defined (TRACING)
                   3746:        trace_inpacket_stash (interface, packet, len, from_port, from, hfrom);
                   3747: #endif
                   3748: 
                   3749:        decoded_packet = (struct packet *)0;
                   3750:        if (!packet_allocate (&decoded_packet, MDL)) {
                   3751:                log_error ("do_packet: no memory for incoming packet!");
                   3752:                return;
                   3753:        }
                   3754:        decoded_packet -> raw = packet;
                   3755:        decoded_packet -> packet_length = len;
                   3756:        decoded_packet -> client_port = from_port;
                   3757:        decoded_packet -> client_addr = from;
                   3758:        interface_reference (&decoded_packet -> interface, interface, MDL);
                   3759:        decoded_packet -> haddr = hfrom;
                   3760: 
                   3761:        if (packet -> hlen > sizeof packet -> chaddr) {
                   3762:                packet_dereference (&decoded_packet, MDL);
                   3763:                log_info ("Discarding packet with bogus hlen.");
                   3764:                return;
                   3765:        }
                   3766: 
                   3767:        /* If there's an option buffer, try to parse it. */
                   3768:        if (decoded_packet -> packet_length >= DHCP_FIXED_NON_UDP + 4) {
                   3769:                if (!parse_options (decoded_packet)) {
                   3770:                        if (decoded_packet -> options)
                   3771:                                option_state_dereference
                   3772:                                        (&decoded_packet -> options, MDL);
                   3773:                        packet_dereference (&decoded_packet, MDL);
                   3774:                        return;
                   3775:                }
                   3776: 
                   3777:                if (decoded_packet -> options_valid &&
                   3778:                    (op = lookup_option (&dhcp_universe,
                   3779:                                         decoded_packet -> options, 
                   3780:                                         DHO_DHCP_MESSAGE_TYPE))) {
                   3781:                        struct data_string dp;
                   3782:                        memset (&dp, 0, sizeof dp);
                   3783:                        evaluate_option_cache (&dp, decoded_packet,
                   3784:                                               (struct lease *)0,
                   3785:                                               (struct client_state *)0,
                   3786:                                               decoded_packet -> options,
                   3787:                                               (struct option_state *)0,
                   3788:                                               (struct binding_scope **)0,
                   3789:                                               op, MDL);
                   3790:                        if (dp.len > 0)
                   3791:                                decoded_packet -> packet_type = dp.data [0];
                   3792:                        else
                   3793:                                decoded_packet -> packet_type = 0;
                   3794:                        data_string_forget (&dp, MDL);
                   3795:                }
                   3796:        }
1.1.1.1 ! misho    3797: 
        !          3798:        if (validate_packet(decoded_packet) != 0) {
        !          3799:                if (decoded_packet->packet_type)
        !          3800:                        dhcp(decoded_packet);
        !          3801:                else
        !          3802:                        bootp(decoded_packet);
        !          3803:        }
1.1       misho    3804: 
                   3805:        /* If the caller kept the packet, they'll have upped the refcnt. */
                   3806:        packet_dereference (&decoded_packet, MDL);
                   3807: 
                   3808: #if defined (DEBUG_MEMORY_LEAKAGE)
                   3809:        log_info ("generation %ld: %ld new, %ld outstanding, %ld long-term",
                   3810:                  dmalloc_generation,
                   3811:                  dmalloc_outstanding - previous_outstanding,
                   3812:                  dmalloc_outstanding, dmalloc_longterm);
                   3813: #endif
                   3814: #if defined (DEBUG_MEMORY_LEAKAGE)
                   3815:        dmalloc_dump_outstanding ();
                   3816: #endif
                   3817: #if defined (DEBUG_RC_HISTORY_EXHAUSTIVELY)
                   3818:        dump_rc_history (0);
                   3819: #endif
                   3820: }
                   3821: 
                   3822: int
                   3823: packet6_len_okay(const char *packet, int len) {
                   3824:        if (len < 1) {
                   3825:                return 0;
                   3826:        }
                   3827:        if ((packet[0] == DHCPV6_RELAY_FORW) || 
                   3828:            (packet[0] == DHCPV6_RELAY_REPL)) {
                   3829:                if (len >= offsetof(struct dhcpv6_relay_packet, options)) {
                   3830:                        return 1;
                   3831:                } else {
                   3832:                        return 0;
                   3833:                }
                   3834:        } else {
                   3835:                if (len >= offsetof(struct dhcpv6_packet, options)) {
                   3836:                        return 1;
                   3837:                } else {
                   3838:                        return 0;
                   3839:                }
                   3840:        }
                   3841: }
                   3842: 
                   3843: #ifdef DHCPv6
                   3844: void 
                   3845: do_packet6(struct interface_info *interface, const char *packet, 
                   3846:           int len, int from_port, const struct iaddr *from, 
                   3847:           isc_boolean_t was_unicast) {
                   3848:        unsigned char msg_type;
                   3849:        const struct dhcpv6_packet *msg;
                   3850:        const struct dhcpv6_relay_packet *relay; 
                   3851:        struct packet *decoded_packet;
                   3852: 
                   3853:        if (!packet6_len_okay(packet, len)) {
                   3854:                log_info("do_packet6: "
                   3855:                         "short packet from %s port %d, len %d, dropped",
                   3856:                         piaddr(*from), from_port, len);
                   3857:                return;
                   3858:        }
                   3859: 
                   3860:        decoded_packet = NULL;
                   3861:        if (!packet_allocate(&decoded_packet, MDL)) {
                   3862:                log_error("do_packet6: no memory for incoming packet.");
                   3863:                return;
                   3864:        }
                   3865: 
                   3866:        if (!option_state_allocate(&decoded_packet->options, MDL)) {
                   3867:                log_error("do_packet6: no memory for options.");
                   3868:                packet_dereference(&decoded_packet, MDL);
                   3869:                return;
                   3870:        }
                   3871: 
                   3872:        /* IPv4 information, already set to 0 */
                   3873:        /* decoded_packet->packet_type = 0; */
                   3874:        /* memset(&decoded_packet->haddr, 0, sizeof(decoded_packet->haddr)); */
                   3875:        /* decoded_packet->circuit_id = NULL; */
                   3876:        /* decoded_packet->circuit_id_len = 0; */
                   3877:        /* decoded_packet->remote_id = NULL; */
                   3878:        /* decoded_packet->remote_id_len = 0; */
                   3879:        decoded_packet->raw = (struct dhcp_packet *) packet;
                   3880:        decoded_packet->packet_length = (unsigned) len;
                   3881:        decoded_packet->client_port = from_port;
                   3882:        decoded_packet->client_addr = *from;
                   3883:        interface_reference(&decoded_packet->interface, interface, MDL);
                   3884: 
                   3885:        decoded_packet->unicast = was_unicast;
                   3886: 
                   3887:        msg_type = packet[0];
                   3888:        if ((msg_type == DHCPV6_RELAY_FORW) || 
                   3889:            (msg_type == DHCPV6_RELAY_REPL)) {
1.1.1.1 ! misho    3890:                int relaylen = (int)(offsetof(struct dhcpv6_relay_packet, options));
1.1       misho    3891:                relay = (const struct dhcpv6_relay_packet *)packet;
                   3892:                decoded_packet->dhcpv6_msg_type = relay->msg_type;
                   3893: 
                   3894:                /* relay-specific data */
                   3895:                decoded_packet->dhcpv6_hop_count = relay->hop_count;
                   3896:                memcpy(&decoded_packet->dhcpv6_link_address,
                   3897:                       relay->link_address, sizeof(relay->link_address));
                   3898:                memcpy(&decoded_packet->dhcpv6_peer_address,
                   3899:                       relay->peer_address, sizeof(relay->peer_address));
                   3900: 
                   3901:                if (!parse_option_buffer(decoded_packet->options, 
1.1.1.1 ! misho    3902:                                         relay->options, len - relaylen, 
1.1       misho    3903:                                         &dhcpv6_universe)) {
                   3904:                        /* no logging here, as parse_option_buffer() logs all
                   3905:                           cases where it fails */
                   3906:                        packet_dereference(&decoded_packet, MDL);
                   3907:                        return;
                   3908:                }
                   3909:        } else {
1.1.1.1 ! misho    3910:                int msglen = (int)(offsetof(struct dhcpv6_packet, options));
1.1       misho    3911:                msg = (const struct dhcpv6_packet *)packet;
                   3912:                decoded_packet->dhcpv6_msg_type = msg->msg_type;
                   3913: 
                   3914:                /* message-specific data */
                   3915:                memcpy(decoded_packet->dhcpv6_transaction_id, 
                   3916:                       msg->transaction_id, 
                   3917:                       sizeof(decoded_packet->dhcpv6_transaction_id));
                   3918: 
                   3919:                if (!parse_option_buffer(decoded_packet->options, 
1.1.1.1 ! misho    3920:                                         msg->options, len - msglen, 
1.1       misho    3921:                                         &dhcpv6_universe)) {
                   3922:                        /* no logging here, as parse_option_buffer() logs all
                   3923:                           cases where it fails */
                   3924:                        packet_dereference(&decoded_packet, MDL);
                   3925:                        return;
                   3926:                }
                   3927:        }
                   3928: 
                   3929:        dhcpv6(decoded_packet);
                   3930: 
                   3931:        packet_dereference(&decoded_packet, MDL);
                   3932: }
                   3933: #endif /* DHCPv6 */
                   3934: 
                   3935: int
                   3936: pretty_escape(char **dst, char *dend, const unsigned char **src,
                   3937:              const unsigned char *send)
                   3938: {
                   3939:        int count = 0;
                   3940: 
                   3941:        /* If there aren't as many bytes left as there are in the source
                   3942:         * buffer, don't even bother entering the loop.
                   3943:         */
                   3944:        if (dst == NULL || dend == NULL || src == NULL || send == NULL ||
                   3945:            *dst == NULL || *src == NULL || (*dst >= dend) || (*src > send) ||
                   3946:            ((send - *src) > (dend - *dst)))
                   3947:                return -1;
                   3948: 
                   3949:        for ( ; *src < send ; (*src)++) {
                   3950:                if (!isascii (**src) || !isprint (**src)) {
                   3951:                        /* Skip trailing NUL. */
                   3952:                        if ((*src + 1) != send || **src != '\0') {
                   3953:                                if (*dst + 4 > dend)
                   3954:                                        return -1;
                   3955: 
                   3956:                                sprintf(*dst, "\\%03o",
                   3957:                                        **src);
                   3958:                                (*dst) += 4;
                   3959:                                count += 4;
                   3960:                        }
                   3961:                } else if (**src == '"' || **src == '\'' || **src == '$' ||
                   3962:                           **src == '`' || **src == '\\' || **src == '|' ||
                   3963:                           **src == '&') {
                   3964:                        if (*dst + 2 > dend)
                   3965:                                return -1;
                   3966: 
                   3967:                        **dst = '\\';
                   3968:                        (*dst)++;
                   3969:                        **dst = **src;
                   3970:                        (*dst)++;
                   3971:                        count += 2;
                   3972:                } else {
                   3973:                        if (*dst + 1 > dend)
                   3974:                                return -1;
                   3975: 
                   3976:                        **dst = **src;
                   3977:                        (*dst)++;
                   3978:                        count++;
                   3979:                }
                   3980:        }
                   3981: 
                   3982:        return count;
                   3983: }
                   3984: 
                   3985: static int
                   3986: pretty_text(char **dst, char *dend, const unsigned char **src,
                   3987:            const unsigned char *send, int emit_quotes)
                   3988: {
                   3989:        int count;
                   3990: 
                   3991:        if (dst == NULL || dend == NULL || src == NULL || send == NULL ||
                   3992:            *dst == NULL || *src == NULL ||
                   3993:            ((*dst + (emit_quotes ? 2 : 0)) > dend) || (*src > send))
                   3994:                return -1;
                   3995: 
                   3996:        if (emit_quotes) {
                   3997:                **dst = '"';
                   3998:                (*dst)++;
                   3999:        }
                   4000: 
                   4001:        /* dend-1 leaves 1 byte for the closing quote. */
                   4002:        count = pretty_escape(dst, dend - (emit_quotes ? 1 : 0), src, send);
                   4003: 
                   4004:        if (count == -1)
                   4005:                return -1;
                   4006: 
                   4007:        if (emit_quotes && (*dst < dend)) {
                   4008:                **dst = '"';
                   4009:                (*dst)++;
                   4010: 
                   4011:                /* Includes quote prior to pretty_escape(); */
                   4012:                count += 2;
                   4013:        }
                   4014: 
                   4015:        return count;
                   4016: }
                   4017: 
                   4018: static int
                   4019: pretty_domain(char **dst, char *dend, const unsigned char **src,
                   4020:              const unsigned char *send)
                   4021: {
                   4022:        const unsigned char *tend;
                   4023:        int count = 2;
                   4024:        int tsiz, status;
                   4025: 
                   4026:        if (dst == NULL || dend == NULL || src == NULL || send == NULL ||
                   4027:            *dst == NULL || *src == NULL ||
                   4028:            ((*dst + 2) > dend) || (*src >= send))
                   4029:                return -1;
                   4030: 
                   4031:        **dst = '"';
                   4032:        (*dst)++;
                   4033: 
                   4034:        do {
                   4035:                /* Continue loop until end of src buffer. */
                   4036:                if (*src >= send)
                   4037:                        break;
                   4038: 
                   4039:                /* Consume tag size. */
                   4040:                tsiz = **src;
                   4041:                (*src)++;
                   4042: 
                   4043:                /* At root, finis. */
                   4044:                if (tsiz == 0)
                   4045:                        break;
                   4046: 
                   4047:                tend = (*src) + tsiz;
                   4048: 
                   4049:                /* If the tag exceeds the source buffer, it's illegal.
                   4050:                 * This should also trap compression pointers (which should
                   4051:                 * not be in these buffers).
                   4052:                 */
                   4053:                if (tend > send)
                   4054:                        return -1;
                   4055: 
                   4056:                /* dend-2 leaves room for a trailing dot and quote. */
                   4057:                status = pretty_escape(dst, dend-2, src, tend);
                   4058: 
                   4059:                if ((status == -1) || ((*dst + 2) > dend))
                   4060:                        return -1;
                   4061: 
                   4062:                **dst = '.';
                   4063:                (*dst)++;
                   4064:                count += status + 1;
                   4065:        }
                   4066:        while(1);
                   4067: 
                   4068:        **dst = '"';
                   4069:        (*dst)++;
                   4070: 
                   4071:        return count;
                   4072: }
                   4073: 
                   4074: /*
                   4075:  * Add the option identified with the option number and data to the
                   4076:  * options state.
                   4077:  */
                   4078: int
                   4079: add_option(struct option_state *options,
                   4080:           unsigned int option_num,
                   4081:           void *data,
                   4082:           unsigned int data_len)
                   4083: {
                   4084:        struct option_cache *oc;
                   4085:        struct option *option;
                   4086: 
                   4087:        /* INSIST(options != NULL); */
                   4088:        /* INSIST(data != NULL); */
                   4089: 
                   4090:        option = NULL;
                   4091:        if (!option_code_hash_lookup(&option, dhcp_universe.code_hash, 
                   4092:                                     &option_num, 0, MDL)) {
                   4093:                log_error("Attempting to add unknown option %d.", option_num);
                   4094:                return 0;
                   4095:        }
                   4096: 
                   4097:        oc = NULL;
                   4098:        if (!option_cache_allocate(&oc, MDL)) {
                   4099:                log_error("No memory for option cache adding %s (option %d).",
                   4100:                          option->name, option_num);
                   4101:                return 0;
                   4102:        }
                   4103: 
                   4104:        if (!make_const_data(&oc->expression, 
                   4105:                             data, 
                   4106:                             data_len,
                   4107:                             0, 
                   4108:                             0, 
                   4109:                             MDL)) {
                   4110:                log_error("No memory for constant data adding %s (option %d).",
                   4111:                          option->name, option_num);
                   4112:                option_cache_dereference(&oc, MDL);
                   4113:                return 0;
                   4114:        }
                   4115: 
                   4116:        option_reference(&(oc->option), option, MDL);
                   4117:        save_option(&dhcp_universe, options, oc);
                   4118:        option_cache_dereference(&oc, MDL);
                   4119: 
                   4120:        return 1;
                   4121: }
                   4122: 
1.1.1.1 ! misho    4123: /**
        !          4124:  *  Checks if received BOOTP/DHCPv4 packet is sane
        !          4125:  *
        !          4126:  * @param packet received, decoded packet
        !          4127:  *
        !          4128:  * @return 1 if packet is sane, 0 if it is not
        !          4129:  */
        !          4130: int validate_packet(struct packet *packet)
        !          4131: {
        !          4132:        struct option_cache *oc = NULL;
1.1       misho    4133: 
1.1.1.1 ! misho    4134:        oc = lookup_option (&dhcp_universe, packet->options,
        !          4135:                            DHO_DHCP_CLIENT_IDENTIFIER);
        !          4136:        if (oc) {
        !          4137:                /* Let's check if client-identifier is sane */
        !          4138:                if (oc->data.len == 0) {
        !          4139:                        log_debug("Dropped DHCPv4 packet with zero-length client-id");
        !          4140:                        return (0);
        !          4141: 
        !          4142:                } else if (oc->data.len == 1) {
        !          4143:                        /*
        !          4144:                         * RFC2132, section 9.14 states that minimum length of client-id
        !          4145:                         * is 2.  We will allow single-character client-ids for now (for
        !          4146:                         * backwards compatibility), but warn the user that support for
        !          4147:                         * this is against the standard.
        !          4148:                         */
        !          4149:                        log_debug("Accepted DHCPv4 packet with one-character client-id - "
        !          4150:                                "a future version of ISC DHCP will reject this");
        !          4151:                }
        !          4152:        } else {
        !          4153:                /* 
        !          4154:                 * If hlen is 0 we don't have any identifier, we warn the user
        !          4155:                 * but continue processing the packet as we can.
        !          4156:                 */
        !          4157:                if (packet->raw->hlen == 0) {
        !          4158:                        log_debug("Received DHCPv4 packet without client-id"
        !          4159:                                  " option and empty hlen field.");
        !          4160:                }
        !          4161:        }
        !          4162: 
        !          4163:        /* @todo: Add checks for other received options */
        !          4164: 
        !          4165:        return (1);
        !          4166: }

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