return (ssize_t)bytes;
}
-#define ADDRSZ 4
#define ADDR6SZ 16
static ssize_t
dhcp_optlen(const struct dhcp_opt *opt, size_t dl)
{
size_t sz;
- if (opt->type == 0 ||
- opt->type & (STRING | BINHEX | RFC3442))
- {
+ if (opt->type & ADDRIPV6)
+ sz = ADDR6SZ;
+ else if (opt->type & (UINT32 | ADDRIPV4))
+ sz = sizeof(uint32_t);
+ else if (opt->type & UINT16)
+ sz = sizeof(uint16_t);
+ else if (opt->type & (UINT8 | BITFLAG))
+ sz = sizeof(uint8_t);
+ else if (opt->type & FLAG)
+ return 0;
+ else {
+ /* All other types are variable length */
if (opt->len) {
- if ((size_t)opt->len > dl)
+ if ((size_t)opt->len > dl) {
+ errno = ENODATA;
return -1;
+ }
return (ssize_t)opt->len;
}
return (ssize_t)dl;
}
-
- if ((opt->type & (ADDRIPV4 | ARRAY)) == (ADDRIPV4 | ARRAY)) {
- if (dl < ADDRSZ)
- return -1;
- return (ssize_t)(dl - (dl % ADDRSZ));
- }
-
- if ((opt->type & (ADDRIPV6 | ARRAY)) == (ADDRIPV6 | ARRAY)) {
- if (dl < ADDR6SZ)
- return -1;
- return (ssize_t)(dl - (dl % ADDR6SZ));
+ if (dl < sz) {
+ errno = ENODATA;
+ return -1;
}
- if (opt->type & (UINT32 | ADDRIPV4))
- sz = sizeof(uint32_t);
- else if (opt->type & UINT16)
- sz = sizeof(uint16_t);
- else if (opt->type & (UINT8 | BITFLAG))
- sz = sizeof(uint8_t);
- else if (opt->type & ADDRIPV6)
- sz = ADDR6SZ;
- else
- /* If we don't know the size, assume it's valid */
- return (ssize_t)dl;
- return dl < sz ? -1 : (ssize_t)sz;
+ /* Trim any extra data.
+ * Maybe we need a settng to reject DHCP options with extra data? */
+ if (opt->type & ARRAY)
+ return (ssize_t)(dl - (dl % sz));
+ return (ssize_t)sz;
}
static ssize_t
size_t e;
char *v, *val;
- if (opt->len && opt->len < ol)
- ol = opt->len;
+ /* Ensure a valid length */
+ ol = (size_t)dhcp_optlen(opt, ol);
+ if ((ssize_t)ol == -1)
+ return 0;
+
len = print_option(NULL, 0, opt, od, ol, ifname);
if (len < 0)
return 0;