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