From: Roy Marples Date: Fri, 1 May 2015 15:52:34 +0000 (+0000) Subject: On carrier down, rebuild routes and expire RA's if keeping IP addressses. X-Git-Tag: v6.8.2~5 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2f53bfd408f7c26fbe73febf466ec3bfe8bbdf61;p=thirdparty%2Fdhcpcd.git On carrier down, rebuild routes and expire RA's if keeping IP addressses. On carrier up, set RA's to expire comletely after a few seconds. If no valid RA's are available, kill DHCPv6. --- diff --git a/dhcpcd.c b/dhcpcd.c index 76205e20..18c19e99 100644 --- a/dhcpcd.c +++ b/dhcpcd.c @@ -640,6 +640,8 @@ dhcpcd_handlecarrier(struct dhcpcd_ctx *ctx, int carrier, unsigned int flags, script_runreason(ifp, "NOCARRIER"); #ifdef NOCARRIER_PRESERVE_IP arp_close(ifp); + ipv4_buildroutes(ifp->ctx); + ipv6nd_expire(ifp, 0); #else dhcpcd_drop(ifp, 0); #endif @@ -671,6 +673,12 @@ dhcpcd_handlecarrier(struct dhcpcd_ctx *ctx, int carrier, unsigned int flags, } dhcpcd_initstate(ifp, 0); script_runreason(ifp, "CARRIER"); +#ifdef NOCARRIER_PRESERVE_IP + /* Set any IPv6 Routers we remembered to expire + * faster than they would normally as we + * maybe on a new network. */ + ipv6nd_expire(ifp, RTR_CARRIER_EXPIRE); +#endif /* RFC4941 Section 3.5 */ if (ifp->options->options & DHCPCD_IPV6RA_OWN) ipv6_gentempifid(ifp); diff --git a/ipv4.c b/ipv4.c index e517bcbb..d088d803 100644 --- a/ipv4.c +++ b/ipv4.c @@ -720,12 +720,14 @@ ipv4_buildroutes(struct dhcpcd_ctx *ctx) } /* Remove old routes we used to manage */ - TAILQ_FOREACH(rt, ctx->ipv4_routes, next) { - if (find_route(nrs, rt, NULL) == NULL && - (rt->iface->options->options & - (DHCPCD_EXITING | DHCPCD_PERSISTENT)) != - (DHCPCD_EXITING | DHCPCD_PERSISTENT)) - d_route(rt); + if (ctx->ipv4_routes) { + TAILQ_FOREACH(rt, ctx->ipv4_routes, next) { + if (find_route(nrs, rt, NULL) == NULL && + (rt->iface->options->options & + (DHCPCD_EXITING | DHCPCD_PERSISTENT)) != + (DHCPCD_EXITING | DHCPCD_PERSISTENT)) + d_route(rt); + } } ipv4_freeroutes(ctx->ipv4_routes); ctx->ipv4_routes = nrs; diff --git a/ipv6nd.c b/ipv6nd.c index ff389a44..89f6782f 100644 --- a/ipv6nd.c +++ b/ipv6nd.c @@ -54,9 +54,6 @@ /* Debugging Router Solicitations is a lot of spam, so disable it */ //#define DEBUG_RS -#define RTR_SOLICITATION_INTERVAL 4 /* seconds */ -#define MAX_RTR_SOLICITATIONS 3 /* times */ - #ifndef ND_OPT_RDNSS #define ND_OPT_RDNSS 25 struct nd_opt_rdnss { /* RDNSS option RFC 6106 */ @@ -311,9 +308,48 @@ ipv6nd_sendrsprobe(void *arg) if (state->rsprobes++ < MAX_RTR_SOLICITATIONS) eloop_timeout_add_sec(ifp->ctx->eloop, RTR_SOLICITATION_INTERVAL, ipv6nd_sendrsprobe, ifp); - else + else { logger(ifp->ctx, LOG_WARNING, "%s: no IPv6 Routers available", ifp->name); + ipv6nd_drop(ifp); + dhcp6_drop(ifp, "EXPIRE6"); + } +} + +void +ipv6nd_expire(struct interface *ifp, uint32_t seconds) +{ + struct ra *rap; + struct timespec now; + + get_monotonic(&now); + + TAILQ_FOREACH(rap, ifp->ctx->ipv6->ra_routers, next) { + if (rap->iface == ifp) { + rap->received = now; + rap->expired = seconds ? 0 : 1; + if (seconds) { + struct ra_opt *rao; + struct ipv6_addr *ap; + + rap->lifetime = seconds; + TAILQ_FOREACH(ap, &rap->addrs, next) { + if (ap->prefix_vltime) { + ap->prefix_vltime = seconds; + ap->prefix_pltime = seconds / 2; + } + } + ipv6_addaddrs(&rap->addrs); + TAILQ_FOREACH(rao, &rap->options, next) { + timespecclear(&rao->expire); + } + } + } + } + if (seconds) + ipv6nd_expirera(ifp); + else + ipv6_buildroutes(ifp->ctx); } static void @@ -407,7 +443,6 @@ void ipv6nd_freedrop_ra(struct ra *rap, int drop) ipv6nd_free_opts(rap); free(rap->data); free(rap); - } ssize_t @@ -1388,13 +1423,14 @@ ipv6nd_expirera(void *arg) struct ra *rap, *ran; struct ra_opt *rao, *raon; struct timespec now, lt, expire, next; - uint8_t expired, valid; + uint8_t expired, valid, validone; ifp = arg; get_monotonic(&now); expired = 0; timespecclear(&next); + validone = 0; TAILQ_FOREACH_SAFE(rap, ifp->ctx->ipv6->ra_routers, next, ran) { if (rap->iface != ifp) continue; @@ -1410,6 +1446,7 @@ ipv6nd_expirera(void *arg) "%s: %s: router expired", ifp->name, rap->sfrom); rap->expired = expired = 1; + rap->lifetime = 0; } } else { valid = 1; @@ -1462,6 +1499,8 @@ ipv6nd_expirera(void *arg) * as well punt it. */ if (!valid && TAILQ_FIRST(&rap->addrs) == NULL) ipv6nd_free_ra(rap); + else + validone = 1; } if (timespecisset(&next)) @@ -1471,6 +1510,10 @@ ipv6nd_expirera(void *arg) ipv6_buildroutes(ifp->ctx); script_runreason(ifp, "ROUTERADVERT"); } + + /* No valid routers? Kill any DHCPv6. */ + if (!validone) + dhcp6_drop(ifp, "EXPIRE6"); } void diff --git a/ipv6nd.h b/ipv6nd.h index cb71d746..2ab76df3 100644 --- a/ipv6nd.h +++ b/ipv6nd.h @@ -73,6 +73,14 @@ struct rs_state { #define MAX_RTR_SOLICITATION_DELAY 1 /* seconds */ #define MAX_UNICAST_SOLICIT 3 /* 3 transmissions */ +#define RTR_SOLICITATION_INTERVAL 4 /* seconds */ +#define MAX_RTR_SOLICITATIONS 3 /* times */ + +/* On carrier up, expire known routers after RTR_CARRIER_EXPIRE seconds. */ +#define RTR_CARRIER_EXPIRE \ + (MAX_RTR_SOLICITATION_DELAY + \ + (MAX_RTR_SOLICITATIONS + 1) * \ + RTR_SOLICITATION_INTERVAL) #define MAX_REACHABLE_TIME 3600000 /* milliseconds */ #define REACHABLE_TIME 30000 /* milliseconds */ @@ -98,6 +106,7 @@ void ipv6nd_runignoredra(struct interface *); void ipv6nd_handleifa(struct dhcpcd_ctx *, int, const char *, const struct in6_addr *, int); int ipv6nd_dadcompleted(const struct interface *); +void ipv6nd_expire(struct interface *, uint32_t); void ipv6nd_drop(struct interface *); void ipv6nd_neighbour(struct dhcpcd_ctx *, struct in6_addr *, int); #else