]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
BSD: RTM_IFINFO is not emitted for all interfaces past unknown link
authorRoy Marples <roy@marples.name>
Thu, 2 May 2019 12:02:36 +0000 (13:02 +0100)
committerRoy Marples <roy@marples.name>
Thu, 2 May 2019 12:02:36 +0000 (13:02 +0100)
It has to work for wireless interfaces, but we have no idea
about other interfaces. So test valid carrier for unknown.

src/dhcpcd.h
src/if-bsd.c
src/if-linux.c
src/if-sun.c
src/if.c
src/if.h

index 24782cbcf98e29980e9d95b159d52ce1b07da33d..3e35a3dedc71d474a16e3642b7fcff80e441b1d9 100644 (file)
@@ -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;
index 20467dfc05e6b6390e41d92d5c4203f64ad46549..637fa22b0ff374e9cbb27ab8ccb3920b85834fcc 100644 (file)
@@ -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
index dd0fb58f9aa4a7afc2f8e69ce860f1d727812950..3b7fa25ce2bf54a61fd40474e62b3ea489b18b90 100644 (file)
@@ -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,
index 9ab81c4812162dbf89b9d2497a57813fd3faaa70..99b9fffd1a78d9ea3c632cd2769e04abcb68758f 100644 (file)
@@ -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;
index efc4314c94dbb897d257416a24bcea2e1d3cf874..28597dc239f1e8c1d8a2cffe21e4df75c547c92d 100644 (file)
--- 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
index f10a8c37c89076789f3b17286a40be011602dc84..91bba49ba05bc8b0b4a3f0477647757cc50e86ce 100644 (file)
--- 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 *);
 
 /*