summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoy Marples <roy@marples.name>2020-09-22 13:09:03 +0100
committerRoy Marples <roy@marples.name>2020-09-22 13:09:03 +0100
commit0ede9e5419b798ae5ed183ca7da7986b8d4419bd (patch)
treeb009feff69e39b125f76f361174635b6e2877b14
parent96bf083104435f38e06375fbaa094ab50626b5de (diff)
downloaddhcpcd-0ede9e5419b798ae5ed183ca7da7986b8d4419bd.tar.xz
BSD: Detect initial link state in ifa_data
Not all interfaces report media state to get the link state. However, link state is available from getifaddrs(3) ifa_data for AF_LINK addresses. Testing shows that link state is also sent correctly via route(4) messages for the same interface. This makes pppoe(4) interfaces more reliable on FreeBSD and OpenBSD.
-rw-r--r--src/if-bsd.c25
-rw-r--r--src/if-linux.c7
-rw-r--r--src/if-sun.c7
-rw-r--r--src/if.c2
-rw-r--r--src/if.h1
5 files changed, 39 insertions, 3 deletions
diff --git a/src/if-bsd.c b/src/if-bsd.c
index 98bcda63..1dacf20c 100644
--- a/src/if-bsd.c
+++ b/src/if-bsd.c
@@ -369,13 +369,34 @@ if_carrier(struct interface *ifp)
return LINK_UNKNOWN;
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))
+ if (ioctl(ifp->ctx->pf_inet_fd, SIOCGIFMEDIA, &ifmr) == -1)
+ return LINK_UNKNOWN;
+
+ if (!(ifmr.ifm_status & IFM_AVALID))
return LINK_UNKNOWN;
return (ifmr.ifm_status & IFM_ACTIVE) ? LINK_UP : LINK_DOWN;
}
+int
+if_carrier_ifadata(struct interface *ifp, void *ifadata)
+{
+ int carrier = if_carrier(ifp);
+ struct if_data *ifdata;
+
+ if (carrier != LINK_UNKNOWN || ifadata == NULL)
+ return carrier;
+
+ ifdata = ifadata;
+ switch (ifdata->ifi_link_state) {
+ case LINK_STATE_DOWN:
+ return LINK_DOWN;
+ case LINK_STATE_UP:
+ return LINK_UP;
+ }
+ return LINK_UNKNOWN;
+}
+
static void
if_linkaddr(struct sockaddr_dl *sdl, const struct interface *ifp)
{
diff --git a/src/if-linux.c b/src/if-linux.c
index 41d80d19..901c68e8 100644
--- a/src/if-linux.c
+++ b/src/if-linux.c
@@ -518,6 +518,13 @@ if_carrier(struct interface *ifp)
}
int
+if_carrier_ifadata(struct interface *ifp, __unused void *ifadata)
+{
+
+ return if_carrier(ifp);
+}
+
+int
if_getnetlink(struct dhcpcd_ctx *ctx, struct iovec *iov, int fd, int flags,
int (*cb)(struct dhcpcd_ctx *, void *, struct nlmsghdr *), void *cbarg)
{
diff --git a/src/if-sun.c b/src/if-sun.c
index be12385a..f9dc7bf1 100644
--- a/src/if-sun.c
+++ b/src/if-sun.c
@@ -246,6 +246,13 @@ err:
}
int
+if_carrier_ifadata(struct interface *ifp, __unused void *ifadata)
+{
+
+ return if_carrier(ifp);
+}
+
+int
if_mtu_os(const struct interface *ifp)
{
dlpi_handle_t dh;
diff --git a/src/if.c b/src/if.c
index d3c326a9..2907cc0e 100644
--- a/src/if.c
+++ b/src/if.c
@@ -684,7 +684,7 @@ if_discover(struct dhcpcd_ctx *ctx, struct ifaddrs **ifaddrs,
#endif
ifp->active = active;
- ifp->carrier = if_carrier(ifp);
+ ifp->carrier = if_carrier_ifadata(ifp, ifa->ifa_data);
TAILQ_INSERT_TAIL(ifs, ifp, next);
}
diff --git a/src/if.h b/src/if.h
index 4e8302ba..7123c3a1 100644
--- a/src/if.h
+++ b/src/if.h
@@ -160,6 +160,7 @@ int if_domtu(const struct interface *, short int);
#define if_getmtu(ifp) if_domtu((ifp), 0)
#define if_setmtu(ifp, mtu) if_domtu((ifp), (mtu))
int if_carrier(struct interface *);
+int if_carrier_ifadata(struct interface *, void *);
int if_pollinit(struct interface *ifp);
#ifdef ALIAS_ADDR