]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
On carrier down, rebuild routes and expire RA's if keeping IP addressses.
authorRoy Marples <roy@marples.name>
Fri, 1 May 2015 15:52:34 +0000 (15:52 +0000)
committerRoy Marples <roy@marples.name>
Fri, 1 May 2015 15:52:34 +0000 (15:52 +0000)
On carrier up, set RA's to expire comletely after a few seconds.
If no valid RA's are available, kill DHCPv6.

dhcpcd.c
ipv4.c
ipv6nd.c
ipv6nd.h

index 76205e201e35be372efbd7109e3bb8c9b649663e..18c19e9906ab434f94f0e517d0706e3ef82ed08c 100644 (file)
--- 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 e517bcbbf43ffb63597512840b150544325e44ea..d088d803a8b7b9633738776109d15280401d2916 100644 (file)
--- 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;
index ff389a44c74a4f75eecbce4011a56c5ec1418458..89f6782f73a1570b248a7473945e6d97bf099f87 100644 (file)
--- 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
index cb71d746845264d730e7dc79f3a79f0dc070536a..2ab76df33cb6911b733966032cf229572f659e57 100644 (file)
--- 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