]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
Fix link handling where kernel reported flags in LINK_UP may not be valid
authorRoy Marples <roy@marples.name>
Tue, 1 Jul 2014 21:06:07 +0000 (21:06 +0000)
committerRoy Marples <roy@marples.name>
Tue, 1 Jul 2014 21:06:07 +0000 (21:06 +0000)
when we actually process them.

dhcpcd.c
if.c
if.h

index 1acc25229f331786ef1dc6dd1c6486da8ca70653..d43bbf2f3180d3613a708032dfe75f0b54f938b4 100644 (file)
--- a/dhcpcd.c
+++ b/dhcpcd.c
@@ -502,10 +502,23 @@ dhcpcd_handlecarrier(struct dhcpcd_ctx *ctx, int carrier, unsigned int flags,
        if (ifp == NULL || !(ifp->options->options & DHCPCD_LINK))
                return;
 
-       if (carrier == LINK_UNKNOWN)
+       switch(carrier) {
+       case LINK_UNKNOWN:
                carrier = if_carrier(ifp); /* will set ifp->flags */
-       else
+               break;
+       case LINK_UP:
+               /* we have a carrier! however, we need to ignore the flags
+                * set in the kernel message as sometimes this message is
+                * reported before IFF_UP is set by the kernel even though
+                * dhcpcd has already set it.
+                *
+                * So we check the flags now. If IFF_UP is still not set
+                * then we should expect an accompanying link_down message */
+               if_setflag(ifp, 0); /* will set ifp->flags */
+               break;
+       default:
                ifp->flags = flags;
+       }
 
        if (carrier == LINK_UNKNOWN)
                syslog(LOG_ERR, "%s: carrier_status: %m", ifname);
@@ -582,12 +595,8 @@ pre_start(struct interface *ifp)
                syslog(LOG_ERR, "%s: ipv6_start: %m", ifp->name);
                ifp->options->options &= DHCPCD_IPV6;
        }
-
-       if (!(ifp->flags & IFF_UP) && if_up(ifp) == -1)
-               syslog(LOG_ERR, "%s: if_up: %m", ifp->name);
 }
 
-
 void
 dhcpcd_startinterface(void *arg)
 {
@@ -597,6 +606,8 @@ dhcpcd_startinterface(void *arg)
        char buf[DUID_LEN * 3];
 
        pre_start(ifp);
+       if (!if_up(ifp) == -1)
+               syslog(LOG_ERR, "%s: if_up: %m", ifp->name);
 
        if (ifp->carrier == LINK_DOWN && ifo->options & DHCPCD_LINK) {
                syslog(LOG_INFO, "%s: waiting for carrier", ifp->name);
diff --git a/if.c b/if.c
index 1155c215113859eb7c96fe5179cbf2cc455f50a3..9deb6dd1eddfe93794b745afd1266945e6f39645 100644 (file)
--- a/if.c
+++ b/if.c
@@ -133,7 +133,7 @@ if_carrier(struct interface *iface)
 }
 
 int
-if_up(struct interface *ifp)
+if_setflag(struct interface *ifp, short flag)
 {
        struct ifreq ifr;
        int s, r;
@@ -152,10 +152,10 @@ if_up(struct interface *ifp)
 #endif
        r = -1;
        if (ioctl(s, SIOCGIFFLAGS, &ifr) == 0) {
-               if ((ifr.ifr_flags & IFF_UP))
+               if (flag == 0 || ifr.ifr_flags & flag)
                        r = 0;
                else {
-                       ifr.ifr_flags |= IFF_UP;
+                       ifr.ifr_flags |= flag;
                        if (ioctl(s, SIOCSIFFLAGS, &ifr) == 0)
                                r = 0;
                }
diff --git a/if.h b/if.h
index 080ea07fa182fa94384392c8cf354dac1078ae32..f2616de7e85d5c734884d1742d5e3dc06049a6c4 100644 (file)
--- a/if.h
+++ b/if.h
@@ -90,7 +90,8 @@
 #define RAW_EOF                        1 << 0
 #define RAW_PARTIALCSUM                2 << 0
 
-int if_up(struct interface *ifp);
+int if_setflag(struct interface *ifp, short flag);
+#define if_up(ifp) if_setflag((ifp), IFF_UP)
 struct if_head *if_discover(struct dhcpcd_ctx *, int, char * const *);
 struct interface *if_find(struct dhcpcd_ctx *, const char *);
 void if_free(struct interface *);