// IA states
static enum odhcp6c_ia_mode na_mode = IA_MODE_NONE, pd_mode = IA_MODE_NONE;
+static bool stateful_only_mode = false;
static bool accept_reconfig = false;
// Server unicast address
static struct in6_addr server_addr = IN6ADDR_ANY_INIT;
static char *dhcpv6_msg_to_str(enum dhcpv6_msg msg)
{
- static char *dhcpv6_msg_str[] = {
- "UNKNOWN",
- "SOLICIT",
- "ADVERTISE",
- "REQUEST",
- "RENEW",
- "REBIND",
- "REPLY",
- "DECLINE",
- "RECONFIGURE",
- "INFORMATION REQUEST",
- };
+ switch (msg) {
+ case DHCPV6_MSG_SOLICIT:
+ return "SOLICIT";
+
+ case DHCPV6_MSG_ADVERT:
+ return "ADVERTISE";
+
+ case DHCPV6_MSG_REQUEST:
+ return "REQUEST";
+
+ case DHCPV6_MSG_RENEW:
+ return "RENEW";
+
+ case DHCPV6_MSG_REBIND:
+ return "REBIND";
+
+ case DHCPV6_MSG_REPLY:
+ return "REPLY";
+
+ case DHCPV6_MSG_RELEASE:
+ return "RELEASE";
+
+ case DHCPV6_MSG_DECLINE:
+ return "DECLINE";
- if (msg < _DHCPV6_MSG_MAX)
- return dhcpv6_msg_str[msg];
+ case DHCPV6_MSG_RECONF:
+ return "RECONFIGURE";
+
+ case DHCPV6_MSG_INFO_REQ:
+ return "INFORMATION REQUEST";
+
+ default:
+ break;
+ }
+
+ return "UNKNOWN";
+}
+
+static char *dhcpv6_status_code_to_str(uint16_t code)
+{
+ switch (code) {
+ case DHCPV6_Success:
+ return "Success";
+
+ case DHCPV6_UnspecFail:
+ return "Unspecified Failure";
+
+ case DHCPV6_NoAddrsAvail:
+ return "No Address Available";
+
+ case DHCPV6_NoBinding:
+ return "No Binding";
+
+ case DHCPV6_NotOnLink:
+ return "Not On Link";
+
+ case DHCPV6_UseMulticast:
+ return "Use Multicast";
+
+ case DHCPV6_NoPrefixAvail:
+ return "No Prefix Available";
+
+ default:
+ break;
+ }
return "Unknown";
}
IOV_TOTAL
};
-int dhcpv6_set_ia_mode(enum odhcp6c_ia_mode na, enum odhcp6c_ia_mode pd)
+int dhcpv6_set_ia_mode(enum odhcp6c_ia_mode na, enum odhcp6c_ia_mode pd, bool stateful_only)
{
int mode = DHCPV6_UNKNOWN;
na_mode = na;
pd_mode = pd;
+ stateful_only_mode = stateful_only;
if (na_mode == IA_MODE_NONE && pd_mode == IA_MODE_NONE)
mode = DHCPV6_STATELESS;
{
int ret = dhcpv6_request(DHCPV6_MSG_UNKNOWN);
- if (ret != -1)
+ switch (ret) {
+ /*
+ * Only RENEW/REBIND/INFORMATION REQUEST
+ * message transmission can be requested
+ * by a RECONFIGURE
+ */
+ case DHCPV6_MSG_RENEW:
+ case DHCPV6_MSG_REBIND:
+ case DHCPV6_MSG_INFO_REQ:
ret = dhcpv6_request(ret);
+ break;
+
+ default:
+ break;
+ }
return ret;
}
if (msg != DHCPV6_MSG_UNKNOWN)
dhcpv6_handle_reply(orig, rc, NULL, NULL, NULL);
- return (msg == DHCPV6_MSG_UNKNOWN? -1: 1);
+ return (msg == DHCPV6_MSG_UNKNOWN? -1: (int)msg);
}
// Collect all advertised servers
}
}
- if ((!have_na && na_mode == IA_MODE_FORCE) ||
+ if ((stateful_only_mode && !have_na && !have_pd) ||
+ (!have_na && na_mode == IA_MODE_FORCE) ||
(!have_pd && pd_mode == IA_MODE_FORCE)) {
/*
* RFC7083 states to process the SOL_MAX_RT and
unsigned int updated_IAs = 0;
bool handled_status_codes[_DHCPV6_Status_Max] = { false, };
- odhcp6c_expire();
+ odhcp6c_expire(true);
if (orig == DHCPV6_MSG_UNKNOWN) {
static time_t last_update = 0;
t1 = ntohl(ia_hdr->t1);
t2 = ntohl(ia_hdr->t2);
- if (t1 > t2)
+ if (t1 > t2 && t1 > 0 && t2 > 0)
return 0;
- syslog(LOG_INFO, "IAID %04x T1 %d T2 %d", htonl(ia_hdr->iaid), t1, t2);
+ syslog(LOG_INFO, "%s %04x T1 %d T2 %d", ntohs(ia_hdr->type) == DHCPV6_OPT_IA_PD ? "IA_PD" : "IA_NA", ntohl(ia_hdr->iaid), t1, t2);
// Update address IA
dhcpv6_for_each_option(&ia_hdr[1], end, otype, olen, odata) {
{
struct odhcp6c_entry *e;
size_t ia_na_entries, ia_pd_entries, i;
+ size_t invalid_entries = 0;
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++) {
+ /* Exclude invalid IA_NA entries */
+ if (!e[i].valid) {
+ invalid_entries++;
+ continue;
+ }
+
if (e[i].t1 < l_t1)
l_t1 = e[i].t1;
ia_pd_entries /= sizeof(*e);
for (i = 0; i < ia_pd_entries; i++) {
+ /* Exclude invalid IA_PD entries */
+ if (!e[i].valid) {
+ invalid_entries++;
+ continue;
+ }
+
if (e[i].t1 < l_t1)
l_t1 = e[i].t1;
l_t3 = e[i].valid;
}
- if (ia_pd_entries || ia_na_entries) {
+ if (ia_pd_entries + ia_na_entries - invalid_entries) {
t1 = l_t1;
t2 = l_t2;
t3 = l_t3;
*dst = 0;
- syslog(LOG_WARNING, "Server returned %s status %i %s",
- scope, code, buf);
+ syslog(LOG_WARNING, "Server returned %s status '%s %s'",
+ scope, dhcpv6_status_code_to_str(code), buf);
}
static void dhcpv6_handle_status_code(const enum dhcpv6_msg orig,