changeset 2555:642134e8d77c draft

Fix link handling where kernel reported flags in LINK_UP may not be valid when we actually process them.
author Roy Marples <roy@marples.name>
date Tue, 01 Jul 2014 21:06:07 +0000
parents 3823ba691bbb
children 32b8516c20fc
files dhcpcd.c if.c if.h
diffstat 3 files changed, 22 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- a/dhcpcd.c	Tue Jul 01 20:34:19 2014 +0000
+++ b/dhcpcd.c	Tue Jul 01 21:06:07 2014 +0000
@@ -502,10 +502,23 @@
 	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 @@
 		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 @@
 	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);
--- a/if.c	Tue Jul 01 20:34:19 2014 +0000
+++ b/if.c	Tue Jul 01 21:06:07 2014 +0000
@@ -133,7 +133,7 @@
 }
 
 int
-if_up(struct interface *ifp)
+if_setflag(struct interface *ifp, short flag)
 {
 	struct ifreq ifr;
 	int s, r;
@@ -152,10 +152,10 @@
 #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;
 		}
--- a/if.h	Tue Jul 01 20:34:19 2014 +0000
+++ b/if.h	Tue Jul 01 21:06:07 2014 +0000
@@ -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 *);