printf(" ip6address");
else if (opt->type & FLAG)
printf(" flag");
+ else if (opt->type & BITFLAG)
+ printf(" bitflags");
else if (opt->type & RFC3397)
printf(" domain");
else if (opt->type & DOMAIN)
printf(" raw");
else if (opt->type & BINHEX)
printf(" binhex");
- else if (opt->type & STRING)
+ else if (opt->type & STRING)
printf(" string");
- if (opt->type & RFC3361)
+ if (opt->type & RFC3361)
printf(" rfc3361");
if (opt->type & RFC3442)
printf(" rfc3442");
sz = sizeof(uint32_t);
else if (opt->type & UINT16)
sz = sizeof(uint16_t);
- else if (opt->type & UINT8)
+ else if (opt->type & (UINT8 | BITFLAG))
sz = sizeof(uint8_t);
else if (opt->type & ADDRIPV6)
sz = ADDR6SZ;
return (dl < sz ? 0 : sz);
}
-#ifdef INET6
-#define PO_IFNAME
-#else
-#define PO_IFNAME __unused
-#endif
-
-ssize_t
-print_option(char *s, size_t len, int type, const uint8_t *data, size_t dl,
- PO_IFNAME const char *ifname)
+static ssize_t
+print_option(char *s, size_t len, const struct dhcp_opt *opt,
+ const uint8_t *data, size_t dl, const char *ifname)
{
const uint8_t *e, *t;
uint16_t u16;
size_t l;
char *tmp;
- if (type & RFC3397) {
+#ifndef INET6
+ UNUSED(ifname);
+#endif
+
+ if (opt->type & RFC3397) {
sl = decode_rfc3397(NULL, 0, data, dl);
if (sl == 0 || sl == -1)
return sl;
if (tmp == NULL)
return -1;
decode_rfc3397(tmp, l, data, dl);
- sl = print_string(s, len, type, (uint8_t *)tmp, l - 1);
+ sl = print_string(s, len, opt->type, (uint8_t *)tmp, l - 1);
free(tmp);
return sl;
}
#ifdef INET
- if (type & RFC3361) {
+ if (opt->type & RFC3361) {
if ((tmp = decode_rfc3361(data, dl)) == NULL)
return -1;
l = strlen(tmp);
- sl = print_string(s, len, type, (uint8_t *)tmp, l);
+ sl = print_string(s, len, opt->type, (uint8_t *)tmp, l);
free(tmp);
return sl;
}
- if (type & RFC3442)
+ if (opt->type & RFC3442)
return decode_rfc3442(s, len, data, dl);
- if (type & RFC5969)
+ if (opt->type & RFC5969)
return decode_rfc5969(s, len, data, dl);
#endif
- if (type & STRING)
- return print_string(s, len, type, data, dl);
+ if (opt->type & STRING)
+ return print_string(s, len, opt->type, data, dl);
- if (type & FLAG) {
+ if (opt->type & FLAG) {
if (s) {
*s++ = '1';
*s = '\0';
return 1;
}
+ if (opt->type & BITFLAG) {
+ /* bitflags are a string, MSB first, such as ABCDEFGH
+ * where A is 10000000, B is 01000000, etc. */
+ bytes = 0;
+ for (l = 0, sl = sizeof(opt->bitflags) - 1;
+ l < sizeof(opt->bitflags);
+ l++, sl--)
+ {
+ /* Don't print NULL or 0 flags */
+ if (opt->bitflags[l] != '\0' &&
+ opt->bitflags[l] != '0' &&
+ *data & (1 << sl))
+ {
+ if (s)
+ *s++ = opt->bitflags[l];
+ bytes++;
+ }
+ }
+ if (s)
+ *s = '\0';
+ return bytes;
+ }
+
if (!s) {
- if (type & UINT8)
+ if (opt->type & UINT8)
l = 3;
- else if (type & UINT16) {
+ else if (opt->type & UINT16) {
l = 5;
dl /= 2;
- } else if (type & SINT16) {
+ } else if (opt->type & SINT16) {
l = 6;
dl /= 2;
- } else if (type & UINT32) {
+ } else if (opt->type & UINT32) {
l = 10;
dl /= 4;
- } else if (type & SINT32) {
+ } else if (opt->type & SINT32) {
l = 11;
dl /= 4;
- } else if (type & ADDRIPV4) {
+ } else if (opt->type & ADDRIPV4) {
l = 16;
dl /= 4;
}
#ifdef INET6
- else if (type & ADDRIPV6) {
+ else if (opt->type & ADDRIPV6) {
e = data + dl;
l = 0;
while (data < e) {
bytes++;
len--;
}
- if (type & UINT8) {
+ if (opt->type & UINT8) {
sl = snprintf(s, len, "%u", *data);
data++;
- } else if (type & UINT16) {
+ } else if (opt->type & UINT16) {
memcpy(&u16, data, sizeof(u16));
u16 = ntohs(u16);
sl = snprintf(s, len, "%u", u16);
data += sizeof(u16);
- } else if (type & SINT16) {
+ } else if (opt->type & SINT16) {
memcpy(&u16, data, sizeof(u16));
s16 = (int16_t)ntohs(u16);
sl = snprintf(s, len, "%d", s16);
data += sizeof(u16);
- } else if (type & UINT32) {
+ } else if (opt->type & UINT32) {
memcpy(&u32, data, sizeof(u32));
u32 = ntohl(u32);
sl = snprintf(s, len, "%u", u32);
data += sizeof(u32);
- } else if (type & SINT32) {
+ } else if (opt->type & SINT32) {
memcpy(&u32, data, sizeof(u32));
s32 = (int32_t)ntohl(u32);
sl = snprintf(s, len, "%d", s32);
data += sizeof(u32);
- } else if (type & ADDRIPV4) {
+ } else if (opt->type & ADDRIPV4) {
memcpy(&addr.s_addr, data, sizeof(addr.s_addr));
sl = snprintf(s, len, "%s", inet_ntoa(addr));
data += sizeof(addr.s_addr);
}
#ifdef INET6
- else if (type & ADDRIPV6) {
+ else if (opt->type & ADDRIPV6) {
ssize_t r;
r = ipv6_printaddr(s, len, data, ifname);
if (opt->len && opt->len < ol)
ol = opt->len;
- len = print_option(NULL, 0, opt->type, od, ol, ifname);
+ len = print_option(NULL, 0, opt, od, ol, ifname);
if (len < 0)
return 0;
if (vname)
else
v += snprintf(val, e, "%s=", prefix);
if (len != 0)
- print_option(v, (size_t)len + 1, opt->type, od, ol, ifname);
+ print_option(v, (size_t)len + 1, opt, od, ol, ifname);
return e;
}
/* If no embedded or encapsulated options, it's easy */
if (opt->embopts_len == 0 && opt->encopts_len == 0) {
- if (dhcp_envoption1(ctx, env == NULL ? NULL : &env[0],
+ if (!(opt->type & RESERVED) &&
+ dhcp_envoption1(ctx, env == NULL ? NULL : &env[0],
prefix, opt, 1, od, ol, ifname))
return 1;
return 0;
/* Use the option prefix if the embedded option
* name is different.
* This avoids new_fqdn_fqdn which would be silly. */
- ov = strcmp(opt->var, eopt->var);
- if (dhcp_envoption1(ctx, env == NULL ? NULL : &env[n],
- pfx, eopt, ov, od, e, ifname))
- n++;
+ if (!(eopt->type & RESERVED)) {
+ ov = strcmp(opt->var, eopt->var);
+ if (dhcp_envoption1(ctx, env == NULL ? NULL : &env[n],
+ pfx, eopt, ov, od, e, ifname))
+ n++;
+ }
od += e;
ol -= e;
}
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd May 14, 2015
+.Dd May 15, 2015
.Dt DHCPCD.CONF 5
.Os
.Sh NAME
it is prefixed with the parent
.Ar variable
first with an underscore.
+If the
+.Ar variable
+has the name of
+.Ar reserved
+then it is not processed.
.It Ic encap Ar code Ar type Ar variable
Defines an encapsulated variable within the defined option.
The length is determined by the
with other data embedded afterwards in the same option.
.Bl -tag -width indent
.It Ic ipaddress
-An IPv4 address, 4 bytes
+An IPv4 address, 4 bytes.
.It Ic ip6address
-An IPv6 address, 16 bytes
+An IPv6 address, 16 bytes.
.It Ic string Op : Ic length
A NVT ASCII string of printable characters.
.It Ic byte
-A byte
+A byte.
+.It Ic bitflags : Ic flags
+A byte represented as a string of flags, most significant bit first.
+For example, using ABCDEFGH then A would equal 10000000, B 01000000,
+C 00100000, etc.
+If the bit is not set, the flag is not printed.
+A flag of 0 is not printed even if the bit postition is set.
+This is to allow reservation of the first bits while assinging the last bits.
.It Ic int16
-A signed 16bit integer, 2 bytes
+A signed 16bit integer, 2 bytes.
.It Ic uint16
-An unsigned 16bit integer, 2 bytes
+An unsigned 16bit integer, 2 bytes.
.It Ic int32
-A signed 32bit integer, 4 bytes
+A signed 32bit integer, 4 bytes.
.It Ic uint32
-An unsigned 32bit integer, 4 bytes
-.It Ic flag
-A fixed value (1) to indicate that the option is present, 0 bytes
+An unsigned 32bit integer, 4 bytes.
+.It Ic flag
+A fixed value (1) to indicate that the option is present, 0 bytes.
.It Ic domain
-A RFC 3397 encoded string
+A RFC 3397 encoded string.
.It Ic dname
-A RFC 1035 validated string
+A RFC 1035 validated string.
.It Ic binhex Op : Ic length
-Binary data expressed as hexadecimal
+Binary data expressed as hexadecimal.
.It Ic embed
-Contains embedded options (implies encap as well)
+Contains embedded options (implies encap as well).
.It Ic encap
-Contains encapsulated options (implies embed as well)
+Contains encapsulated options (implies embed as well).
.It Ic option
-References an option from the global definition
+References an option from the global definition.
.El
.Ss Example definition
.D1 # DHCP option 81, Fully Qualified Domain Name, RFC4702
int e, i, t;
long l;
unsigned long u;
- char *p = NULL, *fp, *np, **nconf;
+ char *p = NULL, *bp, *fp, *np, **nconf;
ssize_t s;
struct in_addr addr, addr2;
in_addr_t *naddr;
/* length */
if (np) {
*np++ = '\0';
+ bp = NULL; /* No bitflag */
l = (long)strtou(np, NULL, 0, 0, LONG_MAX, &e);
if (e) {
- logger(ctx, LOG_ERR, "failed to convert length");
+ logger(ctx,LOG_ERR, "failed to convert length");
return -1;
}
- } else
+ } else {
l = 0;
+ bp = strchr(arg, '='); /* bitflag assignment */
+ if (bp)
+ *bp++ = '\0';
+ }
t = 0;
if (strcasecmp(arg, "request") == 0) {
t |= REQUEST;
t |= STRING;
else if (strcasecmp(arg, "byte") == 0)
t |= UINT8;
+ else if (strcasecmp(arg, "bitflags") == 0)
+ t |= BITFLAG;
else if (strcasecmp(arg, "uint16") == 0)
t |= UINT16;
else if (strcasecmp(arg, "int16") == 0)
logger(ctx, LOG_WARNING, "ignoring array for strings");
t &= ~ARRAY;
}
+ if (t & BITFLAG) {
+ if (bp == NULL)
+ logger(ctx, LOG_WARNING,
+ "missing bitflag assignment");
+ }
/* variable */
if (!fp) {
if (!(t & OPTION)) {
fp = strwhite(arg);
if (fp)
*fp++ = '\0';
- np = strdup(arg);
- if (np == NULL) {
- logger(ctx, LOG_ERR, "%s: %m", __func__);
- return -1;
+ if (strcasecmp(arg, "reserved")) {
+ np = strdup(arg);
+ if (np == NULL) {
+ logger(ctx, LOG_ERR,
+ "%s: %m", __func__);
+ return -1;
+ }
+ } else {
+ np = NULL;
+ t |= RESERVED;
}
}
if (opt != O_EMBED) {
ndop->type = t;
ndop->len = (size_t)l;
ndop->var = np;
+ if (bp) {
+ dl = strlen(bp);
+ memcpy(ndop->bitflags, bp, dl);
+ memset(ndop->bitflags + dl, 0,
+ sizeof(ndop->bitflags) - dl);
+ } else
+ memset(ndop->bitflags, 0, sizeof(ndop->bitflags));
/* Save the define for embed and encap options */
switch (opt) {
case O_DEFINE: