[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[DNA-DT] Patch available for DNA on RADVD.



Hi,


I'd like to make this available to the DT early,
but there's not been much SQA.

If you're interested a patch is attached, which
works with RADVD 0.7.3.

I hope it's OK to send this to the DT list...
apologies if it's not.

Greg.


A few differences from DNA:
---------------------------

TSLLAO and SLLAO processing are performed.

The DNAO is currently variant 2,

The scheduling of fastRAs is not checked, and sometimes
sends a fast multicast RA.

No variation in message format is made if the landmark is Y
(easier to not change)

Fast RAs scheduled regardless of RA contents (no landmark).

Most of my heresies have been cut out of this branch, for use
in a later paper, so it should really just be DNA proposal
behaviour.

----------------------------


Here's the build instructions.

patch -p1 --dry-run < ../DNARADVD.0.01.patch

patch -p1 < ../DNARADVD.0.01.patch

./auto; ./configure --sysconfdir=/etc ; make

setting "DNASupport on;"

Should probably be sufficient to start DNA on an Interface.

This may not yet do Hash Based FastRA.

so you may also need:

UnnegotiatedFastRA on;


diff -rub --exclude=CVS --exclude='config.[gsh]*' --exclude=depcomp --exclude=Makefile.in --new-file radvd/Makefile.am radvddna/Makefile.am
--- radvd/Makefile.am	2004-08-20 17:25:59.000000000 +1000
+++ radvddna/Makefile.am	2005-05-24 16:12:36.727222218 +1000
@@ -23,25 +23,28 @@
 ########################################################################
 
 COMMON_SRC = log.c socket.c recv.c util.c radvd.h defaults.h pathnames.h \
-	includes.h
+	includes.h dna.h
 
 sbin_PROGRAMS = radvd radvdump
 
 radvd_SOURCES = $(COMMON_SRC) radvd.c timer.c send.c process.c interface.c \
-	device.c device-common.c gram.y gram.h scanner.l
-radvd_LDADD = -lfl
+	device.c device-common.c gram.y gram.h scanner.l dna.c
+radvd_LDADD = -lfl -lcrypto 
+radvd_LDFLAGS = #-static    # ARRGH! uml problems GD??
 EXTRA_radvd_SOURCES = device-linux.c device-bsd44.c
 YFLAGS = -d
 
 radvdump_SOURCES = $(COMMON_SRC) radvdump.c
+radvdump_LDADD = -lcrypto 
+radvdump_LDFLAGS = -dynamic #-static   # not strictly necessary GD??
 
 man_MANS = radvd.8 radvdump.8 radvd.conf.5
 EXTRA_DIST = radvd.8.man radvdump.8.man radvd.conf.5.man VERSION CHANGES \
 	COPYRIGHT INTRO.html copyright.blurb radvd.conf.example
-BUILT_SOURCES = device.c
+BUILT_SOURCES = device.c gram.c scanner.c gram.h
 
 CLEANFILES = radvd.8 radvdump.8 radvd.conf.5
-DISTCLEANFILES = device.c
+DISTCLEANFILES = device.c gram.c scanner.c gram.h
 
 SUFFIXES = .man
 
diff -rub --exclude=CVS --exclude='config.[gsh]*' --exclude=depcomp --exclude=Makefile.in --new-file radvd/auto radvddna/auto
--- radvd/auto	1970-01-01 10:00:00.000000000 +1000
+++ radvddna/auto	2005-05-24 16:30:21.008158773 +1000
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+aclocal
+autoheader
+automake -a
+autoconf
+
diff -rub --exclude=CVS --exclude='config.[gsh]*' --exclude=depcomp --exclude=Makefile.in --new-file radvd/bug.txt radvddna/bug.txt
--- radvd/bug.txt	1970-01-01 10:00:00.000000000 +1000
+++ radvddna/bug.txt	2005-05-24 13:04:40.214513883 +1000
@@ -0,0 +1,65 @@
+
+
+#0  0x40086391 in _IO_file_sync () from /lib/libc.so.6
+No symbol table info available.
+#1  0x4007d58b in fflush () from /lib/libc.so.6
+No symbol table info available.
+#2  0x0804966f in ?? ()
+No symbol table info available.
+#3  0x08049750 in ?? ()
+No symbol table info available.
+#4  0x0804ad62 in ?? ()
+No symbol table info available.
+#5  0x0804b7fc in ?? ()
+No symbol table info available.
+#6  0x40045928 in sigaction () from /lib/libc.so.6
+No symbol table info available.
+#7  0x40085ff8 in _IO_do_write () from /lib/libc.so.6
+No symbol table info available.
+#8  0x40085f56 in _IO_do_write () from /lib/libc.so.6
+No symbol table info available.
+#9  0x4008632b in _IO_file_overflow () from /lib/libc.so.6
+No symbol table info available.
+#10 0x400870f5 in __overflow () from /lib/libc.so.6
+No symbol table info available.
+#11 0x40082dcf in fputc () from /lib/libc.so.6
+---Type <return> to continue, or q <return> to quit---
+No symbol table info available.
+#12 0x080496e4 in ?? ()
+No symbol table info available.
+#13 0x08049750 in ?? ()
+No symbol table info available.
+#14 0x0804f10f in ?? ()
+No symbol table info available.
+#15 0x0804d4bb in ?? ()
+No symbol table info available.
+#16 0x0804c6a5 in ?? ()
+No symbol table info available.
+#17 0x0804c536 in ?? ()
+No symbol table info available.
+#18 0x0804ab5a in ?? ()
+No symbol table info available.
+#19 0x400356cf in __libc_start_main () from /lib/libc.so.6
+No symbol table info available.
+
+
+ith this command or "print".
+(gdb) x/i 0x0804f10f
+0x804f10f <install_nc_entry+187>:       add    $0xc,%esp
+(gdb) x/i 0x08049750
+0x8049750 <dlog+36>:    jmp    0x804973e <dlog+18>
+(gdb) x/i 0x080496e4
+0x80496e4 <vlog+336>:   pop    %ecx
+(gdb) f 0x40082dcf
+#0  0x00000000 in ?? ()
+(gdb) x/i 0x40082dcf
+0x40082dcf:     Cannot access memory at address 0x40082dcf
+(gdb) x/i 0x0804b7fc
+0x804b7fc <alarm_handler+140>:  mov    0xffffffe8(%ebp),%eax
+(gdb) x/i 0x0804ad62
+0x804ad62 <timer_handler+30>:   push   $0x0
+(gdb) x/i 0x08049750
+0x8049750 <dlog+36>:    jmp    0x804973e <dlog+18>
+(gdb) x/i 0x0804966f
+0x804966f <vlog+219>:   add    $0x10,%esp
+(gdb)
diff -rub --exclude=CVS --exclude='config.[gsh]*' --exclude=depcomp --exclude=Makefile.in --new-file radvd/defaults.h radvddna/defaults.h
--- radvd/defaults.h	2005-05-24 15:56:49.187348064 +1000
+++ radvddna/defaults.h	2005-05-24 15:59:31.302993238 +1000
@@ -25,6 +25,7 @@
 #define MSG_SIZE			4096
 
 #define MAX2(X,Y) ( (( X ) >=  ( Y )) ? ( X ) : ( Y ))
+#define MIN2(X,Y) ( (( X ) >   ( Y )) ? ( Y ) : ( X ))
 
 
 /* Router Configuration Variables: */
@@ -46,10 +47,41 @@
 #define DFLT_MinDelayBetweenRAs		MIN_DELAY_BETWEEN_RAS
 #define DFLT_AdvDefaultPreference	0
 
+#define DFLT_PrefixLandmarking		0    
+#define DFLT_CompleteRA			0    
+#define DFLT_CompleteRAMaxAdv		8    
+#define DFLT_MaxDNAPrefixes		8    
+#define DFLT_InitialOverloadTime        15    /* Seconds before accounting */
+#define DFLT_OverloadTime		1800  /* Seconds before lose state */
+
 /* Options sent with RA */
 
 #define DFLT_AdvSourceLLAddress		1
 
+
+
+/* Unnegotiated FastRA */
+#define DFLT_MaxFastRARouters		10
+
+
+/* FastRA token refreshing */
+
+#define DFLT_MaxFastResponses		3	/* 3 fastras?? depletion??*/
+#define DFLT_NumUnicastFastRAs		0       /* testing */
+#define DFLT_MaxUnicastFastRAs		10  
+#define DFLT_FastRATokenInterval	1000	/* milliseconds */  
+
+/* separation of fast responses in ranked fastras */
+#define DFLT_FastRASeparation		20  /* ms */
+
+/* Process SLLAOs and create static NCEs: */
+
+#define DFLT_RecvSourceLLAddress	0
+
+/* Process Tentative Source Link Layer Address Options */
+
+#define DFLT_RecvTentativeLLAddress	0 /* draft-daley-ipv6-tsllao-01.txt */
+
 /* Each prefix has an associated: */
 
 #define DFLT_AdvValidLifetime		2592000 /* seconds */
@@ -73,6 +105,7 @@
 #define MIN_DELAY_BETWEEN_RAS_MIPv6     (30.0/1000.0)
 #define MAX_RA_DELAY_TIME		(1000.0/2.0) /* milliseconds */
 
+
 /* Host constants: */
 
 #define MAX_RTR_SOLICITATION_DELAY	1
@@ -150,6 +183,12 @@
 
 #endif
 
+/* draft-daley-ipv6-tsllao-00.txt */
+#ifndef ND_OPT_TENTATIVE_SLLA
+#define ND_OPT_TENTATIVE_SLLA        0x11 /* Not assigned yet */
+#endif
+
+
 /* Flags */
 
 #ifndef ND_RA_FLAG_HOME_AGENT
@@ -159,11 +198,24 @@
 #define ND_OPT_PI_FLAG_RADDR		0x20
 #endif
 
+
+/* TBD unnegotiated FastRA flag */
+#ifndef ND_RA_FLAG_FASTRA
+#define ND_RA_FLAG_FASTRA		0x04  /* DNA flag!! GD */
+#endif
+
+/* TBD DNA Complete RA flag */
+#ifndef ND_RA_FLAG_COMPLETERA
+#define ND_RA_FLAG_COMPLETERA           0x02  /* DNA Flag!! GD */
+#endif
+
+
 /* Configurable values */
 
 #define DFLT_HomeAgentPreference	0
 #define DFLT_HomeAgentLifetime(iface)	DFLT_AdvDefaultLifetime(iface)
 
+
 /* Other */
 
 #define MIN_MinRtrAdvInterval_MIPv6	(3.0/100.0)
@@ -176,7 +228,16 @@
 #define MIN_HomeAgentLifetime		1 /* 0 must NOT be used */
 #define MAX_HomeAgentLifetime		65520 /* 18.2 hours in secs */
 
+#define MAX_ResponseOptionLen           64  /* octets */
+
+#define MAX_Outstanding_Unicast         DFLT_MaxUnicastFastRAs 
+					/* unicast RAs scheduled at any time */
+
+#define FREE_Dynamic_Timers             ( MAX_Outstanding_Unicast )
+#define USED_Dynamic_Timers             ( ( MAX_Outstanding_Unicast ) + 1 )
+
 /* #define MAX_RTR_SOLICITATIONS This MAY be ignored by MIPv6 */
 
+#define IID_HASH_MASK32			0x00ffffff
 
 #endif
diff -rub --exclude=CVS --exclude='config.[gsh]*' --exclude=depcomp --exclude=Makefile.in --new-file radvd/device-bsd44.c radvddna/device-bsd44.c
--- radvd/device-bsd44.c	2005-05-24 15:56:49.194347228 +1000
+++ radvddna/device-bsd44.c	2005-05-24 16:17:49.117926202 +1000
@@ -248,3 +248,18 @@
 
 	return 0;
 }
+
+
+int bind_rtnlsock(void){
+    /* Not yet implemented */
+    return -1;
+}
+
+
+int install_nc_entry(int sock, struct Interface *iface, struct in6_addr *addr, unsigned char *hwaddr,
+		 int hwl , int replace){
+    /* Not yet implemented */
+    return;
+}
+
+
diff -rub --exclude=CVS --exclude='config.[gsh]*' --exclude=depcomp --exclude=Makefile.in --new-file radvd/device-linux.c radvddna/device-linux.c
--- radvd/device-linux.c	2005-05-24 15:56:49.203346154 +1000
+++ radvddna/device-linux.c	2005-05-24 16:17:35.311574529 +1000
@@ -11,6 +11,7 @@
  *   applies to this software. If your distribution is missing this file, you
  *   may request it from <lutchann@litech.org>.
  *
+ *    Greg Daley Sept 2004:   Added support for SLLAO NCE installs 
  */
 
 #include <config.h>
@@ -19,10 +20,33 @@
 #include <defaults.h>
 #include <pathnames.h>		/* for PATH_PROC_NET_IF_INET6 */
 
+#ifndef NUD_VALID
+#define NUD_VALID (NUD_REACHABLE|NUD_STALE|NUD_DELAY|NUD_PROBE)
+#endif				/* NUD_VALID */
+
+/*  rtnetlink socket includes */
+#include <asm/types.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <sys/socket.h>
+
 #ifndef IPV6_ADDR_LINKLOCAL
 #define IPV6_ADDR_LINKLOCAL   0x0020U
 #endif
 
