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.
This commit is contained in:
Roy Marples 2020-09-22 13:09:03 +01:00
parent 96bf083104
commit 0ede9e5419
5 changed files with 39 additions and 3 deletions

View File

@ -369,13 +369,34 @@ if_carrier(struct interface *ifp)
return LINK_UNKNOWN; return LINK_UNKNOWN;
strlcpy(ifmr.ifm_name, ifp->name, sizeof(ifmr.ifm_name)); strlcpy(ifmr.ifm_name, ifp->name, sizeof(ifmr.ifm_name));
if (ioctl(ifp->ctx->pf_inet_fd, SIOCGIFMEDIA, &ifmr) == -1 || if (ioctl(ifp->ctx->pf_inet_fd, SIOCGIFMEDIA, &ifmr) == -1)
!(ifmr.ifm_status & IFM_AVALID)) return LINK_UNKNOWN;
if (!(ifmr.ifm_status & IFM_AVALID))
return LINK_UNKNOWN; return LINK_UNKNOWN;
return (ifmr.ifm_status & IFM_ACTIVE) ? LINK_UP : LINK_DOWN; 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 static void
if_linkaddr(struct sockaddr_dl *sdl, const struct interface *ifp) if_linkaddr(struct sockaddr_dl *sdl, const struct interface *ifp)
{ {

View File

@ -517,6 +517,13 @@ if_carrier(struct interface *ifp)
return ifp->flags & IFF_RUNNING ? LINK_UP : LINK_DOWN; return ifp->flags & IFF_RUNNING ? LINK_UP : LINK_DOWN;
} }
int
if_carrier_ifadata(struct interface *ifp, __unused void *ifadata)
{
return if_carrier(ifp);
}
int int
if_getnetlink(struct dhcpcd_ctx *ctx, struct iovec *iov, int fd, int flags, if_getnetlink(struct dhcpcd_ctx *ctx, struct iovec *iov, int fd, int flags,
int (*cb)(struct dhcpcd_ctx *, void *, struct nlmsghdr *), void *cbarg) int (*cb)(struct dhcpcd_ctx *, void *, struct nlmsghdr *), void *cbarg)

View File

@ -245,6 +245,13 @@ err:
return LINK_UNKNOWN; return LINK_UNKNOWN;
} }
int
if_carrier_ifadata(struct interface *ifp, __unused void *ifadata)
{
return if_carrier(ifp);
}
int int
if_mtu_os(const struct interface *ifp) if_mtu_os(const struct interface *ifp)
{ {

View File

@ -684,7 +684,7 @@ if_discover(struct dhcpcd_ctx *ctx, struct ifaddrs **ifaddrs,
#endif #endif
ifp->active = active; ifp->active = active;
ifp->carrier = if_carrier(ifp); ifp->carrier = if_carrier_ifadata(ifp, ifa->ifa_data);
TAILQ_INSERT_TAIL(ifs, ifp, next); TAILQ_INSERT_TAIL(ifs, ifp, next);
} }

View File

@ -160,6 +160,7 @@ int if_domtu(const struct interface *, short int);
#define if_getmtu(ifp) if_domtu((ifp), 0) #define if_getmtu(ifp) if_domtu((ifp), 0)
#define if_setmtu(ifp, mtu) if_domtu((ifp), (mtu)) #define if_setmtu(ifp, mtu) if_domtu((ifp), (mtu))
int if_carrier(struct interface *); int if_carrier(struct interface *);
int if_carrier_ifadata(struct interface *, void *);
int if_pollinit(struct interface *ifp); int if_pollinit(struct interface *ifp);
#ifdef ALIAS_ADDR #ifdef ALIAS_ADDR