]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
Detect removal of IPv6 routes on BSD
authorRoy Marples <roy@marples.name>
Mon, 22 Sep 2014 09:33:29 +0000 (09:33 +0000)
committerRoy Marples <roy@marples.name>
Mon, 22 Sep 2014 09:33:29 +0000 (09:33 +0000)
if-bsd.c
ipv6.c
ipv6.h

index 08825a19517cd8eb8dd57121357b28bd0ea71c59..52fecc8699aec82fd6c81d8d7f3a4f3533688a8b 100644 (file)
--- a/if-bsd.c
+++ b/if-bsd.c
 #endif
 
 #define COPYOUT(sin, sa)                                                     \
-       sin.s_addr = ((sa) != NULL) ?                                         \
-           (((struct sockaddr_in *)(void *)sa)->sin_addr).s_addr : 0
+       if ((sa) && (sa)->sa_family == AF_INET)                               \
+               (sin) = ((struct sockaddr_in*)(void *)(sa))->sin_addr
 
 #define COPYOUT6(sin, sa)                                                    \
-       sin.s6_addr = ((sa) != NULL) ?                                        \
-           (((struct sockaddr_in6 *)(void *)sa)->sin6_addr).s6_addr : 0
+       if ((sa) && (sa)->sa_family == AF_INET6)                              \
+               (sin) = ((struct sockaddr_in6*)(void *)(sa))->sin6_addr
 
 #ifndef CLLADDR
 #  define CLLADDR(s) ((const char *)((s)->sdl_data + (s)->sdl_nlen))
@@ -783,6 +783,7 @@ if_managelink(struct dhcpcd_ctx *ctx)
        struct rt rt;
 #endif
 #ifdef INET6
+       struct rt6 rt6;
        struct in6_addr ia6;
        struct sockaddr_in6 *sin6;
        int ifa_flags;
@@ -846,18 +847,29 @@ if_managelink(struct dhcpcd_ctx *ctx)
                                break;
                        cp = (char *)(void *)(rtm + 1);
                        sa = (struct sockaddr *)(void *)cp;
-                       if (sa->sa_family != AF_INET)
-                               break;
-#ifdef INET
                        get_addrs(rtm->rtm_addrs, cp, rti_info);
-                       memset(&rt, 0, sizeof(rt));
-                       rt.iface = NULL;
-                       COPYOUT(rt.dest, rti_info[RTAX_DST]);
-                       COPYOUT(rt.net, rti_info[RTAX_NETMASK]);
-                       COPYOUT(rt.gate, rti_info[RTAX_GATEWAY]);
-                       ipv4_routedeleted(ctx, &rt);
+                       switch (sa->sa_family) {
+#ifdef INET
+                       case AF_INET:
+                               memset(&rt, 0, sizeof(rt));
+                               rt.iface = NULL;
+                               COPYOUT(rt.dest, rti_info[RTAX_DST]);
+                               COPYOUT(rt.net, rti_info[RTAX_NETMASK]);
+                               COPYOUT(rt.gate, rti_info[RTAX_GATEWAY]);
+                               ipv4_routedeleted(ctx, &rt);
+                               break;
 #endif
-                       break;
+#ifdef INET6
+                       case AF_INET6:
+                               memset(&rt6, 0, sizeof(rt6));
+                               rt6.iface = NULL;
+                               COPYOUT6(rt6.dest, rti_info[RTAX_DST]);
+                               COPYOUT6(rt6.net, rti_info[RTAX_NETMASK]);
+                               COPYOUT6(rt6.gate, rti_info[RTAX_GATEWAY]);
+                               ipv6_routedeleted(ctx, &rt6);
+                               break;
+#endif
+                       }
 #ifdef RTM_CHGADDR
                case RTM_CHGADDR:       /* FALLTHROUGH */
 #endif
diff --git a/ipv6.c b/ipv6.c
index 5986a18a84024fc35fb14d395a9e51066989cd5d..3ccc30bb70bc7406c21b53093bb92a9bf5748937 100644 (file)
--- a/ipv6.c
+++ b/ipv6.c
@@ -1097,7 +1097,8 @@ find_route6(struct rt6_head *rts, const struct rt6 *r)
        TAILQ_FOREACH(rt, rts, next) {
                if (IN6_ARE_ADDR_EQUAL(&rt->dest, &r->dest) &&
 #if HAVE_ROUTE_METRIC
-                   rt->iface->metric == r->iface->metric &&
+                   (r->iface == NULL || rt->iface == NULL ||
+                   rt->iface->metric == r->iface->metric)
 #endif
                    IN6_ARE_ADDR_EQUAL(&rt->net, &r->net))
                        return rt;
@@ -1110,8 +1111,9 @@ desc_route(const char *cmd, const struct rt6 *rt)
 {
        char destbuf[INET6_ADDRSTRLEN];
        char gatebuf[INET6_ADDRSTRLEN];
-       const char *ifname = rt->iface->name, *dest, *gate;
+       const char *ifname, *dest, *gate;
 
+       ifname = rt->iface ? rt->iface->name : "(no iface)";
        dest = inet_ntop(AF_INET6, &rt->dest, destbuf, INET6_ADDRSTRLEN);
        gate = inet_ntop(AF_INET6, &rt->gate, gatebuf, INET6_ADDRSTRLEN);
        if (IN6_ARE_ADDR_EQUAL(&rt->gate, &in6addr_any))
@@ -1127,6 +1129,22 @@ desc_route(const char *cmd, const struct rt6 *rt)
                    dest, ipv6_prefixlen(&rt->net), gate);
 }
 
+/* If something other than dhcpcd removes a route,
+ * we need to remove it from our internal table. */
+int
+ipv6_routedeleted(struct dhcpcd_ctx *ctx, const struct rt6 *rt)
+{
+       struct rt6 *f;
+
+       f = find_route6(ctx->ipv6->routes, rt);
+       if (f == NULL)
+               return 0;
+       desc_route("removing", f);
+       TAILQ_REMOVE(ctx->ipv6->routes, f, next);
+       free(f);
+       return 1;
+}
+
 #define n_route(a)      nc_route(1, a, a)
 #define c_route(a, b)   nc_route(0, a, b)
 static int
diff --git a/ipv6.h b/ipv6.h
index 5c932aa266e4a82790ec18e7858f7ec3a050dd2a..fac9458a03880dafce7145fdbd193c49b3219fb8 100644 (file)
--- a/ipv6.h
+++ b/ipv6.h
@@ -199,6 +199,7 @@ void ipv6_free_ll_callbacks(struct interface *);
 int ipv6_start(struct interface *);
 void ipv6_free(struct interface *);
 void ipv6_ctxfree(struct dhcpcd_ctx *);
+int ipv6_routedeleted(struct dhcpcd_ctx *, const struct rt6 *);
 int ipv6_removesubnet(struct interface *, struct ipv6_addr *);
 void ipv6_buildroutes(struct dhcpcd_ctx *);