xref: /freebsd-src/sbin/dhclient/options.c (revision 47c0859616bfefdd59ce6bbd8dd46882cef4527a)
1 /*	$OpenBSD: options.c,v 1.15 2004/12/26 03:17:07 deraadt Exp $	*/
2 
3 /* DHCP options parsing and reassembly. */
4 
5 /*
6  * Copyright (c) 1995, 1996, 1997, 1998 The Internet Software Consortium.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
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.
21  *
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 <mellon@fugue.com> in cooperation with Vixie
38  * Enterprises.  To learn more about the Internet Software Consortium,
39  * see ``http://www.vix.com/isc''.  To learn more about Vixie
40  * Enterprises, see ``http://www.vix.com''.
41  */
42 
43 #include <ctype.h>
44 
45 #define DHCP_OPTION_DATA
46 #include "dhcpd.h"
47 
48 int bad_options = 0;
49 int bad_options_max = 5;
50 
51 void	parse_options(struct packet *);
52 void	parse_option_buffer(struct packet *, unsigned char *, int);
53 int	store_options(unsigned char *, int, struct tree_cache **,
54 	    unsigned char *, int, int, int, int);
55 
56 
57 /*
58  * Parse all available options out of the specified packet.
59  */
60 void
61 parse_options(struct packet *packet)
62 {
63 	/* Initially, zero all option pointers. */
64 	memset(packet->options, 0, sizeof(packet->options));
65 
66 	/* If we don't see the magic cookie, there's nothing to parse. */
67 	if (memcmp(packet->raw->options, DHCP_OPTIONS_COOKIE, 4)) {
68 		packet->options_valid = 0;
69 		return;
70 	}
71 
72 	/*
73 	 * Go through the options field, up to the end of the packet or
74 	 * the End field.
75 	 */
76 	parse_option_buffer(packet, &packet->raw->options[4],
77 	    packet->packet_length - DHCP_FIXED_NON_UDP - 4);
78 
79 	/*
80 	 * If we parsed a DHCP Option Overload option, parse more
81 	 * options out of the buffer(s) containing them.
82 	 */
83 	if (packet->options_valid &&
84 	    packet->options[DHO_DHCP_OPTION_OVERLOAD].data) {
85 		if (packet->options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 1)
86 			parse_option_buffer(packet,
87 			    (unsigned char *)packet->raw->file,
88 			    sizeof(packet->raw->file));
89 		if (packet->options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 2)
90 			parse_option_buffer(packet,
91 			    (unsigned char *)packet->raw->sname,
92 			    sizeof(packet->raw->sname));
93 	}
94 }
95 
96 /*
97  * Parse options out of the specified buffer, storing addresses of
98  * option values in packet->options and setting packet->options_valid if
99  * no errors are encountered.
100  */
101 void
102 parse_option_buffer(struct packet *packet,
103     unsigned char *buffer, int length)
104 {
105 	unsigned char *s, *t, *end = buffer + length;
106 	int len, code;
107 
108 	for (s = buffer; *s != DHO_END && s < end; ) {
109 		code = s[0];
110 
111 		/* Pad options don't have a length - just skip them. */
112 		if (code == DHO_PAD) {
113 			s++;
114 			continue;
115 		}
116 		if (s + 2 > end) {
117 			len = 65536;
118 			goto bogus;
119 		}
120 
121 		/*
122 		 * All other fields (except end, see above) have a
123 		 * one-byte length.
124 		 */
125 		len = s[1];
126 
127 		/*
128 		 * If the length is outrageous, silently skip the rest,
129 		 * and mark the packet bad. Unfortunately some crappy
130 		 * dhcp servers always seem to give us garbage on the
131 		 * end of a packet. so rather than keep refusing, give
132 		 * up and try to take one after seeing a few without
133 		 * anything good.
134 		 */
135 		if (s + len + 2 > end) {
136 		    bogus:
137 			bad_options++;
138 			warning("option %s (%d) %s.",
139 			    dhcp_options[code].name, len,
140 			    "larger than buffer");
141 			if (bad_options == bad_options_max) {
142 				packet->options_valid = 1;
143 				bad_options = 0;
144 				warning("Many bogus options seen in offers. "
145 				    "Taking this offer in spite of bogus "
146 				    "options - hope for the best!");
147 			} else {
148 				warning("rejecting bogus offer.");
149 				packet->options_valid = 0;
150 			}
151 			return;
152 		}
153 		/*
154 		 * If we haven't seen this option before, just make
155 		 * space for it and copy it there.
156 		 */
157 		if (!packet->options[code].data) {
158 			if (!(t = calloc(1, len + 1)))
159 				error("Can't allocate storage for option %s.",
160 				    dhcp_options[code].name);
161 			/*
162 			 * Copy and NUL-terminate the option (in case
163 			 * it's an ASCII string.
164 			 */
165 			memcpy(t, &s[2], len);
166 			t[len] = 0;
167 			packet->options[code].len = len;
168 			packet->options[code].data = t;
169 		} else {
170 			/*
171 			 * If it's a repeat, concatenate it to whatever
172 			 * we last saw.   This is really only required
173 			 * for clients, but what the heck...
174 			 */
175 			t = calloc(1, len + packet->options[code].len + 1);
176 			if (!t)
177 				error("Can't expand storage for option %s.",
178 				    dhcp_options[code].name);
179 			memcpy(t, packet->options[code].data,
180 				packet->options[code].len);
181 			memcpy(t + packet->options[code].len,
182 				&s[2], len);
183 			packet->options[code].len += len;
184 			t[packet->options[code].len] = 0;
185 			free(packet->options[code].data);
186 			packet->options[code].data = t;
187 		}
188 		s += len + 2;
189 	}
190 	packet->options_valid = 1;
191 }
192 
193 /*
194  * cons options into a big buffer, and then split them out into the
195  * three separate buffers if needed.  This allows us to cons up a set of
196  * vendor options using the same routine.
197  */
198 int
199 cons_options(struct packet *inpacket, struct dhcp_packet *outpacket,
200     int mms, struct tree_cache **options,
201     int overload, /* Overload flags that may be set. */
202     int terminate, int bootpp, u_int8_t *prl, int prl_len)
203 {
204 	unsigned char priority_list[300], buffer[4096];
205 	int priority_len, main_buffer_size, mainbufix, bufix;
206 	int option_size, length;
207 
208 	/*
209 	 * If the client has provided a maximum DHCP message size, use
210 	 * that; otherwise, if it's BOOTP, only 64 bytes; otherwise use
211 	 * up to the minimum IP MTU size (576 bytes).
212 	 *
213 	 * XXX if a BOOTP client specifies a max message size, we will
214 	 * honor it.
215 	 */
216 	if (!mms &&
217 	    inpacket &&
218 	    inpacket->options[DHO_DHCP_MAX_MESSAGE_SIZE].data &&
219 	    (inpacket->options[DHO_DHCP_MAX_MESSAGE_SIZE].len >=
220 	    sizeof(u_int16_t)))
221 		mms = getUShort(
222 		    inpacket->options[DHO_DHCP_MAX_MESSAGE_SIZE].data);
223 
224 	if (mms)
225 		main_buffer_size = mms - DHCP_FIXED_LEN;
226 	else if (bootpp)
227 		main_buffer_size = 64;
228 	else
229 		main_buffer_size = 576 - DHCP_FIXED_LEN;
230 
231 	if (main_buffer_size > sizeof(buffer))
232 		main_buffer_size = sizeof(buffer);
233 
234 	/* Preload the option priority list with mandatory options. */
235 	priority_len = 0;
236 	priority_list[priority_len++] = DHO_DHCP_MESSAGE_TYPE;
237 	priority_list[priority_len++] = DHO_DHCP_SERVER_IDENTIFIER;
238 	priority_list[priority_len++] = DHO_DHCP_LEASE_TIME;
239 	priority_list[priority_len++] = DHO_DHCP_MESSAGE;
240 
241 	/*
242 	 * If the client has provided a list of options that it wishes
243 	 * returned, use it to prioritize.  Otherwise, prioritize based
244 	 * on the default priority list.
245 	 */
246 	if (inpacket &&
247 	    inpacket->options[DHO_DHCP_PARAMETER_REQUEST_LIST].data) {
248 		int prlen =
249 		    inpacket->options[DHO_DHCP_PARAMETER_REQUEST_LIST].len;
250 		if (prlen + priority_len > sizeof(priority_list))
251 			prlen = sizeof(priority_list) - priority_len;
252 
253 		memcpy(&priority_list[priority_len],
254 		    inpacket->options[DHO_DHCP_PARAMETER_REQUEST_LIST].data,
255 		    prlen);
256 		priority_len += prlen;
257 		prl = priority_list;
258 	} else if (prl) {
259 		if (prl_len + priority_len > sizeof(priority_list))
260 			prl_len = sizeof(priority_list) - priority_len;
261 
262 		memcpy(&priority_list[priority_len], prl, prl_len);
263 		priority_len += prl_len;
264 		prl = priority_list;
265 	} else {
266 		memcpy(&priority_list[priority_len],
267 		    dhcp_option_default_priority_list,
268 		    sizeof_dhcp_option_default_priority_list);
269 		priority_len += sizeof_dhcp_option_default_priority_list;
270 	}
271 
272 	/* Copy the options into the big buffer... */
273 	option_size = store_options(
274 	    buffer,
275 	    (main_buffer_size - 7 + ((overload & 1) ? DHCP_FILE_LEN : 0) +
276 		((overload & 2) ? DHCP_SNAME_LEN : 0)),
277 	    options, priority_list, priority_len, main_buffer_size,
278 	    (main_buffer_size + ((overload & 1) ? DHCP_FILE_LEN : 0)),
279 	    terminate);
280 
281 	/* Put the cookie up front... */
282 	memcpy(outpacket->options, DHCP_OPTIONS_COOKIE, 4);
283 	mainbufix = 4;
284 
285 	/*
286 	 * If we're going to have to overload, store the overload option
287 	 * at the beginning.  If we can, though, just store the whole
288 	 * thing in the packet's option buffer and leave it at that.
289 	 */
290 	if (option_size <= main_buffer_size - mainbufix) {
291 		memcpy(&outpacket->options[mainbufix],
292 		    buffer, option_size);
293 		mainbufix += option_size;
294 		if (mainbufix < main_buffer_size)
295 			outpacket->options[mainbufix++] = DHO_END;
296 		length = DHCP_FIXED_NON_UDP + mainbufix;
297 	} else {
298 		outpacket->options[mainbufix++] = DHO_DHCP_OPTION_OVERLOAD;
299 		outpacket->options[mainbufix++] = 1;
300 		if (option_size >
301 		    main_buffer_size - mainbufix + DHCP_FILE_LEN)
302 			outpacket->options[mainbufix++] = 3;
303 		else
304 			outpacket->options[mainbufix++] = 1;
305 
306 		memcpy(&outpacket->options[mainbufix],
307 		    buffer, main_buffer_size - mainbufix);
308 		bufix = main_buffer_size - mainbufix;
309 		length = DHCP_FIXED_NON_UDP + mainbufix;
310 		if (overload & 1) {
311 			if (option_size - bufix <= DHCP_FILE_LEN) {
312 				memcpy(outpacket->file,
313 				    &buffer[bufix], option_size - bufix);
314 				mainbufix = option_size - bufix;
315 				if (mainbufix < DHCP_FILE_LEN)
316 					outpacket->file[mainbufix++] = (char)DHO_END;
317 				while (mainbufix < DHCP_FILE_LEN)
318 					outpacket->file[mainbufix++] = (char)DHO_PAD;
319 			} else {
320 				memcpy(outpacket->file,
321 				    &buffer[bufix], DHCP_FILE_LEN);
322 				bufix += DHCP_FILE_LEN;
323 			}
324 		}
325 		if ((overload & 2) && option_size < bufix) {
326 			memcpy(outpacket->sname,
327 			    &buffer[bufix], option_size - bufix);
328 
329 			mainbufix = option_size - bufix;
330 			if (mainbufix < DHCP_SNAME_LEN)
331 				outpacket->file[mainbufix++] = (char)DHO_END;
332 			while (mainbufix < DHCP_SNAME_LEN)
333 				outpacket->file[mainbufix++] = (char)DHO_PAD;
334 		}
335 	}
336 	return (length);
337 }
338 
339 /*
340  * Store all the requested options into the requested buffer.
341  */
342 int
343 store_options(unsigned char *buffer, int buflen, struct tree_cache **options,
344     unsigned char *priority_list, int priority_len, int first_cutoff,
345     int second_cutoff, int terminate)
346 {
347 	int bufix = 0, option_stored[256], i, ix, tto;
348 
349 	/* Zero out the stored-lengths array. */
350 	memset(option_stored, 0, sizeof(option_stored));
351 
352 	/*
353 	 * Copy out the options in the order that they appear in the
354 	 * priority list...
355 	 */
356 	for (i = 0; i < priority_len; i++) {
357 		/* Code for next option to try to store. */
358 		int code = priority_list[i];
359 		int optstart;
360 
361 		/*
362 		 * Number of bytes left to store (some may already have
363 		 * been stored by a previous pass).
364 		 */
365 		int length;
366 
367 		/* If no data is available for this option, skip it. */
368 		if (!options[code]) {
369 			continue;
370 		}
371 
372 		/*
373 		 * The client could ask for things that are mandatory,
374 		 * in which case we should avoid storing them twice...
375 		 */
376 		if (option_stored[code])
377 			continue;
378 		option_stored[code] = 1;
379 
380 		/* We should now have a constant length for the option. */
381 		length = options[code]->len;
382 
383 		/* Do we add a NUL? */
384 		if (terminate && dhcp_options[code].format[0] == 't') {
385 			length++;
386 			tto = 1;
387 		} else
388 			tto = 0;
389 
390 		/* Try to store the option. */
391 
392 		/*
393 		 * If the option's length is more than 255, we must
394 		 * store it in multiple hunks.   Store 255-byte hunks
395 		 * first.  However, in any case, if the option data will
396 		 * cross a buffer boundary, split it across that
397 		 * boundary.
398 		 */
399 		ix = 0;
400 
401 		optstart = bufix;
402 		while (length) {
403 			unsigned char incr = length > 255 ? 255 : length;
404 
405 			/*
406 			 * If this hunk of the buffer will cross a
407 			 * boundary, only go up to the boundary in this
408 			 * pass.
409 			 */
410 			if (bufix < first_cutoff &&
411 			    bufix + incr > first_cutoff)
412 				incr = first_cutoff - bufix;
413 			else if (bufix < second_cutoff &&
414 			    bufix + incr > second_cutoff)
415 				incr = second_cutoff - bufix;
416 
417 			/*
418 			 * If this option is going to overflow the
419 			 * buffer, skip it.
420 			 */
421 			if (bufix + 2 + incr > buflen) {
422 				bufix = optstart;
423 				break;
424 			}
425 
426 			/* Everything looks good - copy it in! */
427 			buffer[bufix] = code;
428 			buffer[bufix + 1] = incr;
429 			if (tto && incr == length) {
430 				memcpy(buffer + bufix + 2,
431 				    options[code]->value + ix, incr - 1);
432 				buffer[bufix + 2 + incr - 1] = 0;
433 			} else
434 				memcpy(buffer + bufix + 2,
435 				    options[code]->value + ix, incr);
436 			length -= incr;
437 			ix += incr;
438 			bufix += 2 + incr;
439 		}
440 	}
441 	return (bufix);
442 }
443 
444 /*
445  * Format the specified option so that a human can easily read it.
446  */
447 char *
448 pretty_print_option(unsigned int code, unsigned char *data, int len,
449     int emit_commas, int emit_quotes)
450 {
451 	static char optbuf[32768]; /* XXX */
452 	int hunksize = 0, numhunk = -1, numelem = 0;
453 	char fmtbuf[32], *op = optbuf;
454 	int i, j, k, opleft = sizeof(optbuf);
455 	unsigned char *dp = data;
456 	struct in_addr foo;
457 	char comma;
458 
459 	/* Code should be between 0 and 255. */
460 	if (code > 255)
461 		error("pretty_print_option: bad code %d", code);
462 
463 	if (emit_commas)
464 		comma = ',';
465 	else
466 		comma = ' ';
467 
468 	/* Figure out the size of the data. */
469 	for (i = 0; dhcp_options[code].format[i]; i++) {
470 		if (!numhunk) {
471 			warning("%s: Excess information in format string: %s",
472 			    dhcp_options[code].name,
473 			    &(dhcp_options[code].format[i]));
474 			break;
475 		}
476 		numelem++;
477 		fmtbuf[i] = dhcp_options[code].format[i];
478 		switch (dhcp_options[code].format[i]) {
479 		case 'A':
480 			--numelem;
481 			fmtbuf[i] = 0;
482 			numhunk = 0;
483 			break;
484 		case 'X':
485 			for (k = 0; k < len; k++)
486 				if (!isascii(data[k]) ||
487 				    !isprint(data[k]))
488 					break;
489 			if (k == len) {
490 				fmtbuf[i] = 't';
491 				numhunk = -2;
492 			} else {
493 				fmtbuf[i] = 'x';
494 				hunksize++;
495 				comma = ':';
496 				numhunk = 0;
497 			}
498 			fmtbuf[i + 1] = 0;
499 			break;
500 		case 't':
501 			fmtbuf[i] = 't';
502 			fmtbuf[i + 1] = 0;
503 			numhunk = -2;
504 			break;
505 		case 'I':
506 		case 'l':
507 		case 'L':
508 			hunksize += 4;
509 			break;
510 		case 's':
511 		case 'S':
512 			hunksize += 2;
513 			break;
514 		case 'b':
515 		case 'B':
516 		case 'f':
517 			hunksize++;
518 			break;
519 		case 'e':
520 			break;
521 		default:
522 			warning("%s: garbage in format string: %s",
523 			    dhcp_options[code].name,
524 			    &(dhcp_options[code].format[i]));
525 			break;
526 		}
527 	}
528 
529 	/* Check for too few bytes... */
530 	if (hunksize > len) {
531 		warning("%s: expecting at least %d bytes; got %d",
532 		    dhcp_options[code].name, hunksize, len);
533 		return ("<error>");
534 	}
535 	/* Check for too many bytes... */
536 	if (numhunk == -1 && hunksize < len)
537 		warning("%s: %d extra bytes",
538 		    dhcp_options[code].name, len - hunksize);
539 
540 	/* If this is an array, compute its size. */
541 	if (!numhunk)
542 		numhunk = len / hunksize;
543 	/* See if we got an exact number of hunks. */
544 	if (numhunk > 0 && numhunk * hunksize < len)
545 		warning("%s: %d extra bytes at end of array",
546 		    dhcp_options[code].name, len - numhunk * hunksize);
547 
548 	/* A one-hunk array prints the same as a single hunk. */
549 	if (numhunk < 0)
550 		numhunk = 1;
551 
552 	/* Cycle through the array (or hunk) printing the data. */
553 	for (i = 0; i < numhunk; i++) {
554 		for (j = 0; j < numelem; j++) {
555 			int opcount;
556 			switch (fmtbuf[j]) {
557 			case 't':
558 				if (emit_quotes) {
559 					*op++ = '"';
560 					opleft--;
561 				}
562 				for (; dp < data + len; dp++) {
563 					if (!isascii(*dp) ||
564 					    !isprint(*dp)) {
565 						if (dp + 1 != data + len ||
566 						    *dp != 0) {
567 							snprintf(op, opleft,
568 							    "\\%03o", *dp);
569 							op += 4;
570 							opleft -= 4;
571 						}
572 					} else if (*dp == '"' ||
573 					    *dp == '\'' ||
574 					    *dp == '$' ||
575 					    *dp == '`' ||
576 					    *dp == '\\') {
577 						*op++ = '\\';
578 						*op++ = *dp;
579 						opleft -= 2;
580 					} else {
581 						*op++ = *dp;
582 						opleft--;
583 					}
584 				}
585 				if (emit_quotes) {
586 					*op++ = '"';
587 					opleft--;
588 				}
589 
590 				*op = 0;
591 				break;
592 			case 'I':
593 				foo.s_addr = htonl(getULong(dp));
594 				opcount = strlcpy(op, inet_ntoa(foo), opleft);
595 				if (opcount >= opleft)
596 					goto toobig;
597 				opleft -= opcount;
598 				dp += 4;
599 				break;
600 			case 'l':
601 				opcount = snprintf(op, opleft, "%ld",
602 				    (long)getLong(dp));
603 				if (opcount >= opleft || opcount == -1)
604 					goto toobig;
605 				opleft -= opcount;
606 				dp += 4;
607 				break;
608 			case 'L':
609 				opcount = snprintf(op, opleft, "%ld",
610 				    (unsigned long)getULong(dp));
611 				if (opcount >= opleft || opcount == -1)
612 					goto toobig;
613 				opleft -= opcount;
614 				dp += 4;
615 				break;
616 			case 's':
617 				opcount = snprintf(op, opleft, "%d",
618 				    getShort(dp));
619 				if (opcount >= opleft || opcount == -1)
620 					goto toobig;
621 				opleft -= opcount;
622 				dp += 2;
623 				break;
624 			case 'S':
625 				opcount = snprintf(op, opleft, "%d",
626 				    getUShort(dp));
627 				if (opcount >= opleft || opcount == -1)
628 					goto toobig;
629 				opleft -= opcount;
630 				dp += 2;
631 				break;
632 			case 'b':
633 				opcount = snprintf(op, opleft, "%d",
634 				    *(char *)dp++);
635 				if (opcount >= opleft || opcount == -1)
636 					goto toobig;
637 				opleft -= opcount;
638 				break;
639 			case 'B':
640 				opcount = snprintf(op, opleft, "%d", *dp++);
641 				if (opcount >= opleft || opcount == -1)
642 					goto toobig;
643 				opleft -= opcount;
644 				break;
645 			case 'x':
646 				opcount = snprintf(op, opleft, "%x", *dp++);
647 				if (opcount >= opleft || opcount == -1)
648 					goto toobig;
649 				opleft -= opcount;
650 				break;
651 			case 'f':
652 				opcount = strlcpy(op,
653 				    *dp++ ? "true" : "false", opleft);
654 				if (opcount >= opleft)
655 					goto toobig;
656 				opleft -= opcount;
657 				break;
658 			default:
659 				warning("Unexpected format code %c", fmtbuf[j]);
660 			}
661 			op += strlen(op);
662 			opleft -= strlen(op);
663 			if (opleft < 1)
664 				goto toobig;
665 			if (j + 1 < numelem && comma != ':') {
666 				*op++ = ' ';
667 				opleft--;
668 			}
669 		}
670 		if (i + 1 < numhunk) {
671 			*op++ = comma;
672 			opleft--;
673 		}
674 		if (opleft < 1)
675 			goto toobig;
676 
677 	}
678 	return (optbuf);
679  toobig:
680 	warning("dhcp option too large");
681 	return ("<error>");
682 }
683 
684 void
685 do_packet(struct interface_info *interface, struct dhcp_packet *packet,
686     int len, unsigned int from_port, struct iaddr from, struct hardware *hfrom)
687 {
688 	struct packet tp;
689 	int i;
690 
691 	if (packet->hlen > sizeof(packet->chaddr)) {
692 		note("Discarding packet with invalid hlen.");
693 		return;
694 	}
695 
696 	memset(&tp, 0, sizeof(tp));
697 	tp.raw = packet;
698 	tp.packet_length = len;
699 	tp.client_port = from_port;
700 	tp.client_addr = from;
701 	tp.interface = interface;
702 	tp.haddr = hfrom;
703 
704 	parse_options(&tp);
705 	if (tp.options_valid &&
706 	    tp.options[DHO_DHCP_MESSAGE_TYPE].data)
707 		tp.packet_type = tp.options[DHO_DHCP_MESSAGE_TYPE].data[0];
708 	if (tp.packet_type)
709 		dhcp(&tp);
710 	else
711 		bootp(&tp);
712 
713 	/* Free the data associated with the options. */
714 	for (i = 0; i < 256; i++)
715 		if (tp.options[i].len && tp.options[i].data)
716 			free(tp.options[i].data);
717 }
718