summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans Dedecker2013-10-23 12:04:27 +0000
committerSteven Barth2013-10-23 17:21:54 +0000
commit0c764d13ba834d6be53c4312007584613dec3a1e (patch)
treef3cf0e4e1d1e232f48f704486cf0b6c137c3a6d6
parent24c064ccbf819f85c8709ea60acb3b278377b408 (diff)
downloadodhcp6c-0c764d13ba834d6be53c4312007584613dec3a1e.tar.gz
odhcp6c: preference and status code support in advertise
The patch implements handling of advertise messages as described in RFC3315 paragraph 17.1.2. Client will stop collecting advertise messages if preference option is equal to 255 or if the first RT has elapsed. Status codes are handled in the advertise message depending on the startup parameters Signed-off-by: Hans Dedecker <hans.dedecker@gmail.com>
-rw-r--r--src/dhcpv6.c39
1 files changed, 29 insertions, 10 deletions
diff --git a/src/dhcpv6.c b/src/dhcpv6.c
index 08e3225..d212dec 100644
--- a/src/dhcpv6.c
+++ b/src/dhcpv6.c
@@ -574,11 +574,11 @@ static int dhcpv6_handle_reconfigure(_unused enum dhcpv6_msg orig, const int rc,
// Collect all advertised servers
-static int dhcpv6_handle_advert(enum dhcpv6_msg orig, _unused const int rc,
+static int dhcpv6_handle_advert(enum dhcpv6_msg orig, const int rc,
const void *opt, const void *end)
{
uint16_t olen, otype;
- uint8_t *odata;
+ uint8_t *odata, pref = 0;
struct dhcpv6_server_cand cand = {false, false, 0, 0, {0}, NULL, NULL, 0, 0};
bool have_na = false;
int have_pd = 0;
@@ -594,12 +594,29 @@ static int dhcpv6_handle_advert(enum dhcpv6_msg orig, _unused const int rc,
if (otype == DHCPV6_OPT_SERVERID && olen <= 130) {
memcpy(cand.duid, odata, olen);
cand.duid_len = olen;
- } else if (otype == DHCPV6_OPT_STATUS && olen >= 2 && !odata[0]
- && odata[1] == DHCPV6_NoPrefixAvail) {
- cand.preference -= 2000;
+ } else if (otype == DHCPV6_OPT_STATUS && olen >= 2) {
+ int error = ((int)odata[0] << 8 | (int)odata[1]);
+
+ 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;
+ }
} else if (otype == DHCPV6_OPT_PREF && olen >= 1 &&
cand.preference >= 0) {
- cand.preference = odata[0];
+ cand.preference = pref = odata[0];
} else if (otype == DHCPV6_OPT_RECONF_ACCEPT) {
cand.wants_reconfigure = true;
} else if (otype == DHCPV6_OPT_IA_PD && request_prefix) {
@@ -648,7 +665,7 @@ static int dhcpv6_handle_advert(enum dhcpv6_msg orig, _unused const int rc,
odhcp6c_clear_state(STATE_IA_PD);
}
- return -1;
+ return (rc > 1 || (pref == 255 && cand.preference > 0)) ? 1 : -1;
}
@@ -679,8 +696,10 @@ static int dhcpv6_commit_advert(void)
odhcp6c_add_state(STATE_SERVER_ID, hdr, sizeof(hdr));
odhcp6c_add_state(STATE_SERVER_ID, c->duid, c->duid_len);
accept_reconfig = c->wants_reconfigure;
- odhcp6c_add_state(STATE_IA_NA, c->ia_na, c->ia_na_len);
- odhcp6c_add_state(STATE_IA_PD, c->ia_pd, c->ia_pd_len);
+ if (c->ia_na_len)
+ odhcp6c_add_state(STATE_IA_NA, c->ia_na, c->ia_na_len);
+ if (c->ia_pd_len)
+ odhcp6c_add_state(STATE_IA_PD, c->ia_pd, c->ia_pd_len);
}
for (size_t i = 0; i < cand_len / sizeof(*c); ++i) {
@@ -691,7 +710,7 @@ static int dhcpv6_commit_advert(void)
if (!c)
return -1;
- else if (request_prefix || na_mode != IA_MODE_NONE)
+ else if ((request_prefix && c->ia_pd_len) || (na_mode != IA_MODE_NONE && c->ia_na_len))
return DHCPV6_STATEFUL;
else
return DHCPV6_STATELESS;