#include "dhcp-common.h"
#include "dhcp.h"
-#ifdef INET
-struct dhcp_opt *dhcp_override = NULL;
-size_t dhcp_override_len = 0;
-#endif
-#ifdef INET6
-struct dhcp_opt *dhcp6_override = NULL;
-size_t dhcp6_override_len = 0;
-#endif
+/* DHCP Enterprise options, RFC3925 */
+struct dhcp_opt *vivso = NULL;
+size_t vivso_len = 0;
+
+struct dhcp_opt *
+vivso_find(uint16_t iana_en, const void *arg)
+{
+ const struct interface *ifp = arg;
+ size_t i;
+ struct dhcp_opt *opt;
+
+ if (arg) {
+ ifp = arg;
+ for (i = 0, opt = ifp->options->vivso_override;
+ i < ifp->options->vivso_override_len;
+ i++, opt++)
+ if (opt->option == iana_en)
+ return opt;
+ }
+ for (i = 0, opt = vivso; i < vivso_len; i++, opt++)
+ if (opt->option == iana_en)
+ return opt;
+ return NULL;
+}
-int make_option_mask(const struct dhcp_opt *dopts, size_t dopts_len,
+int
+make_option_mask(const struct dhcp_opt *dopts, size_t dopts_len,
uint8_t *mask, const char *opts, int add)
{
char *token, *o, *p, *t;
const struct dhcp_opt *opt;
- int match, n;
+ int match;
+ unsigned int n;
size_t i;
o = p = strdup(opts);
ssize_t
dhcp_envoption(char **env, const char *prefix,
const char *ifname, struct dhcp_opt *opt,
- const uint8_t *(*dgetopt)(int *, int *, int *, const uint8_t *, int,
- struct dhcp_opt **),
+ const uint8_t *(*dgetopt)(unsigned int *, unsigned int *, unsigned int *,
+ const uint8_t *, unsigned int, struct dhcp_opt **),
const uint8_t *od, int ol)
{
ssize_t e, n;
size_t i;
- int eoc;
+ unsigned int eoc, eos, eol;
const uint8_t *eod;
- int eos, eol, ov;
+ int ov;
struct dhcp_opt *eopt, *oopt;
char *pfx;
#define OPTION (1 << 20)
struct dhcp_opt {
- uint16_t option;
+ uint32_t option; /* Also used for IANA Enterpise Number */
int type;
int len;
char *var;
size_t encopts_len;
};
+/* DHCP Vendor-Identifying Vendor Options, RFC3925 */
+extern struct dhcp_opt *vivso;
+extern size_t vivso_len;
+
+struct dhcp_opt *vivso_find(uint16_t, const void *);
+
#define add_option_mask(var, val) (var[val >> 3] |= 1 << (val & 7))
#define del_option_mask(var, val) (var[val >> 3] &= ~(1 << (val & 7)))
#define has_option_mask(var, val) (var[val >>3] & (1 << (val & 7)))
ssize_t print_option(char *, ssize_t, int, int, const uint8_t *, const char *);
ssize_t dhcp_envoption(char **, const char *, const char *, struct dhcp_opt *,
- const uint8_t *(*dgetopt)(int *, int *, int *, const uint8_t *, int,
- struct dhcp_opt **),
+ const uint8_t *(*dgetopt)(unsigned int *, unsigned int *, unsigned int *,
+ const uint8_t *, unsigned int, struct dhcp_opt **),
const uint8_t *od, int ol);
void dhcp_zero_index(struct dhcp_opt *);
const struct dhcp_lease *lease = &state->lease;
time_t up = uptime() - state->start_uptime;
const char *hostname;
+ const struct vivco *vivco;
dhcp = calloc(1, sizeof (*dhcp));
if (dhcp == NULL)
p += ifo->vendor[0] + 1;
}
+ if (ifo->vivco_len) {
+ *p++ = DHO_VIVCO;
+ lp = p++;
+ *lp = sizeof(ul);
+ ul = htonl(ifo->vivco_en);
+ memcpy(p, &ul, sizeof(ul));
+ p += sizeof(ul);
+ for (i = 0, vivco = ifo->vivco;
+ i < ifo->vivco_len;
+ i++, vivco++)
+ {
+ len = (p - m) + vivco->len + 1;
+ if (len > sizeof(*dhcp))
+ goto toobig;
+ if (vivco->len + 2 + *lp > 255) {
+ syslog(LOG_ERR,
+ "%s: VIVCO option too big",
+ iface->name);
+ free(dhcp);
+ return -1;
+ }
+ *p++ = (uint8_t)vivco->len;
+ memcpy(p, vivco->data, vivco->len);
+ p += vivco->len;
+ *lp += (uint8_t)vivco->len + 1;
+ }
+ }
+
+ len = (p - m) + 3;
+ if (len > sizeof(*dhcp))
+ goto toobig;
*p++ = DHO_PARAMETERREQUESTLIST;
n_params = p;
*p++ = 0;
(opt->option == DHO_RENEWALTIME ||
opt->option == DHO_REBINDTIME))
continue;
+ len = (p - m) + 2;
+ if (len > sizeof(*dhcp))
+ goto toobig;
*p++ = opt->option;
}
*n_params = p - n_params - 1;
*message = dhcp;
return p - m;
+
+toobig:
+ syslog(LOG_ERR, "%s: DHCP messge too big", iface->name);
+ free(dhcp);
+ return -1;
}
ssize_t
}
static const uint8_t *
-dhcp_getoption(int *os, int *code, int *len, const uint8_t *od, int ol,
- struct dhcp_opt **oopt)
+dhcp_getoption(unsigned int *os, unsigned int *code, unsigned int *len,
+ const uint8_t *od, unsigned int ol, struct dhcp_opt **oopt)
{
size_t i;
struct dhcp_opt *opt;
if (od) {
- if (ol < 0) {
+ if (ol < 2) {
errno = EINVAL;
return NULL;
}
*os = 2; /* code + len */
*code = (int)*od++;
*len = (int)*od++;
- if (*len < 0 || *len > ol) {
+ if (*len > ol) {
errno = EINVAL;
return NULL;
}
struct in_addr addr;
struct in_addr net;
struct in_addr brd;
- struct dhcp_opt *opt;
+ struct dhcp_opt *opt, *vo;
ssize_t e = 0;
char **ep;
char cidr[4];
uint8_t overl = 0;
size_t i;
+ uint32_t en;
ifo = ifp->options;
get_option_uint8(&overl, dhcp, DHO_OPTIONSOVERLOADED);
i < ifp->options->dhcp_override_len;
i++, opt++)
dhcp_zero_index(opt);
+ for (i = 0, opt = vivso; i < vivso_len; i++, opt++)
+ dhcp_zero_index(opt);
}
for (i = 0, opt = dhcp_opts;
if ((p = get_option(dhcp, opt->option, &pl)))
ep += dhcp_envoption(ep, prefix, ifp->name,
opt, dhcp_getoption, p, pl);
+ /* Grab the Vendor-Identifying Vendor Options, RFC 3925 */
+ if (opt->option == DHO_VIVSO && pl > (int)sizeof(uint32_t)) {
+ memcpy(&en, p, sizeof(en));
+ en = ntohl(en);
+ vo = vivso_find(en, ifp);
+ if (vo) {
+ /* Skip over en + total size */
+ p += sizeof(en) + 1;
+ pl -= sizeof(en) + 1;
+ ep += dhcp_envoption(ep, prefix, ifp->name,
+ vo, dhcp_getoption, p, pl);
+ printf ("%p\n", ep);
+ }
+ }
}
for (i = 0, opt = ifo->dhcp_override;
DHO_USERCLASS = 77, /* RFC 3004 */
DHO_RAPIDCOMMIT = 80, /* RFC 4039 */
DHO_FQDN = 81,
+ DHO_VIVCO = 124, /* RFC 3925 */
+ DHO_VIVSO = 125, /* RFC 3925 */
DHO_DNSSEARCH = 119, /* RFC 3397 */
DHO_CSR = 121, /* RFC 3442 */
DHO_SIXRD = 212, /* RFC 5969 */
{ DHO_NTPSERVER, D6_OPTION_SNTP_SERVERS },
{ DHO_RAPIDCOMMIT, D6_OPTION_RAPID_COMMIT },
{ DHO_FQDN, D6_OPTION_FQDN },
+ { DHO_VIVCO, D6_OPTION_VENDOR_CLASS },
+ { DHO_VIVSO, D6_OPTION_VENDOR_OPTS },
{ DHO_DNSSEARCH, D6_OPTION_DOMAIN_LIST },
{ 0, 0 }
};
return 0;
}
-#ifdef DHCPCD_IANA_PEN
static size_t
-dhcp6_makevendor(struct dhcp6_option *o)
+dhcp6_makevendor(struct dhcp6_option *o, const struct interface *ifp)
{
+ const struct if_options *ifo;
size_t len;
uint8_t *p;
uint16_t u16;
uint32_t u32;
- size_t vlen;
-#ifdef VENDOR_SPLIT
- const char *platform;
- size_t plen, unl, url, uml, pl;
- struct utsname utn;
-#endif
+ size_t vlen, i;
+ const struct vivco *vivco;
+ ifo = ifp->options;
len = sizeof(uint32_t); /* IANA PEN */
+ if (ifo->vivco_en) {
+ for (i = 0, vivco = ifo->vivco;
+ i < ifo->vivco_len;
+ i++, vivco++)
+ len += sizeof(uint16_t) + vivco->len;
+ vlen = 0; /* silence bogus gcc warning */
+ } else {
+ vlen = strlen(vendor);
+ len += sizeof(uint16_t) + vlen;
+ }
-#ifdef VENDOR_SPLIT
- plen = strlen(PACKAGE);
- vlen = strlen(VERSION);
- len += sizeof(uint16_t) + plen + 1 + vlen;
- if (uname(&utn) == 0) {
- unl = strlen(utn.sysname);
- url = strlen(utn.release);
- uml = strlen(utn.machine);
- platform = hardware_platform();
- pl = strlen(platform);
- len += sizeof(uint16_t) + unl + 1 + url;
- len += sizeof(uint16_t) + uml;
- len += sizeof(uint16_t) + pl;
- } else
- unl = 0;
-#else
- vlen = strlen(vendor);
- len += sizeof(uint16_t) + vlen;
-#endif
+ if (len > UINT16_MAX) {
+ syslog(LOG_ERR, "%s: DHCPv6 Vendor Class too big", ifp->name);
+ return 0;
+ }
if (o) {
- o->code = htons(D6_OPTION_VENDOR);
+ o->code = htons(D6_OPTION_VENDOR_CLASS);
o->len = htons(len);
p = D6_OPTION_DATA(o);
- u32 = htonl(DHCPCD_IANA_PEN);
+ u32 = htonl(ifo->vivco_en ? ifo->vivco_en : DHCPCD_IANA_PEN);
memcpy(p, &u32, sizeof(u32));
p += sizeof(u32);
-#ifdef VENDOR_SPLIT
- u16 = htons(plen + 1 + vlen);
- memcpy(p, &u16, sizeof(u16));
- p += sizeof(u16);
- memcpy(p, PACKAGE, plen);
- p += plen;
- *p++ = '-';
- memcpy(p, VERSION, vlen);
- p += vlen;
- if (unl > 0) {
- u16 = htons(unl + 1 + url);
- memcpy(p, &u16, sizeof(u16));
- p += sizeof(u16);
- memcpy(p, utn.sysname, unl);
- p += unl;
- *p++ = '-';
- memcpy(p, utn.release, url);
- p += url;
- u16 = htons(uml);
- memcpy(p, &u16, sizeof(u16));
- p += sizeof(u16);
- memcpy(p, utn.machine, uml);
- p += uml;
- u16 = htons(pl);
+ if (ifo->vivco_en) {
+ for (i = 0, vivco = ifo->vivco;
+ i < ifo->vivco_len;
+ i++, vivco++)
+ {
+ u16 = htons(vivco->len);
+ memcpy(p, &u16, sizeof(u16));
+ p += sizeof(u16);
+ memcpy(p, vivco->data, vivco->len);
+ p += vivco->len;
+ }
+ } else {
+ u16 = htons(vlen);
memcpy(p, &u16, sizeof(u16));
p += sizeof(u16);
- memcpy(p, platform, pl);
+ memcpy(p, vendor, vlen);
}
-#else
- u16 = htons(vlen);
- memcpy(p, &u16, sizeof(u16));
- p += sizeof(u16);
- memcpy(p, vendor, vlen);
-#endif
}
return len;
}
-#endif
static const struct dhcp6_option *
dhcp6_findoption(int code, const uint8_t *d, ssize_t len)
}
static const uint8_t *
-dhcp6_getoption(int *os, int *code, int *len, const uint8_t *od, int ol,
- struct dhcp_opt **oopt)
+dhcp6_getoption(unsigned int *os, unsigned int *code, unsigned int *len,
+ const uint8_t *od, unsigned int ol, struct dhcp_opt **oopt)
{
const struct dhcp6_option *o;
size_t i;
}
o = (const struct dhcp6_option *)od;
*len = ntohs(o->len);
- if (*len < 0 || *len > ol) {
+ if (*len > ol) {
errno = EINVAL;
return NULL;
}
len += sizeof(*state->send);
len += sizeof(*o) + duid_len;
len += sizeof(*o) + sizeof(uint16_t); /* elapsed */
-#ifdef DHCPCD_IANA_PEN
- len += sizeof(*o) + dhcp6_makevendor(NULL);
-#endif
+ len += sizeof(*o) + dhcp6_makevendor(NULL, ifp);
/* IA */
m = NULL;
p = D6_OPTION_DATA(o);
memset(p, 0, sizeof(u16));
-#ifdef DHCPCD_IANA_PEN
o = D6_NEXT_OPTION(o);
- dhcp6_makevendor(o);
-#endif
+ dhcp6_makevendor(o, ifp);
if (state->state == DH6S_DISCOVER &&
!(options & DHCPCD_TEST) &&
{
const struct dhcp6_state *state;
const struct if_options *ifo;
- struct dhcp_opt *opt;
+ struct dhcp_opt *opt, *vo;
const struct dhcp6_option *o;
size_t i, n;
uint16_t ol, oc;
char *v, *val, *pfx;
const struct ipv6_addr *ap;
+ uint32_t en;
state = D6_CSTATE(ifp);
n = 0;
i < ifp->options->dhcp6_override_len;
i++, opt++)
dhcp_zero_index(opt);
+ for (i = 0, opt = vivso; i < vivso_len; i++, opt++)
+ dhcp_zero_index(opt);
i = strlen(prefix) + strlen("_dhcp6") + 1;
pfx = malloc(i);
if (pfx == NULL) {
i++, opt++)
if (opt->option == oc)
break;
+ if (i == ifo->dhcp6_override_len &&
+ oc == D6_OPTION_VENDOR_OPTS &&
+ ol > sizeof(en))
+ {
+ memcpy(&en, D6_COPTION_DATA(o), sizeof(en));
+ en = ntohl(en);
+ vo = vivso_find(en, ifp);
+ } else
+ vo = NULL;
if (i == ifo->dhcp6_override_len) {
for (i = 0, opt = dhcp6_opts;
i < dhcp6_opts_len;
pfx, ifp->name,
opt, dhcp6_getoption, D6_COPTION_DATA(o), ol);
}
+ if (vo) {
+ n += dhcp_envoption(env == NULL ? NULL : &env[n],
+ pfx, ifp->name,
+ vo, dhcp6_getoption,
+ D6_COPTION_DATA(o) + sizeof(en),
+ ol - sizeof(en));
+ }
}
free(pfx);
#define D6_OPTION_UNICAST 12
#define D6_OPTION_STATUS_CODE 13
#define D6_OPTION_RAPID_COMMIT 14
-#define D6_OPTION_VENDOR 16
+#define D6_OPTION_VENDOR_CLASS 16
+#define D6_OPTION_VENDOR_OPTS 17
#define D6_OPTION_SIP_SERVERS_NAME 21
#define D6_OPTION_SIP_SERVERS_ADDRESS 22
#define D6_OPTION_DNS_SERVERS 23
define 57 uint16 dhcp_max_message_size
define 58 request uint32 dhcp_renewal_time
define 59 request uint32 dhcp_rebinding_time
+define 60 binhex vendor_class_identifier
+define 61 binhex dhcp_client_identifier
define 64 string nisplus_domain
define 65 array ipaddress nisplus_servers
define 66 string tftp_server_name
# DHCP Session Initiated Protocol Servers, RFC3361
define 120 rfc3361 sip_server
+# DHCP Vendor-Identifying Vendor Options, RFC3925
+define 124 binhex vivco
+define 125 embed vivso
+embed uint32 enterprise_number
+# Vendor options are shared between DHCP/DHCPv6
+# Their code is matched to the enterprise number defined above
+# see the end of this file for an example
+
# DHCP IPv6 Rapid Deployment on IPv4 Infrastructures, RFC5969
define 212 rfc5969 sixrd
define6 14 norequest flag rapid_commit
define6 15 binhex user_class
-define6 16 binhex vendor_class
-define6 17 binhex vendor_options
+
+define6 16 binhex vivco
+define6 17 embed vivso
+embed uint32 enterprise_number
+# Vendor options are shared between DHCP/DHCPv6
+# Their code is matched to the enterprise number defined above
+# See the end of this file for an example
+
define6 18 binhex interface_id
define6 19 byte reconfigure_msg
define6 20 flag reconfigure_accept
encap 1 ip6address addr
encap 2 ip6address mcast_addr
encap 3 ip6address fqdn
+
+##############################################################################
+# Vendor-Identifying Vendor Options
+# An example:
+#vendopt 12345 encap frobozzco
+#encap 1 string maze_location
+#encap 2 byte grue_probability
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd November 15, 2013
+.Dd December 6, 2013
.Dt DHCPCD 8
.Os
.Sh NAME
.Xr resolvconf 8
.Sh STANDARDS
RFC\ 951 RFC\ 1534 RFC\ 2131, RFC\ 2132, RFC\ 2855, RFC\ 3004, RFC\ 3315,
-RFC\ 3361, RFC\ 3633, RFC\ 3396, RFC\ 3397, RFC\ 3442, RFC\ 3927, RFC\ 4039,
-RFC\ 4075, RFC\ 4242, RFC\ 4361, RFC\ 4390, RFC\ 4702, RFC\ 4704, RFC\ 4861,
-RFC\ 4833, RFC\ 5227, RFC\ 5942, RFC\ 5969, RFC\ 6106.
+RFC\ 3361, RFC\ 3633, RFC\ 3396, RFC\ 3397, RFC\ 3442, RFC\ 3925, RFC\ 3927,
+RFC\ 4039, RFC\ 4075, RFC\ 4242, RFC\ 4361, RFC\ 4390, RFC\ 4702, RFC\ 4704,
+RFC\ 4861, RFC\ 4833, RFC\ 5227, RFC\ 5942, RFC\ 5969, RFC\ 6106.
.Sh AUTHORS
.An Roy Marples Aq Mt roy@marples.name
.Sh BUGS
free_dhcp_opt_embenc(opt);
free(dhcp6_opts);
#endif
+ for (n = 0, opt = vivso; n < vivso_len; n++, opt++)
+ free_dhcp_opt_embenc(opt);
+ free(vivso);
}
static void
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd December 3, 2013
+.Dd December 6, 2013
.Dt DHCPCD.CONF 5
.Os
.Sh NAME
If not set then none is sent.
Some badly configured DHCP servers reject unknown vendorclassids.
To work around it, try and impersonate Windows by using the MSFT vendorclassid.
+.It Ic vendclass Ar en Ar data
+Add the Vendor Indetifying Vendor Class with the IANA assigned Enterprise
+Number
+.Ar en
+with the
+.Ar data .
+This option can be set more than once to add more data, but the behaviour,
+as per
+.Xr RFC 3925
+is undefined if the Enterprise Number differs.
.It Ic waitip Op 4 | 6
Wait for an address to be assigned before forking to the background.
4 means wait for an IPv4 address to be assigned.
.Xr dhcpcd-run-hooks 8 ,
with a prefix of
.Va _dhcp6 .
+.It Ic vendopt Ar code Ar type Ar variable
+Defines the Vendor-Identifying Vendor Options.
+The
+.Ar code
+is the IANA Enterprise Number which will unqiuely describe the encapsulated
+options.
+.Ar type
+is normally
+.Ar encap .
+.Ar variable
+names the Vendor option to be exported.
.It Ic embed Ar type Ar variable
Defines an embedded variable within the defined option.
The length is determined by the
#define O_DEFINE6 O_BASE + 20
#define O_EMBED O_BASE + 21
#define O_ENCAP O_BASE + 22
+#define O_VENDOPT O_BASE + 23
+#define O_VENDCLASS O_BASE + 24
char *dev_load;
{"noipv4", no_argument, NULL, O_NOIPV4},
{"noipv6", no_argument, NULL, O_NOIPV6},
{"noalias", no_argument, NULL, O_NOALIAS},
- {"iaid", no_argument, NULL, O_IAID},
+ {"iaid", required_argument, NULL, O_IAID},
{"ia_na", no_argument, NULL, O_IA_NA},
{"ia_ta", no_argument, NULL, O_IA_TA},
{"ia_pd", no_argument, NULL, O_IA_PD},
{"hostname_short", no_argument, NULL, O_HOSTNAME_SHORT},
{"dev", required_argument, NULL, O_DEV},
{"nodev", no_argument, NULL, O_NODEV},
- {"define", no_argument, NULL, O_DEFINE},
- {"define6", no_argument, NULL, O_DEFINE6},
- {"embed", no_argument, NULL, O_EMBED},
- {"encap", no_argument, NULL, O_ENCAP},
+ {"define", required_argument, NULL, O_DEFINE},
+ {"define6", required_argument, NULL, O_DEFINE6},
+ {"embed", required_argument, NULL, O_EMBED},
+ {"encap", required_argument, NULL, O_ENCAP},
+ {"vendopt", required_argument, NULL, O_VENDOPT},
+ {"vendclass", required_argument, NULL, O_VENDCLASS},
{NULL, 0, NULL, '\0'}
};
/* If processing a string on the clientid, first byte should be
* 0 to indicate a non hardware type */
if (clid && *str) {
- *sbuf++ = 0;
+ if (sbuf)
+ *sbuf++ = 0;
l++;
}
c[3] = '\0';
while (*str) {
- if (++l > slen) {
+ if (++l > slen && sbuf) {
errno = ENOBUFS;
return -1;
}
case '\0':
break;
case 'b':
- *sbuf++ = '\b';
+ if (sbuf)
+ *sbuf++ = '\b';
str++;
break;
case 'n':
- *sbuf++ = '\n';
+ if (sbuf)
+ *sbuf++ = '\n';
str++;
break;
case 'r':
- *sbuf++ = '\r';
+ if (sbuf)
+ *sbuf++ = '\r';
str++;
break;
case 't':
- *sbuf++ = '\t';
+ if (sbuf)
+ *sbuf++ = '\t';
str++;
break;
case 'x':
break;
c[i] = *str++;
}
- if (c[1] != '\0') {
+ if (c[1] != '\0' && sbuf) {
c[2] = '\0';
*sbuf++ = strtol(c, NULL, 16);
} else
break;
c[i] = *str++;
}
- if (c[2] != '\0') {
+ if (c[2] != '\0' && sbuf) {
i = strtol(c, NULL, 8);
if (i > 255)
i = 255;
l--;
break;
default:
- *sbuf++ = *str++;
+ if (sbuf)
+ *sbuf++ = *str;
+ str++;
+ break;
}
- } else
- *sbuf++ = *str++;
+ } else {
+ if (sbuf)
+ *sbuf++ = *str;
+ str++;
+ }
}
if (punt_last) {
- *--sbuf = '\0';
+ if (sbuf)
+ *--sbuf = '\0';
l--;
}
return l;
parse_option(struct if_options *ifo, int opt, const char *arg)
{
int i, l, t;
+ unsigned int u;
char *p = NULL, *fp, *np, **nconf;
ssize_t s;
struct in_addr addr, addr2;
uint8_t *request, *require, *no;
struct dhcp_opt **dop, *ndop;
size_t *dop_len, dl;
+ struct vivco *vivco;
#ifdef INET6
size_t sl;
struct if_ia *ia;
dop = &ifo->dhcp6_override;
dop_len = &ifo->dhcp6_override_len;
}
+ /* FALLTHROUGH */
+ case O_VENDOPT:
+ if (dop == NULL) {
+ dop = &ifo->vivso_override;
+ dop_len = &ifo->vivso_override_len;
+ }
edop = ldop = NULL;
/* FALLTHROUGH */
case O_EMBED:
/* code */
if (opt == O_EMBED) /* Embedded options don't have codes */
- i = 0;
+ u = 0;
else {
fp = strwhite(arg);
if (!fp) {
return -1;
}
*fp++ = '\0';
- if ((i = atoint(arg)) == -1)
+ errno = 0;
+ u = strtoul(arg, &np, 0);
+ if (u > UINT32_MAX || errno != 0 || *np != '\0') {
+ syslog(LOG_ERR, "invalid code: %s", arg);
return -1;
+ }
arg = strskipwhite(fp);
}
/* type */
ndop = &(*dop)[dl];
/* type 0 seems freshly malloced struct
* for us to use */
- if (ndop->option == i || ndop->type == 0)
+ if (ndop->option == u || ndop->type == 0)
break;
}
}
ndop->encopts_len = 0;
} else
free_dhcp_opt_embenc(ndop);
- ndop->option = i; /* could have been 0 */
+ ndop->option = u; /* could have been 0 */
ndop->type = t;
ndop->len = l;
ndop->var = np;
/* Save the define for embed and encap options */
- if (opt == O_DEFINE || opt == O_DEFINE6)
+ if (opt == O_DEFINE || opt == O_DEFINE6 || opt == O_VENDOPT)
ldop = ndop;
else if (opt == O_ENCAP)
edop = ndop;
break;
+ case O_VENDCLASS:
+ fp = strwhite(arg);
+ if (fp)
+ *fp++ = '\0';
+ errno = 0;
+ u = strtoul(arg, &np, 0);
+ if (u > UINT32_MAX || errno != 0 || *np != '\0') {
+ syslog(LOG_ERR, "invalid code: %s", arg);
+ return -1;
+ }
+ if (fp) {
+ s = parse_string(NULL, 0, fp);
+ if (s == -1) {
+ syslog(LOG_ERR, "%s: %m", __func__);
+ return -1;
+ }
+ if (s + (sizeof(uint16_t) * 2) > UINT16_MAX) {
+ syslog(LOG_ERR, "vendor class is too big");
+ return -1;
+ }
+ np = malloc(s);
+ if (np == NULL) {
+ syslog(LOG_ERR, "%s: %m", __func__);
+ return -1;
+ }
+ parse_string(np, s, fp);
+ } else {
+ s = 0;
+ np = NULL;
+ }
+ vivco = realloc(ifo->vivco, ifo->vivco_len + 1);
+ if (vivco == NULL) {
+ syslog(LOG_ERR, "%s: %m", __func__);
+ return -1;
+ }
+ ifo->vivco = vivco;
+ ifo->vivco_en = u;
+ vivco = &ifo->vivco[ifo->vivco_len++];
+ vivco->len = s;
+ vivco->data = (uint8_t *)np;
+ break;
default:
return 0;
}
#endif
ifo->dhcp6_override = NULL;
ifo->dhcp6_override_len = 0;
+
+ vivso = ifo->vivso_override;
+ vivso_len = ifo->vivso_override_len;
+ ifo->vivso_override = NULL;
+ ifo->vivso_override_len = 0;
}
/* Parse our options file */
for (i = 0, opt = ifo->dhcp6_override;
i < ifo->dhcp6_override_len;
i++, opt++)
+ free_dhcp_opt_embenc(opt);
+ free(ifo->dhcp6_override);
+ for (i = 0, opt = ifo->vivso_override;
+ i < ifo->vivso_override_len;
+ i++, opt++)
+ free_dhcp_opt_embenc(opt);
free(ifo->dhcp6_override);
#ifdef INET6
#endif
};
+struct vivco {
+ uint16_t len;
+ uint8_t *data;
+};
+
struct if_options {
uint8_t iaid[4];
int metric;
size_t dhcp_override_len;
struct dhcp_opt *dhcp6_override;
size_t dhcp6_override_len;
+ uint32_t vivco_en;
+ struct vivco *vivco;
+ size_t vivco_len;
+ struct dhcp_opt *vivso_override;
+ size_t vivso_override_len;
};
extern unsigned long long options;