X-Git-Url: https://git.decadent.org.uk/gitweb/?p=odhcp6c.git;a=blobdiff_plain;f=src%2Fdhcpv6.c;h=4b1ba957b21fcbc3d18c0030a0bc2acb915ec07b;hp=42e512161161ae43cdab56927c1e1f1fadf1645f;hb=c291def1cadf58c0aa10c18a53c2fc4d2dee1ad6;hpb=efb1a99e7cbaf9841226bb7564d07a76411a2552 diff --git a/src/dhcpv6.c b/src/dhcpv6.c index 42e5121..4b1ba95 100644 --- a/src/dhcpv6.c +++ b/src/dhcpv6.c @@ -1,5 +1,5 @@ /** - * Copyright (C) 2012-2013 Steven Barth + * Copyright (C) 2012-2014 Steven Barth * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License v2 as published by @@ -76,19 +76,19 @@ static int dhcpv6_commit_advert(void); // RFC 3315 - 5.5 Timeout and Delay values static struct dhcpv6_retx dhcpv6_retx[_DHCPV6_MSG_MAX] = { [DHCPV6_MSG_UNKNOWN] = {false, 1, 120, 0, "", - dhcpv6_handle_reconfigure, NULL}, + dhcpv6_handle_reconfigure, NULL}, [DHCPV6_MSG_SOLICIT] = {true, 1, DHCPV6_SOL_MAX_RT, 0, "SOLICIT", - dhcpv6_handle_advert, dhcpv6_commit_advert}, + dhcpv6_handle_advert, dhcpv6_commit_advert}, [DHCPV6_MSG_REQUEST] = {true, 1, DHCPV6_REQ_MAX_RT, 10, "REQUEST", - dhcpv6_handle_reply, NULL}, + dhcpv6_handle_reply, NULL}, [DHCPV6_MSG_RENEW] = {false, 10, DHCPV6_REN_MAX_RT, 0, "RENEW", - dhcpv6_handle_reply, NULL}, + dhcpv6_handle_reply, NULL}, [DHCPV6_MSG_REBIND] = {false, 10, DHCPV6_REB_MAX_RT, 0, "REBIND", - dhcpv6_handle_rebind_reply, NULL}, + dhcpv6_handle_rebind_reply, NULL}, [DHCPV6_MSG_RELEASE] = {false, 1, 0, 5, "RELEASE", NULL, NULL}, [DHCPV6_MSG_DECLINE] = {false, 1, 0, 5, "DECLINE", NULL, NULL}, [DHCPV6_MSG_INFO_REQ] = {true, 1, DHCPV6_INF_MAX_RT, 0, "INFOREQ", - dhcpv6_handle_reply, NULL}, + dhcpv6_handle_reply, NULL}, }; @@ -105,10 +105,13 @@ static bool accept_reconfig = false; // Reconfigure key static uint8_t reconf_key[16]; +// client options +static unsigned int client_options = 0; -int init_dhcpv6(const char *ifname, int request_pd, int sol_timeout) + +int init_dhcpv6(const char *ifname, unsigned int options, int sol_timeout) { - request_prefix = request_pd; + client_options = options; dhcpv6_retx[DHCPV6_MSG_SOLICIT].max_timeo = sol_timeout; sock = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP); @@ -158,11 +161,13 @@ int init_dhcpv6(const char *ifname, int request_pd, int sol_timeout) } // Create ORO - uint16_t oro[] = { + if (!(client_options & DHCPV6_STRICT_OPTIONS)) { + 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_SNTP_SERVERS), htons(DHCPV6_OPT_NTP_SERVER), htons(DHCPV6_OPT_AFTR_NAME), htons(DHCPV6_OPT_PD_EXCLUDE), @@ -171,8 +176,9 @@ int init_dhcpv6(const char *ifname, int request_pd, int sol_timeout) #ifdef EXT_PREFIX_CLASS htons(DHCPV6_OPT_PREFIX_CLASS), #endif - }; - odhcp6c_add_state(STATE_ORO, oro, sizeof(oro)); + }; + odhcp6c_add_state(STATE_ORO, oro, sizeof(oro)); + } // Configure IPv6-options int val = 1; @@ -198,7 +204,6 @@ void dhcpv6_set_ia_mode(enum odhcp6c_ia_mode na, enum odhcp6c_ia_mode pd) pd_mode = pd; } - static void dhcpv6_send(enum dhcpv6_msg type, uint8_t trid[3], uint32_t ecs) { // Build FQDN @@ -227,62 +232,112 @@ static void dhcpv6_send(enum dhcpv6_msg type, uint8_t trid[3], uint32_t ecs) // Build IA_PDs size_t ia_pd_entries, ia_pd_len = 0; - 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), - 1, 0, 0 - }; + uint8_t *ia_pd; + if (type == DHCPV6_MSG_SOLICIT) { + odhcp6c_clear_state(STATE_IA_PD); + size_t n_prefixes; + struct odhcp6c_request_prefix *request_prefixes = odhcp6c_get_state(STATE_IA_PD_INIT, &n_prefixes); + n_prefixes /= sizeof(struct odhcp6c_request_prefix); + + ia_pd = alloca(n_prefixes * (sizeof(struct dhcpv6_ia_hdr) + sizeof(struct dhcpv6_ia_prefix))); + + for (size_t i = 0; i < n_prefixes; i++) { + struct dhcpv6_ia_hdr hdr_ia_pd = { + htons(DHCPV6_OPT_IA_PD), + htons(sizeof(hdr_ia_pd) - 4 + sizeof(struct dhcpv6_ia_prefix)), + request_prefixes[i].iaid, 0, 0 + }; + struct dhcpv6_ia_prefix pref = { + .type = htons(DHCPV6_OPT_IA_PREFIX), + .len = htons(25), .prefix = request_prefixes[i].length + }; + memcpy(ia_pd + ia_pd_len, &hdr_ia_pd, sizeof(hdr_ia_pd)); + ia_pd_len += sizeof(hdr_ia_pd); + memcpy(ia_pd + ia_pd_len, &pref, sizeof(pref)); + ia_pd_len += sizeof(pref); + } + } else { + struct odhcp6c_entry *e = odhcp6c_get_state(STATE_IA_PD, &ia_pd_entries); + ia_pd_entries /= sizeof(*e); + + // we're too lazy to count our distinct IAIDs, + // so just allocate maximally needed space + ia_pd = alloca(ia_pd_entries * (sizeof(struct dhcpv6_ia_prefix) + 10 + + sizeof(struct dhcpv6_ia_hdr))); + + for (size_t i = 0; i < ia_pd_entries; ++i) { + uint32_t iaid = e[i].iaid; + + // check if this is an unprocessed IAID and skip if not. + int new_iaid = 1; + for (int j = i-1; j >= 0; j--) { + if (e[j].iaid == iaid) { + new_iaid = 0; + break; + } + } - uint8_t *ia_pd = alloca(ia_pd_entries * (sizeof(struct dhcpv6_ia_prefix) + 10)); - for (size_t i = 0; i < ia_pd_entries; ++i) { - uint8_t ex_len = 0; - if (e[i].priority > 0) - ex_len = ((e[i].priority - e[i].length - 1) / 8) + 6; + if (!new_iaid) + continue; - struct dhcpv6_ia_prefix p = { - .type = htons(DHCPV6_OPT_IA_PREFIX), - .len = htons(sizeof(p) - 4U + ex_len), - .prefix = e[i].length, - .addr = e[i].target - }; + // construct header + struct dhcpv6_ia_hdr hdr_ia_pd = { + htons(DHCPV6_OPT_IA_PD), + htons(sizeof(hdr_ia_pd) - 4), + iaid, 0, 0 + }; - memcpy(ia_pd + ia_pd_len, &p, sizeof(p)); - ia_pd_len += sizeof(p); + memcpy(ia_pd + ia_pd_len, &hdr_ia_pd, sizeof(hdr_ia_pd)); + struct dhcpv6_ia_hdr *hdr = (struct dhcpv6_ia_hdr *) (ia_pd + ia_pd_len); + ia_pd_len += sizeof(hdr_ia_pd); - if (ex_len) { - ia_pd[ia_pd_len++] = 0; - ia_pd[ia_pd_len++] = DHCPV6_OPT_PD_EXCLUDE; - ia_pd[ia_pd_len++] = 0; - ia_pd[ia_pd_len++] = ex_len - 4; - ia_pd[ia_pd_len++] = e[i].priority; + for (size_t j = i; j < ia_pd_entries; j++) { + if (e[j].iaid != iaid) + continue; - uint32_t excl = ntohl(e[i].router.s6_addr32[1]); - excl >>= (64 - e[i].priority); - excl <<= 8 - ((e[i].priority - e[i].length) % 8); + uint8_t ex_len = 0; + if (e[j].priority > 0) + ex_len = ((e[j].priority - e[j].length - 1) / 8) + 6; + + struct dhcpv6_ia_prefix p = { + .type = htons(DHCPV6_OPT_IA_PREFIX), + .len = htons(sizeof(p) - 4U + ex_len), + .prefix = e[j].length, + .addr = e[j].target + }; + + memcpy(ia_pd + ia_pd_len, &p, sizeof(p)); + ia_pd_len += sizeof(p); + + if (ex_len) { + ia_pd[ia_pd_len++] = 0; + ia_pd[ia_pd_len++] = DHCPV6_OPT_PD_EXCLUDE; + ia_pd[ia_pd_len++] = 0; + ia_pd[ia_pd_len++] = ex_len - 4; + ia_pd[ia_pd_len++] = e[j].priority; + + uint32_t excl = ntohl(e[j].router.s6_addr32[1]); + excl >>= (64 - e[j].priority); + excl <<= 8 - ((e[j].priority - e[j].length) % 8); + + for (size_t i = ex_len - 5; i > 0; --i, excl >>= 8) + ia_pd[ia_pd_len + i] = excl & 0xff; + ia_pd_len += ex_len - 5; + } - for (size_t i = ex_len - 5; i > 0; --i, excl >>= 8) - ia_pd[ia_pd_len + i] = excl & 0xff; - ia_pd_len += ex_len - 5; + hdr->len = htons(ntohs(hdr->len) + ntohs(p.len) + 4U); + } } } - struct dhcpv6_ia_prefix pref = { - .type = htons(DHCPV6_OPT_IA_PREFIX), - .len = htons(25), .prefix = request_prefix - }; - if (request_prefix > 0 && ia_pd_len == 0 && type == DHCPV6_MSG_SOLICIT) { - ia_pd = (uint8_t*)&pref; - ia_pd_len = sizeof(pref); - } - hdr_ia_pd.len = htons(ntohs(hdr_ia_pd.len) + ia_pd_len); + if (ia_pd_entries > 0) + request_prefix = 1; // Build IA_NAs size_t ia_na_entries, ia_na_len = 0; void *ia_na = NULL; - e = odhcp6c_get_state(STATE_IA_NA, &ia_na_entries); + struct odhcp6c_entry *e = odhcp6c_get_state(STATE_IA_NA, &ia_na_entries); ia_na_entries /= sizeof(*e); struct dhcpv6_ia_hdr hdr_ia_na = { @@ -313,6 +368,21 @@ static void dhcpv6_send(enum dhcpv6_msg type, uint8_t trid[3], uint32_t ecs) // Request Information Refresh uint16_t oro_refresh = htons(DHCPV6_OPT_INFO_REFRESH); + // Build vendor-class option + size_t vendor_class_len, user_class_len; + struct dhcpv6_vendorclass *vendor_class = odhcp6c_get_state(STATE_VENDORCLASS, &vendor_class_len); + void *user_class = odhcp6c_get_state(STATE_USERCLASS, &user_class_len); + + struct { + uint16_t type; + uint16_t length; + } vendor_class_hdr = {htons(DHCPV6_OPT_VENDOR_CLASS), htons(vendor_class_len)}; + + struct { + uint16_t type; + uint16_t length; + } user_class_hdr = {htons(DHCPV6_OPT_USER_CLASS), htons(user_class_len)}; + // Prepare Header size_t oro_len; void *oro = odhcp6c_get_state(STATE_ORO, &oro_len); @@ -337,35 +407,42 @@ static void dhcpv6_send(enum dhcpv6_msg type, uint8_t trid[3], uint32_t ecs) {&oro_refresh, 0}, {cl_id, cl_id_len}, {srv_id, srv_id_len}, + {&vendor_class_hdr, vendor_class_len ? sizeof(vendor_class_hdr) : 0}, + {vendor_class, vendor_class_len}, + {&user_class_hdr, user_class_len ? sizeof(user_class_hdr) : 0}, + {user_class, user_class_len}, {&reconf_accept, sizeof(reconf_accept)}, {&fqdn, fqdn_len}, {&hdr_ia_na, sizeof(hdr_ia_na)}, {ia_na, ia_na_len}, - {&hdr_ia_pd, sizeof(hdr_ia_pd)}, {ia_pd, ia_pd_len}, }; size_t cnt = ARRAY_SIZE(iov); if (type == DHCPV6_MSG_INFO_REQ) { - cnt = 5; + cnt = 9; iov[2].iov_len = sizeof(oro_refresh); hdr.oro_len = htons(oro_len + sizeof(oro_refresh)); } else if (!request_prefix) { - cnt = 9; + cnt = 13; } // Disable IAs if not used if (type != DHCPV6_MSG_SOLICIT) { - iov[5].iov_len = 0; + iov[7].iov_len = 0; if (ia_na_len == 0) - iov[7].iov_len = 0; - if (ia_pd_len == 0) iov[9].iov_len = 0; } if (na_mode == IA_MODE_NONE) + iov[9].iov_len = 0; + + if (!(client_options & DHCPV6_ACCEPT_RECONFIGURE)) iov[7].iov_len = 0; + if (!(client_options & DHCPV6_CLIENT_FQDN)) + iov[8].iov_len = 0; + struct sockaddr_in6 srv = {AF_INET6, htons(DHCPV6_SERVER_PORT), 0, ALL_DHCPV6_RELAYS, ifindex}; struct msghdr msg = {&srv, sizeof(srv), iov, cnt, NULL, 0, 0}; @@ -397,9 +474,9 @@ int dhcpv6_request(enum dhcpv6_msg type) if (type == DHCPV6_MSG_UNKNOWN) timeout = t1; else if (type == DHCPV6_MSG_RENEW) - timeout = (t2 > t1) ? t2 - t1 : 0; + timeout = (t2 > t1) ? t2 - t1 : ((t1 == UINT32_MAX) ? UINT32_MAX : 0); else if (type == DHCPV6_MSG_REBIND) - timeout = (t3 > t2) ? t3 - t2 : 0; + timeout = (t3 > t2) ? t3 - t2 : ((t2 == UINT32_MAX) ? UINT32_MAX : 0); if (timeout == 0) return -1; @@ -437,8 +514,8 @@ int dhcpv6_request(enum dhcpv6_msg type) uint64_t round_end = round_start + rto; elapsed = round_start - start; - // Don't wait too long - if (round_end - start > timeout * 1000) + // Don't wait too long if timeout differs from infinite + if ((timeout != UINT32_MAX) && (round_end - start > timeout * 1000)) round_end = timeout * 1000 + start; // Built and send package @@ -465,9 +542,9 @@ int dhcpv6_request(enum dhcpv6_msg type) // Set timeout for receiving uint64_t t = round_end - round_start; - struct timeval timeout = {t / 1000, (t % 1000) * 1000}; + struct timeval tv = {t / 1000, (t % 1000) * 1000}; setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, - &timeout, sizeof(timeout)); + &tv, sizeof(tv)); // Receive cycle len = recvmsg(sock, &msg, 0); @@ -512,8 +589,8 @@ int dhcpv6_request(enum dhcpv6_msg type) // Allow if (retx->handler_finish) len = retx->handler_finish(); - } while (len < 0 && ((elapsed / 1000 < timeout) && (!retx->max_rc || rc < retx->max_rc))); - + } while (len < 0 && ((timeout == UINT32_MAX) || (elapsed / 1000 < timeout)) && + (!retx->max_rc || rc < retx->max_rc)); return len; } @@ -564,7 +641,7 @@ static bool dhcpv6_response_is_valid(const void *buf, ssize_t len, if (r->protocol != 3 || r->algorithm != 1 || r->reconf_type != 2) continue; - md5_state_t md5; + md5_ctx_t md5; uint8_t serverhash[16], secretbytes[16], hash[16]; memcpy(serverhash, r->key, sizeof(serverhash)); memset(r->key, 0, sizeof(r->key)); @@ -573,20 +650,20 @@ static bool dhcpv6_response_is_valid(const void *buf, ssize_t len, for (size_t i = 0; i < sizeof(secretbytes); ++i) secretbytes[i] ^= 0x36; - md5_init(&md5); - md5_append(&md5, secretbytes, sizeof(secretbytes)); - md5_append(&md5, buf, len); - md5_finish(&md5, hash); + md5_begin(&md5); + md5_hash(secretbytes, sizeof(secretbytes), &md5); + md5_hash(buf, len, &md5); + md5_end(hash, &md5); for (size_t i = 0; i < sizeof(secretbytes); ++i) { secretbytes[i] ^= 0x36; secretbytes[i] ^= 0x5c; } - md5_init(&md5); - md5_append(&md5, secretbytes, sizeof(secretbytes)); - md5_append(&md5, hash, 16); - md5_finish(&md5, hash); + md5_begin(&md5); + md5_hash(secretbytes, sizeof(secretbytes), &md5); + md5_hash(hash, 16, &md5); + md5_end(hash, &md5); rcauth_ok = !memcmp(hash, serverhash, sizeof(hash)); } else if (otype == DHCPV6_OPT_RECONF_MESSAGE && olen == 1) { @@ -688,12 +765,12 @@ static int dhcpv6_handle_advert(enum dhcpv6_msg orig, const int rc, cand.wants_reconfigure = true; } else if (otype == DHCPV6_OPT_SOL_MAX_RT && olen == 4) { uint32_t sol_max_rt = ntohl(*((uint32_t *)odata)); - if (sol_max_rt >= DHCPV6_SOL_MAX_RT_MIN && + if (sol_max_rt >= DHCPV6_SOL_MAX_RT_MIN && sol_max_rt <= DHCPV6_SOL_MAX_RT_MAX) cand.sol_max_rt = sol_max_rt; } else if (otype == DHCPV6_OPT_INF_MAX_RT && olen == 4) { uint32_t inf_max_rt = ntohl(*((uint32_t *)odata)); - if (inf_max_rt >= DHCPV6_INF_MAX_RT_MIN && + if (inf_max_rt >= DHCPV6_INF_MAX_RT_MIN && inf_max_rt <= DHCPV6_INF_MAX_RT_MAX) cand.inf_max_rt = inf_max_rt; } else if (otype == DHCPV6_OPT_IA_PD && request_prefix) { @@ -717,8 +794,8 @@ static int dhcpv6_handle_advert(enum dhcpv6_msg orig, const int rc, if ((!have_na && na_mode == IA_MODE_FORCE) || (!have_pd && pd_mode == IA_MODE_FORCE)) { - /* - * RFC7083 states to process the SOL_MAX_RT and + /* + * RFC7083 states to process the SOL_MAX_RT and * INF_MAX_RT options even if the DHCPv6 server * did not propose any IA_NA and/or IA_PD */ @@ -784,9 +861,14 @@ static int dhcpv6_handle_reply(enum dhcpv6_msg orig, _unused const int rc, uint32_t elapsed = (last_update > 0) ? now - last_update : 0; last_update = now; - t1 -= elapsed; - t2 -= elapsed; - t3 -= elapsed; + if (t1 != UINT32_MAX) + t1 -= elapsed; + + if (t2 != UINT32_MAX) + t2 -= elapsed; + + if (t3 != UINT32_MAX) + t3 -= elapsed; if (t1 < 0) t1 = 0; @@ -808,7 +890,8 @@ static int dhcpv6_handle_reply(enum dhcpv6_msg orig, _unused const int rc, odhcp6c_clear_state(STATE_DNS); odhcp6c_clear_state(STATE_SEARCH); odhcp6c_clear_state(STATE_SNTP_IP); - odhcp6c_clear_state(STATE_SNTP_FQDN); + odhcp6c_clear_state(STATE_NTP_IP); + odhcp6c_clear_state(STATE_NTP_FQDN); odhcp6c_clear_state(STATE_SIP_IP); odhcp6c_clear_state(STATE_SIP_FQDN); odhcp6c_clear_state(STATE_AFTR_NAME); @@ -821,7 +904,7 @@ static int dhcpv6_handle_reply(enum dhcpv6_msg orig, _unused const int rc, struct dhcpv6_ia_hdr *ia_hdr = (void*)(&odata[-4]); // Test ID - if (ia_hdr->iaid != 1) + if (ia_hdr->iaid != 1 && otype == DHCPV6_OPT_IA_NA) continue; uint16_t code = DHCPV6_Success; @@ -865,6 +948,9 @@ static int dhcpv6_handle_reply(enum dhcpv6_msg orig, _unused const int rc, odhcp6c_add_state(STATE_DNS, odata, olen); } else if (otype == DHCPV6_OPT_DNS_DOMAIN) { odhcp6c_add_state(STATE_SEARCH, odata, olen); + } else if (otype == DHCPV6_OPT_SNTP_SERVERS) { + if (olen % 16 == 0) + odhcp6c_add_state(STATE_SNTP_IP, odata, olen); } else if (otype == DHCPV6_OPT_NTP_SERVER) { uint16_t stype, slen; uint8_t *sdata; @@ -873,10 +959,10 @@ static int dhcpv6_handle_reply(enum dhcpv6_msg orig, _unused const int rc, stype, slen, sdata) { if (slen == 16 && (stype == NTP_MC_ADDR || stype == NTP_SRV_ADDR)) - odhcp6c_add_state(STATE_SNTP_IP, + odhcp6c_add_state(STATE_NTP_IP, sdata, slen); else if (slen > 0 && stype == NTP_SRV_FQDN) - odhcp6c_add_state(STATE_SNTP_FQDN, + odhcp6c_add_state(STATE_NTP_FQDN, sdata, slen); } } else if (otype == DHCPV6_OPT_SIP_SERVER_A) { @@ -899,12 +985,12 @@ static int dhcpv6_handle_reply(enum dhcpv6_msg orig, _unused const int rc, odhcp6c_add_state(STATE_AFTR_NAME, odata, olen); } else if (otype == DHCPV6_OPT_SOL_MAX_RT && olen == 4) { uint32_t sol_max_rt = ntohl(*((uint32_t *)odata)); - if (sol_max_rt >= DHCPV6_SOL_MAX_RT_MIN && + if (sol_max_rt >= DHCPV6_SOL_MAX_RT_MIN && sol_max_rt <= DHCPV6_SOL_MAX_RT_MAX) dhcpv6_retx[DHCPV6_MSG_SOLICIT].max_timeo = sol_max_rt; } else if (otype == DHCPV6_OPT_INF_MAX_RT && olen == 4) { uint32_t inf_max_rt = ntohl(*((uint32_t *)odata)); - if (inf_max_rt >= DHCPV6_INF_MAX_RT_MIN && + if (inf_max_rt >= DHCPV6_INF_MAX_RT_MIN && inf_max_rt <= DHCPV6_INF_MAX_RT_MAX) dhcpv6_retx[DHCPV6_MSG_INFO_REQ].max_timeo = inf_max_rt; }else if (otype != DHCPV6_OPT_CLIENTID && @@ -968,7 +1054,9 @@ static int dhcpv6_parse_ia(void *opt, void *end) // Update address IA dhcpv6_for_each_option(&ia_hdr[1], end, otype, olen, odata) { struct odhcp6c_entry entry = {IN6ADDR_ANY_INIT, 0, 0, - IN6ADDR_ANY_INIT, 0, 0, 0, 0, 0}; + IN6ADDR_ANY_INIT, 0, 0, 0, 0, 0, 0}; + + entry.iaid = ia_hdr->iaid; if (otype == DHCPV6_OPT_IA_PREFIX) { struct dhcpv6_ia_prefix *prefix = (void*)&odata[-4]; @@ -992,7 +1080,7 @@ static int dhcpv6_parse_ia(void *opt, void *end) uint8_t *sdata; #ifdef EXT_PREFIX_CLASS - // Find prefix class, if any + // Find prefix class, if any dhcpv6_for_each_option(&prefix[1], odata + olen, stype, slen, sdata) if (stype == DHCPV6_OPT_PREFIX_CLASS && slen == 2) @@ -1116,6 +1204,8 @@ static int dhcpv6_calc_refresh_timers(void) t1 = l_t1; t2 = l_t2; t3 = l_t3; + } else { + t1 = 600; } return (int)(ia_pd_entries + ia_na_entries); @@ -1253,7 +1343,8 @@ int dhcpv6_promote_server_cand(void) size_t cand_len; struct dhcpv6_server_cand *cand = odhcp6c_get_state(STATE_SERVER_CAND, &cand_len); uint16_t hdr[2]; - int ret = DHCPV6_STATELESS; + int ret = (na_mode == IA_MODE_NONE && pd_mode == IA_MODE_NONE) ? + DHCPV6_STATELESS : DHCPV6_STATEFUL; // Clear lingering candidate state info odhcp6c_clear_state(STATE_SERVER_ID); @@ -1292,7 +1383,7 @@ int dhcpv6_promote_server_cand(void) dhcpv6_retx[DHCPV6_MSG_SOLICIT].max_timeo = cand->sol_max_rt; dhcpv6_retx[DHCPV6_MSG_INFO_REQ].max_timeo = cand->inf_max_rt; - + odhcp6c_remove_state(STATE_SERVER_CAND, 0, sizeof(*cand)); return ret;