Untabify options.[ch].

This commit is contained in:
Nicholas J. Kain 2011-03-30 16:35:23 -04:00
parent 09613fd77a
commit 6265a0e973
2 changed files with 175 additions and 175 deletions

View File

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

View File

@ -1,5 +1,5 @@
/* options.h - DHCP options handling /* 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 <njkain at gmail dot com> * (c) 2004-2011 Nicholas J. Kain <njkain at gmail dot com>
* *
@ -70,14 +70,14 @@
#define DHCP_END 0xff #define DHCP_END 0xff
enum option_type { enum option_type {
OPTION_NONE = 0, OPTION_NONE = 0,
OPTION_IP = 1, OPTION_IP = 1,
OPTION_STRING = 2, OPTION_STRING = 2,
OPTION_U8 = 3, OPTION_U8 = 3,
OPTION_U16 = 4, OPTION_U16 = 4,
OPTION_S16 = 5, OPTION_S16 = 5,
OPTION_U32 = 6, OPTION_U32 = 6,
OPTION_S32 = 7 OPTION_S32 = 7
}; };
const char *option_name(uint8_t code); 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); int option_valid_list(uint8_t code);
size_t sizeof_option(uint8_t code, size_t datalen); 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 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_option(uint8_t code, uint8_t *optdata, size_t datalen);
uint8_t *alloc_dhcp_client_id_option(uint8_t type, uint8_t *idstr, 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); 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); 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_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, 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); void add_option_request_list(uint8_t *optbuf, size_t buflen);
#endif #endif