]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
Fix dhcpcd owning the RA if the kernel has disabled RA but there
authorRoy Marples <roy@marples.name>
Mon, 1 Jul 2013 19:23:19 +0000 (19:23 +0000)
committerRoy Marples <roy@marples.name>
Mon, 1 Jul 2013 19:23:19 +0000 (19:23 +0000)
is no directive in dhcpcd.conf

dhcpcd.c
ipv6.c
ipv6rs.c
platform-bsd.c
platform-linux.c
platform.h

index c2cb2eac3b309673af6bc78772cc3b426fe77e8e..6b15de861dc3038e0e6e9979f75151ff088c8b01 100644 (file)
--- a/dhcpcd.c
+++ b/dhcpcd.c
@@ -294,6 +294,7 @@ static void
 configure_interface1(struct interface *ifp)
 {
        struct if_options *ifo = ifp->options;
+       int ra_global, ra_iface;
 
        /* Do any platform specific configuration */
        if_conf(ifp);
@@ -313,8 +314,13 @@ configure_interface1(struct interface *ifp)
 
        /* We want to disable kernel interface RA as early as possible. */
        if (ifo->options & DHCPCD_IPV6RS) {
-               if (check_ipv6(NULL) != 1 || check_ipv6(ifp->name) != 1)
+               ra_global = check_ipv6(NULL, options & DHCPCD_IPV6RA_OWN);
+               ra_iface = check_ipv6(ifp->name,
+                   ifp->options->options & DHCPCD_IPV6RA_OWN);
+               if (ra_global == -1 || ra_iface == -1)
                        ifo->options &= ~DHCPCD_IPV6RS;
+               else if (ra_iface == 0)
+                       ifo->options |= DHCPCD_IPV6RA_OWN;
        }
 
        /* If we haven't specified a ClientID and our hardware address
diff --git a/ipv6.c b/ipv6.c
index 096996cccbe5eedcf36e49e14b99409bc4eee465..f98ccad45782114ce86dbadc9c523209a47d52a9 100644 (file)
--- a/ipv6.c
+++ b/ipv6.c
@@ -921,6 +921,8 @@ ipv6_build_dhcp_routes(struct rt6head *dnr, enum DH6S dstate)
        struct rt6 *rt;
 
        TAILQ_FOREACH(ifp, ifaces, next) {
+               if (!(ifp->options->options & DHCPCD_IPV6RA_OWN))
+                       continue;
                d6_state = D6_CSTATE(ifp);
                if (d6_state && d6_state->state == dstate) {
                        TAILQ_FOREACH(addr, &d6_state->addrs, next) {
@@ -941,9 +943,7 @@ ipv6_buildroutes(void)
        struct rt6head dnr, *nrs;
        struct rt6 *rt, *rtn, *or;
        uint8_t have_default;
-
-       if (!(options & (DHCPCD_IPV6RA_OWN | DHCPCD_IPV6RA_OWN_DEFAULT)))
-               return;
+       unsigned long long o;
 
        TAILQ_INIT(&dnr);
 
@@ -1017,9 +1017,10 @@ ipv6_buildroutes(void)
        while ((rt = TAILQ_LAST(routes, rt6head))) {
                TAILQ_REMOVE(routes, rt, next);
                if (find_route6(nrs, rt) == NULL) {
+                       o = rt->iface->options->options;
                        if (!have_default &&
-                           (options & DHCPCD_IPV6RA_OWN_DEFAULT) &&
-                           !(options & DHCPCD_IPV6RA_OWN) &&
+                           (o & DHCPCD_IPV6RA_OWN_DEFAULT) &&
+                           !(o & DHCPCD_IPV6RA_OWN) &&
                            RT_IS_DEFAULT(rt))
                                have_default = 1;
                                /* no need to add it back to our routing table
index 0d54b4e54a2b5910db611e944543842b98f9a755..5969f627207591cd04befd43ed20eb133ed022e6 100644 (file)
--- a/ipv6rs.c
+++ b/ipv6rs.c
@@ -912,7 +912,7 @@ ipv6rs_handledata(__unused void *arg)
                script_runreason(ifp, "TEST");
                goto handle_flag;
        }
-       if (options & DHCPCD_IPV6RA_OWN)
+       if (ifp->options->options & DHCPCD_IPV6RA_OWN)
                ipv6ns_probeaddrs(&rap->addrs);
        ipv6_buildroutes();
 
index be53503974fff9d4457e31ed3a2fd6d774172db4..9bb2b86329ea23fbb5b88335f9683b6d8d492372 100644 (file)
@@ -118,52 +118,55 @@ ipv6_ra_flush(void)
 }
 
 int
-check_ipv6(const char *ifname)
+check_ipv6(const char *ifname, int own)
 {
-       static int ipv6_checked = 0;
-       int r;
+       static int set_restore = 0, forward_warned = 0, global_ra = 0;
+       int ra, forward;
 
-       /* BSD doesn't support these values per iface, so just return 1 */
+       /* BSD doesn't support these values per iface, so just return
+        * the global ra setting */
        if (ifname)
-               return 1;
-
-       if (ipv6_checked)
-               return 1;
-       ipv6_checked = 1;
+               return global_ra;
 
-       r = get_inet6_sysctl(IPV6CTL_ACCEPT_RTADV);
-       if (r == -1)
+       ra = get_inet6_sysctl(IPV6CTL_ACCEPT_RTADV);
+       if (ra == -1)
                /* The sysctl probably doesn't exist, but this isn't an
                 * error as such so just log it and continue */
                syslog(errno == ENOENT ? LOG_DEBUG : LOG_WARNING,
                    "IPV6CTL_ACCEPT_RTADV: %m");
-       else if (r == 0)
-               options |= DHCPCD_IPV6RA_OWN;
-       else if (options & DHCPCD_IPV6RA_OWN) {
+       else if (ra != 0 && own) {
                syslog(LOG_INFO, "disabling Kernel IPv6 RA support");
                if (set_inet6_sysctl(IPV6CTL_ACCEPT_RTADV, 0) == -1) {
                        syslog(LOG_ERR, "IPV6CTL_ACCEPT_RTADV: %m");
-                       return 0;
+                       return ra;
+               }
+               if (!set_restore) {
+                       set_restore = 1;
+                       atexit(restore_kernel_ra);
                }
-               atexit(restore_kernel_ra);
+               ra = 0;
        }
-
-       r = get_inet6_sysctl(IPV6CTL_FORWARDING);
-       if (r == -1)
-               /* The sysctl probably doesn't exist, but this isn't an
-                * error as such so just log it and continue */
-               syslog(errno == ENOENT ? LOG_DEBUG : LOG_WARNING,
-                   "IPV6CTL_FORWARDING: %m");
-       else if (r != 0) {
-               syslog(LOG_WARNING,
-                   "Kernel is configured as a router, not a host");
-               return 0;
+       if (ifname == NULL)
+               global_ra = ra;
+
+       if (!forward_warned) {
+               forward = get_inet6_sysctl(IPV6CTL_FORWARDING);
+               if (forward == -1)
+                       /* The sysctl probably doesn't exist, but this isn't an
+                        * error as such so just log it and continue */
+                       syslog(errno == ENOENT ? LOG_DEBUG : LOG_WARNING,
+                           "IPV6CTL_FORWARDING: %m");
+               else if (forward != 0) {
+                       forward_warned = 1;
+                       syslog(LOG_WARNING,
+                           "Kernel is configured as a router, not a host");
+               }
        }
 
        /* Flush the kernel knowledge of advertised routers */
        ipv6_ra_flush();
 
-       return 1;
+       return ra;
 }
 
 int
index f5bbbfc532cbc8136699c3ea3ad18cf609276b1e..7c415d2fb35c3546f9c786d3ee1d686016747f58 100644 (file)
@@ -176,10 +176,10 @@ restore_kernel_ra(void)
 }
 
 int
-check_ipv6(const char *ifname)
+check_ipv6(const char *ifname, int own)
 {
        static int ipv6_checked = 0;
-       int r, ex, i;
+       int ra, forward, ex, i;
        char path[256], *p, **nrest;
 
        if (ifname == NULL) {
@@ -192,20 +192,18 @@ check_ipv6(const char *ifname)
                ex = 0;
 
        snprintf(path, sizeof(path), "%s/%s/accept_ra", prefix, ifname);
-       r = check_proc_int(path);
-       if (r == -1)
+       ra = check_proc_int(path);
+       if (ra == -1)
                /* The sysctl probably doesn't exist, but this isn't an
                 * error as such so just log it and continue */
                syslog(errno == ENOENT ? LOG_DEBUG : LOG_WARNING,
                    "%s: %m", path);
-       else if (r == 0)
-               options |= DHCPCD_IPV6RA_OWN;
-       else if (options & DHCPCD_IPV6RA_OWN) {
+       else if (ra != 0 && own) {
                syslog(LOG_INFO, "%s: disabling Kernel IPv6 RA support",
                    ifname);
                if (write_path(path, "0") == -1) {
                        syslog(LOG_ERR, "write_path: %s: %m", path);
-                       return 0;
+                       return ra;
                }
                for (i = 0; i < nrestore; i++)
                        if (strcmp(restore[i], ifname) == 0)
@@ -231,22 +229,22 @@ check_ipv6(const char *ifname)
        }
 
 forward:
-       if (r != 2) {
+       if (ra != 2) {
                snprintf(path, sizeof(path), "%s/%s/forwarding",
                    prefix, ifname);
-               r = check_proc_int(path);
-               if (r == -1) {
+               forward = check_proc_int(path);
+               if (forward == -1) {
                        /* The sysctl probably doesn't exist, but this isn't an
                         * error as such so just log it and continue */
                        syslog(errno == ENOENT ? LOG_DEBUG : LOG_WARNING,
                            "%s: %m", path);
-               } else if (r != 0) {
+               } else if (forward != 0) {
                        syslog(LOG_WARNING,
                            "%s: configured as a router, not a host", ifname);
                        return 0;
                }
        }
-       return 1;
+       return ra;
 }
 
 int
index 5f469e433e6e86aef87f435f49e26acf73593aa9..36086b5488600b8efe8de65395f4d6924c72df7c 100644 (file)
@@ -30,7 +30,7 @@
 
 char *hardware_platform(void);
 #ifdef INET6
-int check_ipv6(const char *);
+int check_ipv6(const char *, int);
 int ipv6_dadtransmits(const char *);
 #else
 #define check_ipv6(a) 0