tools/adflib: build only host variant which is used by Sam440 target
[AROS.git] / workbench / network / stacks / AROSTCP / dhcp / common / options.c
blob775f1eb1675717c9388a5c7490c28a09f83b69de
1 /* options.c
3 DHCP options parsing and reassembly. */
5 /*
6 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
7 * Copyright (c) 1995-2003 by Internet Software Consortium
9 * Permission to use, copy, modify, and distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice and this permission notice appear in all copies.
13 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
19 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 * Internet Systems Consortium, Inc.
22 * 950 Charter Street
23 * Redwood City, CA 94063
24 * <info@isc.org>
25 * http://www.isc.org/
27 * This software has been written for Internet Systems Consortium
28 * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
29 * To learn more about Internet Systems Consortium, see
30 * ``http://www.isc.org/''. To learn more about Vixie Enterprises,
31 * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
32 * ``http://www.nominum.com''.
35 #if 0
36 static char copyright[] =
37 "$Id$ Copyright (c) 2004 Internet Systems Consortium. All rights reserved.\n";
38 #endif
40 #define DHCP_OPTION_DATA
41 #include "dhcpd.h"
42 #include <omapip/omapip_p.h>
44 struct option *vendor_cfg_option;
46 #if 0
47 static void do_option_set PROTO ((pair *,
48 struct option_cache *,
49 enum statement_op));
50 #endif
52 /* Parse all available options out of the specified packet. */
54 int parse_options (packet)
55 struct packet *packet;
57 // int i;
58 struct option_cache *op = (struct option_cache *)0;
60 /* Allocate a new option state. */
61 if (!option_state_allocate (&packet -> options, MDL)) {
62 packet -> options_valid = 0;
63 return 0;
66 /* If we don't see the magic cookie, there's nothing to parse. */
67 if (memcmp (packet -> raw -> options, DHCP_OPTIONS_COOKIE, 4)) {
68 packet -> options_valid = 0;
69 return 1;
72 /* Go through the options field, up to the end of the packet
73 or the End field. */
74 if (!parse_option_buffer (packet -> options,
75 &packet -> raw -> options [4],
76 (packet -> packet_length -
77 DHCP_FIXED_NON_UDP - 4),
78 &dhcp_universe))
79 return 0;
81 /* If we parsed a DHCP Option Overload option, parse more
82 options out of the buffer(s) containing them. */
83 if (packet -> options_valid &&
84 (op = lookup_option (&dhcp_universe, packet -> options,
85 DHO_DHCP_OPTION_OVERLOAD))) {
86 if (op -> data.data [0] & 1) {
87 if (!parse_option_buffer
88 (packet -> options,
89 (unsigned char *)packet -> raw -> file,
90 sizeof packet -> raw -> file,
91 &dhcp_universe))
92 return 0;
94 if (op -> data.data [0] & 2) {
95 if (!parse_option_buffer
96 (packet -> options,
97 (unsigned char *)packet -> raw -> sname,
98 sizeof packet -> raw -> sname,
99 &dhcp_universe))
100 return 0;
103 packet -> options_valid = 1;
104 return 1;
107 /* Parse options out of the specified buffer, storing addresses of option
108 values in packet -> options and setting packet -> options_valid if no
109 errors are encountered. */
111 int parse_option_buffer (options, buffer, length, universe)
112 struct option_state *options;
113 const unsigned char *buffer;
114 unsigned length;
115 struct universe *universe;
117 // unsigned char *t;
118 // const unsigned char *end = buffer + length;
119 unsigned len, offset;
120 int code;
121 struct option_cache *op = (struct option_cache *)0;
122 struct buffer *bp = (struct buffer *)0;
124 if (!buffer_allocate (&bp, length, MDL)) {
125 log_error ("no memory for option buffer.");
126 return 0;
128 memcpy (bp -> data, buffer, length);
130 for (offset = 0; buffer [offset] != DHO_END && offset < length; ) {
131 code = buffer [offset];
132 /* Pad options don't have a length - just skip them. */
133 if (code == DHO_PAD) {
134 ++offset;
135 continue;
138 /* Don't look for length if the buffer isn't that big. */
139 if (offset + 2 > length) {
140 len = 65536;
141 goto bogus;
144 /* All other fields (except end, see above) have a
145 one-byte length. */
146 len = buffer [offset + 1];
148 /* If the length is outrageous, the options are bad. */
149 if (offset + len + 2 > length) {
150 bogus:
151 log_error ("parse_option_buffer: option %s (%d) %s.",
152 dhcp_options [code].name, len,
153 "larger than buffer");
154 buffer_dereference (&bp, MDL);
155 return 0;
158 /* If the option contains an encapsulation, parse it. If
159 the parse fails, or the option isn't an encapsulation (by
160 far the most common case), or the option isn't entirely
161 an encapsulation, keep the raw data as well. */
162 if (universe -> options [code] &&
163 !((universe -> options [code] -> format [0] == 'e' ||
164 universe -> options [code] -> format [0] == 'E') &&
165 (parse_encapsulated_suboptions
166 (options, universe -> options [code],
167 buffer + offset + 2, len,
168 universe, (const char *)0)))) {
169 op = lookup_option (universe, options, code);
170 if (op) {
171 struct data_string new;
172 memset (&new, 0, sizeof new);
173 if (!buffer_allocate (&new.buffer, op -> data.len + len,
174 MDL)) {
175 log_error ("parse_option_buffer: No memory.");
176 return 0;
178 memcpy (new.buffer -> data, op -> data.data,
179 op -> data.len);
180 memcpy (&new.buffer -> data [op -> data.len],
181 &bp -> data [offset + 2], len);
182 new.len = op -> data.len + len;
183 new.data = new.buffer -> data;
184 data_string_forget (&op -> data, MDL);
185 data_string_copy (&op -> data, &new, MDL);
186 data_string_forget (&new, MDL);
187 } else {
188 save_option_buffer (universe, options, bp,
189 &bp -> data [offset + 2], len,
190 universe -> options [code], 1);
193 offset += len + 2;
195 buffer_dereference (&bp, MDL);
196 return 1;
199 /* If an option in an option buffer turns out to be an encapsulation,
200 figure out what to do. If we don't know how to de-encapsulate it,
201 or it's not well-formed, return zero; otherwise, return 1, indicating
202 that we succeeded in de-encapsulating it. */
204 struct universe *find_option_universe (struct option *eopt, const char *uname)
206 int i;
207 char *s, *t;
208 struct universe *universe = (struct universe *)0;
210 /* Look for the E option in the option format. */
211 s = strchr (eopt -> format, 'E');
212 if (!s) {
213 log_error ("internal encapsulation format error 1.");
214 return 0;
216 /* Look for the universe name in the option format. */
217 t = strchr (++s, '.');
218 /* If there was no trailing '.', or there's something after the
219 trailing '.', the option is bogus and we can't use it. */
220 if (!t || t [1]) {
221 log_error ("internal encapsulation format error 2.");
222 return 0;
224 if (t == s && uname) {
225 for (i = 0; i < universe_count; i++) {
226 if (!strcmp (universes [i] -> name, uname)) {
227 universe = universes [i];
228 break;
231 } else if (t != s) {
232 for (i = 0; i < universe_count; i++) {
233 if (strlen (universes [i] -> name) == t - s &&
234 !memcmp (universes [i] -> name,
235 s, (unsigned)(t - s))) {
236 universe = universes [i];
237 break;
241 return universe;
244 /* If an option in an option buffer turns out to be an encapsulation,
245 figure out what to do. If we don't know how to de-encapsulate it,
246 or it's not well-formed, return zero; otherwise, return 1, indicating
247 that we succeeded in de-encapsulating it. */
249 int parse_encapsulated_suboptions (struct option_state *options,
250 struct option *eopt,
251 const unsigned char *buffer,
252 unsigned len, struct universe *eu,
253 const char *uname)
255 int i;
256 struct universe *universe = find_option_universe (eopt, uname);
258 /* If we didn't find the universe, we can't do anything with it
259 right now (e.g., we can't decode vendor options until we've
260 decoded the packet and executed the scopes that it matches). */
261 if (!universe)
262 return 0;
264 /* If we don't have a decoding function for it, we can't decode
265 it. */
266 if (!universe -> decode)
267 return 0;
269 i = (*universe -> decode) (options, buffer, len, universe);
271 /* If there is stuff before the suboptions, we have to keep it. */
272 if (eopt -> format [0] != 'E')
273 return 0;
274 /* Otherwise, return the status of the decode function. */
275 return i;
278 int fqdn_universe_decode (struct option_state *options,
279 const unsigned char *buffer,
280 unsigned length, struct universe *u)
282 // char *name;
283 struct buffer *bp = (struct buffer *)0;
285 /* FQDN options have to be at least four bytes long. */
286 if (length < 3)
287 return 0;
289 /* Save the contents of the option in a buffer. */
290 if (!buffer_allocate (&bp, length + 4, MDL)) {
291 log_error ("no memory for option buffer.");
292 return 0;
294 memcpy (&bp -> data [3], buffer + 1, length - 1);
296 if (buffer [0] & 4) /* encoded */
297 bp -> data [0] = 1;
298 else
299 bp -> data [0] = 0;
300 if (!save_option_buffer (&fqdn_universe, options, bp,
301 &bp -> data [0], 1,
302 &fqdn_options [FQDN_ENCODED], 0)) {
303 bad:
304 buffer_dereference (&bp, MDL);
305 return 0;
308 if (buffer [0] & 1) /* server-update */
309 bp -> data [2] = 1;
310 else
311 bp -> data [2] = 0;
312 if (buffer [0] & 2) /* no-client-update */
313 bp -> data [1] = 1;
314 else
315 bp -> data [1] = 0;
317 /* XXX Ideally we should store the name in DNS format, so if the
318 XXX label isn't in DNS format, we convert it to DNS format,
319 XXX rather than converting labels specified in DNS format to
320 XXX the plain ASCII representation. But that's hard, so
321 XXX not now. */
323 /* Not encoded using DNS format? */
324 if (!bp -> data [0]) {
325 unsigned i;
327 /* Some broken clients NUL-terminate this option. */
328 if (buffer [length - 1] == 0) {
329 --length;
330 bp -> data [1] = 1;
333 /* Determine the length of the hostname component of the
334 name. If the name contains no '.' character, it
335 represents a non-qualified label. */
336 for (i = 3; i < length && buffer [i] != '.'; i++);
337 i -= 3;
339 /* Note: If the client sends a FQDN, the first '.' will
340 be used as a NUL terminator for the hostname. */
341 if (i)
342 if (!save_option_buffer (&fqdn_universe, options, bp,
343 &bp -> data[5], i,
344 &fqdn_options [FQDN_HOSTNAME],
346 goto bad;
347 /* Note: If the client sends a single label, the
348 FQDN_DOMAINNAME option won't be set. */
349 if (length > 4 + i &&
350 !save_option_buffer (&fqdn_universe, options, bp,
351 &bp -> data[6 + i], length - 4 - i,
352 &fqdn_options [FQDN_DOMAINNAME], 1))
353 goto bad;
354 /* Also save the whole name. */
355 if (length > 3)
356 if (!save_option_buffer (&fqdn_universe, options, bp,
357 &bp -> data [5], length - 3,
358 &fqdn_options [FQDN_FQDN], 1))
359 goto bad;
360 } else {
361 unsigned len;
362 unsigned total_len = 0;
363 unsigned first_len = 0;
364 int terminated = 0;
365 unsigned char *s;
367 s = &bp -> data[5];
369 while (s < &bp -> data[0] + length + 2) {
370 len = *s;
371 if (len > 63) {
372 log_info ("fancy bits in fqdn option");
373 return 0;
375 if (len == 0) {
376 terminated = 1;
377 break;
379 if (s + len > &bp -> data [0] + length + 3) {
380 log_info ("fqdn tag longer than buffer");
381 return 0;
384 if (first_len == 0) {
385 first_len = len;
388 *s = '.';
389 s += len + 1;
390 total_len += len + 1;
393 /* We wind up with a length that's one too many because
394 we shouldn't increment for the last label, but there's
395 no way to tell we're at the last label until we exit
396 the loop. :'*/
397 if (total_len > 0)
398 total_len--;
400 if (!terminated) {
401 first_len = total_len;
404 if (first_len > 0 &&
405 !save_option_buffer (&fqdn_universe, options, bp,
406 &bp -> data[6], first_len,
407 &fqdn_options [FQDN_HOSTNAME], 0))
408 goto bad;
409 if (total_len > 0 && first_len != total_len) {
410 if (!save_option_buffer
411 (&fqdn_universe, options, bp,
412 &bp -> data[6 + first_len], total_len - first_len,
413 &fqdn_options [FQDN_DOMAINNAME], 1))
414 goto bad;
416 if (total_len > 0)
417 if (!save_option_buffer (&fqdn_universe, options, bp,
418 &bp -> data [6], total_len,
419 &fqdn_options [FQDN_FQDN], 1))
420 goto bad;
423 if (!save_option_buffer (&fqdn_universe, options, bp,
424 &bp -> data [1], 1,
425 &fqdn_options [FQDN_NO_CLIENT_UPDATE], 0))
426 goto bad;
427 if (!save_option_buffer (&fqdn_universe, options, bp,
428 &bp -> data [2], 1,
429 &fqdn_options [FQDN_SERVER_UPDATE], 0))
430 goto bad;
432 if (!save_option_buffer (&fqdn_universe, options, bp,
433 &bp -> data [3], 1,
434 &fqdn_options [FQDN_RCODE1], 0))
435 goto bad;
436 if (!save_option_buffer (&fqdn_universe, options, bp,
437 &bp -> data [4], 1,
438 &fqdn_options [FQDN_RCODE2], 0))
439 goto bad;
441 buffer_dereference (&bp, MDL);
442 return 1;
445 /* cons options into a big buffer, and then split them out into the
446 three seperate buffers if needed. This allows us to cons up a set
447 of vendor options using the same routine. */
449 int cons_options (inpacket, outpacket, lease, client_state,
450 mms, in_options, cfg_options,
451 scope, overload, terminate, bootpp, prl, vuname)
452 struct packet *inpacket;
453 struct dhcp_packet *outpacket;
454 struct lease *lease;
455 struct client_state *client_state;
456 int mms;
457 struct option_state *in_options;
458 struct option_state *cfg_options;
459 struct binding_scope **scope;
460 int overload; /* Overload flags that may be set. */
461 int terminate;
462 int bootpp;
463 struct data_string *prl;
464 const char *vuname;
466 #define PRIORITY_COUNT 300
467 unsigned priority_list [PRIORITY_COUNT];
468 int priority_len;
469 unsigned char buffer [4096]; /* Really big buffer... */
470 unsigned main_buffer_size;
471 unsigned mainbufix, agentix;
472 // unsigned bufix;
473 // int fileix;
474 // int snameix;
475 unsigned option_size;
476 unsigned length;
477 int i;
478 struct option_cache *op;
479 struct data_string ds;
480 pair pp, *hash;
481 int need_endopt = 0;
482 // int have_sso = 0;
483 int ocount = 0;
484 int ofbuf1=0, ofbuf2=0;
486 memset (&ds, 0, sizeof ds);
488 /* If there's a Maximum Message Size option in the incoming packet
489 and no alternate maximum message size has been specified, take the
490 one in the packet. */
492 if (inpacket &&
493 (op = lookup_option (&dhcp_universe, inpacket -> options,
494 DHO_DHCP_MAX_MESSAGE_SIZE))) {
495 evaluate_option_cache (&ds, inpacket,
496 lease, client_state, in_options,
497 cfg_options, scope, op, MDL);
498 if (ds.len >= sizeof (u_int16_t)) {
499 i = getUShort (ds.data);
501 if(!mms || (i < mms))
502 mms = i;
504 data_string_forget (&ds, MDL);
507 /* If the client has provided a maximum DHCP message size,
508 use that; otherwise, if it's BOOTP, only 64 bytes; otherwise
509 use up to the minimum IP MTU size (576 bytes). */
510 /* XXX if a BOOTP client specifies a max message size, we will
511 honor it. */
513 if (mms) {
514 main_buffer_size = mms - DHCP_FIXED_LEN;
516 /* Enforce a minimum packet size... */
517 if (main_buffer_size < (576 - DHCP_FIXED_LEN))
518 main_buffer_size = 576 - DHCP_FIXED_LEN;
519 } else if (bootpp) {
520 if (inpacket) {
521 main_buffer_size =
522 inpacket -> packet_length - DHCP_FIXED_LEN;
523 if (main_buffer_size < 64)
524 main_buffer_size = 64;
525 } else
526 main_buffer_size = 64;
527 } else
528 main_buffer_size = 576 - DHCP_FIXED_LEN;
530 /* Set a hard limit at the size of the output buffer. */
531 if (main_buffer_size > sizeof buffer)
532 main_buffer_size = sizeof buffer;
534 /* Preload the option priority list with mandatory options. */
535 priority_len = 0;
536 priority_list [priority_len++] = DHO_DHCP_MESSAGE_TYPE;
537 priority_list [priority_len++] = DHO_DHCP_SERVER_IDENTIFIER;
538 priority_list [priority_len++] = DHO_DHCP_LEASE_TIME;
539 priority_list [priority_len++] = DHO_DHCP_MESSAGE;
540 priority_list [priority_len++] = DHO_DHCP_REQUESTED_ADDRESS;
541 priority_list [priority_len++] = DHO_FQDN;
543 if (prl && prl -> len > 0) {
544 if ((op = lookup_option (&dhcp_universe, cfg_options,
545 DHO_SUBNET_SELECTION))) {
546 if (priority_len < PRIORITY_COUNT)
547 priority_list [priority_len++] =
548 DHO_SUBNET_SELECTION;
551 data_string_truncate (prl, (PRIORITY_COUNT - priority_len));
553 for (i = 0; i < prl -> len; i++) {
554 /* Prevent client from changing order of delivery
555 of relay agent information option. */
556 if (prl -> data [i] != DHO_DHCP_AGENT_OPTIONS)
557 priority_list [priority_len++] =
558 prl -> data [i];
560 } else {
561 /* First, hardcode some more options that ought to be
562 sent first... */
563 priority_list [priority_len++] = DHO_SUBNET_MASK;
564 priority_list [priority_len++] = DHO_ROUTERS;
565 priority_list [priority_len++] = DHO_DOMAIN_NAME_SERVERS;
566 priority_list [priority_len++] = DHO_HOST_NAME;
568 /* Append a list of the standard DHCP options from the
569 standard DHCP option space. Actually, if a site
570 option space hasn't been specified, we wind up
571 treating the dhcp option space as the site option
572 space, and the first for loop is skipped, because
573 it's slightly more general to do it this way,
574 taking the 1Q99 DHCP futures work into account. */
575 if (cfg_options -> site_code_min) {
576 for (i = 0; i < OPTION_HASH_SIZE; i++) {
577 hash = cfg_options -> universes [dhcp_universe.index];
578 if (hash) {
579 for (pp = hash [i]; pp; pp = pp -> cdr) {
580 op = (struct option_cache *)(pp -> car);
581 if (op -> option -> code <
582 cfg_options -> site_code_min &&
583 priority_len < PRIORITY_COUNT &&
584 (op -> option -> code !=
585 DHO_DHCP_AGENT_OPTIONS))
586 priority_list [priority_len++] =
587 op -> option -> code;
593 /* Now cycle through the site option space, or if there
594 is no site option space, we'll be cycling through the
595 dhcp option space. */
596 for (i = 0; i < OPTION_HASH_SIZE; i++) {
597 hash = (cfg_options -> universes
598 [cfg_options -> site_universe]);
599 if (hash)
600 for (pp = hash [i]; pp; pp = pp -> cdr) {
601 op = (struct option_cache *)(pp -> car);
602 if (op -> option -> code >=
603 cfg_options -> site_code_min &&
604 priority_len < PRIORITY_COUNT &&
605 (op -> option -> code !=
606 DHO_DHCP_AGENT_OPTIONS))
607 priority_list [priority_len++] =
608 op -> option -> code;
612 /* Now go through all the universes for which options
613 were set and see if there are encapsulations for
614 them; if there are, put the encapsulation options
615 on the priority list as well. */
616 for (i = 0; i < cfg_options -> universe_count; i++) {
617 if (cfg_options -> universes [i] &&
618 universes [i] -> enc_opt &&
619 priority_len < PRIORITY_COUNT &&
620 universes [i] -> enc_opt -> universe == &dhcp_universe)
622 if (universes [i] -> enc_opt -> code !=
623 DHO_DHCP_AGENT_OPTIONS)
624 priority_list [priority_len++] =
625 universes [i] -> enc_opt -> code;
629 /* The vendor option space can't stand on its own, so always
630 add it to the list. */
631 if (priority_len < PRIORITY_COUNT)
632 priority_list [priority_len++] =
633 DHO_VENDOR_ENCAPSULATED_OPTIONS;
636 /* Figure out the overload buffer offset(s). */
637 if (overload) {
638 ofbuf1 = main_buffer_size - 4;
639 if (overload == 3)
640 ofbuf2 = main_buffer_size - 4 + DHCP_FILE_LEN;
643 /* Copy the options into the big buffer... */
644 option_size = store_options (&ocount, buffer,
645 (main_buffer_size - 4 +
646 ((overload & 1) ? DHCP_FILE_LEN : 0) +
647 ((overload & 2) ? DHCP_SNAME_LEN : 0)),
648 inpacket, lease, client_state,
649 in_options, cfg_options, scope,
650 priority_list, priority_len,
651 ofbuf1, ofbuf2, terminate, vuname);
652 /* If store_options failed. */
653 if (option_size == 0)
654 return 0;
655 if (overload) {
656 if (ocount == 1 && (overload & 1))
657 overload = 1;
658 else if (ocount == 1 && (overload & 2))
659 overload = 2;
660 else if (ocount == 3)
661 overload = 3;
662 else
663 overload = 0;
666 /* Put the cookie up front... */
667 memcpy (outpacket -> options, DHCP_OPTIONS_COOKIE, 4);
668 mainbufix = 4;
670 /* If we're going to have to overload, store the overload
671 option at the beginning. If we can, though, just store the
672 whole thing in the packet's option buffer and leave it at
673 that. */
674 memcpy (&outpacket -> options [mainbufix],
675 buffer, option_size);
676 mainbufix += option_size;
677 if (overload) {
678 outpacket -> options [mainbufix++] = DHO_DHCP_OPTION_OVERLOAD;
679 outpacket -> options [mainbufix++] = 1;
680 outpacket -> options [mainbufix++] = overload;
682 if (overload & 1) {
683 memcpy (outpacket -> file,
684 &buffer [ofbuf1], DHCP_FILE_LEN);
686 if (overload & 2) {
687 if (ofbuf2) {
688 memcpy (outpacket -> sname, &buffer [ofbuf2],
689 DHCP_SNAME_LEN);
690 } else {
691 memcpy (outpacket -> sname, &buffer [ofbuf1],
692 DHCP_SNAME_LEN);
696 agentix = mainbufix;
697 if (mainbufix < main_buffer_size)
698 need_endopt = 1;
699 length = DHCP_FIXED_NON_UDP + mainbufix;
701 /* Now hack in the agent options if there are any. */
702 priority_list [0] = DHO_DHCP_AGENT_OPTIONS;
703 priority_len = 1;
704 agentix +=
705 store_options (0, &outpacket -> options [agentix],
706 1500 - DHCP_FIXED_LEN - agentix,
707 inpacket, lease, client_state,
708 in_options, cfg_options, scope,
709 priority_list, priority_len,
710 0, 0, 0, (char *)0);
712 /* Tack a DHO_END option onto the packet if we need to. */
713 if (agentix < 1500 - DHCP_FIXED_LEN && need_endopt)
714 outpacket -> options [agentix++] = DHO_END;
716 /* Figure out the length. */
717 length = DHCP_FIXED_NON_UDP + agentix;
718 return length;
721 /* Store all the requested options into the requested buffer. */
723 int store_options (ocount, buffer, buflen, packet, lease, client_state,
724 in_options, cfg_options, scope, priority_list, priority_len,
725 first_cutoff, second_cutoff, terminate, vuname)
726 int *ocount;
727 unsigned char *buffer;
728 unsigned buflen;
729 struct packet *packet;
730 struct lease *lease;
731 struct client_state *client_state;
732 struct option_state *in_options;
733 struct option_state *cfg_options;
734 struct binding_scope **scope;
735 unsigned *priority_list;
736 int priority_len;
737 unsigned first_cutoff, second_cutoff;
738 int terminate;
739 const char *vuname;
741 int bufix = 0, six = 0, tix = 0;
742 int i;
743 int ix;
744 int tto;
745 int bufend, sbufend;
746 struct data_string od;
747 struct option_cache *oc;
748 unsigned code;
750 if (first_cutoff) {
751 if (first_cutoff >= buflen)
752 log_fatal("%s:%d:store_options: Invalid first cutoff.", MDL);
754 bufend = first_cutoff;
755 } else
756 bufend = buflen;
758 if (second_cutoff) {
759 if (second_cutoff >= buflen)
760 log_fatal("%s:%d:store_options: Invalid second cutoff.", MDL);
762 sbufend = second_cutoff;
763 } else
764 sbufend = buflen;
766 memset (&od, 0, sizeof od);
768 /* Eliminate duplicate options in the parameter request list.
769 There's got to be some clever knuthian way to do this:
770 Eliminate all but the first occurance of a value in an array
771 of values without otherwise disturbing the order of the array. */
772 for (i = 0; i < priority_len - 1; i++) {
773 tto = 0;
774 for (ix = i + 1; ix < priority_len + tto; ix++) {
775 if (tto)
776 priority_list [ix - tto] =
777 priority_list [ix];
778 if (priority_list [i] == priority_list [ix]) {
779 tto++;
780 priority_len--;
785 /* Copy out the options in the order that they appear in the
786 priority list... */
787 for (i = 0; i < priority_len; i++) {
788 /* Number of bytes left to store (some may already
789 have been stored by a previous pass). */
790 unsigned length;
791 int optstart, soptstart, toptstart;
792 struct universe *u;
793 int have_encapsulation = 0;
794 struct data_string encapsulation;
795 int splitup;
797 memset (&encapsulation, 0, sizeof encapsulation);
799 /* Code for next option to try to store. */
800 code = priority_list [i];
802 /* Look up the option in the site option space if the code
803 is above the cutoff, otherwise in the DHCP option space. */
804 if (code >= cfg_options -> site_code_min)
805 u = universes [cfg_options -> site_universe];
806 else
807 u = &dhcp_universe;
809 oc = lookup_option (u, cfg_options, code);
811 /* It's an encapsulation, try to find the universe
812 to be encapsulated first, except that if it's a straight
813 encapsulation and the user has provided a value for the
814 encapsulation option, use the user-provided value. */
815 if (u -> options [code] &&
816 ((u -> options [code] -> format [0] == 'E' && !oc) ||
817 u -> options [code] -> format [0] == 'e')) {
818 // int uix;
819 static char *s, *t;
820 struct option_cache *tmp;
821 struct data_string name;
823 s = strchr (u -> options [code] -> format, 'E');
824 if (s)
825 t = strchr (++s, '.');
826 if (s && t) {
827 memset (&name, 0, sizeof name);
829 /* A zero-length universe name means the vendor
830 option space, if one is defined. */
831 if (t == s) {
832 if (vendor_cfg_option) {
833 tmp = lookup_option (vendor_cfg_option -> universe,
834 cfg_options,
835 vendor_cfg_option -> code);
836 if (tmp)
837 evaluate_option_cache (&name, packet, lease,
838 client_state,
839 in_options,
840 cfg_options,
841 scope, tmp, MDL);
842 } else if (vuname) {
843 name.data = (unsigned char *)s;
844 name.len = strlen (s);
846 } else {
847 name.data = (unsigned char *)s;
848 name.len = t - s;
851 /* If we found a universe, and there are options configured
852 for that universe, try to encapsulate it. */
853 if (name.len) {
854 have_encapsulation =
855 (option_space_encapsulate
856 (&encapsulation, packet, lease, client_state,
857 in_options, cfg_options, scope, &name));
858 data_string_forget (&name, MDL);
863 /* In order to avoid memory leaks, we have to get to here
864 with any option cache that we allocated in tmp not being
865 referenced by tmp, and whatever option cache is referenced
866 by oc being an actual reference. lookup_option doesn't
867 generate a reference (this needs to be fixed), so the
868 preceding goop ensures that if we *didn't* generate a new
869 option cache, oc still winds up holding an actual reference. */
871 /* If no data is available for this option, skip it. */
872 if (!oc && !have_encapsulation) {
873 continue;
876 /* Find the value of the option... */
877 if (oc) {
878 evaluate_option_cache (&od, packet,
879 lease, client_state, in_options,
880 cfg_options, scope, oc, MDL);
881 if (!od.len) {
882 data_string_forget (&encapsulation, MDL);
883 data_string_forget (&od, MDL);
884 have_encapsulation = 0;
885 continue;
889 /* We should now have a constant length for the option. */
890 length = od.len;
891 if (have_encapsulation) {
892 length += encapsulation.len;
893 if (!od.len) {
894 data_string_copy (&od, &encapsulation, MDL);
895 data_string_forget (&encapsulation, MDL);
896 } else {
897 struct buffer *bp = (struct buffer *)0;
898 if (!buffer_allocate (&bp, length, MDL)) {
899 option_cache_dereference (&oc, MDL);
900 data_string_forget (&od, MDL);
901 data_string_forget (&encapsulation, MDL);
902 continue;
904 memcpy (&bp -> data [0], od.data, od.len);
905 memcpy (&bp -> data [od.len], encapsulation.data,
906 encapsulation.len);
907 data_string_forget (&od, MDL);
908 data_string_forget (&encapsulation, MDL);
909 od.data = &bp -> data [0];
910 buffer_reference (&od.buffer, bp, MDL);
911 buffer_dereference (&bp, MDL);
912 od.len = length;
913 od.terminated = 0;
917 /* Do we add a NUL? */
918 if (terminate && dhcp_options [code].format [0] == 't') {
919 length++;
920 tto = 1;
921 } else {
922 tto = 0;
925 /* Try to store the option. */
927 /* If the option's length is more than 255, we must store it
928 in multiple hunks. Store 255-byte hunks first. However,
929 in any case, if the option data will cross a buffer
930 boundary, split it across that boundary. */
933 if (length > 255)
934 splitup = 1;
935 else
936 splitup = 0;
938 ix = 0;
939 optstart = bufix;
940 soptstart = six;
941 toptstart = tix;
942 while (length) {
943 unsigned incr = length;
944 // int consumed = 0;
945 int *pix;
946 char *base;
948 /* Try to fit it in the options buffer. */
949 if (!splitup &&
950 ((!six && !tix && (i == priority_len - 1) &&
951 (bufix + 2 + length < bufend)) ||
952 (bufix + 5 + length < bufend))) {
953 base = buffer;
954 pix = &bufix;
955 /* Try to fit it in the second buffer. */
956 } else if (!splitup && first_cutoff &&
957 (first_cutoff + six + 3 + length < sbufend)) {
958 base = &buffer[first_cutoff];
959 pix = &six;
960 /* Try to fit it in the third buffer. */
961 } else if (!splitup && second_cutoff &&
962 (second_cutoff + tix + 3 + length < buflen)) {
963 base = &buffer[second_cutoff];
964 pix = &tix;
965 /* Split the option up into the remaining space. */
966 } else {
967 splitup = 1;
969 /* Use any remaining options space. */
970 if (bufix + 6 < bufend) {
971 incr = bufend - bufix - 5;
972 base = buffer;
973 pix = &bufix;
974 /* Use any remaining first_cutoff space. */
975 } else if (first_cutoff &&
976 (first_cutoff + six + 4 < sbufend)) {
977 incr = sbufend - (first_cutoff + six) - 3;
978 base = &buffer[first_cutoff];
979 pix = &six;
980 /* Use any remaining second_cutoff space. */
981 } else if (second_cutoff &&
982 (second_cutoff + tix + 4 < buflen)) {
983 incr = buflen - (second_cutoff + tix) - 3;
984 base = &buffer[second_cutoff];
985 pix = &tix;
986 /* Give up, roll back this option. */
987 } else {
988 bufix = optstart;
989 six = soptstart;
990 tix = toptstart;
991 break;
995 if (incr > length)
996 incr = length;
997 if (incr > 255)
998 incr = 255;
1000 /* Everything looks good - copy it in! */
1001 base [*pix] = code;
1002 base [*pix + 1] = (unsigned char)incr;
1003 if (tto && incr == length) {
1004 if (incr > 1)
1005 memcpy (base + *pix + 2,
1006 od.data + ix, (unsigned)(incr - 1));
1007 base [*pix + 2 + incr - 1] = 0;
1008 } else {
1009 memcpy (base + *pix + 2,
1010 od.data + ix, (unsigned)incr);
1012 length -= incr;
1013 ix += incr;
1014 *pix += 2 + incr;
1016 data_string_forget (&od, MDL);
1019 /* If we can overload, and we have, then PAD and END those spaces. */
1020 if (first_cutoff && six) {
1021 if ((first_cutoff + six + 1) < sbufend)
1022 memset (&buffer[first_cutoff + six + 1], DHO_PAD,
1023 sbufend - (first_cutoff + six + 1));
1024 else if (first_cutoff + six >= sbufend)
1025 log_fatal("Second buffer overflow in overloaded options.");
1027 buffer[first_cutoff + six] = DHO_END;
1028 *ocount |= 1; /* So that caller knows there's data there. */
1031 if (second_cutoff && tix) {
1032 if (second_cutoff + tix + 1 < buflen) {
1033 memset (&buffer[second_cutoff + tix + 1], DHO_PAD,
1034 buflen - (second_cutoff + tix + 1));
1035 } else if (second_cutoff + tix >= buflen)
1036 log_fatal("Third buffer overflow in overloaded options.");
1038 buffer[second_cutoff + tix] = DHO_END;
1039 *ocount |= 2; /* So that caller knows there's data there. */
1042 if ((six || tix) && (bufix + 3 > bufend))
1043 log_fatal("Not enough space for option overload option.");
1045 return bufix;
1048 /* Format the specified option so that a human can easily read it. */
1050 const char *pretty_print_option (option, data, len, emit_commas, emit_quotes)
1051 struct option *option;
1052 const unsigned char *data;
1053 unsigned len;
1054 int emit_commas;
1055 int emit_quotes;
1057 static char optbuf [32768]; /* XXX */
1058 int hunksize = 0;
1059 int opthunk = 0;
1060 int hunkinc = 0;
1061 int numhunk = -1;
1062 int numelem = 0;
1063 char fmtbuf [32];
1064 struct enumeration *enumbuf [32];
1065 int i, j, k, l;
1066 char *op = optbuf;
1067 const unsigned char *dp = data;
1068 struct in_addr foo;
1069 char comma;
1070 unsigned long tval;
1072 if (emit_commas)
1073 comma = ',';
1074 else
1075 comma = ' ';
1077 memset (enumbuf, 0, sizeof enumbuf);
1079 /* Figure out the size of the data. */
1080 for (l = i = 0; option -> format [i]; i++, l++) {
1081 if (!numhunk) {
1082 log_error ("%s: Extra codes in format string: %s",
1083 option -> name,
1084 &(option -> format [i]));
1085 break;
1087 numelem++;
1088 fmtbuf [l] = option -> format [i];
1089 switch (option -> format [i]) {
1090 case 'a':
1091 --numelem;
1092 fmtbuf [l] = 0;
1093 numhunk = 0;
1094 break;
1095 case 'A':
1096 --numelem;
1097 fmtbuf [l] = 0;
1098 numhunk = 0;
1099 break;
1100 case 'E':
1101 /* Skip the universe name. */
1102 while (option -> format [i] &&
1103 option -> format [i] != '.')
1104 i++;
1105 case 'X':
1106 for (k = 0; k < len; k++) {
1107 if (!isascii (data [k]) ||
1108 !isprint (data [k]))
1109 break;
1111 /* If we found no bogus characters, or the bogus
1112 character we found is a trailing NUL, it's
1113 okay to print this option as text. */
1114 if (k == len || (k + 1 == len && data [k] == 0)) {
1115 fmtbuf [l] = 't';
1116 numhunk = -2;
1117 } else {
1118 fmtbuf [l] = 'x';
1119 hunksize++;
1120 comma = ':';
1121 numhunk = 0;
1123 fmtbuf [l + 1] = 0;
1124 break;
1125 case 'd':
1126 case 't':
1127 fmtbuf [l] = 't';
1128 fmtbuf [l + 1] = 0;
1129 numhunk = -2;
1130 break;
1131 case 'N':
1132 k = i;
1133 while (option -> format [i] &&
1134 option -> format [i] != '.')
1135 i++;
1136 enumbuf [l] =
1137 find_enumeration (&option -> format [k] + 1,
1138 i - k - 1);
1139 hunksize += 1;
1140 hunkinc = 1;
1141 break;
1142 case 'I':
1143 case 'l':
1144 case 'L':
1145 case 'T':
1146 hunksize += 4;
1147 hunkinc = 4;
1148 break;
1149 case 's':
1150 case 'S':
1151 hunksize += 2;
1152 hunkinc = 2;
1153 break;
1154 case 'b':
1155 case 'B':
1156 case 'f':
1157 hunksize++;
1158 hunkinc = 1;
1159 break;
1160 case 'e':
1161 break;
1162 case 'o':
1163 opthunk += hunkinc;
1164 break;
1165 default:
1166 log_error ("%s: garbage in format string: %s",
1167 option -> name,
1168 &(option -> format [i]));
1169 break;
1173 /* Check for too few bytes... */
1174 if (hunksize - opthunk > len) {
1175 log_error ("%s: expecting at least %d bytes; got %d",
1176 option -> name,
1177 hunksize, len);
1178 return "<error>";
1180 /* Check for too many bytes... */
1181 if (numhunk == -1 && hunksize < len)
1182 log_error ("%s: %d extra bytes",
1183 option -> name,
1184 len - hunksize);
1186 /* If this is an array, compute its size. */
1187 if (!numhunk)
1188 numhunk = len / hunksize;
1189 /* See if we got an exact number of hunks. */
1190 if (numhunk > 0 && numhunk * hunksize < len)
1191 log_error ("%s: %d extra bytes at end of array\n",
1192 option -> name,
1193 len - numhunk * hunksize);
1195 /* A one-hunk array prints the same as a single hunk. */
1196 if (numhunk < 0)
1197 numhunk = 1;
1199 /* Cycle through the array (or hunk) printing the data. */
1200 for (i = 0; i < numhunk; i++) {
1201 for (j = 0; j < numelem; j++) {
1202 switch (fmtbuf [j]) {
1203 case 't':
1204 if (emit_quotes)
1205 *op++ = '"';
1206 for (; dp < data + len; dp++) {
1207 if (!isascii (*dp) ||
1208 !isprint (*dp)) {
1209 /* Skip trailing NUL. */
1210 if (dp + 1 != data + len ||
1211 *dp != 0) {
1212 sprintf (op, "\\%03o",
1213 *dp);
1214 op += 4;
1216 } else if (*dp == '"' ||
1217 *dp == '\'' ||
1218 *dp == '$' ||
1219 *dp == '`' ||
1220 *dp == '\\') {
1221 *op++ = '\\';
1222 *op++ = *dp;
1223 } else
1224 *op++ = *dp;
1226 if (emit_quotes)
1227 *op++ = '"';
1228 *op = 0;
1229 break;
1230 /* pretty-printing an array of enums is
1231 going to get ugly. */
1232 case 'N':
1233 if (!enumbuf [j])
1234 goto enum_as_num;
1235 for (i = 0; ;i++) {
1236 if (!enumbuf [j] -> values [i].name)
1237 goto enum_as_num;
1238 if (enumbuf [j] -> values [i].value ==
1239 *dp)
1240 break;
1242 strcpy (op, enumbuf [j] -> values [i].name);
1243 op += strlen (op);
1244 break;
1245 case 'I':
1246 foo.s_addr = htonl (getULong (dp));
1247 strcpy (op, inet_ntoa (foo));
1248 dp += 4;
1249 break;
1250 case 'l':
1251 sprintf (op, "%ld", (long)getLong (dp));
1252 dp += 4;
1253 break;
1254 case 'T':
1255 tval = getULong (dp);
1256 if (tval == -1)
1257 sprintf (op, "%s", "infinite");
1258 else
1259 sprintf (op, "%ld", tval);
1260 break;
1261 case 'L':
1262 sprintf (op, "%ld",
1263 (unsigned long)getULong (dp));
1264 dp += 4;
1265 break;
1266 case 's':
1267 sprintf (op, "%d", (int)getShort (dp));
1268 dp += 2;
1269 break;
1270 case 'S':
1271 sprintf (op, "%d", (unsigned)getUShort (dp));
1272 dp += 2;
1273 break;
1274 case 'b':
1275 sprintf (op, "%d", *(const char *)dp++);
1276 break;
1277 case 'B':
1278 enum_as_num:
1279 sprintf (op, "%d", *dp++);
1280 break;
1281 case 'x':
1282 sprintf (op, "%x", *dp++);
1283 break;
1284 case 'f':
1285 strcpy (op, *dp++ ? "true" : "false");
1286 break;
1287 default:
1288 log_error ("Unexpected format code %c",
1289 fmtbuf [j]);
1291 op += strlen (op);
1292 if (dp == data + len)
1293 break;
1294 if (j + 1 < numelem && comma != ':')
1295 *op++ = ' ';
1297 if (i + 1 < numhunk) {
1298 *op++ = comma;
1300 if (dp == data + len)
1301 break;
1303 return optbuf;
1306 int get_option (result, universe, packet, lease, client_state,
1307 in_options, cfg_options, options, scope, code, file, line)
1308 struct data_string *result;
1309 struct universe *universe;
1310 struct packet *packet;
1311 struct lease *lease;
1312 struct client_state *client_state;
1313 struct option_state *in_options;
1314 struct option_state *cfg_options;
1315 struct option_state *options;
1316 struct binding_scope **scope;
1317 unsigned code;
1318 const char *file;
1319 int line;
1321 struct option_cache *oc;
1323 if (!universe -> lookup_func)
1324 return 0;
1325 oc = ((*universe -> lookup_func) (universe, options, code));
1326 if (!oc)
1327 return 0;
1328 if (!evaluate_option_cache (result, packet, lease, client_state,
1329 in_options, cfg_options, scope, oc,
1330 file, line))
1331 return 0;
1332 return 1;
1335 void set_option (universe, options, option, op)
1336 struct universe *universe;
1337 struct option_state *options;
1338 struct option_cache *option;
1339 enum statement_op op;
1341 struct option_cache *oc, *noc;
1343 switch (op) {
1344 case if_statement:
1345 case add_statement:
1346 case eval_statement:
1347 case break_statement:
1348 default:
1349 log_error ("bogus statement type in do_option_set.");
1350 break;
1352 case default_option_statement:
1353 oc = lookup_option (universe, options,
1354 option -> option -> code);
1355 if (oc)
1356 break;
1357 save_option (universe, options, option);
1358 break;
1360 case supersede_option_statement:
1361 case send_option_statement:
1362 /* Install the option, replacing any existing version. */
1363 save_option (universe, options, option);
1364 break;
1366 case append_option_statement:
1367 case prepend_option_statement:
1368 oc = lookup_option (universe, options,
1369 option -> option -> code);
1370 if (!oc) {
1371 save_option (universe, options, option);
1372 break;
1374 /* If it's not an expression, make it into one. */
1375 if (!oc -> expression && oc -> data.len) {
1376 if (!expression_allocate (&oc -> expression, MDL)) {
1377 log_error ("Can't allocate const expression.");
1378 break;
1380 oc -> expression -> op = expr_const_data;
1381 data_string_copy
1382 (&oc -> expression -> data.const_data,
1383 &oc -> data, MDL);
1384 data_string_forget (&oc -> data, MDL);
1386 noc = (struct option_cache *)0;
1387 if (!option_cache_allocate (&noc, MDL))
1388 break;
1389 if (op == append_option_statement) {
1390 if (!make_concat (&noc -> expression,
1391 oc -> expression,
1392 option -> expression)) {
1393 option_cache_dereference (&noc, MDL);
1394 break;
1396 } else {
1397 if (!make_concat (&noc -> expression,
1398 option -> expression,
1399 oc -> expression)) {
1400 option_cache_dereference (&noc, MDL);
1401 break;
1404 noc -> option = oc -> option;
1405 save_option (universe, options, noc);
1406 option_cache_dereference (&noc, MDL);
1407 break;
1411 struct option_cache *lookup_option (universe, options, code)
1412 struct universe *universe;
1413 struct option_state *options;
1414 unsigned code;
1416 if (!options)
1417 return (struct option_cache *)0;
1418 if (universe -> lookup_func)
1419 return (*universe -> lookup_func) (universe, options, code);
1420 else
1421 log_error ("can't look up options in %s space.",
1422 universe -> name);
1423 return (struct option_cache *)0;
1426 struct option_cache *lookup_hashed_option (universe, options, code)
1427 struct universe *universe;
1428 struct option_state *options;
1429 unsigned code;
1431 int hashix;
1432 pair bptr;
1433 pair *hash;
1435 /* Make sure there's a hash table. */
1436 if (universe -> index >= options -> universe_count ||
1437 !(options -> universes [universe -> index]))
1438 return (struct option_cache *)0;
1440 hash = options -> universes [universe -> index];
1442 hashix = compute_option_hash (code);
1443 for (bptr = hash [hashix]; bptr; bptr = bptr -> cdr) {
1444 if (((struct option_cache *)(bptr -> car)) -> option -> code ==
1445 code)
1446 return (struct option_cache *)(bptr -> car);
1448 return (struct option_cache *)0;
1451 int save_option_buffer (struct universe *universe,
1452 struct option_state *options,
1453 struct buffer *bp,
1454 unsigned char *buffer, unsigned length,
1455 struct option *option, int tp)
1457 struct buffer *lbp = (struct buffer *)0;
1458 struct option_cache *op = (struct option_cache *)0;
1460 if (!option_cache_allocate (&op, MDL)) {
1461 log_error ("No memory for option %s.%s.",
1462 universe -> name,
1463 option -> name);
1464 return 0;
1467 /* If we weren't passed a buffer in which the data are saved and
1468 refcounted, allocate one now. */
1469 if (!bp) {
1470 if (!buffer_allocate (&lbp, length, MDL)) {
1471 log_error ("no memory for option buffer.");
1473 option_cache_dereference (&op, MDL);
1474 return 0;
1476 memcpy (lbp -> data, buffer, length + tp);
1477 bp = lbp;
1478 buffer = &bp -> data [0]; /* Refer to saved buffer. */
1481 /* Reference buffer copy to option cache. */
1482 op -> data.buffer = (struct buffer *)0;
1483 buffer_reference (&op -> data.buffer, bp, MDL);
1485 /* Point option cache into buffer. */
1486 op -> data.data = buffer;
1487 op -> data.len = length;
1489 if (tp) {
1490 /* NUL terminate (we can get away with this because we (or
1491 the caller!) allocated one more than the buffer size, and
1492 because the byte following the end of an option is always
1493 the code of the next option, which the caller is getting
1494 out of the *original* buffer. */
1495 buffer [length] = 0;
1496 op -> data.terminated = 1;
1497 } else
1498 op -> data.terminated = 0;
1500 op -> option = option;
1502 /* Now store the option. */
1503 save_option (universe, options, op);
1505 /* And let go of our reference. */
1506 option_cache_dereference (&op, MDL);
1508 return 1;
1511 void save_option (struct universe *universe,
1512 struct option_state *options, struct option_cache *oc)
1514 if (universe -> save_func)
1515 (*universe -> save_func) (universe, options, oc);
1516 else
1517 log_error ("can't store options in %s space.",
1518 universe -> name);
1521 void save_hashed_option (universe, options, oc)
1522 struct universe *universe;
1523 struct option_state *options;
1524 struct option_cache *oc;
1526 int hashix;
1527 pair bptr;
1528 pair *hash = options -> universes [universe -> index];
1530 if (oc -> refcnt == 0)
1531 abort ();
1533 /* Compute the hash. */
1534 hashix = compute_option_hash (oc -> option -> code);
1536 /* If there's no hash table, make one. */
1537 if (!hash) {
1538 hash = (pair *)dmalloc (OPTION_HASH_SIZE * sizeof *hash, MDL);
1539 if (!hash) {
1540 log_error ("no memory to store %s.%s",
1541 universe -> name, oc -> option -> name);
1542 return;
1544 memset (hash, 0, OPTION_HASH_SIZE * sizeof *hash);
1545 options -> universes [universe -> index] = (VOIDPTR)hash;
1546 } else {
1547 /* Try to find an existing option matching the new one. */
1548 for (bptr = hash [hashix]; bptr; bptr = bptr -> cdr) {
1549 if (((struct option_cache *)
1550 (bptr -> car)) -> option -> code ==
1551 oc -> option -> code)
1552 break;
1555 /* If we find one, dereference it and put the new one
1556 in its place. */
1557 if (bptr) {
1558 option_cache_dereference
1559 ((struct option_cache **)&bptr -> car, MDL);
1560 option_cache_reference
1561 ((struct option_cache **)&bptr -> car,
1562 oc, MDL);
1563 return;
1567 /* Otherwise, just put the new one at the head of the list. */
1568 bptr = new_pair (MDL);
1569 if (!bptr) {
1570 log_error ("No memory for option_cache reference.");
1571 return;
1573 bptr -> cdr = hash [hashix];
1574 bptr -> car = 0;
1575 option_cache_reference ((struct option_cache **)&bptr -> car, oc, MDL);
1576 hash [hashix] = bptr;
1579 void delete_option (universe, options, code)
1580 struct universe *universe;
1581 struct option_state *options;
1582 int code;
1584 if (universe -> delete_func)
1585 (*universe -> delete_func) (universe, options, code);
1586 else
1587 log_error ("can't delete options from %s space.",
1588 universe -> name);
1591 void delete_hashed_option (universe, options, code)
1592 struct universe *universe;
1593 struct option_state *options;
1594 int code;
1596 int hashix;
1597 pair bptr, prev = (pair)0;
1598 pair *hash = options -> universes [universe -> index];
1600 /* There may not be any options in this space. */
1601 if (!hash)
1602 return;
1604 /* Try to find an existing option matching the new one. */
1605 hashix = compute_option_hash (code);
1606 for (bptr = hash [hashix]; bptr; bptr = bptr -> cdr) {
1607 if (((struct option_cache *)(bptr -> car)) -> option -> code
1608 == code)
1609 break;
1610 prev = bptr;
1612 /* If we found one, wipe it out... */
1613 if (bptr) {
1614 if (prev)
1615 prev -> cdr = bptr -> cdr;
1616 else
1617 hash [hashix] = bptr -> cdr;
1618 option_cache_dereference
1619 ((struct option_cache **)(&bptr -> car), MDL);
1620 free_pair (bptr, MDL);
1624 extern struct option_cache *free_option_caches; /* XXX */
1626 int option_cache_dereference (ptr, file, line)
1627 struct option_cache **ptr;
1628 const char *file;
1629 int line;
1631 if (!ptr || !*ptr) {
1632 log_error ("Null pointer in option_cache_dereference: %s(%d)",
1633 file, line);
1634 #if defined (POINTER_DEBUG)
1635 abort ();
1636 #else
1637 return 0;
1638 #endif
1641 (*ptr) -> refcnt--;
1642 rc_register (file, line, ptr, *ptr, (*ptr) -> refcnt, 1, RC_MISC);
1643 if (!(*ptr) -> refcnt) {
1644 if ((*ptr) -> data.buffer)
1645 data_string_forget (&(*ptr) -> data, file, line);
1646 if ((*ptr) -> expression)
1647 expression_dereference (&(*ptr) -> expression,
1648 file, line);
1649 if ((*ptr) -> next)
1650 option_cache_dereference (&((*ptr) -> next),
1651 file, line);
1652 /* Put it back on the free list... */
1653 (*ptr) -> expression = (struct expression *)free_option_caches;
1654 free_option_caches = *ptr;
1655 dmalloc_reuse (free_option_caches, (char *)0, 0, 0);
1657 if ((*ptr) -> refcnt < 0) {
1658 log_error ("%s(%d): negative refcnt!", file, line);
1659 #if defined (DEBUG_RC_HISTORY)
1660 dump_rc_history (*ptr);
1661 #endif
1662 #if defined (POINTER_DEBUG)
1663 abort ();
1664 #else
1665 *ptr = (struct option_cache *)0;
1666 return 0;
1667 #endif
1669 *ptr = (struct option_cache *)0;
1670 return 1;
1674 int hashed_option_state_dereference (universe, state, file, line)
1675 struct universe *universe;
1676 struct option_state *state;
1677 const char *file;
1678 int line;
1680 pair *heads;
1681 pair cp, next;
1682 int i;
1684 /* Get the pointer to the array of hash table bucket heads. */
1685 heads = (pair *)(state -> universes [universe -> index]);
1686 if (!heads)
1687 return 0;
1689 /* For each non-null head, loop through all the buckets dereferencing
1690 the attached option cache structures and freeing the buckets. */
1691 for (i = 0; i < OPTION_HASH_SIZE; i++) {
1692 for (cp = heads [i]; cp; cp = next) {
1693 next = cp -> cdr;
1694 option_cache_dereference
1695 ((struct option_cache **)&cp -> car,
1696 file, line);
1697 free_pair (cp, file, line);
1701 dfree (heads, file, line);
1702 state -> universes [universe -> index] = (void *)0;
1703 return 1;
1706 int store_option (result, universe, packet, lease, client_state,
1707 in_options, cfg_options, scope, oc)
1708 struct data_string *result;
1709 struct universe *universe;
1710 struct packet *packet;
1711 struct lease *lease;
1712 struct client_state *client_state;
1713 struct option_state *in_options;
1714 struct option_state *cfg_options;
1715 struct binding_scope **scope;
1716 struct option_cache *oc;
1718 struct data_string d1, d2;
1720 memset (&d1, 0, sizeof d1);
1721 memset (&d2, 0, sizeof d2);
1723 if (evaluate_option_cache (&d2, packet, lease, client_state,
1724 in_options, cfg_options, scope, oc, MDL)) {
1725 if (!buffer_allocate (&d1.buffer,
1726 (result -> len +
1727 universe -> length_size +
1728 universe -> tag_size + d2.len), MDL)) {
1729 data_string_forget (result, MDL);
1730 data_string_forget (&d2, MDL);
1731 return 0;
1733 d1.data = &d1.buffer -> data [0];
1734 if (result -> len)
1735 memcpy (d1.buffer -> data,
1736 result -> data, result -> len);
1737 d1.len = result -> len;
1738 (*universe -> store_tag) (&d1.buffer -> data [d1.len],
1739 oc -> option -> code);
1740 d1.len += universe -> tag_size;
1741 (*universe -> store_length) (&d1.buffer -> data [d1.len],
1742 d2.len);
1743 d1.len += universe -> length_size;
1744 memcpy (&d1.buffer -> data [d1.len], d2.data, d2.len);
1745 d1.len += d2.len;
1746 data_string_forget (&d2, MDL);
1747 data_string_forget (result, MDL);
1748 data_string_copy (result, &d1, MDL);
1749 data_string_forget (&d1, MDL);
1750 return 1;
1752 return 0;
1755 int option_space_encapsulate (result, packet, lease, client_state,
1756 in_options, cfg_options, scope, name)
1757 struct data_string *result;
1758 struct packet *packet;
1759 struct lease *lease;
1760 struct client_state *client_state;
1761 struct option_state *in_options;
1762 struct option_state *cfg_options;
1763 struct binding_scope **scope;
1764 struct data_string *name;
1766 struct universe *u;
1768 u = (struct universe *)0;
1769 universe_hash_lookup (&u, universe_hash,
1770 (const char *)name -> data, name -> len, MDL);
1771 if (!u)
1772 return 0;
1774 if (u -> encapsulate)
1775 return (*u -> encapsulate) (result, packet, lease,
1776 client_state,
1777 in_options, cfg_options, scope, u);
1778 log_error ("encapsulation requested for %s with no support.",
1779 name -> data);
1780 return 0;
1783 int hashed_option_space_encapsulate (result, packet, lease, client_state,
1784 in_options, cfg_options, scope, universe)
1785 struct data_string *result;
1786 struct packet *packet;
1787 struct lease *lease;
1788 struct client_state *client_state;
1789 struct option_state *in_options;
1790 struct option_state *cfg_options;
1791 struct binding_scope **scope;
1792 struct universe *universe;
1794 pair p, *hash;
1795 int status;
1796 int i;
1798 if (universe -> index >= cfg_options -> universe_count)
1799 return 0;
1801 hash = cfg_options -> universes [universe -> index];
1802 if (!hash)
1803 return 0;
1805 status = 0;
1806 for (i = 0; i < OPTION_HASH_SIZE; i++) {
1807 for (p = hash [i]; p; p = p -> cdr) {
1808 if (store_option (result, universe, packet,
1809 lease, client_state, in_options,
1810 cfg_options, scope,
1811 (struct option_cache *)p -> car))
1812 status = 1;
1816 return status;
1819 int nwip_option_space_encapsulate (result, packet, lease, client_state,
1820 in_options, cfg_options, scope, universe)
1821 struct data_string *result;
1822 struct packet *packet;
1823 struct lease *lease;
1824 struct client_state *client_state;
1825 struct option_state *in_options;
1826 struct option_state *cfg_options;
1827 struct binding_scope **scope;
1828 struct universe *universe;
1830 pair ocp;
1831 int status;
1832 // int i;
1833 static struct option_cache *no_nwip;
1834 struct data_string ds;
1835 struct option_chain_head *head;
1837 if (universe -> index >= cfg_options -> universe_count)
1838 return 0;
1839 head = ((struct option_chain_head *)
1840 cfg_options -> universes [fqdn_universe.index]);
1841 if (!head)
1842 return 0;
1844 status = 0;
1845 for (ocp = head -> first; ocp; ocp = ocp -> cdr) {
1846 // struct option_cache *oc = (struct option_cache *)(ocp -> car);
1847 if (store_option (result, universe, packet,
1848 lease, client_state, in_options,
1849 cfg_options, scope,
1850 (struct option_cache *)ocp -> car))
1851 status = 1;
1854 /* If there's no data, the nwip suboption is supposed to contain
1855 a suboption saying there's no data. */
1856 if (!status) {
1857 if (!no_nwip) {
1858 static unsigned char nni [] = { 1, 0 };
1859 memset (&ds, 0, sizeof ds);
1860 ds.data = nni;
1861 ds.len = 2;
1862 if (option_cache_allocate (&no_nwip, MDL))
1863 data_string_copy (&no_nwip -> data, &ds, MDL);
1864 no_nwip -> option = nwip_universe.options [1];
1866 if (no_nwip) {
1867 if (store_option (result, universe, packet, lease,
1868 client_state, in_options,
1869 cfg_options, scope, no_nwip))
1870 status = 1;
1872 } else {
1873 memset (&ds, 0, sizeof ds);
1875 /* If we have nwip options, the first one has to be the
1876 nwip-exists-in-option-area option. */
1877 if (!buffer_allocate (&ds.buffer, result -> len + 2, MDL)) {
1878 data_string_forget (result, MDL);
1879 return 0;
1881 ds.data = &ds.buffer -> data [0];
1882 ds.buffer -> data [0] = 2;
1883 ds.buffer -> data [1] = 0;
1884 memcpy (&ds.buffer -> data [2], result -> data, result -> len);
1885 data_string_forget (result, MDL);
1886 data_string_copy (result, &ds, MDL);
1887 data_string_forget (&ds, MDL);
1890 return status;
1893 int fqdn_option_space_encapsulate (result, packet, lease, client_state,
1894 in_options, cfg_options, scope, universe)
1895 struct data_string *result;
1896 struct packet *packet;
1897 struct lease *lease;
1898 struct client_state *client_state;
1899 struct option_state *in_options;
1900 struct option_state *cfg_options;
1901 struct binding_scope **scope;
1902 struct universe *universe;
1904 pair ocp;
1905 struct data_string results [FQDN_SUBOPTION_COUNT + 1];
1906 unsigned i;
1907 unsigned len;
1908 struct buffer *bp = (struct buffer *)0;
1909 struct option_chain_head *head;
1911 /* If there's no FQDN universe, don't encapsulate. */
1912 if (fqdn_universe.index >= cfg_options -> universe_count)
1913 return 0;
1914 head = ((struct option_chain_head *)
1915 cfg_options -> universes [fqdn_universe.index]);
1916 if (!head)
1917 return 0;
1919 /* Figure out the values of all the suboptions. */
1920 memset (results, 0, sizeof results);
1921 for (ocp = head -> first; ocp; ocp = ocp -> cdr) {
1922 struct option_cache *oc = (struct option_cache *)(ocp -> car);
1923 if (oc -> option -> code > FQDN_SUBOPTION_COUNT)
1924 continue;
1925 evaluate_option_cache (&results [oc -> option -> code],
1926 packet, lease, client_state, in_options,
1927 cfg_options, scope, oc, MDL);
1929 len = 4 + results [FQDN_FQDN].len;
1930 /* Save the contents of the option in a buffer. */
1931 if (!buffer_allocate (&bp, len, MDL)) {
1932 log_error ("no memory for option buffer.");
1933 return 0;
1935 buffer_reference (&result -> buffer, bp, MDL);
1936 result -> len = 3;
1937 result -> data = &bp -> data [0];
1939 memset (&bp -> data [0], 0, len);
1940 if (results [FQDN_NO_CLIENT_UPDATE].len &&
1941 results [FQDN_NO_CLIENT_UPDATE].data [0])
1942 bp -> data [0] |= 2;
1943 if (results [FQDN_SERVER_UPDATE].len &&
1944 results [FQDN_SERVER_UPDATE].data [0])
1945 bp -> data [0] |= 1;
1946 if (results [FQDN_RCODE1].len)
1947 bp -> data [1] = results [FQDN_RCODE1].data [0];
1948 if (results [FQDN_RCODE2].len)
1949 bp -> data [2] = results [FQDN_RCODE2].data [0];
1951 if (results [FQDN_ENCODED].len &&
1952 results [FQDN_ENCODED].data [0]) {
1953 unsigned char *out;
1954 int i;
1955 bp -> data [0] |= 4;
1956 out = &bp -> data [3];
1957 if (results [FQDN_FQDN].len) {
1958 i = 0;
1959 while (i < results [FQDN_FQDN].len) {
1960 int j;
1961 for (j = i; ('.' !=
1962 results [FQDN_FQDN].data [j]) &&
1963 j < results [FQDN_FQDN].len; j++)
1965 *out++ = j - i;
1966 memcpy (out, &results [FQDN_FQDN].data [i],
1967 (unsigned)(j - i));
1968 out += j - i;
1969 i = j;
1970 if (results [FQDN_FQDN].data [j] == '.')
1971 i++;
1973 if ((results [FQDN_FQDN].data
1974 [results [FQDN_FQDN].len - 1] == '.'))
1975 *out++ = 0;
1976 result -> len = out - result -> data;
1977 result -> terminated = 0;
1979 } else {
1980 if (results [FQDN_FQDN].len) {
1981 memcpy (&bp -> data [3], results [FQDN_FQDN].data,
1982 results [FQDN_FQDN].len);
1983 result -> len += results [FQDN_FQDN].len;
1984 result -> terminated = 0;
1987 for (i = 1; i <= FQDN_SUBOPTION_COUNT; i++) {
1988 if (results [i].len)
1989 data_string_forget (&results [i], MDL);
1991 buffer_dereference (&bp, MDL);
1992 return 1;
1995 void option_space_foreach (struct packet *packet, struct lease *lease,
1996 struct client_state *client_state,
1997 struct option_state *in_options,
1998 struct option_state *cfg_options,
1999 struct binding_scope **scope,
2000 struct universe *u, void *stuff,
2001 void (*func) (struct option_cache *,
2002 struct packet *,
2003 struct lease *, struct client_state *,
2004 struct option_state *,
2005 struct option_state *,
2006 struct binding_scope **,
2007 struct universe *, void *))
2009 if (u -> foreach)
2010 (*u -> foreach) (packet, lease, client_state, in_options,
2011 cfg_options, scope, u, stuff, func);
2014 void suboption_foreach (struct packet *packet, struct lease *lease,
2015 struct client_state *client_state,
2016 struct option_state *in_options,
2017 struct option_state *cfg_options,
2018 struct binding_scope **scope,
2019 struct universe *u, void *stuff,
2020 void (*func) (struct option_cache *,
2021 struct packet *,
2022 struct lease *, struct client_state *,
2023 struct option_state *,
2024 struct option_state *,
2025 struct binding_scope **,
2026 struct universe *, void *),
2027 struct option_cache *oc,
2028 const char *vsname)
2030 struct universe *universe = find_option_universe (oc -> option,
2031 vsname);
2032 // int i;
2034 if (universe -> foreach)
2035 (*universe -> foreach) (packet, lease, client_state,
2036 in_options, cfg_options,
2037 scope, universe, stuff, func);
2040 void hashed_option_space_foreach (struct packet *packet, struct lease *lease,
2041 struct client_state *client_state,
2042 struct option_state *in_options,
2043 struct option_state *cfg_options,
2044 struct binding_scope **scope,
2045 struct universe *u, void *stuff,
2046 void (*func) (struct option_cache *,
2047 struct packet *,
2048 struct lease *,
2049 struct client_state *,
2050 struct option_state *,
2051 struct option_state *,
2052 struct binding_scope **,
2053 struct universe *, void *))
2055 pair *hash;
2056 int i;
2057 struct option_cache *oc;
2059 if (cfg_options -> universe_count <= u -> index)
2060 return;
2062 hash = cfg_options -> universes [u -> index];
2063 if (!hash)
2064 return;
2065 for (i = 0; i < OPTION_HASH_SIZE; i++) {
2066 pair p;
2067 /* XXX save _all_ options! XXX */
2068 for (p = hash [i]; p; p = p -> cdr) {
2069 oc = (struct option_cache *)p -> car;
2070 (*func) (oc, packet, lease, client_state,
2071 in_options, cfg_options, scope, u, stuff);
2076 void save_linked_option (universe, options, oc)
2077 struct universe *universe;
2078 struct option_state *options;
2079 struct option_cache *oc;
2081 pair *tail;
2082 // pair np = (pair )0;
2083 struct option_chain_head *head;
2085 if (universe -> index >= options -> universe_count)
2086 return;
2087 head = ((struct option_chain_head *)
2088 options -> universes [universe -> index]);
2089 if (!head) {
2090 if (!option_chain_head_allocate (((struct option_chain_head **)
2091 &options -> universes
2092 [universe -> index]), MDL))
2093 return;
2094 head = ((struct option_chain_head *)
2095 options -> universes [universe -> index]);
2098 /* Find the tail of the list. */
2099 for (tail = &head -> first; *tail; tail = &((*tail) -> cdr)) {
2100 if (oc -> option ==
2101 ((struct option_cache *)((*tail) -> car)) -> option) {
2102 option_cache_dereference ((struct option_cache **)
2103 (&(*tail) -> car), MDL);
2104 option_cache_reference ((struct option_cache **)
2105 (&(*tail) -> car), oc, MDL);
2106 return;
2110 *tail = cons (0, 0);
2111 if (*tail) {
2112 option_cache_reference ((struct option_cache **)
2113 (&(*tail) -> car), oc, MDL);
2117 int linked_option_space_encapsulate (result, packet, lease, client_state,
2118 in_options, cfg_options, scope, universe)
2119 struct data_string *result;
2120 struct packet *packet;
2121 struct lease *lease;
2122 struct client_state *client_state;
2123 struct option_state *in_options;
2124 struct option_state *cfg_options;
2125 struct binding_scope **scope;
2126 struct universe *universe;
2128 int status;
2129 pair oc;
2130 struct option_chain_head *head;
2132 if (universe -> index >= cfg_options -> universe_count)
2133 return 0;
2134 head = ((struct option_chain_head *)
2135 cfg_options -> universes [universe -> index]);
2136 if (!head)
2137 return 0;
2139 status = 0;
2140 for (oc = head -> first; oc; oc = oc -> cdr) {
2141 if (store_option (result, universe, packet,
2142 lease, client_state, in_options, cfg_options,
2143 scope, (struct option_cache *)(oc -> car)))
2144 status = 1;
2147 return status;
2150 void delete_linked_option (universe, options, code)
2151 struct universe *universe;
2152 struct option_state *options;
2153 int code;
2155 pair *tail, tmp = (pair)0;
2156 struct option_chain_head *head;
2158 if (universe -> index >= options -> universe_count)
2159 return;
2160 head = ((struct option_chain_head *)
2161 options -> universes [universe -> index]);
2162 if (!head)
2163 return;
2165 for (tail = &head -> first; *tail; tail = &((*tail) -> cdr)) {
2166 if (code ==
2167 ((struct option_cache *)(*tail) -> car) -> option -> code)
2169 tmp = (*tail) -> cdr;
2170 option_cache_dereference ((struct option_cache **)
2171 (&(*tail) -> car), MDL);
2172 dfree (*tail, MDL);
2173 (*tail) = tmp;
2174 break;
2179 struct option_cache *lookup_linked_option (universe, options, code)
2180 struct universe *universe;
2181 struct option_state *options;
2182 unsigned code;
2184 pair oc;
2185 struct option_chain_head *head;
2187 if (universe -> index >= options -> universe_count)
2188 return 0;
2189 head = ((struct option_chain_head *)
2190 options -> universes [universe -> index]);
2191 if (!head)
2192 return 0;
2194 for (oc = head -> first; oc; oc = oc -> cdr) {
2195 if (code ==
2196 ((struct option_cache *)(oc -> car)) -> option -> code) {
2197 return (struct option_cache *)(oc -> car);
2201 return (struct option_cache *)0;
2204 int linked_option_state_dereference (universe, state, file, line)
2205 struct universe *universe;
2206 struct option_state *state;
2207 const char *file;
2208 int line;
2210 return (option_chain_head_dereference
2211 ((struct option_chain_head **)
2212 (&state -> universes [universe -> index]), MDL));
2215 void linked_option_space_foreach (struct packet *packet, struct lease *lease,
2216 struct client_state *client_state,
2217 struct option_state *in_options,
2218 struct option_state *cfg_options,
2219 struct binding_scope **scope,
2220 struct universe *u, void *stuff,
2221 void (*func) (struct option_cache *,
2222 struct packet *,
2223 struct lease *,
2224 struct client_state *,
2225 struct option_state *,
2226 struct option_state *,
2227 struct binding_scope **,
2228 struct universe *, void *))
2230 pair car;
2231 struct option_chain_head *head;
2233 if (u -> index >= cfg_options -> universe_count)
2234 return;
2235 head = ((struct option_chain_head *)
2236 cfg_options -> universes [u -> index]);
2237 if (!head)
2238 return;
2239 for (car = head -> first; car; car = car -> cdr) {
2240 (*func) ((struct option_cache *)(car -> car),
2241 packet, lease, client_state,
2242 in_options, cfg_options, scope, u, stuff);
2246 void do_packet (interface, packet, len, from_port, from, hfrom)
2247 struct interface_info *interface;
2248 struct dhcp_packet *packet;
2249 unsigned len;
2250 unsigned int from_port;
2251 struct iaddr from;
2252 struct hardware *hfrom;
2254 // int i;
2255 struct option_cache *op;
2256 struct packet *decoded_packet;
2257 #if defined (DEBUG_MEMORY_LEAKAGE)
2258 unsigned long previous_outstanding = dmalloc_outstanding;
2259 #endif
2261 #if defined (TRACING)
2262 trace_inpacket_stash (interface, packet, len, from_port, from, hfrom);
2263 #endif
2265 decoded_packet = (struct packet *)0;
2266 if (!packet_allocate (&decoded_packet, MDL)) {
2267 log_error ("do_packet: no memory for incoming packet!");
2268 return;
2270 decoded_packet -> raw = packet;
2271 decoded_packet -> packet_length = len;
2272 decoded_packet -> client_port = from_port;
2273 decoded_packet -> client_addr = from;
2274 interface_reference (&decoded_packet -> interface, interface, MDL);
2275 decoded_packet -> haddr = hfrom;
2277 if (packet -> hlen > sizeof packet -> chaddr) {
2278 packet_dereference (&decoded_packet, MDL);
2279 log_info ("Discarding packet with bogus hlen.");
2280 return;
2283 /* If there's an option buffer, try to parse it. */
2284 if (decoded_packet -> packet_length >= DHCP_FIXED_NON_UDP + 4) {
2285 if (!parse_options (decoded_packet)) {
2286 if (decoded_packet -> options)
2287 option_state_dereference
2288 (&decoded_packet -> options, MDL);
2289 packet_dereference (&decoded_packet, MDL);
2290 return;
2293 if (decoded_packet -> options_valid &&
2294 (op = lookup_option (&dhcp_universe,
2295 decoded_packet -> options,
2296 DHO_DHCP_MESSAGE_TYPE))) {
2297 struct data_string dp;
2298 memset (&dp, 0, sizeof dp);
2299 evaluate_option_cache (&dp, decoded_packet,
2300 (struct lease *)0,
2301 (struct client_state *)0,
2302 decoded_packet -> options,
2303 (struct option_state *)0,
2304 (struct binding_scope **)0,
2305 op, MDL);
2306 if (dp.len > 0)
2307 decoded_packet -> packet_type = dp.data [0];
2308 else
2309 decoded_packet -> packet_type = 0;
2310 data_string_forget (&dp, MDL);
2314 if (decoded_packet -> packet_type)
2315 dhcp (decoded_packet);
2316 else
2317 bootp (decoded_packet);
2319 /* If the caller kept the packet, they'll have upped the refcnt. */
2320 packet_dereference (&decoded_packet, MDL);
2322 #if defined (DEBUG_MEMORY_LEAKAGE)
2323 log_info ("generation %ld: %ld new, %ld outstanding, %ld long-term",
2324 dmalloc_generation,
2325 dmalloc_outstanding - previous_outstanding,
2326 dmalloc_outstanding, dmalloc_longterm);
2327 #endif
2328 #if defined (DEBUG_MEMORY_LEAKAGE)
2329 dmalloc_dump_outstanding ();
2330 #endif
2331 #if defined (DEBUG_RC_HISTORY_EXHAUSTIVELY)
2332 dump_rc_history (0);
2333 #endif