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 to continue, or q 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 : add $0xc,%esp +(gdb) x/i 0x08049750 +0x8049750 : jmp 0x804973e +(gdb) x/i 0x080496e4 +0x80496e4 : pop %ecx +(gdb) f 0x40082dcf +#0 0x00000000 in ?? () +(gdb) x/i 0x40082dcf +0x40082dcf: Cannot access memory at address 0x40082dcf +(gdb) x/i 0x0804b7fc +0x804b7fc : mov 0xffffffe8(%ebp),%eax +(gdb) x/i 0x0804ad62 +0x804ad62 : push $0x0 +(gdb) x/i 0x08049750 +0x8049750 : jmp 0x804973e +(gdb) x/i 0x0804966f +0x804966f : 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 . * + * Greg Daley Sept 2004: Added support for SLLAO NCE installs */ #include @@ -19,10 +20,33 @@ #include #include /* 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 +#include +#include +#include + #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 + * + * 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 . + * + */ + +#include +#include +#include +#include + + + + /* 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 + * + * 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 . + * + */ + +#ifndef ND_DNA_H +#define ND_DNA_H + + +#include + +#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 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 #endif +#include + #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 #include #include +#include + + +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 #include #include +#include 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 #include #include +#include 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 #include #include +#include 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; +}