X-Git-Url: http://git.archive.openwrt.org/?p=project%2Fodhcpd.git;a=blobdiff_plain;f=src%2Fdhcpv6-ia.c;h=6568c69446655d8922aeb4ae74a0923ad8df2a26;hp=502373fd9904c8c6e4b362c7332c6c3cbc45152b;hb=24cdc1b59f00a065dd1cf0a04145ca6aaf6f23f1;hpb=18df6cca092743a07be8e0f05d0a9ef941957b66 diff --git a/src/dhcpv6-ia.c b/src/dhcpv6-ia.c index 502373f..6568c69 100644 --- a/src/dhcpv6-ia.c +++ b/src/dhcpv6-ia.c @@ -36,22 +36,24 @@ #include #define ADDR_ENTRY_VALID_IA_ADDR(iface, i, m, addrs) \ - ((iface)->managed == RELAYD_MANAGED_NO_AFLAG || (i) == (m) || \ + ((iface)->dhcpv6_assignall || (i) == (m) || \ (addrs)[(i)].prefix > 64) static void free_dhcpv6_assignment(struct dhcpv6_assignment *c); -static void reconf_timer(struct uloop_timeout *event); -static struct uloop_timeout reconf_event = {.cb = reconf_timer}; +static void stop_reconf(struct dhcpv6_assignment *a); +static void valid_until_cb(struct uloop_timeout *event); + +static struct uloop_timeout valid_until_timeout = {.cb = valid_until_cb}; static uint32_t serial = 0; static uint8_t statemd5[16]; int dhcpv6_ia_init(void) { - uloop_timeout_set(&reconf_event, 2000); + uloop_timeout_set(&valid_until_timeout, 1000); return 0; } -int setup_dhcpv6_ia_interface(struct interface *iface, bool enable) +int dhcpv6_setup_ia_interface(struct interface *iface, bool enable) { if (!enable && iface->ia_assignments.next) { struct dhcpv6_assignment *c; @@ -62,7 +64,7 @@ int setup_dhcpv6_ia_interface(struct interface *iface, bool enable) } } - if (enable && iface->dhcpv6 == RELAYD_SERVER) { + if (enable && iface->dhcpv6 == MODE_SERVER) { if (!iface->ia_assignments.next) INIT_LIST_HEAD(&iface->ia_assignments); @@ -120,6 +122,7 @@ int setup_dhcpv6_ia_interface(struct interface *iface, bool enable) } if (a->head.next) { + a->iface = iface; if (lease->hostname[0]) { free(a->hostname); a->hostname = strdup(lease->hostname); @@ -141,6 +144,9 @@ static void free_dhcpv6_assignment(struct dhcpv6_assignment *c) if (c->head.next) list_del(&c->head); + if (c->reconf_cnt) + stop_reconf(c); + free(c->managed); free(c->hostname); free(c); @@ -170,7 +176,7 @@ static size_t get_preferred_addr(const struct odhcpd_ipaddr *addrs, const size_t return m; } -static int send_reconf(struct interface *iface, struct dhcpv6_assignment *assign) +static int send_reconf(struct dhcpv6_assignment *assign) { struct { struct dhcpv6_client_header hdr; @@ -202,6 +208,7 @@ static int send_reconf(struct interface *iface, struct dhcpv6_assignment *assign .clid_len = htons(assign->clid_len), .clid_data = {0}, }; + struct interface *iface = assign->iface; odhcpd_get_mac(iface, reconf_msg.mac); memcpy(reconf_msg.clid_data, assign->clid_data, assign->clid_len); @@ -340,11 +347,11 @@ void dhcpv6_write_statefile(void) ctxt.buf_len = sizeof(leasebuf); list_for_each_entry(ctxt.iface, &interfaces, head) { - if (ctxt.iface->dhcpv6 != RELAYD_SERVER && - ctxt.iface->dhcpv4 != RELAYD_SERVER) + if (ctxt.iface->dhcpv6 != MODE_SERVER && + ctxt.iface->dhcpv4 != MODE_SERVER) continue; - if (ctxt.iface->dhcpv6 == RELAYD_SERVER && + if (ctxt.iface->dhcpv6 == MODE_SERVER && ctxt.iface->ia_assignments.next) { list_for_each_entry(ctxt.c, &ctxt.iface->ia_assignments, head) { if (!(ctxt.c->flags & OAF_BOUND) || ctxt.c->managed_size < 0) @@ -372,7 +379,7 @@ void dhcpv6_write_statefile(void) } } - if (ctxt.iface->dhcpv4 == RELAYD_SERVER && + if (ctxt.iface->dhcpv4 == MODE_SERVER && ctxt.iface->dhcpv4_assignments.next) { struct dhcpv4_assignment *c; list_for_each_entry(c, &ctxt.iface->dhcpv4_assignments, head) { @@ -390,9 +397,9 @@ void dhcpv6_write_statefile(void) (c->valid_until > now ? (c->valid_until - now + wall_time) : (INFINITE_VALID(c->valid_until) ? -1 : 0)), - c->addr); + ntohl(c->addr)); - struct in_addr addr = {htonl(c->addr)}; + struct in_addr addr = {.s_addr = c->addr}; inet_ntop(AF_INET, &addr, ipbuf, sizeof(ipbuf) - 1); if (c->hostname) { @@ -447,7 +454,7 @@ static void apply_lease(struct interface *iface, struct dhcpv6_assignment *a, bo struct in6_addr prefix = addrs[i].addr.in6; prefix.s6_addr32[1] |= htonl(a->assigned); prefix.s6_addr32[2] = prefix.s6_addr32[3] = 0; - odhcpd_setup_route(&prefix, (a->managed_size) ? addrs[i].prefix : a->length, + netlink_setup_route(&prefix, (a->managed_size) ? addrs[i].prefix : a->length, iface, &a->peer.sin6_addr, 1024, add); } } @@ -650,20 +657,51 @@ static bool assign_na(struct interface *iface, struct dhcpv6_assignment *assign) void dhcpv6_ia_preupdate(struct interface *iface) { - if (iface->dhcpv6 != RELAYD_SERVER) + if (iface->dhcpv6 != MODE_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 && (c->flags & OAF_BOUND)) + if (c != border && iface->ra_managed == RA_MANAGED_NO_MFLAG + && (c->flags & OAF_BOUND)) apply_lease(iface, c, false); } +static void reconf_timeout_cb(struct uloop_timeout *event) +{ + struct dhcpv6_assignment *a = container_of(event, struct dhcpv6_assignment, reconf_timer); + + if (a->reconf_cnt > 0 && a->reconf_cnt < DHCPV6_REC_MAX_RC) { + send_reconf(a); + uloop_timeout_set(&a->reconf_timer, + DHCPV6_REC_TIMEOUT << a->reconf_cnt); + a->reconf_cnt++; + } else + stop_reconf(a); +} + +static void start_reconf(struct dhcpv6_assignment *a) +{ + uloop_timeout_set(&a->reconf_timer, + DHCPV6_REC_TIMEOUT << a->reconf_cnt); + a->reconf_timer.cb = reconf_timeout_cb; + a->reconf_cnt++; + + send_reconf(a); +} + +static void stop_reconf(struct dhcpv6_assignment *a) +{ + uloop_timeout_cancel(&a->reconf_timer); + a->reconf_cnt = 0; + a->reconf_timer.cb = NULL; +} + void dhcpv6_ia_postupdate(struct interface *iface) { - if (iface->dhcpv6 != RELAYD_SERVER) + if (iface->dhcpv6 != MODE_SERVER) return; time_t now = odhcpd_time(); @@ -696,16 +734,14 @@ void dhcpv6_ia_postupdate(struct interface *iface) 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); + start_reconf(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; + a->reconf_cnt = INT_MAX; } } @@ -721,12 +757,12 @@ void dhcpv6_ia_postupdate(struct interface *iface) dhcpv6_write_statefile(); } -static void reconf_timer(struct uloop_timeout *event) +static void valid_until_cb(struct uloop_timeout *event) { time_t now = odhcpd_time(); struct interface *iface; list_for_each_entry(iface, &interfaces, head) { - if (iface->dhcpv6 != RELAYD_SERVER || iface->ia_assignments.next == NULL) + if (iface->dhcpv6 != MODE_SERVER || iface->ia_assignments.next == NULL) continue; struct dhcpv6_assignment *a, *n; @@ -736,15 +772,10 @@ static void reconf_timer(struct uloop_timeout *event) (a->length == 128 && a->clid_len == 0)) free_dhcpv6_assignment(a); - } else if (a->reconf_cnt > 0 && a->reconf_cnt < 8 && - now > a->reconf_sent + (1 << a->reconf_cnt)) { - ++a->reconf_cnt; - a->reconf_sent = now; - send_reconf(iface, a); } } } - uloop_timeout_set(event, 2000); + uloop_timeout_set(event, 1000); } static size_t append_reply(uint8_t *buf, size_t buflen, uint16_t status, @@ -1123,8 +1154,7 @@ ssize_t dhcpv6_handle_ia(uint8_t *buf, size_t buflen, struct interface *iface, a->clid_len = clid_len; a->iaid = ia->iaid; a->peer = *addr; - a->reconf_cnt = 0; - a->reconf_sent = 0; + stop_reconf(a); break; } } @@ -1151,6 +1181,7 @@ ssize_t dhcpv6_handle_ia(uint8_t *buf, size_t buflen, struct interface *iface, /* Set valid time to current time indicating */ /* assignment is not having infinite lifetime */ a->valid_until = now; + a->iface = iface; if (first) memcpy(a->key, first->key, sizeof(a->key));