This is useful when you embed two strings in the same option.
}
static size_t
-dhcp_optlen(int type, size_t dl)
+dhcp_optlen(const struct dhcp_opt *opt, size_t dl)
{
size_t sz;
if (dl == 0)
return 0;
- if (type == 0 || type & (STRING | RFC3442 | RFC5969))
+ if (opt->type == 0 ||
+ opt->type & (STRING | BINHEX | RFC3442 | RFC5969))
+ {
+ if (opt->len) {
+ if ((size_t)opt->len > dl)
+ return 0;
+ return opt->len;
+ }
return dl;
+ }
- if ((type & (ADDRIPV4 | ARRAY)) == (ADDRIPV4 | ARRAY)) {
+ if ((opt->type & (ADDRIPV4 | ARRAY)) == (ADDRIPV4 | ARRAY)) {
if (dl < sizeof(uint32_t))
return 0;
return dl - (dl % sizeof(uint32_t));
}
sz = 0;
- if (type & (UINT32 | ADDRIPV4))
+ if (opt->type & (UINT32 | ADDRIPV4))
sz = sizeof(uint32_t);
- else if (type & UINT16)
+ else if (opt->type & UINT16)
sz = sizeof(uint16_t);
- else if (type & UINT8)
+ else if (opt->type & UINT8)
sz = sizeof(uint8_t);
else
/* If we don't know the size, assume it's valid */
size_t e;
char *v, *val;
+ if (opt->len && opt->len < ol)
+ ol = opt->len;
len = print_option(NULL, 0, opt->type, ol, od, ifname);
if (len < 0)
return 0;
n = 0;
for (i = 0; i < opt->embopts_len; i++) {
eopt = &opt->embopts[i];
- e = dhcp_optlen(eopt->type, ol);
+ e = dhcp_optlen(eopt, ol);
if (e == 0)
/* Report error? */
return 0;
struct dhcp_opt {
uint16_t option;
int type;
+ int len;
/* This union allows us to define a global static list of
* variable names which we don't free and a list of user defined
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd November 27, 2013
+.Dd December 1, 2013
.Dt DHCPCD.CONF 5
.Os
.Sh NAME
.Ar type .
.El
.Ss Types to define
-If a length is unspecified by the type, it consumes the rest of the option
-data.
+The type directly affects the length of data consumed inside the option.
+Any remaining data is normally discarded.
+Lengths can be specified for string and binhex types, but this is generally
+with other data embedded afterwards in the same option.
.Bl -tag -width indent
.It Ic ipaddress
An IPv4 address, 4 bytes
.It Ic ip6address
An IPv6 address, 16 bytes
-.It Ic string
+.It Ic string Op : Ic length
A shell escaped string (binary data escaped as octal)
.It Ic byte
A byte
A fixed value (1) to indicate that the option is present, 0 bytes
.It Ic domain
A RFC 3397 encoded string
-.It Ic binhex
+.It Ic binhex Op : Ic length
Binary data expressed as hexadecimal
.It Ic embed
Contains embedded options (implies encap as well)
static int
parse_option(struct if_options *ifo, int opt, const char *arg)
{
- int i, t;
+ int i, l, t;
char *p = NULL, *fp, *np, **nconf;
ssize_t s;
struct in_addr addr, addr2;
fp = strwhite(arg);
if (fp)
*fp++ = '\0';
+ np = strchr(arg, ':');
+ /* length */
+ if (np) {
+ *np++ = '\0';
+ if ((l = atoint(np)) == -1)
+ return -1;
+ } else
+ l = 0;
t = 0;
if (strcasecmp(arg, "request") == 0) {
t |= REQUEST;
syslog(LOG_ERR, "unknown type: %s", arg);
return -1;
}
+ if (l && !(t & (STRING | BINHEX))) {
+ syslog(LOG_WARNING,
+ "ignoring length for type `%s'", arg);
+ l = 0;
+ }
/* variable */
if (fp) {
arg = strskipwhite(fp);
free_dhcp_opt_embenc(ndop);
ndop->option = i; /* could have been 0 */
ndop->type = t;
+ if (t & (STRING | BINHEX))
+ ndop->len = l;
+ else
+ ndop->len = 0;
ndop->v.dvar = np;
/* Save the define for embed and encap options */
if (opt == O_DEFINE || opt == O_DEFINE6)