+ parsed_ia++;
+ }
+ }
+ return parsed_ia;
+}
+
+
+static int dhcpv6_calc_refresh_timers(void)
+{
+ struct odhcp6c_entry *e;
+ size_t ia_na_entries, ia_pd_entries, i;
+ int64_t l_t1 = UINT32_MAX, l_t2 = UINT32_MAX, l_t3 = 0;
+
+ e = odhcp6c_get_state(STATE_IA_NA, &ia_na_entries);
+ ia_na_entries /= sizeof(*e);
+ for (i = 0; i < ia_na_entries; i++) {
+ if (e[i].t1 < l_t1)
+ l_t1 = e[i].t1;
+
+ if (e[i].t2 < l_t2)
+ l_t2 = e[i].t2;
+
+ if (e[i].valid > l_t3)
+ l_t3 = e[i].valid;
+ }
+
+ e = odhcp6c_get_state(STATE_IA_PD, &ia_pd_entries);
+ ia_pd_entries /= sizeof(*e);
+ for (i = 0; i < ia_pd_entries; i++) {
+ if (e[i].t1 < l_t1)
+ l_t1 = e[i].t1;
+
+ if (e[i].t2 < l_t2)
+ l_t2 = e[i].t2;
+
+ if (e[i].valid > l_t3)
+ l_t3 = e[i].valid;
+ }
+
+ if (ia_pd_entries || ia_na_entries) {
+ t1 = l_t1;
+ t2 = l_t2;
+ t3 = l_t3;
+ }
+
+ return (int)(ia_pd_entries + ia_na_entries);
+}
+
+
+static void dhcpv6_log_status_code(const uint16_t code, const char *scope,
+ const void *status_msg, const int len)
+{
+ uint8_t buf[len + 3];
+
+ memset(buf, 0, sizeof(buf));
+ if (len) {
+ buf[0] = '(';
+ memcpy(&buf[1], status_msg, len);
+ buf[len + 1] = ')';
+ }
+
+ syslog(LOG_WARNING, "Server returned %s status %i %s",
+ scope, code, buf);
+}
+
+
+static void dhcpv6_handle_status_code(const enum dhcpv6_msg orig,
+ const uint16_t code, const void *status_msg, const int len,
+ int *ret)
+{
+ dhcpv6_log_status_code(code, "message", status_msg, len);
+
+ switch (code) {
+ case DHCPV6_UnspecFail:
+ // Generic failure
+ *ret = 0;
+ break;
+
+ case DHCPV6_UseMulticast:
+ switch(orig) {
+ case DHCPV6_MSG_REQUEST:
+ case DHCPV6_MSG_RENEW:
+ case DHCPV6_MSG_RELEASE:
+ case DHCPV6_MSG_DECLINE:
+ // Message needs to be retransmitted according to RFC3315 chapter 18.1.8
+ server_addr = in6addr_any;
+ *ret = 0;
+ break;
+ default:
+ break;
+ }
+ break;
+
+ case DHCPV6_NoAddrsAvail:
+ case DHCPV6_NoPrefixAvail:
+ if (orig == DHCPV6_MSG_REQUEST)
+ *ret = 0; // Failure
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+static void dhcpv6_handle_ia_status_code(const enum dhcpv6_msg orig,
+ const struct dhcpv6_ia_hdr *ia_hdr, const uint16_t code,
+ const void *status_msg, const int len,
+ bool handled_status_codes[_DHCPV6_Status_Max], int *ret)
+{
+ dhcpv6_log_status_code(code, ia_hdr->type == DHCPV6_OPT_IA_NA ?
+ "IA_NA" : "IA_PD", status_msg, len);
+
+ switch (code) {
+ case DHCPV6_NoBinding:
+ switch (orig) {
+ case DHCPV6_MSG_RENEW:
+ case DHCPV6_MSG_REBIND:
+ if ((*ret > 0) && !handled_status_codes[code])
+ *ret = dhcpv6_request(DHCPV6_MSG_REQUEST);
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case DHCPV6_NoAddrsAvail:
+ case DHCPV6_NoPrefixAvail:
+ switch (orig) {
+ case DHCPV6_MSG_REQUEST:
+ if (*ret != 0)
+ *ret = 0;
+ break;
+ default:
+ break;