udhcp: implement "raw" binary options. Closes bug 735

function                                             old     new   delta
allocate_tempopt_if_needed                             -      76     +76
udhcp_str2optset                                     351     415     +64
attach_option                                        380     398     +18
len_of_option_as_string                               11      12      +1
dhcp_option_lengths                                   11      12      +1
------------------------------------------------------------------------------
(add/remove: 1/0 grow/shrink: 4/0 up/down: 160/0)             Total: 160 bytes

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
Denys Vlasenko 2010-04-04 15:31:12 +02:00
parent 4836331924
commit 4f3aa51f9d
2 changed files with 43 additions and 13 deletions

View File

@ -324,9 +324,27 @@ int FAST_FUNC udhcp_str2nip(const char *str, void *arg)
} }
/* udhcp_str2optset: /* udhcp_str2optset:
* Parse string option representation to binary form * Parse string option representation to binary form and add it to opt_list.
* and add it to opt_list * Called to parse "udhcpc -x OPTNAME:OPTVAL"
* and to parse udhcpd.conf's "opt OPTNAME OPTVAL" directives.
*/ */
/* helper for the helper */
static char *allocate_tempopt_if_needed(
const struct dhcp_optflag *optflag,
char *buffer,
int *length_p)
{
char *allocated = NULL;
if ((optflag->flags & OPTION_TYPE_MASK) == OPTION_BIN) {
const char *end;
allocated = xstrdup(buffer); /* more than enough */
end = hex2bin(allocated, buffer, 255);
if (errno)
bb_error_msg_and_die("malformed hex string '%s'", buffer);
*length_p = end - allocated;
}
return allocated;
}
/* helper: add an option to the opt_list */ /* helper: add an option to the opt_list */
static NOINLINE void attach_option( static NOINLINE void attach_option(
struct option_set **opt_list, struct option_set **opt_list,
@ -335,13 +353,12 @@ static NOINLINE void attach_option(
int length) int length)
{ {
struct option_set *existing, *new, **curr; struct option_set *existing, *new, **curr;
#if ENABLE_FEATURE_UDHCP_RFC3397
char *allocated = NULL; char *allocated = NULL;
#endif
existing = udhcp_find_option(*opt_list, optflag->code); existing = udhcp_find_option(*opt_list, optflag->code);
if (!existing) { if (!existing) {
log2("Attaching option %02x to list", optflag->code); log2("Attaching option %02x to list", optflag->code);
allocated = allocate_tempopt_if_needed(optflag, buffer, &length);
#if ENABLE_FEATURE_UDHCP_RFC3397 #if ENABLE_FEATURE_UDHCP_RFC3397
if ((optflag->flags & OPTION_TYPE_MASK) == OPTION_DNS_STRING) { if ((optflag->flags & OPTION_TYPE_MASK) == OPTION_DNS_STRING) {
/* reuse buffer and length for RFC1035-formatted string */ /* reuse buffer and length for RFC1035-formatted string */
@ -368,7 +385,8 @@ static NOINLINE void attach_option(
unsigned old_len; unsigned old_len;
/* add it to an existing option */ /* add it to an existing option */
log1("Attaching option %02x to existing member of list", optflag->code); log2("Attaching option %02x to existing member of list", optflag->code);
allocated = allocate_tempopt_if_needed(optflag, buffer, &length);
old_len = existing->data[OPT_LEN]; old_len = existing->data[OPT_LEN];
#if ENABLE_FEATURE_UDHCP_RFC3397 #if ENABLE_FEATURE_UDHCP_RFC3397
if ((optflag->flags & OPTION_TYPE_MASK) == OPTION_DNS_STRING) { if ((optflag->flags & OPTION_TYPE_MASK) == OPTION_DNS_STRING) {
@ -390,10 +408,8 @@ static NOINLINE void attach_option(
} /* else, ignore the data, we could put this in a second option in the future */ } /* else, ignore the data, we could put this in a second option in the future */
} /* else, ignore the new data */ } /* else, ignore the new data */
ret: ; ret:
#if ENABLE_FEATURE_UDHCP_RFC3397
free(allocated); free(allocated);
#endif
} }
int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg) int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg)
@ -402,6 +418,8 @@ int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg)
char *opt, *val, *endptr; char *opt, *val, *endptr;
char *str; char *str;
const struct dhcp_optflag *optflag; const struct dhcp_optflag *optflag;
struct dhcp_optflag bin_optflag;
unsigned optcode;
int retval, length; int retval, length;
char buffer[8] ALIGNED(4); char buffer[8] ALIGNED(4);
uint16_t *result_u16 = (uint16_t *) buffer; uint16_t *result_u16 = (uint16_t *) buffer;
@ -413,7 +431,15 @@ int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg)
if (!opt) if (!opt)
return 0; return 0;
optflag = &dhcp_optflags[udhcp_option_idx(opt)]; optcode = bb_strtou(opt, NULL, 0);
if (!errno && optcode < 255) {
/* Raw (numeric) option code */
bin_optflag.flags = OPTION_BIN;
bin_optflag.code = optcode;
optflag = &bin_optflag;
} else {
optflag = &dhcp_optflags[udhcp_option_idx(opt)];
}
retval = 0; retval = 0;
do { do {
@ -482,6 +508,9 @@ int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg)
retval = (endptr[0] == '\0'); retval = (endptr[0] == '\0');
break; break;
} }
case OPTION_BIN: /* handled in attach_option() */
opt = val;
retval = 1;
default: default:
break; break;
} }

View File

@ -70,17 +70,18 @@ enum {
OPTION_IP = 1, OPTION_IP = 1,
OPTION_IP_PAIR, OPTION_IP_PAIR,
OPTION_STRING, OPTION_STRING,
#if ENABLE_FEATURE_UDHCP_RFC3397
OPTION_DNS_STRING, /* RFC1035 compressed domain name list */
OPTION_SIP_SERVERS,
#endif
// OPTION_BOOLEAN, // OPTION_BOOLEAN,
OPTION_U8, OPTION_U8,
OPTION_U16, OPTION_U16,
// OPTION_S16, // OPTION_S16,
OPTION_U32, OPTION_U32,
OPTION_S32, OPTION_S32,
OPTION_BIN,
OPTION_STATIC_ROUTES, OPTION_STATIC_ROUTES,
#if ENABLE_FEATURE_UDHCP_RFC3397
OPTION_DNS_STRING, /* RFC1035 compressed domain name list */
OPTION_SIP_SERVERS,
#endif
OPTION_TYPE_MASK = 0x0f, OPTION_TYPE_MASK = 0x0f,
/* Client requests this option by default */ /* Client requests this option by default */