X-Git-Url: http://git.archive.openwrt.org/?p=project%2Fodhcpd.git;a=blobdiff_plain;f=src%2Fdhcpv6-ia.c;h=c8473a7cdd6c6bb6949076ffc11c1a79496994db;hp=593b5bd5064ee704657ed80971b444b923878f52;hb=eaff6fa14161d58af63bda2e5d56bed2593ad0d0;hpb=2b4200f2510874a3ee9c09f594d5ab6340ffb336 diff --git a/src/dhcpv6-ia.c b/src/dhcpv6-ia.c index 593b5bd..c8473a7 100644 --- a/src/dhcpv6-ia.c +++ b/src/dhcpv6-ia.c @@ -50,10 +50,13 @@ int dhcpv6_ia_init(void) 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); @@ -67,7 +70,6 @@ int setup_dhcpv6_ia_interface(struct interface *iface, bool enable) 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); } } @@ -401,8 +403,22 @@ static void managed_handle_pd_data(struct ustream *s, _unused int bytes_new) 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; } @@ -410,10 +426,8 @@ static void managed_handle_pd_data(struct ustream *s, _unused int bytes_new) 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); - } } @@ -436,12 +450,17 @@ static bool assign_pd(struct interface *iface, struct dhcpv6_assignment *assign) 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; + assign->valid_until = odhcpd_time() + 15; list_add(&assign->head, &iface->ia_assignments); } @@ -693,6 +712,7 @@ static size_t append_reply(uint8_t *buf, size_t buflen, uint16_t status, 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) { @@ -737,7 +757,7 @@ static size_t append_reply(uint8_t *buf, size_t buflen, uint16_t status, .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); @@ -751,7 +771,8 @@ static size_t append_reply(uint8_t *buf, size_t buflen, uint16_t status, } #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)); @@ -886,7 +907,7 @@ static size_t append_reply(uint8_t *buf, size_t buflen, uint16_t status, } -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(); @@ -935,7 +956,6 @@ size_t dhcpv6_handle_ia(uint8_t *buf, size_t buflen, struct interface *iface, 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) { @@ -1040,9 +1060,7 @@ size_t dhcpv6_handle_ia(uint8_t *buf, size_t buflen, struct interface *iface, // 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; @@ -1070,12 +1088,12 @@ size_t dhcpv6_handle_ia(uint8_t *buf, size_t buflen, struct interface *iface, 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; } } @@ -1113,7 +1131,7 @@ size_t dhcpv6_handle_ia(uint8_t *buf, size_t buflen, struct interface *iface, // Was only a solicitation: mark binding for removal if (assigned && hdr->msg_type == DHCPV6_MSG_SOLICIT) { - a->valid_until = now + 15; + a->valid_until = 0; } else if (assigned && hdr->msg_type == DHCPV6_MSG_REQUEST) { if (hostname_len > 0) { a->hostname = realloc(a->hostname, hostname_len + 1); @@ -1125,7 +1143,7 @@ size_t dhcpv6_handle_ia(uint8_t *buf, size_t buflen, struct interface *iface, a->accept_reconf = accept_reconf; apply_lease(iface, a, true); update_state = true; - } else if (!assigned && a) { // Cleanup failed assignment + } else if (!assigned && a && a->managed_size == 0) { // Cleanup failed assignment free_dhcpv6_assignment(a); } } else if (hdr->msg_type == DHCPV6_MSG_RENEW || @@ -1168,14 +1186,6 @@ size_t dhcpv6_handle_ia(uint8_t *buf, size_t buflen, struct interface *iface, 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)