X-Git-Url: http://git.archive.openwrt.org/?a=blobdiff_plain;f=src%2Fdhcpv6-ia.c;h=90dcaf53f46ff66a83fdda5d97041bf9a656020c;hb=e59238f32a47616091d8c78acb317d7b4023745f;hp=767a546fbe5db0ff776c41cc7c514b1a2479e61c;hpb=2441f9629ddae3656313565c4e48236661c130ff;p=project%2Fodhcpd.git diff --git a/src/dhcpv6-ia.c b/src/dhcpv6-ia.c index 767a546..90dcaf5 100644 --- a/src/dhcpv6-ia.c +++ b/src/dhcpv6-ia.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -257,6 +258,8 @@ void dhcpv6_write_statefile(void) for (size_t i = 0; i < addrlen; ++i) { if (addrs[i].prefix > 96) continue; + if (c->valid_until <= now) + continue; addr = addrs[i].addr; if (c->length == 128) @@ -266,7 +269,7 @@ void dhcpv6_write_statefile(void) inet_ntop(AF_INET6, &addr, ipbuf, sizeof(ipbuf) - 1); - if (c->length == 128 && c->hostname && i == 0) { + if (c->length == 128 && c->hostname) { fputs(ipbuf, fp); char b[256]; @@ -464,6 +467,14 @@ static bool assign_pd(struct interface *iface, struct dhcpv6_assignment *assign) assign->managed_size = -1; assign->valid_until = odhcpd_time() + 15; list_add(&assign->head, &iface->ia_assignments); + + // 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; } return false; @@ -611,7 +622,7 @@ static void update(struct interface *iface) if (change) { struct dhcpv6_assignment *c; list_for_each_entry(c, &iface->ia_assignments, head) - if (c != border) + if (c != border && !iface->managed) apply_lease(iface, c, false); } @@ -709,8 +720,14 @@ static size_t append_reply(uint8_t *buf, size_t buflen, uint16_t status, datalen += sizeof(stat); } else { if (a) { - uint32_t pref = 3600; - uint32_t valid = 3600; + uint32_t leasetime = iface->dhcpv4_leasetime; + if (leasetime == 0) + leasetime = 3600; + else if (leasetime < 60) + leasetime = 60; + + uint32_t pref = leasetime; + uint32_t valid = leasetime; 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; @@ -924,6 +941,8 @@ ssize_t dhcpv6_handle_ia(uint8_t *buf, size_t buflen, struct interface *iface, char hostname[256]; size_t hostname_len = 0; bool class_oro = false; + bool notonlink = false; + dhcpv6_for_each_option(start, end, otype, olen, odata) { if (otype == DHCPV6_OPT_CLIENTID) { clid_data = odata; @@ -957,12 +976,12 @@ ssize_t dhcpv6_handle_ia(uint8_t *buf, size_t buflen, struct interface *iface, goto out; update(iface); - bool update_state = false; 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); + bool ia_addr_present = false; if (!is_pd && !is_na) continue; @@ -1015,6 +1034,7 @@ ssize_t dhcpv6_handle_ia(uint8_t *buf, size_t buflen, struct interface *iface, if (stype != DHCPV6_OPT_IA_ADDR || slen < sizeof(struct dhcpv6_ia_addr) - 4) continue; + ia_addr_present = true; #ifdef DHCPV6_OPT_PREFIX_CLASS uint8_t *xdata; uint16_t xtype, xlen; @@ -1144,7 +1164,6 @@ ssize_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 && a->managed_size == 0) { // Cleanup failed assignment free_dhcpv6_assignment(a); } @@ -1163,16 +1182,15 @@ ssize_t dhcpv6_handle_ia(uint8_t *buf, size_t buflen, struct interface *iface, } else if (hdr->msg_type == DHCPV6_MSG_RELEASE) { a->valid_until = 0; apply_lease(iface, a, false); - update_state = true; } else if (hdr->msg_type == DHCPV6_MSG_DECLINE && a->length == 128) { a->clid_len = 0; a->valid_until = now + 3600; // Block address for 1h - 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); + notonlink = true; } buf += ia_response_len; @@ -1180,18 +1198,18 @@ ssize_t dhcpv6_handle_ia(uint8_t *buf, size_t buflen, struct interface *iface, response_len += ia_response_len; } - if (hdr->msg_type == DHCPV6_MSG_RELEASE && response_len + 6 < buflen) { + if ((hdr->msg_type == DHCPV6_MSG_RELEASE || hdr->msg_type == DHCPV6_MSG_DECLINE || notonlink) && + 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; + buf[5] = (notonlink) ? DHCPV6_STATUS_NOTONLINK : DHCPV6_STATUS_OK; response_len += 6; } - if (update_state) - dhcpv6_write_statefile(); + dhcpv6_write_statefile(); out: return response_len;