1*6fc9f4f6Skrw /* $OpenBSD: options.c,v 1.25 2005/08/22 20:30:52 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 479a2590e5Sderaadt int bad_options = 0; 489a2590e5Sderaadt int bad_options_max = 5; 499a2590e5Sderaadt 50fdcd93f4Shenning void parse_options(struct packet *); 51fdcd93f4Shenning void parse_option_buffer(struct packet *, unsigned char *, int); 52fdcd93f4Shenning 53c714dadcShenning /* 54c714dadcShenning * Parse all available options out of the specified packet. 55c714dadcShenning */ 56c714dadcShenning void 57c714dadcShenning parse_options(struct packet *packet) 589a2590e5Sderaadt { 599a2590e5Sderaadt /* Initially, zero all option pointers. */ 609a2590e5Sderaadt memset(packet->options, 0, sizeof(packet->options)); 619a2590e5Sderaadt 629a2590e5Sderaadt /* If we don't see the magic cookie, there's nothing to parse. */ 639a2590e5Sderaadt if (memcmp(packet->raw->options, DHCP_OPTIONS_COOKIE, 4)) { 649a2590e5Sderaadt packet->options_valid = 0; 659a2590e5Sderaadt return; 669a2590e5Sderaadt } 679a2590e5Sderaadt 68c714dadcShenning /* 69c714dadcShenning * Go through the options field, up to the end of the packet or 70c714dadcShenning * the End field. 71c714dadcShenning */ 729a2590e5Sderaadt parse_option_buffer(packet, &packet->raw->options[4], 739a2590e5Sderaadt packet->packet_length - DHCP_FIXED_NON_UDP - 4); 74d4ce89fdSderaadt 75c714dadcShenning /* 76c714dadcShenning * If we parsed a DHCP Option Overload option, parse more 77c714dadcShenning * options out of the buffer(s) containing them. 78c714dadcShenning */ 79c714dadcShenning if (packet->options_valid && 80c714dadcShenning packet->options[DHO_DHCP_OPTION_OVERLOAD].data) { 819a2590e5Sderaadt if (packet->options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 1) 829a2590e5Sderaadt parse_option_buffer(packet, 83c714dadcShenning (unsigned char *)packet->raw->file, 84c714dadcShenning sizeof(packet->raw->file)); 859a2590e5Sderaadt if (packet->options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 2) 869a2590e5Sderaadt parse_option_buffer(packet, 87c714dadcShenning (unsigned char *)packet->raw->sname, 88c714dadcShenning sizeof(packet->raw->sname)); 899a2590e5Sderaadt } 909a2590e5Sderaadt } 919a2590e5Sderaadt 92c714dadcShenning /* 93c714dadcShenning * Parse options out of the specified buffer, storing addresses of 94c714dadcShenning * option values in packet->options and setting packet->options_valid if 95c714dadcShenning * no errors are encountered. 96c714dadcShenning */ 97c714dadcShenning void 98c714dadcShenning parse_option_buffer(struct packet *packet, 99c714dadcShenning unsigned char *buffer, int length) 1009a2590e5Sderaadt { 101285f06efSderaadt unsigned char *s, *t, *end = buffer + length; 102285f06efSderaadt int len, code; 1039a2590e5Sderaadt 1049a2590e5Sderaadt for (s = buffer; *s != DHO_END && s < end; ) { 1059a2590e5Sderaadt code = s[0]; 1069a2590e5Sderaadt 1079a2590e5Sderaadt /* Pad options don't have a length - just skip them. */ 1089a2590e5Sderaadt if (code == DHO_PAD) { 109f1e89499Shenning s++; 1109a2590e5Sderaadt continue; 1119a2590e5Sderaadt } 1129a2590e5Sderaadt if (s + 2 > end) { 1139a2590e5Sderaadt len = 65536; 1149a2590e5Sderaadt goto bogus; 1159a2590e5Sderaadt } 1169a2590e5Sderaadt 117c714dadcShenning /* 118c714dadcShenning * All other fields (except end, see above) have a 119c714dadcShenning * one-byte length. 120c714dadcShenning */ 1219a2590e5Sderaadt len = s[1]; 1229a2590e5Sderaadt 123c714dadcShenning /* 124c714dadcShenning * If the length is outrageous, silently skip the rest, 125fd9f780dSdavid * and mark the packet bad. Unfortunately some crappy 126c714dadcShenning * dhcp servers always seem to give us garbage on the 127c714dadcShenning * end of a packet. so rather than keep refusing, give 128c714dadcShenning * up and try to take one after seeing a few without 129c714dadcShenning * anything good. 1309a2590e5Sderaadt */ 1319a2590e5Sderaadt if (s + len + 2 > end) { 1329a2590e5Sderaadt bogus: 1339a2590e5Sderaadt bad_options++; 134c955dd46Smickey warning("option %s (%d) %s.", 1359a2590e5Sderaadt dhcp_options[code].name, len, 1369a2590e5Sderaadt "larger than buffer"); 1379a2590e5Sderaadt if (bad_options == bad_options_max) { 1389a2590e5Sderaadt packet->options_valid = 1; 1399a2590e5Sderaadt bad_options = 0; 140c955dd46Smickey warning("Many bogus options seen in offers. " 141c955dd46Smickey "Taking this offer in spite of bogus " 142c955dd46Smickey "options - hope for the best!"); 1439a2590e5Sderaadt } else { 144c955dd46Smickey warning("rejecting bogus offer."); 1459a2590e5Sderaadt packet->options_valid = 0; 1469a2590e5Sderaadt } 1479a2590e5Sderaadt return; 1489a2590e5Sderaadt } 149c714dadcShenning /* 150c714dadcShenning * If we haven't seen this option before, just make 151c714dadcShenning * space for it and copy it there. 152c714dadcShenning */ 1539a2590e5Sderaadt if (!packet->options[code].data) { 1548e916ab9Shenning if (!(t = calloc(1, len + 1))) 1559a2590e5Sderaadt error("Can't allocate storage for option %s.", 1569a2590e5Sderaadt dhcp_options[code].name); 157c714dadcShenning /* 158c714dadcShenning * Copy and NUL-terminate the option (in case 159c714dadcShenning * it's an ASCII string. 160c714dadcShenning */ 1619a2590e5Sderaadt memcpy(t, &s[2], len); 1629a2590e5Sderaadt t[len] = 0; 1639a2590e5Sderaadt packet->options[code].len = len; 1649a2590e5Sderaadt packet->options[code].data = t; 1659a2590e5Sderaadt } else { 166c714dadcShenning /* 167c714dadcShenning * If it's a repeat, concatenate it to whatever 168c714dadcShenning * we last saw. This is really only required 169c714dadcShenning * for clients, but what the heck... 170c714dadcShenning */ 1718e916ab9Shenning t = calloc(1, len + packet->options[code].len + 1); 1729a2590e5Sderaadt if (!t) 1739a2590e5Sderaadt error("Can't expand storage for option %s.", 1749a2590e5Sderaadt dhcp_options[code].name); 1759a2590e5Sderaadt memcpy(t, packet->options[code].data, 1769a2590e5Sderaadt packet->options[code].len); 1779a2590e5Sderaadt memcpy(t + packet->options[code].len, 1789a2590e5Sderaadt &s[2], len); 1799a2590e5Sderaadt packet->options[code].len += len; 1809a2590e5Sderaadt t[packet->options[code].len] = 0; 1818e916ab9Shenning free(packet->options[code].data); 1829a2590e5Sderaadt packet->options[code].data = t; 1839a2590e5Sderaadt } 1849a2590e5Sderaadt s += len + 2; 1859a2590e5Sderaadt } 1869a2590e5Sderaadt packet->options_valid = 1; 1879a2590e5Sderaadt } 1889a2590e5Sderaadt 189c714dadcShenning /* 19096978980Skrw * Copy as many options as fit in buflen bytes of buf. Return the 19196978980Skrw * offset of the start of the last option copied. A caller can check 19296978980Skrw * to see if it's DHO_END to decide if all the options were copied. 193c714dadcShenning */ 194c714dadcShenning int 19596978980Skrw cons_options(unsigned char *buf, const int buflen, struct option_data *options) 1969a2590e5Sderaadt { 19796978980Skrw int ix, incr, length, bufix, code, lastopt = -1; 1989a2590e5Sderaadt 19996978980Skrw bzero(buf, buflen); 2009a2590e5Sderaadt 20196978980Skrw if (buflen > 3) 20296978980Skrw memcpy(buf, DHCP_OPTIONS_COOKIE, 4); 20396978980Skrw bufix = 4; 2049a2590e5Sderaadt 20596978980Skrw for (code = DHO_SUBNET_MASK; code < DHO_END; code++) { 206f5396ce2Skrw if (!options[code].data) 2079a2590e5Sderaadt continue; 2089a2590e5Sderaadt 209d7d9bbf5Skrw length = options[code].len; 21096978980Skrw if (bufix + length + 2*((length+254)/255) >= buflen) 21196978980Skrw return (lastopt); 2129a2590e5Sderaadt 21396978980Skrw lastopt = bufix; 2149a2590e5Sderaadt ix = 0; 2159a2590e5Sderaadt 2169a2590e5Sderaadt while (length) { 21796978980Skrw incr = length > 255 ? 255 : length; 2189a2590e5Sderaadt 21996978980Skrw buf[bufix++] = code; 22096978980Skrw buf[bufix++] = incr; 22196978980Skrw memcpy(buf + bufix, options[code].data + ix, incr); 2229a2590e5Sderaadt 2239a2590e5Sderaadt length -= incr; 2249a2590e5Sderaadt ix += incr; 225*6fc9f4f6Skrw bufix += incr; 2269a2590e5Sderaadt } 2279a2590e5Sderaadt } 22896978980Skrw 22996978980Skrw if (bufix < buflen) { 23096978980Skrw buf[bufix] = DHO_END; 23196978980Skrw lastopt = bufix; 23296978980Skrw } 23396978980Skrw 23496978980Skrw return (lastopt); 2359a2590e5Sderaadt } 2369a2590e5Sderaadt 237c714dadcShenning /* 238c714dadcShenning * Format the specified option so that a human can easily read it. 239c714dadcShenning */ 240c714dadcShenning char * 241c714dadcShenning pretty_print_option(unsigned int code, unsigned char *data, int len, 242c714dadcShenning int emit_commas, int emit_quotes) 2439a2590e5Sderaadt { 2449a2590e5Sderaadt static char optbuf[32768]; /* XXX */ 245285f06efSderaadt int hunksize = 0, numhunk = -1, numelem = 0; 246285f06efSderaadt char fmtbuf[32], *op = optbuf; 247285f06efSderaadt int i, j, k, opleft = sizeof(optbuf); 2489a2590e5Sderaadt unsigned char *dp = data; 2499a2590e5Sderaadt struct in_addr foo; 2509a2590e5Sderaadt char comma; 2519a2590e5Sderaadt 2529a2590e5Sderaadt /* Code should be between 0 and 255. */ 2539a2590e5Sderaadt if (code > 255) 2545eb2300aShenning error("pretty_print_option: bad code %d", code); 2559a2590e5Sderaadt 2569a2590e5Sderaadt if (emit_commas) 2579a2590e5Sderaadt comma = ','; 2589a2590e5Sderaadt else 2599a2590e5Sderaadt comma = ' '; 2609a2590e5Sderaadt 2619a2590e5Sderaadt /* Figure out the size of the data. */ 2629a2590e5Sderaadt for (i = 0; dhcp_options[code].format[i]; i++) { 2639a2590e5Sderaadt if (!numhunk) { 264c955dd46Smickey warning("%s: Excess information in format string: %s", 2659a2590e5Sderaadt dhcp_options[code].name, 2669a2590e5Sderaadt &(dhcp_options[code].format[i])); 2679a2590e5Sderaadt break; 2689a2590e5Sderaadt } 2699a2590e5Sderaadt numelem++; 2709a2590e5Sderaadt fmtbuf[i] = dhcp_options[code].format[i]; 2719a2590e5Sderaadt switch (dhcp_options[code].format[i]) { 2729a2590e5Sderaadt case 'A': 2739a2590e5Sderaadt --numelem; 2749a2590e5Sderaadt fmtbuf[i] = 0; 2759a2590e5Sderaadt numhunk = 0; 2769a2590e5Sderaadt break; 2779a2590e5Sderaadt case 'X': 278c714dadcShenning for (k = 0; k < len; k++) 2799a2590e5Sderaadt if (!isascii(data[k]) || 2809a2590e5Sderaadt !isprint(data[k])) 2819a2590e5Sderaadt break; 282b54c879eShenning if (k == len) { 2839a2590e5Sderaadt fmtbuf[i] = 't'; 2849a2590e5Sderaadt numhunk = -2; 2859a2590e5Sderaadt } else { 2869a2590e5Sderaadt fmtbuf[i] = 'x'; 2879a2590e5Sderaadt hunksize++; 2889a2590e5Sderaadt comma = ':'; 2899a2590e5Sderaadt numhunk = 0; 2909a2590e5Sderaadt } 2919a2590e5Sderaadt fmtbuf[i + 1] = 0; 2929a2590e5Sderaadt break; 2939a2590e5Sderaadt case 't': 2949a2590e5Sderaadt fmtbuf[i] = 't'; 2959a2590e5Sderaadt fmtbuf[i + 1] = 0; 2969a2590e5Sderaadt numhunk = -2; 2979a2590e5Sderaadt break; 2989a2590e5Sderaadt case 'I': 2999a2590e5Sderaadt case 'l': 3009a2590e5Sderaadt case 'L': 3019a2590e5Sderaadt hunksize += 4; 3029a2590e5Sderaadt break; 3039a2590e5Sderaadt case 's': 3049a2590e5Sderaadt case 'S': 3059a2590e5Sderaadt hunksize += 2; 3069a2590e5Sderaadt break; 3079a2590e5Sderaadt case 'b': 3089a2590e5Sderaadt case 'B': 3099a2590e5Sderaadt case 'f': 3109a2590e5Sderaadt hunksize++; 3119a2590e5Sderaadt break; 3129a2590e5Sderaadt case 'e': 3139a2590e5Sderaadt break; 3149a2590e5Sderaadt default: 315c955dd46Smickey warning("%s: garbage in format string: %s", 3169a2590e5Sderaadt dhcp_options[code].name, 3179a2590e5Sderaadt &(dhcp_options[code].format[i])); 3189a2590e5Sderaadt break; 3199a2590e5Sderaadt } 3209a2590e5Sderaadt } 3219a2590e5Sderaadt 3229a2590e5Sderaadt /* Check for too few bytes... */ 3239a2590e5Sderaadt if (hunksize > len) { 324c955dd46Smickey warning("%s: expecting at least %d bytes; got %d", 325c714dadcShenning dhcp_options[code].name, hunksize, len); 326c714dadcShenning return ("<error>"); 3279a2590e5Sderaadt } 3289a2590e5Sderaadt /* Check for too many bytes... */ 3299a2590e5Sderaadt if (numhunk == -1 && hunksize < len) 330c955dd46Smickey warning("%s: %d extra bytes", 331c714dadcShenning dhcp_options[code].name, len - hunksize); 3329a2590e5Sderaadt 3339a2590e5Sderaadt /* If this is an array, compute its size. */ 3349a2590e5Sderaadt if (!numhunk) 3359a2590e5Sderaadt numhunk = len / hunksize; 3369a2590e5Sderaadt /* See if we got an exact number of hunks. */ 3379a2590e5Sderaadt if (numhunk > 0 && numhunk * hunksize < len) 338c955dd46Smickey warning("%s: %d extra bytes at end of array", 339c714dadcShenning dhcp_options[code].name, len - numhunk * hunksize); 3409a2590e5Sderaadt 3419a2590e5Sderaadt /* A one-hunk array prints the same as a single hunk. */ 3429a2590e5Sderaadt if (numhunk < 0) 3439a2590e5Sderaadt numhunk = 1; 3449a2590e5Sderaadt 3459a2590e5Sderaadt /* Cycle through the array (or hunk) printing the data. */ 3469a2590e5Sderaadt for (i = 0; i < numhunk; i++) { 3479a2590e5Sderaadt for (j = 0; j < numelem; j++) { 3489a2590e5Sderaadt int opcount; 3499a2590e5Sderaadt switch (fmtbuf[j]) { 3509a2590e5Sderaadt case 't': 3519a2590e5Sderaadt if (emit_quotes) { 3529a2590e5Sderaadt *op++ = '"'; 3539a2590e5Sderaadt opleft--; 3549a2590e5Sderaadt } 3559a2590e5Sderaadt for (; dp < data + len; dp++) { 3569a2590e5Sderaadt if (!isascii(*dp) || 3579a2590e5Sderaadt !isprint(*dp)) { 3589a2590e5Sderaadt if (dp + 1 != data + len || 3599a2590e5Sderaadt *dp != 0) { 3609a2590e5Sderaadt snprintf(op, opleft, 3619a2590e5Sderaadt "\\%03o", *dp); 3629a2590e5Sderaadt op += 4; 3639a2590e5Sderaadt opleft -= 4; 3649a2590e5Sderaadt } 3659a2590e5Sderaadt } else if (*dp == '"' || 3669a2590e5Sderaadt *dp == '\'' || 3679a2590e5Sderaadt *dp == '$' || 3689a2590e5Sderaadt *dp == '`' || 3699a2590e5Sderaadt *dp == '\\') { 3709a2590e5Sderaadt *op++ = '\\'; 3719a2590e5Sderaadt *op++ = *dp; 3729a2590e5Sderaadt opleft -= 2; 3739a2590e5Sderaadt } else { 3749a2590e5Sderaadt *op++ = *dp; 3759a2590e5Sderaadt opleft--; 3769a2590e5Sderaadt } 3779a2590e5Sderaadt } 3789a2590e5Sderaadt if (emit_quotes) { 3799a2590e5Sderaadt *op++ = '"'; 3809a2590e5Sderaadt opleft--; 3819a2590e5Sderaadt } 3829a2590e5Sderaadt 3839a2590e5Sderaadt *op = 0; 3849a2590e5Sderaadt break; 3859a2590e5Sderaadt case 'I': 3869a2590e5Sderaadt foo.s_addr = htonl(getULong(dp)); 387c714dadcShenning opcount = strlcpy(op, inet_ntoa(foo), opleft); 3889a2590e5Sderaadt if (opcount >= opleft) 3899a2590e5Sderaadt goto toobig; 3909a2590e5Sderaadt opleft -= opcount; 3919a2590e5Sderaadt dp += 4; 3929a2590e5Sderaadt break; 3939a2590e5Sderaadt case 'l': 3949a2590e5Sderaadt opcount = snprintf(op, opleft, "%ld", 3959a2590e5Sderaadt (long)getLong(dp)); 3966ed3db51Sderaadt if (opcount >= opleft || opcount == -1) 3979a2590e5Sderaadt goto toobig; 3989a2590e5Sderaadt opleft -= opcount; 3999a2590e5Sderaadt dp += 4; 4009a2590e5Sderaadt break; 4019a2590e5Sderaadt case 'L': 4029a2590e5Sderaadt opcount = snprintf(op, opleft, "%ld", 4039a2590e5Sderaadt (unsigned long)getULong(dp)); 4046ed3db51Sderaadt if (opcount >= opleft || opcount == -1) 4059a2590e5Sderaadt goto toobig; 4069a2590e5Sderaadt opleft -= opcount; 4079a2590e5Sderaadt dp += 4; 4089a2590e5Sderaadt break; 4099a2590e5Sderaadt case 's': 4109a2590e5Sderaadt opcount = snprintf(op, opleft, "%d", 4119a2590e5Sderaadt getShort(dp)); 4126ed3db51Sderaadt if (opcount >= opleft || opcount == -1) 4139a2590e5Sderaadt goto toobig; 4149a2590e5Sderaadt opleft -= opcount; 4159a2590e5Sderaadt dp += 2; 4169a2590e5Sderaadt break; 4179a2590e5Sderaadt case 'S': 4189a2590e5Sderaadt opcount = snprintf(op, opleft, "%d", 4199a2590e5Sderaadt getUShort(dp)); 4206ed3db51Sderaadt if (opcount >= opleft || opcount == -1) 4219a2590e5Sderaadt goto toobig; 4229a2590e5Sderaadt opleft -= opcount; 4239a2590e5Sderaadt dp += 2; 4249a2590e5Sderaadt break; 4259a2590e5Sderaadt case 'b': 4269a2590e5Sderaadt opcount = snprintf(op, opleft, "%d", 4279a2590e5Sderaadt *(char *)dp++); 4286ed3db51Sderaadt if (opcount >= opleft || opcount == -1) 4299a2590e5Sderaadt goto toobig; 4309a2590e5Sderaadt opleft -= opcount; 4319a2590e5Sderaadt break; 4329a2590e5Sderaadt case 'B': 4339a2590e5Sderaadt opcount = snprintf(op, opleft, "%d", *dp++); 4346ed3db51Sderaadt if (opcount >= opleft || opcount == -1) 4359a2590e5Sderaadt goto toobig; 4369a2590e5Sderaadt opleft -= opcount; 4379a2590e5Sderaadt break; 4389a2590e5Sderaadt case 'x': 4399a2590e5Sderaadt opcount = snprintf(op, opleft, "%x", *dp++); 4406ed3db51Sderaadt if (opcount >= opleft || opcount == -1) 4419a2590e5Sderaadt goto toobig; 4429a2590e5Sderaadt opleft -= opcount; 4439a2590e5Sderaadt break; 4449a2590e5Sderaadt case 'f': 4459a2590e5Sderaadt opcount = strlcpy(op, 4469a2590e5Sderaadt *dp++ ? "true" : "false", opleft); 4479a2590e5Sderaadt if (opcount >= opleft) 4489a2590e5Sderaadt goto toobig; 4499a2590e5Sderaadt opleft -= opcount; 4509a2590e5Sderaadt break; 4519a2590e5Sderaadt default: 452c955dd46Smickey warning("Unexpected format code %c", fmtbuf[j]); 4539a2590e5Sderaadt } 4549a2590e5Sderaadt op += strlen(op); 4559a2590e5Sderaadt opleft -= strlen(op); 4569a2590e5Sderaadt if (opleft < 1) 4579a2590e5Sderaadt goto toobig; 4589a2590e5Sderaadt if (j + 1 < numelem && comma != ':') { 4599a2590e5Sderaadt *op++ = ' '; 4609a2590e5Sderaadt opleft--; 4619a2590e5Sderaadt } 4629a2590e5Sderaadt } 4639a2590e5Sderaadt if (i + 1 < numhunk) { 4649a2590e5Sderaadt *op++ = comma; 4659a2590e5Sderaadt opleft--; 4669a2590e5Sderaadt } 4679a2590e5Sderaadt if (opleft < 1) 4689a2590e5Sderaadt goto toobig; 4699a2590e5Sderaadt 4709a2590e5Sderaadt } 471c714dadcShenning return (optbuf); 4729a2590e5Sderaadt toobig: 473c955dd46Smickey warning("dhcp option too large"); 474c714dadcShenning return ("<error>"); 4759a2590e5Sderaadt } 4769a2590e5Sderaadt 477c714dadcShenning void 478c714dadcShenning do_packet(struct interface_info *interface, struct dhcp_packet *packet, 479c714dadcShenning int len, unsigned int from_port, struct iaddr from, struct hardware *hfrom) 4809a2590e5Sderaadt { 4819a2590e5Sderaadt struct packet tp; 4829a2590e5Sderaadt int i; 4839a2590e5Sderaadt 484c714dadcShenning if (packet->hlen > sizeof(packet->chaddr)) { 4859a2590e5Sderaadt note("Discarding packet with invalid hlen."); 4869a2590e5Sderaadt return; 4879a2590e5Sderaadt } 4889a2590e5Sderaadt 489c714dadcShenning memset(&tp, 0, sizeof(tp)); 4909a2590e5Sderaadt tp.raw = packet; 4919a2590e5Sderaadt tp.packet_length = len; 4929a2590e5Sderaadt tp.client_port = from_port; 4939a2590e5Sderaadt tp.client_addr = from; 4949a2590e5Sderaadt tp.interface = interface; 4959a2590e5Sderaadt tp.haddr = hfrom; 4969a2590e5Sderaadt 4979a2590e5Sderaadt parse_options(&tp); 4989a2590e5Sderaadt if (tp.options_valid && 4999a2590e5Sderaadt tp.options[DHO_DHCP_MESSAGE_TYPE].data) 500c714dadcShenning tp.packet_type = tp.options[DHO_DHCP_MESSAGE_TYPE].data[0]; 5019a2590e5Sderaadt if (tp.packet_type) 5029a2590e5Sderaadt dhcp(&tp); 5039a2590e5Sderaadt else 5049a2590e5Sderaadt bootp(&tp); 5059a2590e5Sderaadt 5069a2590e5Sderaadt /* Free the data associated with the options. */ 507c714dadcShenning for (i = 0; i < 256; i++) 5089a2590e5Sderaadt if (tp.options[i].len && tp.options[i].data) 5098e916ab9Shenning free(tp.options[i].data); 5109a2590e5Sderaadt } 511