From: Roy Marples Date: Tue, 1 Jul 2014 21:06:07 +0000 (+0000) Subject: Fix link handling where kernel reported flags in LINK_UP may not be valid X-Git-Tag: v6.4.1~42 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=fa4cf79ee1fd00e29170a3a9ece480526061d728;p=thirdparty%2Fdhcpcd.git Fix link handling where kernel reported flags in LINK_UP may not be valid when we actually process them. --- diff --git a/dhcpcd.c b/dhcpcd.c index 1acc2522..d43bbf2f 100644 --- 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 1155c215..9deb6dd1 100644 --- 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 080ea07f..f2616de7 100644 --- 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 *);