]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
We now do ARP checking by default as recommended by RFC 2131.
authorRoy Marples <roy@marples.name>
Wed, 18 Jul 2007 11:26:59 +0000 (11:26 +0000)
committerRoy Marples <roy@marples.name>
Wed, 18 Jul 2007 11:26:59 +0000 (11:26 +0000)
Add RFC 3927 (aka IPV4LL aka APIPA) support by default.

13 files changed:
ChangeLog
Makefile
arp.c
arp.h
client.c
common.c
common.h
config.h
dhcpcd.8
dhcpcd.c
dhcpcd.h
ipv4ll.c [new file with mode: 0644]
ipv4ll.h [new file with mode: 0644]

index 40a20b3cf8726989932490408c95ed15cbd3d37f..12bedab61a07af598c54acc92b17cf452c853389 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,5 @@
+We now do ARP checking by default as recommended by RFC 2131.
+Add RFC 3927 (aka IPV4LL aka APIPA) support by default.
 Suport DHCP option (52) overload.
 Added -T test option. This just sends a DHCP_DISCOVER message and then
 prints the configuration data to stdout - we don't request a lease,
index f77e4458fcdcfb32b272f41ab6e5d7ff899b06f2..8323d5b1a44943448d1f3d0fb56a1205ed05ae0d 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-VERSION = 3.1.0_pre4
+VERSION = 3.1.0_pre5
 CFLAGS ?= -O2 -pipe
 
 # Should work for both GNU make and BSD make
@@ -47,7 +47,7 @@ TARGET = $(SBIN_TARGETS)
 
 dhcpcd_H = version.h
 dhcpcd_OBJS = arp.o client.o common.o configure.o dhcp.o dhcpcd.o duid.o \
-               info.o interface.o logger.o signals.o socket.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
diff --git a/arp.c b/arp.c
index 37b49c3cc6f25e256e30c32a3e8e43747900d1b5..83a97b43b3d64a2a12e3115dcc84804702cf18cf 100644 (file)
--- a/arp.c
+++ b/arp.c
@@ -31,6 +31,7 @@
 #include <net/if.h>
 #include <net/if_arp.h>
 #include <arpa/inet.h>
+#include <errno.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 #include "logger.h"
 #include "socket.h"
 
-/* Longer is safer and slower - 2 seconds seems a happy medium */
-#define TIMEOUT 2 
+/* These are really for IPV4LL */
+#define NPROBES                 3
+#define PROBE_INTERVAL          200000
+#define NCLAIMS                 2
+#define CLAIM_INTERVAL          200000
 
 /* Linux does not seem to define these handy macros */
 #ifndef ar_sha
 #define IP_MIN_FRAME_LENGTH 46
 
 #ifdef ENABLE_ARP
