3 DHCP options parsing and reassembly. */
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:
13 * http://www.isc.org/isc-license-1.0.html.
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.
19 * Support and other services are available for ISC products - see
20 * http://www.isc.org for more information.
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";
28 #define DHCP_OPTION_DATA
30 #include <omapip/omapip_p.h>
32 static void do_option_set
PROTO ((pair
*,
33 struct option_cache
*,
36 /* Parse all available options out of the specified packet. */
38 int parse_options (packet
)
39 struct packet
*packet
;
42 struct option_cache
*op
= (struct option_cache
*)0;
44 /* Allocate a new option state. */
45 if (!option_state_allocate (&packet
-> options
, MDL
)) {
46 packet
-> options_valid
= 0;
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;
56 /* Go through the options field, up to the end of the packet
58 if (!parse_option_buffer (packet
, &packet
-> raw
-> options
[4],
59 (packet
-> packet_length
-
60 DHCP_FIXED_NON_UDP
- 4)))
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
))
74 if (op
-> data
.data
[0] & 2) {
75 if (!parse_option_buffer
77 (unsigned char *)packet
-> raw
-> sname
,
78 sizeof packet
-> raw
-> sname
))
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. */
89 int parse_option_buffer (packet
, buffer
, length
)
90 struct packet
*packet
;
91 unsigned char *buffer
;
95 unsigned char *end
= buffer
+ length
;
98 struct option_cache
*op
= (struct option_cache
*)0;
99 struct buffer
*bp
= (struct buffer
*)0;
101 if (!buffer_allocate (&bp
, length
, MDL
)) {
102 log_error ("no memory for option buffer.");
105 memcpy (bp
-> data
, buffer
, length
);
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
) {
115 /* All other fields (except end, see above) have a
117 len
= buffer
[offset
+ 1];
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
);
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
);
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
);
144 /* Reference buffer copy to option cache. */
145 op
-> data
.buffer
= (struct buffer
*)0;
146 buffer_reference (&op
-> data
.buffer
, bp
, MDL
);
148 /* Point option cache into buffer. */
149 op
-> data
.data
= &bp
-> data
[offset
+ 2];
150 op
-> data
.len
= len
;
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;
161 op
-> option
= &dhcp_options
[code
];
162 /* Now store the option. */
163 save_option (&dhcp_universe
, packet
-> options
, op
);
165 /* And let go of our reference. */
166 option_cache_dereference (&op
, MDL
);
170 packet
-> options_valid
= 1;
171 buffer_dereference (&bp
, MDL
);
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. */
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
;
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. */
191 struct data_string
*prl
;
193 #define PRIORITY_COUNT 300
194 unsigned priority_list
[PRIORITY_COUNT
];
196 unsigned char buffer
[4096]; /* Really big buffer... */
197 unsigned main_buffer_size
;
198 unsigned mainbufix
, bufix
, agentix
;
199 unsigned option_size
;
202 struct option_cache
*op
;
203 struct data_string ds
;
206 memset (&ds
, 0, sizeof ds
);
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. */
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
);
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
229 main_buffer_size
= mms
- DHCP_FIXED_LEN
;
231 /* Enforce a minimum packet size... */
232 if (main_buffer_size
< (576 - DHCP_FIXED_LEN
))
233 main_buffer_size
= 576 - DHCP_FIXED_LEN
;
237 inpacket
-> packet_length
- DHCP_FIXED_LEN
;
238 if (main_buffer_size
< 64)
239 main_buffer_size
= 64;
241 main_buffer_size
= 64;
243 main_buffer_size
= 576 - DHCP_FIXED_LEN
;
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
;
249 /* Preload the option priority list with mandatory options. */
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
;
257 if (prl
&& prl
-> len
> 0) {
258 data_string_truncate (prl
, (PRIORITY_COUNT
- priority_len
));
260 for (i
= 0; i
< prl
-> len
; i
++)
261 priority_list
[priority_len
++] = prl
-> data
[i
];
263 /* First, hardcode some more options that ought to be
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
;
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
;
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
;
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)),
315 in_options
, cfg_options
, scope
,
316 priority_list
, priority_len
,
319 ((overload
& 1) ? DHCP_FILE_LEN
: 0)),
322 /* Put the cookie up front... */
323 memcpy (outpacket
-> options
, DHCP_OPTIONS_COOKIE
, 4);
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
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
) {
336 outpacket
-> options
[mainbufix
++] = DHO_END
;
339 length
= DHCP_FIXED_NON_UDP
+ mainbufix
;
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;
346 outpacket
-> options
[mainbufix
++] = 1;
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
;
353 bufix
= main_buffer_size
- mainbufix
;
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
++]
362 while (mainbufix
< DHCP_FILE_LEN
)
363 outpacket
-> file
[mainbufix
++]
366 memcpy (outpacket
-> file
,
367 &buffer
[bufix
], DHCP_FILE_LEN
);
368 bufix
+= DHCP_FILE_LEN
;
371 if ((overload
& 2) && option_size
< bufix
) {
372 memcpy (outpacket
-> sname
,
373 &buffer
[bufix
], option_size
- bufix
);
375 mainbufix
= option_size
- bufix
;
376 if (mainbufix
< DHCP_SNAME_LEN
)
377 outpacket
-> file
[mainbufix
++]
379 while (mainbufix
< DHCP_SNAME_LEN
)
380 outpacket
-> file
[mainbufix
++]
385 length
= cons_agent_information_options (cfg_options
,
386 outpacket
, agentix
, length
);
391 /* Store all the requested options into the requested buffer. */
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
;
398 struct packet
*packet
;
400 struct option_state
*in_options
;
401 struct option_state
*cfg_options
;
402 struct binding_scope
*scope
;
403 unsigned *priority_list
;
405 unsigned first_cutoff
, second_cutoff
;
412 struct data_string od
;
413 struct option_cache
*oc
;
415 memset (&od
, 0, sizeof od
);
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
++) {
423 for (ix
= i
+ 1; ix
< priority_len
+ tto
; ix
++) {
425 priority_list
[ix
- tto
] =
427 if (priority_list
[i
] == priority_list
[ix
]) {
434 /* Copy out the options in the order that they appear in the
436 for (i
= 0; i
< priority_len
; i
++) {
437 /* Code for next option to try to store. */
438 unsigned code
= priority_list
[i
];
441 /* Number of bytes left to store (some may already
442 have been stored by a previous pass). */
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
)
449 (universes
[cfg_options
-> site_universe
],
452 oc
= lookup_option (&dhcp_universe
, cfg_options
, code
);
454 /* If no data is available for this option, skip it. */
459 /* Find the value of the option... */
460 evaluate_option_cache (&od
, packet
, lease
, in_options
,
461 cfg_options
, scope
, oc
, MDL
);
466 /* We should now have a constant length for the option. */
469 /* Do we add a NUL? */
470 if (terminate
&& dhcp_options
[code
].format
[0] == 't') {
477 /* Try to store the option. */
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. */
488 unsigned char incr
= length
> 255 ? 255 : length
;
490 /* If this hunk of the buffer will cross a
491 boundary, only go up to the boundary in this
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
;
500 /* If this option is going to overflow the buffer,
502 if (bufix
+ 2 + incr
> buflen
) {
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;
515 memcpy (buffer
+ bufix
+ 2,
516 od
.data
+ ix
, (unsigned)incr
);
522 data_string_forget (&od
, MDL
);
527 /* Format the specified option so that a human can easily read it. */
529 const char *pretty_print_option (code
, data
, len
, emit_commas
, emit_quotes
)
531 const unsigned char *data
;
536 static char optbuf
[32768]; /* XXX */
543 const unsigned char *dp
= data
;
547 /* Code should be between 0 and 255. */
549 log_fatal ("pretty_print_option: bad code %d\n", code
);
556 /* Figure out the size of the data. */
557 for (i
= 0; dhcp_options
[code
].format
[i
]; i
++) {
559 log_error ("%s: Extra codes in format string: %s\n",
560 dhcp_options
[code
].name
,
561 &(dhcp_options
[code
].format
[i
]));
565 fmtbuf
[i
] = dhcp_options
[code
].format
[i
];
566 switch (dhcp_options
[code
].format
[i
]) {
573 for (k
= 0; k
< len
; k
++) {
574 if (!isascii (data
[k
]) ||
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)) {
614 log_error ("%s: garbage in format string: %s\n",
615 dhcp_options
[code
].name
,
616 &(dhcp_options
[code
].format
[i
]));
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
,
628 /* Check for too many bytes... */
629 if (numhunk
== -1 && hunksize
< len
)
630 log_error ("%s: %d extra bytes",
631 dhcp_options
[code
].name
,
634 /* If this is an array, compute its size. */
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
);
643 /* A one-hunk array prints the same as a single hunk. */
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
]) {
654 strcpy (op
, (const char *)dp
);
655 op
+= strlen ((const char *)dp
);
661 foo
.s_addr
= htonl (getULong (dp
));
662 strcpy (op
, inet_ntoa (foo
));
666 sprintf (op
, "%ld", (long)getLong (dp
));
671 (unsigned long)getULong (dp
));
675 sprintf (op
, "%d", (int)getShort (dp
));
679 sprintf (op
, "%d", (unsigned)getUShort (dp
));
683 sprintf (op
, "%d", *(const char *)dp
++);
686 sprintf (op
, "%d", *dp
++);
689 sprintf (op
, "%x", *dp
++);
692 strcpy (op
, *dp
++ ? "true" : "false");
695 log_error ("Unexpected format code %c",
699 if (j
+ 1 < numelem
&& comma
!= ':')
702 if (i
+ 1 < numhunk
) {
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
;
716 struct option_state
*in_options
;
717 struct option_state
*cfg_options
;
718 struct option_state
*options
;
719 struct binding_scope
*scope
;
722 struct option_cache
*oc
;
724 if (!universe
-> lookup_func
)
726 oc
= ((*universe
-> lookup_func
) (universe
, options
, code
));
729 if (!evaluate_option_cache (result
, packet
, lease
, in_options
,
730 cfg_options
, scope
, oc
, MDL
))
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
;
741 struct option_state
*in_options
;
742 struct option_state
*cfg_options
;
743 struct option_state
*options
;
744 struct binding_scope
*scope
;
747 struct agent_options
*ao
;
748 struct option_tag
*t
;
750 /* Make sure there's agent option state. */
751 if (universe
-> index
>= options
-> universe_count
||
752 !(options
-> universes
[universe
-> index
]))
754 ao
= (struct agent_options
*)options
-> universes
[universe
-> index
];
756 /* Find the last set of agent options and consider it definitive. */
757 for (; ao
-> next
; ao
= ao
-> next
)
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
,
768 (&result
-> buffer
, MDL
);
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;
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
;
789 struct option_cache
*oc
, *noc
;
795 case break_statement
:
797 log_error ("bogus statement type in do_option_set.");
800 case default_option_statement
:
801 oc
= lookup_option (universe
, options
,
802 option
-> option
-> code
);
805 save_option (universe
, options
, option
);
808 case supersede_option_statement
:
809 /* Install the option, replacing any existing version. */
810 save_option (universe
, options
, option
);
813 case append_option_statement
:
814 case prepend_option_statement
:
815 oc
= lookup_option (universe
, options
,
816 option
-> option
-> code
);
818 save_option (universe
, options
, option
);
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.");
827 oc
-> expression
-> op
= expr_const_data
;
829 (&oc
-> expression
-> data
.const_data
,
831 data_string_forget (&oc
-> data
, MDL
);
833 noc
= (struct option_cache
*)0;
834 if (!option_cache_allocate (&noc
, MDL
))
836 if (op
== append_option_statement
) {
837 if (!make_concat (&noc
-> expression
,
839 option
-> expression
)) {
840 option_cache_dereference (&noc
, MDL
);
844 if (!make_concat (&noc
-> expression
,
845 option
-> expression
,
847 option_cache_dereference (&noc
, MDL
);
851 noc
-> option
= oc
-> option
;
852 save_option (universe
, options
, noc
);
853 option_cache_dereference (&noc
, MDL
);
858 struct option_cache
*lookup_option (universe
, options
, code
)
859 struct universe
*universe
;
860 struct option_state
*options
;
863 if (universe
-> lookup_func
)
864 return (*universe
-> lookup_func
) (universe
, options
, code
);
866 log_error ("can't look up options in %s space.",
868 return (struct option_cache
*)0;
871 struct option_cache
*lookup_hashed_option (universe
, options
, code
)
872 struct universe
*universe
;
873 struct option_state
*options
;
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;
885 hash
= options
-> universes
[universe
-> index
];
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
==
891 return (struct option_cache
*)(bptr
-> car
);
893 return (struct option_cache
*)0;
896 void save_option (universe
, options
, oc
)
897 struct universe
*universe
;
898 struct option_state
*options
;
899 struct option_cache
*oc
;
901 if (universe
-> save_func
)
902 (*universe
-> save_func
) (universe
, options
, oc
);
904 log_error ("can't store options in %s space.",
908 void save_hashed_option (universe
, options
, oc
)
909 struct universe
*universe
;
910 struct option_state
*options
;
911 struct option_cache
*oc
;
915 pair
*hash
= options
-> universes
[universe
-> index
];
917 /* Compute the hash. */
918 hashix
= ((oc
-> option
-> code
& 31) +
919 ((oc
-> option
-> code
>> 5) & 31)) % 17;
921 /* If there's no hash table, make one. */
923 hash
= (pair
*)dmalloc (OPTION_HASH_SIZE
* sizeof *hash
, MDL
);
925 log_error ("no memory to store %s.%s",
926 universe
-> name
, oc
-> option
-> name
);
929 memset (hash
, 0, OPTION_HASH_SIZE
* sizeof *hash
);
930 options
-> universes
[universe
-> index
] = (VOIDPTR
)hash
;
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
)
940 /* If we find one, dereference it and put the new one
943 option_cache_dereference
944 ((struct option_cache
**)&bptr
-> car
, MDL
);
945 option_cache_reference
946 ((struct option_cache
**)&bptr
-> car
,
952 /* Otherwise, just put the new one at the head of the list. */
953 bptr
= new_pair (MDL
);
955 log_error ("No memory for option_cache reference.");
958 bptr
-> cdr
= hash
[hashix
];
960 option_cache_reference ((struct option_cache
**)&bptr
-> car
, oc
, MDL
);
961 hash
[hashix
] = bptr
;
964 void delete_option (universe
, options
, code
)
965 struct universe
*universe
;
966 struct option_state
*options
;
969 if (universe
-> delete_func
)
970 (*universe
-> delete_func
) (universe
, options
, code
);
972 log_error ("can't delete options from %s space.",
976 void delete_hashed_option (universe
, options
, code
)
977 struct universe
*universe
;
978 struct option_state
*options
;
982 pair bptr
, prev
= (pair
)0;
983 pair
*hash
= options
-> universes
[universe
-> index
];
985 /* There may not be any options in this space. */
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
998 /* If we found one, wipe it out... */
1001 prev
-> cdr
= bptr
-> cdr
;
1003 hash
[hashix
] = bptr
-> cdr
;
1004 option_cache_dereference
1005 ((struct option_cache
**)(&bptr
-> car
), MDL
);
1006 free_pair (bptr
, MDL
);
1010 extern struct option_cache
*free_option_caches
; /* XXX */
1012 int option_cache_dereference (ptr
, file
, line
)
1013 struct option_cache
**ptr
;
1017 if (!ptr
|| !*ptr
) {
1018 log_error ("Null pointer in option_cache_dereference: %s(%d)",
1020 #if defined (POINTER_DEBUG)
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
,
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);
1040 if ((*ptr
) -> refcnt
< 0) {
1041 log_error ("%s(%d): negative refcnt!", file
, line
);
1042 #if defined (DEBUG_RC_HISTORY)
1045 #if defined (POINTER_DEBUG)
1051 *ptr
= (struct option_cache
*)0;
1056 int hashed_option_state_dereference (universe
, state
)
1057 struct universe
*universe
;
1058 struct option_state
*state
;
1064 /* Get the pointer to the array of hash table bucket heads. */
1065 heads
= (pair
*)(state
-> universes
[universe
-> index
]);
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
) {
1074 option_cache_dereference
1075 ((struct option_cache
**)&cp
-> car
, MDL
);
1076 free_pair (cp
, MDL
);
1081 state
-> universes
[universe
-> index
] = (void *)0;
1085 int agent_option_state_dereference (universe
, state
)
1086 struct universe
*universe
;
1087 struct option_state
*state
;
1089 struct agent_options
*a
, *na
;
1090 struct option_tag
*ot
, *not;
1092 if (universe
-> index
>= state
-> universe_count
||
1093 !state
-> universes
[universe
-> index
])
1096 /* We can also release the agent options, if any... */
1097 for (a
= (struct agent_options
*)(state
-> universes
1098 [universe
-> index
]); a
; a
= na
) {
1100 for (ot
= a
-> first
; ot
; ot
= not) {
1106 dfree (state
-> universes
[universe
-> index
], MDL
);
1107 state
-> universes
[universe
-> index
] = (void *)0;
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
;
1122 struct data_string d1
, d2
;
1124 memset (&d1
, 0, sizeof d1
);
1125 memset (&d2
, 0, sizeof d2
);
1127 if (evaluate_option_cache (&d2
, packet
, lease
, in_options
,
1128 cfg_options
, scope
, oc
, MDL
)) {
1129 if (!buffer_allocate (&d1
.buffer
,
1131 universe
-> length_size
+
1132 universe
-> tag_size
+ d2
.len
), MDL
)) {
1133 data_string_forget (result
, MDL
);
1134 data_string_forget (&d2
, MDL
);
1137 d1
.data
= &d1
.buffer
-> data
[0];
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
],
1147 d1
.len
+= universe
-> length_size
;
1148 memcpy (&d1
.buffer
-> data
[d1
.len
], d2
.data
, 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
);
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
;
1171 u
= (struct universe
*)hash_lookup (&universe_hash
,
1172 name
-> data
, name
-> len
);
1174 log_error ("unknown option space %s.", name
-> data
);
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.",
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
;
1200 if (universe
-> index
>= cfg_options
-> universe_count
)
1203 hash
= cfg_options
-> universes
[universe
-> index
];
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
))
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
;
1233 static struct option_cache
*no_nwip
;
1234 struct data_string ds
;
1236 if (universe
-> index
>= cfg_options
-> universe_count
)
1239 hash
= cfg_options
-> universes
[universe
-> index
];
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
))
1250 /* If there's no data, the nwip suboption is supposed to contain
1251 a suboption saying there's no data. */
1254 static unsigned char nni
[] = { 1, 0 };
1255 memset (&ds
, 0, sizeof ds
);
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];
1263 if (store_option (result
, universe
, packet
, lease
,
1264 in_options
, cfg_options
,
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
);
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
);
1287 void do_packet (interface
, packet
, len
, from_port
, from
, hfrom
)
1288 struct interface_info
*interface
;
1289 struct dhcp_packet
*packet
;
1291 unsigned int from_port
;
1293 struct hardware
*hfrom
;
1296 struct option_cache
*op
;
1297 struct packet
*decoded_packet
;
1298 #if defined (DEBUG_MEMORY_LEAKAGE)
1299 unsigned long previous_outstanding
= dmalloc_outstanding
;
1302 decoded_packet
= (struct packet
*)0;
1303 if (!packet_allocate (&decoded_packet
, MDL
)) {
1304 log_error ("do_packet: no memory for incoming packet!");
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
;
1314 if (packet
-> hlen
> sizeof packet
-> chaddr
) {
1315 packet_dereference (&decoded_packet
, MDL
);
1316 log_info ("Discarding packet with bogus hlen.");
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
);
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
,
1338 decoded_packet
-> options
,
1339 (struct option_state
*)0,
1340 (struct binding_scope
*)0,
1343 decoded_packet
-> packet_type
= dp
.data
[0];
1345 decoded_packet
-> packet_type
= 0;
1346 data_string_forget (&dp
, MDL
);
1350 if (decoded_packet
-> packet_type
)
1351 dhcp (decoded_packet
);
1353 bootp (decoded_packet
);
1355 #if defined (DEBUG_MEMORY_LEAKAGE)
1356 log_info ("generation %ld: %ld new, %ld outstanding, %ld long-term",
1358 dmalloc_outstanding
- previous_outstanding
,
1359 dmalloc_outstanding
, dmalloc_longterm
);
1361 #if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL)
1362 dmalloc_dump_outstanding ();
1364 /* If the caller kept the packet, they'll have upped the refcnt. */
1365 packet_dereference (&decoded_packet
, MDL
);