X-Git-Url: http://git.archive.openwrt.org/?p=project%2Fodhcpd.git;a=blobdiff_plain;f=src%2Fdhcpv6-ia.c;h=30bffbcf0d921e3d8638254c08c2ebef01cc508a;hp=1476e021a590d713d4882c94bc2771e2a2f35b50;hb=a3d1f5148222174f12ea8df0c20a554fc5eaabab;hpb=a06dd6481cd046e4856774ac32cdc11f4bc721e2;ds=sidebyside diff --git a/src/dhcpv6-ia.c b/src/dhcpv6-ia.c index 1476e02..30bffbc 100644 --- a/src/dhcpv6-ia.c +++ b/src/dhcpv6-ia.c @@ -34,7 +34,6 @@ #include -static void update(struct interface *iface); static void reconf_timer(struct uloop_timeout *event); static struct uloop_timeout reconf_event = {.cb = reconf_timer}; static uint32_t serial = 0; @@ -60,7 +59,6 @@ void free_dhcpv6_assignment(struct dhcpv6_assignment *c) free(c->managed); free(c->hostname); - free(c->classes); free(c); } @@ -75,7 +73,7 @@ int setup_dhcpv6_ia_interface(struct interface *iface, bool enable) } } - if (iface->dhcpv6 == RELAYD_SERVER) { + if (enable && iface->dhcpv6 == RELAYD_SERVER) { if (!iface->ia_assignments.next) INIT_LIST_HEAD(&iface->ia_assignments); @@ -90,20 +88,19 @@ int setup_dhcpv6_ia_interface(struct interface *iface, bool enable) list_add(&border->head, &iface->ia_assignments); } - update(iface); - // Parse static entries struct lease *lease; list_for_each_entry(lease, &leases, head) { // Construct entry - struct dhcpv6_assignment *a = calloc(1, sizeof(*a) + lease->duid_len); + size_t duid_len = lease->duid_len ? lease->duid_len : 14; + struct dhcpv6_assignment *a = calloc(1, sizeof(*a) + duid_len); if (!a) { syslog(LOG_ERR, "Calloc failed for static lease assignment on interface %s", iface->ifname); return -1; } - a->clid_len = lease->duid_len; + a->clid_len = duid_len; a->length = 128; if (lease->hostid) { a->assigned = lease->hostid; @@ -133,7 +130,6 @@ int setup_dhcpv6_ia_interface(struct interface *iface, bool enable) a->hostname = strdup(lease->hostname); } } else { - free(a->classes); free(a->hostname); free(a); } @@ -365,7 +361,7 @@ static void apply_lease(struct interface *iface, struct dhcpv6_assignment *a, bo struct in6_addr prefix = addrs[i].addr; prefix.s6_addr32[1] |= htonl(a->assigned); odhcpd_setup_route(&prefix, (a->managed_size) ? addrs[i].prefix : a->length, - iface, &a->peer.sin6_addr, add); + iface, &a->peer.sin6_addr, 1024, add); } } @@ -558,105 +554,73 @@ static bool assign_na(struct interface *iface, struct dhcpv6_assignment *assign) return false; } - -static int prefixcmp(const void *va, const void *vb) +void dhcpv6_ia_preupdate(struct interface *iface) { - const struct odhcpd_ipaddr *a = va, *b = vb; - uint32_t a_pref = ((a->addr.s6_addr[0] & 0xfe) != 0xfc) ? a->preferred : 1; - uint32_t b_pref = ((b->addr.s6_addr[0] & 0xfe) != 0xfc) ? b->preferred : 1; - return (a_pref < b_pref) ? 1 : (a_pref > b_pref) ? -1 : 0; -} + if (iface->dhcpv6 != RELAYD_SERVER) + return; + struct dhcpv6_assignment *c, *border = list_last_entry( + &iface->ia_assignments, struct dhcpv6_assignment, head); + list_for_each_entry(c, &iface->ia_assignments, head) + if (c != border && !iface->managed) + apply_lease(iface, c, false); +} -static void update(struct interface *iface) +void dhcpv6_ia_postupdate(struct interface *iface, time_t now) { - struct odhcpd_ipaddr addr[8]; - memset(addr, 0, sizeof(addr)); - int len = odhcpd_get_interface_addresses(iface->ifindex, addr, 8); - - if (len < 0) + if (iface->dhcpv6 != RELAYD_SERVER) return; - qsort(addr, len, sizeof(*addr), prefixcmp); - - time_t now = odhcpd_time(); int minprefix = -1; - - for (int i = 0; i < len; ++i) { - if (addr[i].preferred > 0 && addr[i].prefix > minprefix) - minprefix = addr[i].prefix; - - addr[i].addr.s6_addr32[3] = 0; - - if (addr[i].preferred < UINT32_MAX - now) - addr[i].preferred += now; - - if (addr[i].valid < UINT32_MAX - now) - addr[i].valid += now; + for (size_t i = 0; i < iface->ia_addr_len; ++i) { + if (iface->ia_addr[i].preferred > (uint32_t)now && + iface->ia_addr[i].prefix < 64 && + iface->ia_addr[i].prefix > minprefix) + minprefix = iface->ia_addr[i].prefix; } - struct dhcpv6_assignment *border = list_last_entry(&iface->ia_assignments, struct dhcpv6_assignment, head); - if (minprefix <= 32 || minprefix > 64) + struct dhcpv6_assignment *border = list_last_entry( + &iface->ia_assignments, struct dhcpv6_assignment, head); + if (minprefix > 32 && minprefix <= 64) border->assigned = 1U << (64 - minprefix); else border->assigned = 0; - bool change = len != (int)iface->ia_addr_len; - for (int i = 0; !change && i < len; ++i) - if (addr[i].addr.s6_addr32[0] != iface->ia_addr[i].addr.s6_addr32[0] || - addr[i].addr.s6_addr32[1] != iface->ia_addr[i].addr.s6_addr32[1] || - (addr[i].preferred > 0) != (iface->ia_addr[i].preferred > 0) || - (addr[i].valid > (uint32_t)now + 7200) != - (iface->ia_addr[i].valid > (uint32_t)now + 7200)) - change = true; - - if (change) { - struct dhcpv6_assignment *c; - list_for_each_entry(c, &iface->ia_assignments, head) - if (c != border && !iface->managed) - apply_lease(iface, c, false); - } - - memcpy(iface->ia_addr, addr, len * sizeof(*addr)); - iface->ia_addr_len = len; + struct list_head reassign = LIST_HEAD_INIT(reassign); + struct dhcpv6_assignment *c, *d; + list_for_each_entry_safe(c, d, &iface->ia_assignments, head) { + if (c->clid_len == 0 || c->valid_until < now || c->managed_size) + continue; - if (change) { // Addresses / prefixes have changed - struct list_head reassign = LIST_HEAD_INIT(reassign); - struct dhcpv6_assignment *c, *d; - list_for_each_entry_safe(c, d, &iface->ia_assignments, head) { - if (c->clid_len == 0 || c->valid_until < now || c->managed_size) - continue; + if (c->length < 128 && c->assigned >= border->assigned && c != border) + list_move(&c->head, &reassign); + else if (c != border) + apply_lease(iface, c, true); - if (c->length < 128 && c->assigned >= border->assigned && c != border) - list_move(&c->head, &reassign); - else if (c != border) - apply_lease(iface, c, true); - - if (c->accept_reconf && c->reconf_cnt == 0) { - c->reconf_cnt = 1; - c->reconf_sent = now; - send_reconf(iface, c); - - // Leave all other assignments of that client alone - struct dhcpv6_assignment *a; - list_for_each_entry(a, &iface->ia_assignments, head) - if (a != c && a->clid_len == c->clid_len && - !memcmp(a->clid_data, c->clid_data, a->clid_len)) - c->reconf_cnt = INT_MAX; - } + if (c->accept_reconf && c->reconf_cnt == 0) { + c->reconf_cnt = 1; + c->reconf_sent = now; + send_reconf(iface, c); + + // Leave all other assignments of that client alone + struct dhcpv6_assignment *a; + list_for_each_entry(a, &iface->ia_assignments, head) + if (a != c && a->clid_len == c->clid_len && + !memcmp(a->clid_data, c->clid_data, a->clid_len)) + c->reconf_cnt = INT_MAX; } + } - while (!list_empty(&reassign)) { - c = list_first_entry(&reassign, struct dhcpv6_assignment, head); - list_del(&c->head); - if (!assign_pd(iface, c)) { - c->assigned = 0; - list_add(&c->head, &iface->ia_assignments); - } + while (!list_empty(&reassign)) { + c = list_first_entry(&reassign, struct dhcpv6_assignment, head); + list_del(&c->head); + if (!assign_pd(iface, c)) { + c->assigned = 0; + list_add(&c->head, &iface->ia_assignments); } - - dhcpv6_write_statefile(); } + + dhcpv6_write_statefile(); } @@ -758,7 +722,8 @@ static size_t append_reply(uint8_t *buf, size_t buflen, uint16_t status, size_t entrlen = sizeof(p) - 4; if (datalen + entrlen + 4 > buflen || - (a->assigned == 0 && a->managed_size == 0)) + (a->assigned == 0 && a->managed_size == 0) || + (!a->managed_size && a->length <= addrs[i].prefix)) continue; memcpy(buf + datalen, &p, sizeof(p)); @@ -775,7 +740,7 @@ static size_t append_reply(uint8_t *buf, size_t buflen, uint16_t status, size_t entrlen = sizeof(n) - 4; if (iface->managed < RELAYD_MANAGED_NO_AFLAG && i != m && - addrs[i].prefix == 64) + addrs[i].prefix <= 64) continue; if (datalen + entrlen + 4 > buflen || a->assigned == 0) @@ -1009,8 +974,6 @@ ssize_t dhcpv6_handle_ia(uint8_t *buf, size_t buflen, struct interface *iface, if (!clid_data || !clid_len || clid_len > 130) goto out; - update(iface); - struct dhcpv6_assignment *first = NULL; dhcpv6_for_each_option(start, end, otype, olen, odata) { bool is_pd = (otype == DHCPV6_OPT_IA_PD);