const struct dhcp_lease *lease = &state->lease;
char hbuf[HOSTNAME_MAX_LEN + 1];
const char *hostname;
- const struct vivco *vivco;
int mtu;
#ifdef AUTH
uint8_t *auth, auth_len;
p += ifo->mudurl[0] + 1;
}
+#ifndef SMALL
if (ifo->vivco_len &&
!has_option_mask(ifo->nomask, DHO_VIVCO))
{
- AREA_CHECK(sizeof(ul));
- *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++)
- {
- AREA_FIT(vivco->len);
- if (vivco->len + 2 + *lp > 255) {
- logerrx("%s: VIVCO option too big",
- ifp->name);
- free(bootp);
- return -1;
- }
- *p++ = (uint8_t)vivco->len;
- memcpy(p, vivco->data, vivco->len);
- p += vivco->len;
+ struct vivco *vivco = ifo->vivco;
+ size_t vlen = ifo->vivco_len;
+ struct rfc3396_ctx rctx = {
+ .code = DHO_VIVCO,
+ .buf = &p,
+ .buflen = AREA_LEFT,
+ };
+
+ for (; vlen > 0; vivco++, vlen--) {
+ ul = htonl(vivco->en);
+ if (rfc3396_write(&rctx, &ul, sizeof(ul)) == -1)
+ goto toobig;
+ lp = rfc3396_zero(&rctx);
+ if (lp == NULL)
+ goto toobig;
+ if (rfc3396_write_byte(&rctx,
+ (uint8_t)vivco->len) == -1)
+ goto toobig;
+ if (rfc3396_write(&rctx,
+ vivco->data, vivco->len) == -1)
+ goto toobig;
*lp = (uint8_t)(*lp + vivco->len + 1);
}
}
-
-#ifndef SMALL
+
if (ifo->vsio_len &&
!has_option_mask(ifo->nomask, DHO_VIVSO))
{
return sizeof(o) + olen;
}
+#ifndef SMALL
+/* DHCPv6 Option 16 (Vendor Class Option) */
static size_t
dhcp6_makevendor(void *data, const struct interface *ifp)
{
const struct if_options *ifo;
- size_t len, vlen, i;
+ size_t len = 0, optlen, vlen, i;
uint8_t *p;
const struct vivco *vivco;
struct dhcp6_option o;
ifo = ifp->options;
- len = sizeof(uint32_t); /* IANA PEN */
- if (ifo->vivco_en) {
- vlen = 0;
+ if (ifo->vivco_len > 0) {
for (i = 0, vivco = ifo->vivco;
i < ifo->vivco_len;
i++, vivco++)
- vlen += sizeof(uint16_t) + vivco->len;
- len += vlen;
+ len += sizeof(o) + sizeof(uint32_t) + sizeof(uint16_t) + vivco->len;
} else if (ifo->vendorclassid[0] != '\0') {
/* dhcpcd owns DHCPCD_IANA_PEN.
* If you need your own string, get your own IANA PEN. */
vlen = strlen(ifp->ctx->vendor);
- len += sizeof(uint16_t) + vlen;
+ len += sizeof(o) + sizeof(uint32_t) + sizeof(uint16_t) + vlen;
} else
return 0;
uint16_t hvlen;
p = data;
- o.code = htons(D6_OPTION_VENDOR_CLASS);
- o.len = htons((uint16_t)len);
- memcpy(p, &o, sizeof(o));
- p += sizeof(o);
- pen = htonl(ifo->vivco_en ? ifo->vivco_en : DHCPCD_IANA_PEN);
- memcpy(p, &pen, sizeof(pen));
- p += sizeof(pen);
- if (ifo->vivco_en) {
+ if (ifo->vivco_len > 0) {
for (i = 0, vivco = ifo->vivco;
i < ifo->vivco_len;
- i++, vivco++)
- {
+ i++, vivco++) {
+ optlen = sizeof(uint32_t) + sizeof(uint16_t) + vivco->len;
+ o.code = htons(D6_OPTION_VENDOR_CLASS);
+ o.len = htons((uint16_t)optlen);
+ memcpy(p, &o, sizeof(o));
+ p += sizeof(o);
+ pen = htonl(vivco->en);
+ memcpy(p, &pen, sizeof(pen));
+ p += sizeof(pen);
hvlen = htons((uint16_t)vivco->len);
memcpy(p, &hvlen, sizeof(hvlen));
p += sizeof(hvlen);
p += vivco->len;
}
} else if (ifo->vendorclassid[0] != '\0') {
+ o.code = htons(D6_OPTION_VENDOR_CLASS);
+ o.len = htons((uint16_t)len);
+ memcpy(p, &o, sizeof(o));
+ p += sizeof(o);
+ pen = htonl(DHCPCD_IANA_PEN);
+ memcpy(p, &pen, sizeof(pen));
+ p += sizeof(pen);
hvlen = htons((uint16_t)vlen);
memcpy(p, &hvlen, sizeof(hvlen));
p += sizeof(hvlen);
memcpy(p, ifp->ctx->vendor, vlen);
}
}
-
- return sizeof(o) + len;
+ return len;
}
-#ifndef SMALL
/* DHCPv6 Option 17 (Vendor-Specific Information Option) */
static size_t
dhcp6_makevendoropts(void *data, const struct interface *ifp)
if (!has_option_mask(ifo->nomask6, D6_OPTION_USER_CLASS))
len += dhcp6_makeuser(NULL, ifp);
- if (!has_option_mask(ifo->nomask6, D6_OPTION_VENDOR_CLASS))
- len += dhcp6_makevendor(NULL, ifp);
#ifndef SMALL
+ if (!has_option_mask(ifo->nomask6, D6_OPTION_VENDOR_CLASS))
+ len += dhcp6_makevendor(NULL, ifp);
if (!has_option_mask(ifo->nomask6, D6_OPTION_VENDOR_OPTS))
len += dhcp6_makevendoropts(NULL, ifp);
#endif
if (!has_option_mask(ifo->nomask6, D6_OPTION_USER_CLASS))
p += dhcp6_makeuser(p, ifp);
- if (!has_option_mask(ifo->nomask6, D6_OPTION_VENDOR_CLASS))
- p += dhcp6_makevendor(p, ifp);
#ifndef SMALL
+ if (!has_option_mask(ifo->nomask6, D6_OPTION_VENDOR_CLASS))
+ p += dhcp6_makevendor(p, ifp);
if (!has_option_mask(ifo->nomask6, D6_OPTION_VENDOR_OPTS))
p += dhcp6_makevendoropts(p, ifp);
#endif
struct dhcp_opt **dop, *ndop;
size_t *dop_len, dl, odl;
struct vivco *vivco;
+ const struct vivco *vivco_endp = ifo->vivco + ifo->vivco_len;
struct group *grp;
#ifdef AUTH
struct token *token;
break;
case O_VENDCLASS:
ARG_REQUIRED;
+#ifdef SMALL
+ logwarnx("%s: vendor options not compiled in", ifname);
+ return -1;
+#else
fp = strwhite(arg);
if (fp)
*fp++ = '\0';
logerrx("invalid code: %s", arg);
return -1;
}
+ for (vivco = ifo->vivco; vivco != vivco_endp; vivco++) {
+ if (vivco->en == (uint32_t)u) {
+ logerrx("vendor class option for enterprise number %u already defined", vivco->en);
+ return -1;
+ }
+ }
fp = strskipwhite(fp);
if (fp) {
s = parse_string(NULL, 0, fp);
return -1;
}
ifo->vivco = vivco;
- ifo->vivco_en = (uint32_t)u;
vivco = &ifo->vivco[ifo->vivco_len++];
+ vivco->en = (uint32_t)u;
vivco->len = dl;
vivco->data = (uint8_t *)np;
break;
+#endif
case O_AUTHPROTOCOL:
ARG_REQUIRED;
#ifdef AUTH
opt++, ifo->dhcp6_override_len--)
free_dhcp_opt_embenc(opt);
free(ifo->dhcp6_override);
+#ifndef SMALL
for (vo = ifo->vivco;
ifo->vivco_len > 0;
vo++, ifo->vivco_len--)
free(vo->data);
free(ifo->vivco);
-#ifndef SMALL
for (vsio = ifo->vsio;
ifo->vsio_len > 0;
vsio++, ifo->vsio_len--)