+static int new_nd_rtnetlink(int sock, int ifindex, unsigned char *dst,
+			    unsigned char *lladdr, int lll, int state,
+			    int replace);
+static int process_ndmsg(struct ndmsg *ndm, int nll, unsigned char *dst,
+			 unsigned char *lladdr, int lll);
+static int check_nd_rtnetlink(int sock, int ifindex, unsigned char *dst,
+			      unsigned char *lladdr, int lll);
+static void clean_nl_inbuff(int sock);
+static int get_nlsequence(void);
+static int make_ndmsg(struct nlmsghdr *nlm, unsigned char *dst,
+		      unsigned char *lladdr, int lll, int state,
+		      int ifindex);
+
 /*
  * this function gets the hardware type and address of an interface,
  * determines the link layer token length and checks it against
@@ -209,6 +233,7 @@
 	return(0);
 }		
 
+
 int
 get_v4addr(const char *ifn, unsigned int *dst)
 {
@@ -247,3 +272,380 @@
 
 	return 0;
 }
+
+int
+bind_rtnlsock(void)
+{
+	int rtnetlink_socket;
+	struct sockaddr_nl local;
+
+	memset(&local, 0, sizeof(local));
+	local.nl_family = AF_NETLINK;
+
+	if ((rtnetlink_socket =
+	     socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE))
+	    < 0) {
+		flog(LOG_ERR, "Unable to get a netlink socket: %s",
+		     strerror(errno));
+		return -1;
+	}
+
+	if (bind
+	    (rtnetlink_socket, (struct sockaddr *) &local,
+	     sizeof(local)) < 0) {
+		flog(LOG_ERR, "Unable to bind a netlink socket: %s",
+		     strerror(errno));
+		return -1;
+	}
+	return rtnetlink_socket;
+}
+
+/**************************************************************************/
+
+
+
+
+static int
+new_nd_rtnetlink(int sock, int ifindex, unsigned char *dst,
+			    unsigned char *lladdr, int lll, int state,
+			    int replace)
+{
+	struct {
+		struct nlmsghdr nh;
+		struct ndmsg nd;
+		char attrbuf[360];
+	} req;
+
+	struct ndmsg *ndm;
+	struct nlmsghdr *nlm;
+	int nll;
+
+	memset(&req, 0, sizeof(req));
+
+	nlm = (struct nlmsghdr *) &req;
+
+	nlm->nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE;
+
+	nlm->nlmsg_flags |= (replace ? NLM_F_REPLACE : NLM_F_EXCL);
+	nlm->nlmsg_seq = get_nlsequence();
+	nlm->nlmsg_type = RTM_NEWNEIGH;
+	ndm = NLMSG_DATA(nlm);
+	nlm->nlmsg_len = make_ndmsg(nlm, dst, lladdr, lll, state, ifindex);
+	nll = nlm->nlmsg_len;
+
+	if (send(sock, &req, req.nh.nlmsg_len, 0) < 0) {
+		flog(LOG_ERR, "unable to send netlink message: %s",
+		     strerror(errno));
+		return -1;
+	}
+	/*system("/sbin/ip -f inet6 neigh show");*/
+	return 0;
+}
+
+
+static int
+process_ndmsg(struct ndmsg *ndm, int nll, unsigned char *dst,
+			 unsigned char *lladdr, int lll)
+{
+	int ret = 0;
+	unsigned int mlll = 0;
+	unsigned char *m_lladdr = NULL;
+	unsigned char *m_dst = NULL;
+	struct rtattr *rta;
+
+	rta = NDA_RTA(ndm);
+
+	dlog(LOG_DEBUG, 5, "NCE process i(%d) t(%d)", ndm->ndm_ifindex,
+	     ndm->ndm_type);
+
+	while (RTA_OK(rta, nll)) {
+		switch (rta->rta_type) {
+		case NDA_DST:
+			dlog(LOG_DEBUG, 4,
+			     "ent: %x:%x:%x:%x:%x:%x:%x:%x",
+			     ntohs(((struct in6_addr *)
+				    RTA_DATA(rta))->s6_addr16[0]),
+			     ntohs(((struct in6_addr *)
+				    RTA_DATA(rta))->s6_addr16[1]),
+			     ntohs(((struct in6_addr *)
+				    RTA_DATA(rta))->s6_addr16[2]),
+			     ntohs(((struct in6_addr *)
+				    RTA_DATA(rta))->s6_addr16[3]),
+			     ntohs(((struct in6_addr *)
+				    RTA_DATA(rta))->s6_addr16[4]),
+			     ntohs(((struct in6_addr *)
+				    RTA_DATA(rta))->s6_addr16[5]),
+			     ntohs(((struct in6_addr *)
+				    RTA_DATA(rta))->s6_addr16[6]),
+			     ntohs(((struct in6_addr *)
+				    RTA_DATA(rta))->s6_addr16[7]));
+
+			dlog(LOG_DEBUG, 4,
+			     "dst: %x:%x:%x:%x:%x:%x:%x:%x",
+			     ntohs(((struct in6_addr *)
+				    dst)->s6_addr16[0]),
+			     ntohs(((struct in6_addr *)
+				    dst)->s6_addr16[1]),
+			     ntohs(((struct in6_addr *)
+				    dst)->s6_addr16[2]),
+			     ntohs(((struct in6_addr *)
+				    dst)->s6_addr16[3]),
+			     ntohs(((struct in6_addr *)
+				    dst)->s6_addr16[4]),
+			     ntohs(((struct in6_addr *)
+				    dst)->s6_addr16[5]),
+			     ntohs(((struct in6_addr *)
+				    dst)->s6_addr16[6]),
+			     ntohs(((struct in6_addr *)
+				    dst)->s6_addr16[7]));
+
+			if (!memcmp(RTA_DATA(rta), dst,
+				    sizeof(struct in6_addr))) {
+				m_dst = RTA_DATA(rta);
+			}
+			break;
+		case NDA_LLADDR:
+			m_lladdr = RTA_DATA(rta);
+			mlll = RTA_PAYLOAD(rta);
+			break;
+		default:
+			break;
+		}
+		rta = RTA_NEXT(rta, nll);
+	}
+	if (m_dst) {
+		/* we have the correct entry */
+		ret = -2;
+		if (ndm->ndm_state & NUD_VALID) {
+			if (m_lladdr && (mlll == lll) && !memcmp(lladdr,
+								 m_lladdr,
+								 lll *
+								 sizeof
+								 (unsigned
+								  char))) {
+				/* entry matches, update with same state */
+				flog(LOG_ERR, "state:%x "
+				     "%02x:%02x:%02x:%02x:%02x:%02x",
+				     ndm->ndm_state,
+				     m_lladdr[0], m_lladdr[1],
+				     m_lladdr[2], m_lladdr[3],
+				     m_lladdr[4], m_lladdr[5]);
+				ret = ndm->ndm_state;
+			} else {	/* conflicting NCE ignores */
+				ret = -1;
+			}
+		}
+	}
+	return ret;
+}
+
+
+
+static int
+check_nd_rtnetlink(int sock, int ifindex, unsigned char *dst,
+			      unsigned char *lladdr, int lll)
+{
+	int recvsize;
+	struct {
+		struct nlmsghdr nh;
+		struct ndmsg nd;
+		char attrbuf[3000];
+	} req;
+	unsigned char *m_lladdr = NULL;
+
+	struct ndmsg *ndm;
+	struct nlmsghdr *nlm;
+	int nll;
+	int ret = 0;
+
+	memset(&req, 0, sizeof(struct nlmsghdr) + sizeof(struct ndmsg));
+
+	nlm = (struct nlmsghdr *) &req;
+	nlm->nlmsg_flags = NLM_F_REQUEST | NLM_F_MATCH;
+	nlm->nlmsg_seq = get_nlsequence();
+	nlm->nlmsg_type = RTM_GETNEIGH;
+	ndm = NLMSG_DATA(nlm);
+	ndm->ndm_family = AF_INET6;
+	ndm->ndm_ifindex = ifindex;
+	ndm->ndm_type = RTN_UNICAST;
+
+	nlm->nlmsg_len = make_ndmsg(nlm, dst, lladdr, lll, 0, ifindex);
+	nll = nlm->nlmsg_len;
+
+	if (send(sock, &req, nll, 0) < 0) {
+		flog(LOG_ERR, "unable to send netlink message: %s",
+		     strerror(errno));
+		return -1;
+	}
+
+	while ((recvsize = recv(sock, &req, sizeof(req), 0)) > 0) {
+		nlm = (struct nlmsghdr *) &req;
+		flog(LOG_WARNING,
+		     "received rtnetlink info of length %d %x", recvsize,
+		     nlm->nlmsg_flags);
+
+
+		while (NLMSG_OK(nlm, recvsize)) {
+
+			switch (nlm->nlmsg_type) {
+			case RTM_NEWNEIGH:
+				m_lladdr = NULL;
+				ndm = NLMSG_DATA(nlm);
+
+				nll = nlm->nlmsg_len;
+
+				if ((ret =
+				    process_ndmsg(ndm, nll, dst, lladdr,
+						  lll))) {
+					if (ret == -2)
+						ret = 0;
+					clean_nl_inbuff(sock);
+					return ret;
+				}
+				break;
+			case NLMSG_ERROR:
+				flog(LOG_ERR,
+				     "netlink error message received: %s",
+				     strerror(-((struct nlmsgerr *)
+						NLMSG_DATA(&req))->error));
+				return 0;
+			case NLMSG_DONE:
+				flog(LOG_WARNING,
+				     "netlink done message received");
+				return ret;
+			default:
+				break;
+			}
+			nlm = NLMSG_NEXT(nlm, recvsize);
+		}
+	}
+	if (recvsize < 0) {
+		flog(LOG_ERR, "unable to receive netlink message: %s",
+		     strerror(errno));
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static void
+clean_nl_inbuff(int sock)
+{
+	char buff[1500];
+	int recvsize;
+	struct nlmsghdr *nlm;
+
+	while ((recvsize = recv(sock, &buff, sizeof(buff), 0)) > 0) {
+		nlm = (struct nlmsghdr *) &buff;
+		while (NLMSG_OK(nlm, recvsize)) {
+			switch (nlm->nlmsg_type) {
+			case NLMSG_DONE:
+				return;
+				break;
+			default:
+				break;
+			}
+			nlm = NLMSG_NEXT(nlm, recvsize);
+		}
+	}
+	if (recvsize < 0) {
+		flog(LOG_ERR, "unable to receive netlink message: %s",
+		     strerror(errno));
+		return;
+	}
+}
+
+static int
+get_nlsequence(void)
+{
+	static int seq = 500;
+	return ++seq;
+}
+
+
+static int
+make_ndmsg(struct nlmsghdr *nlm, unsigned char *dst,
+		      unsigned char *lladdr, int lll, int state,
+		      int ifindex)
+{
+	struct rtattr *rta;
+	unsigned long *rtap;
+	int i;
+	struct ndmsg *ndm;
+	int nll;
+
+	ndm = NLMSG_DATA(nlm);
+	ndm->ndm_family = AF_INET6;
+	ndm->ndm_type = RTN_UNICAST;
+	ndm->ndm_ifindex = ifindex;
+	ndm->ndm_state = state;
+
+	nlm->nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg));
+	nll = nlm->nlmsg_len;
+
+	rta = NDA_RTA(ndm);
+
+	rta->rta_type = NDA_DST;
+	rta->rta_len = RTA_LENGTH(sizeof(struct in6_addr));
+	rtap = (unsigned long *) RTA_DATA(rta);
+
+	for (i = 0; i < 4; i++) {
+		/*rtap[i] =  ntohl(((struct in6_addr *)dst)->s6_addr32[i]); */
+		rtap[i] = ((struct in6_addr *) dst)->s6_addr32[i];
+	}
+	/*memcpy(RTA_DATA(rta),dst,sizeof(struct in6_addr)); */
+
+	nlm->nlmsg_len =
+	    NLMSG_ALIGN(nlm->nlmsg_len) + NLMSG_ALIGN(rta->rta_len);
+	nll = nlm->nlmsg_len;
+
+	rta = RTA_NEXT(rta, nll);
+
+	rta->rta_type = NDA_LLADDR;
+	rta->rta_len = RTA_LENGTH(lll * sizeof(unsigned char));
+	memcpy(RTA_DATA(rta), lladdr, lll);
+
+	nlm->nlmsg_len =
+	    NLMSG_ALIGN(nlm->nlmsg_len) + NLMSG_ALIGN(rta->rta_len);
+	nll = nlm->nlmsg_len;
+
+	return nll;
+}
+
+
+void
+install_nc_entry(int sock, struct Interface *iface, struct in6_addr *addr,
+		 unsigned char *hwaddr, int hwl, int replace)
+{
+	int state;
+
+	dlog(LOG_DEBUG, 4, "installing NCE on %s   replace: %d, len %d",
+	     iface->Name, replace, hwl);
+
+
+	state =
+	    check_nd_rtnetlink(sock, iface->if_index,
+			       (unsigned char *) addr, hwaddr, hwl);
+
+	if (state > 0) {
+		dlog(LOG_DEBUG, 4, "entry match\n");
+		if (new_nd_rtnetlink
+		    (sock, iface->if_index, (unsigned char *) addr, hwaddr,
+		     hwl, state, replace) < 0) {
+
+			flog(LOG_ERR, "unable to update neighbour cache");
+			return;
+		}
+	} else {
+		dlog(LOG_DEBUG, 4,
+		     "no entry or mismatch SLLAO --> STALE\n");
+		if (new_nd_rtnetlink
+		    (sock, iface->if_index, (unsigned char *) addr, hwaddr,
+		     hwl, NUD_STALE, replace) < 0) {
+			flog(LOG_ERR, "unable to %s neighbour cache entry",
+			     (replace ? "replace" : "create"));
+			return;
+		}
+	}
+}
diff -rub --exclude=CVS --exclude='config.[gsh]*' --exclude=depcomp --exclude=Makefile.in --new-file radvd/dna.c radvddna/dna.c
--- radvd/dna.c	1970-01-01 10:00:00.000000000 +1000
+++ radvddna/dna.c	2005-05-24 15:33:58.685970864 +1000
@@ -0,0 +1,258 @@
+/*
+ *   $Id: $
+ *
+ *   Authors:
+ *    Greg Daley  <greg.daley@eng.monash.edu.au>  
+ *
+ *   This software is Copyright 2004 by the above mentioned author(s), 
+ *   All Rights Reserved.
+ *
+ *   The license which is distributed with this software in the file COPYRIGHT
+ *   applies to this software. If your distribution is missing this file, you
+ *   may request it from <lutchann@litech.org>.
+ *
+ */
+
+#include <config.h>
+#include <includes.h>
+#include <radvd.h>
+#include <dna.h>
+
+
+
+	/* For each of the following functions, */
+	/* Option must be complete before return */
+
+int hdr_completera_option(struct Interface *iface, unsigned char *buffer, 
+				int offset){
+	struct nd_dna_opt_hdr *dnao;
+	struct timeval tv;
+	struct RtrPrefixList *landlist;
+	struct AdvPrefix     *prefix;
+	char addr_str[INET6_ADDRSTRLEN];
+	int i;
+
+	/* Clear the landmark list */
+
+	dnao = (struct nd_dna_opt_hdr *)&buffer[offset];
+	dnao->nd_dna_opt_type=ND_DNA_OPT_TYPE;
+	dnao->nd_dna_opt_rsvd1=0;
+	dnao->nd_dna_opt_rsvd2=0;
+
+	dnao->nd_dna_opt_len=1; /* Initially */
+	
+	landlist = iface->DNAPrefixList;
+	gettimeofday(&tv, NULL);
+
+	iface->CurrDNAPrefixes =
+		clean_rtrprefix(landlist, iface->CurrDNAPrefixes, &tv);
+
+	dnao->nd_dna_opt_numprefs=0;
+
+	return sizeof(struct nd_dna_opt_hdr);
+}
+
+
+
+int add_completera_option(struct Interface *iface, unsigned char *buffer,
+				int offset, int optlen, int *complete){
+	struct nd_dna_opt_hdr *dnao;
+	unsigned char *pptr;
+	struct RtrPrefixList *landlist;
+	int skip=0;
+	int i=0,j=0;
+	int poff=0;
+	int oldpref=0;
+	int plens=0; 
+	int added=0,newpref=0;
+	char addr_str[INET6_ADDRSTRLEN];
+	struct timeval now;
+
+	if(complete)
+		*complete=0;
+
+	dnao = (struct nd_dna_opt_hdr *)&buffer[offset];
+	pptr  = ((unsigned char *)dnao) + sizeof(struct nd_dna_opt_hdr) ;
+	landlist = iface->DNAPrefixList;
+
+	oldpref = (optlen - sizeof(struct nd_dna_opt_hdr)) >>4;
+	plens = dnao->nd_dna_opt_numprefs;
+
+	/* not checking end of message */
+	for (i = 0; (i < iface->CurrDNAPrefixes) && ((oldpref + newpref) <
+			iface->CompleteRAMaxAdv); i++){ 
+		skip=0;
+		for(poff=0; (poff + sizeof(struct nd_dna_opt_hdr)) < optlen;
+						poff+=IN6_ADDR_SZ){
+
+			if(!memcmp(&pptr[poff], &landlist[i].Prefix, 
+								IN6_ADDR_SZ)){
+				skip=1;
+				break;	
+			}
+		}
+
+		if(skip)
+			continue;
+
+
+		if(((plens+3)%8)==0){ /* need to shift across */
+			for(j=offset+optlen+added; j >=(offset+3+plens) ; j--){
+				buffer[j+8]= buffer[j]; 
+			}
+			memset(&buffer[offset+plens+3], 0, 8);
+			added+=8;
+		}
+
+		buffer[offset+plens+3]=landlist[i].plen;
+		plens++;
+		memcpy(&buffer[offset+added+optlen], &landlist[i].Prefix,
+				8<< (((unsigned)landlist[i].plen) - 64));
+
+		print_addr((struct in6_addr *)&landlist[i].Prefix,addr_str);
+		dlog(LOG_DEBUG,5,"completeRA loop %s/%d", addr_str, landlist[i].plen);
+		added+= 8<< (((unsigned)landlist[i].plen) - 64);
+		newpref++;
+	}
+	
+	gettimeofday(&now, NULL);
+	if(complete && i >= iface->CurrDNAPrefixes && 
+		(tv_diff(&now, &iface->DNAOverloadExpiry) >0)){
+		*complete=1;
+	}   
+	if(complete)
+		dlog(LOG_DEBUG,5,"completeRA is complete? %d", *complete);
+	dnao->nd_dna_opt_numprefs=plens;
+	dnao->nd_dna_opt_len=(added+optlen) >>3;
+	return added+optlen;
+}
+
+int make_completera_option(struct Interface *iface, unsigned char *buffer,
+		int offset, int *complete){
+
+	int optlen;
+
+	optlen = hdr_completera_option(iface, buffer, offset);
+	optlen = add_completera_option(iface, buffer, offset, optlen, complete);
+	
+	return optlen;
+}
+
+
+int check_landmark(struct Interface *iface, struct in6_addr *prefix,
+			struct timeval *now, int ll){
+	int i;
+	char addr_str[INET6_ADDRSTRLEN];
+	int curr;
+	struct AdvPrefix *advprefix;
+	struct RtrPrefixList *landlist;
+
+	print_addr(prefix,addr_str);
+	dlog(LOG_DEBUG,5,"checking landmarks %s",addr_str);
+
+	/* start by inspecting the local prefix list */
+
+	advprefix = iface->AdvPrefixList;
+	while (advprefix)
+	{
+		if (advprefix->enabled && addr_match(&advprefix->Prefix,prefix,
+				ll)){ /* watch out for short prefix lengths...*/
+			return ND_OPT_LANDMARK_FLAGS_SEEN;
+		}
+		advprefix=advprefix->next;
+	}
+
+	landlist=iface->DNAPrefixList;
+	curr=iface->CurrDNAPrefixes;
+
+	for (i = 0; (i < curr) ; i++){
+
+		print_addr(&landlist[i].Prefix,addr_str);
+		dlog(LOG_DEBUG,5,"landmark check loop %d %s",i,addr_str);
+		if(addr_match(&landlist[i].Prefix, prefix, ll) &&
+						 (landlist[i].plen == ll)){
+			dlog(LOG_DEBUG,5,"landmark check match %d %f",i,
+					tv_diff(&landlist[i].expiry,now));
+			if(tv_diff(&landlist[i].expiry, now) >= 0){
+				return ND_OPT_LANDMARK_FLAGS_SEEN;
+			}
+			else{
+				return ND_OPT_LANDMARK_FLAGS_UNSEEN;
+			}
+		}
+
+	}
+	return (tv_diff(now, &iface->DNAOverloadExpiry) >0)?
+		ND_OPT_LANDMARK_FLAGS_UNSEEN : ND_OPT_LANDMARK_FLAGS_UNKNOWN;
+}
+
+#if 0
+int prefix_landmark_option(unsigned char *buffer, int offset, 
+				unsigned char *new, int nl, int optlen){
+	
+	struct nd_dna_opt_hdr *dnao;
+	unsigned char *pptr;
+	int np=0;
+	int skip=0;
+	int i,j,added=0;
+	int poff=0;
+	unsigned char optbuf[1500];	
+
+	dnao = (struct nd_dna_opt_hdr *)&buffer[offset];
+	pptr  = ((unsigned char *)dnao) + sizeof(struct nd_dna_opt_hdr) ;
+	
+	np=dnao->nd_dna_opt_numprefs;
+
+	/* O(N^2)! small N */
+	/* also, not checking end of message or end of option */
+
+	for(i=0; i < nl; i+=IN6_ADDR_SZ){
+		skip=0;
+		for(poff=0; poff < optlen; poff+=IN6_ADDR_SZ){
+			if(!memcmp(&pptr[poff], &new[i], IN6_ADDR_SZ)){
+				skip=1;
+				break;
+			}
+			dlog(LOG_DEBUG,5,"completeRA pfx %d poff: %d ",i, poff);
+		}
+		if(skip)
+			continue;
+
+		if(((np+3)%8)==0){ /* need to shift across */
+			for(j=offset+optlen+added; j >=(offset+3+np) ; j--){
+				buffer[j+8]= buffer[j]; 
+			}
+			memset(&buffer[offset+np+3], 0, 8);
+			added+=8;
+		}
+		buffer[offset+np+3]=64;
+		np++;
+		memcpy(&buffer[offset+optlen+added],&new[i], IN6_ADDR_SZ);
+		added+=IN6_ADDR_SZ;
+	}
+	dnao->nd_dna_opt_numprefs=np;
+	dnao->nd_dna_opt_len=(added+optlen)>>3;
+	return optlen+added;
+}
+#endif /* 0 */
+
+int make_landmark_option(unsigned char *buffer, int offset,
+	unsigned char *option, uint8_t flags){
+	struct nd_opt_landmark *lmark; 
+	char addr_str[INET6_ADDRSTRLEN];
+
+	if(!option)
+		return;
+
+	memcpy(&buffer[offset], option, sizeof(struct nd_opt_landmark));
+	lmark = (struct nd_opt_landmark *)&buffer[offset];
+
+	lmark->nd_opt_landmark_flags=flags;
+	
+	print_addr(&lmark->nd_opt_landmark_prefix,addr_str);
+	/**addr_str=0;*/
+	printf("Making Prefix Landmark option for transmission: %hhx %hhx %hhx %s",
+		buffer[offset], buffer[offset+1],buffer[offset+2], addr_str);
+		
+	return sizeof (struct nd_opt_landmark);
+}
diff -rub --exclude=CVS --exclude='config.[gsh]*' --exclude=depcomp --exclude=Makefile.in --new-file radvd/dna.h radvddna/dna.h
--- radvd/dna.h	1970-01-01 10:00:00.000000000 +1000
+++ radvddna/dna.h	2005-05-24 15:28:19.563458364 +1000
@@ -0,0 +1,68 @@
+/*
+ *   $Id: $
+ *
+ *   Authors:
+ *    Greg Daley		<Greg.Daley@eng.monash.edu.au>
+ *
+ *   This software is Copyright 2004 by the above mentioned author(s), 
+ *   All Rights Reserved.
+ *
+ *   The license which is distributed with this software in the file COPYRIGHT
+ *   applies to this software. If your distribution is missing this file, you
+ *   may request it from <lutchann@litech.org>.
+ *
+ */
+
+#ifndef ND_DNA_H
+#define ND_DNA_H
+
+
+#include <includes.h>
+
+#ifndef IN6_ADDR_SZ
+#define IN6_ADDR_SZ (sizeof(struct in6_addr))
+#endif /* IN6_ADDR_SZ */
+
+#ifndef ND_DNA_OPT_TYPE 
+#define ND_DNA_OPT_TYPE 32 
+#endif  /* ND_DNA_OPT_TYPE */
+
+#ifndef DNA_PREFIX_ON_LINK_UNKNOWN
+#define DNA_PREFIX_ON_LINK_UNKNOWN 255
+#endif /* PREFIX_ON_LINK_UNKNOWN */
+
+struct nd_dna_opt_hdr{
+
+	uint8_t nd_dna_opt_type;
+	uint8_t nd_dna_opt_len;
+	uint8_t nd_dna_opt_numprefs;
+	uint8_t nd_dna_opt_rsvd1;
+	uint32_t nd_dna_opt_rsvd2;
+};
+
+
+
+#ifndef ND_OPT_LANDMARK
+#define ND_OPT_LANDMARK 0x13
+
+struct nd_opt_landmark{
+        uint8_t  nd_opt_landmark_type;
+        uint8_t  nd_opt_landmark_len;
+        uint8_t  nd_opt_landmark_plen;
+        uint8_t  nd_opt_landmark_flags;
+        uint32_t nd_opt_landmark_reserved2;
+        struct in6_addr nd_opt_landmark_prefix;
+};
+
+#define ND_OPT_LANDMARK_FLAGS_SEEN      128
+#define ND_OPT_LANDMARK_FLAGS_UNSEEN    64
+#define ND_OPT_LANDMARK_FLAGS_UNKNOWN   0
+
+#endif /* ND_OPT_LANDMARK*/
+
+
+
+
+int make_completera_option(struct Interface *iface, unsigned char *buffer,
+				int offset, int *complete);
+#endif /* ND_DNA_H */
diff -rub --exclude=CVS --exclude='config.[gsh]*' --exclude=depcomp --exclude=Makefile.in --new-file radvd/gram.y radvddna/gram.y
--- radvd/gram.y	2005-05-24 15:56:49.206345796 +1000
+++ radvddna/gram.y	2005-05-24 15:59:31.846928298 +1000
@@ -28,6 +28,7 @@
 extern int num_lines;
 extern char *yytext;
 extern int sock;
