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