udhcp: move options.c to common.c; disable unused bool and s16 option code
No binary (build failed)
—
(log yok)
| @@ -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 | |
| @@ -1,7 +1,8 @@ | |
| /* vi: set sw=4 ts=4: */ | |
| - | /* common.c |
| + | /* |
| + | * Rewrite by Russ Dill <[email protected]> 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; |
| + | } |
| @@ -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; | |
| @@ -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) | |
| @@ -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; | |
| } | |
| @@ -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 | |
| @@ -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), ""}, | |
| @@ -1,262 +0,0 @@ | |
| - | /* vi: set sw=4 ts=4: */ |
| - | /* |
| - | * options.c -- DHCP server option packet tools |
| - | * Rewrite by Russ Dill <[email protected]> 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); |
| - | } |