+extern int rtnl_sock;
 
 static void cleanup(void);
 static void yyerror(char *msg);
@@ -71,6 +72,16 @@
 %token		T_AdvDefaultLifetime
 %token		T_AdvDefaultPreference
 %token		T_AdvSourceLLAddress
+%token		T_RecvSourceLLAddress
+%token		T_RecvTentativeLLAddress
+
+%token		T_UnnegotiatedFastRA
+%token		T_MaxFastRARouters
+%token		T_MaxFastResponses
+
+%token		T_FastRASeparation
+%token		T_FastRATokenInterval
+%token          T_MaxUnicastFastRAs
 
 %token		T_AdvOnLink
 %token		T_AdvAutonomous
@@ -85,12 +96,22 @@
 %token		T_Base6to4Interface
 %token		T_UnicastOnly
 
+
+%token		T_PrefixLandmarking
+%token		T_MaxDNAPrefixes
+
 %token		T_HomeAgentPreference
 %token		T_HomeAgentLifetime
 
 %token		T_AdvRoutePreference
 %token		T_AdvRouteLifetime
 
+%token		T_CompleteRA
+%token		T_CompleteRAMaxAdv
+%token		T_OverloadTime
+
+%token		T_DNASupport
+
 %token		T_BAD_TOKEN
 
 %type	<str>	name
