1*35318e8fSkrw /* $OpenBSD: options.c,v 1.35 2017/02/13 22:33:39 krw Exp $ */
2e853bc5dShenning
3c824f21bShenning /* DHCP options parsing and reassembly. */
4e853bc5dShenning
5e853bc5dShenning /*
6e853bc5dShenning * Copyright (c) 1995, 1996, 1997, 1998 The Internet Software Consortium.
7e853bc5dShenning * All rights reserved.
8e853bc5dShenning *
9e853bc5dShenning * Redistribution and use in source and binary forms, with or without
10e853bc5dShenning * modification, are permitted provided that the following conditions
11e853bc5dShenning * are met:
12e853bc5dShenning *
13e853bc5dShenning * 1. Redistributions of source code must retain the above copyright
14e853bc5dShenning * notice, this list of conditions and the following disclaimer.
15e853bc5dShenning * 2. Redistributions in binary form must reproduce the above copyright
16e853bc5dShenning * notice, this list of conditions and the following disclaimer in the
17e853bc5dShenning * documentation and/or other materials provided with the distribution.
18e853bc5dShenning * 3. Neither the name of The Internet Software Consortium nor the names
19e853bc5dShenning * of its contributors may be used to endorse or promote products derived
20e853bc5dShenning * from this software without specific prior written permission.
21e853bc5dShenning *
22e853bc5dShenning * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
23e853bc5dShenning * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
24e853bc5dShenning * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25e853bc5dShenning * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26e853bc5dShenning * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
27e853bc5dShenning * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28e853bc5dShenning * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29e853bc5dShenning * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
30e853bc5dShenning * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31e853bc5dShenning * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32e853bc5dShenning * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
33e853bc5dShenning * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34e853bc5dShenning * SUCH DAMAGE.
35e853bc5dShenning *
36e853bc5dShenning * This software has been written for the Internet Software Consortium
37e853bc5dShenning * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
38e853bc5dShenning * Enterprises. To learn more about the Internet Software Consortium,
39e853bc5dShenning * see ``http://www.vix.com/isc''. To learn more about Vixie
40e853bc5dShenning * Enterprises, see ``http://www.vix.com''.
41e853bc5dShenning */
42e853bc5dShenning
43837cddffSkrw #include <sys/types.h>
44837cddffSkrw #include <sys/socket.h>
45c824f21bShenning
46837cddffSkrw #include <net/if.h>
47837cddffSkrw
48837cddffSkrw #include <netinet/in.h>
49837cddffSkrw
50837cddffSkrw #include <stdio.h>
51837cddffSkrw #include <stdlib.h>
52837cddffSkrw #include <string.h>
53837cddffSkrw
54837cddffSkrw #include "dhcp.h"
55837cddffSkrw #include "tree.h"
56e853bc5dShenning #include "dhcpd.h"
57c525a185Skrw #include "log.h"
58e853bc5dShenning
59e853bc5dShenning int bad_options = 0;
60e853bc5dShenning int bad_options_max = 5;
61e853bc5dShenning
62c824f21bShenning void parse_options(struct packet *);
63c824f21bShenning void parse_option_buffer(struct packet *, unsigned char *, int);
64cd4ecb23Skrw void create_priority_list(unsigned char *, unsigned char *, int);
6584f58762Skrw int store_option_fragment(unsigned char *, int, unsigned char,
6684f58762Skrw int, unsigned char *);
67c824f21bShenning int store_options(unsigned char *, int, struct tree_cache **,
68c432531bSkrw unsigned char *, int, int);
69e853bc5dShenning
70c824f21bShenning
71c824f21bShenning /*
72c824f21bShenning * Parse all available options out of the specified packet.
73c824f21bShenning */
74c824f21bShenning void
parse_options(struct packet * packet)75c824f21bShenning parse_options(struct packet *packet)
76e853bc5dShenning {
77e853bc5dShenning /* Initially, zero all option pointers. */
78e853bc5dShenning memset(packet->options, 0, sizeof(packet->options));
79e853bc5dShenning
80e853bc5dShenning /* If we don't see the magic cookie, there's nothing to parse. */
81e853bc5dShenning if (memcmp(packet->raw->options, DHCP_OPTIONS_COOKIE, 4)) {
82e853bc5dShenning packet->options_valid = 0;
83e853bc5dShenning return;
84e853bc5dShenning }
85e853bc5dShenning
86c824f21bShenning /*
87c824f21bShenning * Go through the options field, up to the end of the packet or
88c824f21bShenning * the End field.
89c824f21bShenning */
90e853bc5dShenning parse_option_buffer(packet, &packet->raw->options[4],
91e853bc5dShenning packet->packet_length - DHCP_FIXED_NON_UDP - 4);
92c824f21bShenning
93c824f21bShenning /*
94c824f21bShenning * If we parsed a DHCP Option Overload option, parse more
95c824f21bShenning * options out of the buffer(s) containing them.
96c824f21bShenning */
97c824f21bShenning if (packet->options_valid &&
98c824f21bShenning packet->options[DHO_DHCP_OPTION_OVERLOAD].data) {
99e853bc5dShenning if (packet->options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 1)
100e853bc5dShenning parse_option_buffer(packet,
101c824f21bShenning (unsigned char *)packet->raw->file,
102c824f21bShenning sizeof(packet->raw->file));
103e853bc5dShenning if (packet->options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 2)
104e853bc5dShenning parse_option_buffer(packet,
105c824f21bShenning (unsigned char *)packet->raw->sname,
106c824f21bShenning sizeof(packet->raw->sname));
107e853bc5dShenning }
108e853bc5dShenning }
109e853bc5dShenning
110c824f21bShenning /*
111c824f21bShenning * Parse options out of the specified buffer, storing addresses of
112c824f21bShenning * option values in packet->options and setting packet->options_valid if
113c824f21bShenning * no errors are encountered.
114c824f21bShenning */
115c824f21bShenning void
parse_option_buffer(struct packet * packet,unsigned char * buffer,int length)116c824f21bShenning parse_option_buffer(struct packet *packet,
117c824f21bShenning unsigned char *buffer, int length)
118e853bc5dShenning {
119e853bc5dShenning unsigned char *s, *t;
120e853bc5dShenning unsigned char *end = buffer + length;
121e853bc5dShenning int len;
122e853bc5dShenning int code;
123e853bc5dShenning
124e853bc5dShenning for (s = buffer; *s != DHO_END && s < end; ) {
125e853bc5dShenning code = s[0];
126e853bc5dShenning
127e853bc5dShenning /* Pad options don't have a length - just skip them. */
128e853bc5dShenning if (code == DHO_PAD) {
129c824f21bShenning s++;
130e853bc5dShenning continue;
131e853bc5dShenning }
132e853bc5dShenning if (s + 2 > end) {
133e853bc5dShenning len = 65536;
134e853bc5dShenning goto bogus;
135e853bc5dShenning }
136e853bc5dShenning
137c824f21bShenning /*
138c824f21bShenning * All other fields (except end, see above) have a
139c824f21bShenning * one-byte length.
140c824f21bShenning */
141e853bc5dShenning len = s[1];
142e853bc5dShenning
143c824f21bShenning /*
144c824f21bShenning * If the length is outrageous, silently skip the rest,
145fd9f780dSdavid * and mark the packet bad. Unfortunately some crappy
146c824f21bShenning * dhcp servers always seem to give us garbage on the
147c824f21bShenning * end of a packet. so rather than keep refusing, give
148c824f21bShenning * up and try to take one after seeing a few without
149c824f21bShenning * anything good.
150e853bc5dShenning */
151e853bc5dShenning if (s + len + 2 > end) {
152e853bc5dShenning bogus:
153e853bc5dShenning bad_options++;
154c525a185Skrw log_warnx("option %s (%d) %s.",
155e853bc5dShenning dhcp_options[code].name, len,
156e853bc5dShenning "larger than buffer");
157e853bc5dShenning if (bad_options == bad_options_max) {
158e853bc5dShenning packet->options_valid = 1;
159e853bc5dShenning bad_options = 0;
160*35318e8fSkrw log_warnx("Many bogus options seen in "
161*35318e8fSkrw "offers.");
162*35318e8fSkrw log_warnx("Taking this offer in spite of "
163*35318e8fSkrw "bogus");
164c525a185Skrw log_warnx("options - hope for the best!");
165e853bc5dShenning } else {
166c525a185Skrw log_warnx("rejecting bogus offer.");
167e853bc5dShenning packet->options_valid = 0;
168e853bc5dShenning }
169e853bc5dShenning return;
170e853bc5dShenning }
171c824f21bShenning /*
172c824f21bShenning * If we haven't seen this option before, just make
173c824f21bShenning * space for it and copy it there.
174c824f21bShenning */
175e853bc5dShenning if (!packet->options[code].data) {
176d60fc4a4Skrw t = calloc(1, len + 1);
177d60fc4a4Skrw if (!t)
178c525a185Skrw fatalx("Can't allocate storage for option %s.",
179e853bc5dShenning dhcp_options[code].name);
180c824f21bShenning /*
181c824f21bShenning * Copy and NUL-terminate the option (in case
182cff08477Sstevesk * it's an ASCII string).
183c824f21bShenning */
184e853bc5dShenning memcpy(t, &s[2], len);
185e853bc5dShenning t[len] = 0;
186e853bc5dShenning packet->options[code].len = len;
187e853bc5dShenning packet->options[code].data = t;
188e853bc5dShenning } else {
189c824f21bShenning /*
190c824f21bShenning * If it's a repeat, concatenate it to whatever
191c824f21bShenning * we last saw. This is really only required
192c824f21bShenning * for clients, but what the heck...
193c824f21bShenning */
194d60fc4a4Skrw t = calloc(1, len + packet->options[code].len + 1);
195e853bc5dShenning if (!t)
196c525a185Skrw fatalx("Can't expand storage for option %s.",
197e853bc5dShenning dhcp_options[code].name);
198e853bc5dShenning memcpy(t, packet->options[code].data,
199e853bc5dShenning packet->options[code].len);
200e853bc5dShenning memcpy(t + packet->options[code].len,
201e853bc5dShenning &s[2], len);
202e853bc5dShenning packet->options[code].len += len;
203e853bc5dShenning t[packet->options[code].len] = 0;
20492b98df2Skrw free(packet->options[code].data);
205e853bc5dShenning packet->options[code].data = t;
206e853bc5dShenning }
207e853bc5dShenning s += len + 2;
208e853bc5dShenning }
209e853bc5dShenning packet->options_valid = 1;
210e853bc5dShenning }
211e853bc5dShenning
212c824f21bShenning /*
213cd4ecb23Skrw * Fill priority_list with a complete list of DHCP options sorted by
214cd4ecb23Skrw * priority. i.e.
215cd4ecb23Skrw * 1) Mandatory options.
216cd4ecb23Skrw * 2) Options from prl that are not already present.
217cd4ecb23Skrw * 3) Options from the default list that are not already present.
218cd4ecb23Skrw */
219cd4ecb23Skrw void
create_priority_list(unsigned char * priority_list,unsigned char * prl,int prl_len)220cd4ecb23Skrw create_priority_list(unsigned char *priority_list, unsigned char *prl,
221cd4ecb23Skrw int prl_len)
222cd4ecb23Skrw {
223c5c66dc3Sreyk unsigned char stored_list[256];
224cd4ecb23Skrw int i, priority_len = 0;
225cd4ecb23Skrw
226c5c66dc3Sreyk /* clear stored_list, priority_list should be cleared before */
227359ce2c3Smestre memset(&stored_list, 0, sizeof(stored_list));
228cd4ecb23Skrw
229cd4ecb23Skrw /* Some options we don't want on the priority list. */
230cd4ecb23Skrw stored_list[DHO_PAD] = 1;
231cd4ecb23Skrw stored_list[DHO_END] = 1;
232cd4ecb23Skrw
233cd4ecb23Skrw /* Mandatory options. */
234cd4ecb23Skrw for(i = 0; dhcp_option_default_priority_list[i] != DHO_END; i++) {
235cd4ecb23Skrw priority_list[priority_len++] =
236cd4ecb23Skrw dhcp_option_default_priority_list[i];
237cd4ecb23Skrw stored_list[dhcp_option_default_priority_list[i]] = 1;
238cd4ecb23Skrw }
239cd4ecb23Skrw
240cd4ecb23Skrw /* Supplied priority list. */
241cd4ecb23Skrw if (!prl)
242cd4ecb23Skrw prl_len = 0;
243cd4ecb23Skrw for(i = 0; i < prl_len; i++) {
2443f461432Skrw /* CLASSLESS routes always have priority, sayeth RFC 3442. */
2453f461432Skrw if (prl[i] == DHO_CLASSLESS_STATIC_ROUTES ||
2463f461432Skrw prl[i] == DHO_CLASSLESS_MS_STATIC_ROUTES) {
2473f461432Skrw priority_list[priority_len++] = prl[i];
2483f461432Skrw stored_list[prl[i]] = 1;
2493f461432Skrw }
2503f461432Skrw }
2513f461432Skrw for(i = 0; i < prl_len; i++) {
252cd4ecb23Skrw if (stored_list[prl[i]])
253cd4ecb23Skrw continue;
254cd4ecb23Skrw priority_list[priority_len++] = prl[i];
255cd4ecb23Skrw stored_list[prl[i]] = 1;
256cd4ecb23Skrw }
257cd4ecb23Skrw
258cd4ecb23Skrw /* Default priority list. */
259cd4ecb23Skrw prl = dhcp_option_default_priority_list;
260cd4ecb23Skrw for(i = 0; i < 256; i++) {
261cd4ecb23Skrw if (stored_list[prl[i]])
262cd4ecb23Skrw continue;
263cd4ecb23Skrw priority_list[priority_len++] = prl[i];
264cd4ecb23Skrw stored_list[prl[i]] = 1;
265cd4ecb23Skrw }
266cd4ecb23Skrw }
267cd4ecb23Skrw /*
268c824f21bShenning * cons options into a big buffer, and then split them out into the
269c824f21bShenning * three separate buffers if needed. This allows us to cons up a set of
270c824f21bShenning * vendor options using the same routine.
271c824f21bShenning */
272c824f21bShenning int
cons_options(struct packet * inpacket,struct dhcp_packet * outpacket,int mms,struct tree_cache ** options,int overload,int terminate,int bootpp,u_int8_t * prl,int prl_len)273c824f21bShenning cons_options(struct packet *inpacket, struct dhcp_packet *outpacket,
274c824f21bShenning int mms, struct tree_cache **options,
275c824f21bShenning int overload, /* Overload flags that may be set. */
276c824f21bShenning int terminate, int bootpp, u_int8_t *prl, int prl_len)
277e853bc5dShenning {
278cd4ecb23Skrw unsigned char priority_list[256];
279e853bc5dShenning unsigned char buffer[4096]; /* Really big buffer... */
280c432531bSkrw int bufix, main_buffer_size, option_size;
281e853bc5dShenning
282c824f21bShenning /*
283c824f21bShenning * If the client has provided a maximum DHCP message size, use
284c824f21bShenning * that; otherwise, if it's BOOTP, only 64 bytes; otherwise use
285c824f21bShenning * up to the minimum IP MTU size (576 bytes).
286c824f21bShenning *
287c824f21bShenning * XXX if a BOOTP client specifies a max message size, we will
288c824f21bShenning * honor it.
289c824f21bShenning */
290e853bc5dShenning if (!mms &&
291e853bc5dShenning inpacket &&
292e853bc5dShenning inpacket->options[DHO_DHCP_MAX_MESSAGE_SIZE].data &&
293e853bc5dShenning (inpacket->options[DHO_DHCP_MAX_MESSAGE_SIZE].len >=
2947eb1ada0Skrw sizeof(u_int16_t))) {
295c824f21bShenning mms = getUShort(
296c824f21bShenning inpacket->options[DHO_DHCP_MAX_MESSAGE_SIZE].data);
2977eb1ada0Skrw }
298e853bc5dShenning
2992b30e5f2Skrw if (mms) {
3002b30e5f2Skrw if (mms < 576)
3012b30e5f2Skrw mms = 576; /* mms must be >= minimum IP MTU */
302e853bc5dShenning main_buffer_size = mms - DHCP_FIXED_LEN;
3032b30e5f2Skrw } else if (bootpp)
304e853bc5dShenning main_buffer_size = 64;
305e853bc5dShenning else
306e853bc5dShenning main_buffer_size = 576 - DHCP_FIXED_LEN;
307e853bc5dShenning
308ef0ff70bSkrw if (main_buffer_size > sizeof(outpacket->options))
309ef0ff70bSkrw main_buffer_size = sizeof(outpacket->options);
310e853bc5dShenning
311c824f21bShenning /*
312c432531bSkrw * Initialize the available buffers, some or all of which may not be
313c432531bSkrw * used.
314c432531bSkrw */
315c432531bSkrw memset(outpacket->options, DHO_PAD, sizeof(outpacket->options));
316c432531bSkrw if (overload & 1)
317c432531bSkrw memset(outpacket->file, DHO_PAD, DHCP_FILE_LEN);
318c432531bSkrw if (overload & 2)
319c432531bSkrw memset(outpacket->sname, DHO_PAD, DHCP_SNAME_LEN);
320c432531bSkrw if (bootpp)
321c432531bSkrw overload = 0; /* Don't use overload buffers for bootp! */
322c432531bSkrw
323c432531bSkrw /*
324cd4ecb23Skrw * Get complete list of possible options in priority order. Use the
325cd4ecb23Skrw * list provided in the options. Lacking that use the list provided by
326cd4ecb23Skrw * prl. If that is not available just use the default list.
327c824f21bShenning */
328359ce2c3Smestre memset(&priority_list, 0, sizeof(priority_list));
329*35318e8fSkrw if (inpacket &&
330*35318e8fSkrw inpacket->options[DHO_DHCP_PARAMETER_REQUEST_LIST].data)
331cd4ecb23Skrw create_priority_list(priority_list,
332c824f21bShenning inpacket->options[DHO_DHCP_PARAMETER_REQUEST_LIST].data,
333cd4ecb23Skrw inpacket->options[DHO_DHCP_PARAMETER_REQUEST_LIST].len);
334cd4ecb23Skrw else if (prl)
335cd4ecb23Skrw create_priority_list(priority_list, prl, prl_len);
336cd4ecb23Skrw else
337cd4ecb23Skrw create_priority_list(priority_list, NULL, 0);
338e853bc5dShenning
339c824f21bShenning /*
340c432531bSkrw * Copy the options into the big buffer, including leading cookie and
341c432531bSkrw * DHCP_OVERLOAD_OPTION, and DHO_END if it fits. All unused space will
342c432531bSkrw * be set to DHO_PAD
343c824f21bShenning */
344c432531bSkrw option_size = store_options(buffer, main_buffer_size, options,
345c432531bSkrw priority_list, overload, terminate);
346c432531bSkrw if (option_size == 0)
347c432531bSkrw return (DHCP_FIXED_NON_UDP);
34858337b23Skrw
349c432531bSkrw /* Copy the main buffer. */
350c432531bSkrw memcpy(&outpacket->options[0], buffer, main_buffer_size);
351c432531bSkrw if (option_size <= main_buffer_size)
352c432531bSkrw return (DHCP_FIXED_NON_UDP + option_size);
353e853bc5dShenning
354c432531bSkrw /* Copy the overflow buffers. */
355c432531bSkrw bufix = main_buffer_size;
356e853bc5dShenning if (overload & 1) {
357b2db86bdSkrw memcpy(outpacket->file, &buffer[bufix], DHCP_FILE_LEN);
358e853bc5dShenning bufix += DHCP_FILE_LEN;
359e853bc5dShenning }
360c432531bSkrw if (overload & 2)
361c432531bSkrw memcpy(outpacket->sname, &buffer[bufix], DHCP_SNAME_LEN);
36258337b23Skrw
36358337b23Skrw return (DHCP_FIXED_NON_UDP + main_buffer_size);
364e853bc5dShenning }
365e853bc5dShenning
366c824f21bShenning /*
36784f58762Skrw * Store a <code><length><data> fragment in buffer. Return the number of
36884f58762Skrw * characters used. Return 0 if no data could be stored.
36984f58762Skrw */
37084f58762Skrw int
store_option_fragment(unsigned char * buffer,int buffer_size,unsigned char code,int length,unsigned char * data)37184f58762Skrw store_option_fragment(unsigned char *buffer, int buffer_size,
37284f58762Skrw unsigned char code, int length, unsigned char *data)
37384f58762Skrw {
37484f58762Skrw buffer_size -= 2; /* Space for option code and option length. */
37584f58762Skrw
37684f58762Skrw if (buffer_size < 1)
37784f58762Skrw return (0);
37884f58762Skrw
37984f58762Skrw if (buffer_size > 255)
38084f58762Skrw buffer_size = 255;
38184f58762Skrw if (length > buffer_size)
38284f58762Skrw length = buffer_size;
38384f58762Skrw
38484f58762Skrw buffer[0] = code;
38584f58762Skrw buffer[1] = length;
38684f58762Skrw
38784f58762Skrw memcpy(&buffer[2], data, length);
38884f58762Skrw
38984f58762Skrw return (length + 2);
39084f58762Skrw }
39184f58762Skrw
39284f58762Skrw /*
393c432531bSkrw * Store all the requested options into the requested buffer. Insert the
394c432531bSkrw * required cookie, DHO_DHCP_OPTION_OVERLOAD options and append a DHO_END if
395c432531bSkrw * if fits. Ensure all buffer space is set to DHO_PAD if unused.
396c824f21bShenning */
397c824f21bShenning int
store_options(unsigned char * buffer,int main_buffer_size,struct tree_cache ** options,unsigned char * priority_list,int overload,int terminate)398c432531bSkrw store_options(unsigned char *buffer, int main_buffer_size,
399c432531bSkrw struct tree_cache **options, unsigned char *priority_list, int overload,
400cd4ecb23Skrw int terminate)
401e853bc5dShenning {
402c432531bSkrw int buflen, code, cutoff, i, incr, ix, length, optstart, overflow;
403c432531bSkrw int second_cutoff;
40484f58762Skrw int bufix = 0;
4053f461432Skrw int stored_classless = 0;
406e853bc5dShenning
407920fcdb1Skrw overload &= 3; /* Only consider valid bits. */
408920fcdb1Skrw
409c432531bSkrw cutoff = main_buffer_size;
410c432531bSkrw second_cutoff = cutoff + ((overload & 1) ? DHCP_FILE_LEN : 0);
411c432531bSkrw buflen = second_cutoff + ((overload & 2) ? DHCP_SNAME_LEN : 0);
412920fcdb1Skrw
413c432531bSkrw memset(buffer, DHO_PAD, buflen);
414c432531bSkrw memcpy(buffer, DHCP_OPTIONS_COOKIE, 4);
415c432531bSkrw
416920fcdb1Skrw if (overload)
417920fcdb1Skrw bufix = 7; /* Reserve space for DHO_DHCP_OPTION_OVERLOAD. */
418920fcdb1Skrw else
419920fcdb1Skrw bufix = 4;
420c432531bSkrw
421c824f21bShenning /*
42284f58762Skrw * Store options in the order they appear in the priority list.
423c824f21bShenning */
424cd4ecb23Skrw for (i = 0; i < 256; i++) {
425e853bc5dShenning /* Code for next option to try to store. */
42684f58762Skrw code = priority_list[i];
427cd4ecb23Skrw if (code == DHO_PAD || code == DHO_END)
428e853bc5dShenning continue;
429e853bc5dShenning
430cd4ecb23Skrw if (!options[code] || !tree_evaluate(options[code]))
431cd4ecb23Skrw continue;
432e853bc5dShenning
4333f461432Skrw /*
4343f461432Skrw * RFC 3442 says:
4353f461432Skrw *
4363f461432Skrw * When a DHCP client requests the Classless Static
4373f461432Skrw * Routes option and also requests either or both of the
4383f461432Skrw * Router option and the Static Routes option, and the
4393f461432Skrw * DHCP server is sending Classless Static Routes options
4403f461432Skrw * to that client, the server SHOULD NOT include the
4413f461432Skrw * Router or Static Routes options.
4423f461432Skrw */
4433f461432Skrw if ((code == DHO_ROUTERS || code == DHO_STATIC_ROUTES) &&
4443f461432Skrw stored_classless)
4453f461432Skrw continue;
4463f461432Skrw
447e853bc5dShenning /* We should now have a constant length for the option. */
448e853bc5dShenning length = options[code]->len;
449e853bc5dShenning
450e853bc5dShenning /* Try to store the option. */
451e853bc5dShenning optstart = bufix;
45284f58762Skrw ix = 0;
453e853bc5dShenning while (length) {
45484f58762Skrw incr = store_option_fragment(&buffer[bufix],
45584f58762Skrw cutoff - bufix, code, length,
45684f58762Skrw options[code]->value + ix);
45784f58762Skrw
45884f58762Skrw if (incr > 0) {
45984f58762Skrw bufix += incr;
46084f58762Skrw length -= incr - 2;
46184f58762Skrw ix += incr - 2;
46284f58762Skrw continue;
46384f58762Skrw }
464e853bc5dShenning
465c824f21bShenning /*
46684f58762Skrw * No fragment could be stored in the space before the
46784f58762Skrw * cutoff. Fill the unusable space with DHO_PAD and
46884f58762Skrw * move cutoff for another attempt.
469c824f21bShenning */
47084f58762Skrw memset(&buffer[bufix], DHO_PAD, cutoff - bufix);
47184f58762Skrw bufix = cutoff;
47284f58762Skrw if (cutoff < second_cutoff)
47384f58762Skrw cutoff = second_cutoff;
47484f58762Skrw else if (cutoff < buflen)
47584f58762Skrw cutoff = buflen;
47684f58762Skrw else
477e853bc5dShenning break;
478e853bc5dShenning }
479e853bc5dShenning
48084f58762Skrw if (length > 0) {
48184f58762Skrw zapfrags:
48284f58762Skrw memset(&buffer[optstart], DHO_PAD, buflen - optstart);
48384f58762Skrw bufix = optstart;
48484f58762Skrw } else if (terminate && dhcp_options[code].format[0] == 't') {
48584f58762Skrw if (bufix < cutoff)
48684f58762Skrw buffer[bufix++] = '\0';
48784f58762Skrw else
48884f58762Skrw goto zapfrags;
489e853bc5dShenning }
4903f461432Skrw if (code == DHO_CLASSLESS_STATIC_ROUTES ||
4913f461432Skrw code == DHO_CLASSLESS_MS_STATIC_ROUTES)
4923f461432Skrw stored_classless = 1;
493e853bc5dShenning }
49484f58762Skrw
495c432531bSkrw if (bufix == (4 + (overload ? 3 : 0)))
496c432531bSkrw /* Didn't manage to store any options. */
497c432531bSkrw return (0);
498c432531bSkrw
499c432531bSkrw if (bufix < buflen)
500c432531bSkrw buffer[bufix++] = DHO_END;
501c432531bSkrw
502c432531bSkrw /* Fill in overload option value based on space used for options. */
5038914f811Skrw if (overload) {
504c432531bSkrw overflow = bufix - main_buffer_size;
5058914f811Skrw if (overflow > 0) {
506920fcdb1Skrw buffer[4] = DHO_DHCP_OPTION_OVERLOAD;
507920fcdb1Skrw buffer[5] = 1;
508c432531bSkrw if (overload & 1) {
509920fcdb1Skrw buffer[6] |= 1;
510c432531bSkrw overflow -= DHCP_FILE_LEN;
511c432531bSkrw }
512920fcdb1Skrw if ((overload & 2) && overflow > 0)
513c432531bSkrw buffer[6] |= 2;
5148914f811Skrw } else {
5158914f811Skrw /*
5168914f811Skrw * Compact buffer to eliminate the unused
5178914f811Skrw * DHO_DHCP_OPTION_OVERLOAD option. Some clients
5188914f811Skrw * choke on DHO_PAD options there.
5198914f811Skrw */
5208914f811Skrw memmove(&buffer[4], &buffer[7], buflen - 7);
5218914f811Skrw bufix -= 3;
5228914f811Skrw memset(&buffer[bufix], DHO_PAD, 3);
5238914f811Skrw }
524c432531bSkrw }
525c432531bSkrw
526c824f21bShenning return (bufix);
527e853bc5dShenning }
528e853bc5dShenning
529c824f21bShenning void
do_packet(struct interface_info * interface,struct dhcp_packet * packet,int len,unsigned int from_port,struct iaddr from,struct hardware * hfrom)530c824f21bShenning do_packet(struct interface_info *interface, struct dhcp_packet *packet,
531c824f21bShenning int len, unsigned int from_port, struct iaddr from, struct hardware *hfrom)
532e853bc5dShenning {
533e853bc5dShenning struct packet tp;
534e853bc5dShenning int i;
535e853bc5dShenning
536c824f21bShenning if (packet->hlen > sizeof(packet->chaddr)) {
537c525a185Skrw log_info("Discarding packet with invalid hlen.");
538e853bc5dShenning return;
539e853bc5dShenning }
540e853bc5dShenning
541c824f21bShenning memset(&tp, 0, sizeof(tp));
542e853bc5dShenning tp.raw = packet;
543e853bc5dShenning tp.packet_length = len;
544e853bc5dShenning tp.client_port = from_port;
545e853bc5dShenning tp.client_addr = from;
546e853bc5dShenning tp.interface = interface;
547e853bc5dShenning tp.haddr = hfrom;
548e853bc5dShenning
549e853bc5dShenning parse_options(&tp);
550e853bc5dShenning if (tp.options_valid &&
551e853bc5dShenning tp.options[DHO_DHCP_MESSAGE_TYPE].data)
552c824f21bShenning tp.packet_type = tp.options[DHO_DHCP_MESSAGE_TYPE].data[0];
55384d8c049Syasuoka
554e853bc5dShenning if (tp.packet_type)
55594bf53e6Skrw dhcp(&tp, interface->is_udpsock);
556e853bc5dShenning else
557e853bc5dShenning bootp(&tp);
558e853bc5dShenning
559e853bc5dShenning /* Free the data associated with the options. */
560c824f21bShenning for (i = 0; i < 256; i++)
56192b98df2Skrw free(tp.options[i].data);
562e853bc5dShenning }
563