From 8563be22c8d9e3cf38b26d69d52368c68ad3a6dd Mon Sep 17 00:00:00 2001 From: Hans Dedecker Date: Mon, 30 Dec 2013 14:58:10 +0100 Subject: [PATCH] Support for SOL_MAX_RT and INF_MAX_RT options (RFC7083) --- src/dhcpv6.c | 66 ++++++++++++++++++++++++++++++++++++++------------- src/odhcp6c.c | 4 ++-- src/odhcp6c.h | 11 +++++++++ 3 files changed, 63 insertions(+), 18 deletions(-) diff --git a/src/dhcpv6.c b/src/dhcpv6.c index 8d65219..7fdf4f6 100644 --- a/src/dhcpv6.c +++ b/src/dhcpv6.c @@ -43,6 +43,10 @@ #define DHCPV6_DUID_LLADDR 3 #define DHCPV6_REQ_DELAY 1 +#define DHCPV6_SOL_MAX_RT_MIN 60 +#define DHCPV6_SOL_MAX_RT_MAX 86400 +#define DHCPV6_INF_MAX_RT_MIN 60 +#define DHCPV6_INF_MAX_RT_MAX 86400 static bool dhcpv6_response_is_valid(const void *buf, ssize_t len, const uint8_t transaction[3], enum dhcpv6_msg type, @@ -74,17 +78,17 @@ static int dhcpv6_commit_advert(void); static struct dhcpv6_retx dhcpv6_retx[_DHCPV6_MSG_MAX] = { [DHCPV6_MSG_UNKNOWN] = {false, 1, 120, 0, "", dhcpv6_handle_reconfigure, NULL}, - [DHCPV6_MSG_SOLICIT] = {true, 1, 3600, 0, "SOLICIT", + [DHCPV6_MSG_SOLICIT] = {true, 1, DHCPV6_SOL_MAX_RT, 0, "SOLICIT", dhcpv6_handle_advert, dhcpv6_commit_advert}, - [DHCPV6_MSG_REQUEST] = {true, 1, 30, 10, "REQUEST", + [DHCPV6_MSG_REQUEST] = {true, 1, DHCPV6_REQ_MAX_RT, 10, "REQUEST", dhcpv6_handle_reply, NULL}, - [DHCPV6_MSG_RENEW] = {false, 10, 600, 0, "RENEW", + [DHCPV6_MSG_RENEW] = {false, 10, DHCPV6_REN_MAX_RT, 0, "RENEW", dhcpv6_handle_reply, NULL}, - [DHCPV6_MSG_REBIND] = {false, 10, 600, 0, "REBIND", + [DHCPV6_MSG_REBIND] = {false, 10, DHCPV6_REB_MAX_RT, 0, "REBIND", 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, 120, 0, "INFOREQ", + [DHCPV6_MSG_INFO_REQ] = {true, 1, DHCPV6_INF_MAX_RT, 0, "INFOREQ", dhcpv6_handle_reply, NULL}, }; @@ -166,6 +170,8 @@ int init_dhcpv6(const char *ifname, int request_pd, int sol_timeout) htons(DHCPV6_OPT_NTP_SERVER), htons(DHCPV6_OPT_AFTR_NAME), htons(DHCPV6_OPT_PD_EXCLUDE), + htons(DHCPV6_OPT_SOL_MAX_RT), + htons(DHCPV6_OPT_INF_MAX_RT), #ifdef EXT_PREFIX_CLASS htons(DHCPV6_OPT_PREFIX_CLASS), #endif @@ -673,7 +679,8 @@ static int dhcpv6_handle_advert(enum dhcpv6_msg orig, const int rc, uint16_t olen, otype; uint8_t *odata, pref = 0; struct dhcpv6_server_cand cand = {false, false, 0, 0, {0}, - IN6ADDR_ANY_INIT, NULL, NULL, 0, 0}; + IN6ADDR_ANY_INIT, DHCPV6_SOL_MAX_RT, + DHCPV6_INF_MAX_RT, NULL, NULL, 0, 0}; bool have_na = false; int have_pd = 0; @@ -694,17 +701,9 @@ static int dhcpv6_handle_advert(enum dhcpv6_msg orig, const int rc, switch (error) { case DHCPV6_NoPrefixAvail: // Status code on global level - if (pd_mode == IA_MODE_FORCE) - return -1; cand.preference -= 2000; break; - case DHCPV6_NoAddrsAvail: - // Status code on global level - if (na_mode == IA_MODE_FORCE) - return -1; - break; - default : break; } @@ -715,6 +714,16 @@ static int dhcpv6_handle_advert(enum dhcpv6_msg orig, const int rc, cand.server_addr = *(struct in6_addr *)odata; } else if (otype == DHCPV6_OPT_RECONF_ACCEPT) { 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 && + 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 && + inf_max_rt <= DHCPV6_INF_MAX_RT_MAX) + cand.inf_max_rt = inf_max_rt; } else if (otype == DHCPV6_OPT_IA_PD && request_prefix) { struct dhcpv6_ia_hdr *h = (struct dhcpv6_ia_hdr*)&odata[-4]; uint8_t *oend = odata + olen, *d; @@ -735,8 +744,16 @@ 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)) + (!have_pd && pd_mode == IA_MODE_FORCE)) { + /* + * 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 + */ + dhcpv6_retx[DHCPV6_MSG_SOLICIT].max_timeo = cand.sol_max_rt; + dhcpv6_retx[DHCPV6_MSG_INFO_REQ].max_timeo = cand.inf_max_rt; return -1; + } if (na_mode != IA_MODE_NONE && !have_na) { cand.has_noaddravail = true; @@ -910,7 +927,17 @@ static int dhcpv6_handle_reply(enum dhcpv6_msg orig, _unused const int rc, odhcp6c_get_state(STATE_AFTR_NAME, &cur_len); if (cur_len == 0) odhcp6c_add_state(STATE_AFTR_NAME, odata, olen); - } else if (otype != DHCPV6_OPT_CLIENTID && + } 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 && + 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 && + 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 && otype != DHCPV6_OPT_SERVERID) { odhcp6c_add_state(STATE_CUSTOM_OPTS, &odata[-4], olen + 4); @@ -1281,6 +1308,10 @@ int dhcpv6_promote_server_cand(void) if (cand->has_noaddravail && na_mode == IA_MODE_TRY) { na_mode = IA_MODE_NONE; + + dhcpv6_retx[DHCPV6_MSG_SOLICIT].max_timeo = cand->sol_max_rt; + dhcpv6_retx[DHCPV6_MSG_INFO_REQ].max_timeo = cand->inf_max_rt; + return dhcpv6_request(DHCPV6_MSG_SOLICIT); } @@ -1302,6 +1333,9 @@ int dhcpv6_promote_server_cand(void) ret = DHCPV6_STATEFUL; } + 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; diff --git a/src/odhcp6c.c b/src/odhcp6c.c index c8d40f6..de452c0 100644 --- a/src/odhcp6c.c +++ b/src/odhcp6c.c @@ -69,7 +69,7 @@ int main(_unused int argc, char* const argv[]) enum odhcp6c_ia_mode ia_na_mode = IA_MODE_TRY; enum odhcp6c_ia_mode ia_pd_mode = IA_MODE_TRY; static struct in6_addr ifid = IN6ADDR_ANY_INIT; - int sol_timeout = 120; + int sol_timeout = DHCPV6_SOL_MAX_RT; #ifdef EXT_BFD_PING int bfd_interval = 0, bfd_loss = 3; @@ -318,7 +318,7 @@ int main(_unused int argc, char* const argv[]) else if (do_signal > 0) break; // Other signal type - // If we have any IAs, send renew, otherwise request + // Send renew as T1 expired res = dhcpv6_request(DHCPV6_MSG_RENEW); odhcp6c_signal_process(); if (res > 0) { // Renew was succesfull diff --git a/src/odhcp6c.h b/src/odhcp6c.h index 15be59a..a33a92e 100644 --- a/src/odhcp6c.h +++ b/src/odhcp6c.h @@ -24,6 +24,13 @@ #define ND_OPT_RECURSIVE_DNS 25 #define ND_OPT_DNSSL 31 +#define DHCPV6_SOL_MAX_RT 3600 +#define DHCPV6_REQ_MAX_RT 30 +#define DHCPV6_CNF_MAX_RT 4 +#define DHCPV6_REN_MAX_RT 600 +#define DHCPV6_REB_MAX_RT 600 +#define DHCPV6_INF_MAX_RT 3600 + enum dhcvp6_opt { DHCPV6_OPT_CLIENTID = 1, DHCPV6_OPT_SERVERID = 2, @@ -50,6 +57,8 @@ enum dhcvp6_opt { DHCPV6_OPT_SIP_SERVER_A = 22, DHCPV6_OPT_AFTR_NAME = 64, DHCPV6_OPT_PD_EXCLUDE = 67, + DHCPV6_OPT_SOL_MAX_RT = 82, + DHCPV6_OPT_INF_MAX_RT = 83, #ifdef EXT_PREFIX_CLASS /* draft-bhandari-dhc-class-based-prefix, not yet standardized */ DHCPV6_OPT_PREFIX_CLASS = EXT_PREFIX_CLASS, @@ -166,6 +175,8 @@ struct dhcpv6_server_cand { uint8_t duid_len; uint8_t duid[130]; struct in6_addr server_addr; + uint32_t sol_max_rt; + uint32_t inf_max_rt; void *ia_na; void *ia_pd; size_t ia_na_len; -- 2.39.2