]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
Ensure ARP checking times out when there is a flood.
authorRoy Marples <roy@marples.name>
Thu, 9 Aug 2007 16:25:20 +0000 (16:25 +0000)
committerRoy Marples <roy@marples.name>
Thu, 9 Aug 2007 16:25:20 +0000 (16:25 +0000)
ChangeLog
Makefile
arp.c
common.c
common.h
dhcpcd.c

index a318e496674605712c2e231e5b8554941cba7476..60d21b075f10aa26ab5fd8859e9770e78aa3654a 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,4 @@
+Ensure ARP checking times out when there is a flood.
 Add -x option to quit without releasing the lease.
 
 dhcpcd-3.1.3
index 8f64812cd4e0a877947528ebcb4b10ce00f219b4..cd0690f2797deb0a7be269b026a919b525576cc7 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-VERSION = 3.1.3
+VERSION = 3.1.4_pre3
 CFLAGS ?= -O2 -pipe
 
 # Should work for both GNU make and BSD make
@@ -49,12 +49,16 @@ dhcpcd_H = version.h
 dhcpcd_OBJS = arp.o client.o common.o configure.o dhcp.o dhcpcd.o duid.o \
                info.o interface.o ipv4ll.o logger.o signals.o socket.o
 
-# By default we don't need to link to anything
-# Except on Darwin where we need -lresolv, so they need to uncomment this
-#dhcpcd_LIBS = -lresolv
+# These are nasty hacks to work out what libs we need to link to
+# We require librt for glibc bases systems
+LIBRT != ldd /bin/date 2>/dev/null | grep -q /librt.so && echo "-lrt" || exit 0
+LIBRT ?= $(shell ldd /bin/date 2>/dev/null | grep -q /librt.so && echo "-lrt")
+
+# Darwin needs this, but we have no way of detecting this atm
+#LIBRESOLV = -lresolv
 
 dhcpcd: $(dhcpcd_H) $(dhcpcd_OBJS)
-       $(CC) $(LDFLAGS) $(dhcpcd_OBJS) $(dhcpcd_LIBS) -o dhcpcd
+       $(CC) $(LDFLAGS) $(dhcpcd_OBJS) $(LIBRT) $(LIBRESOLV) -o dhcpcd
 
 version.h:
        echo '#define VERSION "$(VERSION)"' > version.h
diff --git a/arp.c b/arp.c
index ee2df40e184235b930c54da21b90af063ca3469f..ce2ba417bb5b879bc785331a8e3c86b17832f361 100644 (file)
--- a/arp.c
+++ b/arp.c
@@ -24,7 +24,7 @@
 #include <sys/select.h>
 #include <sys/socket.h>
 #include <netinet/in_systm.h>
-#ifdef __linux
+#ifdef __linux__
 #include <netinet/ether.h>
 #include <netpacket/packet.h>
 #endif
 #define arphdr_len(ap) (arphdr_len2 ((ap)->ar_hln, (ap)->ar_pln))
 #endif
 
-#define IP_MIN_FRAME_LENGTH 46
-
 #ifdef ENABLE_ARP
 
