diff --git a/ndhc/options.c b/ndhc/options.c index f3a929e..a517ee9 100644 --- a/ndhc/options.c +++ b/ndhc/options.c @@ -1,5 +1,5 @@ /* options.c - DHCP options handling - * Time-stamp: <2011-03-30 16:31:50 nk> + * Time-stamp: <2011-03-30 16:34:41 nk> * * (c) 2004-2011 Nicholas J. Kain * @@ -27,9 +27,9 @@ #include "malloc.h" struct dhcp_option { - char name[10]; - enum option_type type; - uint8_t code; + char name[10]; + enum option_type type; + uint8_t code; }; // Marks an option that will be sent on the parameter request list to the @@ -81,238 +81,238 @@ enum option_type option_type(uint8_t code) static const char bad_option_name[] = "BADOPTION"; const char *option_name(uint8_t code) { - int i; - for (i = 0; options[i].code; ++i) + int i; + for (i = 0; options[i].code; ++i) if (options[i].code == code) - return options[i].name; - return bad_option_name; + return options[i].name; + return bad_option_name; } static uint8_t option_type_length(enum option_type type) { - switch (type) { - case OPTION_IP: return 4; - case OPTION_U8: return 1; - case OPTION_U16: return 2; - case OPTION_S16: return 2; - case OPTION_U32: return 4; - case OPTION_S32: return 4; - default: return 0; - } + switch (type) { + case OPTION_IP: return 4; + case OPTION_U8: return 1; + case OPTION_U16: return 2; + case OPTION_S16: return 2; + case OPTION_U32: return 4; + case OPTION_S32: return 4; + default: return 0; + } } uint8_t option_length(uint8_t code) { - int i; - for (i = 0; options[i].code; i++) - if (options[i].code == code) - return option_type_length(options[i].type & 0xf); - log_warning("option_length: unknown length for code 0x%02x", code); - return 0; + int i; + for (i = 0; options[i].code; i++) + if (options[i].code == code) + return option_type_length(options[i].type & 0xf); + log_warning("option_length: unknown length for code 0x%02x", code); + return 0; } int option_valid_list(uint8_t code) { - int i; - for (i = 0; options[i].code; ++i) - if ((options[i].code == code) && (options[i].type & OPTION_LIST)) - return 1; - return 0; + int i; + for (i = 0; options[i].code; ++i) + if ((options[i].code == code) && (options[i].type & OPTION_LIST)) + return 1; + return 0; } size_t sizeof_option(uint8_t code, size_t datalen) { - if (code == DHCP_PADDING || code == DHCP_END) - return 1; - return 2 + datalen; + if (code == DHCP_PADDING || code == DHCP_END) + return 1; + return 2 + datalen; } // optdata can be NULL size_t set_option(uint8_t *buf, size_t buflen, uint8_t code, uint8_t *optdata, - size_t datalen) + size_t datalen) { - if (!optdata) - datalen = 0; - if (code == DHCP_PADDING || code == DHCP_END) { - if (buflen < 1) - return 0; - buf[0] = code; - return 1; - } + if (!optdata) + datalen = 0; + if (code == DHCP_PADDING || code == DHCP_END) { + if (buflen < 1) + return 0; + buf[0] = code; + return 1; + } - if (datalen > 255 || buflen < 2 + datalen) - return 0; - buf[0] = code; - buf[1] = datalen; - memcpy(buf + 2, optdata, datalen); - return 2 + datalen; + if (datalen > 255 || buflen < 2 + datalen) + return 0; + buf[0] = code; + buf[1] = datalen; + memcpy(buf + 2, optdata, datalen); + return 2 + datalen; } uint8_t *alloc_option(uint8_t code, uint8_t *optdata, size_t datalen) { - uint8_t *ret; - size_t len = sizeof_option(code, datalen); - ret = xmalloc(len); - set_option(ret, len, code, optdata, datalen); - return ret; + uint8_t *ret; + size_t len = sizeof_option(code, datalen); + ret = xmalloc(len); + set_option(ret, len, code, optdata, datalen); + return ret; } // This is tricky -- the data must be prefixed by one byte indicating the // type of ARP MAC address (1 for ethernet) or 0 for a purely symbolic // identifier. uint8_t *alloc_dhcp_client_id_option(uint8_t type, uint8_t *idstr, - size_t idstrlen) + size_t idstrlen) { - uint8_t data[idstrlen + 1]; - data[0] = type; - memcpy(data + 1, idstr, idstrlen); - return alloc_option(DHCP_CLIENT_ID, data, sizeof data); + uint8_t data[idstrlen + 1]; + data[0] = type; + memcpy(data + 1, idstr, idstrlen); + return alloc_option(DHCP_CLIENT_ID, data, sizeof data); } // Worker function for get_option_data(). Optlen will be set to the length // of the option data. static uint8_t *do_get_option_data(uint8_t *buf, ssize_t buflen, int code, - char *overload, ssize_t *optlen) + char *overload, ssize_t *optlen) { - /* option bytes: [code][len]([data1][data2]..[dataLEN]) */ - *overload = 0; - while (buflen > 0) { - // Advance over padding. - if (buf[0] == DHCP_PADDING) { - buflen--; - buf++; - continue; - } + /* option bytes: [code][len]([data1][data2]..[dataLEN]) */ + *overload = 0; + while (buflen > 0) { + // Advance over padding. + if (buf[0] == DHCP_PADDING) { + buflen--; + buf++; + continue; + } - // We hit the end. - if (buf[0] == DHCP_END) { - *optlen = 0; - return NULL; - } + // We hit the end. + if (buf[0] == DHCP_END) { + *optlen = 0; + return NULL; + } - buflen -= buf[1] + 2; - if (buflen < 0) { - log_warning("Bad dhcp data: option length would exceed options field length"); - *optlen = 0; - return NULL; - } + buflen -= buf[1] + 2; + if (buflen < 0) { + log_warning("Bad dhcp data: option length would exceed options field length"); + *optlen = 0; + return NULL; + } - if (buf[0] == code) { - *optlen = buf[1]; - return buf + 2; - } + if (buf[0] == code) { + *optlen = buf[1]; + return buf + 2; + } - if (buf[0] == DHCP_OPTION_OVERLOAD) { - if (buf[1] == 1) - *overload |= buf[2]; - /* fall through */ - } - buf += buf[1] + 2; - } - log_warning("Bad dhcp data: unmarked end of options field"); - *optlen = 0; - return NULL; + if (buf[0] == DHCP_OPTION_OVERLOAD) { + if (buf[1] == 1) + *overload |= buf[2]; + /* fall through */ + } + buf += buf[1] + 2; + } + log_warning("Bad dhcp data: unmarked end of options field"); + *optlen = 0; + return NULL; } // Get an option with bounds checking (warning, result is not aligned) // optlen will be equal to the length of the option data. uint8_t *get_option_data(struct dhcpMessage *packet, int code, ssize_t *optlen) { - uint8_t *option, *buf; - ssize_t buflen; - char overload, parsed_ff = 0; + uint8_t *option, *buf; + ssize_t buflen; + char overload, parsed_ff = 0; - buf = packet->options; - buflen = sizeof packet->options; + buf = packet->options; + buflen = sizeof packet->options; - option = do_get_option_data(buf, buflen, code, &overload, optlen); - if (option) - return option; + option = do_get_option_data(buf, buflen, code, &overload, optlen); + if (option) + return option; - if (overload & 1) { - parsed_ff = 1; - option = do_get_option_data(packet->file, sizeof packet->file, - code, &overload, optlen); - if (option) - return option; - } - if (overload & 2) { - option = do_get_option_data(packet->sname, sizeof packet->sname, - code, &overload, optlen); - if (option) - return option; - if (!parsed_ff && overload & 1) - option = do_get_option_data(packet->file, sizeof packet->file, - code, &overload, optlen); - } - return option; + if (overload & 1) { + parsed_ff = 1; + option = do_get_option_data(packet->file, sizeof packet->file, + code, &overload, optlen); + if (option) + return option; + } + if (overload & 2) { + option = do_get_option_data(packet->sname, sizeof packet->sname, + code, &overload, optlen); + if (option) + return option; + if (!parsed_ff && overload & 1) + option = do_get_option_data(packet->file, sizeof packet->file, + code, &overload, optlen); + } + return option; } /* return the position of the 'end' option */ ssize_t get_end_option_idx(uint8_t *optbuf, size_t bufsize) { - int i; - for (i = 0; i < bufsize; ++i) { - if (optbuf[i] == DHCP_END) - return i; - if (optbuf[i] == DHCP_PADDING) - continue; - if (optbuf[i] != DHCP_PADDING) - i += optbuf[i+1] + 1; - } - log_warning("get_end_option_idx(): did not find DHCP_END marker"); - return -1; + int i; + for (i = 0; i < bufsize; ++i) { + if (optbuf[i] == DHCP_END) + return i; + if (optbuf[i] == DHCP_PADDING) + continue; + if (optbuf[i] != DHCP_PADDING) + i += optbuf[i+1] + 1; + } + log_warning("get_end_option_idx(): did not find DHCP_END marker"); + return -1; } /* add an option string to the options (an option string contains an option * code, length, then data) */ size_t add_option_string(uint8_t *optbuf, size_t buflen, uint8_t *optstr) { - size_t end = get_end_option_idx(optbuf, buflen); - size_t datalen = optstr[1]; + size_t end = get_end_option_idx(optbuf, buflen); + size_t datalen = optstr[1]; - if (end == -1) { - log_warning("add_option_string: Buffer has no DHCP_END marker"); - return 0; - } - /* end position + optstr length + option code/length + end option */ - if (end + datalen + 2 + 1 >= buflen) { - log_warning("Option 0x%02x did not fit into the packet!", optstr[0]); - return 0; - } - memcpy(optbuf + end, optstr, datalen + 2); - optbuf[end + datalen + 2] = DHCP_END; - return datalen + 2; + if (end == -1) { + log_warning("add_option_string: Buffer has no DHCP_END marker"); + return 0; + } + /* end position + optstr length + option code/length + end option */ + if (end + datalen + 2 + 1 >= buflen) { + log_warning("Option 0x%02x did not fit into the packet!", optstr[0]); + return 0; + } + memcpy(optbuf + end, optstr, datalen + 2); + optbuf[end + datalen + 2] = DHCP_END; + return datalen + 2; } size_t add_u32_option(uint8_t *optbuf, size_t buflen, uint8_t code, - uint32_t data) + uint32_t data) { - int length = 0; - uint8_t option[6]; + int length = 0; + uint8_t option[6]; - length = option_length(code); + length = option_length(code); - log_line("add_u32_option: code=0x%02x length=0x%02x", code, length); - option[0] = code; - option[1] = length; + log_line("add_u32_option: code=0x%02x length=0x%02x", code, length); + option[0] = code; + option[1] = length; - if (!length) { - log_warning("add_u32_option: option code 0x%02x has 0 length", code); - return 0; - } + if (!length) { + log_warning("add_u32_option: option code 0x%02x has 0 length", code); + return 0; + } - if (length == 1) { - uint8_t t = (uint8_t)data; - memcpy(option + 2, &t, 1); - } else if (length == 2) { - uint16_t t = (uint16_t)data; - memcpy(option + 2, &t, 2); - } else if (length == 4) { - uint32_t t = (uint32_t)data; - memcpy(option + 2, &t, 4); - } - return add_option_string(optbuf, buflen, option); + if (length == 1) { + uint8_t t = (uint8_t)data; + memcpy(option + 2, &t, 1); + } else if (length == 2) { + uint16_t t = (uint16_t)data; + memcpy(option + 2, &t, 2); + } else if (length == 4) { + uint32_t t = (uint32_t)data; + memcpy(option + 2, &t, 4); + } + return add_option_string(optbuf, buflen, option); } /* Add a paramater request list for stubborn DHCP servers */ diff --git a/ndhc/options.h b/ndhc/options.h index 7f5d77d..8e5c557 100644 --- a/ndhc/options.h +++ b/ndhc/options.h @@ -1,5 +1,5 @@ /* options.h - DHCP options handling - * Time-stamp: <2011-03-30 16:07:24 nk> + * Time-stamp: <2011-03-30 16:34:55 nk> * * (c) 2004-2011 Nicholas J. Kain * @@ -70,14 +70,14 @@ #define DHCP_END 0xff enum option_type { - OPTION_NONE = 0, - OPTION_IP = 1, - OPTION_STRING = 2, - OPTION_U8 = 3, - OPTION_U16 = 4, - OPTION_S16 = 5, - OPTION_U32 = 6, - OPTION_S32 = 7 + OPTION_NONE = 0, + OPTION_IP = 1, + OPTION_STRING = 2, + OPTION_U8 = 3, + OPTION_U16 = 4, + OPTION_S16 = 5, + OPTION_U32 = 6, + OPTION_S32 = 7 }; const char *option_name(uint8_t code); @@ -86,17 +86,17 @@ uint8_t option_length(uint8_t code); int option_valid_list(uint8_t code); size_t sizeof_option(uint8_t code, size_t datalen); size_t set_option(uint8_t *buf, size_t buflen, uint8_t code, uint8_t *optdata, - size_t datalen); + size_t datalen); uint8_t *alloc_option(uint8_t code, uint8_t *optdata, size_t datalen); uint8_t *alloc_dhcp_client_id_option(uint8_t type, uint8_t *idstr, - size_t idstrlen); + size_t idstrlen); uint8_t *get_option_data(struct dhcpMessage *packet, int code, ssize_t *optlen); ssize_t get_end_option_idx(uint8_t *optbuf, size_t bufsize); size_t add_option_string(uint8_t *optbuf, size_t buflen, uint8_t *optstr); size_t add_u32_option(uint8_t *optbuf, size_t buflen, uint8_t code, - uint32_t data); + uint32_t data); void add_option_request_list(uint8_t *optbuf, size_t buflen); #endif