static bool dhcpv6_response_is_valid(const void *buf, ssize_t len,
const uint8_t transaction[3], enum dhcpv6_msg type);
-static time_t dhcpv6_parse_ia(void *opt, void *end);
+static uint32_t dhcpv6_parse_ia(void *opt, void *end);
static reply_handler dhcpv6_handle_reply;
static reply_handler dhcpv6_handle_advert;
// Sockets
static int sock = -1;
static int ifindex = -1;
-static time_t t1 = 0, t2 = 0, t3 = 0;
+static int64_t t1 = 0, t2 = 0, t3 = 0;
// IA states
static int request_prefix = -1;
htons(DHCPV6_OPT_DNS_DOMAIN),
htons(DHCPV6_OPT_NTP_SERVER),
htons(DHCPV6_OPT_SIP_SERVER_A),
- htons(DHCPV6_OPT_SIP_SERVER_D)};
+ htons(DHCPV6_OPT_PREFIX_CLASS)
+ };
odhcp6c_add_state(STATE_ORO, oro, sizeof(oro));
void *srv_id = odhcp6c_get_state(STATE_SERVER_ID, &srv_id_len);
// Build IA_PDs
- size_t ia_pd_entry_len, ia_pd_len = 0;
+ size_t ia_pd_entries, ia_pd_len = 0;
void *ia_pd = NULL;
- void *ia_pd_entries = odhcp6c_get_state(STATE_IA_PD, &ia_pd_entry_len);
+ struct odhcp6c_entry *e = odhcp6c_get_state(STATE_IA_PD, &ia_pd_entries);
+ ia_pd_entries /= sizeof(*e);
struct dhcpv6_ia_hdr hdr_ia_pd = {
htons(DHCPV6_OPT_IA_PD),
htons(sizeof(hdr_ia_pd) - 4),
.len = htons(25), .prefix = request_prefix
};
- if (ia_pd_entry_len > 0) {
- struct odhcp6c_entry *e = ia_pd_entries;
- size_t entries = ia_pd_entry_len / sizeof(*e);
- struct dhcpv6_ia_prefix p[entries];
- for (size_t i = 0; i < entries; ++i) {
- p[i].type = htons(DHCPV6_OPT_IA_PREFIX);
- p[i].len = htons(sizeof(p[i]) - 4U);
- p[i].preferred = htonl(e[i].preferred);
- p[i].valid = htonl(e[i].valid);
- p[i].prefix = e[i].length;
- p[i].addr = e[i].target;
- }
- ia_pd = p;
- ia_pd_len = sizeof(p);
- hdr_ia_pd.len = htons(ntohs(hdr_ia_pd.len) + ia_pd_len);
- } else if (request_prefix > 0 &&
+
+ struct dhcpv6_ia_prefix p[ia_pd_entries];
+ for (size_t i = 0; i < ia_pd_entries; ++i) {
+ p[i].type = htons(DHCPV6_OPT_IA_PREFIX);
+ p[i].len = htons(sizeof(p[i]) - 4U);
+ p[i].preferred = 0;
+ p[i].valid = 0;
+ p[i].prefix = e[i].length;
+ p[i].addr = e[i].target;
+ }
+ ia_pd = p;
+ ia_pd_len = sizeof(p);
+ hdr_ia_pd.len = htons(ntohs(hdr_ia_pd.len) + ia_pd_len);
+
+ if (request_prefix > 0 &&
(type == DHCPV6_MSG_SOLICIT ||
type == DHCPV6_MSG_REQUEST)) {
ia_pd = &pref;
}
// Build IA_NAs
- size_t ia_na_entry_len, ia_na_len = 0;
+ size_t ia_na_entries, ia_na_len = 0;
void *ia_na = NULL;
- void *ia_na_entries = odhcp6c_get_state(STATE_IA_NA, &ia_na_entry_len);
+ e = odhcp6c_get_state(STATE_IA_NA, &ia_na_entries);
+ ia_na_entries /= sizeof(*e);
+
struct dhcpv6_ia_hdr hdr_ia_na = {
htons(DHCPV6_OPT_IA_NA),
htons(sizeof(hdr_ia_na) - 4),
1, 0, 0
};
- if (ia_na_entry_len > 0) {
- struct odhcp6c_entry *e = ia_na_entries;
- size_t entries = ia_na_entry_len / sizeof(*e);
- struct dhcpv6_ia_addr p[entries];
- for (size_t i = 0; i < entries; ++i) {
- p[i].type = htons(DHCPV6_OPT_IA_ADDR);
- p[i].len = htons(sizeof(p[i]) - 4U);
- p[i].addr = e[i].target;
- p[i].preferred = htonl(e[i].preferred);
- p[i].valid = htonl(e[i].valid);
- }
- ia_na = p;
- ia_na_len = sizeof(p);
- hdr_ia_na.len = htons(ntohs(hdr_ia_na.len) + ia_na_len);
+ struct dhcpv6_ia_addr pa[ia_na_entries];
+ for (size_t i = 0; i < ia_na_entries; ++i) {
+ pa[i].type = htons(DHCPV6_OPT_IA_ADDR);
+ pa[i].len = htons(sizeof(pa[i]) - 4U);
+ pa[i].addr = e[i].target;
+ pa[i].preferred = 0;
+ pa[i].valid = 0;
}
+ ia_na = pa;
+ ia_na_len = sizeof(pa);
+ hdr_ia_na.len = htons(ntohs(hdr_ia_na.len) + ia_na_len);
+
// Reconfigure Accept
struct {
uint16_t type;
cand.preference -= 2000;
} else if (otype == DHCPV6_OPT_PREF && olen >= 1 &&
cand.preference >= 0) {
- cand.preference = odata[1];
+ cand.preference = odata[0];
} else if (otype == DHCPV6_OPT_RECONF_ACCEPT) {
cand.wants_reconfigure = true;
} else if (otype == DHCPV6_OPT_IA_PD && request_prefix) {
if (t3 < 0)
t3 = 0;
} else {
- t1 = t2 = t3 = 86400;
+ t1 = t2 = t3 = UINT32_MAX;
}
if (opt) {
if ((otype == DHCPV6_OPT_IA_PD || otype == DHCPV6_OPT_IA_NA)
&& olen > sizeof(struct dhcpv6_ia_hdr)) {
struct dhcpv6_ia_hdr *ia_hdr = (void*)(&odata[-4]);
- time_t l_t1 = ntohl(ia_hdr->t1);
- time_t l_t2 = ntohl(ia_hdr->t2);
+ uint32_t l_t1 = ntohl(ia_hdr->t1);
+ uint32_t l_t2 = ntohl(ia_hdr->t2);
// Test ID and T1-T2 validity
if (ia_hdr->iaid != 1 || l_t2 < l_t1)
if (l_t2 > 0 && t2 > l_t2)
t2 = l_t2;
- time_t n = dhcpv6_parse_ia(&ia_hdr[1], odata + olen);
+ uint32_t n = dhcpv6_parse_ia(&ia_hdr[1], odata + olen);
if (n < t1)
t1 = n;
if (n < t3)
t3 = n;
+ if (t2 >= t3)
+ t2 = 8 * t3 / 10;
+
+ if (t1 >= t2)
+ t1 = 5 * t2 / 8;
+
} else if (otype == DHCPV6_OPT_DNS_SERVERS) {
if (olen % 16 == 0)
odhcp6c_add_state(STATE_DNS, odata, olen);
}
-static time_t dhcpv6_parse_ia(void *opt, void *end)
+static uint32_t dhcpv6_parse_ia(void *opt, void *end)
{
uint32_t timeout = UINT32_MAX; // Minimum timeout
uint16_t otype, olen;
uint8_t *odata;
- struct odhcp6c_entry entry = {IN6ADDR_ANY_INIT,
- 0, 0, IN6ADDR_ANY_INIT, 0, 0};
-
// Update address IA
dhcpv6_for_each_option(opt, end, otype, olen, odata) {
+ struct odhcp6c_entry entry = {IN6ADDR_ANY_INIT,
+ 0, 0, IN6ADDR_ANY_INIT, 0, 0, 0};
+
if (otype == DHCPV6_OPT_IA_PREFIX) {
struct dhcpv6_ia_prefix *prefix = (void*)&odata[-4];
if (olen + 4U < sizeof(*prefix))
entry.length = prefix->prefix;
entry.target = prefix->addr;
+ uint16_t stype, slen;
+ uint8_t *sdata;
+
+ // Find prefix class, if any
+ dhcpv6_for_each_option(odata, 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);
} else if (otype == DHCPV6_OPT_IA_ADDR) {