-VERSION = 3.1.3
+VERSION = 3.1.4_pre3
CFLAGS ?= -O2 -pipe
# Should work for both GNU make and BSD make
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
#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));
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);
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);
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;
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;
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)
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;
# 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;
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);