-int arp_check (interface_t *iface, struct in_addr address)
+
+static int send_arp (interface_t *iface, int op, struct in_addr sip,
+                                        unsigned char *taddr, struct in_addr tip)
 {
        struct arphdr *arp;
-       struct arphdr *reply = NULL;
-       long timeout = 0;
-       unsigned char *buffer;
        int arpsize = arphdr_len2 (iface->hwlen, sizeof (struct in_addr));
-       int retval = 0;
-
-       if (! iface->arpable) {
-               logger (LOG_DEBUG, "arp_check: interface `%s' is not ARPable",
-                               iface->name);
-               return (0);
-       }
+       int retval;
 
-       inet_aton ("192.168.0.3", &address);
        arp = xmalloc (arpsize);
        memset (arp, 0, arpsize);
 
@@ -87,18 +83,41 @@ int arp_check (interface_t *iface, struct in_addr address)
        arp->ar_pro = htons (ETHERTYPE_IP);
        arp->ar_hln = iface->hwlen;
        arp->ar_pln = sizeof (struct in_addr);
-       arp->ar_op = htons (ARPOP_REQUEST);
+       arp->ar_op = htons (op);
        memcpy (ar_sha (arp), &iface->hwaddr, arp->ar_hln);
-       memcpy (ar_tpa (arp), &address, arp->ar_pln);
+       memcpy (ar_spa (arp), &sip, arp->ar_pln);
+       if (taddr)
+               memcpy (ar_tha (arp), taddr, arp->ar_hln); 
+       memcpy (ar_tpa (arp), &tip, arp->ar_pln);
+
+       retval = send_packet (iface, ETHERTYPE_ARP,
+                                                 (unsigned char *) arp, arphdr_len (arp));
+       free (arp);
+       return (retval);
+}
+
+int arp_claim (interface_t *iface, struct in_addr address)
+{
+       struct arphdr *reply = NULL;
+       long timeout = 0;
+       unsigned char *buffer;
+       int retval = -1;
+       int nprobes = 0;
+       int nclaims = 0;
+       struct in_addr null_address;
+
+       if (! iface->arpable) {
+               logger (LOG_DEBUG, "interface `%s' is not ARPable", iface->name);
+               return (0);
+       }
 
        logger (LOG_INFO, "checking %s is available on attached networks",
                        inet_ntoa (address));
 
-       open_socket (iface, true);
-       send_packet (iface, ETHERTYPE_ARP, (unsigned char *) arp,
-                                arphdr_len (arp));
+       if (! open_socket (iface, true))
+               return (0);
 
-       timeout = uptime() + TIMEOUT;
+       memset (&null_address, 0, sizeof (null_address));
 
        buffer = xmalloc (sizeof (char *) * iface->buffer_length);
 
@@ -111,21 +130,40 @@ int arp_check (interface_t *iface, struct in_addr address)
                int buflen = sizeof (char *) * iface->buffer_length;
                fd_set rset;
                int bytes;
+               int s;
 
-               tv.tv_sec = timeout - uptime();
-               tv.tv_usec = 0;
-
-               if (tv.tv_sec < 1)
-                       break; /* Time out */
+               tv.tv_sec = 0; 
+               tv.tv_usec = timeout;
 
                FD_ZERO (&rset);
                FD_SET (iface->fd, &rset);
-               if (select (FD_SETSIZE, &rset, NULL, NULL, &tv) == 0)
+               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 */
+                       if (nprobes < NPROBES) {
+                               nprobes ++;
+                               timeout = PROBE_INTERVAL;
+                               logger (LOG_DEBUG, "sending ARP probe #%d", nprobes);
+                               send_arp (iface, ARPOP_REQUEST, null_address, NULL, address);
+                       } else if (nclaims < NCLAIMS) {
+                               nclaims ++;
+                               timeout = CLAIM_INTERVAL;
+                               logger (LOG_DEBUG, "sending ARP claim #%d", nclaims);
+                               send_arp (iface, ARPOP_REQUEST, address, iface->hwaddr, address);
+                       } else {
+                               /* No replies, so done */
+                               retval = 0;
+                               break;
+                       }
+               }
+               
                if (! FD_ISSET (iface->fd, &rset))
                        continue;
