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;
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 + ia_pd_len),
+ htons(sizeof(hdr_ia_pd) - 4),
1, 0, 0
};
.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);
- } 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;
ia_pd_len = sizeof(pref);
+ hdr_ia_pd.len = htons(ntohs(hdr_ia_pd.len) + ia_pd_len);
}
// 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 + ia_na_len),
+ 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);
+ 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)
continue;
+ bool error = false;
uint16_t stype, slen;
uint8_t *sdata;
// Test status and bail if error
stype, slen, sdata)
if (stype == DHCPV6_OPT_STATUS && slen >= 2 &&
(sdata[0] || sdata[1]))
- continue;
+ error = true;
+
+ if (error)
+ continue;
// Update times
if (l_t1 > 0 && t1 > 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;