void free_dhcpv6_assignment(struct dhcpv6_assignment *c)
{
if (c->managed_sock.fd.registered) {
- close(c->managed_sock.fd.fd);
ustream_free(&c->managed_sock.stream);
+ close(c->managed_sock.fd.fd);
}
+ if (c->head.next)
+ list_del(&c->head);
+
free(c->managed);
free(c->hostname);
free(c->classes);
struct dhcpv6_assignment *c;
while (!list_empty(&iface->ia_assignments)) {
c = list_first_entry(&iface->ia_assignments, struct dhcpv6_assignment, head);
- list_del(&c->head);
free_dhcpv6_assignment(c);
}
}
if (sscanf(x, "%u", &n->valid) < 1)
continue;
- n->preferred += now;
- n->valid += now;
+ if (n->preferred > n->valid)
+ continue;
+
+ if (UINT32_MAX - now < n->preferred)
+ n->preferred = UINT32_MAX;
+ else
+ n->preferred += now;
+
+ if (UINT32_MAX - now < n->valid)
+ n->valid = UINT32_MAX;
+ else
+ n->valid += now;
+
+ n->has_class = false;
+ n->class = 0;
+ n->dprefix = 0;
++c->managed_size;
}
ustream_consume(s, end - data);
}
- if (first && c->managed_size == 0) {
- list_del(&c->head);
+ if (first && c->managed_size == 0)
free_dhcpv6_assignment(c);
- }
}
if (iface->dhcpv6_pd_manager[0]) {
int fd = usock(USOCK_UNIX | USOCK_TCP, iface->dhcpv6_pd_manager, NULL);
if (fd >= 0) {
+ char iaidbuf[298];
+ odhcpd_hexlify(iaidbuf, assign->clid_data, assign->clid_len);
+
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);
ustream_write_pending(&assign->managed_sock.stream);
assign->managed_size = -1;
list_add(&assign->head, &iface->ia_assignments);
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;
+
for (size_t i = 0; i < addrlen; ++i) {
bool match = true;
if (addrs[i].has_class) {
.len = htons(sizeof(p) - 4),
.preferred = htonl(prefix_pref),
.valid = htonl(prefix_valid),
- .prefix = (a->managed_size) ? a->managed_size : a->length,
+ .prefix = (a->managed_size) ? addrs[i].prefix : a->length,
.addr = addrs[i].addr
};
p.addr.s6_addr32[1] |= htonl(a->assigned);
}
#endif
- if (datalen + entrlen + 4 > buflen || a->assigned == 0)
+ if (datalen + entrlen + 4 > buflen ||
+ (a->assigned == 0 && a->managed_size == 0))
continue;
memcpy(buf + datalen, &p, sizeof(p));
}
-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();
update(iface);
bool update_state = false;
- bool managed_pd_out = false;
struct dhcpv6_assignment *first = NULL;
dhcpv6_for_each_option(start, end, otype, olen, odata) {
// 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);
+ return -1;
} else if (hdr->msg_type == DHCPV6_MSG_SOLICIT || hdr->msg_type == DHCPV6_MSG_REQUEST) {
bool assigned = !!a;
if (is_pd)
while (!(assigned = assign_pd(iface, a)) &&
- ++a->length <= 64 && !a->managed_size);
+ !a->managed_size && ++a->length <= 64);
else
assigned = assign_na(iface, a);
if (a->managed_size && !assigned)
- managed_pd_out = true;
+ return -1;
}
}
buf[4] = 0;
buf[5] = DHCPV6_STATUS_OK;
response_len += 6;
- } else if (managed_pd_out && 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_NOADDRSAVAIL;
- response_len += 6;
}
if (update_state)