@@ -149,6 +170,8 @@
 				ABORT;
 			if (setup_allrouters_membership(sock, iface) < 0)
 				ABORT;
+			if(check_if_addr(iface) < 0 )
+				ABORT;
 
 			iface->next = IfaceList;
 			IfaceList = iface;
@@ -278,6 +301,20 @@
 		{
 			iface->AdvSourceLLAddress = $2;
 		}
+		| T_RecvSourceLLAddress SWITCH ';'
+		{
+			if(rtnl_sock < 0){
+                             rtnl_sock = bind_rtnlsock(); 
+                        }
+                        iface->RecvSourceLLAddress = $2;
+		}
+		| T_RecvTentativeLLAddress SWITCH ';'
+		{
+			if(rtnl_sock < 0){
+                             rtnl_sock = bind_rtnlsock(); 
+                        }
+                        iface->RecvTentativeLLAddress = $2;
+		}
 		| T_AdvIntervalOpt SWITCH ';'
 		{
 			iface->AdvIntervalOpt = $2;
@@ -306,6 +343,62 @@
 		{
 			iface->UnicastOnly = $2;
 		}
+		| T_MaxUnicastFastRAs NUMBER ';'
+		{
+			iface->MaxUnicastFastRAs = $2;
+		}
+		| T_FastRASeparation NUMBER ';'
+		{
+                        if($2 > 255){
+			        iface->FastRASeparation = 255;
+                        }
+                        else if ($2 > 0){
+			        iface->FastRASeparation = $2;
+                        }
+		}
+		| T_PrefixLandmarking SWITCH ';'
+		{
+			iface->PrefixLandmarking = $2;
+		}
+		| T_MaxDNAPrefixes NUMBER ';'
+		{
+			iface->MaxDNAPrefixes = $2;
+		}
+		| T_UnnegotiatedFastRA SWITCH ';'
+		{
+			iface->UnnegotiatedFastRA = $2;
+		}
+		| T_MaxFastRARouters NUMBER ';'
+		{
+			iface->MaxFastRARouters = $2;
+		}
+		| T_MaxFastResponses NUMBER ';'
+		{
+			iface->MaxFastResponses = $2;
+		}
+		| T_FastRATokenInterval NUMBER ';'
+		{
+			iface->FastRATokenInterval = $2;
+		}
+		| T_CompleteRA SWITCH ';'
+		{
+			iface->CompleteRA = $2;
+		}
+		| T_CompleteRAMaxAdv NUMBER ';'
+		{
+			iface->CompleteRAMaxAdv = $2;
+		}
+		| T_OverloadTime NUMBER ';'
+		{
+			iface->OverloadTime = $2;
+		}
+		| T_DNASupport SWITCH ';'
+		{
+			if ($2 && (!iface->CompleteRA))
+				iface->CompleteRA = $2;
+			if ($2 && (!iface->PrefixLandmarking))
+				iface->PrefixLandmarking = $2;
+		}
 		;
 		
 prefixlist	: prefixdef
diff -rub --exclude=CVS --exclude='config.[gsh]*' --exclude=depcomp --exclude=Makefile.in --new-file radvd/includes.h radvddna/includes.h
--- radvd/includes.h	2002-06-15 20:25:04.000000000 +1000
+++ radvddna/includes.h	2005-05-24 13:04:40.121524985 +1000
@@ -95,4 +95,6 @@
 # include <getopt.h>
 #endif
 
+#include <openssl/sha.h>
+
 #endif /* INCLUDES_H */
diff -rub --exclude=CVS --exclude='config.[gsh]*' --exclude=depcomp --exclude=Makefile.in --new-file radvd/interface.c radvddna/interface.c
--- radvd/interface.c	2005-05-24 15:56:49.209345438 +1000
+++ radvddna/interface.c	2005-05-24 15:59:32.045904542 +1000
@@ -21,12 +21,15 @@
 void
 iface_init_defaults(struct Interface *iface)
 {
+        int i;
 	memset(iface, 0, sizeof(struct Interface));
 
 	iface->IgnoreIfMissing	  = DFLT_IgnoreIfMissing;
 	iface->AdvSendAdvert	  = DFLT_AdvSendAdv;
 	iface->MaxRtrAdvInterval  = DFLT_MaxRtrAdvInterval;
 	iface->AdvSourceLLAddress = DFLT_AdvSourceLLAddress;
+	iface->RecvSourceLLAddress= DFLT_RecvSourceLLAddress;
+	iface->RecvTentativeLLAddress= DFLT_RecvTentativeLLAddress;
 	iface->AdvReachableTime	  = DFLT_AdvReachableTime;
 	iface->AdvRetransTimer    = DFLT_AdvRetransTimer;
 	iface->AdvLinkMTU	  = DFLT_AdvLinkMTU;
@@ -37,10 +40,42 @@
 	iface->HomeAgentPreference = DFLT_HomeAgentPreference;
 	iface->MinDelayBetweenRAs   = DFLT_MinDelayBetweenRAs;
 
+
+	iface->PrefixLandmarking   = DFLT_PrefixLandmarking;
+	iface->MaxDNAPrefixes      = DFLT_MaxDNAPrefixes;
+	iface->CompleteRA	   = DFLT_CompleteRA;
+	iface->CompleteRAMaxAdv	   = DFLT_CompleteRAMaxAdv;
+	iface->OverloadTime	   = DFLT_OverloadTime;
+
+	iface->NumUnicastFastRAs  = DFLT_NumUnicastFastRAs;
+	iface->MaxUnicastFastRAs  = DFLT_MaxUnicastFastRAs;
+
+	iface->FastRATokenInterval = DFLT_FastRATokenInterval; 
+
+        gettimeofday(&iface->LastFastRAToken,NULL);
+	
 	iface->MinRtrAdvInterval  = -1;
 	iface->AdvDefaultLifetime = -1;
 	iface->AdvDefaultPreference = DFLT_AdvDefaultPreference;
 	iface->HomeAgentLifetime  = 0;
+
+        iface->FastRASeparation   = DFLT_FastRASeparation;
+        iface->MaxUnicastFastRAs  = DFLT_MaxUnicastFastRAs;
+        iface->NumUnicastFastRAs  = 0;
+
+	iface->dyntimers[FREE_Dynamic_Timers].next=NULL;
+	iface->dyntimers[USED_Dynamic_Timers].next=NULL;
+
+	for(i = 0 ; i < MAX_Outstanding_Unicast ; i++){
+		init_timer(&iface->uni_tm[i], dynamic_handler, (void *) iface);
+		iface->dyntimers[i].tm=&iface->uni_tm[i];
+		insert_into_list(&iface->dyntimers[FREE_Dynamic_Timers],
+							&iface->dyntimers[i]);
+	}
+	/* start:remove from production */
+	log_list(&iface->dyntimers[FREE_Dynamic_Timers],"FREE");
+	log_list(&iface->dyntimers[USED_Dynamic_Timers],"USED");
+	/* end: remove from production */
 }
 
 void
@@ -194,7 +229,25 @@
 		res = -1;
 	}
 
+        /* make space for a number of unknown prefixes */
+	if((iface->PrefixLandmarking || iface->CompleteRA)
+			 && iface->MaxDNAPrefixes >0)
+	{
+		if((iface->DNAPrefixList = (struct RtrPrefixList *)malloc(
+			iface->MaxDNAPrefixes *
+				sizeof(struct RtrPrefixList))) == NULL){
+			iface->PrefixLandmarking = 0;			
+			iface->CompleteRA = 0;			
+			iface->CompleteRAMaxAdv = 0;			
+			iface->MaxDNAPrefixes = 0;			
+		}
+		iface->CurrDNAPrefixes = 0;			
+		gettimeofday(&iface->DNAOverloadExpiry,NULL);
+		iface->DNAOverloadExpiry.tv_sec +=  DFLT_InitialOverloadTime;
+	}
+
 	/* XXX: need this? prefix = iface->AdvPrefixList; */
+	prefix = iface->AdvPrefixList;
 
 	while (prefix)
 	{
@@ -231,3 +284,41 @@
 
 	return res;
 }
+
+
+check_if_addr(struct Interface *iface){
+	int res=0;
+	char addr_str[40];
+	unsigned char digest[SHA_DIGEST_LENGTH];
+
+	if(iface->UnnegotiatedFastRA && iface->MaxFastRARouters >0)
+	{
+		if((iface->RouterList = (struct RtrPrefixList *)malloc(
+			iface->MaxFastRARouters *
+				sizeof(struct RtrPrefixList))) == NULL){
+			iface->UnnegotiatedFastRA = 0;			
+			iface->MaxFastRARouters = 0;			
+			flog(LOG_ERR, "Unable to allocate routers list on %s",
+					iface->Name);
+			res = -1;	
+		}
+		iface->CurrFastRARouters = 0;			
+		if(SHA1((unsigned char *)&iface->if_addr, 
+					sizeof(struct in6_addr), digest)){
+			
+			print_addr(&iface->if_addr,addr_str);
+			memcpy(&iface->FastRAOwnHashBits, digest , 8);
+			flog(LOG_ERR, "SHA1-hash:   %8.8lx%8.8lx %s",
+				ntohl(iface->FastRAOwnHashBits.b32[0]),
+				ntohl(iface->FastRAOwnHashBits.b32[1]),
+					addr_str);
+		}
+		else{
+			flog(LOG_ERR, "Msg Digest failure on %s", iface->Name);
+			res = -1;	
+		}
+	}
+	
+	return res;
+
+}
diff -rub --exclude=CVS --exclude='config.[gsh]*' --exclude=depcomp --exclude=Makefile.in --new-file radvd/process.c radvddna/process.c
--- radvd/process.c	2005-05-24 15:56:49.212345079 +1000
+++ radvddna/process.c	2005-05-24 16:02:01.197097529 +1000
@@ -17,12 +17,21 @@
 #include <config.h>
 #include <includes.h>
 #include <radvd.h>
+#include <dna.h>
+
+
+extern int rtnl_sock;
+
+static void process_rs(int sock, struct Interface *iface, unsigned char *msg,
+			int len, struct sockaddr_in6 *addr);
+static unsigned char *process_rs_options(struct Interface *, unsigned char *, 
+	int, struct sockaddr_in6 *,  unsigned char **,
+	struct timeval *tv, uint8_t *);
 
-static void process_rs(int, struct Interface *, struct sockaddr_in6 *);
 static void process_ra(struct Interface *, unsigned char *msg, int len,
 	struct sockaddr_in6 *);
-static int  addr_match(struct in6_addr *a1, struct in6_addr *a2,
-	int prefixlen);
+/*static int  addr_match(struct in6_addr *a1, struct in6_addr *a2,
+			int prefixlen);*/
 static int rs_has_srclladdr(unsigned char *, int);
 
 void
@@ -138,7 +147,7 @@
 
 	if (icmph->icmp6_type == ND_ROUTER_SOLICIT)
 	{
-		process_rs(sock, iface, addr);
+                process_rs(sock, iface, msg, len, addr);
 	}
 	else if (icmph->icmp6_type == ND_ROUTER_ADVERT)
 	{
@@ -147,37 +156,144 @@
 }
 
 static void
