struct dhcpv6_assignment *c;
while (!list_empty(&iface->ia_assignments)) {
c = list_first_entry(&iface->ia_assignments, struct dhcpv6_assignment, head);
struct dhcpv6_assignment *c;
while (!list_empty(&iface->ia_assignments)) {
c = list_first_entry(&iface->ia_assignments, struct dhcpv6_assignment, head);
- l += snprintf(leasebuf + l, sizeof(leasebuf) - l, "%s/%hhu ", ipbuf,
+ l += snprintf(leasebuf + l, sizeof(leasebuf) - l, "%s/%d ", ipbuf,
if (iface->dhcpv6_pd_manager[0]) {
int fd = usock(USOCK_UNIX | USOCK_TCP, iface->dhcpv6_pd_manager, NULL);
if (fd >= 0) {
if (iface->dhcpv6_pd_manager[0]) {
int fd = usock(USOCK_UNIX | USOCK_TCP, iface->dhcpv6_pd_manager, NULL);
if (fd >= 0) {
assign->managed_sock.stream.notify_read = managed_handle_pd_data;
assign->managed_sock.stream.notify_state = managed_handle_pd_done;
ustream_fd_init(&assign->managed_sock, fd);
assign->managed_sock.stream.notify_read = managed_handle_pd_data;
assign->managed_sock.stream.notify_state = managed_handle_pd_done;
ustream_fd_init(&assign->managed_sock, fd);
- ustream_printf(&assign->managed_sock.stream, "::/%d,0,0\n\n", assign->length);
+ ustream_printf(&assign->managed_sock.stream, "%s,%x\n::/%d,0,0\n\n",
+ iaidbuf, assign->iaid, assign->length);
+
+ // Wait initial period of up to 250ms for immediate assignment
+ struct pollfd pfd = { .fd = fd, .events = POLLIN };
+ poll(&pfd, 1, 250);
+ managed_handle_pd_data(&assign->managed_sock.stream, 0);
+
+ if (fcntl(fd, F_GETFL) >= 0 && assign->managed_size > 0)
+ return true;
struct odhcpd_ipaddr *addrs = (a->managed) ? a->managed : iface->ia_addr;
size_t addrlen = (a->managed) ? (size_t)a->managed_size : iface->ia_addr_len;
struct odhcpd_ipaddr *addrs = (a->managed) ? a->managed : iface->ia_addr;
size_t addrlen = (a->managed) ? (size_t)a->managed_size : iface->ia_addr_len;
.len = htons(sizeof(p) - 4),
.preferred = htonl(prefix_pref),
.valid = htonl(prefix_valid),
.len = htons(sizeof(p) - 4),
.preferred = htonl(prefix_pref),
.valid = htonl(prefix_valid),
-size_t dhcpv6_handle_ia(uint8_t *buf, size_t buflen, struct interface *iface,
+ssize_t dhcpv6_handle_ia(uint8_t *buf, size_t buflen, struct interface *iface,
const struct sockaddr_in6 *addr, const void *data, const uint8_t *end)
{
time_t now = odhcpd_time();
const struct sockaddr_in6 *addr, const void *data, const uint8_t *end)
{
time_t now = odhcpd_time();
dhcpv6_for_each_option(start, end, otype, olen, odata) {
if (otype == DHCPV6_OPT_CLIENTID) {
clid_data = odata;
dhcpv6_for_each_option(start, end, otype, olen, odata) {
if (otype == DHCPV6_OPT_CLIENTID) {
clid_data = odata;
struct dhcpv6_assignment *first = NULL;
dhcpv6_for_each_option(start, end, otype, olen, odata) {
bool is_pd = (otype == DHCPV6_OPT_IA_PD);
bool is_na = (otype == DHCPV6_OPT_IA_NA);
struct dhcpv6_assignment *first = NULL;
dhcpv6_for_each_option(start, end, otype, olen, odata) {
bool is_pd = (otype == DHCPV6_OPT_IA_PD);
bool is_na = (otype == DHCPV6_OPT_IA_NA);
// Generic message handling
uint16_t status = DHCPV6_STATUS_OK;
if (a && a->managed_size < 0) {
// Generic message handling
uint16_t status = DHCPV6_STATUS_OK;
if (a && a->managed_size < 0) {
- managed_pd_out = true;
- status = DHCPV6_STATUS_NOTONLINK;
- ia_response_len = append_reply(buf, buflen, status, ia, NULL, iface, true);
else
assigned = assign_na(iface, a);
if (a->managed_size && !assigned)
else
assigned = assign_na(iface, a);
if (a->managed_size && !assigned)
// Was only a solicitation: mark binding for removal
if (assigned && hdr->msg_type == DHCPV6_MSG_SOLICIT) {
// Was only a solicitation: mark binding for removal
if (assigned && hdr->msg_type == DHCPV6_MSG_SOLICIT) {
} else if (assigned && hdr->msg_type == DHCPV6_MSG_REQUEST) {
if (hostname_len > 0) {
a->hostname = realloc(a->hostname, hostname_len + 1);
} else if (assigned && hdr->msg_type == DHCPV6_MSG_REQUEST) {
if (hostname_len > 0) {
a->hostname = realloc(a->hostname, hostname_len + 1);
a->accept_reconf = accept_reconf;
apply_lease(iface, a, true);
update_state = true;
a->accept_reconf = accept_reconf;
apply_lease(iface, a, true);
update_state = true;
- } else if (hdr->msg_type == DHCPV6_MSG_CONFIRM) {
- // Always send NOTONLINK for CONFIRM so that clients restart connection
+ } else if (hdr->msg_type == DHCPV6_MSG_CONFIRM && ia_addr_present) {
+ // Send NOTONLINK for CONFIRM with addr present so that clients restart connection
status = DHCPV6_STATUS_NOTONLINK;
ia_response_len = append_reply(buf, buflen, status, ia, a, iface, true);
status = DHCPV6_STATUS_NOTONLINK;
ia_response_len = append_reply(buf, buflen, status, ia, a, iface, true);
- if (hdr->msg_type == DHCPV6_MSG_RELEASE && response_len + 6 < buflen) {
- buf[0] = 0;
- buf[1] = DHCPV6_OPT_STATUS;
- buf[2] = 0;
- buf[3] = 2;
- buf[4] = 0;
- buf[5] = DHCPV6_STATUS_OK;
- response_len += 6;
- } else if (managed_pd_out && response_len + 6 < buflen) {
+ if ((hdr->msg_type == DHCPV6_MSG_RELEASE || hdr->msg_type == DHCPV6_MSG_DECLINE || notonlink) &&
+ response_len + 6 < buflen) {