-static int send_arp (interface_t *iface, int op, struct in_addr sip,
-                                        unsigned char *taddr, struct in_addr tip)
+static int send_arp (const interface_t *iface, int op, struct in_addr sip,
+                                        const unsigned char *taddr, struct in_addr tip)
 {
        struct arphdr *arp;
        int arpsize = arphdr_len2 (iface->hwlen, sizeof (struct in_addr));
@@ -84,7 +82,7 @@ static int send_arp (interface_t *iface, int op, struct in_addr sip,
        arp->ar_hln = iface->hwlen;
        arp->ar_pln = sizeof (struct in_addr);
        arp->ar_op = htons (op);
-       memcpy (ar_sha (arp), &iface->hwaddr, arp->ar_hln);
+       memcpy (ar_sha (arp), iface->hwaddr, arp->ar_hln);
        memcpy (ar_spa (arp), &sip, arp->ar_pln);
        if (taddr)
                memcpy (ar_tha (arp), taddr, arp->ar_hln); 
@@ -105,6 +103,11 @@ int arp_claim (interface_t *iface, struct in_addr address)
        int nprobes = 0;
        int nclaims = 0;
        struct in_addr null_address;
+       struct timeval stopat;
+       struct timeval now;
+
+       if (! iface)
+               return (-1);
 
        if (! iface->arpable) {
                logger (LOG_DEBUG, "interface `%s' is not ARPable", iface->name);
@@ -115,35 +118,39 @@ int arp_claim (interface_t *iface, struct in_addr address)
                        inet_ntoa (address));
 
        if (! open_socket (iface, true))
-               return (0);
+               return (-1);
 
-       memset (&null_address, 0, sizeof (null_address));
+       memset (&null_address, 0, sizeof (struct in_addr));
 
-       buffer = xmalloc (sizeof (char *) * iface->buffer_length);
-
-       /* Our ARP packets are always smaller - hopefully */
-       reply = xmalloc (IP_MIN_FRAME_LENGTH);
+       buffer = xmalloc (iface->buffer_length);
+       reply = xmalloc (iface->buffer_length);
 
        while (1) {
                struct timeval tv;
                int bufpos = -1;
-               int buflen = sizeof (char *) * iface->buffer_length;
+               int buflen = iface->buffer_length;
                fd_set rset;
                int bytes;
-               int s;
+               int s = 0;
 
-               tv.tv_sec = 0; 
-               tv.tv_usec = timeout;
+               /* Only select if we have a timeout */
+               if (timeout > 0) {
+                       tv.tv_sec = 0; 
+                       tv.tv_usec = timeout;
 
-               FD_ZERO (&rset);
-               FD_SET (iface->fd, &rset);
-               errno = 0;
-               if ((s = select (FD_SETSIZE, &rset, NULL, NULL, &tv)) == -1) {
-                       if (errno != EINTR)
-                               logger (LOG_ERR, "select: `%s'", strerror (errno));
-                       break;
-               } else if (s == 0) {
-                       /* Timed out */
+                       FD_ZERO (&rset);
+                       FD_SET (iface->fd, &rset);
+
+                       errno = 0;
+                       if ((s = select (FD_SETSIZE, &rset, NULL, NULL, &tv)) == -1) {
+                               if (errno != EINTR)
+                                       logger (LOG_ERR, "select: `%s'", strerror (errno));
+                               break;
+                       }
+               }
+
+               /* Timed out */
+               if (s == 0) {
                        if (nprobes < NPROBES) {
                                nprobes ++;
                                timeout = PROBE_INTERVAL;
@@ -159,8 +166,23 @@ int arp_claim (interface_t *iface, struct in_addr address)
                                retval = 0;
                                break;
                        }
+
+                       /* Setup our stop time */
+                       if (get_time (&stopat) != 0)
+                               break;
+                       stopat.tv_usec += timeout;
+
+                       continue;
+               }
+
+               /* We maybe ARP flooded, so check our time */
+               if (get_time (&now) != 0)
+                       break;
+               if (timercmp (&now, &stopat, >)) {
+                       timeout = 0;
+                       continue;
                }
-               
+
                if (! FD_ISSET (iface->fd, &rset))
                        continue;
 
@@ -175,7 +197,7 @@ int arp_claim (interface_t *iface, struct in_addr address)
                                struct ether_addr *a;
                        } rh;
 
-                       memset (reply, 0, IP_MIN_FRAME_LENGTH);
+                       memset (reply, 0, iface->buffer_length);
                        if ((bytes = get_packet (iface, (unsigned char *) reply,
                                                                         buffer,
                                                                         &buflen, &bufpos)) == -1)
@@ -196,7 +218,7 @@ int arp_claim (interface_t *iface, struct in_addr address)
 
                        rp.c = (unsigned char *) ar_spa (reply);
                        rh.c = (unsigned char *) ar_sha (reply);
-                       
+
                        /* Ensure the ARP reply is for the address we asked for */
                        if (rp.a->s_addr != address.s_addr)
                                continue;
index b699dd613b9089daf8f131a32965c0ef4b52ba04..2eb4e9376c2644908a5b2cdd92a3ecd01701ea5a 100644 (file)
--- a/common.c
+++ b/common.c
@@ -76,18 +76,47 @@ size_t strlcpy (char *dst, const char *src, size_t size)
 #  endif
 #endif
 
-/* This requires us to link to rt on glibc, so we use sysinfo instead */
-#ifdef __linux__
-#include <sys/sysinfo.h>
+/* Handy function to get the time.
+ * We only care about time advancements, not the actual time itself
+ * Which is why we use CLOCK_MONOTONIC, but it is not available on all
+ * platforms
+ */
+#ifdef CLOCK_MONOTONIC
+int get_time (struct timeval *tp)
+{
+       struct timespec ts;
+
+       if (clock_gettime (CLOCK_MONOTONIC, &ts) == -1) {
+               logger (LOG_ERR, "clock_gettime: %s", strerror (errno));
+               return (-1);
+       }
+
+       tp->tv_sec = ts.tv_sec;
+       tp->tv_usec = ts.tv_nsec / 1000;
+       return (0);
+}
+
 long uptime (void)
 {
-       struct sysinfo info;
+       struct timespec tp;
+
+       if (clock_gettime (CLOCK_MONOTONIC, &tp) == -1) {
+               logger (LOG_ERR, "clock_gettime: %s", strerror (errno));
+               return (-1);
+       }
 
-       sysinfo (&info);
-       return info.uptime;
+       return (tp.tv_sec);
 }
-#elif __APPLE__
-/* Darwin doesn't appear to have an uptime, so try and make one ourselves */
+#else
+int get_time (struct timeval *tp)
+{
+       if (gettimeofday (&tp, NULL) == -1) {
+               logger (LOG_ERR, "gettimeofday: %s", strerror (errno));
+               return (-1);
+       }
+       return (0);
+}
+
 long uptime (void)
 {
        struct timeval tv;
@@ -95,34 +124,22 @@ long uptime (void)
 
        if (gettimeofday (&tv, NULL) == -1) {
                logger (LOG_ERR, "gettimeofday: %s", strerror (errno));
-               return -1;
+               return (-1);
        }
 
        if (start == 0)
                start = tv.tv_sec;
 
-       return tv.tv_sec - start;
-}
-#else
-long uptime (void)
-{
-       struct timespec tp;
-
-       if (clock_gettime (CLOCK_MONOTONIC, &tp) == -1) {
-               logger (LOG_ERR, "clock_gettime: %s", strerror (errno));
-               return -1;
-       }
-
-       return tp.tv_sec;
+       return (tv.tv_sec - start);
 }
 #endif
 
-void *xmalloc (size_t size)
+void *xmalloc (size_t s)
 {
-       void *value = malloc (size);
+       void *value = malloc (s);
 
        if (value)
-               return value;
+               return (value);
 
        logger (LOG_ERR, "memory exhausted");
        exit (EXIT_FAILURE);
index 2f7310f9fcd1ed1281424fbb328f8b673631ad45..79940997db0ad2166c9283eed377d30297b00b77 100644 (file)
--- a/common.h
+++ b/common.h
@@ -23,6 +23,7 @@
 #define COMMON_H
 
 /* string.h pulls in features.h so the below define checks work */
+#include <sys/time.h>
 #include <string.h>
 
 /* Only GLIBC doesn't support strlcpy */
@@ -36,6 +37,7 @@ size_t strlcpy (char *dst, const char *src, size_t size);
 void srandomdev (void);
 #endif
 
+int get_time (struct timeval *tp);
 long uptime (void);
 void *xmalloc (size_t size);
 char *xstrdup (const char *str);
index 5f510269a745ea445b30d56160fe0804fc2751e7..63f922da04c0743905f651d25160c44abdd57949 100644 (file)
--- a/dhcpcd.c
+++ b/dhcpcd.c
        _int = (int) _number; \
 }
 
-static pid_t read_pid(const char *pidfile)
+static pid_t read_pid (const char *pidfile)
 {
        FILE *fp;
-       pid_t pid;
+       pid_t pid = 0;
 
        if ((fp = fopen (pidfile, "r")) == NULL) {
                errno = ENOENT;