-process_rs(int sock, struct Interface *iface, struct sockaddr_in6 *addr)
+process_rs(int sock, struct Interface *iface, unsigned char *msg,
+		int len, struct sockaddr_in6 *addr)
 {
-	double delay;
-	double next;
+	struct in6_addr unspec = { { { 0 } } };
+	struct in6_addr bitdiff;
+	int delay=0;
+        int delayset=0;
+	double next, resdelay;
 	struct timeval tv;
+	int tokens =-1;
+        uint8_t lmv=0;
+        int do_multicast=1;
+        struct dtimer_list *dtm_tmp=NULL;
+	int calcnr=0, probslot=0, i=0;
+        uint32_t flags=0;
+	int rank;
+	char addr_str[40];
+	struct nd_opt_landmark *lmark=NULL;
 
 	gettimeofday(&tv, NULL);
 
-	delay = MAX_RA_DELAY_TIME*rand()/(RAND_MAX+1.0);
-	dlog(LOG_DEBUG, 3, "random mdelay for %s: %.2f", iface->Name, delay);
+	dlog(LOG_DEBUG, 5, "PROCESS ROUTER SOLICIT ON %s", iface->Name);
+
+
+	lmark=NULL;
+	process_rs_options(iface, msg, len, addr, (unsigned char**)&lmark , 
+				&tv, &lmv); 
+
+	if(iface->UnnegotiatedFastRA)
+		tokens = token_bucket_update(iface, &tv);
+
+	if(!delayset && iface->UnnegotiatedFastRA && tokens &&
+		 memcmp(&addr->sin6_addr, &unspec, sizeof(struct in6_addr))){
+			
+		rank=check_before(iface->RouterList,iface->CurrFastRARouters,
+					(uint32_t *)&iface->FastRAOwnHashBits,
+					&addr->sin6_addr);
+		iface->NumUnicastFastRAs--;
+		delay=rank * iface->FastRASeparation;
+		dlog(LOG_DEBUG, 3, "Unneg FastRA delay for %s %d r(%d)",
+				iface->Name, delay, rank);
+                delayset=1;
+	}
+
+
+        if(!delayset){
+		delay = (int) (MAX_RA_DELAY_TIME*rand()/(RAND_MAX+1.0));
+  		dlog(LOG_DEBUG, 3, "random mdelay for %s: %d", iface->Name, delay);
+	}
+   	
+	next=tv_diff(&(iface->tm.expires), &tv);
+
+	/* residual delay for multicast */
+	resdelay = MAX2((((double)delay)/1000.0),
+			MAX2(0.0, (iface->MinDelayBetweenRAs) - 
+				tv_diff(&tv,&iface->last_multicast)));
+ 
+	dlog(LOG_DEBUG, 4, "next:%10.10f resdelay: %10.10f (%f) [%f]",next,
+		resdelay,MAX2(0.0, (iface->MinDelayBetweenRAs) -
+			tv_diff(&tv,&iface->last_multicast)),
+		iface->MinDelayBetweenRAs - tv_diff(&tv,&iface->last_multicast) );
+        /* GD: not sure here: on no more fastras need multicast! */
+        if(!tokens){
+		dlog(LOG_DEBUG, 4, "Run out of FastRA tokens on %s, Mcast",
+					 iface->Name);
+	}
+	else if((!IN6_IS_ADDR_UNSPECIFIED(&addr->sin6_addr) && 
+		(resdelay > ((double)delay)/1000.0))|| iface->UnicastOnly ||
+		delayset){
+		dlog(LOG_DEBUG, 4, "too soon for mcast on %s", iface->Name);
+		do_multicast=0; 
+	} 
  	
-	if (iface->UnicastOnly) {
-		mdelay(delay);
-		send_ra(sock, iface, &addr->sin6_addr);
-	}
-	else if ((tv.tv_sec + tv.tv_usec / 1000000.0) - (iface->last_multicast_sec +
-	          iface->last_multicast_usec / 1000000.0) < iface->MinDelayBetweenRAs) {
-		/* last RA was sent only a few moments ago, don't send another immediately */
+
+	/* MCast rescheduling */
+
+	if(do_multicast){
+		dlog(LOG_DEBUG, 5, "multicast response on %s",iface->Name);
+		/* Reschedule multicast if nearer */
+		if((resdelay + 0.001) < next){
+			dlog(LOG_DEBUG, 3, "Reschedule multicast to %f on %s",
+						resdelay,iface->Name);
+			next=resdelay;
 		clear_timer(&iface->tm);
-		next = iface->MinDelayBetweenRAs - (tv.tv_sec + tv.tv_usec / 1000000.0) +
-		       (iface->last_multicast_sec + iface->last_multicast_usec / 1000000.0) + delay/1000.0;
 		set_timer(&iface->tm, next);
 	}
-	else {
-		/* no RA sent in a while, send an immediate multicast reply */
-		clear_timer(&iface->tm);
-		send_ra(sock, iface, NULL);
+		return;
+	} 
 		
-		next = rand_between(iface->MinRtrAdvInterval, iface->MaxRtrAdvInterval); 
-		set_timer(&iface->tm, next);
+  		/*
+  		 *	unicast reply
+  		 */
+  
+	if(delay == 0){ /* No need to take a schedule slot */
+		*addr_str='\0';
+		if(lmark){
+			/*print_addr(&lmark->nd_opt_landmark_prefix,addr_str);*/
+			dlog(LOG_DEBUG, 5,
+				 "Responding LM: T:%hhu L:%hhu F:%hhu %hx:%hx:%hx:%hx/%hhu",
+				lmark->nd_opt_landmark_type,
+				lmark->nd_opt_landmark_len,
+				lmv,	
+				ntohs(lmark->nd_opt_landmark_prefix.s6_addr16[0]),
+				ntohs(lmark->nd_opt_landmark_prefix.s6_addr16[1]),
+				ntohs(lmark->nd_opt_landmark_prefix.s6_addr16[2]),
+				ntohs(lmark->nd_opt_landmark_prefix.s6_addr16[3]),
+				lmark->nd_opt_landmark_plen);
+		}
+
+		dlog(LOG_DEBUG, 5, "Zero Delay response %s",iface->Name);
+		send_ra(sock, iface, &addr->sin6_addr, (unsigned char *)lmark,
+				lmv);
+		return;
+        }
+	dlog(LOG_DEBUG, 3, "delay on  %s %d",iface->Name, delay);
+
+	if((dtm_tmp = remove_from_list(&iface->dyntimers[FREE_Dynamic_Timers],
+			NULL)) ==  NULL){
+		dlog(LOG_DEBUG, 3, "No entries on free list %s",iface->Name);
+		return;
+  	}
+	if(lmark){
+		memcpy(dtm_tmp->lmark, lmark, sizeof(struct nd_opt_landmark));
+		dtm_tmp->lmv=lmv;
 	}
+	memcpy(&dtm_tmp->addr, &addr->sin6_addr, sizeof (struct in6_addr));
+  
+	insert_into_list(&iface->dyntimers[USED_Dynamic_Timers], dtm_tmp);
+  		
+	/* start: remove from production */
+	log_list(&iface->dyntimers[FREE_Dynamic_Timers], "FREE p");
+	log_list(&iface->dyntimers[USED_Dynamic_Timers], "USED p");
+	/* end: remove from production */
+      
+	next = ((double)delay)/1000.0; 
+
+	set_timer(dtm_tmp->tm, next);
+	return;
 }
 
 /*
@@ -188,11 +304,31 @@
 	struct sockaddr_in6 *addr)
 {
 	struct nd_router_advert *radvert;
+        unsigned int advint=0;
 	char addr_str[INET6_ADDRSTRLEN];
+	int matched=0;
+	int new_landmark=0;
+        int new_overload=0;
+	struct timeval tv,now;
+        int num; 
+
 	uint8_t *opt_str;
 
 	print_addr(&addr->sin6_addr, addr_str);
 
+	if(!memcmp(&addr->sin6_addr, &iface->if_addr, sizeof(struct in6_addr))){
+		dlog(LOG_DEBUG, 5, "own RA from %s on %s", addr_str,
+                                iface->Name);
+		return;
+	}
+
+	gettimeofday(&now, NULL);
+
+
+	dlog(LOG_DEBUG, 1, "RECEIVE ROUTER ADV from %s on %s", addr_str,
+				iface->Name);
+
+
 	radvert = (struct nd_router_advert *) msg;
 
 	if ((radvert->nd_ra_curhoplimit && iface->AdvCurHopLimit) && 
@@ -230,6 +366,8 @@
 			iface->Name, addr_str);
 	}
 
+	dlog(LOG_DEBUG, 1, "About to check length %d %d", len, 
+				 sizeof(struct nd_router_advert));
 	len -= sizeof(struct nd_router_advert);
 
 	if (len == 0)
@@ -284,6 +422,11 @@
 			pinfo = (struct nd_opt_prefix_info *) opt_str;
 			preferred = ntohl(pinfo->nd_opt_pi_preferred_time);
 			valid = ntohl(pinfo->nd_opt_pi_valid_time);
+			matched=0;
+			
+			print_addr(&pinfo->nd_opt_pi_prefix, prefix_str);
+			dlog(LOG_DEBUG,5,"received PIO: %s/%d",
+				prefix_str, pinfo->nd_opt_pi_prefix_len);
 			
 			prefix = iface->AdvPrefixList;
 			while (prefix)
@@ -294,6 +437,7 @@
 				    	 prefix->PrefixLen))
 				{
 					print_addr(&prefix->Prefix, prefix_str);
+					matched=1;
 
 					if (valid != prefix->AdvValidLifetime)
 					{
@@ -314,9 +458,42 @@
 						 );
 					}
 				}
-
+				dlog(LOG_DEBUG,5,"PIO match: %d",matched);
 				prefix = prefix->next;
 			}			
+			if(!matched && (iface->PrefixLandmarking || 
+						iface->CompleteRA)){
+				struct in6_addr prefaddr;
+				/* add prefix to landmark list */
+				prefix_mask(&prefaddr,
+					&pinfo->nd_opt_pi_prefix,
+					pinfo->nd_opt_pi_prefix_len);
+				print_addr(&prefaddr, prefix_str);
+
+				if((num = add_rtrprefix(iface->DNAPrefixList,
+					iface->MaxDNAPrefixes,	
+					iface->CurrDNAPrefixes,	
+					&prefaddr, MIN2(preferred,
+					iface->OverloadTime),0,
+					pinfo->nd_opt_pi_prefix_len))){
+					
+					new_landmark=1;
+					iface->CurrDNAPrefixes=num;
+					dlog(LOG_DEBUG,5,"DNA prefix %s %d",
+						prefix_str,
+						iface->CurrDNAPrefixes);
+				}		
+				else{
+					/* overload */
+					new_overload=1;
+					dlog(LOG_DEBUG,5,"DNA Overload %s/%d %lu.%lu",
+						prefix_str,
+						pinfo->
+						nd_opt_pi_prefix_len,
+						iface->DNAOverloadExpiry.tv_sec,
+						iface->DNAOverloadExpiry.tv_usec);
+				}
+			}
 			break;
 		case ND_OPT_ROUTE_INFORMATION:
 			/* not checked: these will very likely vary a lot */
@@ -331,6 +508,9 @@
 			break;
 		/* Mobile IPv6 extensions */
 		case ND_OPT_RTR_ADV_INTERVAL:
+			advint=ntohl(((struct nd_opt_adv_interval *)opt_str)->nd_opt_adv_interval_ival);
+			dlog(LOG_DEBUG, 5, "Advint %d in RA on %s from %s",
+                                advint, iface->Name, addr_str);
 		case ND_OPT_HOME_AGENT_INFO:
 			/* not checked */
 			break;
@@ -343,8 +523,54 @@
 		len -= optlen;
 		opt_str += optlen;
 	}
+
+	/* GD XXX update with processed Advertisement Interval */
+	if(iface->UnnegotiatedFastRA && (radvert->nd_ra_flags_reserved &
+						 ND_RA_FLAG_FASTRA)){
+		uint32_t life;	
+		
+		life = (advint/1000 ? MIN2(advint/1000, 
+                                ntohs(radvert->nd_ra_router_lifetime)):
+                           	ntohs(radvert->nd_ra_router_lifetime));	
+		
+		if((num =  add_rtrprefix(iface->RouterList,
+                                        	iface->MaxFastRARouters,
+                                        	iface->CurrFastRARouters,
+                                        	&addr->sin6_addr, life,1,128))){
+	
+			iface->CurrFastRARouters=num;
+		}
+	}
+			
+
+	if(iface->PrefixLandmarking || iface->CompleteRA){
+		
+		//tv.tv_usec = tv.tv_sec=0;
+
+		if(advint && (new_overload || new_landmark)){
+			struct timeval ai_timeval;
+
+                	ai_timeval.tv_usec = (advint % 1000) * 1000;
+                	ai_timeval.tv_sec = advint / 1000;
+			timeradd(&now, &ai_timeval, &tv);
+		}
+		if(new_overload){
+			gettimeofday(&iface->DNAOverloadExpiry,NULL);
+			iface->DNAOverloadExpiry.tv_sec += DFLT_OverloadTime;
+			dlog(LOG_DEBUG, 1, "new overload timer: %lu.%lu , now:%lu.%lu",
+				iface->DNAOverloadExpiry.tv_sec, iface->DNAOverloadExpiry.tv_usec, tv.tv_sec, tv.tv_usec);
+		}	
+
+		/*if(new_landmark){
+			update_landtimers(iface->DNAPrefixList,
+						iface->CurrDNAPrefixes,&tv);
+		}*/
+	}
+        
+
 }
 
+#if 0 
 static int 
 addr_match(struct in6_addr *a1, struct in6_addr *a2, int prefixlen)
 {
@@ -376,6 +602,7 @@
 
 	return 1;
 }
+#endif /* 0 */
 
 static int
 rs_has_srclladdr(unsigned char *msg, int len)
@@ -426,3 +653,120 @@
 
 	return has_lladdr;
 }
+
+
+
+
+static unsigned char *process_rs_options(struct Interface *iface, 
+	unsigned char *msg, int len, struct sockaddr_in6 *addr,
+	unsigned char **lmark, struct timeval *tv, uint8_t*lmv)
+{
+	uint8_t *opt_str;
+	int i;
+	unsigned char *copy=NULL;
+	unsigned char hw_addr[16];
+	struct AdvPrefix *prefix=NULL;
+	struct nd_opt_landmark *lm_opt=NULL;
+	struct in6_addr tmp_addr;
+	char addr_str[INET6_ADDRSTRLEN];
+ 
+	len -= sizeof(struct nd_router_solicit);
+	opt_str = (uint8_t *)(msg + sizeof(struct nd_router_solicit));
+
+	while (len > 0)
+	{
+		int optlen;
+
+		if (len < 2)
+		{
+			flog(LOG_ERR, "trailing garbage in RS");
+			break;
+		}
+
+		optlen = (opt_str[1] << 3);
+
+		dlog(LOG_DEBUG,4, "option type %d, length %d", (int)*opt_str,
+			optlen);
+
+		if (optlen == 0)
+		{
+			flog(LOG_ERR, "zero length option in RA");
+			break;
+		}
+		else if (optlen > len)
+		{
+			flog(LOG_ERR, "option length greater than total"
+				" length in RA (type %d, optlen %d, len %d)",
+				(int)*opt_str, optlen, len);
+			break;
+		}
+		switch (*opt_str)
+		{
+                case ND_OPT_SOURCE_LINKADDR:
+                        dlog(LOG_DEBUG, 4, "RecvSourceLLAddress: %d l:%d",
+                              iface->RecvSourceLLAddress, optlen);
+
+                        if(iface->RecvSourceLLAddress && (optlen <= 16)){
+				for (i = 2; i < optlen; i++)
+				{
+                                              hw_addr[i-2] = opt_str[i];
+				}
+				install_nc_entry(rtnl_sock,iface,
+                                              &addr->sin6_addr, hw_addr, 6,1);
+                        }
+                        break;
+                case ND_OPT_TENTATIVE_SLLA:
+                        dlog(LOG_DEBUG, 4, "RecvTentativeLLAddress: ");
+
+                        if(iface->RecvTentativeLLAddress && (optlen <= 16)){
+                                      for (i = 2; i < optlen; i++)
+                              {
+                                              hw_addr[i-2] = opt_str[i];
+                              }
+                                install_nc_entry(rtnl_sock,iface,
+                                              &addr->sin6_addr, hw_addr, 6,0);
+                        }
+                        break;
+		case ND_OPT_LANDMARK:
+			dlog(LOG_DEBUG, 4, "received Landmark opt in RS on %s %hhu",
+				iface->Name, opt_str );
+			if(iface->PrefixLandmarking){
+
+			 	lm_opt = (struct nd_opt_landmark *)opt_str;
+
+				i = lm_opt->nd_opt_landmark_plen;
+				/* store in an ipv6 address for comparison */
+				prefix_mask(&tmp_addr,
+					&lm_opt->nd_opt_landmark_prefix, i);
+
+				/* check if a known prefix */
+				*lmv=check_landmark(iface, &tmp_addr, tv, i);
+				*lmark=opt_str;	
+				/*print_addr(&((struct nd_opt_landmark *)opt_str)->nd_opt_landmark_prefix, addr_str);*/
+				copy=opt_str;
+				dlog(LOG_DEBUG,5, "Received LM: T:%hhu L:%hhu F:%hhu %hx:%hx:%hx:%hx/%d (%p, %d)",
+				lm_opt->nd_opt_landmark_type, 
+				lm_opt->nd_opt_landmark_len, 
+				lm_opt->nd_opt_landmark_flags, 
+				ntohs(lm_opt->nd_opt_landmark_prefix.s6_addr16[0]),
+				ntohs(lm_opt->nd_opt_landmark_prefix.s6_addr16[1]),
+				ntohs(lm_opt->nd_opt_landmark_prefix.s6_addr16[2]),
+				ntohs(lm_opt->nd_opt_landmark_prefix.s6_addr16[3]),
+				lm_opt->nd_opt_landmark_plen,
+				*lmark,*lmv);
+			}
+			break;
+		default:
+			dlog(LOG_DEBUG, 1, "unknown option %d in RS",
+				(int)*opt_str);
+			break;
+		}
+
+		len -= optlen;
+		opt_str += optlen;
+ 
+	}
+	return copy;
+}
+ 
+
diff -rub --exclude=CVS --exclude='config.[gsh]*' --exclude=depcomp --exclude=Makefile.in --new-file radvd/radvd.c radvddna/radvd.c
--- radvd/radvd.c	2005-05-24 15:56:49.421320130 +1000
+++ radvddna/radvd.c	2005-05-24 15:59:32.293874937 +1000
@@ -18,6 +18,7 @@
 #include <includes.h>
 #include <radvd.h>
 #include <pathnames.h>
