diff options
Diffstat (limited to 'networking/udhcp/common.c')
-rw-r--r-- | networking/udhcp/common.c | 71 |
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) | |||
378 | * Called to parse "udhcpc -x OPTNAME:OPTVAL" | 378 | * Called to parse "udhcpc -x OPTNAME:OPTVAL" |
379 | * and to parse udhcpd.conf's "opt OPTNAME OPTVAL" directives. | 379 | * and to parse udhcpd.conf's "opt OPTNAME OPTVAL" directives. |
380 | */ | 380 | */ |
381 | /* helper for the helper */ | 381 | /* helper: add an option to the opt_list */ |
382 | static char *allocate_tempopt_if_needed( | 382 | static NOINLINE void attach_option( |
383 | struct option_set **opt_list, | ||
383 | const struct dhcp_optflag *optflag, | 384 | const struct dhcp_optflag *optflag, |
384 | char *buffer, | 385 | char *buffer, |
385 | int *length_p) | 386 | int length) |
386 | { | 387 | { |
388 | struct option_set *existing; | ||
387 | char *allocated = NULL; | 389 | char *allocated = NULL; |
390 | |||
388 | if ((optflag->flags & OPTION_TYPE_MASK) == OPTION_BIN) { | 391 | if ((optflag->flags & OPTION_TYPE_MASK) == OPTION_BIN) { |
389 | const char *end; | 392 | const char *end; |
390 | allocated = xstrdup(buffer); /* more than enough */ | 393 | allocated = xstrdup(buffer); /* more than enough */ |
391 | end = hex2bin(allocated, buffer, 255); | 394 | end = hex2bin(allocated, buffer, 255); |
392 | if (errno) | 395 | if (errno) |
393 | bb_error_msg_and_die("malformed hex string '%s'", buffer); | 396 | bb_error_msg_and_die("malformed hex string '%s'", buffer); |
394 | *length_p = end - allocated; | 397 | length = end - allocated; |
395 | } | 398 | } |
396 | return allocated; | ||
397 | } | ||
398 | /* helper: add an option to the opt_list */ | ||
399 | static NOINLINE void attach_option( | ||
400 | struct option_set **opt_list, | ||
401 | const struct dhcp_optflag *optflag, | ||
402 | char *buffer, | ||
403 | int length) | ||
404 | { | ||
405 | struct option_set *existing; | ||
406 | char *allocated; | ||
407 | |||
408 | allocated = allocate_tempopt_if_needed(optflag, buffer, &length); | ||
409 | #if ENABLE_FEATURE_UDHCP_RFC3397 | 399 | #if ENABLE_FEATURE_UDHCP_RFC3397 |
410 | if ((optflag->flags & OPTION_TYPE_MASK) == OPTION_DNS_STRING) { | 400 | if ((optflag->flags & OPTION_TYPE_MASK) == OPTION_DNS_STRING) { |
411 | /* reuse buffer and length for RFC1035-formatted string */ | 401 | /* reuse buffer and length for RFC1035-formatted string */ |
@@ -463,12 +453,12 @@ static NOINLINE void attach_option( | |||
463 | int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg, const struct dhcp_optflag *optflags, const char *option_strings) | 453 | int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg, const struct dhcp_optflag *optflags, const char *option_strings) |
464 | { | 454 | { |
465 | struct option_set **opt_list = arg; | 455 | struct option_set **opt_list = arg; |
466 | char *opt, *val; | 456 | char *opt; |
467 | char *str; | 457 | char *str; |
468 | const struct dhcp_optflag *optflag; | 458 | const struct dhcp_optflag *optflag; |
469 | struct dhcp_optflag bin_optflag; | 459 | struct dhcp_optflag userdef_optflag; |
470 | unsigned optcode; | 460 | unsigned optcode; |
471 | int retval, length; | 461 | int retval; |
472 | /* IP_PAIR needs 8 bytes, STATIC_ROUTES needs 9 max */ | 462 | /* IP_PAIR needs 8 bytes, STATIC_ROUTES needs 9 max */ |
473 | char buffer[9] ALIGNED(4); | 463 | char buffer[9] ALIGNED(4); |
474 | uint16_t *result_u16 = (uint16_t *) buffer; | 464 | 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 | |||
476 | 466 | ||
477 | /* Cheat, the only *const* str possible is "" */ | 467 | /* Cheat, the only *const* str possible is "" */ |
478 | str = (char *) const_str; | 468 | str = (char *) const_str; |
479 | opt = strtok(str, " \t="); | 469 | opt = strtok(str, " \t=:"); |
480 | if (!opt) | 470 | if (!opt) |
481 | return 0; | 471 | return 0; |
482 | 472 | ||
483 | optcode = bb_strtou(opt, NULL, 0); | 473 | optcode = bb_strtou(opt, NULL, 0); |
484 | if (!errno && optcode < 255) { | 474 | if (!errno && optcode < 255) { |
485 | /* Raw (numeric) option code */ | 475 | /* Raw (numeric) option code. |
486 | bin_optflag.flags = OPTION_BIN; | 476 | * Initially assume binary (hex-str), but if "str" or 'str' |
487 | bin_optflag.code = optcode; | 477 | * is seen later, switch to STRING. |
488 | optflag = &bin_optflag; | 478 | */ |
479 | userdef_optflag.flags = OPTION_BIN; | ||
480 | userdef_optflag.code = optcode; | ||
481 | optflag = &userdef_optflag; | ||
489 | } else { | 482 | } else { |
490 | optflag = &optflags[udhcp_option_idx(opt, option_strings)]; | 483 | optflag = &optflags[udhcp_option_idx(opt, option_strings)]; |
491 | } | 484 | } |
492 | 485 | ||
486 | /* Loop to handle OPTION_LIST case, else execute just once */ | ||
493 | retval = 0; | 487 | retval = 0; |
494 | do { | 488 | do { |
495 | val = strtok(NULL, ", \t"); | 489 | int length; |
490 | char *val; | ||
491 | |||
492 | if (optflag->flags == OPTION_BIN) | ||
493 | val = trim(strtok(NULL, "")); /* do not split "'q w e'" */ | ||
494 | else | ||
495 | val = strtok(NULL, ", \t"); | ||
496 | if (!val) | 496 | if (!val) |
497 | break; | 497 | break; |
498 | |||
498 | length = dhcp_option_lengths[optflag->flags & OPTION_TYPE_MASK]; | 499 | length = dhcp_option_lengths[optflag->flags & OPTION_TYPE_MASK]; |
499 | retval = 0; | 500 | retval = 0; |
500 | opt = buffer; /* new meaning for variable opt */ | 501 | opt = buffer; /* new meaning for variable opt */ |
502 | |||
501 | switch (optflag->flags & OPTION_TYPE_MASK) { | 503 | switch (optflag->flags & OPTION_TYPE_MASK) { |
502 | case OPTION_IP: | 504 | case OPTION_IP: |
503 | retval = udhcp_str2nip(val, buffer); | 505 | retval = udhcp_str2nip(val, buffer); |
@@ -510,6 +512,7 @@ int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg, const struct dh | |||
510 | if (retval) | 512 | if (retval) |
511 | retval = udhcp_str2nip(val, buffer + 4); | 513 | retval = udhcp_str2nip(val, buffer + 4); |
512 | break; | 514 | break; |
515 | case_OPTION_STRING: | ||
513 | case OPTION_STRING: | 516 | case OPTION_STRING: |
514 | case OPTION_STRING_HOST: | 517 | case OPTION_STRING_HOST: |
515 | #if ENABLE_FEATURE_UDHCP_RFC3397 | 518 | #if ENABLE_FEATURE_UDHCP_RFC3397 |
@@ -577,12 +580,26 @@ int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg, const struct dh | |||
577 | } | 580 | } |
578 | break; | 581 | break; |
579 | } | 582 | } |
580 | case OPTION_BIN: /* handled in attach_option() */ | 583 | case OPTION_BIN: |
584 | /* Raw (numeric) option code. Is it a string? */ | ||
585 | if (val[0] == '"' || val[0] == '\'') { | ||
586 | char delim = val[0]; | ||
587 | char *end = last_char_is(val + 1, delim); | ||
588 | if (end) { | ||
589 | *end = '\0'; | ||
590 | val++; | ||
591 | userdef_optflag.flags = OPTION_STRING; | ||
592 | goto case_OPTION_STRING; | ||
593 | } | ||
594 | } | ||
595 | /* No: hex-str option, handled in attach_option() */ | ||
581 | opt = val; | 596 | opt = val; |
582 | retval = 1; | 597 | retval = 1; |
598 | break; | ||
583 | default: | 599 | default: |
584 | break; | 600 | break; |
585 | } | 601 | } |
602 | |||
586 | if (retval) | 603 | if (retval) |
587 | attach_option(opt_list, optflag, opt, length); | 604 | attach_option(opt_list, optflag, opt, length); |
588 | } while (retval && (optflag->flags & OPTION_LIST)); | 605 | } while (retval && (optflag->flags & OPTION_LIST)); |