From a8f6b9998727ad67db4b812270a1bbceea011dde Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 26 Mar 2010 08:35:24 +0100 Subject: [PATCH] udhcp: move options.c to common.c; disable unused bool and s16 option code function old new delta udhcp_add_binary_option - 94 +94 udhcp_str2nip - 42 +42 len_of_option_as_string 12 10 -2 dhcp_option_lengths 12 10 -2 udhcpc_main 2859 2851 -8 read_nip 42 - -42 xmalloc_optname_optval 590 536 -54 udhcp_str2optset 443 366 -77 udhcp_add_option_string 86 - -86 ------------------------------------------------------------------------------ (add/remove: 2/2 grow/shrink: 0/5 up/down: 136/-271) Total: -135 bytes Signed-off-by: Denys Vlasenko --- networking/udhcp/Kbuild | 4 +- networking/udhcp/common.c | 454 ++++++++++++++++++++++++++++++++++++- networking/udhcp/common.h | 14 +- networking/udhcp/dhcpc.c | 33 +-- networking/udhcp/dhcpd.c | 2 +- networking/udhcp/dhcpd.h | 1 - networking/udhcp/files.c | 212 +---------------- networking/udhcp/options.c | 262 --------------------- 8 files changed, 485 insertions(+), 497 deletions(-) delete mode 100644 networking/udhcp/options.c diff --git a/networking/udhcp/Kbuild b/networking/udhcp/Kbuild index c09f9aaf0..1803903f0 100644 --- a/networking/udhcp/Kbuild +++ b/networking/udhcp/Kbuild @@ -7,8 +7,8 @@ lib-y:= -lib-$(CONFIG_UDHCPC) += common.o options.o packet.o signalpipe.o socket.o -lib-$(CONFIG_UDHCPD) += common.o options.o packet.o signalpipe.o socket.o +lib-$(CONFIG_UDHCPC) += common.o packet.o signalpipe.o socket.o +lib-$(CONFIG_UDHCPD) += common.o packet.o signalpipe.o socket.o lib-$(CONFIG_UDHCPC) += dhcpc.o lib-$(CONFIG_UDHCPD) += dhcpd.o arpping.o files.o leases.o static_leases.o diff --git a/networking/udhcp/common.c b/networking/udhcp/common.c index 4de29f258..bc458ac7a 100644 --- a/networking/udhcp/common.c +++ b/networking/udhcp/common.c @@ -1,7 +1,8 @@ /* vi: set sw=4 ts=4: */ -/* common.c +/* + * Rewrite by Russ Dill July 2001 * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this tarball for details. */ #include "common.h" @@ -12,3 +13,452 @@ unsigned dhcp_verbose; const uint8_t MAC_BCAST_ADDR[6] ALIGN2 = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + +/* Supported options are easily added here. + * See RFC2132 for more options. + * OPTION_REQ: these options are requested by udhcpc (unless -o). + */ +const struct dhcp_option dhcp_options[] = { + /* flags code */ + { OPTION_IP | OPTION_REQ, 0x01 }, /* DHCP_SUBNET */ + { OPTION_S32 , 0x02 }, /* DHCP_TIME_OFFSET */ + { OPTION_IP | OPTION_LIST | OPTION_REQ, 0x03 }, /* DHCP_ROUTER */ +// { OPTION_IP | OPTION_LIST , 0x04 }, /* DHCP_TIME_SERVER */ +// { OPTION_IP | OPTION_LIST , 0x05 }, /* DHCP_NAME_SERVER */ + { OPTION_IP | OPTION_LIST | OPTION_REQ, 0x06 }, /* DHCP_DNS_SERVER */ +// { OPTION_IP | OPTION_LIST , 0x07 }, /* DHCP_LOG_SERVER */ +// { OPTION_IP | OPTION_LIST , 0x08 }, /* DHCP_COOKIE_SERVER */ + { OPTION_IP | OPTION_LIST , 0x09 }, /* DHCP_LPR_SERVER */ + { OPTION_STRING | OPTION_REQ, 0x0c }, /* DHCP_HOST_NAME */ + { OPTION_U16 , 0x0d }, /* DHCP_BOOT_SIZE */ + { OPTION_STRING | OPTION_REQ, 0x0f }, /* DHCP_DOMAIN_NAME */ + { OPTION_IP , 0x10 }, /* DHCP_SWAP_SERVER */ + { OPTION_STRING , 0x11 }, /* DHCP_ROOT_PATH */ + { OPTION_U8 , 0x17 }, /* DHCP_IP_TTL */ + { OPTION_U16 , 0x1a }, /* DHCP_MTU */ + { OPTION_IP | OPTION_REQ, 0x1c }, /* DHCP_BROADCAST */ + { OPTION_STRING , 0x28 }, /* DHCP_NIS_DOMAIN */ + { OPTION_IP | OPTION_LIST , 0x29 }, /* DHCP_NIS_SERVER */ + { OPTION_IP | OPTION_LIST | OPTION_REQ, 0x2a }, /* DHCP_NTP_SERVER */ + { OPTION_IP | OPTION_LIST , 0x2c }, /* DHCP_WINS_SERVER */ + { OPTION_U32 , 0x33 }, /* DHCP_LEASE_TIME */ + { OPTION_IP , 0x36 }, /* DHCP_SERVER_ID */ + { OPTION_STRING , 0x38 }, /* DHCP_ERR_MESSAGE */ +//TODO: must be combined with 'sname' and 'file' handling: + { OPTION_STRING , 0x42 }, /* DHCP_TFTP_SERVER_NAME */ + { OPTION_STRING , 0x43 }, /* DHCP_BOOT_FILE */ +//TODO: not a string, but a set of LASCII strings: +// { OPTION_STRING , 0x4D }, /* DHCP_USER_CLASS */ +#if ENABLE_FEATURE_UDHCP_RFC3397 + { OPTION_STR1035 | OPTION_LIST , 0x77 }, /* DHCP_DOMAIN_SEARCH */ +#endif + { OPTION_STATIC_ROUTES , 0x79 }, /* DHCP_STATIC_ROUTES */ + { OPTION_STRING , 0xfc }, /* DHCP_WPAD */ + + /* Options below have no match in dhcp_option_strings[], + * are not passed to dhcpc scripts, and cannot be specified + * with "option XXX YYY" syntax in dhcpd config file. + * These entries are only used internally by udhcp[cd] + * to correctly encode options into packets. + */ + + { OPTION_IP , 0x32 }, /* DHCP_REQUESTED_IP */ + { OPTION_U8 , 0x35 }, /* DHCP_MESSAGE_TYPE */ + { OPTION_U16 , 0x39 }, /* DHCP_MAX_SIZE */ + { OPTION_STRING , 0x3c }, /* DHCP_VENDOR */ +//FIXME: handling of this option is not exactly correct: + { OPTION_STRING , 0x3d }, /* DHCP_CLIENT_ID */ + { 0, 0 } /* zeroed terminating entry */ +}; + +/* Used for converting options from incoming packets to env variables + * for udhcpc stript, and for setting options for udhcpd via + * "opt OPTION_NAME OPTION_VALUE" directives in udhcpd.conf file. + */ +/* Must match dhcp_options[] order */ +const char dhcp_option_strings[] ALIGN1 = + "subnet" "\0" /* DHCP_SUBNET */ + "timezone" "\0" /* DHCP_TIME_OFFSET */ + "router" "\0" /* DHCP_ROUTER */ +// "timesrv" "\0" /* DHCP_TIME_SERVER */ +// "namesrv" "\0" /* DHCP_NAME_SERVER */ + "dns" "\0" /* DHCP_DNS_SERVER */ +// "logsrv" "\0" /* DHCP_LOG_SERVER */ +// "cookiesrv" "\0" /* DHCP_COOKIE_SERVER */ + "lprsrv" "\0" /* DHCP_LPR_SERVER */ + "hostname" "\0" /* DHCP_HOST_NAME */ + "bootsize" "\0" /* DHCP_BOOT_SIZE */ + "domain" "\0" /* DHCP_DOMAIN_NAME */ + "swapsrv" "\0" /* DHCP_SWAP_SERVER */ + "rootpath" "\0" /* DHCP_ROOT_PATH */ + "ipttl" "\0" /* DHCP_IP_TTL */ + "mtu" "\0" /* DHCP_MTU */ + "broadcast" "\0" /* DHCP_BROADCAST */ + "nisdomain" "\0" /* DHCP_NIS_DOMAIN */ + "nissrv" "\0" /* DHCP_NIS_SERVER */ + "ntpsrv" "\0" /* DHCP_NTP_SERVER */ + "wins" "\0" /* DHCP_WINS_SERVER */ + "lease" "\0" /* DHCP_LEASE_TIME */ + "serverid" "\0" /* DHCP_SERVER_ID */ + "message" "\0" /* DHCP_ERR_MESSAGE */ + "tftp" "\0" /* DHCP_TFTP_SERVER_NAME */ + "bootfile" "\0" /* DHCP_BOOT_FILE */ +// "userclass" "\0" /* DHCP_USER_CLASS */ +#if ENABLE_FEATURE_UDHCP_RFC3397 + "search" "\0" /* DHCP_DOMAIN_SEARCH */ +#endif +// "staticroutes" is only used to set udhcpc environment, it doesn't work +// in udhcpd.conf since OPTION_STATIC_ROUTES is not handled yet +// by "string->option" conversion code: + "staticroutes" "\0"/* DHCP_STATIC_ROUTES */ + "wpad" "\0" /* DHCP_WPAD */ + ; + +/* Lengths of the different option types */ +const uint8_t dhcp_option_lengths[] ALIGN1 = { + [OPTION_IP] = 4, + [OPTION_IP_PAIR] = 8, +// [OPTION_BOOLEAN] = 1, + [OPTION_STRING] = 1, +#if ENABLE_FEATURE_UDHCP_RFC3397 + [OPTION_STR1035] = 1, +#endif + [OPTION_U8] = 1, + [OPTION_U16] = 2, +// [OPTION_S16] = 2, + [OPTION_U32] = 4, + [OPTION_S32] = 4, + /* Just like OPTION_STRING, we use minimum length here */ + [OPTION_STATIC_ROUTES] = 5, +}; + + +#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 2 +static void log_option(const char *pfx, const uint8_t *opt) +{ + if (dhcp_verbose >= 2) { + char buf[256 * 2 + 2]; + *bin2hex(buf, (void*) (opt + OPT_DATA), opt[OPT_LEN]) = '\0'; + bb_info_msg("%s: 0x%02x %s", pfx, opt[OPT_CODE], buf); + } +} +#else +# define log_option(pfx, opt) ((void)0) +#endif + +/* get an option with bounds checking (warning, result is not aligned). */ +uint8_t* FAST_FUNC udhcp_get_option(struct dhcp_packet *packet, int code) +{ + uint8_t *optionptr; + 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; + rem = sizeof(packet->options); + while (1) { + if (rem <= 0) { + bb_error_msg("bad packet, malformed option field"); + return NULL; + } + if (optionptr[OPT_CODE] == DHCP_PADDING) { + rem--; + optionptr++; + continue; + } + 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; + 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; + rem = sizeof(packet->sname); + continue; + } + break; + } + len = 2 + optionptr[OPT_LEN]; + rem -= len; + if (rem < 0) + continue; /* complain and return NULL */ + + if (optionptr[OPT_CODE] == code) { + log_option("Option found", optionptr); + return optionptr + OPT_DATA; + } + + if (optionptr[OPT_CODE] == DHCP_OPTION_OVERLOAD) { + overload |= optionptr[OPT_DATA]; + /* fall through */ + } + optionptr += len; + } + + /* log3 because udhcpc uses it a lot - very noisy */ + log3("Option 0x%02x not found", code); + return NULL; +} + +/* return the position of the 'end' option (no bounds checking) */ +int FAST_FUNC udhcp_end_option(uint8_t *optionptr) +{ + int i = 0; + + while (optionptr[i] != DHCP_END) { + if (optionptr[i] != DHCP_PADDING) + i += optionptr[i + OPT_LEN] + OPT_DATA-1; + i++; + } + return i; +} + +/* Add an option (supplied in binary form) to the options. + * Option format: [code][len][data1][data2]..[dataLEN] + */ +void FAST_FUNC udhcp_add_binary_option(uint8_t *optionptr, uint8_t *addopt) +{ + unsigned len; + unsigned end = udhcp_end_option(optionptr); + + /* end position + option code/length + addopt length + end option */ + len = OPT_DATA + addopt[OPT_LEN]; + if (end + len + 1 >= DHCP_OPTIONS_BUFSIZE) { + bb_error_msg("option 0x%02x did not fit into the packet", + addopt[OPT_CODE]); + return; + } + log_option("Adding option", addopt); + memcpy(optionptr + end, addopt, len); + optionptr[end + len] = DHCP_END; +} + +/* Add a one to four byte option to a packet */ +void FAST_FUNC udhcp_add_simple_option(uint8_t *optionptr, uint8_t code, uint32_t data) +{ + const struct dhcp_option *dh; + + for (dh = dhcp_options; dh->code; dh++) { + if (dh->code == code) { + uint8_t option[6], len; + + option[OPT_CODE] = code; + len = dhcp_option_lengths[dh->flags & OPTION_TYPE_MASK]; + option[OPT_LEN] = len; + if (BB_BIG_ENDIAN) + data <<= 8 * (4 - len); + /* Assignment is unaligned! */ + move_to_unaligned32(&option[OPT_DATA], data); + udhcp_add_binary_option(optionptr, option); + return; + } + } + + bb_error_msg("can't add option 0x%02x", code); +} + +/* Find option 'code' in opt_list */ +struct option_set* FAST_FUNC find_option(struct option_set *opt_list, uint8_t code) +{ + while (opt_list && opt_list->data[OPT_CODE] < code) + opt_list = opt_list->next; + + if (opt_list && opt_list->data[OPT_CODE] == code) + return opt_list; + return NULL; +} + +/* Parse string to IP in network order */ +int FAST_FUNC udhcp_str2nip(const char *str, void *arg) +{ + len_and_sockaddr *lsa; + + lsa = host_and_af2sockaddr(str, 0, AF_INET); + if (!lsa) + return 0; + *(uint32_t*)arg = lsa->u.sin.sin_addr.s_addr; + free(lsa); + return 1; +} + +/* udhcp_str2optset: + * Parse string option representation to binary form + * and add it to opt_list + */ +/* helper: add an option to the opt_list */ +static NOINLINE void attach_option( + struct option_set **opt_list, + const struct dhcp_option *option, + char *buffer, + int length) +{ + struct option_set *existing, *new, **curr; +#if ENABLE_FEATURE_UDHCP_RFC3397 + char *allocated = NULL; +#endif + + existing = find_option(*opt_list, option->code); + if (!existing) { + log2("Attaching option %02x to list", option->code); +#if ENABLE_FEATURE_UDHCP_RFC3397 + if ((option->flags & OPTION_TYPE_MASK) == OPTION_STR1035) { + /* reuse buffer and length for RFC1035-formatted string */ + allocated = buffer = (char *)dname_enc(NULL, 0, buffer, &length); + } +#endif + /* make a new option */ + new = xmalloc(sizeof(*new)); + new->data = xmalloc(length + OPT_DATA); + new->data[OPT_CODE] = option->code; + new->data[OPT_LEN] = length; + memcpy(new->data + OPT_DATA, buffer, length); + + curr = opt_list; + while (*curr && (*curr)->data[OPT_CODE] < option->code) + curr = &(*curr)->next; + + new->next = *curr; + *curr = new; + goto ret; + } + + if (option->flags & OPTION_LIST) { + unsigned old_len; + + /* add it to an existing option */ + log1("Attaching option %02x to existing member of list", option->code); + old_len = existing->data[OPT_LEN]; +#if ENABLE_FEATURE_UDHCP_RFC3397 + if ((option->flags & OPTION_TYPE_MASK) == OPTION_STR1035) { + /* reuse buffer and length for RFC1035-formatted string */ + allocated = buffer = (char *)dname_enc(existing->data + OPT_DATA, old_len, buffer, &length); + } +#endif + if (old_len + length < 255) { + /* actually 255 is ok too, but adding a space can overlow it */ + + existing->data = xrealloc(existing->data, OPT_DATA + 1 + old_len + length); + if ((option->flags & OPTION_TYPE_MASK) == OPTION_STRING) { + /* add space separator between STRING options in a list */ + existing->data[OPT_DATA + old_len] = ' '; + old_len++; + } + memcpy(existing->data + OPT_DATA + old_len, buffer, length); + existing->data[OPT_LEN] = old_len + length; + } /* else, ignore the data, we could put this in a second option in the future */ + } /* else, ignore the new data */ + + ret: ; +#if ENABLE_FEATURE_UDHCP_RFC3397 + free(allocated); +#endif +} + +int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg) +{ + struct option_set **opt_list = arg; + char *opt, *val, *endptr; + char *str; + const struct dhcp_option *option; + int retval, length, idx; + char buffer[8] ALIGNED(4); + uint16_t *result_u16 = (uint16_t *) buffer; + uint32_t *result_u32 = (uint32_t *) buffer; + + /* Cheat, the only *const* str possible is "" */ + str = (char *) const_str; + opt = strtok(str, " \t="); + if (!opt) + return 0; + + idx = index_in_strings(dhcp_option_strings, opt); /* NB: was strcasecmp! */ + if (idx < 0) + return 0; + option = &dhcp_options[idx]; + + retval = 0; + do { + val = strtok(NULL, ", \t"); + if (!val) + break; + length = dhcp_option_lengths[option->flags & OPTION_TYPE_MASK]; + retval = 0; + opt = buffer; /* new meaning for variable opt */ + switch (option->flags & OPTION_TYPE_MASK) { + case OPTION_IP: + retval = udhcp_str2nip(val, buffer); + break; + case OPTION_IP_PAIR: + retval = udhcp_str2nip(val, buffer); + val = strtok(NULL, ", \t/-"); + if (!val) + retval = 0; + if (retval) + retval = udhcp_str2nip(val, buffer + 4); + break; + case OPTION_STRING: +#if ENABLE_FEATURE_UDHCP_RFC3397 + case OPTION_STR1035: +#endif + length = strnlen(val, 254); + if (length > 0) { + opt = val; + retval = 1; + } + break; +// case OPTION_BOOLEAN: { +// static const char noyes[] ALIGN1 = "no\0yes\0"; +// buffer[0] = retval = index_in_strings(noyes, val); +// retval++; /* 0 - bad; 1: "no" 2: "yes" */ +// break; +// } + case OPTION_U8: + buffer[0] = strtoul(val, &endptr, 0); + retval = (endptr[0] == '\0'); + break; + /* htonX are macros in older libc's, using temp var + * in code below for safety */ + /* TODO: use bb_strtoX? */ + case OPTION_U16: { + unsigned long tmp = strtoul(val, &endptr, 0); + *result_u16 = htons(tmp); + retval = (endptr[0] == '\0' /*&& tmp < 0x10000*/); + break; + } +// case OPTION_S16: { +// long tmp = strtol(val, &endptr, 0); +// *result_u16 = htons(tmp); +// retval = (endptr[0] == '\0'); +// break; +// } + case OPTION_U32: { + unsigned long tmp = strtoul(val, &endptr, 0); + *result_u32 = htonl(tmp); + retval = (endptr[0] == '\0'); + break; + } + case OPTION_S32: { + long tmp = strtol(val, &endptr, 0); + *result_u32 = htonl(tmp); + retval = (endptr[0] == '\0'); + break; + } + default: + break; + } + if (retval) + attach_option(opt_list, option, opt, length); + } while (retval && option->flags & OPTION_LIST); + + return retval; +} diff --git a/networking/udhcp/common.h b/networking/udhcp/common.h index 9c3b4960b..cc0cab6e4 100644 --- a/networking/udhcp/common.h +++ b/networking/udhcp/common.h @@ -74,10 +74,10 @@ enum { #if ENABLE_FEATURE_UDHCP_RFC3397 OPTION_STR1035, /* RFC1035 compressed domain name list */ #endif - OPTION_BOOLEAN, +// OPTION_BOOLEAN, OPTION_U8, OPTION_U16, - OPTION_S16, +// OPTION_S16, OPTION_U32, OPTION_S32, OPTION_STATIC_ROUTES, @@ -172,14 +172,13 @@ extern const uint8_t dhcp_option_lengths[]; uint8_t *udhcp_get_option(struct dhcp_packet *packet, int code) FAST_FUNC; int udhcp_end_option(uint8_t *optionptr) FAST_FUNC; -void udhcp_add_option_string(uint8_t *optionptr, uint8_t *string) FAST_FUNC; +void udhcp_add_binary_option(uint8_t *optionptr, uint8_t *addopt) FAST_FUNC; void udhcp_add_simple_option(uint8_t *optionptr, uint8_t code, uint32_t data) FAST_FUNC; #if ENABLE_FEATURE_UDHCP_RFC3397 char *dname_dec(const uint8_t *cstr, int clen, const char *pre) FAST_FUNC; uint8_t *dname_enc(const uint8_t *cstr, int clen, const char *src, int *retlen) FAST_FUNC; #endif -/* 2nd param is actually "struct option_set**" */ -int FAST_FUNC udhcp_str2optset(const char *const_line, void *arg); +struct option_set *find_option(struct option_set *opt_list, uint8_t code) FAST_FUNC; // RFC 2131 Table 5: Fields and options used by DHCP clients @@ -255,6 +254,11 @@ void udhcp_dump_packet(struct dhcp_packet *packet) FAST_FUNC; /*** Other shared functions ***/ +/* 2nd param is "uint32_t*" */ +int FAST_FUNC udhcp_str2nip(const char *str, void *arg); +/* 2nd param is "struct option_set**" */ +int FAST_FUNC udhcp_str2optset(const char *str, void *arg); + uint16_t udhcp_checksum(void *addr, int count) FAST_FUNC; void udhcp_init_header(struct dhcp_packet *packet, char type) FAST_FUNC; diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c index 4565d7fd2..2c7608048 100644 --- a/networking/udhcp/dhcpc.c +++ b/networking/udhcp/dhcpc.c @@ -49,10 +49,10 @@ static const uint8_t len_of_option_as_string[] = { #if ENABLE_FEATURE_UDHCP_RFC3397 [OPTION_STR1035] = 1, #endif - [OPTION_BOOLEAN] = sizeof("yes "), +// [OPTION_BOOLEAN] = sizeof("yes "), [OPTION_U8] = sizeof("255 "), [OPTION_U16] = sizeof("65535 "), - [OPTION_S16] = sizeof("-32768 "), +// [OPTION_S16] = sizeof("-32768 "), [OPTION_U32] = sizeof("4294967295 "), [OPTION_S32] = sizeof("-2147483684 "), }; @@ -81,7 +81,6 @@ static NOINLINE char *xmalloc_optname_optval(uint8_t *option, const struct dhcp_ unsigned upper_length; int len, type, optlen; uint16_t val_u16; - int16_t val_s16; uint32_t val_u32; int32_t val_s32; char *dest, *ret; @@ -108,9 +107,9 @@ static NOINLINE char *xmalloc_optname_optval(uint8_t *option, const struct dhcp_ // Should we bail out/warn if we see multi-ip option which is // not allowed to be such? For example, DHCP_BROADCAST... break; - case OPTION_BOOLEAN: - dest += sprintf(dest, *option ? "yes" : "no"); - break; +// case OPTION_BOOLEAN: +// dest += sprintf(dest, *option ? "yes" : "no"); +// break; case OPTION_U8: dest += sprintf(dest, "%u", *option); break; @@ -118,10 +117,12 @@ static NOINLINE char *xmalloc_optname_optval(uint8_t *option, const struct dhcp_ move_from_unaligned16(val_u16, option); dest += sprintf(dest, "%u", ntohs(val_u16)); break; - case OPTION_S16: - move_from_unaligned16(val_s16, option); - dest += sprintf(dest, "%d", ntohs(val_s16)); - break; +// case OPTION_S16: { +// int16_t val_s16; +// move_from_unaligned16(val_s16, option); +// dest += sprintf(dest, "%d", ntohs(val_s16)); +// break; +// } case OPTION_U32: move_from_unaligned32(val_u32, option); dest += sprintf(dest, "%lu", (unsigned long) ntohl(val_u32)); @@ -318,23 +319,23 @@ static void init_packet(struct dhcp_packet *packet, char type) udhcp_init_header(packet, type); memcpy(packet->chaddr, client_config.client_mac, 6); if (client_config.clientid) - udhcp_add_option_string(packet->options, client_config.clientid); + udhcp_add_binary_option(packet->options, client_config.clientid); if (client_config.hostname) - udhcp_add_option_string(packet->options, client_config.hostname); + udhcp_add_binary_option(packet->options, client_config.hostname); if (client_config.fqdn) - udhcp_add_option_string(packet->options, client_config.fqdn); + udhcp_add_binary_option(packet->options, client_config.fqdn); if (type != DHCPDECLINE && type != DHCPRELEASE && client_config.vendorclass ) { - udhcp_add_option_string(packet->options, client_config.vendorclass); + udhcp_add_binary_option(packet->options, client_config.vendorclass); } } static void add_client_options(struct dhcp_packet *packet) { /* Add am "param req" option with the list of options we'd like to have - * from stubborn DHCP servers. Pull the data from the struct in options.c. + * from stubborn DHCP servers. Pull the data from the struct in common.c. * No bounds checking because it goes towards the head of the packet. */ uint8_t c; int end = udhcp_end_option(packet->options); @@ -360,7 +361,7 @@ static void add_client_options(struct dhcp_packet *packet) { struct option_set *curr = client_config.options; while (curr) { - udhcp_add_option_string(packet->options, curr->data); + udhcp_add_binary_option(packet->options, curr->data); curr = curr->next; } // if (client_config.sname) diff --git a/networking/udhcp/dhcpd.c b/networking/udhcp/dhcpd.c index 795ac4841..32f351f52 100644 --- a/networking/udhcp/dhcpd.c +++ b/networking/udhcp/dhcpd.c @@ -105,7 +105,7 @@ static void add_server_options(struct dhcp_packet *packet) while (curr) { if (curr->data[OPT_CODE] != DHCP_LEASE_TIME) - udhcp_add_option_string(packet->options, curr->data); + udhcp_add_binary_option(packet->options, curr->data); curr = curr->next; } diff --git a/networking/udhcp/dhcpd.h b/networking/udhcp/dhcpd.h index a4e9a58ff..f6187679d 100644 --- a/networking/udhcp/dhcpd.h +++ b/networking/udhcp/dhcpd.h @@ -123,7 +123,6 @@ void log_static_leases(struct static_lease **st_lease_pp) FAST_FUNC; void read_config(const char *file) FAST_FUNC; void write_leases(void) FAST_FUNC; void read_leases(const char *file) FAST_FUNC; -struct option_set *find_option(struct option_set *opt_list, uint8_t code) FAST_FUNC; POP_SAVED_FUNCTION_VISIBILITY diff --git a/networking/udhcp/files.c b/networking/udhcp/files.c index fddda4cba..1f25bb105 100644 --- a/networking/udhcp/files.c +++ b/networking/udhcp/files.c @@ -22,18 +22,6 @@ static inline uint64_t hton64(uint64_t v) #define ntoh64(v) hton64(v) /* on these functions, make sure your datatype matches */ -static int FAST_FUNC read_nip(const char *line, void *arg) -{ - len_and_sockaddr *lsa; - - lsa = host_and_af2sockaddr(line, 0, AF_INET); - if (!lsa) - return 0; - *(uint32_t*)arg = lsa->u.sin.sin_addr.s_addr; - free(lsa); - return 1; -} - static int FAST_FUNC read_str(const char *line, void *arg) { char **dest = arg; @@ -49,198 +37,6 @@ static int FAST_FUNC read_u32(const char *line, void *arg) return errno == 0; } -static int read_yn(const char *line, void *arg) -{ - char *dest = arg; - - if (strcasecmp("yes", line) == 0) { - *dest = 1; - return 1; - } - if (strcasecmp("no", line) == 0) { - *dest = 0; - return 1; - } - return 0; -} - -/* find option 'code' in opt_list */ -struct option_set* FAST_FUNC find_option(struct option_set *opt_list, uint8_t code) -{ - while (opt_list && opt_list->data[OPT_CODE] < code) - opt_list = opt_list->next; - - if (opt_list && opt_list->data[OPT_CODE] == code) - return opt_list; - return NULL; -} - -/* add an option to the opt_list */ -static NOINLINE void attach_option( - struct option_set **opt_list, - const struct dhcp_option *option, - char *buffer, - int length) -{ - struct option_set *existing, *new, **curr; -#if ENABLE_FEATURE_UDHCP_RFC3397 - char *allocated = NULL; -#endif - - existing = find_option(*opt_list, option->code); - if (!existing) { - log2("Attaching option %02x to list", option->code); -#if ENABLE_FEATURE_UDHCP_RFC3397 - if ((option->flags & OPTION_TYPE_MASK) == OPTION_STR1035) { - /* reuse buffer and length for RFC1035-formatted string */ - allocated = buffer = (char *)dname_enc(NULL, 0, buffer, &length); - } -#endif - /* make a new option */ - new = xmalloc(sizeof(*new)); - new->data = xmalloc(length + OPT_DATA); - new->data[OPT_CODE] = option->code; - new->data[OPT_LEN] = length; - memcpy(new->data + OPT_DATA, buffer, length); - - curr = opt_list; - while (*curr && (*curr)->data[OPT_CODE] < option->code) - curr = &(*curr)->next; - - new->next = *curr; - *curr = new; - goto ret; - } - - if (option->flags & OPTION_LIST) { - unsigned old_len; - - /* add it to an existing option */ - log1("Attaching option %02x to existing member of list", option->code); - old_len = existing->data[OPT_LEN]; -#if ENABLE_FEATURE_UDHCP_RFC3397 - if ((option->flags & OPTION_TYPE_MASK) == OPTION_STR1035) { - /* reuse buffer and length for RFC1035-formatted string */ - allocated = buffer = (char *)dname_enc(existing->data + OPT_DATA, old_len, buffer, &length); - } -#endif - if (old_len + length < 255) { - /* actually 255 is ok too, but adding a space can overlow it */ - - existing->data = xrealloc(existing->data, OPT_DATA + 1 + old_len + length); - if ((option->flags & OPTION_TYPE_MASK) == OPTION_STRING) { - /* add space separator between STRING options in a list */ - existing->data[OPT_DATA + old_len] = ' '; - old_len++; - } - memcpy(existing->data + OPT_DATA + old_len, buffer, length); - existing->data[OPT_LEN] = old_len + length; - } /* else, ignore the data, we could put this in a second option in the future */ - } /* else, ignore the new data */ - - ret: ; -#if ENABLE_FEATURE_UDHCP_RFC3397 - free(allocated); -#endif -} - -/* read a dhcp option and add it to opt_list */ -int FAST_FUNC udhcp_str2optset(const char *const_line, void *arg) -{ - struct option_set **opt_list = arg; - char *opt, *val, *endptr; - char *line; - const struct dhcp_option *option; - int retval, length, idx; - char buffer[8] ALIGNED(4); - uint16_t *result_u16 = (uint16_t *) buffer; - uint32_t *result_u32 = (uint32_t *) buffer; - - /* Cheat, the only *const* line possible is "" */ - line = (char *) const_line; - opt = strtok(line, " \t="); - if (!opt) - return 0; - - idx = index_in_strings(dhcp_option_strings, opt); /* NB: was strcasecmp! */ - if (idx < 0) - return 0; - option = &dhcp_options[idx]; - - retval = 0; - do { - val = strtok(NULL, ", \t"); - if (!val) - break; - length = dhcp_option_lengths[option->flags & OPTION_TYPE_MASK]; - retval = 0; - opt = buffer; /* new meaning for variable opt */ - switch (option->flags & OPTION_TYPE_MASK) { - case OPTION_IP: - retval = read_nip(val, buffer); - break; - case OPTION_IP_PAIR: - retval = read_nip(val, buffer); - val = strtok(NULL, ", \t/-"); - if (!val) - retval = 0; - if (retval) - retval = read_nip(val, buffer + 4); - break; - case OPTION_STRING: -#if ENABLE_FEATURE_UDHCP_RFC3397 - case OPTION_STR1035: -#endif - length = strnlen(val, 254); - if (length > 0) { - opt = val; - retval = 1; - } - break; - case OPTION_BOOLEAN: - retval = read_yn(val, buffer); - break; - case OPTION_U8: - buffer[0] = strtoul(val, &endptr, 0); - retval = (endptr[0] == '\0'); - break; - /* htonX are macros in older libc's, using temp var - * in code below for safety */ - /* TODO: use bb_strtoX? */ - case OPTION_U16: { - unsigned long tmp = strtoul(val, &endptr, 0); - *result_u16 = htons(tmp); - retval = (endptr[0] == '\0' /*&& tmp < 0x10000*/); - break; - } - case OPTION_S16: { - long tmp = strtol(val, &endptr, 0); - *result_u16 = htons(tmp); - retval = (endptr[0] == '\0'); - break; - } - case OPTION_U32: { - unsigned long tmp = strtoul(val, &endptr, 0); - *result_u32 = htonl(tmp); - retval = (endptr[0] == '\0'); - break; - } - case OPTION_S32: { - long tmp = strtol(val, &endptr, 0); - *result_u32 = htonl(tmp); - retval = (endptr[0] == '\0'); - break; - } - default: - break; - } - if (retval) - attach_option(opt_list, option, opt, length); - } while (retval && option->flags & OPTION_LIST); - - return retval; -} - static int FAST_FUNC read_staticlease(const char *const_line, void *arg) { char *line; @@ -257,7 +53,7 @@ static int FAST_FUNC read_staticlease(const char *const_line, void *arg) /* Read ip */ ip_string = strtok_r(NULL, " \t", &line); - if (!ip_string || !read_nip(ip_string, &nip)) + if (!ip_string || !udhcp_str2nip(ip_string, &nip)) return 0; add_static_lease(arg, (uint8_t*) &mac_bytes, nip); @@ -277,8 +73,8 @@ struct config_keyword { static const struct config_keyword keywords[] = { /* keyword handler variable address default */ - {"start", read_nip, &(server_config.start_ip), "192.168.0.20"}, - {"end", read_nip, &(server_config.end_ip), "192.168.0.254"}, + {"start", udhcp_str2nip, &(server_config.start_ip), "192.168.0.20"}, + {"end", udhcp_str2nip, &(server_config.end_ip), "192.168.0.254"}, {"interface", read_str, &(server_config.interface), "eth0"}, /* Avoid "max_leases value not sane" warning by setting default * to default_end_ip - default_start_ip + 1: */ @@ -290,7 +86,7 @@ static const struct config_keyword keywords[] = { {"min_lease", read_u32, &(server_config.min_lease_sec),"60"}, {"lease_file", read_str, &(server_config.lease_file), LEASES_FILE}, {"pidfile", read_str, &(server_config.pidfile), "/var/run/udhcpd.pid"}, - {"siaddr", read_nip, &(server_config.siaddr_nip), "0.0.0.0"}, + {"siaddr", udhcp_str2nip, &(server_config.siaddr_nip), "0.0.0.0"}, /* keywords with no defaults must be last! */ {"option", udhcp_str2optset, &(server_config.options), ""}, {"opt", udhcp_str2optset, &(server_config.options), ""}, diff --git a/networking/udhcp/options.c b/networking/udhcp/options.c deleted file mode 100644 index af3c217e8..000000000 --- a/networking/udhcp/options.c +++ /dev/null @@ -1,262 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * options.c -- DHCP server option packet tools - * Rewrite by Russ Dill July 2001 - * - * Licensed under GPLv2, see file LICENSE in this tarball for details. - */ - -#include "common.h" - - -/* Supported options are easily added here. - * See RFC2132 for more options. - * OPTION_REQ: these options are requested by udhcpc (unless -o). - */ -const struct dhcp_option dhcp_options[] = { - /* flags code */ - { OPTION_IP | OPTION_REQ, 0x01 }, /* DHCP_SUBNET */ - { OPTION_S32 , 0x02 }, /* DHCP_TIME_OFFSET */ - { OPTION_IP | OPTION_LIST | OPTION_REQ, 0x03 }, /* DHCP_ROUTER */ -// { OPTION_IP | OPTION_LIST , 0x04 }, /* DHCP_TIME_SERVER */ -// { OPTION_IP | OPTION_LIST , 0x05 }, /* DHCP_NAME_SERVER */ - { OPTION_IP | OPTION_LIST | OPTION_REQ, 0x06 }, /* DHCP_DNS_SERVER */ -// { OPTION_IP | OPTION_LIST , 0x07 }, /* DHCP_LOG_SERVER */ -// { OPTION_IP | OPTION_LIST , 0x08 }, /* DHCP_COOKIE_SERVER */ - { OPTION_IP | OPTION_LIST , 0x09 }, /* DHCP_LPR_SERVER */ - { OPTION_STRING | OPTION_REQ, 0x0c }, /* DHCP_HOST_NAME */ - { OPTION_U16 , 0x0d }, /* DHCP_BOOT_SIZE */ - { OPTION_STRING | OPTION_REQ, 0x0f }, /* DHCP_DOMAIN_NAME */ - { OPTION_IP , 0x10 }, /* DHCP_SWAP_SERVER */ - { OPTION_STRING , 0x11 }, /* DHCP_ROOT_PATH */ - { OPTION_U8 , 0x17 }, /* DHCP_IP_TTL */ - { OPTION_U16 , 0x1a }, /* DHCP_MTU */ - { OPTION_IP | OPTION_REQ, 0x1c }, /* DHCP_BROADCAST */ - { OPTION_STRING , 0x28 }, /* DHCP_NIS_DOMAIN */ - { OPTION_IP | OPTION_LIST , 0x29 }, /* DHCP_NIS_SERVER */ - { OPTION_IP | OPTION_LIST | OPTION_REQ, 0x2a }, /* DHCP_NTP_SERVER */ - { OPTION_IP | OPTION_LIST , 0x2c }, /* DHCP_WINS_SERVER */ - { OPTION_U32 , 0x33 }, /* DHCP_LEASE_TIME */ - { OPTION_IP , 0x36 }, /* DHCP_SERVER_ID */ - { OPTION_STRING , 0x38 }, /* DHCP_ERR_MESSAGE */ -//TODO: must be combined with 'sname' and 'file' handling: - { OPTION_STRING , 0x42 }, /* DHCP_TFTP_SERVER_NAME */ - { OPTION_STRING , 0x43 }, /* DHCP_BOOT_FILE */ -//TODO: not a string, but a set of LASCII strings: -// { OPTION_STRING , 0x4D }, /* DHCP_USER_CLASS */ -#if ENABLE_FEATURE_UDHCP_RFC3397 - { OPTION_STR1035 | OPTION_LIST , 0x77 }, /* DHCP_DOMAIN_SEARCH */ -#endif - { OPTION_STATIC_ROUTES , 0x79 }, /* DHCP_STATIC_ROUTES */ - { OPTION_STRING , 0xfc }, /* DHCP_WPAD */ - - /* Options below have no match in dhcp_option_strings[], - * are not passed to dhcpc scripts, and cannot be specified - * with "option XXX YYY" syntax in dhcpd config file. - * These entries are only used internally by udhcp[cd] - * to correctly encode options into packets. - */ - - { OPTION_IP , 0x32 }, /* DHCP_REQUESTED_IP */ - { OPTION_U8 , 0x35 }, /* DHCP_MESSAGE_TYPE */ - { OPTION_U16 , 0x39 }, /* DHCP_MAX_SIZE */ - { OPTION_STRING , 0x3c }, /* DHCP_VENDOR */ -//FIXME: handling of this option is not exactly correct: - { OPTION_STRING , 0x3d }, /* DHCP_CLIENT_ID */ - { 0, 0 } /* zeroed terminating entry */ -}; - -/* Used for converting options from incoming packets to env variables - * for udhcpc stript, and for setting options for udhcpd via - * "opt OPTION_NAME OPTION_VALUE" directives in udhcpd.conf file. - */ -/* Must match dhcp_options[] order */ -const char dhcp_option_strings[] ALIGN1 = - "subnet" "\0" /* DHCP_SUBNET */ - "timezone" "\0" /* DHCP_TIME_OFFSET */ - "router" "\0" /* DHCP_ROUTER */ -// "timesrv" "\0" /* DHCP_TIME_SERVER */ -// "namesrv" "\0" /* DHCP_NAME_SERVER */ - "dns" "\0" /* DHCP_DNS_SERVER */ -// "logsrv" "\0" /* DHCP_LOG_SERVER */ -// "cookiesrv" "\0" /* DHCP_COOKIE_SERVER */ - "lprsrv" "\0" /* DHCP_LPR_SERVER */ - "hostname" "\0" /* DHCP_HOST_NAME */ - "bootsize" "\0" /* DHCP_BOOT_SIZE */ - "domain" "\0" /* DHCP_DOMAIN_NAME */ - "swapsrv" "\0" /* DHCP_SWAP_SERVER */ - "rootpath" "\0" /* DHCP_ROOT_PATH */ - "ipttl" "\0" /* DHCP_IP_TTL */ - "mtu" "\0" /* DHCP_MTU */ - "broadcast" "\0" /* DHCP_BROADCAST */ - "nisdomain" "\0" /* DHCP_NIS_DOMAIN */ - "nissrv" "\0" /* DHCP_NIS_SERVER */ - "ntpsrv" "\0" /* DHCP_NTP_SERVER */ - "wins" "\0" /* DHCP_WINS_SERVER */ - "lease" "\0" /* DHCP_LEASE_TIME */ - "serverid" "\0" /* DHCP_SERVER_ID */ - "message" "\0" /* DHCP_ERR_MESSAGE */ - "tftp" "\0" /* DHCP_TFTP_SERVER_NAME */ - "bootfile" "\0" /* DHCP_BOOT_FILE */ -// "userclass" "\0" /* DHCP_USER_CLASS */ -#if ENABLE_FEATURE_UDHCP_RFC3397 - "search" "\0" /* DHCP_DOMAIN_SEARCH */ -#endif -// "staticroutes" is only used to set udhcpc environment, it doesn't work -// in udhcpd.conf since OPTION_STATIC_ROUTES is not handled yet -// by "string->option" conversion code: - "staticroutes" "\0"/* DHCP_STATIC_ROUTES */ - "wpad" "\0" /* DHCP_WPAD */ - ; - -/* Lengths of the different option types */ -const uint8_t dhcp_option_lengths[] ALIGN1 = { - [OPTION_IP] = 4, - [OPTION_IP_PAIR] = 8, - [OPTION_BOOLEAN] = 1, - [OPTION_STRING] = 1, -#if ENABLE_FEATURE_UDHCP_RFC3397 - [OPTION_STR1035] = 1, -#endif - [OPTION_U8] = 1, - [OPTION_U16] = 2, - [OPTION_S16] = 2, - [OPTION_U32] = 4, - [OPTION_S32] = 4, - /* Just like OPTION_STRING, we use minimum length here */ - [OPTION_STATIC_ROUTES] = 5, -}; - - -#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 2 -static void log_option(const char *pfx, const uint8_t *opt) -{ - if (dhcp_verbose >= 2) { - char buf[256 * 2 + 2]; - *bin2hex(buf, (void*) (opt + OPT_DATA), opt[OPT_LEN]) = '\0'; - bb_info_msg("%s: 0x%02x %s", pfx, opt[OPT_CODE], buf); - } -} -#else -# define log_option(pfx, opt) ((void)0) -#endif - -/* get an option with bounds checking (warning, result is not aligned). */ -uint8_t* FAST_FUNC udhcp_get_option(struct dhcp_packet *packet, int code) -{ - uint8_t *optionptr; - 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; - rem = sizeof(packet->options); - while (1) { - if (rem <= 0) { - bb_error_msg("bad packet, malformed option field"); - return NULL; - } - if (optionptr[OPT_CODE] == DHCP_PADDING) { - rem--; - optionptr++; - continue; - } - 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; - 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; - rem = sizeof(packet->sname); - continue; - } - break; - } - len = 2 + optionptr[OPT_LEN]; - rem -= len; - if (rem < 0) - continue; /* complain and return NULL */ - - if (optionptr[OPT_CODE] == code) { - log_option("Option found", optionptr); - return optionptr + OPT_DATA; - } - - if (optionptr[OPT_CODE] == DHCP_OPTION_OVERLOAD) { - overload |= optionptr[OPT_DATA]; - /* fall through */ - } - optionptr += len; - } - - /* log3 because udhcpc uses it a lot - very noisy */ - log3("Option 0x%02x not found", code); - return NULL; -} - -/* return the position of the 'end' option (no bounds checking) */ -int FAST_FUNC udhcp_end_option(uint8_t *optionptr) -{ - int i = 0; - - while (optionptr[i] != DHCP_END) { - if (optionptr[i] != DHCP_PADDING) - i += optionptr[i + OPT_LEN] + OPT_DATA-1; - i++; - } - return i; -} - -/* add an option string to the options */ -/* option bytes: [code][len][data1][data2]..[dataLEN] */ -void FAST_FUNC udhcp_add_option_string(uint8_t *optionptr, uint8_t *string) -{ - unsigned len; - unsigned end = udhcp_end_option(optionptr); - - /* end position + string length + option code/length + end option */ - if (end + string[OPT_LEN] + 2 + 1 >= DHCP_OPTIONS_BUFSIZE) { - bb_error_msg("option 0x%02x did not fit into the packet", - string[OPT_CODE]); - return; - } - log_option("Adding option", string); - len = OPT_DATA + string[OPT_LEN]; - memcpy(optionptr + end, string, len); - optionptr[end + len] = DHCP_END; -} - -/* add a one to four byte option to a packet */ -void FAST_FUNC udhcp_add_simple_option(uint8_t *optionptr, uint8_t code, uint32_t data) -{ - const struct dhcp_option *dh; - - for (dh = dhcp_options; dh->code; dh++) { - if (dh->code == code) { - uint8_t option[6], len; - - option[OPT_CODE] = code; - len = dhcp_option_lengths[dh->flags & OPTION_TYPE_MASK]; - option[OPT_LEN] = len; - if (BB_BIG_ENDIAN) - data <<= 8 * (4 - len); - /* Assignment is unaligned! */ - move_to_unaligned32(&option[OPT_DATA], data); - udhcp_add_option_string(optionptr, option); - return; - } - } - - bb_error_msg("can't add option 0x%02x", code); -} -- 2.25.1