]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
BSD: treat LINK_STATE_UNKNOWN as DOWN if media is invalid
authorRoy Marples <roy@marples.name>
Sat, 26 Jan 2019 00:08:43 +0000 (00:08 +0000)
committerRoy Marples <roy@marples.name>
Sat, 26 Jan 2019 00:08:43 +0000 (00:08 +0000)
On BSD, some interfaces might emit RTM_IFINFO before the link state
has initialised. Mainly wireless cards.
If the intial carrier call says media state change is valid,
we need to treat LINK_STATE_UNKNOWN as LINK_DOWN rather than
LINK_UP.

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

index 16b9ad2590514a9791a0a9e78bf86e4f0831474c..b395c18d421f6fc9c16273b6934f33193e145ba2 100644 (file)
@@ -84,7 +84,8 @@ struct interface {
        unsigned short vlanid;
        unsigned int metric;
        int carrier;
-       int wireless;
+       bool media_valid;
+       bool wireless;
        uint8_t ssid[IF_SSIDLEN + 1]; /* NULL terminated */
        unsigned int ssid_len;
 
index a533862449c49dba33f3028a50ff0ea55a3a111b..5ec60eb5c1312526f56b1a3f71a509e3c998822e 100644 (file)
@@ -946,16 +946,22 @@ if_ifinfo(struct dhcpcd_ctx *ctx, const struct if_msghdr *ifm)
        if ((ifp = if_findindex(ctx->ifaces, ifm->ifm_index)) == NULL)
                return;
 
-       /* If we get LINK_STATE_UNKNOWN here, it means the interface
-        * doesn't support reporting carrier state.
-        * As such, we need to rely on IFF_UP.
-        * Even if LINK_STATE_UP is reported, we also need IFF_UP as well
-        * so for dhcpcd they are equivalent and we only need to check
-        * LINK_STATE_DOWN. */
-       if (ifm->ifm_data.ifi_link_state == LINK_STATE_DOWN)
-               link_state = LINK_DOWN;
-       else
+       switch (ifm->ifm_data.ifi_link_state) {
+       case LINK_STATE_UNKNOWN:
+               if (ifp->media_valid) {
+                       link_state = LINK_DOWN;
+                       break;
+               }
+               /* Interface does not report media state, so we have
+                * to rely on IFF_UP. */
+               /* FALLTHROUGH */
+       case LINK_STATE_UP:
                link_state = ifm->ifm_flags & IFF_UP ? LINK_UP : LINK_DOWN;
+               break;
+       default:
+               link_state = LINK_DOWN;
+               break;
+       }
 
        dhcpcd_handlecarrier(ctx, link_state,
            (unsigned int)ifm->ifm_flags, ifp->name);
index 8590e6e0d98748f1508f59f300893b15b59e3b9a..e8950d7ed822d74df268b57e3ab7fa9f47bf8087 100644 (file)
--- a/src/if.c
+++ b/src/if.c
@@ -155,9 +155,13 @@ if_carrier(struct interface *ifp)
        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
+       } 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
@@ -592,7 +596,7 @@ if_discover(struct dhcpcd_ctx *ctx, struct ifaddrs **ifaddrs,
                 * we can work them out. */
                ifp->metric = 200 + ifp->index;
                if (if_getssid(ifp) != -1) {
-                       ifp->wireless = 1;
+                       ifp->wireless = true;
                        ifp->metric += 100;
                }
 #endif