From: Roy Marples Date: Wed, 18 Jul 2007 11:26:59 +0000 (+0000) Subject: We now do ARP checking by default as recommended by RFC 2131. X-Git-Tag: v3.2.3~236 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=77659ce0359c096d8a2667541879f8a59fad8121;p=thirdparty%2Fdhcpcd.git We now do ARP checking by default as recommended by RFC 2131. Add RFC 3927 (aka IPV4LL aka APIPA) support by default. --- diff --git a/ChangeLog b/ChangeLog index 40a20b3c..12bedab6 100644 --- 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, diff --git a/Makefile b/Makefile index f77e4458..8323d5b1 100644 --- 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 37b49c3c..83a97b43 100644 --- a/arp.c +++ b/arp.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -42,8 +43,11 @@ #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 @@ -64,22 +68,14 @@ #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 bb424748..4ed06c6d 100644 --- 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 diff --git a/client.c b/client.c index 5904337b..234c600a 100644 --- 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); diff --git a/common.c b/common.c index 7362d793..df2f709d 100644 --- a/common.c +++ b/common.c @@ -23,10 +23,33 @@ #include #include #include +#include #include "common.h" #include "logger.h" +/* OK, this should be in dhcpcd.c + * It's here to make dhcpcd more readable */ +#ifdef __linux__ +#include +#include +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 long uptime (void) { struct timeval tv; @@ -82,7 +104,6 @@ long uptime (void) return tv.tv_sec - start; } #else -#include long uptime (void) { struct timespec tp; diff --git a/common.h b/common.h index da2962cb..2f7310f9 100644 --- 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); diff --git a/config.h b/config.h index df1ca3ad..00155492 100644 --- a/config.h +++ b/config.h @@ -33,6 +33,10 @@ /* 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. diff --git a/dhcpcd.8 b/dhcpcd.8 index 6db1c718..27c4ed50 100644 --- 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-.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. diff --git a/dhcpcd.c b/dhcpcd.c index 55ce5280..429b0f4c 100644 --- 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); diff --git a/dhcpcd.h b/dhcpcd.h index 065943db..7c6d9c20 100644 --- 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 index 00000000..bb6a7b1f --- /dev/null +++ b/ipv4ll.c @@ -0,0 +1,63 @@ +/* + * dhcpcd - DHCP client daemon - + * Copyright 2006-2007 Roy Marples + * + * 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 +#include + +#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 index 00000000..f05d188e --- /dev/null +++ b/ipv4ll.h @@ -0,0 +1,37 @@ +/* + * dhcpcd - DHCP client daemon - + * Copyright 2005 - 2007 Roy Marples + * + * 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