From bd79c3d337304a96dcce4ae4f97b36143919af10 Mon Sep 17 00:00:00 2001 From: Denis Vlasenko Date: Wed, 1 Apr 2009 12:36:09 +0000 Subject: dhcpd: remember and record hostnames; optimize get_option dumpleases: show hostnames function old new delta add_lease 230 292 +62 send_offer 403 421 +18 send_ACK 232 249 +17 read_leases 249 258 +9 dumpleases_main 604 609 +5 nobody_responds_to_arp 84 86 +2 udhcp_end_option 32 30 -2 udhcp_get_option 222 171 -51 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 6/2 up/down: 113/-53) Total: 60 bytes --- networking/udhcp/options.c | 96 +++++++++++++++++++++++----------------------- 1 file changed, 49 insertions(+), 47 deletions(-) (limited to 'networking/udhcp/options.c') diff --git a/networking/udhcp/options.c b/networking/udhcp/options.c index 581a7b6..143a1fd 100644 --- a/networking/udhcp/options.c +++ b/networking/udhcp/options.c @@ -119,58 +119,61 @@ const uint8_t dhcp_option_lengths[] ALIGN1 = { }; -/* get an option with bounds checking (warning, not aligned). */ +/* get an option with bounds checking (warning, result is not aligned). */ uint8_t* FAST_FUNC get_option(struct dhcpMessage *packet, int code) { - int i, length; uint8_t *optionptr; - int over = 0; - int curr = OPTION_FIELD; - + int len; + int rem; + int overload = 0; + enum { + FILE_FIELD101 = FILE_FIELD * 0x101, + SNAME_FIELD101 = SNAME_FIELD * 0x101, + }; + + /* option bytes: [code][len][data1][data2]..[dataLEN] */ optionptr = packet->options; - i = 0; - length = sizeof(packet->options); + rem = sizeof(packet->options); while (1) { - if (i >= length) { - bb_error_msg("bogus packet, option fields too long"); + if (rem <= 0) { + bb_error_msg("bogus packet, malformed option field"); return NULL; } - if (optionptr[i + OPT_CODE] == code) { - if (i + 1 + optionptr[i + OPT_LEN] >= length) { - bb_error_msg("bogus packet, option fields too long"); - return NULL; - } - return optionptr + i + 2; + if (optionptr[OPT_CODE] == DHCP_PADDING) { + rem--; + optionptr++; + continue; } - switch (optionptr[i + OPT_CODE]) { - case DHCP_PADDING: - i++; - break; - case DHCP_OPTION_OVER: - if (i + 1 + optionptr[i + OPT_LEN] >= length) { - bb_error_msg("bogus packet, option fields too long"); - return NULL; - } - over = optionptr[i + 3]; - i += optionptr[OPT_LEN] + 2; - break; - case DHCP_END: - if (curr == OPTION_FIELD && (over & FILE_FIELD)) { + if (optionptr[OPT_CODE] == DHCP_END) { + if ((overload & FILE_FIELD101) == FILE_FIELD) { + /* can use packet->file, and didn't look at it yet */ + overload |= FILE_FIELD101; /* "we looked at it" */ optionptr = packet->file; - i = 0; - length = sizeof(packet->file); - curr = FILE_FIELD; - } else if (curr == FILE_FIELD && (over & SNAME_FIELD)) { + rem = sizeof(packet->file); + continue; + } + if ((overload & SNAME_FIELD101) == SNAME_FIELD) { + /* can use packet->sname, and didn't look at it yet */ + overload |= SNAME_FIELD101; /* "we looked at it" */ optionptr = packet->sname; - i = 0; - length = sizeof(packet->sname); - curr = SNAME_FIELD; - } else - return NULL; - break; - default: - i += optionptr[OPT_LEN + i] + 2; + rem = sizeof(packet->sname); + continue; + } + return NULL; + } + len = 2 + optionptr[OPT_LEN]; + rem -= len; + if (rem < 0) + continue; /* complain and return NULL */ + + if (optionptr[OPT_CODE] == code) + return optionptr + OPT_DATA; + + if (optionptr[OPT_CODE] == DHCP_OPTION_OVERLOAD) { + overload |= optionptr[OPT_DATA]; + /* fall through */ } + optionptr += len; } return NULL; } @@ -182,17 +185,16 @@ int FAST_FUNC end_option(uint8_t *optionptr) int i = 0; while (optionptr[i] != DHCP_END) { - if (optionptr[i] == DHCP_PADDING) - i++; - else - i += optionptr[i + OPT_LEN] + 2; + if (optionptr[i] != DHCP_PADDING) + i += optionptr[i + OPT_LEN] + 1; + i++; } return i; } -/* add an option string to the options (an option string contains an option code, - * length, then data) */ +/* add an option string to the options */ +/* option bytes: [code][len][data1][data2]..[dataLEN] */ int FAST_FUNC add_option_string(uint8_t *optionptr, uint8_t *string) { int end = end_option(optionptr); -- cgit v1.1