dhcpv6: rapid commit support
authorHans Dedecker <dedeckeh@gmail.com>
Wed, 13 Feb 2019 11:07:49 +0000 (12:07 +0100)
committerHans Dedecker <dedeckeh@gmail.com>
Wed, 13 Feb 2019 11:07:49 +0000 (12:07 +0100)
Add support for rapid commit according to RFC8415 18.3.1

Signed-off-by: Hans Dedecker <dedeckeh@gmail.com>
src/dhcpv6-ia.c
src/dhcpv6.c
src/dhcpv6.h

index 2820946f2dfdaf2439162556877f2d01eb798290..7c3ccad5b0d219ab8e95349481251ac4901c6c38 100644 (file)
@@ -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) {
index a40c35361d6055bcc3fb352a8b98ae843342837a..f2080c87e1fdb01b531be6e3cd19f71400bd1d4b 100644 (file)
@@ -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;
@@ -273,6 +276,11 @@ static void handle_client_request(void *addr, void *data, size_t len,
        } maxrt = {htons(DHCPV6_OPT_SOL_MAX_RT), htons(sizeof(maxrt) - 4),
                        htonl(60)};
 
+       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;
@@ -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);
 }
index 7abc8afb2b6d93b5773b3c58f56ee9be3cff05a4..aaf919cc3bd0c0030cb5d8b2fe1ba5ce75430e0e 100644 (file)
@@ -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