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) {
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)
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) {
IOV_DEST,
IOV_MAXRT,
#define IOV_STAT IOV_MAXRT
+ IOV_RAPID_COMMIT,
IOV_DNS,
IOV_DNS_ADDR,
IOV_SEARCH,
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;
} 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;
[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},
[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;
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;
}
}
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);
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);
}