From 009dc39be56be9b2fae857e64aa55c20f2842d13 Mon Sep 17 00:00:00 2001 From: Roy Marples Date: Thu, 18 Jun 2020 21:15:15 +0100 Subject: [PATCH] dhcpcd: Add an option to poll the interface carrier state Only to be used if the interface does not report carrier state changes for whatever reason. --- src/common.h | 1 + src/dhcpcd.c | 21 ++++++--------------- src/dhcpcd.conf.5.in | 8 +++++++- src/dhcpcd.h | 4 ---- src/if-bsd.c | 4 ++++ src/if-options.c | 13 +++++++++++++ src/if-options.h | 2 ++ src/if.c | 26 ++++++++++++++++++++++++++ src/if.h | 5 +++++ 9 files changed, 64 insertions(+), 20 deletions(-) diff --git a/src/common.h b/src/common.h index 6a68fa15..e79d7d7f 100644 --- a/src/common.h +++ b/src/common.h @@ -43,6 +43,7 @@ #define ELOOP_IPV6ND 6 #define ELOOP_IPV6RA_EXPIRE 7 #define ELOOP_DHCP6 8 +#define ELOOP_IF 9 #ifndef HOSTNAME_MAX_LEN #define HOSTNAME_MAX_LEN 250 /* 255 - 3 (FQDN) - 2 (DNS enc) */ diff --git a/src/dhcpcd.c b/src/dhcpcd.c index 281ab5e4..c7176d93 100644 --- a/src/dhcpcd.c +++ b/src/dhcpcd.c @@ -867,7 +867,6 @@ dhcpcd_startinterface(void *arg) { struct interface *ifp = arg; struct if_options *ifo = ifp->options; - int carrier; if (ifo->options & DHCPCD_LINK) { switch (ifp->carrier) { @@ -879,19 +878,7 @@ dhcpcd_startinterface(void *arg) case LINK_UNKNOWN: /* No media state available. * Loop until both IFF_UP and IFF_RUNNING are set */ - carrier = if_carrier(ifp); - if (carrier == LINK_UNKNOWN) { - if (IF_UPANDRUNNING(ifp)) - carrier = LINK_UP; - else { - eloop_timeout_add_msec(ifp->ctx->eloop, - IF_POLL_UP * MSEC_PER_SEC, - dhcpcd_startinterface, ifp); - return; - } - } - dhcpcd_handlecarrier(ifp->ctx, carrier, - ifp->flags, ifp->name); + if_pollinit(ifp); return; } } @@ -979,8 +966,12 @@ static void dhcpcd_prestartinterface(void *arg) { struct interface *ifp = arg; + struct dhcpcd_ctx *ctx = ifp->ctx; bool anondown; + if (ifp->options->poll != 0) + if_pollinit(ifp); + if (ifp->carrier == LINK_DOWN && ifp->options->options & DHCPCD_ANONYMOUS && ifp->flags & IFF_UP) @@ -990,7 +981,7 @@ dhcpcd_prestartinterface(void *arg) } else anondown = false; - if ((!(ifp->ctx->options & DHCPCD_MASTER) || + if ((!(ctx->options & DHCPCD_MASTER) || ifp->options->options & DHCPCD_IF_UP || anondown) && !(ifp->flags & IFF_UP)) { diff --git a/src/dhcpcd.conf.5.in b/src/dhcpcd.conf.5.in index c4e08106..071bef49 100644 --- a/src/dhcpcd.conf.5.in +++ b/src/dhcpcd.conf.5.in @@ -24,7 +24,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd May 12, 2020 +.Dd June 18, 2020 .Dt DHCPCD.CONF 5 .Os .Sh NAME @@ -595,6 +595,12 @@ If detects an address added to a point to point interface (PPP, TUN, etc) then it will set the listed DHCP options to the destination address of the interface. +.It Ic poll Op Ar time +Polls the interface every +.Ar time +milliseconds (default of 100) to check flags and carrier status. +This option should only be used if the driver does not report link state +changes but can report the link state. .It Ic profile Ar name Subsequent options are only parsed for this profile .Ar name . diff --git a/src/dhcpcd.h b/src/dhcpcd.h index b165f5fc..61a6a081 100644 --- a/src/dhcpcd.h +++ b/src/dhcpcd.h @@ -66,10 +66,6 @@ #define IF_DATA_DHCP6 6 #define IF_DATA_MAX 7 -/* If the interface does not support carrier status (ie PPP), - * dhcpcd can poll it for the relevant flags periodically */ -#define IF_POLL_UP 100 /* milliseconds */ - #ifdef __QNX__ /* QNX carries defines for, but does not actually support PF_LINK */ #undef IFLR_ACTIVE diff --git a/src/if-bsd.c b/src/if-bsd.c index 090b587b..5e748a4e 100644 --- a/src/if-bsd.c +++ b/src/if-bsd.c @@ -358,6 +358,10 @@ if_carrier(struct interface *ifp) { struct ifmediareq ifmr = { .ifm_status = 0 }; + /* Not really needed, but the other OS update flags here also */ + if (if_getflags(ifp) == -1) + 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)) diff --git a/src/if-options.c b/src/if-options.c index 1b66f758..4c4ca90f 100644 --- a/src/if-options.c +++ b/src/if-options.c @@ -158,6 +158,7 @@ const struct option cf_options[] = { {"inactive", no_argument, NULL, O_INACTIVE}, {"mudurl", required_argument, NULL, O_MUDURL}, {"link_rcvbuf", required_argument, NULL, O_LINK_RCVBUF}, + {"poll", optional_argument, NULL, O_POLL}, {NULL, 0, NULL, '\0'} }; @@ -2192,6 +2193,18 @@ invalid_token: } #endif break; + case O_POLL: + if (arg == NULL) { + ifo->poll = IF_POLL_UP; + break; + } + ifo->poll = (unsigned long) + strtou(arg, NULL, 0, 0, ULONG_MAX, &e); + if (e) { + logerrx("failed to convert poll %s", arg); + return -1; + } + break; default: return 0; } diff --git a/src/if-options.h b/src/if-options.h index 2c974f57..efb69290 100644 --- a/src/if-options.h +++ b/src/if-options.h @@ -180,6 +180,7 @@ #define O_INACTIVE O_BASE + 47 #define O_MUDURL O_BASE + 48 #define O_MSUSERCLASS O_BASE + 49 +#define O_POLL O_BASE + 50 extern const struct option cf_options[]; @@ -215,6 +216,7 @@ struct if_options { time_t mtime; uint8_t iaid[4]; int metric; + unsigned long poll; uint8_t requestmask[256 / NBBY]; uint8_t requiremask[256 / NBBY]; uint8_t nomask[256 / NBBY]; diff --git a/src/if.c b/src/if.c index 9e158a9c..04a48c3b 100644 --- a/src/if.c +++ b/src/if.c @@ -64,7 +64,9 @@ #include #include +#define ELOOP_QUEUE ELOOP_IF #include "common.h" +#include "eloop.h" #include "dev.h" #include "dhcp.h" #include "dhcp6.h" @@ -661,6 +663,30 @@ if_discover(struct dhcpcd_ctx *ctx, struct ifaddrs **ifaddrs, return ifs; } +static void +if_poll(void *arg) +{ + struct interface *ifp = arg; + unsigned int flags = ifp->flags; + int carrier; + + carrier = if_carrier(ifp); /* if_carrier will update ifp->flags */ + if (ifp->carrier != carrier || ifp->flags != flags) + dhcpcd_handlecarrier(ifp->ctx, carrier, ifp->flags, ifp->name); + + if (ifp->options->poll != 0 || ifp->carrier != LINK_UP) + if_pollinit(ifp); +} + +int +if_pollinit(struct interface *ifp) +{ + unsigned long msec; + + msec = ifp->options->poll != 0 ? ifp->options->poll : IF_POLL_UP; + return eloop_timeout_add_msec(ifp->ctx->eloop, msec, if_poll, ifp); +} + /* * eth0.100:2 OR eth0i100:2 (seems to be NetBSD xvif(4) only) * diff --git a/src/if.h b/src/if.h index 8abf079a..2323501f 100644 --- a/src/if.h +++ b/src/if.h @@ -38,6 +38,10 @@ #include +/* If the interface does not support carrier status (ie PPP), + * dhcpcd can poll it for the relevant flags periodically */ +#define IF_POLL_UP 100 /* milliseconds */ + /* Some systems have in-built IPv4 DAD. * However, we need them to do DAD at carrier up as well. */ #ifdef IN_IFF_TENTATIVE @@ -156,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_pollinit(struct interface *ifp); #ifdef ALIAS_ADDR int if_makealias(char *, size_t, const char *, int); -- 2.47.2