* SNTP_FQDN A space-separated list of SNTP server FQDNs
* SIP_IP A space-separated list of SIP servers
* SIP_DOMAIN A space-separated list of SIP domains
- * OPTION_<num> Custom option received as base-16
+ * OPTION_<num> Custom option received as base-16
* PREFIXES A space-separated list of prefixes currently assigned
- Format: <prefix>/<length>,preferred,valid[,cls]
- Format: <prefix>/<length>,preferred,valid[,excluded=<excluded-prefix>/<length>]
++ Format: <prefix>/<length>,preferred,valid[,excluded=<excluded-prefix>/<length>][,class=<prefix class #>]
* ADDRESSES A space-separated list of addresses currently assigned
Format: <address>/<length>,preferred,valid
- * RA_ADDRESSES A space-separated list of addresses from RA-prefixes
+ * RA_ADDRESSES A space-separated list of addresses from RA-prefixes
Format: <address>/<length>,preferred,valid
* RA_ROUTES A space-separated list of routes from the RA
Format: <address>/<length>,gateway,valid,metric
}
// Create ORO
- uint16_t oro[] = {htons(DHCPV6_OPT_DNS_SERVERS),
+ uint16_t oro[] = {
+ htons(DHCPV6_OPT_SIP_SERVER_D),
+ htons(DHCPV6_OPT_SIP_SERVER_A),
+ htons(DHCPV6_OPT_DNS_SERVERS),
htons(DHCPV6_OPT_DNS_DOMAIN),
htons(DHCPV6_OPT_NTP_SERVER),
- htons(DHCPV6_OPT_PREFIX_CLASS)
- };
+ htons(DHCPV6_OPT_SIP_SERVER_A),
+ htons(DHCPV6_OPT_AFTR_NAME),
+ htons(DHCPV6_OPT_PD_EXCLUDE),
++ htons(DHCPV6_OPT_PREFIX_CLASS),
+ };
odhcp6c_add_state(STATE_ORO, oro, sizeof(oro));
entry.length = prefix->prefix;
entry.target = prefix->addr;
+ uint16_t stype, slen;
+ uint8_t *sdata;
+
+ // Find prefix class, if any
+ dhcpv6_for_each_option(&prefix[1], odata + olen,
+ stype, slen, sdata)
+ if (stype == DHCPV6_OPT_PREFIX_CLASS && slen == 2)
+ entry.prefix_class = ntohs(*((uint16_t*)sdata));
- odhcp6c_update_entry(STATE_IA_PD, &entry);
+ // Parse PD-exclude
+ bool ok = true;
- uint16_t stype, slen;
- uint8_t *sdata;
+ dhcpv6_for_each_option(odata + sizeof(*prefix) - 4U,
+ odata + olen, stype, slen, sdata) {
+ if (stype != DHCPV6_OPT_PD_EXCLUDE || slen < 2)
+ continue;
+
+ uint8_t elen = sdata[0];
+ if (elen > 64)
+ elen = 64;
+
+ if (elen <= 32 || elen <= entry.length) {
+ ok = false;
+ continue;
+ }
+
+
+ uint8_t bytes = ((elen - entry.length - 1) / 8) + 1;
+ if (slen <= bytes) {
+ ok = false;
+ continue;
+ }
+
+ uint32_t exclude = 0;
+ do {
+ exclude = exclude << 8 | sdata[bytes];
+ } while (--bytes);
+
+ exclude >>= 8 - ((elen - entry.length) % 8);
+ exclude <<= 64 - elen;
+
+ // Abusing router & priority fields for exclusion
+ entry.router = entry.target;
+ entry.router.s6_addr32[1] |= htonl(exclude);
+ entry.priority = elen;
+ }
+
+ if (ok)
+ odhcp6c_update_entry(STATE_IA_PD, &entry);
+
+ entry.priority = 0;
+ memset(&entry.router, 0, sizeof(entry.router));
} else if (otype == DHCPV6_OPT_IA_ADDR) {
struct dhcpv6_ia_addr *addr = (void*)&odata[-4];
if (olen + 4U < sizeof(*addr))
DHCPV6_OPT_NTP_SERVER = 56,
DHCPV6_OPT_SIP_SERVER_D = 21,
DHCPV6_OPT_SIP_SERVER_A = 22,
-
+ DHCPV6_OPT_AFTR_NAME = 64,
+ DHCPV6_OPT_PD_EXCLUDE = 67,
+ /* draft-bhandari-dhc-class-based-prefix */
+ DHCPV6_OPT_PREFIX_CLASS = 200, /* NOT STANDARDIZED! */
};
enum dhcpv6_opt_npt {
bool found = false;
uint8_t buf[1500];
struct nd_router_advert *adv = (struct nd_router_advert*)buf;
- struct odhcp6c_entry entry = {IN6ADDR_ANY_INIT, 0, 0, IN6ADDR_ANY_INIT, 0, 0};
+ struct odhcp6c_entry entry = {IN6ADDR_ANY_INIT, 0, 0, IN6ADDR_ANY_INIT, 0, 0, 0};
const struct in6_addr any = IN6ADDR_ANY_INIT;
- odhcp6c_expire();
while (true) {
struct sockaddr_in6 from;
buf_len += snprintf(&buf[buf_len], 12, ",%u", e[i].priority);
} else {
buf_len += snprintf(&buf[buf_len], 24, ",%u,%u", e[i].preferred, e[i].valid);
- if (e[i].prefix_class)
- buf_len += snprintf(&buf[buf_len], 12, ",%u", e[i].prefix_class);
+ }
++ if (type == ENTRY_PREFIX && e[i].prefix_class) {
++ buf_len += snprintf(&buf[buf_len], 12, ",class=%u", e[i].prefix_class);
++ }
+
+ if (type == ENTRY_PREFIX && e[i].priority) {
+ // priority and router are abused for prefix exclusion
+ buf_len += snprintf(&buf[buf_len], 12, ",excluded=");
+ inet_ntop(AF_INET6, &e[i].router, &buf[buf_len], INET6_ADDRSTRLEN);
+ buf_len += strlen(&buf[buf_len]);
+ buf_len += snprintf(&buf[buf_len], 24, "/%u", e[i].priority);
}
}
buf[buf_len++] = ' ';