Handle STRING options properly in fill_options and refactor a bit.
This commit is contained in:
parent
7c32f968c9
commit
97137ec3fc
@ -55,22 +55,30 @@ static int sprintip(char *dest, size_t size, char *pre, unsigned char *ip)
|
|||||||
pre, ip[0], ip[1], ip[2], ip[3]);
|
pre, ip[0], ip[1], ip[2], ip[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Fill dest with the text of option 'option'. */
|
/* Fill buf with the ifchd command text of option 'option'. */
|
||||||
/* Returns 0 if successful, -1 if nothing was filled in. */
|
/* Returns 0 if successful, -1 if nothing was filled in. */
|
||||||
static int fill_options(char *dest, unsigned char *option, ssize_t optlen,
|
static int fill_options(char *buf, unsigned char *option, ssize_t optlen,
|
||||||
struct dhcp_option *type_p, unsigned int maxlen)
|
struct dhcp_option *type_p, unsigned int maxlen)
|
||||||
{
|
{
|
||||||
char *odest;
|
char *obuf = buf;
|
||||||
enum option_type type = type_p->type;
|
enum option_type type = type_p->type;
|
||||||
ssize_t typelen = option_length(type);
|
ssize_t typelen = option_length(type);
|
||||||
uint32_t val_u32;
|
ssize_t rem = optlen;
|
||||||
int32_t val_s32;
|
|
||||||
uint16_t val_u16;
|
|
||||||
int16_t val_s16;
|
|
||||||
uint8_t code = type_p->code;
|
uint8_t code = type_p->code;
|
||||||
|
|
||||||
if (!option)
|
if (!option)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
if (type == OPTION_STRING) {
|
||||||
|
buf += snprintf(buf, maxlen, "%s=", type_p->name);
|
||||||
|
if (maxlen < rem + 1)
|
||||||
|
return -1;
|
||||||
|
memcpy(buf, option, rem);
|
||||||
|
buf[rem] = '\0';
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Length and type checking.
|
||||||
if (optlen != typelen) {
|
if (optlen != typelen) {
|
||||||
if (option_valid_list(code)) {
|
if (option_valid_list(code)) {
|
||||||
if ((optlen % typelen)) {
|
if ((optlen % typelen)) {
|
||||||
@ -84,55 +92,53 @@ static int fill_options(char *dest, unsigned char *option, ssize_t optlen,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int len = option[-1]; // XXX: WTF ugly as all hell
|
|
||||||
|
|
||||||
odest = dest;
|
buf += snprintf(buf, maxlen, "%s=", type_p->name);
|
||||||
|
|
||||||
dest += snprintf(dest, maxlen, "%s=", type_p->name);
|
|
||||||
|
|
||||||
for(;;) {
|
for(;;) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case OPTION_IP: /* Works regardless of host byte order. */
|
case OPTION_IP: /* Works regardless of host byte order. */
|
||||||
dest += sprintip(dest, maxlen - (dest - odest), "", option);
|
buf += sprintip(buf, maxlen - (buf - obuf), "", option);
|
||||||
break;
|
break;
|
||||||
case OPTION_U8:
|
case OPTION_U8:
|
||||||
dest += snprintf(dest, maxlen - (dest - odest),
|
buf += snprintf(buf, maxlen - (buf - obuf), "%u ", *option);
|
||||||
"%u ", *option);
|
|
||||||
break;
|
break;
|
||||||
case OPTION_U16:
|
case OPTION_U16: {
|
||||||
|
uint16_t val_u16;
|
||||||
memcpy(&val_u16, option, 2);
|
memcpy(&val_u16, option, 2);
|
||||||
dest += snprintf(dest, maxlen - (dest - odest),
|
buf += snprintf(buf, maxlen - (buf - obuf), "%u ",
|
||||||
"%u ", ntohs(val_u16));
|
ntohs(val_u16));
|
||||||
break;
|
break;
|
||||||
case OPTION_S16:
|
}
|
||||||
|
case OPTION_S16: {
|
||||||
|
int16_t val_s16;
|
||||||
memcpy(&val_s16, option, 2);
|
memcpy(&val_s16, option, 2);
|
||||||
dest += snprintf(dest, maxlen - (dest - odest),
|
buf += snprintf(buf, maxlen - (buf - obuf), "%d ",
|
||||||
"%d ", ntohs(val_s16));
|
ntohs(val_s16));
|
||||||
break;
|
break;
|
||||||
case OPTION_U32:
|
}
|
||||||
|
case OPTION_U32: {
|
||||||
|
uint32_t val_u32;
|
||||||
memcpy(&val_u32, option, 4);
|
memcpy(&val_u32, option, 4);
|
||||||
dest += snprintf(dest, maxlen - (dest - odest),
|
buf += snprintf(buf, maxlen - (buf - obuf), "%u ",
|
||||||
"%u ", (uint32_t) ntohl(val_u32));
|
ntohl(val_u32));
|
||||||
break;
|
break;
|
||||||
case OPTION_S32:
|
}
|
||||||
|
case OPTION_S32: {
|
||||||
|
int32_t val_s32;
|
||||||
memcpy(&val_s32, option, 4);
|
memcpy(&val_s32, option, 4);
|
||||||
dest += snprintf(dest, maxlen - (dest - odest),
|
buf += snprintf(buf, maxlen - (buf - obuf), "%d ",
|
||||||
"%d ", (int32_t) ntohl(val_s32));
|
ntohl(val_s32));
|
||||||
break;
|
break;
|
||||||
case OPTION_STRING:
|
}
|
||||||
if ( (maxlen - (dest - odest)) < (unsigned)len)
|
default:
|
||||||
return -1;
|
|
||||||
memcpy(dest, option, len);
|
|
||||||
dest[len] = '\0';
|
|
||||||
return 0; /* Short circuit this case */
|
|
||||||
case OPTION_NONE:
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
option += typelen;
|
option += typelen;
|
||||||
len -= typelen;
|
rem -= typelen;
|
||||||
if (len <= 0)
|
if (rem <= 0)
|
||||||
break;
|
break;
|
||||||
*(dest++) = ':';
|
*(buf++) = ':';
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -81,7 +81,6 @@ uint8_t option_length(enum option_type type)
|
|||||||
{
|
{
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case OPTION_IP: return 4;
|
case OPTION_IP: return 4;
|
||||||
case OPTION_STRING: return 1; // XXX ?
|
|
||||||
case OPTION_U8: return 1;
|
case OPTION_U8: return 1;
|
||||||
case OPTION_U16: return 2;
|
case OPTION_U16: return 2;
|
||||||
case OPTION_S16: return 2;
|
case OPTION_S16: return 2;
|
||||||
@ -150,7 +149,8 @@ unsigned char *alloc_dhcp_client_id_option(unsigned char type,
|
|||||||
return alloc_option(DHCP_CLIENT_ID, data, sizeof data);
|
return alloc_option(DHCP_CLIENT_ID, data, sizeof data);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Worker function for get_option().
|
// Worker function for get_option(). Optlen will be set to the length
|
||||||
|
// of the option data.
|
||||||
static uint8_t *do_get_option(uint8_t *buf, ssize_t buflen, int code,
|
static uint8_t *do_get_option(uint8_t *buf, ssize_t buflen, int code,
|
||||||
char *overload, ssize_t *optlen)
|
char *overload, ssize_t *optlen)
|
||||||
{
|
{
|
||||||
@ -194,7 +194,8 @@ static uint8_t *do_get_option(uint8_t *buf, ssize_t buflen, int code,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get an option with bounds checking (warning, result is not aligned) */
|
// Get an option with bounds checking (warning, result is not aligned)
|
||||||
|
// optlen will be equal to the length of the option data.
|
||||||
uint8_t *get_option(struct dhcpMessage *packet, int code, ssize_t *optlen)
|
uint8_t *get_option(struct dhcpMessage *packet, int code, ssize_t *optlen)
|
||||||
{
|
{
|
||||||
uint8_t *option, *buf;
|
uint8_t *option, *buf;
|
||||||
|
Loading…
Reference in New Issue
Block a user