-               
+
                memset (buffer, 0, buflen);
                while (bufpos != 0)     {
                        union {
@@ -171,7 +209,6 @@ int arp_check (interface_t *iface, struct in_addr address)
 eexit:
        close (iface->fd);
        iface->fd = -1;
-       free (arp);
        free (buffer);
        free (reply);
        return (retval);
diff --git a/arp.h b/arp.h
index bb424748cc7fe134a2693c00ca7611a3a9e4b8fd..4ed06c6d0d49d5655231b6d5799c068d60272c6f 100644 (file)
--- a/arp.h
+++ b/arp.h
@@ -25,7 +25,7 @@
 
 #include "interface.h"
 
-int arp_check (interface_t *iface, struct in_addr address);
+int arp_claim (interface_t *iface, struct in_addr address);
 #endif
 
 #endif
index 5904337bc3bd633d7fb8bfa1369cc8772fdb9a7f..234c600a780910315b68c47d69f7ddb4574dd289 100644 (file)
--- a/client.c
+++ b/client.c
@@ -51,6 +51,9 @@
 #include "dhcpcd.h"
 #include "info.h"
 #include "interface.h"
+#ifdef ENABLE_IPV4LL
+# include "ipv4ll.h"
+#endif
 #include "logger.h"
 #include "signals.h"
 #include "socket.h"
@@ -132,32 +135,9 @@ static bool daemonise (int *pidfd)
        return (true);
 }
 
-static unsigned long random_xid (void)
-{
-       static int initialized;
-
-       if (! initialized) {
-               int fd;
-               unsigned long seed;
-
-               fd = open ("/dev/urandom", 0);
-               if (fd < 0 || read (fd,  &seed, sizeof(seed)) < 0) {
-                       logger (LOG_WARNING, "Could not load seed from /dev/urandom: %s",
-                                       strerror (errno));
-                       seed = time (0);
-               }
-               if (fd >= 0)
-                       close(fd);
-
-               srand(seed);
-               initialized++;
-       }
-
-       return rand();
-}
-
 #ifdef ENABLE_INFO
-static bool get_old_lease (interface_t *iface, dhcp_t *dhcp, long *timeout)
+static bool get_old_lease (const options_t *options, interface_t *iface,
+                                                  dhcp_t *dhcp, long *timeout)
 {
        struct timeval tv;
        unsigned int offset = 0;
@@ -170,6 +150,21 @@ static bool get_old_lease (interface_t *iface, dhcp_t *dhcp, long *timeout)
        memset (&dhcp->serveraddress, 0, sizeof (struct in_addr));
        memset (dhcp->servername, 0, sizeof (dhcp->servername));
 
+#ifdef ENABLE_ARP
+       /* Check that no-one is using the address */
+       if ((options->dolastlease ||
+                IN_LINKLOCAL (dhcp->address.s_addr)) &&
+               arp_claim (iface, dhcp->address)) {
+               memset (&dhcp->address, 0, sizeof (struct in_addr));
+               memset (&dhcp->netmask, 0, sizeof (struct in_addr));
+               memset (&dhcp->broadcast, 0, sizeof (struct in_addr));
+               return (false);
+       }
+
+       /* Ok, lets use this */
+       if (IN_LINKLOCAL (dhcp->address.s_addr))
+               return (true);
+#endif
 
        /* Ensure that we can still use the lease */
        if (gettimeofday (&tv, NULL) == -1) {
@@ -191,7 +186,6 @@ static bool get_old_lease (interface_t *iface, dhcp_t *dhcp, long *timeout)
        if (timeout)
                *timeout = dhcp->renewaltime - offset;
        iface->start_uptime = uptime ();
-       logger (LOG_INFO, "using last known IP address %s", inet_ntoa (dhcp->address));
        return (true);
 }
 #endif
@@ -241,7 +235,7 @@ int dhcp_run (const options_t *options, int *pidfd)
                (options->doinform || options->dorequest))
        {
 #ifdef ENABLE_INFO
-               if (! get_old_lease (iface, dhcp, NULL))
+               if (! get_old_lease (options, iface, dhcp, NULL))
 #endif
                {
                        free (dhcp);
@@ -374,7 +368,7 @@ int dhcp_run (const options_t *options, int *pidfd)
                                        {
                                                logger (LOG_INFO, "received SIGHUP, releasing lease");
                                                SOCKET_MODE (SOCKET_OPEN);
-                                               xid = random_xid ();
+                                               xid = random ();
                                                if ((open_socket (iface, false)) >= 0)
                                                        SEND_MESSAGE (DHCP_RELEASE);
                                                SOCKET_MODE (SOCKET_CLOSED);
@@ -395,7 +389,11 @@ int dhcp_run (const options_t *options, int *pidfd)
                        /* timed out */
                        switch (state) {
                                case STATE_INIT:
-                                       if (iface->previous_address.s_addr != 0 && ! options->doinform) {
+                                       if (iface->previous_address.s_addr != 0 &&
+#ifdef ENABLE_IPV4LL
+                                               ! IN_LINKLOCAL (iface->previous_address.s_addr) &&
+#endif
+                                               ! options->doinform) {
                                                logger (LOG_ERR, "lost lease");
                                                xid = 0;
                                                SOCKET_MODE (SOCKET_CLOSED);
@@ -404,31 +402,64 @@ int dhcp_run (const options_t *options, int *pidfd)
                                        }
 
                                        if (xid == 0)
-                                               xid = random_xid ();
+                                               xid = random ();
                                        else {
                                                SOCKET_MODE (SOCKET_CLOSED);
                                                logger (LOG_ERR, "timed out");
+
+                                               free_dhcp (dhcp);
+                                               memset (dhcp, 0, sizeof (dhcp_t));
 #ifdef ENABLE_INFO
-                                               if (options->dolastlease) {
-                                                       if (! get_old_lease (iface, dhcp, &timeout))
-                                                               if (! daemonised ||
-                                                                       configure (options, iface, dhcp, true))
-                                                               {
-                                                                       retval = EXIT_FAILURE;
-                                                                       goto eexit;
-                                                               }
+                                               if (! get_old_lease (options, iface, dhcp, &timeout)) {
+                                                       if (options->dolastlease) {
+                                                               retval = EXIT_FAILURE;
+                                                               goto eexit;
+                                                       }
+
+                                                       free_dhcp (dhcp);
+                                                       memset (dhcp, 0, sizeof (dhcp_t));
+                                               }
+#endif
+
+#ifdef ENABLE_IPV4LL
+                                               if (! dhcp->address.s_addr ||
+                                                       (! IN_LINKLOCAL (dhcp->address.s_addr) &&
+                                                        ! options->dolastlease))
+                                               {
+                                                       logger (LOG_INFO, "probing for an IPV4LL address");
+                                                       free_dhcp (dhcp);
+                                                       memset (dhcp, 0, sizeof (dhcp_t));
+                                                       if (ipv4ll_get_address (iface, dhcp) == -1)
+                                                               break;
+                                                       timeout = dhcp->renewaltime;
+                                               }
+#endif
+
+#if defined (ENABLE_INFO) || defined (ENABLE_IPV4LL)
+                                               if (dhcp->address.s_addr)
+                                               {
+                                                       if (configure (options, iface, dhcp, true) < 0 &&
+                                                               ! daemonised)
+                                                       {
+                                                               retval = EXIT_FAILURE;
+                                                               goto eexit;
+                                                       }
 
                                                        state = STATE_BOUND;
                                                        if (! daemonised && options->daemonise) {
                                                                if ((daemonise (pidfd)) < 0) {
-                                                                       retval = -1;
+                                                                       retval = EXIT_FAILURE;
                                                                        goto eexit;
                                                                }
                                                                daemonised = true;
-                                                       }                   
-                                                       continue;
+                                                       }
+
+                                                       timeout = dhcp->renewaltime;
+                                                       xid = 0;
+                                                       break;
                                                }
 #endif
+
                                                if (! daemonised) {
                                                        retval = EXIT_FAILURE;
                                                        goto eexit;
@@ -456,10 +487,19 @@ int dhcp_run (const options_t *options, int *pidfd)
                                        break;
                                case STATE_BOUND:
                                case STATE_RENEW_REQUESTED:
+#ifdef ENABLE_IPV4LL
+                                       if (IN_LINKLOCAL (dhcp->address.s_addr)) {
+                                               memset (&dhcp->address, 0, sizeof (struct in_addr));
+                                               state = STATE_INIT;
+                                               xid = 0;
+                                               break;
+                                       }
+#endif
                                        state = STATE_RENEWING;
-                                       xid = random_xid ();
+                                       xid = random ();
                                case STATE_RENEWING:
                                        iface->start_uptime = uptime ();
+                                       free_dhcp (dhcp);
                                        logger (LOG_INFO, "renewing lease of %s", inet_ntoa
                                                        (dhcp->address));
                                        SOCKET_MODE (SOCKET_OPEN);
@@ -472,7 +512,7 @@ int dhcp_run (const options_t *options, int *pidfd)
                                        memset (&dhcp->address, 0, sizeof (struct in_addr));
                                        SOCKET_MODE (SOCKET_OPEN);
                                        if (xid == 0)
-                                               xid = random_xid ();
+                                               xid = random ();
                                        SEND_MESSAGE (DHCP_REQUEST);
                                        timeout = dhcp->leasetime - dhcp->rebindtime;
                                        state = STATE_REQUESTING;
@@ -604,7 +644,7 @@ int dhcp_run (const options_t *options, int *pidfd)
                                                if (options->doarp && iface->previous_address.s_addr !=
                                                        dhcp->address.s_addr)
                                                {
-                                                       if (arp_check (iface, dhcp->address)) {
+                                                       if (arp_claim (iface, dhcp->address)) {
                                                                SOCKET_MODE (SOCKET_OPEN);
                                                                SEND_MESSAGE (DHCP_DECLINE);
                                                                SOCKET_MODE (SOCKET_CLOSED);
index 7362d7933811727f531ec52dddf138b690854c57..df2f709dd21e91a9c3095e699526a981d5982bb5 100644 (file)
--- a/common.c
+++ b/common.c
 #include <errno.h>
 #include <stdlib.h>
 #include <string.h>
+#include <time.h>
 
 #include "common.h"
 #include "logger.h"
 
+/* OK, this should be in dhcpcd.c
+ * It's here to make dhcpcd more readable */
+#ifdef __linux__
+#include <fcntl.h>
+#include <unistd.h>
+void srandomdev (void) {
+       int fd;
+       unsigned long seed;
+
+       fd = open ("/dev/urandom", 0);
+       if (fd == -1 || read (fd,  &seed, sizeof(seed)) == -1) {
+               logger (LOG_WARNING, "Could not load seed from /dev/urandom: %s",
+                               strerror (errno));
+               seed = time (0);
+       }
+       if (fd >= 0)
+               close(fd);
+
+       srandom (seed);
+}
+#endif
+
 /* strlcpy is nice, shame glibc does not define it */
 #ifdef __GLIBC__
 #  if ! defined(__UCLIBC__) && ! defined (__dietlibc__)
@@ -65,7 +88,6 @@ long uptime (void)
 }
 #elif __APPLE__
 /* Darwin doesn't appear to have an uptime, so try and make one ourselves */
-#include <sys/time.h>
 long uptime (void)
 {
        struct timeval tv;
@@ -82,7 +104,6 @@ long uptime (void)
        return tv.tv_sec - start;
 }
 #else
-#include <time.h>
 long uptime (void)
 {
        struct timespec tp;
index da2962cb27930e1f091d5c69e2d15695f39999f3..2f7310f9fcd1ed1281424fbb328f8b673631ad45 100644 (file)
--- a/common.h
+++ b/common.h
@@ -32,6 +32,10 @@ size_t strlcpy (char *dst, const char *src, size_t size);
 #  endif
 #endif
 
+#ifdef __linux__
+void srandomdev (void);
+#endif
+
 long uptime (void);
 void *xmalloc (size_t size);
 char *xstrdup (const char *str);
index df1ca3ad1baebaa7f06c12b42ec73c8845aba8ec..00155492c890335ea8d3607c1598eb07a0d517e2 100644 (file)
--- a/config.h
+++ b/config.h
 /* Define this to enable some compatability with 1.x and 2.x info files */
 // #define ENABLE_INFO_COMPAT
 
+/* IPV4LL, aka ZeroConf, aka APIPA, aka RFC 3927.
+ * Needs ARP. */
+#define ENABLE_IPV4LL
+
 /* We will auto create a DUID_LLT file if it doesn't exist.
  * You can always create your own DUID file that just contains the
  * hex string that represents the DUID.
index 6db1c718014451968ef177b13b0d5b1bf248c1df..27c4ed50aee331d2f4f7a642f0f0f1716445a4b5 100644 (file)
--- a/dhcpcd.8
+++ b/dhcpcd.8
@@ -1,6 +1,6 @@
 .\" $Id$
 .\"
-.TH DHCPCD 8 "12 Jul 2007" "dhcpcd 3.1"
+.TH DHCPCD 8 "18 Jul 2007" "dhcpcd 3.1"
 
 .SH NAME
 dhcpcd \- DHCP client daemon
@@ -9,7 +9,7 @@ dhcpcd \- DHCP client daemon
 .in +.5i
 .ti -.5i
 dhcpcd
-\%[\-adknpEGHMNRTY]
+\%[\-dknpAEGHMLNRTY]
 \%[\-c\ script]
 \%[\-h\ hostname]
 \%[\-i\ vendorClassID]
@@ -26,27 +26,26 @@ dhcpcd
 .SH DESCRIPTION
 .B dhcpcd
 is an implementation of the DHCP client specified in
-.B RFC2131.
+.B RFC 2131.
 
 It gets the host information (IP address, netmask, broadcast address,
 etc.) from a DHCP server and configures the network interface of the
 machine on which it is running. It also tries to renew the lease time
 according to
-.B RFC2131.
+.B RFC 2131.
+
+If
+.B dhcpcd
+fails to get a lease then we attempt Dynamic Configuration of IPv4
+Link-Local Addresses unless the
+.B \-L
+option is given.
 
 .SH OPTIONS
 .TP
 .BI interface
 Specifies the network interface name (eth0, eth1, etc.).
 .TP
-.BI \-a
-Do an
-.B ARP
-check on the IP address give to us by the DHCP server. We may need to do this
-if a client on the same network segment has the same IP address, however we do
-not do this by default as most DHCP servers test the IP briefly with an ICMP
-Echo request before assigning the IP address.
-.TP
 .BI \-c \ script
 .B dhcpcd
 will try to execute
@@ -187,6 +186,11 @@ fixed hardware addresses. You can specify more than one user class, but the
 total length must be less than 255 characters, -1 character for each user
 class.
 .TP
+.BI \-A
+Don't do an
+.B ARP
+check on the IP address. 
+.TP
 .BI \-E
 Will read 
 .I /var/lib/dhcpcd/dhcpcd-<interface>.info
@@ -266,6 +270,10 @@ and store the DUID part in
 uses the MAC address of the network interface. If \fB-I\fR is not given
 an option then we use the MAC address of the network interface.
 .TP
+.BI \-L
+Prevents dhcpcd from probing for IPV4LL addresses. IPV4LL is otherwise
+known as ZeroConf or APIPA and is \fBRFC 3927\fR.
+.TP
 .BI \-M
 Prevents
 .B dhcpcd
@@ -353,13 +361,16 @@ is attached.
 .SH SEE ALSO
 .LP
 .I Dynamic Host Configuration Protocol,
-RFC2132
+RFC 2131
 .LP
 .I DHCP Options and BOOTP Vendor Extensions,
-RFC2132
+RFC 2132
+.LP
+.I Dynamic Configuration of IPv4 Link-Local Addresses, 
+RFC 3927
 .LP
 .I DHCP FQDN Option specification,
-RFC4702
+RFC 4702
 
 .SH BUGS
 Please report them to http://dhcpcd.berlios.de or http://bugs.gentoo.org.
index 55ce528047a9f8c67334606dae51d1bc8bd19671..429b0f4c2e97d8997c60a1f10b241f96d8446b21 100644 (file)
--- a/dhcpcd.c
+++ b/dhcpcd.c
@@ -118,6 +118,7 @@ int main(int argc, char **argv)
                {"nogateway",   no_argument,        NULL, 'G'},
                {"sethostname", no_argument,        NULL, 'H'},
                {"clientid",    optional_argument,  NULL, 'I'},
+               {"noipv4ll",    no_argument,            NULL, 'L'},
                {"nomtu",       no_argument,        NULL, 'M'},
                {"nontp",       no_argument,        NULL, 'N'},
                {"nodns",       no_argument,        NULL, 'R'},
@@ -139,7 +140,7 @@ int main(int argc, char **argv)
        snprintf (options.classid, CLASS_ID_MAX_LEN, "%s %s", PACKAGE, VERSION);
        options.classid_len = strlen (options.classid);
 
-       options.doarp = false;
+       options.doarp = true;
        options.dodns = true;
        options.domtu = true;
        options.donis = true;
@@ -147,6 +148,7 @@ int main(int argc, char **argv)
        options.dogateway = true;
        options.daemonise = true;
        options.doinform = false;
+       options.doipv4ll = true;
        options.timeout = DEFAULT_TIMEOUT;
 
        gethostname (options.hostname, sizeof (options.hostname));
@@ -156,7 +158,7 @@ int main(int argc, char **argv)
 
        /* Don't set any optional arguments here so we retain POSIX
         * compatibility with getopt */
-       while ((opt = getopt_long(argc, argv, "ac:dh:i:kl:m:npr:s:t:u:EF:GHI:MNRTY",
+       while ((opt = getopt_long(argc, argv, "c:dh:i:kl:m:npr:s:t:u:AEF:GHI:LMNRTY",
                                                          longopts, &option_index)) != -1)
        {
                switch (opt) {
@@ -167,14 +169,6 @@ int main(int argc, char **argv)
                                                longopts[option_index].name);
                                exit (EXIT_FAILURE);
                                break;
-
-                       case 'a':
-#ifndef ENABLE_ARP
-                               logger (LOG_ERR, "arp support not compiled into dhcpcd");
-                               exit (EXIT_FAILURE);
-#endif
-                               options.doarp = true;
-                               break;
                        case 'c':
                                options.script = optarg;
                                break;
@@ -283,6 +277,13 @@ int main(int argc, char **argv)
                                        options.userclass_len += (strlen (optarg)) + 1;
                                }
                                break;
+                       case 'A':
+#ifndef ENABLE_ARP
+                               logger (LOG_ERR, "arp support not compiled into dhcpcd");
+                               exit (EXIT_FAILURE);
+#endif
+                               options.doarp = false;
+                               break;
                        case 'E':
 #ifndef ENABLE_INFO
                                logger (LOG_ERR, "info support not compiled into dhcpcd");
@@ -325,6 +326,9 @@ int main(int argc, char **argv)
                                        options.clientid_len = -1;
                                }
                                break;
+                       case 'L':
+                               options.doipv4ll = false;
+                               break;
                        case 'M':
                                options.domtu = false;
                                break;
@@ -477,6 +481,9 @@ int main(int argc, char **argv)
                logger (LOG_INFO, PACKAGE " " VERSION " starting");
        }
 
+       /* Seed random */
+       srandomdev ();
+
        if (dhcp_run (&options, &pidfd)) {
                if (pidfd > -1)
                        close (pidfd);
index 065943db674501aac0c5f317532484e37e8b3cbf..7c6d9c2080b677f2befcb58e1acde07943cf6e78 100644 (file)
--- a/dhcpcd.h
+++ b/dhcpcd.h
@@ -61,6 +61,7 @@ typedef struct options_t {
        bool dolastlease;
        bool doinform;
        bool dorequest;
+       bool doipv4ll;
 
        struct in_addr request_address;
        struct in_addr request_netmask;
diff --git a/ipv4ll.c b/ipv4ll.c
new file mode 100644 (file)
index 0000000..bb6a7b1
--- /dev/null
+++ b/ipv4ll.c
@@ -0,0 +1,63 @@
+/*
+ * dhcpcd - DHCP client daemon -
+ * Copyright 2006-2007 Roy Marples <uberlord@gentoo.org>
+ *
+ * dhcpcd is an RFC2131 compliant DHCP client daemon.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+
+#include "config.h"
+#include "arp.h"
+#include "ipv4ll.h"
+
+#ifdef ENABLE_IPV4LL
+
+#ifndef ENABLE_ARP
+#error IPV4LL requires ARP
+#endif
+
+#define IPV4LL_LEASETIME 10 
+
+int ipv4ll_get_address (interface_t *iface, dhcp_t *dhcp) {
+       struct in_addr addr;
+
+       while (1) {
+               addr.s_addr = htonl (LINKLOCAL_ADDR |
+                                                        ((abs (random ()) % 0xFD00) + 0x0100));
+               errno = 0;
+               if (! arp_claim (iface, addr))
+                       break;
+               /* Our ARP may have been interrupted */
+               if (errno == EINTR)
+                       return (-1);
+       }
+
+       dhcp->address.s_addr = addr.s_addr;
+       dhcp->netmask.s_addr = htonl (LINKLOCAL_MASK);
+       dhcp->broadcast.s_addr = htonl (LINKLOCAL_BRDC);
+
+       /* Finally configure some DHCP like lease times */
+       dhcp->leasetime = IPV4LL_LEASETIME;
+       dhcp->renewaltime = (dhcp->leasetime * 0.5);
+       dhcp->rebindtime = (dhcp->leasetime * 0.875);
+
+       return (0);
+}
+
+#endif
diff --git a/ipv4ll.h b/ipv4ll.h
new file mode 100644 (file)
index 0000000..f05d188
--- /dev/null
+++ b/ipv4ll.h
@@ -0,0 +1,37 @@
+/*
+ * dhcpcd - DHCP client daemon -
+ * Copyright 2005 - 2007 Roy Marples <uberlord@gentoo.org>
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef IPV4LL_H
+#define IPV4LL_H
+
+#ifdef ENABLE_IPV4LL
+
+#include "dhcp.h"
+#include "interface.h"
+
+#define LINKLOCAL_ADDR       0xa9fe0000
+#define LINKLOCAL_MASK       0xffff0000
+#define LINKLOCAL_BRDC          0xa9feffff
+
+#define IN_LINKLOCAL(addr) ((ntohl (addr) & IN_CLASSB_NET) == LINKLOCAL_ADDR)
+
+int ipv4ll_get_address (interface_t *iface, dhcp_t *dhcp);
+
+#endif
+#endif