+#include <dna.h>
 
 struct Interface *IfaceList = NULL;
 
@@ -46,6 +47,7 @@
 char *conf_file = NULL;
 char *pname;
 int sock = -1;
+int rtnl_sock = -1;
 
 volatile int sighup_received = 0;
 volatile int sigterm_received = 0;
@@ -285,15 +287,64 @@
 	exit(0);
 }
 
+
+void
+dynamic_handler(void *data)
+{
+	struct timer_lst *tm = (struct timer_lst *) data;
+	struct Interface *iface;
+	char addr_str[40];
+	struct in6_addr unspec = { { { 0 } } };
+	struct in6_addr *dst=NULL;
+	unsigned char *lmark=NULL;
+	uint8_t lmv=0;
+	struct dtimer_list *dtm_tmp = NULL;
+
+	iface= tm->iface;
+
+	dlog(LOG_DEBUG, 4, "dynamic_handler called for %s", iface->Name);
+
+
+	if((dtm_tmp = remove_from_list(&iface->dyntimers[USED_Dynamic_Timers],
+			tm)) == NULL){
+		return;
+	}
+	print_addr(&dtm_tmp->addr, addr_str);
+	dlog(LOG_DEBUG, 4, "dynamic_handler:address: %s on %s f(%8.8x)",
+			 iface->Name, addr_str,dtm_tmp->flags);
+
+	if(memcmp(&dtm_tmp->addr,&unspec, sizeof(struct in6_addr))){
+		dst=&dtm_tmp->addr;
+	} 
+
+	if(dtm_tmp->lmark[0]){
+		lmark=dtm_tmp->lmark;
+		print_addr(&((struct nd_opt_landmark *)lmark)->nd_opt_landmark_prefix, addr_str);
+		lmv=dtm_tmp->lmv;
+		dlog(LOG_DEBUG, 4, "dynamic_handler:lmark prefix: %s on %s lf(%8.8x)",
+			 iface->Name, addr_str,dtm_tmp->lmv);
+	}	
+	send_ra(sock, iface, dst, lmark, lmv);
+
+	dtm_tmp->lmv=0;
+	memset(dtm_tmp->lmark, 0, sizeof(struct nd_opt_landmark));
+	insert_into_list(&iface->dyntimers[FREE_Dynamic_Timers], dtm_tmp);
+}
+
+
 void
 timer_handler(void *data)
 {
-	struct Interface *iface = (struct Interface *) data;
+	struct timer_lst *tm = (struct timer_lst *) data;
+	struct Interface *iface;
 	double next;
+        double lidc;
+
+	iface= tm->iface;
 
 	dlog(LOG_DEBUG, 4, "timer_handler called for %s", iface->Name);
 
-	send_ra(sock, iface, NULL);
+	send_ra(sock, iface, NULL, NULL, 0);
 
 	next = rand_between(iface->MinRtrAdvInterval, iface->MaxRtrAdvInterval); 
 	set_timer(&iface->tm, next);
@@ -316,7 +367,7 @@
 			if (iface->AdvSendAdvert)
 			{
 				/* send an initial advertisement */
-				send_ra(sock, iface, NULL);
+				send_ra(sock, iface, NULL, NULL,0);
 
 				set_timer(&iface->tm, iface->MaxRtrAdvInterval);
 			}
@@ -338,7 +389,7 @@
 			if (iface->AdvSendAdvert) {
 				/* send a final advertisement with zero Router Lifetime */
 				iface->AdvDefaultLifetime = 0;
-				send_ra(sock, iface, NULL);
+				send_ra(sock, iface, NULL, NULL,0);
 			}
 		}
 	}
diff -rub --exclude=CVS --exclude='config.[gsh]*' --exclude=depcomp --exclude=Makefile.in --new-file radvd/radvd.conf.5.man radvddna/radvd.conf.5.man
--- radvd/radvd.conf.5.man	2004-10-27 16:13:40.000000000 +1000
+++ radvddna/radvd.conf.5.man	2005-05-24 16:22:05.724290223 +1000
@@ -83,7 +83,7 @@
 
 A flag indicating whether or not the router sends
 periodic router advertisements and responds to
-router solicitations. 
+Router Solicitations. 
 
 This option no longer has to be specified first, but it
 needs to be
@@ -242,6 +242,62 @@
 Default: on
 
 .TP
+.BR RecvSourceLLAddress " " on | off
+
+When set, the source link-layer address option in an incoming
+Router Solicitation is used to create a STALE neighbour cache
+entry for the solicitor, if one didn't exist already.
+It also overrides an existing neighbour cache entry, if 
+the link-layer addresses differ.
+
+Default: off
+
+.TP
+.BR RecvTentativeLLAddress " " on | off
+
+When set, the processing of Tentative Source Link-Layer Address
+Options is supported.  These options allow creation of a
+neighbour cache entry only if there is no pre-existing valid
+entry.
+The receivd Router Solicitation creates a STALE neighbour cache
+entry for the solicitor, if one didn't exist already.
+
+Default: off
+
+
+.TP
+.BR MaxUnicastFastRAs " " integer
+
+Provides the maximum size of the token bucket used to
+rate limit fast unicast Router Advertisement responses
+to solicitation, generated by either of the FastRA
+algorithms.
+In order to affect transmission, either of 
+ProbabilisticFastRA or DetermineFastRA must be on.
+
+Default: 10
+
+.TP
+.BR "FastRATokenInterval " milliseconds
+
+Provides the interval between token arrivals for 
+allowing fast responses to Router Solicitations.
+The maximum amount of tokens outstanding is determined by 
+MaxUnicastFastRAs.
+In order to affect transmission, either of 
+ProbabilisticFastRA or DetermineFastRA must be on.
+
+Default: 1000
+
+.TP
+.BR "FastRASeparation " milliseconds
+
+The interval between responses of  FastRA routers,
+upon reception of a solicitation.
+
+Default: 20
+
+.TP
 .BR AdvHomeAgentFlag " " on | off
 
 When set, indicates that sending router is able to serve as Mobile
diff -rub --exclude=CVS --exclude='config.[gsh]*' --exclude=depcomp --exclude=Makefile.in --new-file radvd/radvd.conf.example radvddna/radvd.conf.example
--- radvd/radvd.conf.example	2004-08-20 17:17:53.000000000 +1000
+++ radvddna/radvd.conf.example	2005-05-24 13:04:40.122524865 +1000
@@ -25,6 +25,12 @@
 	AdvDefaultPreference low;
 
 #
+# Add a STALE neighbour cache entry for previously unseen soliciting
+# hosts, which have the SLLAO set
+#
+        RecvSourceLLAddress on;
+
+#
 # Disable Mobile IPv6 support
 #
 	AdvHomeAgentFlag off;
diff -rub --exclude=CVS --exclude='config.[gsh]*' --exclude=depcomp --exclude=Makefile.in --new-file radvd/radvd.h radvddna/radvd.h
--- radvd/radvd.h	2005-05-24 15:56:49.443317504 +1000
+++ radvddna/radvd.h	2005-05-24 16:06:49.509676177 +1000
@@ -31,15 +31,35 @@
 
 #define LOG_TIME_FORMAT "%b %d %H:%M:%S"
 
+struct Interface;
+
 struct timer_lst {
 	struct timeval		expires;
 	void			(*handler)(void *);
 	void *			data;
 	struct timer_lst	*next;
 	struct timer_lst	*prev;	
+        struct Interface        *iface;
+};
+
+
+struct dtimer_list{
+	struct timer_lst   *tm;
+	struct dtimer_list *next;
+        /* other data for dynamic timers...*/
+        struct in6_addr    addr;
+	uint32_t	   flags;
+	uint8_t		   lmv;
+        unsigned char      lmark[MAX_ResponseOptionLen];
+};
+
+struct fastralist{
+    struct in6_addr addr;
+    struct timeval expires;
 };
 
 struct AdvPrefix;
+struct RtrPrefixList;
 
 #define HWADDR_MAX 16
 
@@ -68,8 +88,29 @@
 	int			AdvDefaultLifetime;
 	int			AdvDefaultPreference;
 	int			AdvSourceLLAddress;
+	int			RecvSourceLLAddress;
+	int			RecvTentativeLLAddress;
 	int			UnicastOnly;
 
+	int			UnnegotiatedFastRA;
+
+	union			{
+					uint8_t  b8[8];
+					uint16_t b16[4];
+					uint32_t b32[2];
+	}			FastRAOwnHashBits;
+
+	int			MaxFastRARouters;
+	int			CurrFastRARouters;
+	struct RtrPrefixList	*RouterList;
+
+	int			MaxFastResponses; /* not implemented for Detfra */
+        int                     FastRASeparation;
+	struct timeval		LastFastRAToken;
+        int			FastRATokenInterval;
+        int			NumUnicastFastRAs;
+	int			MaxUnicastFastRAs;
+
 	/* Mobile IPv6 extensions */
 	int			AdvIntervalOpt;
 	int			AdvHomeAgentInfo;
@@ -77,12 +118,27 @@
 	int16_t			HomeAgentPreference;
 	uint16_t		HomeAgentLifetime;
 
+	struct timer_lst	rtrtm;
+	struct timeval		last_rtrmc;
+
+        int                     DetFastRASeparation;
+
+        int			PrefixLandmarking;
+        int			MaxDNAPrefixes;
+        int			CurrDNAPrefixes;
+	int			CompleteRA;
+	int			CompleteRAMaxAdv;
+	int			OverloadTime;
+	struct RtrPrefixList	*DNAPrefixList;
+	struct timeval		DNAOverloadExpiry;
+
 	struct AdvPrefix	*AdvPrefixList;
 	struct AdvRoute		*AdvRouteList;
 	struct timer_lst	tm;
-	time_t                  last_multicast_sec;
-	suseconds_t             last_multicast_usec;
+	struct timeval		last_multicast;
 	struct Interface	*next;
+	struct dtimer_list      dyntimers[MAX_Outstanding_Unicast+2];
+	struct timer_lst        uni_tm[MAX_Outstanding_Unicast];
 
 };
 
@@ -105,6 +161,7 @@
 	struct AdvPrefix	*next;
 };
 
+
 /* More-Specific Routes extensions */
 
 struct AdvRoute {
@@ -134,6 +191,15 @@
 	uint16_t		lifetime;
 };	
 
+struct RtrPrefixList{
+	struct in6_addr		Prefix;
+	struct timeval 		expiry;
+	int			plen;
+	int			this_adv;
+	unsigned char		hash[8];
+};
+
+
 
 /* gram.y */
 int yyparse(void);
@@ -164,19 +230,26 @@
 int setup_linklocal_addr(int, struct Interface *);
 int setup_allrouters_membership(int, struct Interface *);
 int check_allrouters_membership(int, struct Interface *);
+int check_routertorouter_membership(int sock, struct Interface *iface);
 int get_v4addr(const char *, unsigned int *);
+int bind_rtnlsock(void);
+int open_rtnlsock(void);
+void install_nc_entry(int, struct Interface *, struct in6_addr *, unsigned char *, int , int);
 
 /* interface.c */
 void iface_init_defaults(struct Interface *);
 void prefix_init_defaults(struct AdvPrefix *);
 void route_init_defaults(struct AdvRoute *, struct Interface *);
 int check_iface(struct Interface *);
+int check_if_addr(struct Interface *);
 
-/* socket.c */
-int open_icmpv6_socket(void);
+/* socket.c */ int open_icmpv6_socket(void);
 
 /* send.c */
