On carrier up, set RA's to expire comletely after a few seconds.
If no valid RA's are available, kill DHCPv6.
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
}
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);
}
/* 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;
/* 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 */
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
ipv6nd_free_opts(rap);
free(rap->data);
free(rap);
-
}
ssize_t
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;
"%s: %s: router expired",
ifp->name, rap->sfrom);
rap->expired = expired = 1;
+ rap->lifetime = 0;
}
} else {
valid = 1;
* as well punt it. */
if (!valid && TAILQ_FIRST(&rap->addrs) == NULL)
ipv6nd_free_ra(rap);
+ else
+ validone = 1;
}
if (timespecisset(&next))
ipv6_buildroutes(ifp->ctx);
script_runreason(ifp, "ROUTERADVERT");
}
+
+ /* No valid routers? Kill any DHCPv6. */
+ if (!validone)
+ dhcp6_drop(ifp, "EXPIRE6");
}
void
#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 */
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