common/options.c

Go to the documentation of this file.
00001 /* options.c
00002 
00003    DHCP options parsing and reassembly. */
00004 
00005 /*
00006  * Copyright (c) 2004-2012,2014 by Internet Systems Consortium, Inc. ("ISC")
00007  * Copyright (c) 1995-2003 by Internet Software Consortium
00008  *
00009  * Permission to use, copy, modify, and distribute this software for any
00010  * purpose with or without fee is hereby granted, provided that the above
00011  * copyright notice and this permission notice appear in all copies.
00012  *
00013  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
00014  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
00015  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
00016  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
00017  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
00018  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
00019  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
00020  *
00021  *   Internet Systems Consortium, Inc.
00022  *   950 Charter Street
00023  *   Redwood City, CA 94063
00024  *   <info@isc.org>
00025  *   https://www.isc.org/
00026  *
00027  */
00028 
00029 #define DHCP_OPTION_DATA
00030 #include "dhcpd.h"
00031 #include <omapip/omapip_p.h>
00032 #include <limits.h>
00033 
00034 struct option *vendor_cfg_option;
00035 
00036 static int pretty_text(char **, char *, const unsigned char **,
00037                          const unsigned char *, int);
00038 static int pretty_domain(char **, char *, const unsigned char **,
00039                          const unsigned char *);
00040 static int prepare_option_buffer(struct universe *universe, struct buffer *bp,
00041                                  unsigned char *buffer, unsigned length,
00042                                  unsigned code, int terminatep,
00043                                  struct option_cache **opp);
00044 
00045 /* Parse all available options out of the specified packet. */
00046 
00047 int parse_options (packet)
00048         struct packet *packet;
00049 {
00050         struct option_cache *op = (struct option_cache *)0;
00051 
00052         /* Allocate a new option state. */
00053         if (!option_state_allocate (&packet -> options, MDL)) {
00054                 packet -> options_valid = 0;
00055                 return 0;
00056         }
00057 
00058         /* If we don't see the magic cookie, there's nothing to parse. */
00059         if (memcmp (packet -> raw -> options, DHCP_OPTIONS_COOKIE, 4)) {
00060                 packet -> options_valid = 0;
00061                 return 1;
00062         }
00063 
00064         /* Go through the options field, up to the end of the packet
00065            or the End field. */
00066         if (!parse_option_buffer (packet -> options,
00067                                   &packet -> raw -> options [4],
00068                                   (packet -> packet_length -
00069                                    DHCP_FIXED_NON_UDP - 4),
00070                                   &dhcp_universe)) {
00071 
00072                 /* STSN servers have a bug where they send a mangled
00073                    domain-name option, and whatever is beyond that in
00074                    the packet is junk.   Microsoft clients accept this,
00075                    which is probably why whoever implemented the STSN
00076                    server isn't aware of the problem yet.   To work around
00077                    this, we will accept corrupt packets from the server if
00078                    they contain a valid DHCP_MESSAGE_TYPE option, but
00079                    will not accept any corrupt client packets (the ISC DHCP
00080                    server is sufficiently widely used that it is probably
00081                    beneficial for it to be picky) and will not accept
00082                    packets whose type can't be determined. */
00083 
00084                 if ((op = lookup_option (&dhcp_universe, packet -> options,
00085                                          DHO_DHCP_MESSAGE_TYPE))) {
00086                         if (!op -> data.data ||
00087                             (op -> data.data [0] != DHCPOFFER &&
00088                              op -> data.data [0] != DHCPACK &&
00089                              op -> data.data [0] != DHCPNAK))
00090                                 return 0;
00091                 } else
00092                         return 0;
00093         }
00094 
00095         /* If we parsed a DHCP Option Overload option, parse more
00096            options out of the buffer(s) containing them. */
00097         if ((op = lookup_option (&dhcp_universe, packet -> options,
00098                                  DHO_DHCP_OPTION_OVERLOAD))) {
00099                 if (op -> data.data [0] & 1) {
00100                         if (!parse_option_buffer
00101                             (packet -> options,
00102                              (unsigned char *)packet -> raw -> file,
00103                              sizeof packet -> raw -> file,
00104                              &dhcp_universe))
00105                                 return 0;
00106                 }
00107                 if (op -> data.data [0] & 2) {
00108                         if (!parse_option_buffer
00109                             (packet -> options,
00110                              (unsigned char *)packet -> raw -> sname,
00111                              sizeof packet -> raw -> sname,
00112                              &dhcp_universe))
00113                                 return 0;
00114                 }
00115         }
00116         packet -> options_valid = 1;
00117         return 1;
00118 }
00119 
00120 /* Parse options out of the specified buffer, storing addresses of option
00121  * values in packet->options.
00122  */
00123 int parse_option_buffer (options, buffer, length, universe)
00124         struct option_state *options;
00125         const unsigned char *buffer;
00126         unsigned length;
00127         struct universe *universe;
00128 {
00129         unsigned len, offset;
00130         unsigned code;
00131         struct option_cache *op = NULL, *nop = NULL;
00132         struct buffer *bp = (struct buffer *)0;
00133         struct option *option = NULL;
00134         char *reason = "general failure";
00135 
00136         if (!buffer_allocate (&bp, length, MDL)) {
00137                 log_error ("no memory for option buffer.");
00138                 return 0;
00139         }
00140         memcpy (bp -> data, buffer, length);
00141 
00142         for (offset = 0;
00143              (offset + universe->tag_size) <= length &&
00144              (code = universe->get_tag(buffer + offset)) != universe->end; ) {
00145                 offset += universe->tag_size;
00146 
00147                 /* Pad options don't have a length - just skip them. */
00148                 if (code == DHO_PAD)
00149                         continue;
00150 
00151                 /* Don't look for length if the buffer isn't that big. */
00152                 if ((offset + universe->length_size) > length) {
00153                         reason = "code tag at end of buffer - missing "
00154                                  "length field";
00155                         goto bogus;
00156                 }
00157 
00158                 /* All other fields (except PAD and END handled above)
00159                  * have a length field, unless it's a DHCPv6 zero-length
00160                  * options space (eg any of the enterprise-id'd options).
00161                  *
00162                  * Zero-length-size option spaces basically consume the
00163                  * entire options buffer, so have at it.
00164                  */
00165                 if (universe->get_length != NULL)
00166                         len = universe->get_length(buffer + offset);
00167                 else if (universe->length_size == 0)
00168                         len = length - universe->tag_size;
00169                 else {
00170                         log_fatal("Improperly configured option space(%s): "
00171                                   "may not have a nonzero length size "
00172                                   "AND a NULL get_length function.",
00173                                   universe->name);
00174 
00175                         /* Silence compiler warnings. */
00176                         return 0;
00177                 }
00178 
00179                 offset += universe->length_size;
00180 
00181                 option_code_hash_lookup(&option, universe->code_hash, &code,
00182                                         0, MDL);
00183 
00184                 /* If the length is outrageous, the options are bad. */
00185                 if (offset + len > length) {
00186                         reason = "option length exceeds option buffer length";
00187                       bogus:
00188                         log_error("parse_option_buffer: malformed option "
00189                                   "%s.%s (code %u): %s.", universe->name,
00190                                   option ? option->name : "<unknown>",
00191                                   code, reason);
00192                         buffer_dereference (&bp, MDL);
00193                         return 0;
00194                 }
00195 
00196                 /* If the option contains an encapsulation, parse it.   If
00197                    the parse fails, or the option isn't an encapsulation (by
00198                    far the most common case), or the option isn't entirely
00199                    an encapsulation, keep the raw data as well. */
00200                 if (!(option &&
00201                       (option->format[0] == 'e' ||
00202                        option->format[0] == 'E') &&
00203                       (parse_encapsulated_suboptions(options, option,
00204                                                      bp->data + offset, len,
00205                                                      universe, NULL)))) {
00206                         op = lookup_option(universe, options, code);
00207 
00208                         if (op != NULL && universe->concat_duplicates) {
00209                                 struct data_string new;
00210                                 memset(&new, 0, sizeof new);
00211                                 if (!buffer_allocate(&new.buffer,
00212                                                      op->data.len + len,
00213                                                      MDL)) {
00214                                         log_error("parse_option_buffer: "
00215                                                   "No memory.");
00216                                         buffer_dereference(&bp, MDL);
00217                                         return 0;
00218                                 }
00219                                 /* Copy old option to new data object. */
00220                                 memcpy(new.buffer->data, op->data.data,
00221                                         op->data.len);
00222                                 /* Concat new option behind old. */
00223                                 memcpy(new.buffer->data + op->data.len,
00224                                         bp->data + offset, len);
00225                                 new.len = op->data.len + len;
00226                                 new.data = new.buffer->data;
00227                                 /* Save new concat'd object. */
00228                                 data_string_forget(&op->data, MDL);
00229                                 data_string_copy(&op->data, &new, MDL);
00230                                 data_string_forget(&new, MDL);
00231                         } else if (op != NULL) {
00232                                 /* We must append this statement onto the
00233                                  * end of the list.
00234                                  */
00235                                 while (op->next != NULL)
00236                                         op = op->next;
00237 
00238                                 if (!option_cache_allocate(&nop, MDL)) {
00239                                         log_error("parse_option_buffer: "
00240                                                   "No memory.");
00241                                         buffer_dereference(&bp, MDL);
00242                                         return 0;
00243                                 }
00244 
00245                                 option_reference(&nop->option, op->option, MDL);
00246 
00247                                 nop->data.buffer = NULL;
00248                                 buffer_reference(&nop->data.buffer, bp, MDL);
00249                                 nop->data.data = bp->data + offset;
00250                                 nop->data.len = len;
00251 
00252                                 option_cache_reference(&op->next, nop, MDL);
00253                                 option_cache_dereference(&nop, MDL);
00254                         } else {
00255                                 if (save_option_buffer(universe, options, bp,
00256                                                        bp->data + offset, len,
00257                                                        code, 1) == 0) {
00258                                         log_error("parse_option_buffer: "
00259                                                   "save_option_buffer failed");
00260                                         buffer_dereference(&bp, MDL);
00261                                         return 0;
00262                                 }
00263                         }
00264                 }
00265                 option_dereference(&option, MDL);
00266                 offset += len;
00267         }
00268         buffer_dereference (&bp, MDL);
00269         return 1;
00270 }
00271 
00272 /* If an option in an option buffer turns out to be an encapsulation,
00273    figure out what to do.   If we don't know how to de-encapsulate it,
00274    or it's not well-formed, return zero; otherwise, return 1, indicating
00275    that we succeeded in de-encapsulating it. */
00276 
00277 struct universe *find_option_universe (struct option *eopt, const char *uname)
00278 {
00279         int i;
00280         char *s, *t;
00281         struct universe *universe = (struct universe *)0;
00282 
00283         /* Look for the E option in the option format. */
00284         s = strchr (eopt -> format, 'E');
00285         if (!s) {
00286                 log_error ("internal encapsulation format error 1.");
00287                 return 0;
00288         }
00289         /* Look for the universe name in the option format. */
00290         t = strchr (++s, '.');
00291         /* If there was no trailing '.', or there's something after the
00292            trailing '.', the option is bogus and we can't use it. */
00293         if (!t || t [1]) {
00294                 log_error ("internal encapsulation format error 2.");
00295                 return 0;
00296         }
00297         if (t == s && uname) {
00298                 for (i = 0; i < universe_count; i++) {
00299                         if (!strcmp (universes [i] -> name, uname)) {
00300                                 universe = universes [i];
00301                                 break;
00302                         }
00303                 }
00304         } else if (t != s) {
00305                 for (i = 0; i < universe_count; i++) {
00306                         if (strlen (universes [i] -> name) == t - s &&
00307                             !memcmp (universes [i] -> name,
00308                                      s, (unsigned)(t - s))) {
00309                                 universe = universes [i];
00310                                 break;
00311                         }
00312                 }
00313         }
00314         return universe;
00315 }
00316 
00317 /* If an option in an option buffer turns out to be an encapsulation,
00318    figure out what to do.   If we don't know how to de-encapsulate it,
00319    or it's not well-formed, return zero; otherwise, return 1, indicating
00320    that we succeeded in de-encapsulating it. */
00321 
00322 int parse_encapsulated_suboptions (struct option_state *options,
00323                                    struct option *eopt,
00324                                    const unsigned char *buffer,
00325                                    unsigned len, struct universe *eu,
00326                                    const char *uname)
00327 {
00328         int i;
00329         struct universe *universe = find_option_universe (eopt, uname);
00330 
00331         /* If we didn't find the universe, we can't do anything with it
00332            right now (e.g., we can't decode vendor options until we've
00333            decoded the packet and executed the scopes that it matches). */
00334         if (!universe)
00335                 return 0;
00336                 
00337         /* If we don't have a decoding function for it, we can't decode
00338            it. */
00339         if (!universe -> decode)
00340                 return 0;
00341 
00342         i = (*universe -> decode) (options, buffer, len, universe);
00343 
00344         /* If there is stuff before the suboptions, we have to keep it. */
00345         if (eopt -> format [0] != 'E')
00346                 return 0;
00347         /* Otherwise, return the status of the decode function. */
00348         return i;
00349 }
00350 
00351 int fqdn_universe_decode (struct option_state *options,
00352                           const unsigned char *buffer,
00353                           unsigned length, struct universe *u)
00354 {
00355         struct buffer *bp = (struct buffer *)0;
00356 
00357         /* FQDN options have to be at least four bytes long. */
00358         if (length < 3)
00359                 return 0;
00360 
00361         /* Save the contents of the option in a buffer. */
00362         if (!buffer_allocate (&bp, length + 4, MDL)) {
00363                 log_error ("no memory for option buffer.");
00364                 return 0;
00365         }
00366         memcpy (&bp -> data [3], buffer + 1, length - 1);
00367 
00368         if (buffer [0] & 4)     /* encoded */
00369                 bp -> data [0] = 1;
00370         else
00371                 bp -> data [0] = 0;
00372         if (!save_option_buffer(&fqdn_universe, options, bp,
00373                                 bp->data, 1, FQDN_ENCODED, 0)) {
00374               bad:
00375                 buffer_dereference (&bp, MDL);
00376                 return 0;
00377         }
00378 
00379         if (buffer [0] & 1)     /* server-update */
00380                 bp -> data [2] = 1;
00381         else
00382                 bp -> data [2] = 0;
00383         if (buffer [0] & 2)     /* no-client-update */
00384                 bp -> data [1] = 1;
00385         else
00386                 bp -> data [1] = 0;
00387 
00388         /* XXX Ideally we should store the name in DNS format, so if the
00389            XXX label isn't in DNS format, we convert it to DNS format,
00390            XXX rather than converting labels specified in DNS format to
00391            XXX the plain ASCII representation.   But that's hard, so
00392            XXX not now. */
00393 
00394         /* Not encoded using DNS format? */
00395         if (!bp -> data [0]) {
00396                 unsigned i;
00397 
00398                 /* Some broken clients NUL-terminate this option. */
00399                 if (buffer [length - 1] == 0) {
00400                         --length;
00401                         bp -> data [1] = 1;
00402                 }
00403 
00404                 /* Determine the length of the hostname component of the
00405                    name.  If the name contains no '.' character, it
00406                    represents a non-qualified label. */
00407                 for (i = 3; i < length && buffer [i] != '.'; i++);
00408                 i -= 3;
00409 
00410                 /* Note: If the client sends a FQDN, the first '.' will
00411                    be used as a NUL terminator for the hostname. */
00412                 if (i && (!save_option_buffer(&fqdn_universe, options, bp,
00413                                               &bp->data[5], i,
00414                                               FQDN_HOSTNAME, 0)))
00415                         goto bad;
00416                 /* Note: If the client sends a single label, the
00417                    FQDN_DOMAINNAME option won't be set. */
00418                 if (length > 4 + i &&
00419                     (!save_option_buffer(&fqdn_universe, options, bp,
00420                                          &bp -> data[6 + i], length - 4 - i,
00421                                          FQDN_DOMAINNAME, 1)))
00422                         goto bad;
00423                 /* Also save the whole name. */
00424                 if (length > 3) {
00425                         if (!save_option_buffer(&fqdn_universe, options, bp,
00426                                                 &bp -> data [5], length - 3,
00427                                                 FQDN_FQDN, 1))
00428                                 goto bad;
00429                 }
00430         } else {
00431                 unsigned len;
00432                 unsigned total_len = 0;
00433                 unsigned first_len = 0;
00434                 int terminated = 0;
00435                 unsigned char *s;
00436 
00437                 s = &bp -> data[5];
00438 
00439                 while (s < &bp -> data[0] + length + 2) {
00440                         len = *s;
00441                         if (len > 63) {
00442                                 log_info ("fancy bits in fqdn option");
00443                                 return 0;
00444                         }       
00445                         if (len == 0) {
00446                                 terminated = 1;
00447                                 break;
00448                         }
00449                         if (s + len > &bp -> data [0] + length + 3) {
00450                                 log_info ("fqdn tag longer than buffer");
00451                                 return 0;
00452                         }
00453 
00454                         if (first_len == 0) {
00455                                 first_len = len;
00456                         }
00457 
00458                         *s = '.';
00459                         s += len + 1;
00460                         total_len += len + 1;
00461                 }
00462 
00463                 /* We wind up with a length that's one too many because
00464                    we shouldn't increment for the last label, but there's
00465                    no way to tell we're at the last label until we exit
00466                    the loop.   :'*/
00467                 if (total_len > 0)
00468                         total_len--;
00469 
00470                 if (!terminated) {
00471                         first_len = total_len;
00472                 }
00473 
00474                 if (first_len > 0 &&
00475                     !save_option_buffer(&fqdn_universe, options, bp,
00476                                         &bp -> data[6], first_len,
00477                                         FQDN_HOSTNAME, 0))
00478                         goto bad;
00479                 if (total_len > 0 && first_len != total_len) {
00480                         if (!save_option_buffer(&fqdn_universe, options, bp,
00481                                                 &bp->data[6 + first_len],
00482                                                 total_len - first_len,
00483                                                 FQDN_DOMAINNAME, 1))
00484                                 goto bad;
00485                 }
00486                 if (total_len > 0)
00487                         if (!save_option_buffer (&fqdn_universe, options, bp,
00488                                                  &bp -> data [6], total_len,
00489                                                  FQDN_FQDN, 1))
00490                                 goto bad;
00491         }
00492 
00493         if (!save_option_buffer (&fqdn_universe, options, bp,
00494                                  &bp -> data [1], 1,
00495                                  FQDN_NO_CLIENT_UPDATE, 0))
00496             goto bad;
00497         if (!save_option_buffer (&fqdn_universe, options, bp,
00498                                  &bp -> data [2], 1,
00499                                  FQDN_SERVER_UPDATE, 0))
00500                 goto bad;
00501 
00502         if (!save_option_buffer (&fqdn_universe, options, bp,
00503                                  &bp -> data [3], 1,
00504                                  FQDN_RCODE1, 0))
00505                 goto bad;
00506         if (!save_option_buffer (&fqdn_universe, options, bp,
00507                                  &bp -> data [4], 1,
00508                                  FQDN_RCODE2, 0))
00509                 goto bad;
00510 
00511         buffer_dereference (&bp, MDL);
00512         return 1;
00513 }
00514 
00515 /*
00516  * Load all options into a buffer, and then split them out into the three
00517  * separate fields in the dhcp packet (options, file, and sname) where
00518  * options can be stored.
00519  *
00520  * returns 0 on error, length of packet on success
00521  */
00522 int
00523 cons_options(struct packet *inpacket, struct dhcp_packet *outpacket,
00524              struct lease *lease, struct client_state *client_state,
00525              int mms, struct option_state *in_options,
00526              struct option_state *cfg_options,
00527              struct binding_scope **scope,
00528              int overload_avail, int terminate, int bootpp,
00529              struct data_string *prl, const char *vuname)
00530 {
00531 #define PRIORITY_COUNT 300
00532         unsigned priority_list[PRIORITY_COUNT];
00533         int priority_len;
00534         unsigned char buffer[4096], agentopts[1024];
00535         unsigned index = 0;
00536         unsigned mb_size = 0, mb_max = 0;
00537         unsigned option_size = 0, agent_size = 0;
00538         unsigned length;
00539         int i;
00540         struct option_cache *op;
00541         struct data_string ds;
00542         pair pp, *hash;
00543         int overload_used = 0;
00544         int of1 = 0, of2 = 0;
00545 
00546         memset(&ds, 0, sizeof ds);
00547 
00548         /*
00549          * If there's a Maximum Message Size option in the incoming packet
00550          * and no alternate maximum message size has been specified, or
00551          * if the one specified in the packet is shorter than the
00552          * alternative, take the one in the packet.
00553          */
00554 
00555         if (inpacket &&
00556             (op = lookup_option(&dhcp_universe, inpacket->options,
00557                                 DHO_DHCP_MAX_MESSAGE_SIZE)) &&
00558             (evaluate_option_cache(&ds, inpacket, lease,
00559                                    client_state, in_options,
00560                                    cfg_options, scope, op, MDL) != 0)) {
00561                 if (ds.len >= sizeof (u_int16_t)) {
00562                         i = getUShort(ds.data);
00563                         if(!mms || (i < mms))
00564                                 mms = i;
00565                 }
00566                 data_string_forget(&ds, MDL);
00567         }
00568 
00569         /*
00570          * If the client has provided a maximum DHCP message size,
00571          * use that, up to the MTU limit.  Otherwise, if it's BOOTP,
00572          * only 64 bytes; otherwise use up to the minimum IP MTU size
00573          * (576 bytes).
00574          *
00575          * XXX if a BOOTP client specifies a max message size, we will
00576          * honor it.
00577          */
00578         if (mms) {
00579                 if (mms < DHCP_MTU_MIN)
00580                         /* Enforce minimum packet size, per RFC 2132 */
00581                         mb_size = DHCP_MIN_OPTION_LEN;
00582                 else if (mms > DHCP_MTU_MAX)
00583                         /*
00584                          * TODO: Packets longer than 1500 bytes really
00585                          * should be allowed, but it requires upstream
00586                          * changes to the way the packet is allocated.  For
00587                          * now, we forbid them.  They won't be needed very
00588                          * often anyway.
00589                          */
00590                         mb_size = DHCP_MAX_OPTION_LEN;
00591                 else
00592                         mb_size = mms - DHCP_FIXED_LEN;
00593         } else if (bootpp) {
00594                 mb_size = 64;
00595                 if (inpacket != NULL &&
00596                     (inpacket->packet_length >= 64 + DHCP_FIXED_NON_UDP))
00597                         mb_size = inpacket->packet_length - DHCP_FIXED_NON_UDP;
00598         } else
00599                 mb_size = DHCP_MIN_OPTION_LEN;
00600 
00601         /*
00602          * If answering a client message, see whether any relay agent
00603          * options were included with the message.  If so, save them
00604          * to copy back in later, and make space in the main buffer
00605          * to accommodate them
00606          */
00607         if (client_state == NULL) {
00608                 priority_list[0] = DHO_DHCP_AGENT_OPTIONS;
00609                 priority_len = 1;
00610                 agent_size = store_options(NULL, agentopts, 0,
00611                                            sizeof(agentopts),
00612                                            inpacket, lease, client_state,
00613                                            in_options, cfg_options, scope,
00614                                            priority_list, priority_len,
00615                                            0, 0, 0, NULL);
00616 
00617                 mb_size += agent_size;
00618                 if (mb_size > DHCP_MAX_OPTION_LEN)
00619                         mb_size = DHCP_MAX_OPTION_LEN;
00620         }
00621 
00622         /*
00623          * Set offsets for buffer data to be copied into filename
00624          * and servername fields 
00625          */
00626         mb_max = mb_size;
00627 
00628         if (overload_avail & 1) {
00629                 of1 = mb_max;
00630                 mb_max += DHCP_FILE_LEN;
00631         }
00632 
00633         if (overload_avail & 2) {
00634                 of2 = mb_max;
00635                 mb_max += DHCP_SNAME_LEN;
00636         }
00637                 
00638         /*
00639          * Preload the option priority list with protocol-mandatory options.
00640          * This effectively gives these options the highest priority.
00641          * This provides the order for any available options, the option
00642          * must be in the option cache in order to actually be included.
00643          */
00644         priority_len = 0;
00645         priority_list[priority_len++] = DHO_DHCP_MESSAGE_TYPE;
00646         priority_list[priority_len++] = DHO_DHCP_SERVER_IDENTIFIER;
00647         priority_list[priority_len++] = DHO_DHCP_LEASE_TIME;
00648         priority_list[priority_len++] = DHO_DHCP_RENEWAL_TIME;
00649         priority_list[priority_len++] = DHO_DHCP_REBINDING_TIME;
00650         priority_list[priority_len++] = DHO_DHCP_MESSAGE;
00651         priority_list[priority_len++] = DHO_DHCP_REQUESTED_ADDRESS;
00652         priority_list[priority_len++] = DHO_ASSOCIATED_IP;
00653 
00654         if (prl != NULL && prl->len > 0) {
00655                 if ((op = lookup_option(&dhcp_universe, cfg_options,
00656                                          DHO_SUBNET_SELECTION))) {
00657                         if (priority_len < PRIORITY_COUNT)
00658                                 priority_list[priority_len++] =
00659                                         DHO_SUBNET_SELECTION;
00660                 }
00661 
00662                 data_string_truncate(prl, (PRIORITY_COUNT - priority_len));
00663 
00664                 /*
00665                  * Copy the client's PRL onto the priority_list after our high
00666                  * priority header.
00667                  */
00668                 for (i = 0; i < prl->len; i++) {
00669                         /*
00670                          * Prevent client from changing order of delivery
00671                          * of relay agent information option.
00672                          */
00673                         if (prl->data[i] != DHO_DHCP_AGENT_OPTIONS)
00674                                 priority_list[priority_len++] = prl->data[i];
00675                 }
00676 
00677                 /*
00678                  * If the client doesn't request the FQDN option explicitly,
00679                  * to indicate priority, consider it lowest priority.  Fit
00680                  * in the packet if there is space.  Note that the option
00681                  * may only be included if the client supplied one.
00682                  */
00683                 if ((inpacket != NULL) && (priority_len < PRIORITY_COUNT) &&
00684                     (lookup_option(&fqdn_universe, inpacket->options,
00685                                    FQDN_ENCODED) != NULL))
00686                         priority_list[priority_len++] = DHO_FQDN;
00687 
00688                 /*
00689                  * Some DHCP Servers will give the subnet-mask option if
00690                  * it is not on the parameter request list - so some client
00691                  * implementations have come to rely on this - so we will
00692                  * also make sure we supply this, at lowest priority.
00693                  *
00694                  * This is only done in response to DHCPDISCOVER or
00695                  * DHCPREQUEST messages, to avoid providing the option on
00696                  * DHCPINFORM or DHCPLEASEQUERY responses (if the client
00697                  * didn't request it).
00698                  */
00699                 if ((inpacket != NULL) && (priority_len < PRIORITY_COUNT) &&
00700                     ((inpacket->packet_type == DHCPDISCOVER) ||
00701                      (inpacket->packet_type == DHCPREQUEST)))
00702                         priority_list[priority_len++] = DHO_SUBNET_MASK;
00703         } else {
00704                 /*
00705                  * First, hardcode some more options that ought to be
00706                  * sent first...these are high priority to have in the
00707                  * packet.
00708                  */
00709                 priority_list[priority_len++] = DHO_SUBNET_MASK;
00710                 if (lookup_option(&dhcp_universe, cfg_options,
00711                                                         DHO_CLASSLESS_STATIC_ROUTES))
00712                         priority_list[priority_len++] = DHO_CLASSLESS_STATIC_ROUTES;
00713                 else
00714                         priority_list[priority_len++] = DHO_ROUTERS;
00715                 priority_list[priority_len++] = DHO_DOMAIN_NAME_SERVERS;
00716                 priority_list[priority_len++] = DHO_HOST_NAME;
00717                 priority_list[priority_len++] = DHO_FQDN;
00718 
00719                 /*
00720                  * Append a list of the standard DHCP options from the
00721                  * standard DHCP option space.  Actually, if a site
00722                  * option space hasn't been specified, we wind up
00723                  * treating the dhcp option space as the site option
00724                  * space, and the first for loop is skipped, because
00725                  * it's slightly more general to do it this way,
00726                  * taking the 1Q99 DHCP futures work into account.
00727                  */
00728                 if (cfg_options->site_code_min) {
00729                     for (i = 0; i < OPTION_HASH_SIZE; i++) {
00730                         hash = cfg_options->universes[dhcp_universe.index];
00731                         if (hash) {
00732                             for (pp = hash[i]; pp; pp = pp->cdr) {
00733                                 op = (struct option_cache *)(pp->car);
00734                                 if (op->option->code <
00735                                      cfg_options->site_code_min &&
00736                                     priority_len < PRIORITY_COUNT &&
00737                                     op->option->code != DHO_DHCP_AGENT_OPTIONS)
00738                                         priority_list[priority_len++] =
00739                                                 op->option->code;
00740                             }
00741                         }
00742                     }
00743                 }
00744 
00745                 /*
00746                  * Now cycle through the site option space, or if there
00747                  * is no site option space, we'll be cycling through the
00748                  * dhcp option space.
00749                  */
00750                 for (i = 0; i < OPTION_HASH_SIZE; i++) {
00751                     hash = cfg_options->universes[cfg_options->site_universe];
00752                     if (hash != NULL)
00753                         for (pp = hash[i]; pp; pp = pp->cdr) {
00754                                 op = (struct option_cache *)(pp->car);
00755                                 if (op->option->code >=
00756                                      cfg_options->site_code_min &&
00757                                     priority_len < PRIORITY_COUNT &&
00758                                     op->option->code != DHO_DHCP_AGENT_OPTIONS)
00759                                         priority_list[priority_len++] =
00760                                                 op->option->code;
00761                         }
00762                 }
00763 
00764                 /*
00765                  * Put any spaces that are encapsulated on the list,
00766                  * sort out whether they contain values later.
00767                  */
00768                 for (i = 0; i < cfg_options->universe_count; i++) {
00769                     if (universes[i]->enc_opt &&
00770                         priority_len < PRIORITY_COUNT &&
00771                         universes[i]->enc_opt->universe == &dhcp_universe) {
00772                             if (universes[i]->enc_opt->code !=
00773                                 DHO_DHCP_AGENT_OPTIONS)
00774                                     priority_list[priority_len++] =
00775                                             universes[i]->enc_opt->code;
00776                     }
00777                 }
00778 
00779                 /*
00780                  * The vendor option space can't stand on its own, so always
00781                  * add it to the list.
00782                  */
00783                 if (priority_len < PRIORITY_COUNT)
00784                         priority_list[priority_len++] =
00785                                 DHO_VENDOR_ENCAPSULATED_OPTIONS;
00786         }
00787 
00788         /* Put the cookie up front... */
00789         memcpy(buffer, DHCP_OPTIONS_COOKIE, 4);
00790         index += 4;
00791 
00792         /* Copy the options into the big buffer... */
00793         option_size = store_options(&overload_used, buffer, index, mb_max,
00794                                     inpacket, lease, client_state,
00795                                     in_options, cfg_options, scope,
00796                                     priority_list, priority_len,
00797                                     of1, of2, terminate, vuname);
00798 
00799         /* If store_options() failed */
00800         if (option_size == 0)
00801                 return 0;
00802 
00803         /* How much was stored in the main buffer? */
00804         index += option_size;
00805 
00806         /*
00807          * If we're going to have to overload, store the overload
00808          * option first.
00809          */
00810         if (overload_used) {
00811                 if (mb_size - agent_size - index < 3)
00812                         return 0;
00813 
00814                 buffer[index++] = DHO_DHCP_OPTION_OVERLOAD;
00815                 buffer[index++] = 1;
00816                 buffer[index++] = overload_used;
00817 
00818                 if (overload_used & 1)
00819                         memcpy(outpacket->file, &buffer[of1], DHCP_FILE_LEN);
00820 
00821                 if (overload_used & 2)
00822                         memcpy(outpacket->sname, &buffer[of2], DHCP_SNAME_LEN);
00823         }
00824 
00825         /* Now copy in preserved agent options, if any */
00826         if (agent_size) {
00827                 if (mb_size - index >= agent_size) {
00828                         memcpy(&buffer[index], agentopts, agent_size);
00829                         index += agent_size;
00830                 } else
00831                         log_error("Unable to store relay agent information "
00832                                   "in reply packet.");
00833         }
00834 
00835         /* Tack a DHO_END option onto the packet if we need to. */
00836         if (index < mb_size)
00837                 buffer[index++] = DHO_END;
00838 
00839         /* Copy main buffer into the options buffer of the packet */
00840         memcpy(outpacket->options, buffer, index);
00841 
00842         /* Figure out the length. */
00843         length = DHCP_FIXED_NON_UDP + index;
00844         return length;
00845 }
00846 
00847 /*
00848  * XXX: We currently special case collecting VSIO options.
00849  *      We should be able to handle this in a more generic fashion, by
00850  *      including any encapsulated options that are present and desired.
00851  *      This will look something like the VSIO handling VSIO code.
00852  *      We may also consider handling the ORO-like options within
00853  *      encapsulated spaces.
00854  */
00855 
00856 struct vsio_state {
00857         char *buf;
00858         int buflen;
00859         int bufpos;
00860 };
00861 
00862 static void
00863 vsio_options(struct option_cache *oc,
00864              struct packet *packet,
00865              struct lease *dummy_lease, 
00866              struct client_state *dummy_client_state,
00867              struct option_state *dummy_opt_state,
00868              struct option_state *opt_state,
00869              struct binding_scope **dummy_binding_scope,
00870              struct universe *universe, 
00871              void *void_vsio_state) {
00872         struct vsio_state *vs = (struct vsio_state *)void_vsio_state;
00873         struct data_string ds;
00874         int total_len;
00875 
00876         memset(&ds, 0, sizeof(ds));
00877         if (evaluate_option_cache(&ds, packet, NULL,
00878                                   NULL, opt_state, NULL, 
00879                                   &global_scope, oc, MDL)) {
00880                 total_len = ds.len + universe->tag_size + universe->length_size;
00881                 if (total_len <= (vs->buflen - vs->bufpos)) {
00882                         if (universe->tag_size == 1) {
00883                                 vs->buf[vs->bufpos++] = oc->option->code;
00884                         } else if (universe->tag_size == 2) {
00885                                 putUShort((unsigned char *)vs->buf+vs->bufpos,
00886                                           oc->option->code);
00887                                 vs->bufpos += 2;
00888                         } else if (universe->tag_size == 4) {
00889                                 putULong((unsigned char *)vs->buf+vs->bufpos,
00890                                          oc->option->code);
00891                                 vs->bufpos += 4;
00892                         }
00893                         if (universe->length_size == 1) {
00894                                 vs->buf[vs->bufpos++] = ds.len;
00895                         } else if (universe->length_size == 2) {
00896                                 putUShort((unsigned char *)vs->buf+vs->bufpos, 
00897                                           ds.len);
00898                                 vs->bufpos += 2;
00899                         } else if (universe->length_size == 4) {
00900                                 putULong((unsigned char *)vs->buf+vs->bufpos, 
00901                                          ds.len);
00902                                 vs->bufpos += 4;
00903                         }
00904                         memcpy(vs->buf + vs->bufpos, ds.data, ds.len);
00905                         vs->bufpos += ds.len;
00906                 } else {
00907                         log_debug("No space for option %d in VSIO space %s.",
00908                                 oc->option->code, universe->name);
00909                 }
00910                 data_string_forget(&ds, MDL);
00911         } else {
00912                 log_error("Error evaluating option %d in VSIO space %s.",
00913                         oc->option->code, universe->name);
00914         }
00915 }
00916 
00917 /*
00918  * Stores the options from the DHCPv6 universe into the buffer given.
00919  *
00920  * Required options are given as a 0-terminated list of option codes.
00921  * Once those are added, the ORO is consulted.
00922  */
00923 
00924 int
00925 store_options6(char *buf, int buflen, 
00926                struct option_state *opt_state, 
00927                struct packet *packet,
00928                const int *required_opts,
00929                struct data_string *oro) {
00930         int i, j;
00931         struct option_cache *oc;
00932         struct option *o;
00933         struct data_string ds;
00934         int bufpos;
00935         int oro_size;
00936         u_int16_t code;
00937         int in_required_opts;
00938         int vsio_option_code;
00939         int vsio_wanted;
00940         struct vsio_state vs;
00941         unsigned char *tmp;
00942 
00943         bufpos = 0;
00944         vsio_wanted = 0;
00945 
00946         /*
00947          * Find the option code for the VSIO universe.
00948          */
00949         vsio_option_code = 0;
00950         o = vsio_universe.enc_opt;
00951         while (o != NULL) { 
00952                 if (o->universe == &dhcpv6_universe) {
00953                         vsio_option_code = o->code;
00954                         break;
00955                 } 
00956                 o = o->universe->enc_opt;
00957         }
00958         if (vsio_option_code == 0) {
00959                 log_fatal("No VSIO option code found.");
00960         }
00961 
00962         if (required_opts != NULL) {
00963                 for (i=0; required_opts[i] != 0; i++) {
00964                         if (required_opts[i] == vsio_option_code) {
00965                                 vsio_wanted = 1;
00966                         }
00967 
00968                         oc = lookup_option(&dhcpv6_universe, 
00969                                            opt_state, required_opts[i]);
00970                         if (oc == NULL) {
00971                                 continue;
00972                         }
00973                         memset(&ds, 0, sizeof(ds));
00974                         for (; oc != NULL ; oc = oc->next) {
00975                                 if (evaluate_option_cache(&ds, packet, NULL,
00976                                                           NULL, opt_state,
00977                                                           NULL, &global_scope,
00978                                                           oc, MDL)) {
00979                                         if ((ds.len + 4) <=
00980                                             (buflen - bufpos)) {
00981                                                 tmp = (unsigned char *)buf;
00982                                                 tmp += bufpos;
00983                                                 /* option tag */
00984                                                 putUShort(tmp,
00985                                                           required_opts[i]);
00986                                                 /* option length */
00987                                                 putUShort(tmp+2, ds.len);
00988                                                 /* option data */
00989                                                 memcpy(tmp+4, ds.data, ds.len);
00990                                                 /* update position */
00991                                                 bufpos += (4 + ds.len);
00992                                         } else {
00993                                                 log_debug("No space for "
00994                                                           "option %d",
00995                                                           required_opts[i]);
00996                                         }
00997                                         data_string_forget(&ds, MDL);
00998                                 } else {
00999                                         log_error("Error evaluating option %d",
01000                                                 required_opts[i]);
01001                                 }
01002                         }
01003                 }
01004         }
01005 
01006         if (oro == NULL) {
01007                 oro_size = 0;
01008         } else {
01009                 oro_size = oro->len / 2;
01010         }
01011         for (i=0; i<oro_size; i++) {
01012                 memcpy(&code, oro->data+(i*2), 2);
01013                 code = ntohs(code);
01014 
01015                 /* 
01016                  * See if we've already included this option because
01017                  * it is required.
01018                  */
01019                 in_required_opts = 0;
01020                 if (required_opts != NULL) {
01021                         for (j=0; required_opts[j] != 0; j++) {
01022                                 if (required_opts[j] == code) {
01023                                         in_required_opts = 1;
01024                                         break;
01025                                 }
01026                         }
01027                 }
01028                 if (in_required_opts) {
01029                         continue;
01030                 }
01031 
01032                 /*
01033                  * See if this is the VSIO option.
01034                  */
01035                 if (code == vsio_option_code) {
01036                         vsio_wanted = 1;
01037                 }
01038 
01039                 /* 
01040                  * Not already added, find this option.
01041                  */
01042                 oc = lookup_option(&dhcpv6_universe, opt_state, code);
01043                 memset(&ds, 0, sizeof(ds));
01044                 for (; oc != NULL ; oc = oc->next) {
01045                         if (evaluate_option_cache(&ds, packet, NULL, NULL,
01046                                                   opt_state, NULL,
01047                                                   &global_scope, oc, MDL)) {
01048                                 if ((ds.len + 4) <= (buflen - bufpos)) {
01049                                         tmp = (unsigned char *)buf + bufpos;
01050                                         /* option tag */
01051                                         putUShort(tmp, code);
01052                                         /* option length */
01053                                         putUShort(tmp+2, ds.len);
01054                                         /* option data */
01055                                         memcpy(tmp+4, ds.data, ds.len);
01056                                         /* update position */
01057                                         bufpos += (4 + ds.len);
01058                                 } else {
01059                                         log_debug("No space for option %d",
01060                                                   code);
01061                                 }
01062                                 data_string_forget(&ds, MDL);
01063                         } else {
01064                                 log_error("Error evaluating option %d", code);
01065                         }
01066                 }
01067         }
01068 
01069         if (vsio_wanted) {
01070                 for (i=0; i < opt_state->universe_count; i++) {
01071                         if (opt_state->universes[i] != NULL) {
01072                                 o = universes[i]->enc_opt;
01073                                 if ((o != NULL) && 
01074                                     (o->universe == &vsio_universe)) {
01075                                         /*
01076                                          * Add the data from this VSIO option.
01077                                          */
01078                                         vs.buf = buf;
01079                                         vs.buflen = buflen;
01080                                         vs.bufpos = bufpos+8;
01081                                         option_space_foreach(packet, NULL,
01082                                                              NULL, 
01083                                                              NULL, opt_state,
01084                                                              NULL, 
01085                                                              universes[i], 
01086                                                              (void *)&vs,
01087                                                              vsio_options);
01088 
01089                                         /* 
01090                                          * If there was actually data here,
01091                                          * add the "header".
01092                                          */
01093                                         if (vs.bufpos > bufpos+8) {
01094                                                 tmp = (unsigned char *)buf +
01095                                                       bufpos;
01096                                                 putUShort(tmp,
01097                                                           vsio_option_code);
01098                                                 putUShort(tmp+2,
01099                                                           vs.bufpos-bufpos-4);
01100                                                 putULong(tmp+4, o->code);
01101 
01102                                                 bufpos = vs.bufpos;
01103                                         }
01104                                 }
01105                         }
01106                 }
01107         }
01108 
01109         return bufpos;
01110 }
01111 
01112 /*
01113  * Store all the requested options into the requested buffer.
01114  * XXX: ought to be static
01115  */
01116 int
01117 store_options(int *ocount,
01118               unsigned char *buffer, unsigned index, unsigned buflen,
01119               struct packet *packet, struct lease *lease,
01120               struct client_state *client_state,
01121               struct option_state *in_options,
01122               struct option_state *cfg_options,
01123               struct binding_scope **scope,
01124               unsigned *priority_list, int priority_len,
01125               unsigned first_cutoff, int second_cutoff, int terminate,
01126               const char *vuname)
01127 {
01128         int bufix = 0, six = 0, tix = 0;
01129         int i;
01130         int ix;
01131         int tto;
01132         int bufend, sbufend;
01133         struct data_string od;
01134         struct option_cache *oc;
01135         struct option *option = NULL;
01136         unsigned code;
01137 
01138         /*
01139          * These arguments are relative to the start of the buffer, so 
01140          * reduce them by the current buffer index, and advance the
01141          * buffer pointer to where we're going to start writing.
01142          */
01143         buffer = &buffer[index];
01144         buflen -= index;
01145         if (first_cutoff)
01146                 first_cutoff -= index;
01147         if (second_cutoff)
01148                 second_cutoff -= index;
01149 
01150         /* Calculate the start and end of each section of the buffer */
01151         bufend = sbufend = buflen;
01152         if (first_cutoff) {
01153             if (first_cutoff >= buflen)
01154                 log_fatal("%s:%d:store_options: Invalid first cutoff.", MDL);
01155             bufend = first_cutoff;
01156 
01157             if (second_cutoff) {
01158                 if (second_cutoff >= buflen)
01159                     log_fatal("%s:%d:store_options: Invalid second cutoff.",
01160                               MDL);
01161                 sbufend = second_cutoff;
01162             }
01163         } else if (second_cutoff) {
01164             if (second_cutoff >= buflen)
01165                 log_fatal("%s:%d:store_options: Invalid second cutoff.", MDL);
01166             bufend = second_cutoff;
01167         }
01168 
01169         memset (&od, 0, sizeof od);
01170 
01171         /* Eliminate duplicate options from the parameter request list.
01172          * Enforce RFC-mandated ordering of options that are present.
01173          */
01174         for (i = 0; i < priority_len - 1; i++) {
01175                 /* Eliminate duplicates. */
01176                 tto = 0;
01177                 for (ix = i + 1; ix < priority_len + tto; ix++) {
01178                         if (tto)
01179                                 priority_list [ix - tto] =
01180                                         priority_list [ix];
01181                         if (priority_list [i] == priority_list [ix]) {
01182                                 tto++;
01183                                 priority_len--;
01184                         }
01185                 }
01186 
01187                 /* Enforce ordering of SUBNET_MASK options, according to
01188                  * RFC2132 Section 3.3:
01189                  *
01190                  *   If both the subnet mask and the router option are
01191                  *   specified in a DHCP reply, the subnet mask option MUST
01192                  *   be first.
01193                  *
01194                  * This guidance does not specify what to do if the client
01195                  * PRL explicitly requests the options out of order, it is
01196                  * a general statement.
01197                  */
01198                 if (priority_list[i] == DHO_SUBNET_MASK) {
01199                         for (ix = i - 1 ; ix >= 0 ; ix--) {
01200                                 if (priority_list[ix] == DHO_ROUTERS) {
01201                                         /* swap */
01202                                         priority_list[ix] = DHO_SUBNET_MASK;
01203                                         priority_list[i] = DHO_ROUTERS;
01204                                         break;
01205                                 }
01206                         }
01207                 }
01208         }
01209 
01210         /* Copy out the options in the order that they appear in the
01211            priority list... */
01212         for (i = 0; i < priority_len; i++) {
01213             /* Number of bytes left to store (some may already
01214                have been stored by a previous pass). */
01215             unsigned length;
01216             int optstart, soptstart, toptstart;
01217             struct universe *u;
01218             int have_encapsulation = 0;
01219             struct data_string encapsulation;
01220             int splitup;
01221 
01222             memset (&encapsulation, 0, sizeof encapsulation);
01223             have_encapsulation = 0;
01224 
01225             if (option != NULL)
01226                 option_dereference(&option, MDL);
01227 
01228             /* Code for next option to try to store. */
01229             code = priority_list [i];
01230             
01231             /* Look up the option in the site option space if the code
01232                is above the cutoff, otherwise in the DHCP option space. */
01233             if (code >= cfg_options -> site_code_min)
01234                     u = universes [cfg_options -> site_universe];
01235             else
01236                     u = &dhcp_universe;
01237 
01238             oc = lookup_option (u, cfg_options, code);
01239 
01240             if (oc && oc->option)
01241                 option_reference(&option, oc->option, MDL);
01242             else
01243                 option_code_hash_lookup(&option, u->code_hash, &code, 0, MDL);
01244 
01245             /* If it's a straight encapsulation, and the user supplied a
01246              * value for the entire option, use that.  Otherwise, search
01247              * the encapsulated space.
01248              *
01249              * If it's a limited encapsulation with preceding data, and the
01250              * user supplied values for the preceding bytes, search the
01251              * encapsulated space.
01252              */
01253             if ((option != NULL) &&
01254                 (((oc == NULL) && (option->format[0] == 'E')) ||
01255                  ((oc != NULL) && (option->format[0] == 'e')))) {
01256                 static char *s, *t;
01257                 struct option_cache *tmp;
01258                 struct data_string name;
01259 
01260                 s = strchr (option->format, 'E');
01261                 if (s)
01262                     t = strchr (++s, '.');
01263                 if (s && t) {
01264                     memset (&name, 0, sizeof name);
01265 
01266                     /* A zero-length universe name means the vendor
01267                        option space, if one is defined. */
01268                     if (t == s) {
01269                         if (vendor_cfg_option) {
01270                             tmp = lookup_option (vendor_cfg_option -> universe,
01271                                                  cfg_options,
01272                                                  vendor_cfg_option -> code);
01273                             if (tmp)
01274                                 /* No need to check the return as we check name.len below */
01275                                 (void) evaluate_option_cache (&name, packet, lease,
01276                                                               client_state,
01277                                                               in_options,
01278                                                               cfg_options,
01279                                                               scope, tmp, MDL);
01280                         } else if (vuname) {
01281                             name.data = (unsigned char *)s;
01282                             name.len = strlen (s);
01283                         }
01284                     } else {
01285                         name.data = (unsigned char *)s;
01286                         name.len = t - s;
01287                     }
01288                         
01289                     /* If we found a universe, and there are options configured
01290                        for that universe, try to encapsulate it. */
01291                     if (name.len) {
01292                         have_encapsulation =
01293                                 (option_space_encapsulate
01294                                  (&encapsulation, packet, lease, client_state,
01295                                   in_options, cfg_options, scope, &name));
01296                         data_string_forget (&name, MDL);
01297                     }
01298                 }
01299             }
01300 
01301             /* In order to avoid memory leaks, we have to get to here
01302                with any option cache that we allocated in tmp not being
01303                referenced by tmp, and whatever option cache is referenced
01304                by oc being an actual reference.   lookup_option doesn't
01305                generate a reference (this needs to be fixed), so the
01306                preceding goop ensures that if we *didn't* generate a new
01307                option cache, oc still winds up holding an actual reference. */
01308 
01309             /* If no data is available for this option, skip it. */
01310             if (!oc && !have_encapsulation) {
01311                     continue;
01312             }
01313             
01314             /* Find the value of the option... */
01315             od.len = 0;
01316             if (oc) {
01317                 /* No need to check the return as we check od.len below */
01318                 (void) evaluate_option_cache (&od, packet,
01319                                               lease, client_state, in_options,
01320                                               cfg_options, scope, oc, MDL);
01321 
01322                 /* If we have encapsulation for this option, and an oc
01323                  * lookup succeeded, but the evaluation failed, it is
01324                  * either because this is a complex atom (atoms before
01325                  * E on format list) and the top half of the option is
01326                  * not configured, or this is a simple encapsulated
01327                  * space and the evaluator is giving us a NULL.  Prefer
01328                  * the evaluator's opinion over the subspace.
01329                  */
01330                 if (!od.len) {
01331                     data_string_forget (&encapsulation, MDL);
01332                     data_string_forget (&od, MDL);
01333                     continue;
01334                 }
01335             }
01336 
01337             /* We should now have a constant length for the option. */
01338             length = od.len;
01339             if (have_encapsulation) {
01340                     length += encapsulation.len;
01341 
01342                     /* od.len can be nonzero if we got here without an
01343                      * oc (cache lookup failed), but did have an encapsulated
01344                      * simple encapsulation space.
01345                      */
01346                     if (!od.len) {
01347                             data_string_copy (&od, &encapsulation, MDL);
01348                             data_string_forget (&encapsulation, MDL);
01349                     } else {
01350                             struct buffer *bp = (struct buffer *)0;
01351                             if (!buffer_allocate (&bp, length, MDL)) {
01352                                     option_cache_dereference (&oc, MDL);
01353                                     data_string_forget (&od, MDL);
01354                                     data_string_forget (&encapsulation, MDL);
01355                                     continue;
01356                             }
01357                             memcpy (&bp -> data [0], od.data, od.len);
01358                             memcpy (&bp -> data [od.len], encapsulation.data,
01359                                     encapsulation.len);
01360                             data_string_forget (&od, MDL);
01361                             data_string_forget (&encapsulation, MDL);
01362                             od.data = &bp -> data [0];
01363                             buffer_reference (&od.buffer, bp, MDL);
01364                             buffer_dereference (&bp, MDL);
01365                             od.len = length;
01366                             od.terminated = 0;
01367                     }
01368             }
01369 
01370             /* Do we add a NUL? */
01371             if (terminate && option && format_has_text(option->format)) {
01372                     length++;
01373                     tto = 1;
01374             } else {
01375                     tto = 0;
01376             }
01377 
01378             /* Try to store the option. */
01379             
01380             /* If the option's length is more than 255, we must store it
01381                in multiple hunks.   Store 255-byte hunks first.  However,
01382                in any case, if the option data will cross a buffer
01383                boundary, split it across that boundary. */
01384 
01385             if (length > 255)
01386                 splitup = 1;
01387             else
01388                 splitup = 0;
01389 
01390             ix = 0;
01391             optstart = bufix;
01392             soptstart = six;
01393             toptstart = tix;
01394             while (length) {
01395                     unsigned incr = length;
01396                     int *pix;
01397                     unsigned char *base;
01398 
01399                     /* Try to fit it in the options buffer. */
01400                     if (!splitup &&
01401                         ((!six && !tix && (i == priority_len - 1) &&
01402                           (bufix + 2 + length < bufend)) ||
01403                          (bufix + 5 + length < bufend))) {
01404                         base = buffer;
01405                         pix = &bufix;
01406                     /* Try to fit it in the second buffer. */
01407                     } else if (!splitup && first_cutoff &&
01408                                (first_cutoff + six + 3 + length < sbufend)) {
01409                         base = &buffer[first_cutoff];
01410                         pix = &six;
01411                     /* Try to fit it in the third buffer. */
01412                     } else if (!splitup && second_cutoff &&
01413                                (second_cutoff + tix + 3 + length < buflen)) {
01414                         base = &buffer[second_cutoff];
01415                         pix = &tix;
01416                     /* Split the option up into the remaining space. */
01417                     } else {
01418                         splitup = 1;
01419 
01420                         /* Use any remaining options space. */
01421                         if (bufix + 6 < bufend) {
01422                             incr = bufend - bufix - 5;
01423                             base = buffer;
01424                             pix = &bufix;
01425                         /* Use any remaining first_cutoff space. */
01426                         } else if (first_cutoff &&
01427                                    (first_cutoff + six + 4 < sbufend)) {
01428                             incr = sbufend - (first_cutoff + six) - 3;
01429                             base = &buffer[first_cutoff];
01430                             pix = &six;
01431                         /* Use any remaining second_cutoff space. */
01432                         } else if (second_cutoff &&
01433                                    (second_cutoff + tix + 4 < buflen)) {
01434                             incr = buflen - (second_cutoff + tix) - 3;
01435                             base = &buffer[second_cutoff];
01436                             pix = &tix;
01437                         /* Give up, roll back this option. */
01438                         } else {
01439                             bufix = optstart;
01440                             six = soptstart;
01441                             tix = toptstart;
01442                             break;
01443                         }
01444                     }
01445 
01446                     if (incr > length)
01447                         incr = length;
01448                     if (incr > 255)
01449                         incr = 255;
01450 
01451                     /* Everything looks good - copy it in! */
01452                     base [*pix] = code;
01453                     base [*pix + 1] = (unsigned char)incr;
01454                     if (tto && incr == length) {
01455                             if (incr > 1)
01456                                 memcpy (base + *pix + 2,
01457                                         od.data + ix, (unsigned)(incr - 1));
01458                             base [*pix + 2 + incr - 1] = 0;
01459                     } else {
01460                             memcpy (base + *pix + 2,
01461                                     od.data + ix, (unsigned)incr);
01462                     }
01463                     length -= incr;
01464                     ix += incr;
01465                     *pix += 2 + incr;
01466             }
01467             data_string_forget (&od, MDL);
01468         }
01469 
01470         if (option != NULL)
01471             option_dereference(&option, MDL);
01472 
01473         /* If we can overload, and we have, then PAD and END those spaces. */
01474         if (first_cutoff && six) {
01475             if ((first_cutoff + six + 1) < sbufend)
01476                 memset (&buffer[first_cutoff + six + 1], DHO_PAD,
01477                         sbufend - (first_cutoff + six + 1));
01478             else if (first_cutoff + six >= sbufend)
01479                 log_fatal("Second buffer overflow in overloaded options.");
01480 
01481             buffer[first_cutoff + six] = DHO_END;
01482             if (ocount != NULL)
01483                 *ocount |= 1; /* So that caller knows there's data there. */
01484         }
01485 
01486         if (second_cutoff && tix) {
01487             if (second_cutoff + tix + 1 < buflen) {
01488                 memset (&buffer[second_cutoff + tix + 1], DHO_PAD,
01489                         buflen - (second_cutoff + tix + 1));
01490             } else if (second_cutoff + tix >= buflen)
01491                 log_fatal("Third buffer overflow in overloaded options.");
01492 
01493             buffer[second_cutoff + tix] = DHO_END;
01494             if (ocount != NULL)
01495                 *ocount |= 2; /* So that caller knows there's data there. */
01496         }
01497 
01498         if ((six || tix) && (bufix + 3 > bufend))
01499             log_fatal("Not enough space for option overload option.");
01500 
01501         return bufix;
01502 }
01503 
01504 /* Return true if the format string has a variable length text option
01505  * ("t"), return false otherwise.
01506  */
01507 
01508 int
01509 format_has_text(format)
01510         const char *format;
01511 {
01512         const char *p;
01513 
01514         p = format;
01515         while (*p != '\0') {
01516                 switch (*p++) {
01517                     case 'd':
01518                     case 't':
01519                         return 1;
01520 
01521                         /* These symbols are arbitrary, not fixed or
01522                          * determinable length...text options with them is
01523                          * invalid (whatever the case, they are never NULL
01524                          * terminated).
01525                          */
01526                     case 'A':
01527                     case 'a':
01528                     case 'X':
01529                     case 'x':
01530                     case 'D':
01531                         return 0;
01532 
01533                     case 'c':
01534                         /* 'c' only follows 'D' atoms, and indicates that
01535                          * compression may be used.  If there was a 'D'
01536                          * atom already, we would have returned.  So this
01537                          * is an error, but continue looking for 't' anyway.
01538                          */
01539                         log_error("format_has_text(%s): 'c' atoms are illegal "
01540                                   "except after 'D' atoms.", format);
01541                         break;
01542 
01543                         /* 'E' is variable length, but not arbitrary...you
01544                          * can find its length if you can find an END option.
01545                          * N is (n)-byte in length but trails a name of a
01546                          * space defining the enumeration values.  So treat
01547                          * both the same - valid, fixed-length fields.
01548                          */
01549                     case 'E':
01550                     case 'N':
01551                         /* Consume the space name. */
01552                         while ((*p != '\0') && (*p++ != '.'))
01553                                 ;
01554                         break;
01555 
01556                     default:
01557                         break;
01558                 }
01559         }
01560 
01561         return 0;
01562 }
01563 
01564 /* Determine the minimum length of a DHCP option prior to any variable
01565  * or inconsistent length formats, according to its configured format
01566  * variable (and possibly from supplied option cache contents for variable
01567  * length format symbols).
01568  */
01569 
01570 int
01571 format_min_length(format, oc)
01572         const char *format;
01573         struct option_cache *oc;
01574 {
01575         const char *p, *name;
01576         int min_len = 0;
01577         int last_size = 0;
01578         struct enumeration *espace;
01579 
01580         p = format;
01581         while (*p != '\0') {
01582                 switch (*p++) {
01583                     case '6': /* IPv6 Address */
01584                         min_len += 16;
01585                         last_size = 16;
01586                         break;
01587 
01588                     case 'I': /* IPv4 Address */
01589                     case 'l': /* int32_t */
01590                     case 'L': /* uint32_t */
01591                     case 'T': /* Lease Time, uint32_t equivalent */
01592                         min_len += 4;
01593                         last_size = 4;
01594                         break;
01595 
01596                     case 's': /* int16_t */
01597                     case 'S': /* uint16_t */
01598                         min_len += 2;
01599                         last_size = 2;
01600                         break;
01601 
01602                     case 'N': /* Enumeration value. */
01603                         /* Consume space name. */
01604                         name = p;
01605                         p = strchr(p, '.');
01606                         if (p == NULL)
01607                                 log_fatal("Corrupt format: %s", format);
01608 
01609                         espace = find_enumeration(name, p - name);
01610                         if (espace == NULL) {
01611                                 log_error("Unknown enumeration: %s", format);
01612                                 /* Max is safest value to return. */
01613                                 return INT_MAX;
01614                         }
01615 
01616                         min_len += espace->width;
01617                         last_size = espace->width;
01618                         p++;
01619 
01620                         break;
01621 
01622                     case 'b': /* int8_t */
01623                     case 'B': /* uint8_t */
01624                     case 'F': /* Flag that is always true. */
01625                     case 'f': /* Flag */
01626                         min_len++;
01627                         last_size = 1;
01628                         break;
01629 
01630                     case 'o': /* Last argument is optional. */
01631                         min_len -= last_size;
01632 
01633                     /* XXX: It MAY be possible to sense the end of an
01634                      * encapsulated space, but right now this is too
01635                      * hard to support.  Return a safe value.
01636                      */
01637                     case 'e': /* Encapsulation hint (there is an 'E' later). */
01638                     case 'E': /* Encapsulated options. */
01639                         return min_len;
01640 
01641                     case 'd': /* "Domain name" */
01642                     case 'D': /* "rfc1035 formatted names" */
01643                     case 't': /* "ASCII Text" */
01644                     case 'X': /* "ASCII or Hex Conditional */
01645                     case 'x': /* "Hex" */
01646                     case 'A': /* Array of all that precedes. */
01647                     case 'a': /* Array of preceding symbol. */
01648                     case 'Z': /* nothing. */
01649                         return min_len;
01650 
01651                     case 'c': /* Compress flag for D atom. */
01652                         log_error("format_min_length(%s): 'c' atom is illegal "
01653                                   "except after 'D' atom.", format);
01654                         return INT_MAX;
01655 
01656                     default:
01657                         /* No safe value is known. */
01658                         log_error("format_min_length(%s): No safe value "
01659                                   "for unknown format symbols.", format);
01660                         return INT_MAX;
01661                 }
01662         }
01663 
01664         return min_len;
01665 }
01666 
01667 
01668 /* Format the specified option so that a human can easily read it. */
01669 
01670 const char *pretty_print_option (option, data, len, emit_commas, emit_quotes)
01671         struct option *option;
01672         const unsigned char *data;
01673         unsigned len;
01674         int emit_commas;
01675         int emit_quotes;
01676 {
01677         static char optbuf [32768]; /* XXX */
01678         static char *endbuf = &optbuf[sizeof(optbuf)];
01679         int hunksize = 0;
01680         int opthunk = 0;
01681         int hunkinc = 0;
01682         int numhunk = -1;
01683         int numelem = 0;
01684         int count;
01685         int i, j, k, l;
01686         char fmtbuf[32] = "";
01687         struct iaddr iaddr;
01688         struct enumeration *enumbuf[32]; /* MUST be same as fmtbuf */
01689         char *op = optbuf;
01690         const unsigned char *dp = data;
01691         char comma;
01692         unsigned long tval;
01693         isc_boolean_t a_array = ISC_FALSE;
01694         int len_used;
01695         unsigned int octets = 0;
01696 
01697         if (emit_commas)
01698                 comma = ',';
01699         else
01700                 comma = ' ';
01701 
01702         memset (enumbuf, 0, sizeof enumbuf);
01703 
01704         if (option->format[0] != 'R') { /* see explanation lower */
01705         /* Figure out the size of the data. */
01706         for (l = i = 0; option -> format [i]; i++, l++) {
01707                 if (l >= sizeof(fmtbuf) - 1)
01708                         log_fatal("Bounds failure on internal buffer at "
01709                                   "%s:%d", MDL);
01710 
01711                 if (!numhunk) {
01712                         log_error ("%s: Extra codes in format string: %s",
01713                                    option -> name,
01714                                    &(option -> format [i]));
01715                         break;
01716                 }
01717                 numelem++;
01718                 fmtbuf [l] = option -> format [i];
01719                 switch (option -> format [i]) {
01720                       case 'a':
01721                         a_array = ISC_TRUE;
01722                         /* Fall through */
01723                       case 'A':
01724                         --numelem;
01725                         fmtbuf [l] = 0;
01726                         numhunk = 0;
01727                         break;
01728                       case 'E':
01729                         /* Skip the universe name. */
01730                         while (option -> format [i] &&
01731                                option -> format [i] != '.')
01732                                 i++;
01733                         /* Fall Through! */
01734                       case 'X':
01735                         for (k = 0; k < len; k++) {
01736                                 if (!isascii (data [k]) ||
01737                                     !isprint (data [k]))
01738                                         break;
01739                         }
01740                         /* If we found no bogus characters, or the bogus
01741                            character we found is a trailing NUL, it's
01742                            okay to print this option as text. */
01743                         if (k == len || (k + 1 == len && data [k] == 0)) {
01744                                 fmtbuf [l] = 't';
01745                                 numhunk = -2;
01746                         } else {
01747                                 fmtbuf [l] = 'x';
01748                                 hunksize++;
01749                                 comma = ':';
01750                                 numhunk = 0;
01751                                 a_array = ISC_TRUE;
01752                                 hunkinc = 1;
01753                         }
01754                         fmtbuf [l + 1] = 0;
01755                         break;
01756                       case 'c':
01757                         /* The 'c' atom is a 'D' modifier only. */
01758                         log_error("'c' atom not following D atom in format "
01759                                   "string: %s", option->format);
01760                         break;
01761                       case 'D':
01762                         /*
01763                          * Skip the 'c' atom, if present.  It does not affect
01764                          * how we convert wire->text format (if compression is
01765                          * present either way, we still process it).
01766                          */
01767                         if (option->format[i+1] == 'c')
01768                                 i++;
01769                         fmtbuf[l + 1] = 0;
01770                         numhunk = -2;
01771                         break;
01772                       case 'd':
01773                         fmtbuf[l] = 't';
01774                         /* Fall Through ! */
01775                       case 't':
01776                         fmtbuf[l + 1] = 0;
01777                         numhunk = -2;
01778                         break;
01779                       case 'N':
01780                         k = i;
01781                         while (option -> format [i] &&
01782                                option -> format [i] != '.')
01783                                 i++;
01784                         enumbuf [l] =
01785                                 find_enumeration (&option -> format [k] + 1,
01786                                                   i - k - 1);
01787                         if (enumbuf[l] == NULL) {
01788                                 hunksize += 1;
01789                                 hunkinc = 1;
01790                         } else {
01791                                 hunksize += enumbuf[l]->width;
01792                                 hunkinc = enumbuf[l]->width;
01793                         }
01794                         break;
01795                       case '6':
01796                         hunksize += 16;
01797                         hunkinc = 16;
01798                         break;
01799                       case 'I':
01800                       case 'l':
01801                       case 'L':
01802                       case 'T':
01803                         hunksize += 4;
01804                         hunkinc = 4;
01805                         break;
01806                       case 's':
01807                       case 'S':
01808                         hunksize += 2;
01809                         hunkinc = 2;
01810                         break;
01811                       case 'b':
01812                       case 'B':
01813                       case 'f':
01814                       case 'F':
01815                         hunksize++;
01816                         hunkinc = 1;
01817                         break;
01818                       case 'e':
01819                       case 'Z':
01820                         break;
01821                       case 'o':
01822                         opthunk += hunkinc;
01823                         break;
01824                       default:
01825                         log_error ("%s: garbage in format string: %s",
01826                               option -> name,
01827                               &(option -> format [i]));
01828                         break;
01829                 } 
01830         }
01831 
01832         /* Check for too few bytes... */
01833         if (hunksize - opthunk > len) {
01834                 log_error ("%s: expecting at least %d bytes; got %d",
01835                       option -> name,
01836                       hunksize, len);
01837                 return "<error>";
01838         }
01839         /* Check for too many bytes... */
01840         if (numhunk == -1 && hunksize < len)
01841                 log_error ("%s: %d extra bytes",
01842                       option -> name,
01843                       len - hunksize);
01844 
01845         /* If this is an array, compute its size. */
01846         if (numhunk == 0) {
01847                 if (a_array == ISC_TRUE) {
01848                         /*
01849                          * It is an 'a' type array - we repeat the
01850                          * last format type.  A binary string for 'X'
01851                          * is also like this.  hunkinc is the size
01852                          * of the last format type and we add 1 to
01853                          * cover the entire first record.
01854                          */
01855                         numhunk = ((len - hunksize) / hunkinc) + 1;
01856                         len_used = hunksize + ((numhunk - 1) * hunkinc);
01857                 } else {
01858                         /*
01859                          * It is an 'A' type array - we repeat the
01860                          * entire record
01861                          */
01862                         numhunk = len / hunksize;
01863                         len_used = numhunk * hunksize;
01864                 }
01865 
01866                 /* See if we got an exact number of hunks. */
01867                 if (len_used < len) {
01868                         log_error ("%s: %d extra bytes at end of array\n",
01869                                    option -> name,
01870                                    len - len_used);
01871                 }
01872         }
01873 
01874 
01875         /* A one-hunk array prints the same as a single hunk. */
01876         if (numhunk < 0)
01877                 numhunk = 1;
01878 
01879         } else { /* option->format[i] == 'R') */
01880                 /* R (destination descriptor) has variable length.
01881                  * We can find it only in classless static route option,
01882                  * so we are for sure parsing classless static route option now.
01883                  * We go through whole the option to check whether there are no
01884                  * missing/extra bytes.
01885                  * I didn't find out how to improve the existing code and that's the
01886                  * reason for this separate 'else' where I do my own checkings.
01887                  * I know it's little bit unsystematic, but it works.
01888                  */
01889                 numhunk = 0;
01890                 numelem = 2; /* RI */
01891                 fmtbuf[0]='R'; fmtbuf[1]='I'; fmtbuf[2]=0;
01892                 for (i =0; i < len; i = i + octets + 5) {
01893                         if (data[i] > 32) { /* subnet mask width */
01894                                 log_error ("wrong subnet mask width in destination descriptor");
01895                                 break;
01896                         }
01897                         numhunk++;
01898                         octets = ((data[i]+7) / 8);
01899                 }
01900                 if (i != len) {
01901                         log_error ("classless static routes option has wrong size or "
01902                                            "there's some garbage in format");
01903                 }
01904         }
01905 
01906         /* Cycle through the array (or hunk) printing the data. */
01907         for (i = 0; i < numhunk; i++) {
01908                 if ((a_array == ISC_TRUE) && (i != 0) && (numelem > 0)) {
01909                         /*
01910                          * For 'a' type of arrays we repeat
01911                          * only the last format character
01912                          * We should never hit the case of numelem == 0
01913                          * but let's include the check to be safe.
01914                          */
01915                         j = numelem - 1;
01916                 } else {
01917                         /*
01918                          * for other types of arrays or the first
01919                          * time through for 'a' types, we go through
01920                          * the entire set of format characters.
01921                          */
01922                         j = 0;
01923                 }
01924 
01925                 for (; j < numelem; j++) {
01926                         switch (fmtbuf [j]) {
01927                               case 't':
01928                                 /* endbuf-1 leaves room for NULL. */
01929                                 k = pretty_text(&op, endbuf - 1, &dp,
01930                                                 data + len, emit_quotes);
01931                                 if (k == -1) {
01932                                         log_error("Error printing text.");
01933                                         break;
01934                                 }
01935                                 *op = 0;
01936                                 break;
01937                               case 'D': /* RFC1035 format name list */
01938                                 for( ; dp < (data + len) ; dp += k) {
01939                                         unsigned char nbuff[NS_MAXCDNAME];
01940                                         const unsigned char *nbp, *nend;
01941 
01942                                         nend = &nbuff[sizeof(nbuff)];
01943 
01944                                         /* If this is for ISC DHCP consumption
01945                                          * (emit_quotes), lay it out as a list
01946                                          * of STRING tokens.  Otherwise, it is
01947                                          * a space-separated list of DNS-
01948                                          * escaped names as /etc/resolv.conf
01949                                          * might digest.
01950                                          */
01951                                         if (dp != data) {
01952                                                 if (op + 2 > endbuf)
01953                                                         break;
01954 
01955                                                 if (emit_quotes)
01956                                                         *op++ = ',';
01957                                                 *op++ = ' ';
01958                                         }
01959 
01960                                         /* XXX: if fmtbuf[j+1] != 'c', we
01961                                          * should warn if the data was
01962                                          * compressed anyway.
01963                                          */
01964                                         k = MRns_name_unpack(data,
01965                                                              data + len,
01966                                                              dp, nbuff,
01967                                                              sizeof(nbuff));
01968 
01969                                         if (k == -1) {
01970                                                 log_error("Invalid domain "
01971                                                           "list.");
01972                                                 break;
01973                                         }
01974 
01975                                         /* If emit_quotes, then use ISC DHCP
01976                                          * escapes.  Otherwise, rely only on
01977                                          * ns_name_ntop().
01978                                          */
01979                                         if (emit_quotes) {
01980                                                 nbp = nbuff;
01981                                                 pretty_domain(&op, endbuf-1,
01982                                                               &nbp, nend);
01983                                         } else {
01984                                                 /* ns_name_ntop() includes
01985                                                  * a trailing NUL in its
01986                                                  * count.
01987                                                  */
01988                                                 count = MRns_name_ntop(
01989                                                                 nbuff, op, 
01990                                                                 (endbuf-op)-1);
01991 
01992                                                 if (count <= 0) {
01993                                                         log_error("Invalid "
01994                                                                 "domain name.");
01995                                                         break;
01996                                                 }
01997 
01998                                                 /* Consume all but the trailing
01999                                                  * NUL.
02000                                                  */
02001                                                 op += count - 1;
02002 
02003                                                 /* Replace the trailing NUL
02004                                                  * with the implicit root
02005                                                  * (in the unlikely event the
02006                                                  * domain name /is/ the root).
02007                                                  */
02008                                                 *op++ = '.';
02009                                         }
02010                                 }
02011                                 *op = '\0';
02012                                 break;
02013                                 /* pretty-printing an array of enums is
02014                                    going to get ugly. */
02015                               case 'N':
02016                                 if (!enumbuf [j]) {
02017                                         tval = *dp++;
02018                                         goto enum_as_num;
02019                                 }
02020 
02021                                 switch (enumbuf[j]->width) {
02022                                       case 1:
02023                                         tval = getUChar(dp);
02024                                         break;
02025 
02026                                      case 2:
02027                                         tval = getUShort(dp);
02028                                         break;
02029 
02030                                     case 4:
02031                                         tval = getULong(dp);
02032                                         break;
02033 
02034                                     default:
02035                                         log_fatal("Impossible case at %s:%d.",
02036                                                   MDL);
02037                                         return "<double impossible condition>";
02038                                 }
02039 
02040                                 for (i = 0; ;i++) {
02041                                         if (!enumbuf [j] -> values [i].name)
02042                                                 goto enum_as_num;
02043                                         if (enumbuf [j] -> values [i].value ==
02044                                             tval)
02045                                                 break;
02046                                 }
02047                                 strcpy (op, enumbuf [j] -> values [i].name);
02048                                 dp += enumbuf[j]->width;
02049                                 break;
02050 
02051                               enum_as_num:
02052                                 sprintf(op, "%lu", tval);
02053                                 break;
02054 
02055                               case 'I':
02056                                 iaddr.len = 4;
02057                                 memcpy(iaddr.iabuf, dp, 4);
02058                                 strcpy(op, piaddr(iaddr));
02059                                 dp += 4;
02060                                 break;
02061 
02062                               case 'R':
02063                                 if (dp[0] <= 32)
02064                                         iaddr.len = (((dp[0]+7)/8)+1);
02065                                 else {
02066                                         log_error ("wrong subnet mask width in destination descriptor");
02067                                         return "<error>";
02068                                 }
02069 
02070                                 memcpy(iaddr.iabuf, dp, iaddr.len);
02071                                 strcpy(op, pdestdesc(iaddr));
02072                                 dp += iaddr.len;
02073                                 break;
02074 
02075                               case '6':
02076                                 iaddr.len = 16;
02077                                 memcpy(iaddr.iabuf, dp, 16);
02078                                 strcpy(op, piaddr(iaddr));
02079                                 dp += 16;
02080                                 break;
02081                               case 'l':
02082                                 sprintf (op, "%ld", (long)getLong (dp));
02083                                 dp += 4;
02084                                 break;
02085                               case 'T':
02086                                 tval = getULong (dp);
02087                                 if (tval == -1)
02088                                         sprintf (op, "%s", "infinite");
02089                                 else
02090                                         sprintf(op, "%lu", tval);
02091                                 break;
02092                               case 'L':
02093                                 sprintf(op, "%lu",
02094                                         (unsigned long)getULong(dp));
02095                                 dp += 4;
02096                                 break;
02097                               case 's':
02098                                 sprintf (op, "%d", (int)getShort (dp));
02099                                 dp += 2;
02100                                 break;
02101                               case 'S':
02102                                 sprintf(op, "%u", (unsigned)getUShort(dp));
02103                                 dp += 2;
02104                                 break;
02105                               case 'b':
02106                                 sprintf (op, "%d", *(const char *)dp++);
02107                                 break;
02108                               case 'B':
02109                                 sprintf (op, "%d", *dp++);
02110                                 break;
02111                               case 'X':
02112                               case 'x':
02113                                 sprintf (op, "%x", *dp++);
02114                                 break;
02115                               case 'f':
02116                                 strcpy (op, *dp++ ? "true" : "false");
02117                                 break;
02118                               case 'F':
02119                                 strcpy (op, "true");
02120                                 break;
02121                               case 'e':
02122                               case 'Z':
02123                                 *op = '\0';
02124                                 break;
02125                               default:
02126                                 log_error ("Unexpected format code %c",
02127                                            fmtbuf [j]);
02128                         }
02129                         op += strlen (op);
02130                         if (dp == data + len)
02131                                 break;
02132                         if (j + 1 < numelem && comma != ':')
02133                                 *op++ = ' ';
02134                 }
02135                 if (i + 1 < numhunk) {
02136                         *op++ = comma;
02137                 }
02138                 if (dp == data + len)
02139                         break;
02140         }
02141         return optbuf;
02142 }
02143 
02144 int get_option (result, universe, packet, lease, client_state,
02145                 in_options, cfg_options, options, scope, code, file, line)
02146         struct data_string *result;
02147         struct universe *universe;
02148         struct packet *packet;
02149         struct lease *lease;
02150         struct client_state *client_state;
02151         struct option_state *in_options;
02152         struct option_state *cfg_options;
02153         struct option_state *options;
02154         struct binding_scope **scope;
02155         unsigned code;
02156         const char *file;
02157         int line;
02158 {
02159         struct option_cache *oc;
02160 
02161         if (!universe -> lookup_func)
02162                 return 0;
02163         oc = ((*universe -> lookup_func) (universe, options, code));
02164         if (!oc)
02165                 return 0;
02166         if (!evaluate_option_cache (result, packet, lease, client_state,
02167                                     in_options, cfg_options, scope, oc,
02168                                     file, line))
02169                 return 0;
02170         return 1;
02171 }
02172 
02173 void set_option (universe, options, option, op)
02174         struct universe *universe;
02175         struct option_state *options;
02176         struct option_cache *option;
02177         enum statement_op op;
02178 {
02179         struct option_cache *oc, *noc;
02180 
02181         switch (op) {
02182               case if_statement:
02183               case add_statement:
02184               case eval_statement:
02185               case break_statement:
02186               default:
02187                 log_error ("bogus statement type in set_option.");
02188                 break;
02189 
02190               case default_option_statement:
02191                 oc = lookup_option (universe, options,
02192                                     option -> option -> code);
02193                 if (oc)
02194                         break;
02195                 save_option (universe, options, option);
02196                 break;
02197 
02198               case supersede_option_statement:
02199               case send_option_statement:
02200                 /* Install the option, replacing any existing version. */
02201                 save_option (universe, options, option);
02202                 break;
02203 
02204               case append_option_statement:
02205               case prepend_option_statement:
02206                 oc = lookup_option (universe, options,
02207                                     option -> option -> code);
02208                 if (!oc) {
02209                         save_option (universe, options, option);
02210                         break;
02211                 }
02212                 /* If it's not an expression, make it into one. */
02213                 if (!oc -> expression && oc -> data.len) {
02214                         if (!expression_allocate (&oc -> expression, MDL)) {
02215                                 log_error ("Can't allocate const expression.");
02216                                 break;
02217                         }
02218                         oc -> expression -> op = expr_const_data;
02219                         data_string_copy
02220                                 (&oc -> expression -> data.const_data,
02221                                  &oc -> data, MDL);
02222                         data_string_forget (&oc -> data, MDL);
02223                 }
02224                 noc = (struct option_cache *)0;
02225                 if (!option_cache_allocate (&noc, MDL))
02226                         break;
02227                 if (op == append_option_statement) {
02228                         if (!make_concat (&noc -> expression,
02229                                           oc -> expression,
02230                                           option -> expression)) {
02231                                 option_cache_dereference (&noc, MDL);
02232                                 break;
02233                         }
02234                 } else {
02235                         if (!make_concat (&noc -> expression,
02236                                           option -> expression,
02237                                           oc -> expression)) {
02238                                 option_cache_dereference (&noc, MDL);
02239                                 break;
02240                         }
02241                 }
02242                 option_reference(&(noc->option), oc->option, MDL);
02243                 save_option (universe, options, noc);
02244                 option_cache_dereference (&noc, MDL);
02245                 break;
02246         }
02247 }
02248 
02249 struct option_cache *lookup_option (universe, options, code)
02250         struct universe *universe;
02251         struct option_state *options;
02252         unsigned code;
02253 {
02254         if (!options)
02255                 return (struct option_cache *)0;
02256         if (universe -> lookup_func)
02257                 return (*universe -> lookup_func) (universe, options, code);
02258         else
02259                 log_error ("can't look up options in %s space.",
02260                            universe -> name);
02261         return (struct option_cache *)0;
02262 }
02263 
02264 struct option_cache *lookup_hashed_option (universe, options, code)
02265         struct universe *universe;
02266         struct option_state *options;
02267         unsigned code;
02268 {
02269         int hashix;
02270         pair bptr;
02271         pair *hash;
02272 
02273         /* Make sure there's a hash table. */
02274         if (universe -> index >= options -> universe_count ||
02275             !(options -> universes [universe -> index]))
02276                 return (struct option_cache *)0;
02277 
02278         hash = options -> universes [universe -> index];
02279 
02280         hashix = compute_option_hash (code);
02281         for (bptr = hash [hashix]; bptr; bptr = bptr -> cdr) {
02282                 if (((struct option_cache *)(bptr -> car)) -> option -> code ==
02283                     code)
02284                         return (struct option_cache *)(bptr -> car);
02285         }
02286         return (struct option_cache *)0;
02287 }
02288 
02289 /* Save a specified buffer into an option cache. */
02290 int
02291 save_option_buffer(struct universe *universe, struct option_state *options,
02292                    struct buffer *bp, unsigned char *buffer, unsigned length,
02293                    unsigned code, int terminatep)
02294 {
02295         struct option_cache *op = NULL;
02296         int status = 1;
02297 
02298         status = prepare_option_buffer(universe, bp, buffer, length, code,
02299                                        terminatep, &op);
02300 
02301         if (status == 0)
02302                 goto cleanup;
02303 
02304         save_option(universe, options, op);
02305 
02306     cleanup:
02307         if (op != NULL)
02308                 option_cache_dereference(&op, MDL);
02309 
02310         return status;
02311 }
02312 
02313 /* Append a specified buffer onto the tail of an option cache. */
02314 int
02315 append_option_buffer(struct universe *universe, struct option_state *options,
02316                      struct buffer *bp, unsigned char *buffer, unsigned length,
02317                      unsigned code, int terminatep)
02318 {
02319         struct option_cache *op = NULL;
02320         int status = 1;
02321 
02322         status = prepare_option_buffer(universe, bp, buffer, length, code,
02323                                        terminatep, &op);
02324 
02325         if (status == 0)
02326                 goto cleanup;
02327 
02328         also_save_option(universe, options, op);
02329 
02330       cleanup:
02331         if (op != NULL)
02332                 option_cache_dereference(&op, MDL);
02333 
02334         return status;
02335 }
02336 
02337 /* Create/copy a buffer into a new option cache. */
02338 static int
02339 prepare_option_buffer(struct universe *universe, struct buffer *bp,
02340                       unsigned char *buffer, unsigned length, unsigned code,
02341                       int terminatep, struct option_cache **opp)
02342 {
02343         struct buffer *lbp = NULL;
02344         struct option *option = NULL;
02345         struct option_cache *op;
02346         int status = 1;
02347 
02348         /* Code sizes of 8, 16, and 32 bits are allowed. */
02349         switch(universe->tag_size) {
02350               case 1:
02351                 if (code > 0xff)
02352                         return 0;
02353                 break;
02354               case 2:
02355                 if (code > 0xffff)
02356                         return 0;
02357                 break;
02358               case 4:
02359                 if (code > 0xffffffff)
02360                         return 0;
02361                 break;
02362 
02363               default:
02364                 log_fatal("Inconsistent universe tag size at %s:%d.", MDL);
02365         }
02366 
02367         option_code_hash_lookup(&option, universe->code_hash, &code, 0, MDL);
02368 
02369         /* If we created an option structure for each option a client
02370          * supplied, it's possible we may create > 2^32 option structures.
02371          * That's not feasible.  So by failing to enter these option
02372          * structures into the code and name hash tables, references will
02373          * never be more than 1 - when the option cache is destroyed, this
02374          * will be cleaned up.
02375          */
02376         if (!option) {
02377                 char nbuf[sizeof("unknown-4294967295")];
02378 
02379                 sprintf(nbuf, "unknown-%u", code);
02380 
02381                 option = new_option(nbuf, MDL);
02382 
02383                 if (!option)
02384                         return 0;
02385 
02386                 option->format = default_option_format;
02387                 option->universe = universe;
02388                 option->code = code;
02389 
02390                 /* new_option() doesn't set references, pretend. */
02391                 option->refcnt = 1;
02392         }
02393 
02394         if (!option_cache_allocate (opp, MDL)) {
02395                 log_error("No memory for option code %s.%s.",
02396                           universe->name, option->name);
02397                 status = 0;
02398                 goto cleanup;
02399         }
02400 
02401         /* Pointer rather than double pointer makes for less parens. */
02402         op = *opp;
02403 
02404         option_reference(&op->option, option, MDL);
02405 
02406         /* If we weren't passed a buffer in which the data are saved and
02407            refcounted, allocate one now. */
02408         if (!bp) {
02409                 if (!buffer_allocate (&lbp, length + terminatep, MDL)) {
02410                         log_error ("no memory for option buffer.");
02411 
02412                         status = 0;
02413                         goto cleanup;
02414                 }
02415                 memcpy (lbp -> data, buffer, length + terminatep);
02416                 bp = lbp;
02417                 buffer = &bp -> data [0]; /* Refer to saved buffer. */
02418         }
02419 
02420         /* Reference buffer copy to option cache. */
02421         op -> data.buffer = (struct buffer *)0;
02422         buffer_reference (&op -> data.buffer, bp, MDL);
02423 
02424         /* Point option cache into buffer. */
02425         op -> data.data = buffer;
02426         op -> data.len = length;
02427 
02428         if (terminatep) {
02429                 /* NUL terminate (we can get away with this because we (or
02430                    the caller!) allocated one more than the buffer size, and
02431                    because the byte following the end of an option is always
02432                    the code of the next option, which the caller is getting
02433                    out of the *original* buffer. */
02434                 buffer [length] = 0;
02435                 op -> data.terminated = 1;
02436         } else
02437                 op -> data.terminated = 0;
02438 
02439         /* If this option is ultimately a text option, null determinate to
02440          * comply with RFC2132 section 2.  Mark a flag so this can be sensed
02441          * later to echo NULLs back to clients that supplied them (they
02442          * probably expect them).
02443          */
02444         if (format_has_text(option->format)) {
02445                 int min_len = format_min_length(option->format, op);
02446 
02447                 while ((op->data.len > min_len) &&
02448                        (op->data.data[op->data.len-1] == '\0')) {
02449                         op->data.len--;
02450                         op->flags |= OPTION_HAD_NULLS;
02451                 }
02452         }
02453 
02454         /* And let go of our references. */
02455       cleanup:
02456         if (lbp != NULL)
02457                 buffer_dereference(&lbp, MDL);
02458         option_dereference(&option, MDL);
02459 
02460         return status;
02461 }
02462 
02463 static void
02464 count_options(struct option_cache *dummy_oc,
02465               struct packet *dummy_packet,
02466               struct lease *dummy_lease, 
02467               struct client_state *dummy_client_state,
02468               struct option_state *dummy_opt_state,
02469               struct option_state *opt_state,
02470               struct binding_scope **dummy_binding_scope,
02471               struct universe *dummy_universe, 
02472               void *void_accumulator) {
02473         int *accumulator = (int *)void_accumulator;
02474 
02475         *accumulator += 1;
02476 }
02477 
02478 static void
02479 collect_oro(struct option_cache *oc,
02480             struct packet *dummy_packet,
02481             struct lease *dummy_lease, 
02482             struct client_state *dummy_client_state,
02483             struct option_state *dummy_opt_state,
02484             struct option_state *opt_state,
02485             struct binding_scope **dummy_binding_scope,
02486             struct universe *dummy_universe, 
02487             void *void_oro) {
02488         struct data_string *oro = (struct data_string *)void_oro;
02489 
02490         putUShort(oro->buffer->data + oro->len, oc->option->code);
02491         oro->len += 2;
02492 }
02493 
02494 /* build_server_oro() is presently unusued, but may be used at a future date
02495  * with support for Reconfigure messages (as a hint to the client about new
02496  * option value contents).
02497  */
02498 void
02499 build_server_oro(struct data_string *server_oro, 
02500                  struct option_state *options,
02501                  const char *file, int line) {
02502         int num_opts;
02503         int i;
02504         struct option *o;
02505 
02506         /*
02507          * Count the number of options, so we can allocate enough memory.
02508          * We want to mention sub-options too, so check all universes.
02509          */
02510         num_opts = 0;
02511         option_space_foreach(NULL, NULL, NULL, NULL, options,
02512                              NULL, &dhcpv6_universe, (void *)&num_opts,
02513                              count_options);
02514         for (i=0; i < options->universe_count; i++) {
02515                 if (options->universes[i] != NULL) {
02516                         o = universes[i]->enc_opt;
02517                         while (o != NULL) {
02518                                 if (o->universe == &dhcpv6_universe) {
02519                                         num_opts++;
02520                                         break;
02521                                 }
02522                                 o = o->universe->enc_opt;
02523                         }
02524                 }
02525         }
02526 
02527         /*
02528          * Allocate space.
02529          */
02530         memset(server_oro, 0, sizeof(*server_oro));
02531         if (!buffer_allocate(&server_oro->buffer, num_opts * 2, MDL)) {
02532                 log_fatal("no memory to build server ORO");
02533         }
02534         server_oro->data = server_oro->buffer->data;
02535 
02536         /*
02537          * Copy the data in.
02538          * We want to mention sub-options too, so check all universes.
02539          */
02540         server_oro->len = 0;    /* gets set in collect_oro */
02541         option_space_foreach(NULL, NULL, NULL, NULL, options,
02542                              NULL, &dhcpv6_universe, (void *)server_oro,
02543                              collect_oro);
02544         for (i=0; i < options->universe_count; i++) {
02545                 if (options->universes[i] != NULL) {
02546                         o = universes[i]->enc_opt;
02547                         while (o != NULL) {
02548                                 if (o->universe == &dhcpv6_universe) {
02549                                         unsigned char *tmp;
02550                                         tmp = server_oro->buffer->data;
02551                                         putUShort(tmp + server_oro->len,
02552                                                   o->code);
02553                                         server_oro->len += 2;
02554                                         break;
02555                                 }
02556                                 o = o->universe->enc_opt;
02557                         }
02558                 }
02559         }
02560 }
02561 
02562 /* Wrapper function to put an option cache into an option state. */
02563 void
02564 save_option(struct universe *universe, struct option_state *options,
02565             struct option_cache *oc)
02566 {
02567         if (universe->save_func)
02568                 (*universe->save_func)(universe, options, oc, ISC_FALSE);
02569         else
02570                 log_error("can't store options in %s space.", universe->name);
02571 }
02572 
02573 /* Wrapper function to append an option cache into an option state's list. */
02574 void
02575 also_save_option(struct universe *universe, struct option_state *options,
02576                  struct option_cache *oc)
02577 {
02578         if (universe->save_func)
02579                 (*universe->save_func)(universe, options, oc, ISC_TRUE);
02580         else
02581                 log_error("can't store options in %s space.", universe->name);
02582 }
02583 
02584 void
02585 save_hashed_option(struct universe *universe, struct option_state *options,
02586                    struct option_cache *oc, isc_boolean_t appendp)
02587 {
02588         int hashix;
02589         pair bptr;
02590         pair *hash = options -> universes [universe -> index];
02591         struct option_cache **ocloc;
02592 
02593         if (oc -> refcnt == 0)
02594                 abort ();
02595 
02596         /* Compute the hash. */
02597         hashix = compute_option_hash (oc -> option -> code);
02598 
02599         /* If there's no hash table, make one. */
02600         if (!hash) {
02601                 hash = (pair *)dmalloc (OPTION_HASH_SIZE * sizeof *hash, MDL);
02602                 if (!hash) {
02603                         log_error ("no memory to store %s.%s",
02604                                    universe -> name, oc -> option -> name);
02605                         return;
02606                 }
02607                 memset (hash, 0, OPTION_HASH_SIZE * sizeof *hash);
02608                 options -> universes [universe -> index] = (void *)hash;
02609         } else {
02610                 /* Try to find an existing option matching the new one. */
02611                 for (bptr = hash [hashix]; bptr; bptr = bptr -> cdr) {
02612                         if (((struct option_cache *)
02613                              (bptr -> car)) -> option -> code ==
02614                             oc -> option -> code)
02615                                 break;
02616                 }
02617 
02618                 /* Deal with collisions on the hash list. */
02619                 if (bptr) {
02620                         ocloc = (struct option_cache **)&bptr->car;
02621 
02622                         /*
02623                          * If appendp is set, append it onto the tail of the
02624                          * ->next list.  If it is not set, rotate it into
02625                          * position at the head of the list.
02626                          */
02627                         if (appendp) {
02628                                 do {
02629                                         ocloc = &(*ocloc)->next;
02630                                 } while (*ocloc != NULL);
02631                         } else {
02632                                 option_cache_dereference(ocloc, MDL);
02633                         }
02634 
02635                         option_cache_reference(ocloc, oc, MDL);
02636                         return;
02637                 }
02638         }
02639 
02640         /* Otherwise, just put the new one at the head of the list. */
02641         bptr = new_pair (MDL);
02642         if (!bptr) {
02643                 log_error ("No memory for option_cache reference.");
02644                 return;
02645         }
02646         bptr -> cdr = hash [hashix];
02647         bptr -> car = 0;
02648         option_cache_reference ((struct option_cache **)&bptr -> car, oc, MDL);
02649         hash [hashix] = bptr;
02650 }
02651 
02652 void delete_option (universe, options, code)
02653         struct universe *universe;
02654         struct option_state *options;
02655         int code;
02656 {
02657         if (universe -> delete_func)
02658                 (*universe -> delete_func) (universe, options, code);
02659         else
02660                 log_error ("can't delete options from %s space.",
02661                            universe -> name);
02662 }
02663 
02664 void delete_hashed_option (universe, options, code)
02665         struct universe *universe;
02666         struct option_state *options;
02667         int code;
02668 {
02669         int hashix;
02670         pair bptr, prev = (pair)0;
02671         pair *hash = options -> universes [universe -> index];
02672 
02673         /* There may not be any options in this space. */
02674         if (!hash)
02675                 return;
02676 
02677         /* Try to find an existing option matching the new one. */
02678         hashix = compute_option_hash (code);
02679         for (bptr = hash [hashix]; bptr; bptr = bptr -> cdr) {
02680                 if (((struct option_cache *)(bptr -> car)) -> option -> code
02681                     == code)
02682                         break;
02683                 prev = bptr;
02684         }
02685         /* If we found one, wipe it out... */
02686         if (bptr) {
02687                 if (prev)
02688                         prev -> cdr = bptr -> cdr;
02689                 else
02690                         hash [hashix] = bptr -> cdr;
02691                 option_cache_dereference
02692                         ((struct option_cache **)(&bptr -> car), MDL);
02693                 free_pair (bptr, MDL);
02694         }
02695 }
02696 
02697 extern struct option_cache *free_option_caches; /* XXX */
02698 
02699 int option_cache_dereference (ptr, file, line)
02700         struct option_cache **ptr;
02701         const char *file;
02702         int line;
02703 {
02704         if (!ptr || !*ptr) {
02705                 log_error ("Null pointer in option_cache_dereference: %s(%d)",
02706                            file, line);
02707 #if defined (POINTER_DEBUG)
02708                 abort ();
02709 #else
02710                 return 0;
02711 #endif
02712         }
02713 
02714         (*ptr) -> refcnt--;
02715         rc_register (file, line, ptr, *ptr, (*ptr) -> refcnt, 1, RC_MISC);
02716         if (!(*ptr) -> refcnt) {
02717                 if ((*ptr) -> data.buffer)
02718                         data_string_forget (&(*ptr) -> data, file, line);
02719                 if ((*ptr)->option)
02720                         option_dereference(&(*ptr)->option, MDL);
02721                 if ((*ptr) -> expression)
02722                         expression_dereference (&(*ptr) -> expression,
02723                                                 file, line);
02724                 if ((*ptr) -> next)
02725                         option_cache_dereference (&((*ptr) -> next),
02726                                                   file, line);
02727                 /* Put it back on the free list... */
02728                 (*ptr) -> expression = (struct expression *)free_option_caches;
02729                 free_option_caches = *ptr;
02730                 dmalloc_reuse (free_option_caches, (char *)0, 0, 0);
02731         }
02732         if ((*ptr) -> refcnt < 0) {
02733                 log_error ("%s(%d): negative refcnt!", file, line);
02734 #if defined (DEBUG_RC_HISTORY)
02735                 dump_rc_history (*ptr);
02736 #endif
02737 #if defined (POINTER_DEBUG)
02738                 abort ();
02739 #else
02740                 *ptr = (struct option_cache *)0;
02741                 return 0;
02742 #endif
02743         }
02744         *ptr = (struct option_cache *)0;
02745         return 1;
02746 
02747 }
02748 
02749 int hashed_option_state_dereference (universe, state, file, line)
02750         struct universe *universe;
02751         struct option_state *state;
02752         const char *file;
02753         int line;
02754 {
02755         pair *heads;
02756         pair cp, next;
02757         int i;
02758 
02759         /* Get the pointer to the array of hash table bucket heads. */
02760         heads = (pair *)(state -> universes [universe -> index]);
02761         if (!heads)
02762                 return 0;
02763 
02764         /* For each non-null head, loop through all the buckets dereferencing
02765            the attached option cache structures and freeing the buckets. */
02766         for (i = 0; i < OPTION_HASH_SIZE; i++) {
02767                 for (cp = heads [i]; cp; cp = next) {
02768                         next = cp -> cdr;
02769                         option_cache_dereference
02770                                 ((struct option_cache **)&cp -> car,
02771                                  file, line);
02772                         free_pair (cp, file, line);
02773                 }
02774         }
02775 
02776         dfree (heads, file, line);
02777         state -> universes [universe -> index] = (void *)0;
02778         return 1;
02779 }
02780 
02781 /* The 'data_string' primitive doesn't have an appension mechanism.
02782  * This function must then append a new option onto an existing buffer
02783  * by first duplicating the original buffer and appending the desired
02784  * values, followed by coping the new value into place.
02785  */
02786 int
02787 append_option(struct data_string *dst, struct universe *universe,
02788               struct option *option, struct data_string *src)
02789 {
02790         struct data_string tmp;
02791 
02792         if (src->len == 0 && option->format[0] != 'Z')
02793                 return 0;
02794 
02795         memset(&tmp, 0, sizeof(tmp));
02796 
02797         /* Allocate a buffer to hold existing data, the current option's
02798          * tag and length, and the option's content.
02799          */
02800         if (!buffer_allocate(&tmp.buffer,
02801                              (dst->len + universe->length_size +
02802                               universe->tag_size + src->len), MDL)) {
02803                 /* XXX: This kills all options presently stored in the
02804                  * destination buffer.  This is the way the original code
02805                  * worked, and assumes an 'all or nothing' approach to
02806                  * eg encapsulated option spaces.  It may or may not be
02807                  * desirable.
02808                  */
02809                 data_string_forget(dst, MDL);
02810                 return 0;
02811         }
02812         tmp.data = tmp.buffer->data;
02813 
02814         /* Copy the existing data off the destination. */
02815         if (dst->len != 0)
02816                 memcpy(tmp.buffer->data, dst->data, dst->len);
02817         tmp.len = dst->len;
02818 
02819         /* Place the new option tag and length. */
02820         (*universe->store_tag)(tmp.buffer->data + tmp.len, option->code);
02821         tmp.len += universe->tag_size;
02822         (*universe->store_length)(tmp.buffer->data + tmp.len, src->len);
02823         tmp.len += universe->length_size;
02824 
02825         /* Copy the option contents onto the end. */
02826         memcpy(tmp.buffer->data + tmp.len, src->data, src->len);
02827         tmp.len += src->len;
02828 
02829         /* Play the shell game. */
02830         data_string_forget(dst, MDL);
02831         data_string_copy(dst, &tmp, MDL);
02832         data_string_forget(&tmp, MDL);
02833         return 1;
02834 }
02835 
02836 int
02837 store_option(struct data_string *result, struct universe *universe,
02838              struct packet *packet, struct lease *lease,
02839              struct client_state *client_state,
02840              struct option_state *in_options, struct option_state *cfg_options,
02841              struct binding_scope **scope, struct option_cache *oc)
02842 {
02843         struct data_string tmp;
02844         struct universe *subu=NULL;
02845         int status;
02846         char *start, *end;
02847 
02848         memset(&tmp, 0, sizeof(tmp));
02849 
02850         if (evaluate_option_cache(&tmp, packet, lease, client_state,
02851                                   in_options, cfg_options, scope, oc, MDL)) {
02852                 /* If the option is an extended 'e'ncapsulation (not a
02853                  * direct 'E'ncapsulation), append the encapsulated space
02854                  * onto the currently prepared value.
02855                  */
02856                 do {
02857                         if (oc->option->format &&
02858                             oc->option->format[0] == 'e') {
02859                                 /* Skip forward to the universe name. */
02860                                 start = strchr(oc->option->format, 'E');
02861                                 if (start == NULL)
02862                                         break;
02863 
02864                                 /* Locate the name-terminating '.'. */
02865                                 end = strchr(++start, '.');
02866 
02867                                 /* A zero-length name is not allowed in
02868                                  * these kinds of encapsulations.
02869                                  */
02870                                 if (end == NULL || start == end)
02871                                         break;
02872 
02873                                 universe_hash_lookup(&subu, universe_hash,
02874                                                      start, end - start, MDL);
02875 
02876                                 if (subu == NULL) {
02877                                         log_error("store_option: option %d "
02878                                                   "refers to unknown "
02879                                                   "option space '%.*s'.",
02880                                                   oc->option->code,
02881                                                   (int)(end - start), start);
02882                                         break;
02883                                 }
02884 
02885                                 /* Append encapsulations, if any.  We
02886                                  * already have the prepended values, so
02887                                  * we send those even if there are no
02888                                  * encapsulated options (and ->encapsulate()
02889                                  * returns zero).
02890                                  */
02891                                 subu->encapsulate(&tmp, packet, lease,
02892                                                   client_state, in_options,
02893                                                   cfg_options, scope, subu);
02894                                 subu = NULL;
02895                         }
02896                 } while (ISC_FALSE);
02897 
02898                 status = append_option(result, universe, oc->option, &tmp);
02899                 data_string_forget(&tmp, MDL);
02900 
02901                 return status;
02902         }
02903 
02904         return 0;
02905 }
02906 
02907 int option_space_encapsulate (result, packet, lease, client_state,
02908                               in_options, cfg_options, scope, name)
02909         struct data_string *result;
02910         struct packet *packet;
02911         struct lease *lease;
02912         struct client_state *client_state;
02913         struct option_state *in_options;
02914         struct option_state *cfg_options;
02915         struct binding_scope **scope;
02916         struct data_string *name;
02917 {
02918         struct universe *u = NULL;
02919         int status = 0;
02920 
02921         universe_hash_lookup(&u, universe_hash, 
02922                              (const char *)name->data, name->len, MDL);
02923         if (u == NULL) {
02924                 log_error("option_space_encapsulate: option space '%.*s' does "
02925                           "not exist, but is configured.",
02926                           (int)name->len, name->data);
02927                 return status;
02928         }
02929 
02930         if (u->encapsulate != NULL) {
02931                 if (u->encapsulate(result, packet, lease, client_state,
02932                                    in_options, cfg_options, scope, u))
02933                         status = 1;
02934         } else
02935                 log_error("encapsulation requested for '%s' with no support.",
02936                           name->data);
02937 
02938         return status;
02939 }
02940 
02941 /* Attempt to store any 'E'ncapsulated options that have not yet been
02942  * placed on the option buffer by the above (configuring a value in
02943  * the space over-rides any values in the child universe).
02944  *
02945  * Note that there are far fewer universes than there will ever be
02946  * options in any universe.  So it is faster to traverse the
02947  * configured universes, checking if each is encapsulated in the
02948  * current universe, and if so attempting to do so.
02949  *
02950  * For each configured universe for this configuration option space,
02951  * which is encapsulated within the current universe, can not be found
02952  * by the lookup function (the universe-specific encapsulation
02953  * functions would already have stored such a value), and encapsulates
02954  * at least one option, append it.
02955  */
02956 static int
02957 search_subencapsulation(struct data_string *result, struct packet *packet,
02958                         struct lease *lease, struct client_state *client_state,
02959                         struct option_state *in_options,
02960                         struct option_state *cfg_options,
02961                         struct binding_scope **scope,
02962                         struct universe *universe)
02963 {
02964         struct data_string sub;
02965         struct universe *subu;
02966         int i, status = 0;
02967 
02968         memset(&sub, 0, sizeof(sub));
02969         for (i = 0 ; i < cfg_options->universe_count ; i++) {
02970                 subu = universes[i];
02971 
02972                 if (subu == NULL)
02973                         log_fatal("Impossible condition at %s:%d.", MDL);
02974 
02975                 if (subu->enc_opt != NULL &&
02976                     subu->enc_opt->universe == universe &&
02977                     subu->enc_opt->format != NULL &&
02978                     subu->enc_opt->format[0] == 'E' &&
02979                     lookup_option(universe, cfg_options,
02980                                   subu->enc_opt->code) == NULL &&
02981                     subu->encapsulate(&sub, packet, lease, client_state,
02982                                       in_options, cfg_options,
02983                                       scope, subu)) {
02984                         if (append_option(result, universe,
02985                                           subu->enc_opt, &sub))
02986                                 status = 1;
02987 
02988                         data_string_forget(&sub, MDL);
02989                 }
02990         }
02991 
02992         return status;
02993 }
02994 
02995 int hashed_option_space_encapsulate (result, packet, lease, client_state,
02996                                      in_options, cfg_options, scope, universe)
02997         struct data_string *result;
02998         struct packet *packet;
02999         struct lease *lease;
03000         struct client_state *client_state;
03001         struct option_state *in_options;
03002         struct option_state *cfg_options;
03003         struct binding_scope **scope;
03004         struct universe *universe;
03005 {
03006         pair p, *hash;
03007         int status;
03008         int i;
03009 
03010         if (universe -> index >= cfg_options -> universe_count)
03011                 return 0;
03012 
03013         hash = cfg_options -> universes [universe -> index];
03014         if (!hash)
03015                 return 0;
03016 
03017         /* For each hash bucket, and each configured option cache within
03018          * that bucket, append the option onto the buffer in encapsulated
03019          * format appropriate to the universe.
03020          */
03021         status = 0;
03022         for (i = 0; i < OPTION_HASH_SIZE; i++) {
03023                 for (p = hash [i]; p; p = p -> cdr) {
03024                         if (store_option(result, universe, packet, lease,
03025                                          client_state, in_options, cfg_options,
03026                                          scope, (struct option_cache *)p->car))
03027                                 status = 1;
03028                 }
03029         }
03030 
03031         if (search_subencapsulation(result, packet, lease, client_state,
03032                                     in_options, cfg_options, scope, universe))
03033                 status = 1;
03034 
03035         return status;
03036 }
03037 
03038 int nwip_option_space_encapsulate (result, packet, lease, client_state,
03039                                    in_options, cfg_options, scope, universe)
03040         struct data_string *result;
03041         struct packet *packet;
03042         struct lease *lease;
03043         struct client_state *client_state;
03044         struct option_state *in_options;
03045         struct option_state *cfg_options;
03046         struct binding_scope **scope;
03047         struct universe *universe;
03048 {
03049         pair ocp;
03050         int status;
03051         static struct option_cache *no_nwip;
03052         struct data_string ds;
03053         struct option_chain_head *head;
03054 
03055         if (universe -> index >= cfg_options -> universe_count)
03056                 return 0;
03057         head = ((struct option_chain_head *)
03058                 cfg_options -> universes [nwip_universe.index]);
03059         if (!head)
03060                 return 0;
03061 
03062         status = 0;
03063         for (ocp = head -> first; ocp; ocp = ocp -> cdr) {
03064                 if (store_option (result, universe, packet,
03065                                   lease, client_state, in_options,
03066                                   cfg_options, scope,
03067                                   (struct option_cache *)ocp -> car))
03068                         status = 1;
03069         }
03070 
03071         /* If there's no data, the nwip suboption is supposed to contain
03072            a suboption saying there's no data. */
03073         if (!status) {
03074                 if (!no_nwip) {
03075                         unsigned one = 1;
03076                         static unsigned char nni [] = { 1, 0 };
03077 
03078                         memset (&ds, 0, sizeof ds);
03079                         ds.data = nni;
03080                         ds.len = 2;
03081                         if (option_cache_allocate (&no_nwip, MDL))
03082                                 data_string_copy (&no_nwip -> data, &ds, MDL);
03083                         if (!option_code_hash_lookup(&no_nwip->option,
03084                                                      nwip_universe.code_hash,
03085                                                      &one, 0, MDL))
03086                                 log_fatal("Nwip option hash does not contain "
03087                                           "1 (%s:%d).", MDL);
03088                 }
03089                 if (no_nwip) {
03090                         if (store_option (result, universe, packet, lease,
03091                                           client_state, in_options,
03092                                           cfg_options, scope, no_nwip))
03093                                 status = 1;
03094                 }
03095         } else {
03096                 memset (&ds, 0, sizeof ds);
03097 
03098                 /* If we have nwip options, the first one has to be the
03099                    nwip-exists-in-option-area option. */
03100                 if (!buffer_allocate (&ds.buffer, result -> len + 2, MDL)) {
03101                         data_string_forget (result, MDL);
03102                         return 0;
03103                 }
03104                 ds.data = &ds.buffer -> data [0];
03105                 ds.buffer -> data [0] = 2;
03106                 ds.buffer -> data [1] = 0;
03107                 memcpy (&ds.buffer -> data [2], result -> data, result -> len);
03108                 data_string_forget (result, MDL);
03109                 data_string_copy (result, &ds, MDL);
03110                 data_string_forget (&ds, MDL);
03111         }
03112 
03113         return status;
03114 }
03115 
03116 /* We don't want to use ns_name_pton()...it doesn't tell us how many bytes
03117  * it has consumed, and it plays havoc with our escapes.
03118  *
03119  * So this function does DNS encoding, and returns either the number of
03120  * octects consumed (on success), or -1 on failure.
03121  */
03122 static int
03123 fqdn_encode(unsigned char *dst, int dstlen, const unsigned char *src,
03124             int srclen)
03125 {
03126         unsigned char *out;
03127         int i, j, len, outlen=0;
03128 
03129         out = dst;
03130         for (i = 0, j = 0 ; i < srclen ; i = j) {
03131                 while ((j < srclen) && (src[j] != '.') && (src[j] != '\0'))
03132                         j++;
03133 
03134                 len = j - i;
03135                 if ((outlen + 1 + len) > dstlen)
03136                         return -1;
03137 
03138                 *out++ = len;
03139                 outlen++;
03140 
03141                 /* We only do one FQDN, ending in one root label. */
03142                 if (len == 0)
03143                         return outlen;
03144 
03145                 memcpy(out, src + i, len);
03146                 out += len;
03147                 outlen += len;
03148 
03149                 /* Advance past the root label. */
03150                 j++;
03151         }
03152 
03153         if ((outlen + 1) > dstlen)
03154                 return -1;
03155 
03156         /* Place the root label. */
03157         *out++ = 0;
03158         outlen++;
03159 
03160         return outlen;
03161 }
03162 
03163 int fqdn_option_space_encapsulate (result, packet, lease, client_state,
03164                                    in_options, cfg_options, scope, universe)
03165         struct data_string *result;
03166         struct packet *packet;
03167         struct lease *lease;
03168         struct client_state *client_state;
03169         struct option_state *in_options;
03170         struct option_state *cfg_options;
03171         struct binding_scope **scope;
03172         struct universe *universe;
03173 {
03174         pair ocp;
03175         struct data_string results [FQDN_SUBOPTION_COUNT + 1];
03176         int status = 1;
03177         int i;
03178         unsigned len;
03179         struct buffer *bp = (struct buffer *)0;
03180         struct option_chain_head *head;
03181 
03182         /* If there's no FQDN universe, don't encapsulate. */
03183         if (fqdn_universe.index >= cfg_options -> universe_count)
03184                 return 0;
03185         head = ((struct option_chain_head *)
03186                 cfg_options -> universes [fqdn_universe.index]);
03187         if (!head)
03188                 return 0;
03189 
03190         /* Figure out the values of all the suboptions. */
03191         memset (results, 0, sizeof results);
03192         for (ocp = head -> first; ocp; ocp = ocp -> cdr) {
03193                 struct option_cache *oc = (struct option_cache *)(ocp -> car);
03194                 if (oc -> option -> code > FQDN_SUBOPTION_COUNT)
03195                         continue;
03196                 /* No need to check the return code, we check the length later */
03197                 (void) evaluate_option_cache (&results[oc->option->code],
03198                                               packet, lease, client_state,
03199                                               in_options, cfg_options, scope,
03200                                               oc, MDL);
03201         }
03202         /* We add a byte for the flags field.
03203          * We add two bytes for the two RCODE fields.
03204          * We add a byte because we will prepend a label count.
03205          * We add a byte because the input len doesn't count null termination,
03206          * and we will add a root label.
03207          */
03208         len = 5 + results [FQDN_FQDN].len;
03209         /* Save the contents of the option in a buffer. */
03210         if (!buffer_allocate (&bp, len, MDL)) {
03211                 log_error ("no memory for option buffer.");
03212                 status = 0;
03213                 goto exit;
03214         }
03215         buffer_reference (&result -> buffer, bp, MDL);
03216         result -> len = 3;
03217         result -> data = &bp -> data [0];
03218 
03219         memset (&bp -> data [0], 0, len);
03220         /* XXX: The server should set bit 4 (yes, 4, not 3) to 1 if it is
03221          * not going to perform any ddns updates.  The client should set the
03222          * bit if it doesn't want the server to perform any updates.
03223          * The problem is at this layer of abstraction we have no idea if
03224          * the caller is a client or server.
03225          *
03226          * See RFC4702, Section 3.1, 'The "N" bit'.
03227          *
03228          * if (?)
03229          *      bp->data[0] |= 8;
03230          */
03231         if (results [FQDN_NO_CLIENT_UPDATE].len &&
03232             results [FQDN_NO_CLIENT_UPDATE].data [0])
03233                 bp -> data [0] |= 2;
03234         if (results [FQDN_SERVER_UPDATE].len &&
03235             results [FQDN_SERVER_UPDATE].data [0])
03236                 bp -> data [0] |= 1;
03237         if (results [FQDN_RCODE1].len)
03238                 bp -> data [1] = results [FQDN_RCODE1].data [0];
03239         if (results [FQDN_RCODE2].len)
03240                 bp -> data [2] = results [FQDN_RCODE2].data [0];
03241 
03242         if (results [FQDN_ENCODED].len &&
03243             results [FQDN_ENCODED].data [0]) {
03244                 bp->data[0] |= 4;
03245                 if (results [FQDN_FQDN].len) {
03246                         i = fqdn_encode(&bp->data[3], len - 3,
03247                                         results[FQDN_FQDN].data,
03248                                         results[FQDN_FQDN].len);
03249 
03250                         if (i < 0) {
03251                                 status = 0;
03252                                 goto exit;
03253                         }
03254 
03255                         result->len += i;
03256                         result->terminated = 0;
03257                 }
03258         } else {
03259                 if (results [FQDN_FQDN].len) {
03260                         memcpy (&bp -> data [3], results [FQDN_FQDN].data,
03261                                 results [FQDN_FQDN].len);
03262                         result -> len += results [FQDN_FQDN].len;
03263                         result -> terminated = 0;
03264                 }
03265         }
03266       exit:
03267         for (i = 1; i <= FQDN_SUBOPTION_COUNT; i++) {
03268                 if (results [i].len)
03269                         data_string_forget (&results [i], MDL);
03270         }
03271         buffer_dereference (&bp, MDL);
03272         if (!status)
03273                 data_string_forget(result, MDL);
03274         return status;
03275 }
03276 
03277 /*
03278  * Trap invalid attempts to inspect FQND6 contents.
03279  */
03280 struct option_cache *
03281 lookup_fqdn6_option(struct universe *universe, struct option_state *options,
03282                     unsigned code)
03283 {
03284         log_fatal("Impossible condition at %s:%d.", MDL);
03285         return NULL;
03286 }
03287 
03288 /*
03289  * Trap invalid attempts to save options directly to FQDN6 rather than FQDN.
03290  */
03291 void
03292 save_fqdn6_option(struct universe *universe, struct option_state *options,
03293                   struct option_cache *oc, isc_boolean_t appendp)
03294 {
03295         log_fatal("Impossible condition at %s:%d.", MDL);
03296 }
03297 
03298 /*
03299  * Trap invalid attempts to delete an option out of the FQDN6 universe.
03300  */
03301 void
03302 delete_fqdn6_option(struct universe *universe, struct option_state *options,
03303                     int code)
03304 {
03305         log_fatal("Impossible condition at %s:%d.", MDL);
03306 }
03307 
03308 /* Shill to the DHCPv4 fqdn option cache any attempts to traverse the
03309  * V6's option cache entry.
03310  *
03311  * This function is called speculatively by dhclient to setup
03312  * environment variables.  But it would have already called the
03313  * foreach on the normal fqdn universe, so this is superfluous.
03314  */
03315 void
03316 fqdn6_option_space_foreach(struct packet *packet, struct lease *lease,
03317                            struct client_state *client_state,
03318                            struct option_state *in_options,
03319                            struct option_state *cfg_options,
03320                            struct binding_scope **scope,
03321                            struct universe *u, void *stuff,
03322                            void (*func)(struct option_cache *,
03323                                         struct packet *,
03324                                         struct lease *,
03325                                         struct client_state *,
03326                                         struct option_state *,
03327                                         struct option_state *,
03328                                         struct binding_scope **,
03329                                         struct universe *, void *))
03330 {
03331         /* Pretend it is empty. */
03332         return;
03333 }
03334 
03335 /* Turn the FQDN option space into a DHCPv6 FQDN option buffer.
03336  */
03337 int
03338 fqdn6_option_space_encapsulate(struct data_string *result,
03339                                struct packet *packet, struct lease *lease,
03340                                struct client_state *client_state,
03341                                struct option_state *in_options,
03342                                struct option_state *cfg_options,
03343                                struct binding_scope **scope,
03344                                struct universe *universe)
03345 {
03346         pair ocp;
03347         struct option_chain_head *head;
03348         struct option_cache *oc;
03349         unsigned char *data;
03350         int i, len, rval = 0, count;
03351         struct data_string results[FQDN_SUBOPTION_COUNT + 1];
03352 
03353         if (fqdn_universe.index >= cfg_options->universe_count)
03354                 return 0;
03355         head = ((struct option_chain_head *)
03356                 cfg_options->universes[fqdn_universe.index]);
03357         if (head == NULL)
03358                 return 0;
03359 
03360         memset(results, 0, sizeof(results));
03361         for (ocp = head->first ; ocp != NULL ; ocp = ocp->cdr) {
03362                 oc = (struct option_cache *)(ocp->car);
03363                 if (oc->option->code > FQDN_SUBOPTION_COUNT)
03364                         log_fatal("Impossible condition at %s:%d.", MDL);
03365                 /* No need to check the return code, we check the length later */
03366                 (void) evaluate_option_cache(&results[oc->option->code], packet,
03367                                              lease, client_state, in_options,
03368                                              cfg_options, scope, oc, MDL);
03369         }
03370 
03371         /* We add a byte for the flags field at the start of the option.
03372          * We add a byte because we will prepend a label count.
03373          * We add a byte because the input length doesn't include a trailing
03374          * NULL, and we will add a root label.
03375          */
03376         len = results[FQDN_FQDN].len + 3;
03377         if (!buffer_allocate(&result->buffer, len, MDL)) {
03378                 log_error("No memory for virtual option buffer.");
03379                 goto exit;
03380         }
03381         data = result->buffer->data;
03382         result->data = data;
03383 
03384         /* The first byte is the flags field. */
03385         result->len = 1;
03386         data[0] = 0;
03387         /* XXX: The server should set bit 3 (yes, 3, not 4) to 1 if we
03388          * are not going to perform any DNS updates.  The problem is
03389          * that at this layer of abstraction, we do not know if the caller
03390          * is the client or the server.
03391          *
03392          * See RFC4704 Section 4.1, 'The "N" bit'.
03393          *
03394          * if (?)
03395          *      data[0] |= 4;
03396          */
03397         if (results[FQDN_NO_CLIENT_UPDATE].len &&
03398             results[FQDN_NO_CLIENT_UPDATE].data[0])
03399                 data[0] |= 2;
03400         if (results[FQDN_SERVER_UPDATE].len &&
03401             results[FQDN_SERVER_UPDATE].data[0])
03402                 data[0] |= 1;
03403 
03404         /* If there is no name, we're done. */
03405         if (results[FQDN_FQDN].len == 0) {
03406                 rval = 1;
03407                 goto exit;
03408         }
03409 
03410         /* Convert textual representation to DNS format. */
03411         count = fqdn_encode(data + 1, len - 1,
03412                             results[FQDN_FQDN].data, results[FQDN_FQDN].len);
03413 
03414         if (count < 0) {
03415                 rval = 0;
03416                 data_string_forget(result, MDL);
03417                 goto exit;
03418         }
03419 
03420         result->len += count;
03421         result->terminated = 0;
03422 
03423         /* Success! */
03424         rval = 1;
03425 
03426       exit:
03427         for (i = 1 ; i <= FQDN_SUBOPTION_COUNT ; i++) {
03428                 if (result[i].len)
03429                         data_string_forget(&results[i], MDL);
03430         }
03431 
03432         return rval;
03433 }
03434 
03435 /* Read the DHCPv6 FQDN option's contents into the FQDN virtual space.
03436  */
03437 int
03438 fqdn6_universe_decode(struct option_state *options,
03439                       const unsigned char *buffer, unsigned length,
03440                       struct universe *u)
03441 {
03442         struct buffer *bp = NULL;
03443         unsigned char *first_dot;
03444         int len, hlen, dlen;
03445 
03446         /* The FQDN option has to be at least 1 byte long. */
03447         if (length < 1)
03448                 return 0;
03449 
03450         /* Save the contents of the option in a buffer.  There are 3
03451          * one-byte values we record from the packet, so we go ahead
03452          * and allocate a bigger buffer to accommodate them.  But the
03453          * 'length' we got (because it is a DNS encoded string) is
03454          * one longer than we need...so we only add two extra octets.
03455          */
03456         if (!buffer_allocate(&bp, length + 2, MDL)) {
03457                 log_error("No memory for dhcp6.fqdn option buffer.");
03458                 return 0;
03459         }
03460 
03461         /* The v6 FQDN is always 'encoded' per DNS. */
03462         bp->data[0] = 1;
03463         if (!save_option_buffer(&fqdn_universe, options, bp,
03464                                 bp->data, 1, FQDN_ENCODED, 0))
03465                 goto error;
03466 
03467         /* XXX: We need to process 'The "N" bit'. */
03468 
03469         if (buffer[0] & 1) /* server-update. */
03470                 bp->data[2] = 1;
03471         else
03472                 bp->data[2] = 0;
03473 
03474         if (!save_option_buffer(&fqdn_universe, options, bp, bp->data + 2, 1,
03475                                 FQDN_SERVER_UPDATE, 0))
03476                 goto error;
03477 
03478         if (buffer[0] & 2) /* no-client-update. */
03479                 bp->data[1] = 1;
03480         else
03481                 bp->data[1] = 0;
03482 
03483         if (!save_option_buffer(&fqdn_universe, options, bp, bp->data + 1, 1,
03484                                 FQDN_NO_CLIENT_UPDATE, 0))
03485                 goto error;
03486 
03487         /* Convert the domain name to textual representation for config. */
03488         len = MRns_name_ntop(buffer + 1, (char *)bp->data + 3, length - 1);
03489         if (len == -1) {
03490                 log_error("Unable to convert dhcp6.fqdn domain name to "
03491                           "printable form.");
03492                 goto error;
03493         }
03494 
03495         /* Save the domain name. */
03496         if (len > 0) {
03497                 unsigned char *fqdn_start = bp->data + 3;
03498 
03499                 if (!save_option_buffer(&fqdn_universe, options, bp,
03500                                         fqdn_start, len, FQDN_FQDN, 1))
03501                         goto error;
03502 
03503                 first_dot = (unsigned char *)strchr((char *)fqdn_start, '.');
03504 
03505                 if (first_dot != NULL) {
03506                         hlen = first_dot - fqdn_start;
03507                         dlen = len - hlen;
03508                 } else {
03509                         hlen = len;
03510                         dlen = 0;
03511                 }
03512 
03513                 if (!save_option_buffer(&fqdn_universe, options, bp,
03514                                         fqdn_start, len, FQDN_FQDN, 1) ||
03515                     ((hlen > 0) &&
03516                      !save_option_buffer(&fqdn_universe, options, bp,
03517                                          fqdn_start, hlen,
03518                                          FQDN_HOSTNAME, 0)) ||
03519                     ((dlen > 0) &&
03520                      !save_option_buffer(&fqdn_universe, options, bp,
03521                                          first_dot, dlen, FQDN_DOMAINNAME, 0)))
03522                                 goto error;
03523         }
03524 
03525         buffer_dereference(&bp, MDL);
03526         return 1;
03527 
03528       error:
03529         buffer_dereference(&bp, MDL);
03530         return 0;
03531 }
03532 
03533 void option_space_foreach (struct packet *packet, struct lease *lease,
03534                            struct client_state *client_state,
03535                            struct option_state *in_options,
03536                            struct option_state *cfg_options,
03537                            struct binding_scope **scope,
03538                            struct universe *u, void *stuff,
03539                            void (*func) (struct option_cache *,
03540                                          struct packet *,
03541                                          struct lease *, struct client_state *,
03542                                          struct option_state *,
03543                                          struct option_state *,
03544                                          struct binding_scope **,
03545                                          struct universe *, void *))
03546 {
03547         if (u -> foreach)
03548                 (*u -> foreach) (packet, lease, client_state, in_options,
03549                                  cfg_options, scope, u, stuff, func);
03550 }
03551 
03552 void suboption_foreach (struct packet *packet, struct lease *lease,
03553                         struct client_state *client_state,
03554                         struct option_state *in_options,
03555                         struct option_state *cfg_options,
03556                         struct binding_scope **scope,
03557                         struct universe *u, void *stuff,
03558                         void (*func) (struct option_cache *,
03559                                       struct packet *,
03560                                       struct lease *, struct client_state *,
03561                                       struct option_state *,
03562                                       struct option_state *,
03563                                       struct binding_scope **,
03564                                       struct universe *, void *),
03565                         struct option_cache *oc,
03566                         const char *vsname)
03567 {
03568         struct universe *universe = find_option_universe (oc -> option,
03569                                                           vsname);
03570         if (universe -> foreach)
03571                 (*universe -> foreach) (packet, lease, client_state,
03572                                         in_options, cfg_options,
03573                                         scope, universe, stuff, func);
03574 }
03575 
03576 void hashed_option_space_foreach (struct packet *packet, struct lease *lease,
03577                                   struct client_state *client_state,
03578                                   struct option_state *in_options,
03579                                   struct option_state *cfg_options,
03580                                   struct binding_scope **scope,
03581                                   struct universe *u, void *stuff,
03582                                   void (*func) (struct option_cache *,
03583                                                 struct packet *,
03584                                                 struct lease *,
03585                                                 struct client_state *,
03586                                                 struct option_state *,
03587                                                 struct option_state *,
03588                                                 struct binding_scope **,
03589                                                 struct universe *, void *))
03590 {
03591         pair *hash;
03592         int i;
03593         struct option_cache *oc;
03594 
03595         if (cfg_options -> universe_count <= u -> index)
03596                 return;
03597 
03598         hash = cfg_options -> universes [u -> index];
03599         if (!hash)
03600                 return;
03601         for (i = 0; i < OPTION_HASH_SIZE; i++) {
03602                 pair p;
03603                 /* XXX save _all_ options! XXX */
03604                 for (p = hash [i]; p; p = p -> cdr) {
03605                         oc = (struct option_cache *)p -> car;
03606                         (*func) (oc, packet, lease, client_state,
03607                                  in_options, cfg_options, scope, u, stuff);
03608                 }
03609         }
03610 }
03611 
03612 void
03613 save_linked_option(struct universe *universe, struct option_state *options,
03614                    struct option_cache *oc, isc_boolean_t appendp)
03615 {
03616         pair *tail;
03617         struct option_chain_head *head;
03618         struct option_cache **ocloc;
03619 
03620         if (universe -> index >= options -> universe_count)
03621                 return;
03622         head = ((struct option_chain_head *)
03623                 options -> universes [universe -> index]);
03624         if (!head) {
03625                 if (!option_chain_head_allocate (((struct option_chain_head **)
03626                                                   &options -> universes
03627                                                   [universe -> index]), MDL))
03628                         return;
03629                 head = ((struct option_chain_head *)
03630                         options -> universes [universe -> index]);
03631         }
03632 
03633         /* Find the tail of the list. */
03634         for (tail = &head -> first; *tail; tail = &((*tail) -> cdr)) {
03635                 ocloc = (struct option_cache **)&(*tail)->car;
03636 
03637                 if (oc->option->code == (*ocloc)->option->code) {
03638                         if (appendp) {
03639                                 do {
03640                                         ocloc = &(*ocloc)->next;
03641                                 } while (*ocloc != NULL);
03642                         } else {
03643                                 option_cache_dereference(ocloc, MDL);
03644                         }
03645                         option_cache_reference(ocloc, oc, MDL);
03646                         return;
03647                 }
03648         }
03649 
03650         *tail = cons (0, 0);
03651         if (*tail) {
03652                 option_cache_reference ((struct option_cache **)
03653                                         (&(*tail) -> car), oc, MDL);
03654         }
03655 }
03656 
03657 int linked_option_space_encapsulate (result, packet, lease, client_state,
03658                                     in_options, cfg_options, scope, universe)
03659         struct data_string *result;
03660         struct packet *packet;
03661         struct lease *lease;
03662         struct client_state *client_state;
03663         struct option_state *in_options;
03664         struct option_state *cfg_options;
03665         struct binding_scope **scope;
03666         struct universe *universe;
03667 {
03668         int status = 0;
03669         pair oc;
03670         struct option_chain_head *head;
03671 
03672         if (universe -> index >= cfg_options -> universe_count)
03673                 return status;
03674         head = ((struct option_chain_head *)
03675                 cfg_options -> universes [universe -> index]);
03676         if (!head)
03677                 return status;
03678 
03679         for (oc = head -> first; oc; oc = oc -> cdr) {
03680                 if (store_option (result, universe, packet,
03681                                   lease, client_state, in_options, cfg_options,
03682                                   scope, (struct option_cache *)(oc -> car)))
03683                         status = 1;
03684         }
03685 
03686         if (search_subencapsulation(result, packet, lease, client_state,
03687                                     in_options, cfg_options, scope, universe))
03688                 status = 1;
03689 
03690         return status;
03691 }
03692 
03693 void delete_linked_option (universe, options, code)
03694         struct universe *universe;
03695         struct option_state *options;
03696         int code;
03697 {
03698         pair *tail, tmp = (pair)0;
03699         struct option_chain_head *head;
03700 
03701         if (universe -> index >= options -> universe_count)
03702                 return;
03703         head = ((struct option_chain_head *)
03704                 options -> universes [universe -> index]);
03705         if (!head)
03706                 return;
03707 
03708         for (tail = &head -> first; *tail; tail = &((*tail) -> cdr)) {
03709                 if (code ==
03710                     ((struct option_cache *)(*tail) -> car) -> option -> code)
03711                 {
03712                         tmp = (*tail) -> cdr;
03713                         option_cache_dereference ((struct option_cache **)
03714                                                   (&(*tail) -> car), MDL);
03715                         dfree (*tail, MDL);
03716                         (*tail) = tmp;
03717                         break;
03718                 }
03719         }
03720 }
03721 
03722 struct option_cache *lookup_linked_option (universe, options, code)
03723         struct universe *universe;
03724         struct option_state *options;
03725         unsigned code;
03726 {
03727         pair oc;
03728         struct option_chain_head *head;
03729 
03730         if (universe -> index >= options -> universe_count)
03731                 return 0;
03732         head = ((struct option_chain_head *)
03733                 options -> universes [universe -> index]);
03734         if (!head)
03735                 return 0;
03736 
03737         for (oc = head -> first; oc; oc = oc -> cdr) {
03738                 if (code ==
03739                     ((struct option_cache *)(oc -> car)) -> option -> code) {
03740                         return (struct option_cache *)(oc -> car);
03741                 }
03742         }
03743 
03744         return (struct option_cache *)0;
03745 }
03746 
03747 int linked_option_state_dereference (universe, state, file, line)
03748         struct universe *universe;
03749         struct option_state *state;
03750         const char *file;
03751         int line;
03752 {
03753         return (option_chain_head_dereference
03754                 ((struct option_chain_head **)
03755                  (&state -> universes [universe -> index]), MDL));
03756 }
03757 
03758 void linked_option_space_foreach (struct packet *packet, struct lease *lease,
03759                                   struct client_state *client_state,
03760                                   struct option_state *in_options,
03761                                   struct option_state *cfg_options,
03762                                   struct binding_scope **scope,
03763                                   struct universe *u, void *stuff,
03764                                   void (*func) (struct option_cache *,
03765                                                 struct packet *,
03766                                                 struct lease *,
03767                                                 struct client_state *,
03768                                                 struct option_state *,
03769                                                 struct option_state *,
03770                                                 struct binding_scope **,
03771                                                 struct universe *, void *))
03772 {
03773         pair car;
03774         struct option_chain_head *head;
03775 
03776         if (u -> index >= cfg_options -> universe_count)
03777                 return;
03778         head = ((struct option_chain_head *)
03779                 cfg_options -> universes [u -> index]);
03780         if (!head)
03781                 return;
03782         for (car = head -> first; car; car = car -> cdr) {
03783                 (*func) ((struct option_cache *)(car -> car),
03784                          packet, lease, client_state,
03785                          in_options, cfg_options, scope, u, stuff);
03786         }
03787 }
03788 
03789 void do_packet (interface, packet, len, from_port, from, hfrom)
03790         struct interface_info *interface;
03791         struct dhcp_packet *packet;
03792         unsigned len;
03793         unsigned int from_port;
03794         struct iaddr from;
03795         struct hardware *hfrom;
03796 {
03797         struct option_cache *op;
03798         struct packet *decoded_packet;
03799 #if defined (DEBUG_MEMORY_LEAKAGE)
03800         unsigned long previous_outstanding = dmalloc_outstanding;
03801 #endif
03802 
03803 #if defined (TRACING)
03804         trace_inpacket_stash(interface, packet, len, from_port, from, hfrom);
03805 #endif
03806 
03807         decoded_packet = NULL;
03808         if (!packet_allocate(&decoded_packet, MDL)) {
03809                 log_error("do_packet: no memory for incoming packet!");
03810                 return;
03811         }
03812         decoded_packet->raw = packet;
03813         decoded_packet->packet_length = len;
03814         decoded_packet->client_port = from_port;
03815         decoded_packet->client_addr = from;
03816         interface_reference(&decoded_packet->interface, interface, MDL);
03817         decoded_packet->haddr = hfrom;
03818 
03819         if (packet->hlen > sizeof packet->chaddr) {
03820                 packet_dereference(&decoded_packet, MDL);
03821                 log_info("Discarding packet with bogus hlen.");
03822                 return;
03823         }
03824 
03825         /* If there's an option buffer, try to parse it. */
03826         if (decoded_packet->packet_length >= DHCP_FIXED_NON_UDP + 4) {
03827                 if (!parse_options(decoded_packet)) {
03828                         if (decoded_packet->options)
03829                                 option_state_dereference
03830                                         (&decoded_packet->options, MDL);
03831                         packet_dereference (&decoded_packet, MDL);
03832                         return;
03833                 }
03834 
03835                 if (decoded_packet->options_valid &&
03836                     (op = lookup_option(&dhcp_universe,
03837                                         decoded_packet->options, 
03838                                         DHO_DHCP_MESSAGE_TYPE))) {
03839                         struct data_string dp;
03840                         memset(&dp, 0, sizeof dp);
03841                         evaluate_option_cache(&dp, decoded_packet, NULL, NULL,
03842                                               decoded_packet->options, NULL,
03843                                               NULL, op, MDL);
03844                         if (dp.len > 0)
03845                                 decoded_packet->packet_type = dp.data[0];
03846                         else
03847                                 decoded_packet->packet_type = 0;
03848                         data_string_forget(&dp, MDL);
03849                 }
03850         }
03851 
03852         if (validate_packet(decoded_packet) != 0) {
03853                 if (decoded_packet->packet_type)
03854                         dhcp(decoded_packet);
03855                 else
03856                         bootp(decoded_packet);
03857         }
03858 
03859         /* If the caller kept the packet, they'll have upped the refcnt. */
03860         packet_dereference(&decoded_packet, MDL);
03861 
03862 #if defined (DEBUG_MEMORY_LEAKAGE)
03863         log_info("generation %ld: %ld new, %ld outstanding, %ld long-term",
03864                  dmalloc_generation,
03865                  dmalloc_outstanding - previous_outstanding,
03866                  dmalloc_outstanding, dmalloc_longterm);
03867         dmalloc_dump_outstanding();
03868 #endif
03869 #if defined (DEBUG_RC_HISTORY_EXHAUSTIVELY)
03870         dump_rc_history(0);
03871 #endif
03872 }
03873 
03874 int
03875 packet6_len_okay(const char *packet, int len) {
03876         if (len < 1) {
03877                 return 0;
03878         }
03879         if ((packet[0] == DHCPV6_RELAY_FORW) || 
03880             (packet[0] == DHCPV6_RELAY_REPL)) {
03881                 if (len >= offsetof(struct dhcpv6_relay_packet, options)) {
03882                         return 1;
03883                 } else {
03884                         return 0;
03885                 }
03886         } else {
03887                 if (len >= offsetof(struct dhcpv6_packet, options)) {
03888                         return 1;
03889                 } else {
03890                         return 0;
03891                 }
03892         }
03893 }
03894 
03895 #ifdef DHCPv6
03896 void 
03897 do_packet6(struct interface_info *interface, const char *packet, 
03898            int len, int from_port, const struct iaddr *from, 
03899            isc_boolean_t was_unicast) {
03900         unsigned char msg_type;
03901         const struct dhcpv6_packet *msg;
03902         const struct dhcpv6_relay_packet *relay; 
03903         struct packet *decoded_packet;
03904 #if defined (DEBUG_MEMORY_LEAKAGE)
03905         unsigned long previous_outstanding = dmalloc_outstanding;
03906 #endif
03907 
03908         if (!packet6_len_okay(packet, len)) {
03909                 log_info("do_packet6: "
03910                          "short packet from %s port %d, len %d, dropped",
03911                          piaddr(*from), from_port, len);
03912                 return;
03913         }
03914 
03915         decoded_packet = NULL;
03916         if (!packet_allocate(&decoded_packet, MDL)) {
03917                 log_error("do_packet6: no memory for incoming packet.");
03918                 return;
03919         }
03920 
03921         if (!option_state_allocate(&decoded_packet->options, MDL)) {
03922                 log_error("do_packet6: no memory for options.");
03923                 packet_dereference(&decoded_packet, MDL);
03924                 return;
03925         }
03926 
03927         /* IPv4 information, already set to 0 */
03928         /* decoded_packet->packet_type = 0; */
03929         /* memset(&decoded_packet->haddr, 0, sizeof(decoded_packet->haddr)); */
03930         /* decoded_packet->circuit_id = NULL; */
03931         /* decoded_packet->circuit_id_len = 0; */
03932         /* decoded_packet->remote_id = NULL; */
03933         /* decoded_packet->remote_id_len = 0; */
03934         decoded_packet->raw = (struct dhcp_packet *)packet;
03935         decoded_packet->packet_length = (unsigned)len;
03936         decoded_packet->client_port = from_port;
03937         decoded_packet->client_addr = *from;
03938         interface_reference(&decoded_packet->interface, interface, MDL);
03939 
03940         decoded_packet->unicast = was_unicast;
03941 
03942         msg_type = packet[0];
03943         if ((msg_type == DHCPV6_RELAY_FORW) || 
03944             (msg_type == DHCPV6_RELAY_REPL)) {
03945                 int relaylen = (int)(offsetof(struct dhcpv6_relay_packet, options));
03946                 relay = (const struct dhcpv6_relay_packet *)packet;
03947                 decoded_packet->dhcpv6_msg_type = relay->msg_type;
03948 
03949                 /* relay-specific data */
03950                 decoded_packet->dhcpv6_hop_count = relay->hop_count;
03951                 memcpy(&decoded_packet->dhcpv6_link_address,
03952                        relay->link_address, sizeof(relay->link_address));
03953                 memcpy(&decoded_packet->dhcpv6_peer_address,
03954                        relay->peer_address, sizeof(relay->peer_address));
03955 
03956                 if (!parse_option_buffer(decoded_packet->options, 
03957                                          relay->options, len - relaylen, 
03958                                          &dhcpv6_universe)) {
03959                         /* no logging here, as parse_option_buffer() logs all
03960                            cases where it fails */
03961                         packet_dereference(&decoded_packet, MDL);
03962                         return;
03963                 }
03964         } else {
03965                 int msglen = (int)(offsetof(struct dhcpv6_packet, options));
03966                 msg = (const struct dhcpv6_packet *)packet;
03967                 decoded_packet->dhcpv6_msg_type = msg->msg_type;
03968 
03969                 /* message-specific data */
03970                 memcpy(decoded_packet->dhcpv6_transaction_id, 
03971                        msg->transaction_id, 
03972                        sizeof(decoded_packet->dhcpv6_transaction_id));
03973 
03974                 if (!parse_option_buffer(decoded_packet->options, 
03975                                          msg->options, len - msglen, 
03976                                          &dhcpv6_universe)) {
03977                         /* no logging here, as parse_option_buffer() logs all
03978                            cases where it fails */
03979                         packet_dereference(&decoded_packet, MDL);
03980                         return;
03981                 }
03982         }
03983 
03984         dhcpv6(decoded_packet);
03985 
03986         packet_dereference(&decoded_packet, MDL);
03987 
03988 #if defined (DEBUG_MEMORY_LEAKAGE)
03989         log_info("generation %ld: %ld new, %ld outstanding, %ld long-term",
03990                  dmalloc_generation,
03991                  dmalloc_outstanding - previous_outstanding,
03992                  dmalloc_outstanding, dmalloc_longterm);
03993         dmalloc_dump_outstanding();
03994 #endif
03995 #if defined (DEBUG_RC_HISTORY_EXHAUSTIVELY)
03996         dump_rc_history(0);
03997 #endif
03998 }
03999 #endif /* DHCPv6 */
04000 
04001 int
04002 pretty_escape(char **dst, char *dend, const unsigned char **src,
04003               const unsigned char *send)
04004 {
04005         int count = 0;
04006 
04007         /* If there aren't as many bytes left as there are in the source
04008          * buffer, don't even bother entering the loop.
04009          */
04010         if (dst == NULL || dend == NULL || src == NULL || send == NULL ||
04011             *dst == NULL || *src == NULL || (*dst >= dend) || (*src > send) ||
04012             ((send - *src) > (dend - *dst)))
04013                 return -1;
04014 
04015         for ( ; *src < send ; (*src)++) {
04016                 if (!isascii (**src) || !isprint (**src)) {
04017                         /* Skip trailing NUL. */
04018                         if ((*src + 1) != send || **src != '\0') {
04019                                 if (*dst + 4 > dend)
04020                                         return -1;
04021 
04022                                 sprintf(*dst, "\\%03o",
04023                                         **src);
04024                                 (*dst) += 4;
04025                                 count += 4;
04026                         }
04027                 } else if (**src == '"' || **src == '\'' || **src == '$' ||
04028                            **src == '`' || **src == '\\' || **src == '|' ||
04029                            **src == '&') {
04030                         if (*dst + 2 > dend)
04031                                 return -1;
04032 
04033                         **dst = '\\';
04034                         (*dst)++;
04035                         **dst = **src;
04036                         (*dst)++;
04037                         count += 2;
04038                 } else {
04039                         if (*dst + 1 > dend)
04040                                 return -1;
04041 
04042                         **dst = **src;
04043                         (*dst)++;
04044                         count++;
04045                 }
04046         }
04047 
04048         return count;
04049 }
04050 
04051 static int
04052 pretty_text(char **dst, char *dend, const unsigned char **src,
04053             const unsigned char *send, int emit_quotes)
04054 {
04055         int count;
04056 
04057         if (dst == NULL || dend == NULL || src == NULL || send == NULL ||
04058             *dst == NULL || *src == NULL ||
04059             ((*dst + (emit_quotes ? 2 : 0)) > dend) || (*src > send))
04060                 return -1;
04061 
04062         if (emit_quotes) {
04063                 **dst = '"';
04064                 (*dst)++;
04065         }
04066 
04067         /* dend-1 leaves 1 byte for the closing quote. */
04068         count = pretty_escape(dst, dend - (emit_quotes ? 1 : 0), src, send);
04069 
04070         if (count == -1)
04071                 return -1;
04072 
04073         if (emit_quotes && (*dst < dend)) {
04074                 **dst = '"';
04075                 (*dst)++;
04076 
04077                 /* Includes quote prior to pretty_escape(); */
04078                 count += 2;
04079         }
04080 
04081         return count;
04082 }
04083 
04084 static int
04085 pretty_domain(char **dst, char *dend, const unsigned char **src,
04086               const unsigned char *send)
04087 {
04088         const unsigned char *tend;
04089         int count = 2;
04090         int tsiz, status;
04091 
04092         if (dst == NULL || dend == NULL || src == NULL || send == NULL ||
04093             *dst == NULL || *src == NULL ||
04094             ((*dst + 2) > dend) || (*src >= send))
04095                 return -1;
04096 
04097         **dst = '"';
04098         (*dst)++;
04099 
04100         do {
04101                 /* Continue loop until end of src buffer. */
04102                 if (*src >= send)
04103                         break;
04104 
04105                 /* Consume tag size. */
04106                 tsiz = **src;
04107                 (*src)++;
04108 
04109                 /* At root, finis. */
04110                 if (tsiz == 0)
04111                         break;
04112 
04113                 tend = (*src) + tsiz;
04114 
04115                 /* If the tag exceeds the source buffer, it's illegal.
04116                  * This should also trap compression pointers (which should
04117                  * not be in these buffers).
04118                  */
04119                 if (tend > send)
04120                         return -1;
04121 
04122                 /* dend-2 leaves room for a trailing dot and quote. */
04123                 status = pretty_escape(dst, dend-2, src, tend);
04124 
04125                 if ((status == -1) || ((*dst + 2) > dend))
04126                         return -1;
04127 
04128                 **dst = '.';
04129                 (*dst)++;
04130                 count += status + 1;
04131         }
04132         while(1);
04133 
04134         **dst = '"';
04135         (*dst)++;
04136 
04137         return count;
04138 }
04139 
04140 /*
04141  * Add the option identified with the option number and data to the
04142  * options state.
04143  */
04144 int
04145 add_option(struct option_state *options,
04146            unsigned int option_num,
04147            void *data,
04148            unsigned int data_len)
04149 {
04150         struct option_cache *oc;
04151         struct option *option;
04152 
04153         /* INSIST(options != NULL); */
04154         /* INSIST(data != NULL); */
04155 
04156         option = NULL;
04157         if (!option_code_hash_lookup(&option, dhcp_universe.code_hash, 
04158                                      &option_num, 0, MDL)) {
04159                 log_error("Attempting to add unknown option %d.", option_num);
04160                 return 0;
04161         }
04162 
04163         oc = NULL;
04164         if (!option_cache_allocate(&oc, MDL)) {
04165                 log_error("No memory for option cache adding %s (option %d).",
04166                           option->name, option_num);
04167                 return 0;
04168         }
04169 
04170         if (!make_const_data(&oc->expression, 
04171                              data, 
04172                              data_len,
04173                              0, 
04174                              0, 
04175                              MDL)) {
04176                 log_error("No memory for constant data adding %s (option %d).",
04177                           option->name, option_num);
04178                 option_cache_dereference(&oc, MDL);
04179                 return 0;
04180         }
04181 
04182         option_reference(&(oc->option), option, MDL);
04183         save_option(&dhcp_universe, options, oc);
04184         option_cache_dereference(&oc, MDL);
04185 
04186         return 1;
04187 }
04188 
04196 int validate_packet(struct packet *packet)
04197 {
04198         struct option_cache *oc = NULL;
04199 
04200         oc = lookup_option (&dhcp_universe, packet->options,
04201                             DHO_DHCP_CLIENT_IDENTIFIER);
04202         if (oc) {
04203                 /* Let's check if client-identifier is sane */
04204                 if (oc->data.len == 0) {
04205                         log_debug("Dropped DHCPv4 packet with zero-length client-id");
04206                         return (0);
04207 
04208                 } else if (oc->data.len == 1) {
04209                         /*
04210                          * RFC2132, section 9.14 states that minimum length of client-id
04211                          * is 2.  We will allow single-character client-ids for now (for
04212                          * backwards compatibility), but warn the user that support for
04213                          * this is against the standard.
04214                          */
04215                         log_debug("Accepted DHCPv4 packet with one-character client-id - "
04216                                 "a future version of ISC DHCP will reject this");
04217                 }
04218         } else {
04219                 /* 
04220                  * If hlen is 0 we don't have any identifier, we warn the user
04221                  * but continue processing the packet as we can.
04222                  */
04223                 if (packet->raw->hlen == 0) {
04224                         log_debug("Received DHCPv4 packet without client-id"
04225                                   " option and empty hlen field.");
04226                 }
04227         }
04228 
04229         /* @todo: Add checks for other received options */
04230 
04231         return (1);
04232 }

Generated on 5 Apr 2014 for ISC DHCP by  doxygen 1.6.1