]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
dhcpcd: Add an option to poll the interface carrier state
authorRoy Marples <roy@marples.name>
Thu, 18 Jun 2020 20:15:15 +0000 (21:15 +0100)
committerRoy Marples <roy@marples.name>
Thu, 18 Jun 2020 20:15:15 +0000 (21:15 +0100)
Only to be used if the interface does not report carrier state
changes for whatever reason.

src/common.h
src/dhcpcd.c
src/dhcpcd.conf.5.in
src/dhcpcd.h
src/if-bsd.c
src/if-options.c
src/if-options.h
src/if.c
src/if.h

index 6a68fa1549c317216de956f7c8ff74d6576f128d..e79d7d7f8e46dc622d8ba180bb22e378dd49c73b 100644 (file)
@@ -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) */
index 281ab5e432a679f5296dafe9c7e2288a78a47cb9..c7176d9350190e7238d65732b38652435d72d435 100644 (file)
@@ -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))
        {
index c4e08106a32e4618def0b6f56755b6ebac15a713..071bef49d12c26fd7e61f85a8b2ac8b11c917234 100644 (file)
@@ -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 .
index b165f5fc0510f556fc20b43d15c539166a38300d..61a6a08144dad0f6d9ba94abadccee24c7216c3e 100644 (file)
 #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
index 090b587b00f5c1a1c3c3e6b8ebfcf02ef33471d9..5e748a4e9dcfa8d8737def0fd25992b6849e650e 100644 (file)
@@ -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))
index 1b66f7589a887408d4d23442a15e64d52b2b2c86..4c4ca90f06d45c6fab794917d47a8efe67f3e475 100644 (file)
@@ -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;
        }
index 2c974f578521c19a6baccf08f2ceefaa681fd3be..efb6929093d05f7d5cc7ec154980e7b90936b2f1 100644 (file)
 #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];
index 9e158a9ccaae15b2cd8320649941a0ae1cb26f1d..04a48c3b844c8a0c655b064fec815bc049309c9b 100644 (file)
--- a/src/if.c
+++ b/src/if.c
@@ -64,7 +64,9 @@
 #include <syslog.h>
 #include <unistd.h>
 
+#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)
  *
index 8abf079a783b4fcd793747eca8c79ac856cb4a91..2323501f3b2964cd0b1e173995ceb874637e35d3 100644 (file)
--- a/src/if.h
+++ b/src/if.h
 
 #include <ifaddrs.h>
 
+/* 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);