summaryrefslogtreecommitdiffhomepage
path: root/networking/udhcp/common.c
diff options
context:
space:
mode:
Diffstat (limited to 'networking/udhcp/common.c')
-rw-r--r--networking/udhcp/common.c71
1 files changed, 44 insertions, 27 deletions
diff --git a/networking/udhcp/common.c b/networking/udhcp/common.c
index d3eea5def..fbf9c6878 100644
--- a/networking/udhcp/common.c
+++ b/networking/udhcp/common.c
@@ -378,34 +378,24 @@ int FAST_FUNC udhcp_str2nip(const char *str, void *arg)
* 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(
+/* helper: add an option to the opt_list */
+static NOINLINE void attach_option(
+ struct option_set **opt_list,
const struct dhcp_optflag *optflag,
char *buffer,
- int *length_p)
+ int length)
{
+ struct option_set *existing;
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;
+ length = end - allocated;
}
- return allocated;
-}
-/* helper: add an option to the opt_list */
-static NOINLINE void attach_option(
- struct option_set **opt_list,
- const struct dhcp_optflag *optflag,
- char *buffer,
- int length)
-{
- struct option_set *existing;
- char *allocated;
-
- 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 */
@@ -463,12 +453,12 @@ static NOINLINE void attach_option(
int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg, const struct dhcp_optflag *optflags, const char *option_strings)
{
struct option_set **opt_list = arg;
- char *opt, *val;
+ char *opt;
char *str;
const struct dhcp_optflag *optflag;
- struct dhcp_optflag bin_optflag;
+ struct dhcp_optflag userdef_optflag;
unsigned optcode;
- int retval, length;
+ int retval;
/* IP_PAIR needs 8 bytes, STATIC_ROUTES needs 9 max */
char buffer[9] ALIGNED(4);
uint16_t *result_u16 = (uint16_t *) buffer;
@@ -476,28 +466,40 @@ int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg, const struct dh
/* Cheat, the only *const* str possible is "" */
str = (char *) const_str;
- opt = strtok(str, " \t=");
+ opt = strtok(str, " \t=:");
if (!opt)
return 0;
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;
+ /* Raw (numeric) option code.
+ * Initially assume binary (hex-str), but if "str" or 'str'
+ * is seen later, switch to STRING.
+ */
+ userdef_optflag.flags = OPTION_BIN;
+ userdef_optflag.code = optcode;
+ optflag = &userdef_optflag;
} else {
optflag = &optflags[udhcp_option_idx(opt, option_strings)];
}
+ /* Loop to handle OPTION_LIST case, else execute just once */
retval = 0;
do {
- val = strtok(NULL, ", \t");
+ int length;
+ char *val;
+
+ if (optflag->flags == OPTION_BIN)
+ val = trim(strtok(NULL, "")); /* do not split "'q w e'" */
+ else
+ val = strtok(NULL, ", \t");
if (!val)
break;
+
length = dhcp_option_lengths[optflag->flags & OPTION_TYPE_MASK];
retval = 0;
opt = buffer; /* new meaning for variable opt */
+
switch (optflag->flags & OPTION_TYPE_MASK) {
case OPTION_IP:
retval = udhcp_str2nip(val, buffer);
@@ -510,6 +512,7 @@ int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg, const struct dh
if (retval)
retval = udhcp_str2nip(val, buffer + 4);
break;
+case_OPTION_STRING:
case OPTION_STRING:
case OPTION_STRING_HOST:
#if ENABLE_FEATURE_UDHCP_RFC3397
@@ -577,12 +580,26 @@ int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg, const struct dh
}
break;
}
- case OPTION_BIN: /* handled in attach_option() */
+ case OPTION_BIN:
+ /* Raw (numeric) option code. Is it a string? */
+ if (val[0] == '"' || val[0] == '\'') {
+ char delim = val[0];
+ char *end = last_char_is(val + 1, delim);
+ if (end) {
+ *end = '\0';
+ val++;
+ userdef_optflag.flags = OPTION_STRING;
+ goto case_OPTION_STRING;
+ }
+ }
+ /* No: hex-str option, handled in attach_option() */
opt = val;
retval = 1;
+ break;
default:
break;
}
+
if (retval)
attach_option(opt_list, optflag, opt, length);
} while (retval && (optflag->flags & OPTION_LIST));