From: Roy Marples Date: Thu, 2 May 2019 12:02:36 +0000 (+0100) Subject: BSD: RTM_IFINFO is not emitted for all interfaces past unknown link X-Git-Tag: v7.2.2~11 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d5133a7b84a510f5feb4e3890d829aec4aadbe73;p=thirdparty%2Fdhcpcd.git BSD: RTM_IFINFO is not emitted for all interfaces past unknown link It has to work for wireless interfaces, but we have no idea about other interfaces. So test valid carrier for unknown. --- diff --git a/src/dhcpcd.h b/src/dhcpcd.h index 24782cbc..3e35a3de 100644 --- a/src/dhcpcd.h +++ b/src/dhcpcd.h @@ -85,7 +85,6 @@ struct interface { unsigned short vlanid; unsigned int metric; int carrier; - bool media_valid; bool wireless; uint8_t ssid[IF_SSIDLEN]; unsigned int ssid_len; diff --git a/src/if-bsd.c b/src/if-bsd.c index 20467dfc..637fa22b 100644 --- a/src/if-bsd.c +++ b/src/if-bsd.c @@ -203,6 +203,28 @@ if_closesockets_os(struct dhcpcd_ctx *ctx) close(priv->pf_inet6_fd); } +static int +if_carrier_flags(struct interface *ifp, unsigned int flags) +{ + struct ifmediareq ifmr = { .ifm_status = 0 }; + + strlcpy(ifmr.ifm_name, ifp->name, sizeof(ifmr.ifm_name)); + if (ioctl(ifp->ctx->pf_inet_fd, SIOCGIFMEDIA, &ifmr) == -1 || + !(ifmr.ifm_status & IFM_AVALID)) + return flags & IFF_RUNNING ? LINK_UP : LINK_UNKNOWN; + + return (ifmr.ifm_status & IFM_ACTIVE) ? LINK_UP : LINK_DOWN; +} + +int +if_carrier(struct interface *ifp) +{ + + if (if_getflags(ifp) == -1) + return LINK_UNKNOWN; + return if_carrier_flags(ifp, ifp->flags); +} + static void if_linkaddr(struct sockaddr_dl *sdl, const struct interface *ifp) { @@ -987,19 +1009,24 @@ if_ifinfo(struct dhcpcd_ctx *ctx, const struct if_msghdr *ifm) { struct interface *ifp; int link_state; + unsigned int flags; if ((ifp = if_findindex(ctx->ifaces, ifm->ifm_index)) == NULL) return; + flags = (unsigned int)ifm->ifm_flags; switch (ifm->ifm_data.ifi_link_state) { case LINK_STATE_UNKNOWN: - if (ifp->media_valid) { + /* In theory this is only set when an interface is first + * initiaised. + * However whilst some drivers report an active link + * via SIOCGIFMEDIA, they don't bother to announce it + * via a routing message. */ + if (ifp->wireless) /* Wireless need to work correctly. */ link_state = LINK_DOWN; - break; - } - /* Interface does not report media state, so we have - * to rely on IFF_UP. */ - /* FALLTHROUGH */ + else + link_state = if_carrier_flags(ifp, flags); + break; case LINK_STATE_UP: link_state = ifm->ifm_flags & IFF_UP ? LINK_UP : LINK_DOWN; break; @@ -1008,8 +1035,7 @@ if_ifinfo(struct dhcpcd_ctx *ctx, const struct if_msghdr *ifm) break; } - dhcpcd_handlecarrier(ctx, link_state, - (unsigned int)ifm->ifm_flags, ifp->name); + dhcpcd_handlecarrier(ctx, link_state, flags, ifp->name); } static void diff --git a/src/if-linux.c b/src/if-linux.c index dd0fb58f..3b7fa25c 100644 --- a/src/if-linux.c +++ b/src/if-linux.c @@ -349,6 +349,15 @@ if_closesockets_os(struct dhcpcd_ctx *ctx) } } +int +if_carrier(struct interface *ifp) +{ + + if (if_getflags(ifp) == -1) + return LINK_UNKNOWN; + return ifp->flags & IFF_RUNNING ? LINK_UP : LINK_DOWN; +} + static int get_netlink(struct dhcpcd_ctx *ctx, struct iovec *iov, struct interface *ifp, int fd, int flags, diff --git a/src/if-sun.c b/src/if-sun.c index 9ab81c48..99b9fffd 100644 --- a/src/if-sun.c +++ b/src/if-sun.c @@ -171,13 +171,16 @@ if_closesockets_os(struct dhcpcd_ctx *ctx) } int -if_carrier_os(struct interface *ifp) +if_carrier(struct interface *ifp) { kstat_ctl_t *kcp; kstat_t *ksp; kstat_named_t *knp; link_state_t linkstate; + if (if_getflags(ifp) == -1) + return LINK_UNKNOWN; + kcp = kstat_open(); if (kcp == NULL) goto err; diff --git a/src/if.c b/src/if.c index efc4314c..28597dc2 100644 --- a/src/if.c +++ b/src/if.c @@ -126,65 +126,37 @@ if_closesockets(struct dhcpcd_ctx *ctx) } int -if_carrier(struct interface *ifp) +if_getflags(struct interface *ifp) { - int r; - struct ifreq ifr; -#ifdef SIOCGIFMEDIA - struct ifmediareq ifmr; -#endif + struct ifreq ifr = { .ifr_flags = 0 }; - memset(&ifr, 0, sizeof(ifr)); strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name)); - r = ioctl(ifp->ctx->pf_inet_fd, SIOCGIFFLAGS, &ifr); - if (r != -1) - ifp->flags = (unsigned int)ifr.ifr_flags; - -#ifdef __sun - return if_carrier_os(ifp); -#else - if (r == -1) - return LINK_UNKNOWN; - -#ifdef SIOCGIFMEDIA - memset(&ifmr, 0, sizeof(ifmr)); - strlcpy(ifmr.ifm_name, ifp->name, sizeof(ifmr.ifm_name)); - if (ioctl(ifp->ctx->pf_inet_fd, SIOCGIFMEDIA, &ifmr) != -1 && - ifmr.ifm_status & IFM_AVALID) - { - ifp->media_valid = true; - r = (ifmr.ifm_status & IFM_ACTIVE) ? LINK_UP : LINK_DOWN; - } else { - ifp->media_valid = false; - r = ifr.ifr_flags & IFF_RUNNING ? LINK_UP : LINK_UNKNOWN; - } -#else - r = ifr.ifr_flags & IFF_RUNNING ? LINK_UP : LINK_DOWN; -#endif -#endif /* __sun */ - return r; + if (ioctl(ifp->ctx->pf_inet_fd, SIOCGIFFLAGS, &ifr) == -1) + return -1; + ifp->flags = (unsigned int)ifr.ifr_flags; + return 0; } int if_setflag(struct interface *ifp, short flag) { - struct ifreq ifr; - int r; + struct ifreq ifr = { .ifr_flags = 0 }; + short f; + + if (if_getflags(ifp) == -1) + return -1; + + f = (short)ifp->flags; + if ((f & flag) == flag) + return 0; - memset(&ifr, 0, sizeof(ifr)); strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name)); - r = -1; - if (ioctl(ifp->ctx->pf_inet_fd, SIOCGIFFLAGS, &ifr) == 0) { - if (flag == 0 || (ifr.ifr_flags & flag) == flag) - r = 0; - else { - ifr.ifr_flags |= flag; - if (ioctl(ifp->ctx->pf_inet_fd, SIOCSIFFLAGS, &ifr) ==0) - r = 0; - } - ifp->flags = (unsigned int)ifr.ifr_flags; - } - return r; + ifr.ifr_flags = f | flag; + if (ioctl(ifp->ctx->pf_inet_fd, SIOCSIFFLAGS, &ifr) == -1) + return -1; + + ifp->flags = (unsigned int)ifr.ifr_flags; + return 0; } static int diff --git a/src/if.h b/src/if.h index f10a8c37..91bba49b 100644 --- a/src/if.h +++ b/src/if.h @@ -111,6 +111,7 @@ int if_getifaddrs(struct ifaddrs **); #define getifaddrs if_getifaddrs #endif +int if_getflags(struct interface *ifp); int if_setflag(struct interface *ifp, short flag); #define if_up(ifp) if_setflag((ifp), (IFF_UP | IFF_RUNNING)) bool if_valid_hwaddr(const uint8_t *, size_t); @@ -133,7 +134,6 @@ int if_carrier(struct interface *); int if_makealias(char *, size_t, const char *, int); #endif -int if_carrier_os(struct interface *); int if_mtu_os(const struct interface *); /*