udhcp: add option scanner
Added an option scanner to udhcp to enable iteration over packet options. Signed-off-by: Martin Lewis <martin.lewis.x84@gmail.com> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
parent
fc2ce04a38
commit
acdc8eed89
@ -15,7 +15,7 @@ const uint8_t MAC_BCAST_ADDR[6] ALIGN2 = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
#if ENABLE_UDHCPC || ENABLE_UDHCPD
|
#if ENABLE_UDHCPC || ENABLE_UDHCPD
|
||||||
/* Supported options are easily added here.
|
/* Supported options are easily added here, they need to be sorted.
|
||||||
* See RFC2132 for more options.
|
* See RFC2132 for more options.
|
||||||
* OPTION_REQ: these options are requested by udhcpc (unless -o).
|
* OPTION_REQ: these options are requested by udhcpc (unless -o).
|
||||||
*/
|
*/
|
||||||
@ -222,79 +222,91 @@ unsigned FAST_FUNC udhcp_option_idx(const char *name, const char *option_strings
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get an option with bounds checking (warning, result is not aligned) */
|
/* Initialize state to be used between subsequent udhcp_scan_options calls */
|
||||||
uint8_t* FAST_FUNC udhcp_get_option(struct dhcp_packet *packet, int code)
|
void FAST_FUNC init_scan_state(struct dhcp_packet *packet, struct dhcp_scan_state *scan_state)
|
||||||
|
{
|
||||||
|
scan_state->overload = 0;
|
||||||
|
scan_state->rem = sizeof(packet->options);
|
||||||
|
scan_state->optionptr = packet->options;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Iterate over packet's options, each call returning the next option.
|
||||||
|
* scan_state needs to be initialized with init_scan_state beforehand.
|
||||||
|
* Warning, result is not aligned. */
|
||||||
|
uint8_t* FAST_FUNC udhcp_scan_options(struct dhcp_packet *packet, struct dhcp_scan_state *scan_state)
|
||||||
{
|
{
|
||||||
uint8_t *optionptr;
|
|
||||||
int len;
|
int len;
|
||||||
int rem;
|
|
||||||
int overload = 0;
|
|
||||||
enum {
|
enum {
|
||||||
FILE_FIELD101 = FILE_FIELD * 0x101,
|
FILE_FIELD101 = FILE_FIELD * 0x101,
|
||||||
SNAME_FIELD101 = SNAME_FIELD * 0x101,
|
SNAME_FIELD101 = SNAME_FIELD * 0x101,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* option bytes: [code][len][data1][data2]..[dataLEN] */
|
/* option bytes: [code][len][data1][data2]..[dataLEN] */
|
||||||
optionptr = packet->options;
|
|
||||||
rem = sizeof(packet->options);
|
|
||||||
while (1) {
|
while (1) {
|
||||||
if (rem <= 0) {
|
if (scan_state->rem <= 0) {
|
||||||
complain:
|
complain:
|
||||||
bb_simple_error_msg("bad packet, malformed option field");
|
bb_simple_error_msg("bad packet, malformed option field");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* DHCP_PADDING and DHCP_END have no [len] byte */
|
/* DHCP_PADDING and DHCP_END have no [len] byte */
|
||||||
if (optionptr[OPT_CODE] == DHCP_PADDING) {
|
if (scan_state->optionptr[OPT_CODE] == DHCP_PADDING) {
|
||||||
rem--;
|
scan_state->rem--;
|
||||||
optionptr++;
|
scan_state->optionptr++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (optionptr[OPT_CODE] == DHCP_END) {
|
if (scan_state->optionptr[OPT_CODE] == DHCP_END) {
|
||||||
if ((overload & FILE_FIELD101) == FILE_FIELD) {
|
if ((scan_state->overload & FILE_FIELD101) == FILE_FIELD) {
|
||||||
/* can use packet->file, and didn't look at it yet */
|
/* can use packet->file, and didn't look at it yet */
|
||||||
overload |= FILE_FIELD101; /* "we looked at it" */
|
scan_state->overload |= FILE_FIELD101; /* "we looked at it" */
|
||||||
optionptr = packet->file;
|
scan_state->optionptr = packet->file;
|
||||||
rem = sizeof(packet->file);
|
scan_state->rem = sizeof(packet->file);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ((overload & SNAME_FIELD101) == SNAME_FIELD) {
|
if ((scan_state->overload & SNAME_FIELD101) == SNAME_FIELD) {
|
||||||
/* can use packet->sname, and didn't look at it yet */
|
/* can use packet->sname, and didn't look at it yet */
|
||||||
overload |= SNAME_FIELD101; /* "we looked at it" */
|
scan_state->overload |= SNAME_FIELD101; /* "we looked at it" */
|
||||||
optionptr = packet->sname;
|
scan_state->optionptr = packet->sname;
|
||||||
rem = sizeof(packet->sname);
|
scan_state->rem = sizeof(packet->sname);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rem <= OPT_LEN)
|
if (scan_state->rem <= OPT_LEN)
|
||||||
goto complain; /* complain and return NULL */
|
goto complain; /* complain and return NULL */
|
||||||
len = 2 + optionptr[OPT_LEN];
|
len = 2 + scan_state->optionptr[OPT_LEN];
|
||||||
rem -= len;
|
scan_state->rem -= len;
|
||||||
if (rem < 0)
|
/* So far no valid option with length 0 known. */
|
||||||
|
if (scan_state->rem < 0 || scan_state->optionptr[OPT_LEN] == 0)
|
||||||
goto complain; /* complain and return NULL */
|
goto complain; /* complain and return NULL */
|
||||||
|
|
||||||
if (optionptr[OPT_CODE] == code) {
|
if (scan_state->optionptr[OPT_CODE] == DHCP_OPTION_OVERLOAD) {
|
||||||
if (optionptr[OPT_LEN] == 0) {
|
|
||||||
/* So far no valid option with length 0 known.
|
|
||||||
* Having this check means that searching
|
|
||||||
* for DHCP_MESSAGE_TYPE need not worry
|
|
||||||
* that returned pointer might be unsafe
|
|
||||||
* to dereference.
|
|
||||||
*/
|
|
||||||
goto complain; /* complain and return NULL */
|
|
||||||
}
|
|
||||||
log_option("option found", optionptr);
|
|
||||||
return optionptr + OPT_DATA;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (optionptr[OPT_CODE] == DHCP_OPTION_OVERLOAD) {
|
|
||||||
if (len >= 3)
|
if (len >= 3)
|
||||||
overload |= optionptr[OPT_DATA];
|
scan_state->overload |= scan_state->optionptr[OPT_DATA];
|
||||||
/* fall through */
|
} else {
|
||||||
|
uint8_t *return_ptr = scan_state->optionptr;
|
||||||
|
scan_state->optionptr += len;
|
||||||
|
return return_ptr;
|
||||||
|
}
|
||||||
|
scan_state->optionptr += len;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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 *optptr;
|
||||||
|
struct dhcp_scan_state scan_state;
|
||||||
|
|
||||||
|
init_scan_state(packet, &scan_state);
|
||||||
|
while ((optptr = udhcp_scan_options(packet, &scan_state)) != NULL) {
|
||||||
|
if (optptr[OPT_CODE] == code) {
|
||||||
|
log_option("option found", optptr);
|
||||||
|
return optptr + OPT_DATA;
|
||||||
}
|
}
|
||||||
optionptr += len;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* log3 because udhcpc uses it a lot - very noisy */
|
/* log3 because udhcpc uses it a lot - very noisy */
|
||||||
|
@ -107,6 +107,12 @@ enum {
|
|||||||
OPTION_LIST = 0x20,
|
OPTION_LIST = 0x20,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct dhcp_scan_state {
|
||||||
|
int overload;
|
||||||
|
int rem;
|
||||||
|
uint8_t *optionptr;
|
||||||
|
};
|
||||||
|
|
||||||
/* DHCP option codes (partial list). See RFC 2132 and
|
/* DHCP option codes (partial list). See RFC 2132 and
|
||||||
* http://www.iana.org/assignments/bootp-dhcp-parameters/
|
* http://www.iana.org/assignments/bootp-dhcp-parameters/
|
||||||
* Commented out options are handled by common option machinery,
|
* Commented out options are handled by common option machinery,
|
||||||
@ -206,6 +212,8 @@ extern const uint8_t dhcp_option_lengths[] ALIGN1;
|
|||||||
|
|
||||||
unsigned FAST_FUNC udhcp_option_idx(const char *name, const char *option_strings);
|
unsigned FAST_FUNC udhcp_option_idx(const char *name, const char *option_strings);
|
||||||
|
|
||||||
|
void init_scan_state(struct dhcp_packet *packet, struct dhcp_scan_state *scan_state) FAST_FUNC;
|
||||||
|
uint8_t *udhcp_scan_options(struct dhcp_packet *packet, struct dhcp_scan_state *scan_state) FAST_FUNC;
|
||||||
uint8_t *udhcp_get_option(struct dhcp_packet *packet, int code) FAST_FUNC;
|
uint8_t *udhcp_get_option(struct dhcp_packet *packet, int code) FAST_FUNC;
|
||||||
/* Same as above + ensures that option length is 4 bytes
|
/* Same as above + ensures that option length is 4 bytes
|
||||||
* (returns NULL if size is different)
|
* (returns NULL if size is different)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user