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