-void send_ra(int, struct Interface *iface, struct in6_addr *dest);
+void send_ra(int sock, struct Interface *iface, struct in6_addr *dest,
+	unsigned char *lmark, uint8_t lmv);
+void send_r2r(int sock, struct Interface *iface, struct in6_addr *dest,
+	int req);
 
 /* process.c */
 void process(int sock, struct Interface *, unsigned char *, int,
@@ -189,5 +262,29 @@
 void mdelay(int);
 double rand_between(double, double);
 void print_addr(struct in6_addr *, char *);
+double tv_diff(struct timeval *, struct timeval *);
+struct dtimer_list *remove_from_list(struct dtimer_list *, struct timer_lst *);
+void insert_into_drtrlist(struct dtimer_list *, struct dtimer_list *);
+void insert_into_list(struct dtimer_list *list, struct dtimer_list *entry);
+void log_list(struct dtimer_list *list, const char *listname);
+int  add_to_fastralist(struct Interface *iface, struct in6_addr *addr,
+        unsigned int lifetime);
+void clear_fastralist(struct Interface *iface, struct timeval *tv);
+int  token_bucket_update(struct Interface *iface, struct timeval *tv);
+int prefix_mask(struct in6_addr *prefix, struct in6_addr *addr, int plen);
+int check_landmark(struct Interface *iface, struct in6_addr *prefix, 
+			struct timeval *now, int plen);
+int addr_match(struct in6_addr *a1, struct in6_addr *a2, int prefixlen);
+int add_rtrprefix(struct RtrPrefixList *landlist, int num, int curr,
+		struct in6_addr *prefix, uint32_t expires, int hash, int plen);
+int update_landtimers(struct RtrPrefixList *landlist, int curr,
+		uint32_t expires);
+
+int check_before(struct RtrPrefixList *list, int curr,
+                                uint32_t *ownhash, struct in6_addr *addr);
+
+/* radvd.c */
+void timer_handler(void *data);
+void dynamic_handler(void *data);
 
 #endif
diff -rub --exclude=CVS --exclude='config.[gsh]*' --exclude=depcomp --exclude=Makefile.in --new-file radvd/scanner.l radvddna/scanner.l
--- radvd/scanner.l	2004-10-27 16:13:40.000000000 +1000
+++ radvddna/scanner.l	2005-05-24 15:44:47.271536876 +1000
@@ -58,6 +58,8 @@
 AdvDefaultLifetime	{ return T_AdvDefaultLifetime; }
 AdvDefaultPreference	{ return T_AdvDefaultPreference; }
 AdvSourceLLAddress	{ return T_AdvSourceLLAddress; }
+RecvSourceLLAddress	{ return T_RecvSourceLLAddress; }     
+RecvTentativeLLAddress	{ return T_RecvTentativeLLAddress; }     
 
 AdvOnLink		{ return T_AdvOnLink; }
 AdvAutonomous		{ return T_AdvAutonomous; }
@@ -70,6 +72,15 @@
 AdvHomeAgentInfo	{ return T_AdvHomeAgentInfo; }
 UnicastOnly		{ return T_UnicastOnly; }
 
+PrefixLandmarking	{ return T_PrefixLandmarking; } 
+
+CompleteRA		{ return T_CompleteRA;}
+CompleteRAMaxAdv	{ return T_CompleteRAMaxAdv;}
+OverloadTime		{ return T_OverloadTime;}
+
+MaxDNAPrefixes		{ return T_MaxDNAPrefixes; } 
+
+
 Base6to4Interface	{ return T_Base6to4Interface; }
 
 HomeAgentPreference	{ return T_HomeAgentPreference; }
@@ -80,6 +91,16 @@
 
 MinDelayBetweenRAs      { return T_MinDelayBetweenRAs; }
 
+UnnegotiatedFastRA	{ return T_UnnegotiatedFastRA; }
+MaxFastRARouters	{ return T_MaxFastRARouters; } 
+
+MaxFastResponses	{ return T_MaxFastResponses; } 
+FastRATokenInterval	{ return T_FastRATokenInterval; }
+MaxUnicastFastRAs	{ return T_MaxUnicastFastRAs; }
+FastRASeparation	{ return T_FastRASeparation; }
+
+DNASupport		{ return T_DNASupport; }
+
 {addr}		{
 			static struct in6_addr addr;
 			int i;
diff -rub --exclude=CVS --exclude='config.[gsh]*' --exclude=depcomp --exclude=Makefile.in --new-file radvd/send.c radvddna/send.c
--- radvd/send.c	2005-05-24 15:56:49.466314758 +1000
+++ radvddna/send.c	2005-05-24 16:06:29.513063552 +1000
@@ -17,9 +17,11 @@
 #include <config.h>
 #include <includes.h>
 #include <radvd.h>
+#include <dna.h>
 
 void
-send_ra(int sock, struct Interface *iface, struct in6_addr *dest)
+send_ra(int sock, struct Interface *iface, struct in6_addr *dest,
+	 unsigned char *lmark, uint8_t lmv)
 {
 	uint8_t all_hosts_addr[] = {0xff,0x02,0,0,0,0,0,0,0,0,0,0,0,0,0,1};
 	struct sockaddr_in6 addr;
@@ -34,22 +36,26 @@
 	unsigned char buff[MSG_SIZE];
 	int len = 0;
 	int err;
+	struct timeval tv;
 
 	/* Make sure that we've joined the all-routers multicast group */
 	if (check_allrouters_membership(sock, iface) < 0)
 		flog(LOG_WARNING, "problem checking all-routers membership on %s", iface->Name);
 
+	
 	dlog(LOG_DEBUG, 3, "sending RA on %s", iface->Name);
 
+	gettimeofday(&tv, NULL);
+
 	if (dest == NULL)
 	{
-		struct timeval tv;
 
 		dest = (struct in6_addr *)all_hosts_addr;
-		gettimeofday(&tv, NULL);
 
-		iface->last_multicast_sec = tv.tv_sec;
-		iface->last_multicast_usec = tv.tv_usec;
+		iface->last_multicast.tv_sec = tv.tv_sec;
+		iface->last_multicast.tv_usec = tv.tv_usec;
+
+		dlog(LOG_DEBUG, 5, "RA is Multicast on %s", iface->Name);
 	}
 	
 	memset((void *)&addr, 0, sizeof(addr));
@@ -77,6 +83,15 @@
 	radvert->nd_ra_flags_reserved   |=
 		(iface->AdvDefaultPreference << ND_OPT_RI_PRF_SHIFT) & ND_OPT_RI_PRF_MASK;
 
+	/* Completeness DNA !!! */
+	radvert->nd_ra_flags_reserved   |=
+		(iface->UnnegotiatedFastRA)?ND_RA_FLAG_FASTRA:0;
+
+#if 0 
+	radvert->nd_ra_flags_reserved   |= flags & ND_RA_FLAG_LANDMARK_SEEN;
+	radvert->nd_ra_flags_reserved   |= flags & ND_RA_FLAG_LANDMARK_INVALID;
+#endif /* 0 */
+
 	radvert->nd_ra_reachable  = htonl(iface->AdvReachableTime);
 	radvert->nd_ra_retransmit = htonl(iface->AdvRetransTimer);
 
@@ -232,6 +247,32 @@
 		len += sizeof(ha_info);
 	}
 	
+	/*
+	 * Add a complete list of prefixes to the RA.
+	 */
+
+        if(iface->PrefixLandmarking && lmark){
+		int added=0; 
+                dlog(LOG_DEBUG, 4, "Send LM/CRA:   %p %s",lmark, lmark);
+		added = make_landmark_option(buff,len,lmark,lmv);
+		len += added;
+	}
+
+	if(iface->CompleteRA){
+		int added;
+                int complete=0;
+                added = make_completera_option(iface,buff,len, &complete);
+
+                if(buff[len+1]==1)/* no RA in completeRA */
+                        added=0;
+
+                /* still need completeRA flag management */
+                radvert->nd_ra_flags_reserved   |=
+                                        (complete)?ND_RA_FLAG_COMPLETERA:0;
+
+		len += added;
+	} 
+
 	iov.iov_len  = len;
 	iov.iov_base = (caddr_t) buff;
 	
@@ -265,3 +306,4 @@
 		flog(LOG_WARNING, "sendmsg: %s", strerror(errno));
 	}
 }
+
diff -rub --exclude=CVS --exclude='config.[gsh]*' --exclude=depcomp --exclude=Makefile.in --new-file radvd/timer.c radvddna/timer.c
--- radvd/timer.c	2001-11-15 06:58:11.000000000 +1100
+++ radvddna/timer.c	2005-05-24 13:04:40.123524746 +1000
@@ -77,6 +77,7 @@
 	gettimeofday(&tv, NULL);
 	timeradd(&tv, &firein, &tm->expires);
 
+	dlog(LOG_DEBUG, 5, "expiry: %d.%d", tm->expires.tv_sec, tm->expires.tv_usec);
 	sigemptyset(&bmask);
 	sigaddset(&bmask, SIGALRM);
 	sigprocmask(SIG_BLOCK, &bmask, &oldmask);
@@ -85,6 +86,7 @@
 
 	do {
 		lst = lst->next;
+	        dlog(LOG_DEBUG, 5, "list: %d.%d (%p)", lst->expires.tv_sec, lst->expires.tv_usec, lst->prev);
 	} while ((tm->expires.tv_sec > lst->expires.tv_sec) ||
 		 ((tm->expires.tv_sec == lst->expires.tv_sec) && 
 		  (tm->expires.tv_usec > lst->expires.tv_usec)));
@@ -98,6 +100,7 @@
 	schedule_timer();
 
 	sigprocmask(SIG_SETMASK, &oldmask, NULL);
+	dlog(LOG_DEBUG, 5, "finished scheduling");
 }
 
 void
@@ -129,6 +132,10 @@
 	gettimeofday(&tv, NULL);
 	tm = timers_head.next;
 
+	dlog(LOG_DEBUG, 5, "calling alarm_handler %p p(%p) n(%p)", tm, tm->prev,
+			tm->next);
+
+
 	while ((tm->expires.tv_sec < tv.tv_sec)
 			|| ((tm->expires.tv_sec == tv.tv_sec) 
 			    && (tm->expires.tv_usec <= tv.tv_usec)))
@@ -153,5 +160,6 @@
 {
 	memset(tm, 0, sizeof(struct timer_lst));
 	tm->handler = handler;
-	tm->data = data;
+	tm->iface= data;
+	tm->data = tm;
 }
diff -rub --exclude=CVS --exclude='config.[gsh]*' --exclude=depcomp --exclude=Makefile.in --new-file radvd/util.c radvddna/util.c
--- radvd/util.c	2005-05-24 15:56:49.474313803 +1000
+++ radvddna/util.c	2005-05-24 16:03:04.084589454 +1000
@@ -16,6 +16,7 @@
 #include <config.h>
 #include <includes.h>
 #include <radvd.h>
+#include <dna.h>
                
 void
 mdelay(int msecs)
@@ -47,3 +48,439 @@
 		strcpy(str, "[invalid address]");	
 	}
 }
