1*02e02bd5Skrw /* $OpenBSD: options.c,v 1.33 2007/01/25 01:21:04 krw Exp $ */ 29a2590e5Sderaadt 3e7eb2effShenning /* DHCP options parsing and reassembly. */ 49a2590e5Sderaadt 59a2590e5Sderaadt /* 69a2590e5Sderaadt * Copyright (c) 1995, 1996, 1997, 1998 The Internet Software Consortium. 79a2590e5Sderaadt * All rights reserved. 89a2590e5Sderaadt * 99a2590e5Sderaadt * Redistribution and use in source and binary forms, with or without 109a2590e5Sderaadt * modification, are permitted provided that the following conditions 119a2590e5Sderaadt * are met: 129a2590e5Sderaadt * 139a2590e5Sderaadt * 1. Redistributions of source code must retain the above copyright 149a2590e5Sderaadt * notice, this list of conditions and the following disclaimer. 159a2590e5Sderaadt * 2. Redistributions in binary form must reproduce the above copyright 169a2590e5Sderaadt * notice, this list of conditions and the following disclaimer in the 179a2590e5Sderaadt * documentation and/or other materials provided with the distribution. 189a2590e5Sderaadt * 3. Neither the name of The Internet Software Consortium nor the names 199a2590e5Sderaadt * of its contributors may be used to endorse or promote products derived 209a2590e5Sderaadt * from this software without specific prior written permission. 219a2590e5Sderaadt * 229a2590e5Sderaadt * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND 239a2590e5Sderaadt * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 249a2590e5Sderaadt * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 259a2590e5Sderaadt * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 269a2590e5Sderaadt * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR 279a2590e5Sderaadt * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 289a2590e5Sderaadt * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 299a2590e5Sderaadt * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 309a2590e5Sderaadt * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 319a2590e5Sderaadt * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 329a2590e5Sderaadt * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 339a2590e5Sderaadt * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 349a2590e5Sderaadt * SUCH DAMAGE. 359a2590e5Sderaadt * 369a2590e5Sderaadt * This software has been written for the Internet Software Consortium 379a2590e5Sderaadt * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie 389a2590e5Sderaadt * Enterprises. To learn more about the Internet Software Consortium, 399a2590e5Sderaadt * see ``http://www.vix.com/isc''. To learn more about Vixie 409a2590e5Sderaadt * Enterprises, see ``http://www.vix.com''. 419a2590e5Sderaadt */ 429a2590e5Sderaadt 43c714dadcShenning #include <ctype.h> 44c714dadcShenning 459a2590e5Sderaadt #include "dhcpd.h" 469a2590e5Sderaadt 47*02e02bd5Skrw int parse_option_buffer(struct option_data *, unsigned char *, int); 489a2590e5Sderaadt 49c714dadcShenning /* 50c714dadcShenning * Parse options out of the specified buffer, storing addresses of 514f062ee3Skrw * option values in options and setting client->options_valid if 52c714dadcShenning * no errors are encountered. 53c714dadcShenning */ 54*02e02bd5Skrw int 554f062ee3Skrw parse_option_buffer(struct option_data *options, unsigned char *buffer, 564f062ee3Skrw int length) 579a2590e5Sderaadt { 58285f06efSderaadt unsigned char *s, *t, *end = buffer + length; 59285f06efSderaadt int len, code; 609a2590e5Sderaadt 619a2590e5Sderaadt for (s = buffer; *s != DHO_END && s < end; ) { 629a2590e5Sderaadt code = s[0]; 639a2590e5Sderaadt 649a2590e5Sderaadt /* Pad options don't have a length - just skip them. */ 659a2590e5Sderaadt if (code == DHO_PAD) { 66f1e89499Shenning s++; 679a2590e5Sderaadt continue; 689a2590e5Sderaadt } 699a2590e5Sderaadt 70c714dadcShenning /* 71b6fc88b9Skrw * All options other than DHO_PAD and DHO_END have a 72b6fc88b9Skrw * one-byte length field. 73c714dadcShenning */ 74b6fc88b9Skrw if (s + 2 > end) 75b6fc88b9Skrw len = 0; 76b6fc88b9Skrw else 779a2590e5Sderaadt len = s[1]; 789a2590e5Sderaadt 79c714dadcShenning /* 80b6fc88b9Skrw * If the option claims to extend beyond the end of the buffer 81b6fc88b9Skrw * then mark the options buffer bad. 829a2590e5Sderaadt */ 839a2590e5Sderaadt if (s + len + 2 > end) { 84b6fc88b9Skrw warning("option %s (%d) larger than buffer.", 85b6fc88b9Skrw dhcp_options[code].name, len); 86c955dd46Smickey warning("rejecting bogus offer."); 87*02e02bd5Skrw return (0); 889a2590e5Sderaadt } 89c714dadcShenning /* 90c714dadcShenning * If we haven't seen this option before, just make 91c714dadcShenning * space for it and copy it there. 92c714dadcShenning */ 934f062ee3Skrw if (!options[code].data) { 948e916ab9Shenning if (!(t = calloc(1, len + 1))) 959a2590e5Sderaadt error("Can't allocate storage for option %s.", 969a2590e5Sderaadt dhcp_options[code].name); 97c714dadcShenning /* 98c714dadcShenning * Copy and NUL-terminate the option (in case 99cff08477Sstevesk * it's an ASCII string). 100c714dadcShenning */ 1019a2590e5Sderaadt memcpy(t, &s[2], len); 1029a2590e5Sderaadt t[len] = 0; 1034f062ee3Skrw options[code].len = len; 1044f062ee3Skrw options[code].data = t; 1059a2590e5Sderaadt } else { 106c714dadcShenning /* 107c714dadcShenning * If it's a repeat, concatenate it to whatever 108c714dadcShenning * we last saw. This is really only required 109c714dadcShenning * for clients, but what the heck... 110c714dadcShenning */ 1114f062ee3Skrw t = calloc(1, len + options[code].len + 1); 1129a2590e5Sderaadt if (!t) 1139a2590e5Sderaadt error("Can't expand storage for option %s.", 1149a2590e5Sderaadt dhcp_options[code].name); 1154f062ee3Skrw memcpy(t, options[code].data, options[code].len); 1164f062ee3Skrw memcpy(t + options[code].len, &s[2], len); 1174f062ee3Skrw options[code].len += len; 1184f062ee3Skrw t[options[code].len] = 0; 1194f062ee3Skrw free(options[code].data); 1204f062ee3Skrw options[code].data = t; 1219a2590e5Sderaadt } 1229a2590e5Sderaadt s += len + 2; 1239a2590e5Sderaadt } 124*02e02bd5Skrw 125*02e02bd5Skrw return (1); 1269a2590e5Sderaadt } 1279a2590e5Sderaadt 128c714dadcShenning /* 12996978980Skrw * Copy as many options as fit in buflen bytes of buf. Return the 13096978980Skrw * offset of the start of the last option copied. A caller can check 13196978980Skrw * to see if it's DHO_END to decide if all the options were copied. 132c714dadcShenning */ 133c714dadcShenning int 13496978980Skrw cons_options(unsigned char *buf, const int buflen, struct option_data *options) 1359a2590e5Sderaadt { 13696978980Skrw int ix, incr, length, bufix, code, lastopt = -1; 1379a2590e5Sderaadt 13896978980Skrw bzero(buf, buflen); 1399a2590e5Sderaadt 14096978980Skrw if (buflen > 3) 14196978980Skrw memcpy(buf, DHCP_OPTIONS_COOKIE, 4); 14296978980Skrw bufix = 4; 1439a2590e5Sderaadt 14496978980Skrw for (code = DHO_SUBNET_MASK; code < DHO_END; code++) { 145f5396ce2Skrw if (!options[code].data) 1469a2590e5Sderaadt continue; 1479a2590e5Sderaadt 148d7d9bbf5Skrw length = options[code].len; 14996978980Skrw if (bufix + length + 2*((length+254)/255) >= buflen) 15096978980Skrw return (lastopt); 1519a2590e5Sderaadt 15296978980Skrw lastopt = bufix; 1539a2590e5Sderaadt ix = 0; 1549a2590e5Sderaadt 1559a2590e5Sderaadt while (length) { 15696978980Skrw incr = length > 255 ? 255 : length; 1579a2590e5Sderaadt 15896978980Skrw buf[bufix++] = code; 15996978980Skrw buf[bufix++] = incr; 16096978980Skrw memcpy(buf + bufix, options[code].data + ix, incr); 1619a2590e5Sderaadt 1629a2590e5Sderaadt length -= incr; 1639a2590e5Sderaadt ix += incr; 1646fc9f4f6Skrw bufix += incr; 1659a2590e5Sderaadt } 1669a2590e5Sderaadt } 16796978980Skrw 16896978980Skrw if (bufix < buflen) { 16996978980Skrw buf[bufix] = DHO_END; 17096978980Skrw lastopt = bufix; 17196978980Skrw } 17296978980Skrw 17396978980Skrw return (lastopt); 1749a2590e5Sderaadt } 1759a2590e5Sderaadt 176c714dadcShenning /* 177c714dadcShenning * Format the specified option so that a human can easily read it. 178c714dadcShenning */ 179c714dadcShenning char * 180c714dadcShenning pretty_print_option(unsigned int code, unsigned char *data, int len, 181c714dadcShenning int emit_commas, int emit_quotes) 1829a2590e5Sderaadt { 1839a2590e5Sderaadt static char optbuf[32768]; /* XXX */ 184285f06efSderaadt int hunksize = 0, numhunk = -1, numelem = 0; 185285f06efSderaadt char fmtbuf[32], *op = optbuf; 186285f06efSderaadt int i, j, k, opleft = sizeof(optbuf); 1879a2590e5Sderaadt unsigned char *dp = data; 1889a2590e5Sderaadt struct in_addr foo; 1899a2590e5Sderaadt char comma; 1909a2590e5Sderaadt 1919a2590e5Sderaadt /* Code should be between 0 and 255. */ 1929a2590e5Sderaadt if (code > 255) 1935eb2300aShenning error("pretty_print_option: bad code %d", code); 1949a2590e5Sderaadt 1959a2590e5Sderaadt if (emit_commas) 1969a2590e5Sderaadt comma = ','; 1979a2590e5Sderaadt else 1989a2590e5Sderaadt comma = ' '; 1999a2590e5Sderaadt 2009a2590e5Sderaadt /* Figure out the size of the data. */ 2019a2590e5Sderaadt for (i = 0; dhcp_options[code].format[i]; i++) { 2029a2590e5Sderaadt if (!numhunk) { 203c955dd46Smickey warning("%s: Excess information in format string: %s", 2049a2590e5Sderaadt dhcp_options[code].name, 2059a2590e5Sderaadt &(dhcp_options[code].format[i])); 2069a2590e5Sderaadt break; 2079a2590e5Sderaadt } 2089a2590e5Sderaadt numelem++; 2099a2590e5Sderaadt fmtbuf[i] = dhcp_options[code].format[i]; 2109a2590e5Sderaadt switch (dhcp_options[code].format[i]) { 2119a2590e5Sderaadt case 'A': 2129a2590e5Sderaadt --numelem; 2139a2590e5Sderaadt fmtbuf[i] = 0; 2149a2590e5Sderaadt numhunk = 0; 2159a2590e5Sderaadt break; 2169a2590e5Sderaadt case 'X': 217c714dadcShenning for (k = 0; k < len; k++) 2189a2590e5Sderaadt if (!isascii(data[k]) || 2199a2590e5Sderaadt !isprint(data[k])) 2209a2590e5Sderaadt break; 221b54c879eShenning if (k == len) { 2229a2590e5Sderaadt fmtbuf[i] = 't'; 2239a2590e5Sderaadt numhunk = -2; 2249a2590e5Sderaadt } else { 2259a2590e5Sderaadt fmtbuf[i] = 'x'; 2269a2590e5Sderaadt hunksize++; 2279a2590e5Sderaadt comma = ':'; 2289a2590e5Sderaadt numhunk = 0; 2299a2590e5Sderaadt } 2309a2590e5Sderaadt fmtbuf[i + 1] = 0; 2319a2590e5Sderaadt break; 2329a2590e5Sderaadt case 't': 2339a2590e5Sderaadt fmtbuf[i] = 't'; 2349a2590e5Sderaadt fmtbuf[i + 1] = 0; 2359a2590e5Sderaadt numhunk = -2; 2369a2590e5Sderaadt break; 2379a2590e5Sderaadt case 'I': 2389a2590e5Sderaadt case 'l': 2399a2590e5Sderaadt case 'L': 2409a2590e5Sderaadt hunksize += 4; 2419a2590e5Sderaadt break; 2429a2590e5Sderaadt case 's': 2439a2590e5Sderaadt case 'S': 2449a2590e5Sderaadt hunksize += 2; 2459a2590e5Sderaadt break; 2469a2590e5Sderaadt case 'b': 2479a2590e5Sderaadt case 'B': 2489a2590e5Sderaadt case 'f': 2499a2590e5Sderaadt hunksize++; 2509a2590e5Sderaadt break; 2519a2590e5Sderaadt case 'e': 2529a2590e5Sderaadt break; 2539a2590e5Sderaadt default: 254c955dd46Smickey warning("%s: garbage in format string: %s", 2559a2590e5Sderaadt dhcp_options[code].name, 2569a2590e5Sderaadt &(dhcp_options[code].format[i])); 2579a2590e5Sderaadt break; 2589a2590e5Sderaadt } 2599a2590e5Sderaadt } 2609a2590e5Sderaadt 2619a2590e5Sderaadt /* Check for too few bytes... */ 2629a2590e5Sderaadt if (hunksize > len) { 263c955dd46Smickey warning("%s: expecting at least %d bytes; got %d", 264c714dadcShenning dhcp_options[code].name, hunksize, len); 265c714dadcShenning return ("<error>"); 2669a2590e5Sderaadt } 2679a2590e5Sderaadt /* Check for too many bytes... */ 2689a2590e5Sderaadt if (numhunk == -1 && hunksize < len) 269c955dd46Smickey warning("%s: %d extra bytes", 270c714dadcShenning dhcp_options[code].name, len - hunksize); 2719a2590e5Sderaadt 2729a2590e5Sderaadt /* If this is an array, compute its size. */ 2739a2590e5Sderaadt if (!numhunk) 2749a2590e5Sderaadt numhunk = len / hunksize; 2759a2590e5Sderaadt /* See if we got an exact number of hunks. */ 2769a2590e5Sderaadt if (numhunk > 0 && numhunk * hunksize < len) 277c955dd46Smickey warning("%s: %d extra bytes at end of array", 278c714dadcShenning dhcp_options[code].name, len - numhunk * hunksize); 2799a2590e5Sderaadt 2809a2590e5Sderaadt /* A one-hunk array prints the same as a single hunk. */ 2819a2590e5Sderaadt if (numhunk < 0) 2829a2590e5Sderaadt numhunk = 1; 2839a2590e5Sderaadt 2849a2590e5Sderaadt /* Cycle through the array (or hunk) printing the data. */ 2859a2590e5Sderaadt for (i = 0; i < numhunk; i++) { 2869a2590e5Sderaadt for (j = 0; j < numelem; j++) { 2879a2590e5Sderaadt int opcount; 2889a2590e5Sderaadt switch (fmtbuf[j]) { 2899a2590e5Sderaadt case 't': 2909a2590e5Sderaadt if (emit_quotes) { 2919a2590e5Sderaadt *op++ = '"'; 2929a2590e5Sderaadt opleft--; 2939a2590e5Sderaadt } 2949a2590e5Sderaadt for (; dp < data + len; dp++) { 2959a2590e5Sderaadt if (!isascii(*dp) || 2969a2590e5Sderaadt !isprint(*dp)) { 2979a2590e5Sderaadt if (dp + 1 != data + len || 2989a2590e5Sderaadt *dp != 0) { 2999a2590e5Sderaadt snprintf(op, opleft, 3009a2590e5Sderaadt "\\%03o", *dp); 3019a2590e5Sderaadt op += 4; 3029a2590e5Sderaadt opleft -= 4; 3039a2590e5Sderaadt } 3049a2590e5Sderaadt } else if (*dp == '"' || 3059a2590e5Sderaadt *dp == '\'' || 3069a2590e5Sderaadt *dp == '$' || 3079a2590e5Sderaadt *dp == '`' || 3089a2590e5Sderaadt *dp == '\\') { 3099a2590e5Sderaadt *op++ = '\\'; 3109a2590e5Sderaadt *op++ = *dp; 3119a2590e5Sderaadt opleft -= 2; 3129a2590e5Sderaadt } else { 3139a2590e5Sderaadt *op++ = *dp; 3149a2590e5Sderaadt opleft--; 3159a2590e5Sderaadt } 3169a2590e5Sderaadt } 3179a2590e5Sderaadt if (emit_quotes) { 3189a2590e5Sderaadt *op++ = '"'; 3199a2590e5Sderaadt opleft--; 3209a2590e5Sderaadt } 3219a2590e5Sderaadt 3229a2590e5Sderaadt *op = 0; 3239a2590e5Sderaadt break; 3249a2590e5Sderaadt case 'I': 3259a2590e5Sderaadt foo.s_addr = htonl(getULong(dp)); 326c714dadcShenning opcount = strlcpy(op, inet_ntoa(foo), opleft); 3279a2590e5Sderaadt if (opcount >= opleft) 3289a2590e5Sderaadt goto toobig; 3299a2590e5Sderaadt opleft -= opcount; 3309a2590e5Sderaadt dp += 4; 3319a2590e5Sderaadt break; 3329a2590e5Sderaadt case 'l': 3339a2590e5Sderaadt opcount = snprintf(op, opleft, "%ld", 3349a2590e5Sderaadt (long)getLong(dp)); 3356ed3db51Sderaadt if (opcount >= opleft || opcount == -1) 3369a2590e5Sderaadt goto toobig; 3379a2590e5Sderaadt opleft -= opcount; 3389a2590e5Sderaadt dp += 4; 3399a2590e5Sderaadt break; 3409a2590e5Sderaadt case 'L': 3419a2590e5Sderaadt opcount = snprintf(op, opleft, "%ld", 3429a2590e5Sderaadt (unsigned long)getULong(dp)); 3436ed3db51Sderaadt if (opcount >= opleft || opcount == -1) 3449a2590e5Sderaadt goto toobig; 3459a2590e5Sderaadt opleft -= opcount; 3469a2590e5Sderaadt dp += 4; 3479a2590e5Sderaadt break; 3489a2590e5Sderaadt case 's': 3499a2590e5Sderaadt opcount = snprintf(op, opleft, "%d", 3509a2590e5Sderaadt getShort(dp)); 3516ed3db51Sderaadt if (opcount >= opleft || opcount == -1) 3529a2590e5Sderaadt goto toobig; 3539a2590e5Sderaadt opleft -= opcount; 3549a2590e5Sderaadt dp += 2; 3559a2590e5Sderaadt break; 3569a2590e5Sderaadt case 'S': 3579a2590e5Sderaadt opcount = snprintf(op, opleft, "%d", 3589a2590e5Sderaadt getUShort(dp)); 3596ed3db51Sderaadt if (opcount >= opleft || opcount == -1) 3609a2590e5Sderaadt goto toobig; 3619a2590e5Sderaadt opleft -= opcount; 3629a2590e5Sderaadt dp += 2; 3639a2590e5Sderaadt break; 3649a2590e5Sderaadt case 'b': 3659a2590e5Sderaadt opcount = snprintf(op, opleft, "%d", 3669a2590e5Sderaadt *(char *)dp++); 3676ed3db51Sderaadt if (opcount >= opleft || opcount == -1) 3689a2590e5Sderaadt goto toobig; 3699a2590e5Sderaadt opleft -= opcount; 3709a2590e5Sderaadt break; 3719a2590e5Sderaadt case 'B': 3729a2590e5Sderaadt opcount = snprintf(op, opleft, "%d", *dp++); 3736ed3db51Sderaadt if (opcount >= opleft || opcount == -1) 3749a2590e5Sderaadt goto toobig; 3759a2590e5Sderaadt opleft -= opcount; 3769a2590e5Sderaadt break; 3779a2590e5Sderaadt case 'x': 3789a2590e5Sderaadt opcount = snprintf(op, opleft, "%x", *dp++); 3796ed3db51Sderaadt if (opcount >= opleft || opcount == -1) 3809a2590e5Sderaadt goto toobig; 3819a2590e5Sderaadt opleft -= opcount; 3829a2590e5Sderaadt break; 3839a2590e5Sderaadt case 'f': 3849a2590e5Sderaadt opcount = strlcpy(op, 3859a2590e5Sderaadt *dp++ ? "true" : "false", opleft); 3869a2590e5Sderaadt if (opcount >= opleft) 3879a2590e5Sderaadt goto toobig; 3889a2590e5Sderaadt opleft -= opcount; 3899a2590e5Sderaadt break; 3909a2590e5Sderaadt default: 391c955dd46Smickey warning("Unexpected format code %c", fmtbuf[j]); 3929a2590e5Sderaadt } 3939a2590e5Sderaadt op += strlen(op); 3949a2590e5Sderaadt opleft -= strlen(op); 3959a2590e5Sderaadt if (opleft < 1) 3969a2590e5Sderaadt goto toobig; 3979a2590e5Sderaadt if (j + 1 < numelem && comma != ':') { 3989a2590e5Sderaadt *op++ = ' '; 3999a2590e5Sderaadt opleft--; 4009a2590e5Sderaadt } 4019a2590e5Sderaadt } 4029a2590e5Sderaadt if (i + 1 < numhunk) { 4039a2590e5Sderaadt *op++ = comma; 4049a2590e5Sderaadt opleft--; 4059a2590e5Sderaadt } 4069a2590e5Sderaadt if (opleft < 1) 4079a2590e5Sderaadt goto toobig; 4089a2590e5Sderaadt 4099a2590e5Sderaadt } 410c714dadcShenning return (optbuf); 4119a2590e5Sderaadt toobig: 412c955dd46Smickey warning("dhcp option too large"); 413c714dadcShenning return ("<error>"); 4149a2590e5Sderaadt } 4159a2590e5Sderaadt 416c714dadcShenning void 417d5dec8a0Skrw do_packet(int len, unsigned int from_port, struct iaddr from, 418d5dec8a0Skrw struct hardware *hfrom) 4199a2590e5Sderaadt { 420*02e02bd5Skrw struct dhcp_packet *packet = &client->packet; 4214f062ee3Skrw struct option_data options[256]; 422*02e02bd5Skrw struct iaddrlist *ap; 423*02e02bd5Skrw void (*handler)(struct iaddr, struct option_data *); 424*02e02bd5Skrw char *type; 425*02e02bd5Skrw int i, options_valid = 1; 4269a2590e5Sderaadt 427*02e02bd5Skrw if (packet->hlen > sizeof(packet->chaddr)) { 4289a2590e5Sderaadt note("Discarding packet with invalid hlen."); 4299a2590e5Sderaadt return; 4309a2590e5Sderaadt } 4319a2590e5Sderaadt 432*02e02bd5Skrw /* 433*02e02bd5Skrw * Silently drop the packet if the client hardware address in the 434*02e02bd5Skrw * packet is not the hardware address of the interface being managed. 435*02e02bd5Skrw */ 436*02e02bd5Skrw if ((ifi->hw_address.hlen != packet->hlen) || 437*02e02bd5Skrw (memcmp(ifi->hw_address.haddr, packet->chaddr, packet->hlen))) 438*02e02bd5Skrw return; 4399a2590e5Sderaadt 440*02e02bd5Skrw memset(options, 0, sizeof(options)); 441*02e02bd5Skrw 442*02e02bd5Skrw if (memcmp(&packet->options, DHCP_OPTIONS_COOKIE, 4) == 0) { 443*02e02bd5Skrw /* Parse the BOOTP/DHCP options field. */ 444*02e02bd5Skrw options_valid = parse_option_buffer(options, 445*02e02bd5Skrw &packet->options[4], sizeof(packet->options) - 4); 446*02e02bd5Skrw 447*02e02bd5Skrw /* Only DHCP packets have overload areas for options. */ 448*02e02bd5Skrw if (options_valid && 449*02e02bd5Skrw options[DHO_DHCP_MESSAGE_TYPE].data && 450*02e02bd5Skrw options[DHO_DHCP_OPTION_OVERLOAD].data) { 451*02e02bd5Skrw if (options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 1) 452*02e02bd5Skrw options_valid = parse_option_buffer(options, 453*02e02bd5Skrw (unsigned char *)packet->file, 454*02e02bd5Skrw sizeof(packet->file)); 455*02e02bd5Skrw if (options_valid && 456*02e02bd5Skrw options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 2) 457*02e02bd5Skrw options_valid = parse_option_buffer(options, 458*02e02bd5Skrw (unsigned char *)packet->sname, 459*02e02bd5Skrw sizeof(packet->sname)); 460*02e02bd5Skrw } 461*02e02bd5Skrw } 462*02e02bd5Skrw 463*02e02bd5Skrw type = ""; 464*02e02bd5Skrw handler = NULL; 465*02e02bd5Skrw 4664f062ee3Skrw if (options[DHO_DHCP_MESSAGE_TYPE].data) { 467*02e02bd5Skrw /* Always try a DHCP packet, even if a bad option was seen. */ 468*02e02bd5Skrw switch (options[DHO_DHCP_MESSAGE_TYPE].data[0]) { 469*02e02bd5Skrw case DHCPOFFER: 470*02e02bd5Skrw handler = dhcpoffer; 471*02e02bd5Skrw type = "DHCPOFFER"; 472*02e02bd5Skrw break; 473*02e02bd5Skrw case DHCPNAK: 474*02e02bd5Skrw handler = dhcpnak; 475*02e02bd5Skrw type = "DHCPNACK"; 476*02e02bd5Skrw break; 477*02e02bd5Skrw case DHCPACK: 478*02e02bd5Skrw handler = dhcpack; 479*02e02bd5Skrw type = "DHCPACK"; 480*02e02bd5Skrw break; 481*02e02bd5Skrw default: 482*02e02bd5Skrw break; 483*02e02bd5Skrw } 484*02e02bd5Skrw } else if (options_valid && packet->op == BOOTREPLY) { 485*02e02bd5Skrw handler = dhcpoffer; 486*02e02bd5Skrw type = "BOOTREPLY"; 487*02e02bd5Skrw } 4889a2590e5Sderaadt 489*02e02bd5Skrw for (ap = config->reject_list; ap && handler; ap = ap->next) 490*02e02bd5Skrw if (addr_eq(from, ap->addr)) { 491*02e02bd5Skrw note("%s from %s rejected.", type, piaddr(from)); 492*02e02bd5Skrw handler = NULL; 493*02e02bd5Skrw } 494*02e02bd5Skrw 495*02e02bd5Skrw if (handler) 496*02e02bd5Skrw (*handler)(from, options); 497*02e02bd5Skrw 498c714dadcShenning for (i = 0; i < 256; i++) 4994f062ee3Skrw if (options[i].len && options[i].data) 5004f062ee3Skrw free(options[i].data); 5019a2590e5Sderaadt } 502