]> git.ipfire.org Git - thirdparty/dhcp.git/blame - common/options.c
- Fix all the OMAPI objects in the DHCP server and client that weren't
[thirdparty/dhcp.git] / common / options.c
CommitLineData
d7837182
TL
1/* options.c
2
3 DHCP options parsing and reassembly. */
4
5/*
49733f31
TL
6 * Copyright (c) 1995-2000 Internet Software Consortium.
7 * All rights reserved.
d7837182 8 *
49733f31
TL
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
d7837182 12 *
49733f31
TL
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of The Internet Software Consortium nor the names
19 * of its contributors may be used to endorse or promote products derived
20 * from this software without specific prior written permission.
d7837182 21 *
49733f31
TL
22 * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
23 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
24 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26 * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
27 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
30 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
33 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 * This software has been written for the Internet Software Consortium
37 * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
38 * To learn more about the Internet Software Consortium, see
39 * ``http://www.isc.org/''. To learn more about Vixie Enterprises,
40 * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
41 * ``http://www.nominum.com''.
d7837182
TL
42 */
43
44#ifndef lint
45static char copyright[] =
20916cae 46"$Id: options.c,v 1.59 2000/05/16 23:02:27 mellon Exp $ Copyright (c) 1995-2000 The Internet Software Consortium. All rights reserved.\n";
d7837182
TL
47#endif /* not lint */
48
49#define DHCP_OPTION_DATA
50#include "dhcpd.h"
4bd8800e 51#include <omapip/omapip_p.h>
d7837182 52
a370b55d 53static void do_option_set PROTO ((pair *,
b4807938
TL
54 struct option_cache *,
55 enum statement_op));
56
d7837182
TL
57/* Parse all available options out of the specified packet. */
58
a370b55d 59int parse_options (packet)
d7837182
TL
60 struct packet *packet;
61{
a370b55d
TL
62 int i;
63 struct option_cache *op = (struct option_cache *)0;
64
c9605ddb 65 /* Allocate a new option state. */
dbf6124a 66 if (!option_state_allocate (&packet -> options, MDL)) {
c9605ddb
TL
67 packet -> options_valid = 0;
68 return 0;
69 }
d7837182
TL
70
71 /* If we don't see the magic cookie, there's nothing to parse. */
72 if (memcmp (packet -> raw -> options, DHCP_OPTIONS_COOKIE, 4)) {
73 packet -> options_valid = 0;
a370b55d 74 return 1;
d7837182
TL
75 }
76
77 /* Go through the options field, up to the end of the packet
78 or the End field. */
a370b55d
TL
79 if (!parse_option_buffer (packet, &packet -> raw -> options [4],
80 (packet -> packet_length -
81 DHCP_FIXED_NON_UDP - 4)))
82 return 0;
83
d7837182
TL
84 /* If we parsed a DHCP Option Overload option, parse more
85 options out of the buffer(s) containing them. */
a370b55d 86 if (packet -> options_valid &&
c9605ddb 87 (op = lookup_option (&dhcp_universe, packet -> options,
a370b55d
TL
88 DHO_DHCP_OPTION_OVERLOAD))) {
89 if (op -> data.data [0] & 1) {
90 if (!parse_option_buffer
91 (packet, (unsigned char *)packet -> raw -> file,
92 sizeof packet -> raw -> file))
93 return 0;
94 }
95 if (op -> data.data [0] & 2) {
96 if (!parse_option_buffer
97 (packet,
98 (unsigned char *)packet -> raw -> sname,
99 sizeof packet -> raw -> sname))
100 return 0;
101 }
d7837182 102 }
a370b55d 103 return 1;
d7837182
TL
104}
105
106/* Parse options out of the specified buffer, storing addresses of option
107 values in packet -> options and setting packet -> options_valid if no
108 errors are encountered. */
109
a370b55d 110int parse_option_buffer (packet, buffer, length)
d7837182
TL
111 struct packet *packet;
112 unsigned char *buffer;
b1b7b521 113 unsigned length;
d7837182 114{
a370b55d 115 unsigned char *t;
d7837182 116 unsigned char *end = buffer + length;
a370b55d 117 int len, offset;
d7837182 118 int code;
a370b55d
TL
119 struct option_cache *op = (struct option_cache *)0;
120 struct buffer *bp = (struct buffer *)0;
d7837182 121
dbf6124a 122 if (!buffer_allocate (&bp, length, MDL)) {
c9605ddb 123 log_error ("no memory for option buffer.");
a370b55d
TL
124 return 0;
125 }
126 memcpy (bp -> data, buffer, length);
127
128 for (offset = 0; buffer [offset] != DHO_END && offset < length; ) {
129 code = buffer [offset];
d7837182
TL
130 /* Pad options don't have a length - just skip them. */
131 if (code == DHO_PAD) {
a370b55d 132 ++offset;
d7837182
TL
133 continue;
134 }
a370b55d 135
d7837182
TL
136 /* All other fields (except end, see above) have a
137 one-byte length. */
a370b55d 138 len = buffer [offset + 1];
a3e52198 139
d7837182 140 /* If the length is outrageous, the options are bad. */
a370b55d 141 if (offset + len + 2 > length) {
c9605ddb
TL
142 log_error ("Client option %s (%d) larger than buffer.",
143 dhcp_options [code].name, len);
dbf6124a 144 buffer_dereference (&bp, MDL);
a370b55d 145 return 0;
d7837182 146 }
81477e91
TL
147
148 /* If this is a Relay Agent Information option, we must
149 handle it specially. */
150 if (code == DHO_DHCP_AGENT_OPTIONS) {
a370b55d
TL
151 if (!parse_agent_information_option
152 (packet, len, buffer + offset + 2)) {
c9605ddb 153 log_error ("bad agent information option.");
dbf6124a 154 buffer_dereference (&bp, MDL);
a370b55d 155 return 0;
81477e91 156 }
d7837182 157 } else {
dbf6124a 158 if (!option_cache_allocate (&op, MDL)) {
c9605ddb
TL
159 log_error ("No memory for option %s.",
160 dhcp_options [code].name);
dbf6124a 161 buffer_dereference (&bp, MDL);
a370b55d
TL
162 return 0;
163 }
164
165 /* Reference buffer copy to option cache. */
166 op -> data.buffer = (struct buffer *)0;
dbf6124a 167 buffer_reference (&op -> data.buffer, bp, MDL);
a370b55d
TL
168
169 /* Point option cache into buffer. */
170 op -> data.data = &bp -> data [offset + 2];
171 op -> data.len = len;
172
173 /* NUL terminate (we can get away with this
174 because we allocated one more than the
175 buffer size, and because the byte following
176 the end of an option is always the code of
177 the next option, which we're getting out of
178 the *original* buffer. */
179 bp -> data [offset + 2 + len] = 0;
180 op -> data.terminated = 1;
181
182 op -> option = &dhcp_options [code];
183 /* Now store the option. */
c9605ddb 184 save_option (&dhcp_universe, packet -> options, op);
a370b55d
TL
185
186 /* And let go of our reference. */
dbf6124a 187 option_cache_dereference (&op, MDL);
d7837182 188 }
a370b55d 189 offset += len + 2;
d7837182
TL
190 }
191 packet -> options_valid = 1;
dbf6124a 192 buffer_dereference (&bp, MDL);
a370b55d 193 return 1;
d7837182
TL
194}
195
a3e52198
TL
196/* cons options into a big buffer, and then split them out into the
197 three seperate buffers if needed. This allows us to cons up a set
198 of vendor options using the same routine. */
199
4038ec52 200int cons_options (inpacket, outpacket, lease, mms, in_options, cfg_options,
dbf6124a 201 scope, overload, terminate, bootpp, prl)
a3e52198 202 struct packet *inpacket;
a4cb16ca 203 struct dhcp_packet *outpacket;
da38df14 204 struct lease *lease;
81477e91 205 int mms;
4038ec52
TL
206 struct option_state *in_options;
207 struct option_state *cfg_options;
dbf6124a 208 struct binding_scope *scope;
a3e52198 209 int overload; /* Overload flags that may be set. */
c34fcd38 210 int terminate;
eb0a9b2a 211 int bootpp;
ce0ec46d 212 struct data_string *prl;
a3e52198 213{
a370b55d 214#define PRIORITY_COUNT 300
e703795d 215 unsigned priority_list [PRIORITY_COUNT];
a3e52198
TL
216 int priority_len;
217 unsigned char buffer [4096]; /* Really big buffer... */
b1b7b521
TL
218 unsigned main_buffer_size;
219 unsigned mainbufix, bufix, agentix;
220 unsigned option_size;
221 unsigned length;
a370b55d
TL
222 int i;
223 struct option_cache *op;
224 struct data_string ds;
c9605ddb 225 pair pp, *hash;
a370b55d
TL
226
227 memset (&ds, 0, sizeof ds);
a3e52198 228
81477e91
TL
229 /* If there's a Maximum Message Size option in the incoming packet
230 and no alternate maximum message size has been specified, take the
231 one in the packet. */
232
a370b55d 233 if (!mms && inpacket &&
c9605ddb 234 (op = lookup_option (&dhcp_universe, inpacket -> options,
a370b55d 235 DHO_DHCP_MAX_MESSAGE_SIZE))) {
dbf6124a
TL
236 evaluate_option_cache (&ds, inpacket, lease, in_options,
237 cfg_options, scope, op, MDL);
a370b55d
TL
238 if (ds.len >= sizeof (u_int16_t))
239 mms = getUShort (ds.data);
dbf6124a 240 data_string_forget (&ds, MDL);
81477e91
TL
241 }
242
a3e52198 243 /* If the client has provided a maximum DHCP message size,
eb0a9b2a
TL
244 use that; otherwise, if it's BOOTP, only 64 bytes; otherwise
245 use up to the minimum IP MTU size (576 bytes). */
246 /* XXX if a BOOTP client specifies a max message size, we will
247 honor it. */
81477e91
TL
248
249 if (mms) {
250 main_buffer_size = mms - DHCP_FIXED_LEN;
251
a8b53b42
TL
252 /* Enforce a minimum packet size... */
253 if (main_buffer_size < (576 - DHCP_FIXED_LEN))
254 main_buffer_size = 576 - DHCP_FIXED_LEN;
0a98d498
TL
255 } else if (bootpp) {
256 if (inpacket) {
257 main_buffer_size =
258 inpacket -> packet_length - DHCP_FIXED_LEN;
259 if (main_buffer_size < 64)
260 main_buffer_size = 64;
261 } else
262 main_buffer_size = 64;
263 } else
a3e52198
TL
264 main_buffer_size = 576 - DHCP_FIXED_LEN;
265
81477e91
TL
266 /* Set a hard limit at the size of the output buffer. */
267 if (main_buffer_size > sizeof buffer)
268 main_buffer_size = sizeof buffer;
269
a3e52198
TL
270 /* Preload the option priority list with mandatory options. */
271 priority_len = 0;
272 priority_list [priority_len++] = DHO_DHCP_MESSAGE_TYPE;
273 priority_list [priority_len++] = DHO_DHCP_SERVER_IDENTIFIER;
274 priority_list [priority_len++] = DHO_DHCP_LEASE_TIME;
275 priority_list [priority_len++] = DHO_DHCP_MESSAGE;
a370b55d 276 priority_list [priority_len++] = DHO_DHCP_REQUESTED_ADDRESS;
a3e52198 277
ce0ec46d
TL
278 if (prl && prl -> len > 0) {
279 data_string_truncate (prl, (PRIORITY_COUNT - priority_len));
a3e52198 280
ce0ec46d
TL
281 for (i = 0; i < prl -> len; i++)
282 priority_list [priority_len++] = prl -> data [i];
a3e52198 283 } else {
a370b55d
TL
284 /* First, hardcode some more options that ought to be
285 sent first... */
286 priority_list [priority_len++] = DHO_SUBNET_MASK;
287 priority_list [priority_len++] = DHO_ROUTERS;
288 priority_list [priority_len++] = DHO_DOMAIN_NAME_SERVERS;
289 priority_list [priority_len++] = DHO_HOST_NAME;
290
33c85638
TL
291 /* Append a list of the standard DHCP options from the
292 standard DHCP option space. Actually, if a site
293 option space hasn't been specified, we wind up
294 treating the dhcp option space as the site option
295 space, and the first for loop is skipped, because
296 it's slightly more general to do it this way,
297 taking the 1Q99 DHCP futures work into account. */
4038ec52 298 if (cfg_options -> site_code_min) {
33c85638 299 for (i = 0; i < OPTION_HASH_SIZE; i++) {
4038ec52 300 hash = cfg_options -> universes [dhcp_universe.index];
c9605ddb 301 for (pp = hash [i]; pp; pp = pp -> cdr) {
a370b55d 302 op = (struct option_cache *)(pp -> car);
33c85638 303 if (op -> option -> code <
4038ec52 304 cfg_options -> site_code_min &&
33c85638 305 priority_len < PRIORITY_COUNT)
a370b55d
TL
306 priority_list [priority_len++] =
307 op -> option -> code;
308 }
33c85638 309 }
a370b55d 310 }
33c85638
TL
311
312 /* Now cycle through the site option space, or if there
313 is no site option space, we'll be cycling through the
314 dhcp option space. */
315 for (i = 0; i < OPTION_HASH_SIZE; i++) {
4038ec52
TL
316 hash = (cfg_options -> universes
317 [cfg_options -> site_universe]);
33c85638
TL
318 for (pp = hash [i]; pp; pp = pp -> cdr) {
319 op = (struct option_cache *)(pp -> car);
320 if (op -> option -> code >=
4038ec52 321 cfg_options -> site_code_min &&
33c85638
TL
322 priority_len < PRIORITY_COUNT)
323 priority_list [priority_len++] =
324 op -> option -> code;
325 }
326 }
a3e52198
TL
327 }
328
a3e52198 329 /* Copy the options into the big buffer... */
1a74d33b
TL
330 option_size = store_options (buffer,
331 (main_buffer_size - 7 +
332 ((overload & 1) ? DHCP_FILE_LEN : 0) +
333 ((overload & 2) ? DHCP_SNAME_LEN : 0)),
4038ec52 334 inpacket,
da38df14 335 lease,
dbf6124a 336 in_options, cfg_options, scope,
b4807938 337 priority_list, priority_len,
1a74d33b
TL
338 main_buffer_size,
339 (main_buffer_size +
c34fcd38
TL
340 ((overload & 1) ? DHCP_FILE_LEN : 0)),
341 terminate);
a3e52198 342
1a74d33b 343 /* Put the cookie up front... */
a4cb16ca 344 memcpy (outpacket -> options, DHCP_OPTIONS_COOKIE, 4);
1a74d33b
TL
345 mainbufix = 4;
346
347 /* If we're going to have to overload, store the overload
348 option at the beginning. If we can, though, just store the
349 whole thing in the packet's option buffer and leave it at
350 that. */
351 if (option_size <= main_buffer_size - mainbufix) {
a4cb16ca 352 memcpy (&outpacket -> options [mainbufix],
1a74d33b
TL
353 buffer, option_size);
354 mainbufix += option_size;
81477e91
TL
355 if (mainbufix < main_buffer_size) {
356 agentix = mainbufix;
a370b55d 357 outpacket -> options [mainbufix++] = DHO_END;
81477e91
TL
358 } else
359 agentix = mainbufix;
a4cb16ca 360 length = DHCP_FIXED_NON_UDP + mainbufix;
1a74d33b 361 } else {
a370b55d 362 outpacket -> options [mainbufix++] = DHO_DHCP_OPTION_OVERLOAD;
a4cb16ca 363 outpacket -> options [mainbufix++] = 1;
1a74d33b 364 if (option_size > main_buffer_size - mainbufix + DHCP_FILE_LEN)
a4cb16ca 365 outpacket -> options [mainbufix++] = 3;
1a74d33b 366 else
a4cb16ca 367 outpacket -> options [mainbufix++] = 1;
1a74d33b 368
a4cb16ca 369 memcpy (&outpacket -> options [mainbufix],
1a74d33b 370 buffer, main_buffer_size - mainbufix);
81477e91
TL
371 length = DHCP_FIXED_NON_UDP + main_buffer_size;
372 agentix = main_buffer_size;
373
1a74d33b 374 bufix = main_buffer_size - mainbufix;
1a74d33b
TL
375 if (overload & 1) {
376 if (option_size - bufix <= DHCP_FILE_LEN) {
a4cb16ca 377 memcpy (outpacket -> file,
1a74d33b
TL
378 &buffer [bufix], option_size - bufix);
379 mainbufix = option_size - bufix;
380 if (mainbufix < DHCP_FILE_LEN)
a4cb16ca 381 outpacket -> file [mainbufix++]
1a74d33b
TL
382 = DHO_END;
383 while (mainbufix < DHCP_FILE_LEN)
a4cb16ca 384 outpacket -> file [mainbufix++]
1a74d33b
TL
385 = DHO_PAD;
386 } else {
a4cb16ca 387 memcpy (outpacket -> file,
1a74d33b
TL
388 &buffer [bufix], DHCP_FILE_LEN);
389 bufix += DHCP_FILE_LEN;
390 }
391 }
392 if ((overload & 2) && option_size < bufix) {
a4cb16ca 393 memcpy (outpacket -> sname,
1a74d33b
TL
394 &buffer [bufix], option_size - bufix);
395
396 mainbufix = option_size - bufix;
397 if (mainbufix < DHCP_SNAME_LEN)
a4cb16ca 398 outpacket -> file [mainbufix++]
1a74d33b
TL
399 = DHO_END;
400 while (mainbufix < DHCP_SNAME_LEN)
a4cb16ca 401 outpacket -> file [mainbufix++]
1a74d33b
TL
402 = DHO_PAD;
403 }
404 }
81477e91 405
d9c0544c
TL
406 length = cons_agent_information_options (cfg_options,
407 outpacket, agentix, length);
81477e91 408
a4cb16ca 409 return length;
a3e52198
TL
410}
411
412/* Store all the requested options into the requested buffer. */
413
4038ec52 414int store_options (buffer, buflen, packet, lease,
dbf6124a 415 in_options, cfg_options, scope, priority_list,
4038ec52 416 priority_len, first_cutoff, second_cutoff, terminate)
a3e52198 417 unsigned char *buffer;
b1b7b521 418 unsigned buflen;
4038ec52 419 struct packet *packet;
da38df14 420 struct lease *lease;
4038ec52
TL
421 struct option_state *in_options;
422 struct option_state *cfg_options;
dbf6124a 423 struct binding_scope *scope;
b1b7b521 424 unsigned *priority_list;
a3e52198 425 int priority_len;
b1b7b521 426 unsigned first_cutoff, second_cutoff;
c34fcd38 427 int terminate;
a3e52198
TL
428{
429 int bufix = 0;
a3e52198
TL
430 int i;
431 int ix;
c34fcd38 432 int tto;
b4807938 433 struct data_string od;
a370b55d 434 struct option_cache *oc;
a3e52198 435
a370b55d
TL
436 memset (&od, 0, sizeof od);
437
438 /* Eliminate duplicate options in the parameter request list.
439 There's got to be some clever knuthian way to do this:
440 Eliminate all but the first occurance of a value in an array
441 of values without otherwise disturbing the order of the array. */
442 for (i = 0; i < priority_len - 1; i++) {
443 tto = 0;
444 for (ix = i + 1; ix < priority_len + tto; ix++) {
445 if (tto)
446 priority_list [ix - tto] =
447 priority_list [ix];
448 if (priority_list [i] == priority_list [ix]) {
449 tto++;
450 priority_len--;
451 }
452 }
453 }
a3e52198
TL
454
455 /* Copy out the options in the order that they appear in the
456 priority list... */
457 for (i = 0; i < priority_len; i++) {
458 /* Code for next option to try to store. */
b1b7b521 459 unsigned code = priority_list [i];
1a74d33b 460 int optstart;
a3e52198
TL
461
462 /* Number of bytes left to store (some may already
463 have been stored by a previous pass). */
464 int length;
465
33c85638
TL
466 /* Look up the option in the site option space if the code
467 is above the cutoff, otherwise in the DHCP option space. */
4038ec52 468 if (code >= cfg_options -> site_code_min)
33c85638 469 oc = lookup_option
4038ec52
TL
470 (universes [cfg_options -> site_universe],
471 cfg_options, code);
33c85638 472 else
4038ec52 473 oc = lookup_option (&dhcp_universe, cfg_options, code);
33c85638 474
a3e52198 475 /* If no data is available for this option, skip it. */
33c85638 476 if (!oc) {
a3e52198
TL
477 continue;
478 }
479
a3e52198 480 /* Find the value of the option... */
dbf6124a
TL
481 evaluate_option_cache (&od, packet, lease, in_options,
482 cfg_options, scope, oc, MDL);
a370b55d 483 if (!od.len) {
6f76b6ac 484 continue;
a370b55d 485 }
6f76b6ac 486
a3e52198 487 /* We should now have a constant length for the option. */
b4807938 488 length = od.len;
a3e52198 489
c34fcd38
TL
490 /* Do we add a NUL? */
491 if (terminate && dhcp_options [code].format [0] == 't') {
492 length++;
493 tto = 1;
494 } else {
495 tto = 0;
496 }
497
1a74d33b 498 /* Try to store the option. */
a3e52198
TL
499
500 /* If the option's length is more than 255, we must store it
1a74d33b
TL
501 in multiple hunks. Store 255-byte hunks first. However,
502 in any case, if the option data will cross a buffer
503 boundary, split it across that boundary. */
a3e52198
TL
504
505 ix = 0;
506
1a74d33b 507 optstart = bufix;
a3e52198
TL
508 while (length) {
509 unsigned char incr = length > 255 ? 255 : length;
1a74d33b
TL
510
511 /* If this hunk of the buffer will cross a
512 boundary, only go up to the boundary in this
513 pass. */
514 if (bufix < first_cutoff &&
515 bufix + incr > first_cutoff)
516 incr = first_cutoff - bufix;
517 else if (bufix < second_cutoff &&
518 bufix + incr > second_cutoff)
519 incr = second_cutoff - bufix;
520
521 /* If this option is going to overflow the buffer,
522 skip it. */
523 if (bufix + 2 + incr > buflen) {
524 bufix = optstart;
525 break;
526 }
527
528 /* Everything looks good - copy it in! */
a3e52198
TL
529 buffer [bufix] = code;
530 buffer [bufix + 1] = incr;
c34fcd38
TL
531 if (tto && incr == length) {
532 memcpy (buffer + bufix + 2,
b1b7b521 533 od.data + ix, (unsigned)(incr - 1));
c34fcd38
TL
534 buffer [bufix + 2 + incr - 1] = 0;
535 } else {
536 memcpy (buffer + bufix + 2,
b1b7b521 537 od.data + ix, (unsigned)incr);
c34fcd38 538 }
a3e52198
TL
539 length -= incr;
540 ix += incr;
541 bufix += 2 + incr;
542 }
dbf6124a 543 data_string_forget (&od, MDL);
a3e52198
TL
544 }
545 return bufix;
d7837182
TL
546}
547
548/* Format the specified option so that a human can easily read it. */
549
b1b7b521 550const char *pretty_print_option (code, data, len, emit_commas, emit_quotes)
a9a9b7f1 551 unsigned int code;
b1b7b521
TL
552 const unsigned char *data;
553 unsigned len;
171c47a6 554 int emit_commas;
a9a9b7f1 555 int emit_quotes;
d7837182
TL
556{
557 static char optbuf [32768]; /* XXX */
558 int hunksize = 0;
559 int numhunk = -1;
560 int numelem = 0;
561 char fmtbuf [32];
c6e7518c 562 int i, j, k;
d7837182 563 char *op = optbuf;
b1b7b521 564 const unsigned char *dp = data;
d7837182 565 struct in_addr foo;
17f4dab7 566 char comma;
d7837182 567
a9a9b7f1
TL
568 /* Code should be between 0 and 255. */
569 if (code > 255)
8ae2d595 570 log_fatal ("pretty_print_option: bad code %d\n", code);
a9a9b7f1 571
17f4dab7
TL
572 if (emit_commas)
573 comma = ',';
574 else
575 comma = ' ';
576
d7837182
TL
577 /* Figure out the size of the data. */
578 for (i = 0; dhcp_options [code].format [i]; i++) {
579 if (!numhunk) {
c9605ddb 580 log_error ("%s: Extra codes in format string: %s\n",
c6e7518c
TL
581 dhcp_options [code].name,
582 &(dhcp_options [code].format [i]));
d7837182
TL
583 break;
584 }
585 numelem++;
586 fmtbuf [i] = dhcp_options [code].format [i];
587 switch (dhcp_options [code].format [i]) {
588 case 'A':
589 --numelem;
590 fmtbuf [i] = 0;
591 numhunk = 0;
592 break;
17f4dab7 593 case 'X':
c6e7518c
TL
594 for (k = 0; k < len; k++) {
595 if (!isascii (data [k]) ||
596 !isprint (data [k]))
597 break;
598 }
dbf6124a
TL
599 /* If we found no bogus characters, or the bogus
600 character we found is a trailing NUL, it's
601 okay to print this option as text. */
602 if (k == len || (k + 1 == len && data [k] == 0)) {
c6e7518c
TL
603 fmtbuf [i] = 't';
604 numhunk = -2;
605 } else {
606 fmtbuf [i] = 'x';
607 hunksize++;
608 comma = ':';
609 numhunk = 0;
610 }
17f4dab7 611 fmtbuf [i + 1] = 0;
17f4dab7 612 break;
d7837182
TL
613 case 't':
614 fmtbuf [i] = 't';
615 fmtbuf [i + 1] = 0;
616 numhunk = -2;
617 break;
618 case 'I':
619 case 'l':
620 case 'L':
621 hunksize += 4;
622 break;
623 case 's':
624 case 'S':
625 hunksize += 2;
626 break;
627 case 'b':
628 case 'B':
629 case 'f':
630 hunksize++;
631 break;
632 case 'e':
633 break;
634 default:
8ae2d595 635 log_error ("%s: garbage in format string: %s\n",
d7837182
TL
636 dhcp_options [code].name,
637 &(dhcp_options [code].format [i]));
638 break;
639 }
640 }
641
642 /* Check for too few bytes... */
643 if (hunksize > len) {
8ae2d595 644 log_error ("%s: expecting at least %d bytes; got %d",
d7837182
TL
645 dhcp_options [code].name,
646 hunksize, len);
647 return "<error>";
648 }
649 /* Check for too many bytes... */
650 if (numhunk == -1 && hunksize < len)
8ae2d595 651 log_error ("%s: %d extra bytes",
d7837182
TL
652 dhcp_options [code].name,
653 len - hunksize);
654
655 /* If this is an array, compute its size. */
656 if (!numhunk)
657 numhunk = len / hunksize;
658 /* See if we got an exact number of hunks. */
659 if (numhunk > 0 && numhunk * hunksize < len)
8ae2d595 660 log_error ("%s: %d extra bytes at end of array\n",
d7837182
TL
661 dhcp_options [code].name,
662 len - numhunk * hunksize);
663
664 /* A one-hunk array prints the same as a single hunk. */
665 if (numhunk < 0)
666 numhunk = 1;
667
d7837182
TL
668 /* Cycle through the array (or hunk) printing the data. */
669 for (i = 0; i < numhunk; i++) {
670 for (j = 0; j < numelem; j++) {
671 switch (fmtbuf [j]) {
672 case 't':
a9a9b7f1
TL
673 if (emit_quotes)
674 *op++ = '"';
b1b7b521
TL
675 strcpy (op, (const char *)dp);
676 op += strlen ((const char *)dp);
a9a9b7f1
TL
677 if (emit_quotes)
678 *op++ = '"';
171c47a6 679 *op = 0;
d7837182
TL
680 break;
681 case 'I':
682 foo.s_addr = htonl (getULong (dp));
683 strcpy (op, inet_ntoa (foo));
684 dp += 4;
685 break;
686 case 'l':
67bb0d24 687 sprintf (op, "%ld", (long)getLong (dp));
d7837182
TL
688 dp += 4;
689 break;
690 case 'L':
67bb0d24
TL
691 sprintf (op, "%ld",
692 (unsigned long)getULong (dp));
d7837182
TL
693 dp += 4;
694 break;
695 case 's':
2c9c0291 696 sprintf (op, "%d", (int)getShort (dp));
d7837182
TL
697 dp += 2;
698 break;
699 case 'S':
2c9c0291 700 sprintf (op, "%d", (unsigned)getUShort (dp));
d7837182
TL
701 dp += 2;
702 break;
703 case 'b':
b1b7b521 704 sprintf (op, "%d", *(const char *)dp++);
d7837182
TL
705 break;
706 case 'B':
707 sprintf (op, "%d", *dp++);
708 break;
17f4dab7
TL
709 case 'x':
710 sprintf (op, "%x", *dp++);
711 break;
d7837182
TL
712 case 'f':
713 strcpy (op, *dp++ ? "true" : "false");
714 break;
715 default:
c9605ddb
TL
716 log_error ("Unexpected format code %c",
717 fmtbuf [j]);
d7837182
TL
718 }
719 op += strlen (op);
17f4dab7 720 if (j + 1 < numelem && comma != ':')
29539f1a
TL
721 *op++ = ' ';
722 }
723 if (i + 1 < numhunk) {
17f4dab7 724 *op++ = comma;
d7837182 725 }
29539f1a 726
d7837182 727 }
d7837182
TL
728 return optbuf;
729}
17f4dab7 730
4038ec52 731int hashed_option_get (result, universe, packet, lease,
dbf6124a 732 in_options, cfg_options, options, scope, code)
a370b55d 733 struct data_string *result;
c9605ddb 734 struct universe *universe;
da38df14
TL
735 struct packet *packet;
736 struct lease *lease;
4038ec52
TL
737 struct option_state *in_options;
738 struct option_state *cfg_options;
a370b55d 739 struct option_state *options;
dbf6124a 740 struct binding_scope *scope;
b1b7b521 741 unsigned code;
f4c34053 742{
a370b55d 743 struct option_cache *oc;
f4c34053 744
c9605ddb
TL
745 if (!universe -> lookup_func)
746 return 0;
2c9c0291 747 oc = ((*universe -> lookup_func) (universe, options, code));
c9605ddb 748 if (!oc)
a370b55d 749 return 0;
dbf6124a
TL
750 if (!evaluate_option_cache (result, packet, lease, in_options,
751 cfg_options, scope, oc, MDL))
a370b55d
TL
752 return 0;
753 return 1;
f4c34053
TL
754}
755
4038ec52 756int agent_option_get (result, universe, packet, lease,
dbf6124a 757 in_options, cfg_options, options, scope, code)
a370b55d 758 struct data_string *result;
c9605ddb 759 struct universe *universe;
da38df14
TL
760 struct packet *packet;
761 struct lease *lease;
4038ec52
TL
762 struct option_state *in_options;
763 struct option_state *cfg_options;
a370b55d 764 struct option_state *options;
dbf6124a 765 struct binding_scope *scope;
b1b7b521 766 unsigned code;
f4c34053
TL
767{
768 struct agent_options *ao;
769 struct option_tag *t;
f4c34053 770
c9605ddb
TL
771 /* Make sure there's agent option state. */
772 if (universe -> index >= options -> universe_count ||
773 !(options -> universes [universe -> index]))
774 return 0;
775 ao = (struct agent_options *)options -> universes [universe -> index];
776
f4c34053 777 /* Find the last set of agent options and consider it definitive. */
c9605ddb 778 for (; ao -> next; ao = ao -> next)
a370b55d 779 ;
f4c34053 780 if (ao) {
a370b55d 781 for (t = ao -> first; t; t = t -> next) {
f4c34053 782 if (t -> data [0] == code) {
a370b55d 783 result -> len = t -> data [1];
dbf6124a
TL
784 if (!(buffer_allocate (&result -> buffer,
785 result -> len + 1,
786 MDL))) {
a370b55d
TL
787 result -> len = 0;
788 buffer_dereference
dbf6124a 789 (&result -> buffer, MDL);
a370b55d
TL
790 return 0;
791 }
792 result -> data = &result -> buffer -> data [0];
b1b7b521 793 memcpy (result -> buffer -> data,
a370b55d 794 &t -> data [2], result -> len);
b1b7b521 795 result -> buffer -> data [result -> len] = 0;
a370b55d
TL
796 result -> terminated = 1;
797 return 1;
f4c34053 798 }
a370b55d 799 }
f4c34053 800 }
a370b55d 801 return 0;
f4c34053
TL
802}
803
c9605ddb
TL
804void hashed_option_set (universe, options, option, op)
805 struct universe *universe;
b4807938
TL
806 struct option_state *options;
807 struct option_cache *option;
808 enum statement_op op;
b4807938 809{
a370b55d 810 struct option_cache *oc, *noc;
b4807938
TL
811
812 switch (op) {
813 case if_statement:
814 case add_statement:
815 case eval_statement:
816 case break_statement:
817 default:
8ae2d595 818 log_error ("bogus statement type in do_option_set.");
b4807938
TL
819 break;
820
821 case default_option_statement:
c9605ddb
TL
822 oc = lookup_option (universe, options,
823 option -> option -> code);
a370b55d 824 if (oc)
b4807938 825 break;
c9605ddb 826 save_option (universe, options, option);
b4807938
TL
827 break;
828
829 case supersede_option_statement:
a370b55d 830 /* Install the option, replacing any existing version. */
c9605ddb 831 save_option (universe, options, option);
b4807938
TL
832 break;
833
834 case append_option_statement:
835 case prepend_option_statement:
c9605ddb
TL
836 oc = lookup_option (universe, options,
837 option -> option -> code);
a370b55d 838 if (!oc) {
c9605ddb 839 save_option (universe, options, option);
b4807938
TL
840 break;
841 }
a370b55d
TL
842 /* If it's not an expression, make it into one. */
843 if (!oc -> expression && oc -> data.len) {
dbf6124a 844 if (!expression_allocate (&oc -> expression, MDL)) {
8ae2d595 845 log_error ("Can't allocate const expression.");
a370b55d
TL
846 break;
847 }
848 oc -> expression -> op = expr_const_data;
849 data_string_copy
850 (&oc -> expression -> data.const_data,
dbf6124a
TL
851 &oc -> data, MDL);
852 data_string_forget (&oc -> data, MDL);
a370b55d
TL
853 }
854 noc = (struct option_cache *)0;
dbf6124a 855 if (!option_cache_allocate (&noc, MDL))
a370b55d
TL
856 break;
857 if (op == append_option_statement) {
858 if (!make_concat (&noc -> expression,
859 oc -> expression,
860 option -> expression)) {
dbf6124a 861 option_cache_dereference (&noc, MDL);
a370b55d
TL
862 break;
863 }
864 } else {
865 if (!make_concat (&noc -> expression,
866 option -> expression,
867 oc -> expression)) {
dbf6124a 868 option_cache_dereference (&noc, MDL);
b4807938
TL
869 break;
870 }
b4807938 871 }
a370b55d 872 noc -> option = oc -> option;
c9605ddb 873 save_option (universe, options, noc);
dbf6124a 874 option_cache_dereference (&noc, MDL);
a370b55d
TL
875 break;
876 }
877}
878
c9605ddb
TL
879struct option_cache *lookup_option (universe, options, code)
880 struct universe *universe;
881 struct option_state *options;
b1b7b521 882 unsigned code;
c9605ddb
TL
883{
884 if (universe -> lookup_func)
885 return (*universe -> lookup_func) (universe, options, code);
886 else
887 log_error ("can't look up options in %s space.",
888 universe -> name);
889 return (struct option_cache *)0;
890}
891
892struct option_cache *lookup_hashed_option (universe, options, code)
893 struct universe *universe;
894 struct option_state *options;
b1b7b521 895 unsigned code;
a370b55d
TL
896{
897 int hashix;
898 pair bptr;
c9605ddb
TL
899 pair *hash;
900
901 /* Make sure there's a hash table. */
902 if (universe -> index >= options -> universe_count ||
903 !(options -> universes [universe -> index]))
904 return (struct option_cache *)0;
905
906 hash = options -> universes [universe -> index];
a370b55d 907
59ab1324 908 hashix = compute_option_hash (code);
a370b55d
TL
909 for (bptr = hash [hashix]; bptr; bptr = bptr -> cdr) {
910 if (((struct option_cache *)(bptr -> car)) -> option -> code ==
911 code)
912 return (struct option_cache *)(bptr -> car);
913 }
914 return (struct option_cache *)0;
915}
916
c9605ddb
TL
917void save_option (universe, options, oc)
918 struct universe *universe;
919 struct option_state *options;
920 struct option_cache *oc;
921{
922 if (universe -> save_func)
923 (*universe -> save_func) (universe, options, oc);
924 else
925 log_error ("can't store options in %s space.",
926 universe -> name);
927}
928
929void save_hashed_option (universe, options, oc)
930 struct universe *universe;
931 struct option_state *options;
a370b55d
TL
932 struct option_cache *oc;
933{
934 int hashix;
935 pair bptr;
c9605ddb 936 pair *hash = options -> universes [universe -> index];
a370b55d 937
c9605ddb 938 /* Compute the hash. */
59ab1324 939 hashix = compute_option_hash (oc -> option -> code);
a370b55d 940
c9605ddb
TL
941 /* If there's no hash table, make one. */
942 if (!hash) {
dbf6124a 943 hash = (pair *)dmalloc (OPTION_HASH_SIZE * sizeof *hash, MDL);
c9605ddb
TL
944 if (!hash) {
945 log_error ("no memory to store %s.%s",
946 universe -> name, oc -> option -> name);
947 return;
948 }
949 memset (hash, 0, OPTION_HASH_SIZE * sizeof *hash);
950 options -> universes [universe -> index] = (VOIDPTR)hash;
a370b55d 951 } else {
c9605ddb
TL
952 /* Try to find an existing option matching the new one. */
953 for (bptr = hash [hashix]; bptr; bptr = bptr -> cdr) {
954 if (((struct option_cache *)
955 (bptr -> car)) -> option -> code ==
956 oc -> option -> code)
957 break;
958 }
959
960 /* If we find one, dereference it and put the new one
961 in its place. */
962 if (bptr) {
963 option_cache_dereference
dbf6124a 964 ((struct option_cache **)&bptr -> car, MDL);
c9605ddb
TL
965 option_cache_reference
966 ((struct option_cache **)&bptr -> car,
dbf6124a 967 oc, MDL);
a370b55d
TL
968 return;
969 }
a370b55d 970 }
c9605ddb
TL
971
972 /* Otherwise, just put the new one at the head of the list. */
dbf6124a 973 bptr = new_pair (MDL);
c9605ddb
TL
974 if (!bptr) {
975 log_error ("No memory for option_cache reference.");
976 return;
977 }
978 bptr -> cdr = hash [hashix];
979 bptr -> car = 0;
dbf6124a 980 option_cache_reference ((struct option_cache **)&bptr -> car, oc, MDL);
c9605ddb 981 hash [hashix] = bptr;
a370b55d
TL
982}
983
c9605ddb
TL
984void delete_option (universe, options, code)
985 struct universe *universe;
986 struct option_state *options;
987 int code;
988{
989 if (universe -> delete_func)
990 (*universe -> delete_func) (universe, options, code);
991 else
992 log_error ("can't delete options from %s space.",
993 universe -> name);
994}
995
996void delete_hashed_option (universe, options, code)
997 struct universe *universe;
998 struct option_state *options;
a370b55d
TL
999 int code;
1000{
1001 int hashix;
1002 pair bptr, prev = (pair)0;
c9605ddb
TL
1003 pair *hash = options -> universes [universe -> index];
1004
1005 /* There may not be any options in this space. */
1006 if (!hash)
1007 return;
a370b55d
TL
1008
1009 /* Try to find an existing option matching the new one. */
59ab1324 1010 hashix = compute_option_hash (code);
a370b55d
TL
1011 for (bptr = hash [hashix]; bptr; bptr = bptr -> cdr) {
1012 if (((struct option_cache *)(bptr -> car)) -> option -> code
1013 == code)
1014 break;
1015 prev = bptr;
1016 }
1017 /* If we found one, wipe it out... */
1018 if (bptr) {
1019 if (prev)
1020 prev -> cdr = bptr -> cdr;
b4807938 1021 else
a370b55d
TL
1022 hash [hashix] = bptr -> cdr;
1023 option_cache_dereference
dbf6124a
TL
1024 ((struct option_cache **)(&bptr -> car), MDL);
1025 free_pair (bptr, MDL);
a370b55d
TL
1026 }
1027}
b4807938 1028
a370b55d
TL
1029extern struct option_cache *free_option_caches; /* XXX */
1030
dbf6124a 1031int option_cache_dereference (ptr, file, line)
a370b55d 1032 struct option_cache **ptr;
dbf6124a
TL
1033 const char *file;
1034 int line;
a370b55d
TL
1035{
1036 if (!ptr || !*ptr) {
dbf6124a
TL
1037 log_error ("Null pointer in option_cache_dereference: %s(%d)",
1038 file, line);
8e0a40b8 1039#if defined (POINTER_DEBUG)
a370b55d 1040 abort ();
8e0a40b8
TL
1041#else
1042 return 0;
1043#endif
a370b55d
TL
1044 }
1045
1046 (*ptr) -> refcnt--;
37e365b4 1047 rc_register (file, line, ptr, *ptr, (*ptr) -> refcnt);
a370b55d
TL
1048 if (!(*ptr) -> refcnt) {
1049 if ((*ptr) -> data.buffer)
4bd8800e 1050 data_string_forget (&(*ptr) -> data, file, line);
a370b55d 1051 if ((*ptr) -> expression)
4bd8800e
TL
1052 expression_dereference (&(*ptr) -> expression,
1053 file, line);
a370b55d
TL
1054 /* Put it back on the free list... */
1055 (*ptr) -> expression = (struct expression *)free_option_caches;
1056 free_option_caches = *ptr;
dbf6124a
TL
1057 dmalloc_reuse (free_option_caches, (char *)0, 0, 0);
1058 }
1059 if ((*ptr) -> refcnt < 0) {
1060 log_error ("%s(%d): negative refcnt!", file, line);
1061#if defined (DEBUG_RC_HISTORY)
1062 dump_rc_history ();
1063#endif
1064#if defined (POINTER_DEBUG)
1065 abort ();
1066#else
a77040e7 1067 *ptr = (struct option_cache *)0;
dbf6124a
TL
1068 return 0;
1069#endif
b4807938 1070 }
a370b55d
TL
1071 *ptr = (struct option_cache *)0;
1072 return 1;
1073
b4807938 1074}
c9605ddb 1075
59ab1324 1076int hashed_option_state_dereference (universe, state, file, line)
c9605ddb
TL
1077 struct universe *universe;
1078 struct option_state *state;
59ab1324
TL
1079 const char *file;
1080 int line;
c9605ddb
TL
1081{
1082 pair *heads;
1083 pair cp, next;
1084 int i;
1085
1086 /* Get the pointer to the array of hash table bucket heads. */
1087 heads = (pair *)(state -> universes [universe -> index]);
1088 if (!heads)
1089 return 0;
1090
1091 /* For each non-null head, loop through all the buckets dereferencing
1092 the attached option cache structures and freeing the buckets. */
1093 for (i = 0; i < OPTION_HASH_SIZE; i++) {
1094 for (cp = heads [i]; cp; cp = next) {
1095 next = cp -> cdr;
1096 option_cache_dereference
59ab1324
TL
1097 ((struct option_cache **)&cp -> car, file, line);
1098 free_pair (cp, file, line);
c9605ddb
TL
1099 }
1100 }
1101
59ab1324 1102 dfree (heads, file, line);
c9605ddb
TL
1103 state -> universes [universe -> index] = (void *)0;
1104 return 1;
1105}
1106
59ab1324 1107int agent_option_state_dereference (universe, state, file, line)
c9605ddb
TL
1108 struct universe *universe;
1109 struct option_state *state;
59ab1324
TL
1110 const char *file;
1111 int line;
c9605ddb
TL
1112{
1113 struct agent_options *a, *na;
1114 struct option_tag *ot, *not;
1115
1116 if (universe -> index >= state -> universe_count ||
1117 !state -> universes [universe -> index])
1118 return 0;
1119
1120 /* We can also release the agent options, if any... */
1121 for (a = (struct agent_options *)(state -> universes
1122 [universe -> index]); a; a = na) {
1123 na = a -> next;
1124 for (ot = a -> first; ot; ot = not) {
1125 not = ot -> next;
59ab1324 1126 dfree (ot, file, line);
c9605ddb
TL
1127 }
1128 }
1129
59ab1324 1130 dfree (state -> universes [universe -> index], file, line);
c9605ddb
TL
1131 state -> universes [universe -> index] = (void *)0;
1132 return 1;
1133}
1134
dbf6124a
TL
1135int store_option (result, universe, packet, lease,
1136 in_options, cfg_options, scope, oc)
c9605ddb
TL
1137 struct data_string *result;
1138 struct universe *universe;
4038ec52 1139 struct packet *packet;
da38df14 1140 struct lease *lease;
4038ec52
TL
1141 struct option_state *in_options;
1142 struct option_state *cfg_options;
dbf6124a 1143 struct binding_scope *scope;
c9605ddb
TL
1144 struct option_cache *oc;
1145{
1146 struct data_string d1, d2;
1147
1148 memset (&d1, 0, sizeof d1);
1149 memset (&d2, 0, sizeof d2);
1150
dbf6124a
TL
1151 if (evaluate_option_cache (&d2, packet, lease, in_options,
1152 cfg_options, scope, oc, MDL)) {
c9605ddb
TL
1153 if (!buffer_allocate (&d1.buffer,
1154 (result -> len +
1155 universe -> length_size +
dbf6124a
TL
1156 universe -> tag_size + d2.len), MDL)) {
1157 data_string_forget (result, MDL);
1158 data_string_forget (&d2, MDL);
c9605ddb
TL
1159 return 0;
1160 }
1161 d1.data = &d1.buffer -> data [0];
1162 if (result -> len)
b1b7b521
TL
1163 memcpy (d1.buffer -> data,
1164 result -> data, result -> len);
c9605ddb 1165 d1.len = result -> len;
b1b7b521 1166 (*universe -> store_tag) (&d1.buffer -> data [d1.len],
c9605ddb
TL
1167 oc -> option -> code);
1168 d1.len += universe -> tag_size;
b1b7b521
TL
1169 (*universe -> store_length) (&d1.buffer -> data [d1.len],
1170 d2.len);
c9605ddb 1171 d1.len += universe -> length_size;
b1b7b521 1172 memcpy (&d1.buffer -> data [d1.len], d2.data, d2.len);
c9605ddb 1173 d1.len += d2.len;
dbf6124a
TL
1174 data_string_forget (&d2, MDL);
1175 data_string_forget (result, MDL);
1176 data_string_copy (result, &d1, MDL);
1177 data_string_forget (&d1, MDL);
c9605ddb
TL
1178 return 1;
1179 }
1180 return 0;
1181}
1182
4038ec52 1183int option_space_encapsulate (result, packet, lease,
dbf6124a 1184 in_options, cfg_options, scope, name)
c9605ddb 1185 struct data_string *result;
4038ec52 1186 struct packet *packet;
da38df14 1187 struct lease *lease;
4038ec52
TL
1188 struct option_state *in_options;
1189 struct option_state *cfg_options;
dbf6124a 1190 struct binding_scope *scope;
c9605ddb
TL
1191 struct data_string *name;
1192{
1193 struct universe *u;
1194
20916cae
TL
1195 u = (struct universe *)0;
1196 universe_hash_lookup (&u, universe_hash,
1197 name -> data, name -> len, MDL);
c9605ddb
TL
1198 if (!u) {
1199 log_error ("unknown option space %s.", name -> data);
1200 return 0;
1201 }
1202
1203 if (u -> encapsulate)
4038ec52 1204 return (*u -> encapsulate) (result, packet, lease,
dbf6124a 1205 in_options, cfg_options, scope, u);
c9605ddb
TL
1206 log_error ("encapsulation requested for %s with no support.",
1207 name -> data);
1208 return 0;
1209}
1210
4038ec52 1211int hashed_option_space_encapsulate (result, packet, lease,
dbf6124a 1212 in_options, cfg_options, scope, universe)
c9605ddb 1213 struct data_string *result;
4038ec52 1214 struct packet *packet;
da38df14 1215 struct lease *lease;
4038ec52
TL
1216 struct option_state *in_options;
1217 struct option_state *cfg_options;
dbf6124a 1218 struct binding_scope *scope;
c9605ddb
TL
1219 struct universe *universe;
1220{
1221 pair p, *hash;
1222 int status;
1223 int i;
1224
4038ec52 1225 if (universe -> index >= cfg_options -> universe_count)
c9605ddb
TL
1226 return 0;
1227
4038ec52 1228 hash = cfg_options -> universes [universe -> index];
c9605ddb
TL
1229 if (!hash)
1230 return 0;
1231
1232 status = 0;
1233 for (i = 0; i < OPTION_HASH_SIZE; i++) {
1234 for (p = hash [i]; p; p = p -> cdr) {
4038ec52 1235 if (store_option (result, universe, packet, lease,
dbf6124a 1236 in_options, cfg_options, scope,
c9605ddb
TL
1237 (struct option_cache *)p -> car))
1238 status = 1;
1239 }
1240 }
1241
1242 return status;
1243}
4038ec52 1244
6dd369e0 1245int nwip_option_space_encapsulate (result, packet, lease,
dbf6124a 1246 in_options, cfg_options, scope, universe)
6dd369e0
TL
1247 struct data_string *result;
1248 struct packet *packet;
1249 struct lease *lease;
1250 struct option_state *in_options;
1251 struct option_state *cfg_options;
dbf6124a 1252 struct binding_scope *scope;
6dd369e0
TL
1253 struct universe *universe;
1254{
1255 pair p, *hash;
1256 int status;
1257 int i;
1258 static struct option_cache *no_nwip;
1259 struct data_string ds;
1260
1261 if (universe -> index >= cfg_options -> universe_count)
1262 return 0;
1263
1264 hash = cfg_options -> universes [universe -> index];
1265 status = 0;
1266 for (i = 0; hash && i < OPTION_HASH_SIZE; i++) {
1267 for (p = hash [i]; p; p = p -> cdr) {
1268 if (store_option (result, universe, packet, lease,
dbf6124a 1269 in_options, cfg_options, scope,
6dd369e0
TL
1270 (struct option_cache *)p -> car))
1271 status = 1;
1272 }
1273 }
1274
1275 /* If there's no data, the nwip suboption is supposed to contain
1276 a suboption saying there's no data. */
1277 if (!status) {
1278 if (!no_nwip) {
1279 static unsigned char nni [] = { 1, 0 };
1280 memset (&ds, 0, sizeof ds);
1281 ds.data = nni;
1282 ds.len = 2;
dbf6124a
TL
1283 if (option_cache_allocate (&no_nwip, MDL))
1284 data_string_copy (&no_nwip -> data, &ds, MDL);
1285 no_nwip -> option = nwip_universe.options [1];
6dd369e0
TL
1286 }
1287 if (no_nwip) {
1288 if (store_option (result, universe, packet, lease,
1289 in_options, cfg_options,
dbf6124a 1290 scope, no_nwip))
6dd369e0
TL
1291 status = 1;
1292 }
1293 } else {
1294 /* If we have nwip options, the first one has to be the
1295 nwip-exists-in-option-area option. */
dbf6124a
TL
1296 if (!buffer_allocate (&ds.buffer, result -> len + 2, MDL)) {
1297 data_string_forget (result, MDL);
6dd369e0
TL
1298 return 0;
1299 }
1300 ds.data = &ds.buffer -> data [0];
1301 ds.buffer -> data [0] = 2;
1302 ds.buffer -> data [1] = 0;
1303 memcpy (&ds.buffer -> data [2], result -> data, result -> len);
dbf6124a
TL
1304 data_string_forget (result, MDL);
1305 data_string_copy (result, &ds, MDL);
1306 data_string_forget (&ds, MDL);
6dd369e0
TL
1307 }
1308
1309 return status;
1310}
1311
4038ec52
TL
1312void do_packet (interface, packet, len, from_port, from, hfrom)
1313 struct interface_info *interface;
1314 struct dhcp_packet *packet;
b1b7b521 1315 unsigned len;
4038ec52
TL
1316 unsigned int from_port;
1317 struct iaddr from;
1318 struct hardware *hfrom;
1319{
1320 int i;
1321 struct option_cache *op;
1322 struct packet *decoded_packet;
dbf6124a
TL
1323#if defined (DEBUG_MEMORY_LEAKAGE)
1324 unsigned long previous_outstanding = dmalloc_outstanding;
1325#endif
4038ec52
TL
1326
1327 decoded_packet = (struct packet *)0;
dbf6124a 1328 if (!packet_allocate (&decoded_packet, MDL)) {
4038ec52
TL
1329 log_error ("do_packet: no memory for incoming packet!");
1330 return;
1331 }
1332 decoded_packet -> raw = packet;
1333 decoded_packet -> packet_length = len;
1334 decoded_packet -> client_port = from_port;
1335 decoded_packet -> client_addr = from;
20916cae 1336 interface_reference (&decoded_packet -> interface, interface, MDL);
4038ec52
TL
1337 decoded_packet -> haddr = hfrom;
1338
1339 if (packet -> hlen > sizeof packet -> chaddr) {
dbf6124a 1340 packet_dereference (&decoded_packet, MDL);
4038ec52
TL
1341 log_info ("Discarding packet with bogus hlen.");
1342 return;
1343 }
4038ec52 1344
bb404b74
TL
1345 /* If there's an option buffer, try to parse it. */
1346 if (decoded_packet -> packet_length >= DHCP_FIXED_NON_UDP + 4) {
1347 if (!parse_options (decoded_packet)) {
1348 if (decoded_packet -> options)
1349 option_state_dereference
dbf6124a
TL
1350 (&decoded_packet -> options, MDL);
1351 packet_dereference (&decoded_packet, MDL);
bb404b74
TL
1352 return;
1353 }
1354
1355 if (decoded_packet -> options_valid &&
1356 (op = lookup_option (&dhcp_universe,
1357 decoded_packet -> options,
1358 DHO_DHCP_MESSAGE_TYPE))) {
1359 struct data_string dp;
1360 memset (&dp, 0, sizeof dp);
1361 evaluate_option_cache (&dp, decoded_packet,
1362 (struct lease *)0,
1363 decoded_packet -> options,
dbf6124a
TL
1364 (struct option_state *)0,
1365 (struct binding_scope *)0,
1366 op, MDL);
bb404b74
TL
1367 if (dp.len > 0)
1368 decoded_packet -> packet_type = dp.data [0];
1369 else
1370 decoded_packet -> packet_type = 0;
dbf6124a 1371 data_string_forget (&dp, MDL);
bb404b74 1372 }
4038ec52
TL
1373 }
1374
1375 if (decoded_packet -> packet_type)
1376 dhcp (decoded_packet);
1377 else
1378 bootp (decoded_packet);
1379
2545e6e7
TL
1380 /* If the caller kept the packet, they'll have upped the refcnt. */
1381 packet_dereference (&decoded_packet, MDL);
1382
dbf6124a
TL
1383#if defined (DEBUG_MEMORY_LEAKAGE)
1384 log_info ("generation %ld: %ld new, %ld outstanding, %ld long-term",
1385 dmalloc_generation,
1386 dmalloc_outstanding - previous_outstanding,
1387 dmalloc_outstanding, dmalloc_longterm);
1388#endif
1389#if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL)
1390 dmalloc_dump_outstanding ();
1391#endif
a77040e7 1392#if defined (DEBUG_RC_HISTORY_EXHAUSTIVELY)
59ab1324
TL
1393 dump_rc_history ();
1394#endif
4038ec52
TL
1395}
1396