+
+/*return number of milliseconds */
+
+double tv_diff(struct timeval *tv1, struct timeval *tv2){
+    double sdiff=0.0;
+    int sign=0;
+   
+	 /* reduce gap by ms diff if tv1.sec - tv2.sec negative */
+    sign=((tv2->tv_sec > tv1->tv_sec)? -1 : 1);
+    
+    sdiff = ((long int)tv1->tv_sec - (long int)tv2->tv_sec);
+    
+    sdiff += sign * 
+		(((long int)tv1->tv_usec - (long int)tv2->tv_usec) * 0.000001);
+    return sdiff;
+}
+
+
+	/* compares two blocks of memory byte by byte in 
+	   reverse order */
+int revcmp(const void *s1, const void *s2, size_t n){
+	int ret=0;
+	uint8_t *c1, *c2;
+	int i; 
+	
+	if(!s1  || ! s2){
+		dlog(LOG_DEBUG, 5, "revcmp invalid arg: %p %p",s1, s2);
+		return 0;
+	}		
+   
+	c1 = (uint8_t *)s1; 
+	c2 = (uint8_t *)s2; 
+	for(i = n-1; i >= 0; i--){
+		if(c1[i] < c2[i])
+			ret = -1; 	
+
+		if(c1[i] > c2[i])
+			ret = 1; 	
+		if(ret){
+			/*dlog(LOG_DEBUG, 5,
+				"revcmp i%d c:%d c1[i]:%hhx c2[i]:%hhx:",
+				i, ret, c1[i], c2[i]);*/
+			return ret;	
+		}
+			
+	}
+	/*dlog(LOG_DEBUG, 5, "revcmp i%d cmp:%d",i, ret);*/
+	return ret; 
+}
+
+struct dtimer_list *remove_from_list(struct dtimer_list  *list,
+		 struct timer_lst *tm){
+	struct dtimer_list *entry, *tmp=NULL;
+
+	if(list == NULL)
+		return NULL;
+
+	if(tm == NULL){ /* any entry will do (free list only) */
+	      entry=list->next; 
+	      if(entry){
+		    list->next=entry->next;
+		    entry->next=NULL;
+	      }
+	      return entry;
+	}
+	tmp=list;
+	while(tmp->next !=NULL){
+		if(tmp->next->tm == tm){
+			entry=tmp->next;
+			tmp->next=entry->next;
+			entry->next=NULL;
+			return entry;
+		}
+		tmp=tmp->next;
+	}
+	return NULL;
+}
+
+
+void insert_into_list(struct dtimer_list *list, struct dtimer_list *entry){
+	if(!(list && entry))
+		return;
+
+	entry->next=list->next;
+	list->next=entry;	
+}
+
+
+void log_list(struct dtimer_list *list, const char *listname){
+
+	char emptystring[1]={'\0'};
+	char *tmpstr=NULL;
+	struct dtimer_list *tmp;
+
+	tmpstr=emptystring;
+
+	if(list==NULL){
+		return;
+	}
+	if (listname){
+		tmpstr=(char *)listname;
+	}
+
+	dlog(LOG_DEBUG, 5, "Printing %s list: %p n(%p)", tmpstr, 
+			   list, list->next);
+	
+	tmp=list;
+	while(tmp != NULL){
+
+		dlog(LOG_DEBUG, 5, "\t%p tm(%p) n(%p)",  tmp, tmp->tm,
+								 tmp->next);
+		tmp=tmp->next;
+	}
+
+}
+
+
+
+addr_match(struct in6_addr *a1, struct in6_addr *a2, int prefixlen)
+{
+	int pdw;
+	int pbi;
+
+	pdw = prefixlen >> 0x05;  /* num of whole uint32_t in prefix */
+	pbi = prefixlen &  0x1f;  /* num of bits in incomplete uint32_t in prefix */
+
+	if (pdw)
+	{
+		if (memcmp(a1, a2, pdw << 2))
+			return 0;
+	}
+
+	if (pbi)
+	{
+		uint32_t w1, w2;
+		uint32_t mask;
+
+		w1 = *((uint32_t *)a1 + pdw);
+		w2 = *((uint32_t *)a2 + pdw);
+
+		mask = htonl(((uint32_t) 0xffffffff) << (0x20 - pbi));
+
+		if ((w1 ^ w2) & mask)
+			return 0;
+	}
+	return 1;
+}
+
+
+
+
+
+int token_bucket_update(struct Interface *iface, struct timeval *tv)
+{
+	/* returns the number of tokens in the bucket for FastRA */
+	double difference;
+	int new_tokens;
+	struct timeval offsettv;
+	struct timeval newtokentv;
+	/*double offset;*/
+
+	difference = tv_diff(tv,&iface->LastFastRAToken);
+
+	if(difference < (((double)iface->FastRATokenInterval)/1000.0))
+	{
+		dlog(LOG_DEBUG, 5, "token bucket:  No New tokens (%d)",
+				iface->NumUnicastFastRAs);
+		return iface->NumUnicastFastRAs;
+	}
+	
+	dlog(LOG_DEBUG, 5, "token bucket:  last(%d.%d) now(%d.%d) %f %f", 
+		iface->LastFastRAToken.tv_sec, iface->LastFastRAToken.tv_usec,
+		tv->tv_sec, tv->tv_usec, difference, 
+		tv_diff(tv,&iface->LastFastRAToken) );
+
+	new_tokens = (int) (difference * 1000)/iface->FastRATokenInterval; 
+   
+	dlog(LOG_DEBUG, 5, "new tokens:  %d (ival:%d) ", new_tokens,
+			iface->FastRATokenInterval);
+
+	offsettv.tv_sec = (iface->FastRATokenInterval * new_tokens)/ 1000; 
+	offsettv.tv_usec = ((iface->FastRATokenInterval * new_tokens)% 1000) 
+				* 1000; 
+
+	dlog(LOG_DEBUG, 5, "token offset: %ld secs %ld usecs",
+			 offsettv.tv_sec, offsettv.tv_usec);
+
+	timeradd(&iface->LastFastRAToken, &offsettv, &newtokentv);
+
+	memcpy(&iface->LastFastRAToken, &newtokentv, sizeof(struct timeval));	
+	if(new_tokens >= (iface->MaxUnicastFastRAs - iface->NumUnicastFastRAs))
+	{
+		iface->NumUnicastFastRAs = iface->MaxUnicastFastRAs;	
+	}
+	else{
+		iface->NumUnicastFastRAs += new_tokens;
+	}
+
+	dlog(LOG_DEBUG, 5, "Tokens %d  Max %d  last token time: %d.%d",
+			iface->NumUnicastFastRAs, iface->MaxUnicastFastRAs,
+			iface->LastFastRAToken.tv_sec,
+			iface->LastFastRAToken.tv_usec);
+
+	return iface->NumUnicastFastRAs;
+}
+
+
+int prefix_mask(struct in6_addr *prefix, struct in6_addr *addr, int plen){
+	uint32_t mask;
+	int i=0; 
+
+	while(plen > 32){
+		plen -=32;
+		prefix->s6_addr32[i] = addr->s6_addr32[i];
+		dlog(LOG_DEBUG, 5, "(%d)%2.2hx:%2.2hx", i,
+				 ntohs(prefix->s6_addr16[2 * i]),
+				 ntohs(prefix->s6_addr16[(2 * i)+1])); 
+		i++; 
+	}
+
+	mask = 0xffffffff << (32 - plen);	
+
+	prefix->s6_addr32[i] = addr->s6_addr32[i] & htonl(mask);
+
+	dlog(LOG_DEBUG, 5, "(m%d)%2.2hx:%2.2hx -[%d]", i,
+			 ntohs(prefix->s6_addr16[2 * i]),
+			 ntohs(prefix->s6_addr16[(2 * i)+1]),plen); 
+
+	i++; 
+
+	for( ; i < 4; i++){
+		prefix->s6_addr32[i]=0;
+		dlog(LOG_DEBUG, 5, "(a%d)%2.2hx:%2.2hx", i,
+			 ntohs(prefix->s6_addr16[2 * i]),
+			 ntohs(prefix->s6_addr16[(2 * i)+1])); 
+	}
+	return 0;
+}
+
+int clean_rtrprefix(struct RtrPrefixList *landlist, int curr,
+			struct timeval *now){
+	char addr_str[INET6_ADDRSTRLEN];
+	int i, j, found=0;
+	struct in6_addr astruct, *prefix;
+
+	dlog(LOG_DEBUG,5,"cleaning landmarks: num: %d (%lu.%lu) ",
+			curr, now->tv_sec, now->tv_usec);
+
+	for (i = 0; i < curr ; i++){
+
+		dlog(LOG_DEBUG,5,"landmark loop: %d curr:%d %f x(%d.%d) n(%d.%d)",
+			i,curr,tv_diff(&landlist[i].expiry, now),
+			landlist[i].expiry.tv_sec, landlist[i].expiry.tv_usec,
+			now->tv_sec, now->tv_usec);
+
+		while ((i < curr) && (tv_diff(&landlist[i].expiry, now) < 0)){
+
+			dlog(LOG_DEBUG,5,"landmark loop expiry: %d %f",i,
+					tv_diff(now, &landlist[i].expiry));
+			
+			memset(&landlist[0], 0, sizeof(struct RtrPrefixList));
+			curr--;
+
+			for(j = i; j < curr; j++){
+				memcpy( &landlist[j], &landlist[j+1],
+					sizeof(struct RtrPrefixList));
+			}
+			memset(&landlist[j], 0, sizeof(struct RtrPrefixList));
+		}
+	}
+
+	dlog(LOG_DEBUG,5,"landmark loop exit: %d c:%d",i,curr);
+
+	return curr;
+}
+
+
+int add_rtrprefix(struct RtrPrefixList *landlist, int num, int curr,
+	struct in6_addr *prefix, uint32_t expires, int hash, int plen){
+	struct timeval now, tv, expirestimer;
+	unsigned char digest[SHA_DIGEST_LENGTH];
+	char addr_str[INET6_ADDRSTRLEN];
+	int i, j, found=0;
+	expirestimer.tv_sec=expires;
+	expirestimer.tv_usec=0;
+	gettimeofday(&now, NULL);
+	timeradd(&now, &expirestimer, &tv);
+
+	dlog(LOG_DEBUG,5,"adding landmarks: Prefix expiry: %lu %d (%d.%d) ",
+			expires, curr, tv.tv_sec, tv.tv_usec);
+
+	for (i = 0; i < curr ; i++){
+
+		dlog(LOG_DEBUG,5,"landmark loop: %d curr:%d %f x(%d.%d) n(%d.%d)",
+			i,curr,tv_diff(&landlist[i].expiry, &now),
+			landlist[i].expiry.tv_sec, landlist[i].expiry.tv_usec,
+			now.tv_sec, now.tv_usec);
+
+
+
+		while ((i < curr) && (tv_diff(&landlist[i].expiry, &now) < 0)){
+
+			dlog(LOG_DEBUG,5,"landmark loop expiry: %d %f",i,
+					tv_diff(&now, &landlist[i].expiry));
+			
+			memset(&landlist[0], 0, sizeof(struct RtrPrefixList));
+			curr--;
+
+			for(j = i; j < curr; j++){
+				memcpy( &landlist[j], &landlist[j+1],
+					sizeof(struct RtrPrefixList));
+			}
+			memset(&landlist[j], 0, sizeof(struct RtrPrefixList));
+		}
+		if(!memcmp(&landlist[i].Prefix, prefix,
+					 sizeof(struct in6_addr))){
+
+			dlog(LOG_DEBUG,5,"landmark match: %d  e(%d.%d)",i,
+					landlist[i].expiry.tv_sec,
+					landlist[i].expiry.tv_usec);
+			if(tv_diff(&tv , &landlist[i].expiry) > 0){
+				memcpy(&landlist[i].expiry, &tv, sizeof (struct
+					timeval));
+			}
+			landlist[i].this_adv=1;
+			found=1;
+			return curr;
+		}
+	}
+
+	dlog(LOG_DEBUG,5,"landmark loop exit: %d c:%d n:%d",i,curr, num);
+	if(curr == num)
+		return 0;
+			
+	dlog(LOG_DEBUG,5,"landmark curr != num ");
+	dlog(LOG_DEBUG,5,"landmark expiry: %lu.%lu",tv.tv_sec, tv.tv_usec);
+
+	memcpy(&landlist[curr].Prefix, prefix, sizeof(struct in6_addr));
+	memcpy(&landlist[curr].expiry, &tv,  sizeof (struct timeval));
+	landlist[curr].this_adv=1;
+	landlist[curr].plen=plen;
+
+	print_addr(&landlist[curr].Prefix, addr_str);
+
+	dlog(LOG_DEBUG,5,"landmark prefix(%d): %s",curr,addr_str);
+ 
+	dlog(LOG_DEBUG,5,"about to hash? (%d)");
+	if(hash){
+		SHA1((unsigned char *)&landlist[curr].Prefix, 
+			sizeof(struct in6_addr), digest);
+		memcpy(&landlist[curr].hash, digest, 8);
+		dlog(LOG_DEBUG,5,"hash install: %d  c:%d %8.8lx%8.8lx",i, curr,
+				ntohl(((uint32_t *)landlist[curr].hash)[0]),
+				ntohl(((uint32_t *)landlist[curr].hash)[1]));
+	}
+	dlog(LOG_DEBUG,5,"landmark install: %d  c:%d e(%d.%d)",i, curr,
+				landlist[curr].expiry.tv_sec,
+				landlist[curr].expiry.tv_usec);
+	return curr+1;
+}
+
+
+
+/* the land timers need to be set to a nearer expiry if that exists */
+
+int update_landtimers(struct RtrPrefixList *landlist, int curr,
+						uint32_t expires){
+	int i;
+	struct timeval now, tv, expirestimer;
+
+	expirestimer.tv_sec=expires;
+	expirestimer.tv_usec=0;
+	gettimeofday(&now, NULL);
+	timeradd(&now, &expirestimer, &tv);
+
+	for(i = 0; i < curr ; i++){
+		
+		dlog(LOG_DEBUG,5,"landmark update loop",i);
+		if(landlist[i].this_adv && (tv_diff(&tv, &landlist[i].expiry)
+					 < 0)){
+			memcpy(&landlist[i].expiry, &tv, sizeof
+				(struct timeval));	
+		}
+		landlist[i].this_adv=0;
+	}
+	return i;
+}
+
+
+
+int check_before(struct RtrPrefixList *list, int curr,
+				uint32_t *ownhash, struct in6_addr *addr){
+	int count = 0;
+	int i;
+	uint64_t ownval[8], calcval[8];
+	char  addr_str[INET6_ADDRSTRLEN];
+
+	if(curr == 0)
+		return 0;
+
+	ownval[0] = *((uint64_t *)ownhash) ^ *((uint64_t *)&addr->s6_addr[8]);
+
+	dlog(LOG_DEBUG,5,"own hash: c:%d %8.8lx%8.8lx",curr,
+				ntohl(ownhash[0]), ntohl(ownhash[1]));
+	print_addr(addr, addr_str);
+	dlog(LOG_DEBUG,4,"own xor: %8.8lx%8.8lx %s",
+				ntohl(((uint32_t *)ownval)[0]),
+				ntohl(((uint32_t *)ownval)[1]),
+				addr_str);
+
+	for(i = 0; i < curr; i ++){
+		print_addr(&list[i].Prefix, addr_str);
+		calcval[0] = *((uint64_t *)list[i].hash) ^ 
+				*((uint64_t *)&addr->s6_addr[8]);
+		/*calcval[1] = list[i].hash[1] ^ addr->s6_addr32[3];*/
+		dlog(LOG_DEBUG,5,"peer   hash: %d %8.8lx%8.8lx %s",i, 
+				ntohl(((uint32_t *)list[i].hash)[0]),
+				ntohl(((uint32_t *)list[i].hash)[1]),addr_str);
+		dlog(LOG_DEBUG,5,"rec pattern: %d %8.8lx%8.8lx",i, 
+				ntohl(addr->s6_addr32[2]),
+				ntohl(addr->s6_addr32[3]));
+
+		print_addr(addr, addr_str);
+		dlog(LOG_DEBUG,4,"peer    xor: %d %8.8lx%8.8lx %s %d",i,
+				ntohl(((uint32_t *)calcval)[0]),
+				ntohl(((uint32_t *)calcval)[1]),
+				addr_str,
+				revcmp(ownval, calcval, 8));
+
+		if(revcmp(ownval, calcval, 8) < 0 ){
+			count++;
+		}
+	}
+
+	return count;	
+}