summaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorHans Dedecker <dedeckeh@gmail.com>2019-02-13 12:07:49 +0100
committerHans Dedecker <dedeckeh@gmail.com>2019-02-13 12:07:49 +0100
commit36833ea26684b70b0d6093ecec648fe192a582ec (patch)
treeeca96b7349d4855d37961db4d9d76d57eb00727e /src
parent1ae316e330acb49d3fb3279be4452fd3e1b732c4 (diff)
dhcpv6: rapid commit support
Add support for rapid commit according to RFC8415 18.3.1 Signed-off-by: Hans Dedecker <dedeckeh@gmail.com>
Diffstat (limited to 'src')
-rw-r--r--src/dhcpv6-ia.c12
-rw-r--r--src/dhcpv6.c48
-rw-r--r--src/dhcpv6.h1
3 files changed, 39 insertions, 22 deletions
diff --git a/src/dhcpv6-ia.c b/src/dhcpv6-ia.c
index 2820946..7c3ccad 100644
--- a/src/dhcpv6-ia.c
+++ b/src/dhcpv6-ia.c
@@ -1170,7 +1170,7 @@ ssize_t dhcpv6_ia_handle_IAs(uint8_t *buf, size_t buflen, struct interface *ifac
uint8_t *clid_data = NULL, clid_len = 0, mac[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
char hostname[256];
size_t hostname_len = 0;
- bool notonlink = false;
+ bool notonlink = false, rapid_commit = false;
char duidbuf[261];
dhcpv6_for_each_option(start, end, otype, olen, odata) {
@@ -1194,6 +1194,8 @@ ssize_t dhcpv6_ia_handle_IAs(uint8_t *buf, size_t buflen, struct interface *ifac
hostname_len = strcspn(hostname, ".");
} else if (otype == DHCPV6_OPT_RECONF_ACCEPT)
accept_reconf = true;
+ else if (otype == DHCPV6_OPT_RAPID_COMMIT && hdr->msg_type == DHCPV6_MSG_SOLICIT)
+ rapid_commit = true;
}
if (!clid_data || !clid_len || clid_len > 130)
@@ -1348,16 +1350,18 @@ ssize_t dhcpv6_ia_handle_IAs(uint8_t *buf, size_t buflen, struct interface *ifac
hdr->msg_type == DHCPV6_MSG_REBIND ? false : true);
/* Was only a solicitation: mark binding for removal */
- if (assigned && hdr->msg_type == DHCPV6_MSG_SOLICIT) {
+ if (assigned && hdr->msg_type == DHCPV6_MSG_SOLICIT && !rapid_commit) {
a->flags &= ~OAF_BOUND;
a->flags |= OAF_TENTATIVE;
if (!(a->flags & OAF_STATIC))
/* Keep tentative assignment around for 60 seconds */
a->valid_until = now + 60;
+
} else if (assigned &&
- (hdr->msg_type == DHCPV6_MSG_REQUEST ||
- hdr->msg_type == DHCPV6_MSG_REBIND)) {
+ ((hdr->msg_type == DHCPV6_MSG_SOLICIT && rapid_commit) ||
+ hdr->msg_type == DHCPV6_MSG_REQUEST ||
+ hdr->msg_type == DHCPV6_MSG_REBIND)) {
if (hostname_len > 0) {
a->hostname = realloc(a->hostname, hostname_len + 1);
if (a->hostname) {
diff --git a/src/dhcpv6.c b/src/dhcpv6.c
index a40c353..f2080c8 100644
--- a/src/dhcpv6.c
+++ b/src/dhcpv6.c
@@ -163,6 +163,7 @@ enum {
IOV_DEST,
IOV_MAXRT,
#define IOV_STAT IOV_MAXRT
+ IOV_RAPID_COMMIT,
IOV_DNS,
IOV_DNS_ADDR,
IOV_SEARCH,
@@ -237,6 +238,8 @@ static void handle_client_request(void *addr, void *data, size_t len,
struct interface *iface, void *dest_addr)
{
struct dhcpv6_client_header *hdr = data;
+ uint8_t *opts = (uint8_t *)&hdr[1], *opts_end = (uint8_t *)data + len;
+ bool o_rapid_commit = false;
if (len < sizeof(*hdr))
return;
@@ -276,6 +279,11 @@ static void handle_client_request(void *addr, void *data, size_t len,
struct __attribute__((packed)) {
uint16_t type;
uint16_t len;
+ } rapid_commit = {htons(DHCPV6_OPT_RAPID_COMMIT), 0};
+
+ struct __attribute__((packed)) {
+ uint16_t type;
+ uint16_t len;
uint16_t value;
} stat = {htons(DHCPV6_OPT_STATUS), htons(sizeof(stat) - 4),
htons(DHCPV6_STATUS_USEMULTICAST)};
@@ -336,6 +344,7 @@ static void handle_client_request(void *addr, void *data, size_t len,
[IOV_NESTED] = {NULL, 0},
[IOV_DEST] = {&dest, (uint8_t*)&dest.clientid_type - (uint8_t*)&dest},
[IOV_MAXRT] = {&maxrt, sizeof(maxrt)},
+ [IOV_RAPID_COMMIT] = {&rapid_commit, 0},
[IOV_DNS] = {&dns, (dns_cnt) ? sizeof(dns) : 0},
[IOV_DNS_ADDR] = {dns_addr_ptr, dns_cnt * sizeof(*dns_addr_ptr)},
[IOV_SEARCH] = {&search, (search_len) ? sizeof(search) : 0},
@@ -346,30 +355,19 @@ static void handle_client_request(void *addr, void *data, size_t len,
[IOV_RELAY_MSG] = {NULL, 0}
};
- uint8_t *opts = (uint8_t*)&hdr[1], *opts_end = (uint8_t*)data + len;
if (hdr->msg_type == DHCPV6_MSG_RELAY_FORW)
handle_nested_message(data, len, &hdr, &opts, &opts_end, iov);
- memcpy(dest.tr_id, hdr->transaction_id, sizeof(dest.tr_id));
-
if (hdr->msg_type == DHCPV6_MSG_ADVERTISE || hdr->msg_type == DHCPV6_MSG_REPLY ||
hdr->msg_type == DHCPV6_MSG_RELAY_REPL)
return;
if (!IN6_IS_ADDR_MULTICAST((struct in6_addr *)dest_addr) && iov[IOV_NESTED].iov_len == 0 &&
- (hdr->msg_type == DHCPV6_MSG_SOLICIT || hdr->msg_type == DHCPV6_MSG_CONFIRM ||
- hdr->msg_type == DHCPV6_MSG_REBIND || hdr->msg_type == DHCPV6_MSG_INFORMATION_REQUEST))
+ (hdr->msg_type == DHCPV6_MSG_SOLICIT || hdr->msg_type == DHCPV6_MSG_CONFIRM ||
+ hdr->msg_type == DHCPV6_MSG_REBIND || hdr->msg_type == DHCPV6_MSG_INFORMATION_REQUEST))
return;
- if (hdr->msg_type == DHCPV6_MSG_SOLICIT) {
- dest.msg_type = DHCPV6_MSG_ADVERTISE;
- } else if (hdr->msg_type == DHCPV6_MSG_INFORMATION_REQUEST) {
- iov[IOV_REFRESH].iov_base = &refresh;
- iov[IOV_REFRESH].iov_len = sizeof(refresh);
-
- /* Return inf max rt option in reply to information request */
- maxrt.type = htons(DHCPV6_OPT_INF_MAX_RT);
- }
+ memcpy(dest.tr_id, hdr->transaction_id, sizeof(dest.tr_id));
/* Go through options and find what we need */
uint16_t otype, olen;
@@ -406,6 +404,9 @@ static void handle_client_request(void *addr, void *data, size_t len,
free(addrs);
}
#endif
+ } else if (otype == DHCPV6_OPT_RAPID_COMMIT && hdr->msg_type == DHCPV6_MSG_SOLICIT) {
+ iov[IOV_RAPID_COMMIT].iov_len = sizeof(rapid_commit);
+ o_rapid_commit = true;
}
}
@@ -422,6 +423,16 @@ static void handle_client_request(void *addr, void *data, size_t len,
return;
}
+ if (hdr->msg_type == DHCPV6_MSG_SOLICIT && !o_rapid_commit) {
+ dest.msg_type = DHCPV6_MSG_ADVERTISE;
+ } else if (hdr->msg_type == DHCPV6_MSG_INFORMATION_REQUEST) {
+ iov[IOV_REFRESH].iov_base = &refresh;
+ iov[IOV_REFRESH].iov_len = sizeof(refresh);
+
+ /* Return inf max rt option in reply to information request */
+ maxrt.type = htons(DHCPV6_OPT_INF_MAX_RT);
+ }
+
if (hdr->msg_type != DHCPV6_MSG_INFORMATION_REQUEST) {
ssize_t ialen = dhcpv6_ia_handle_IAs(pdbuf, sizeof(pdbuf), iface, addr, (const void *)hdr, opts_end);
@@ -433,10 +444,11 @@ static void handle_client_request(void *addr, void *data, size_t len,
if (iov[IOV_NESTED].iov_len > 0) /* Update length */
update_nested_message(data, len, iov[IOV_DEST].iov_len + iov[IOV_MAXRT].iov_len +
- iov[IOV_DNS].iov_len + iov[IOV_DNS_ADDR].iov_len +
- iov[IOV_SEARCH].iov_len + iov[IOV_SEARCH_DOMAIN].iov_len +
- iov[IOV_PDBUF].iov_len + iov[IOV_CERID].iov_len +
- iov[IOV_DHCPV6_RAW].iov_len - (4 + opts_end - opts));
+ iov[IOV_RAPID_COMMIT].iov_len + iov[IOV_DNS].iov_len +
+ iov[IOV_DNS_ADDR].iov_len + iov[IOV_SEARCH].iov_len +
+ iov[IOV_SEARCH_DOMAIN].iov_len + iov[IOV_PDBUF].iov_len +
+ iov[IOV_CERID].iov_len + iov[IOV_DHCPV6_RAW].iov_len -
+ (4 + opts_end - opts));
odhcpd_send(iface->dhcpv6_event.uloop.fd, addr, iov, ARRAY_SIZE(iov), iface);
}
diff --git a/src/dhcpv6.h b/src/dhcpv6.h
index 7abc8af..aaf919c 100644
--- a/src/dhcpv6.h
+++ b/src/dhcpv6.h
@@ -44,6 +44,7 @@
#define DHCPV6_OPT_STATUS 13
#define DHCPV6_OPT_RELAY_MSG 9
#define DHCPV6_OPT_AUTH 11
+#define DHCPV6_OPT_RAPID_COMMIT 14
#define DHCPV6_OPT_USER_CLASS 15
#define DHCPV6_OPT_INTERFACE_ID 18
#define DHCPV6_OPT_RECONF_MSG 19