aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--networking/udhcp/common.c47
-rw-r--r--networking/udhcp/common.h9
2 files changed, 43 insertions, 13 deletions
diff --git a/networking/udhcp/common.c b/networking/udhcp/common.c
index fb4f8d16c..50e2c84e3 100644
--- a/networking/udhcp/common.c
+++ b/networking/udhcp/common.c
@@ -324,9 +324,27 @@ int FAST_FUNC udhcp_str2nip(const char *str, void *arg)
}
/* udhcp_str2optset:
- * Parse string option representation to binary form
- * and add it to opt_list
+ * Parse string option representation to binary form 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 */
static NOINLINE void attach_option(
struct option_set **opt_list,
@@ -335,13 +353,12 @@ static NOINLINE void attach_option(
int length)
{
struct option_set *existing, *new, **curr;
-#if ENABLE_FEATURE_UDHCP_RFC3397
char *allocated = NULL;
-#endif
existing = udhcp_find_option(*opt_list, optflag->code);
if (!existing) {
log2("Attaching option %02x to list", optflag->code);
+ allocated = allocate_tempopt_if_needed(optflag, buffer, &length);
#if ENABLE_FEATURE_UDHCP_RFC3397
if ((optflag->flags & OPTION_TYPE_MASK) == OPTION_DNS_STRING) {
/* reuse buffer and length for RFC1035-formatted string */
@@ -368,7 +385,8 @@ static NOINLINE void attach_option(
unsigned old_len;
/* 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];
#if ENABLE_FEATURE_UDHCP_RFC3397
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 new data */
- ret: ;
-#if ENABLE_FEATURE_UDHCP_RFC3397
+ ret:
free(allocated);
-#endif
}
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 *str;
const struct dhcp_optflag *optflag;
+ struct dhcp_optflag bin_optflag;
+ unsigned optcode;
int retval, length;
char buffer[8] ALIGNED(4);
uint16_t *result_u16 = (uint16_t *) buffer;
@@ -413,7 +431,15 @@ int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg)
if (!opt)
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;
do {
@@ -482,6 +508,9 @@ int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg)
retval = (endptr[0] == '\0');
break;
}
+ case OPTION_BIN: /* handled in attach_option() */
+ opt = val;
+ retval = 1;
default:
break;
}
diff --git a/networking/udhcp/common.h b/networking/udhcp/common.h
index 7dd1f119a..c9dd0bb25 100644
--- a/networking/udhcp/common.h
+++ b/networking/udhcp/common.h
@@ -70,17 +70,18 @@ enum {
OPTION_IP = 1,
OPTION_IP_PAIR,
OPTION_STRING,
-#if ENABLE_FEATURE_UDHCP_RFC3397
- OPTION_DNS_STRING, /* RFC1035 compressed domain name list */
- OPTION_SIP_SERVERS,
-#endif
// OPTION_BOOLEAN,
OPTION_U8,
OPTION_U16,
// OPTION_S16,
OPTION_U32,
OPTION_S32,
+ OPTION_BIN,
OPTION_STATIC_ROUTES,
+#if ENABLE_FEATURE_UDHCP_RFC3397
+ OPTION_DNS_STRING, /* RFC1035 compressed domain name list */
+ OPTION_SIP_SERVERS,
+#endif
OPTION_TYPE_MASK = 0x0f,
/* Client requests this option by default */