diff -rub --exclude=CVS --exclude=ExtendedMode.txt --exclude=Makefile.test --exclude=.* --exclude=*~ --exclude=*.detail --ignore-matching-lines=$Id: mipl-0.9.3/linux/Documentation/Configure.help mipl-0.9.3-hmipv6/linux/Documentation/Configure.help --- mipl-0.9.3/linux/Documentation/Configure.help Mon Jul 15 16:33:27 2002 +++ mipl-0.9.3-hmipv6/linux/Documentation/Configure.help Mon Jul 22 09:19:09 2002 @@ -5325,6 +5325,25 @@ Be sure to say Y and record debug messages when submitting a bug report. +MIPv6: Hierarchical Mobile IPv6 Management (HMIPv6) +CONFIG_IPV6_MOBILITY_HMIPV6 + Hierarchical Mobility Management reduces signalling requirements + outside the access network where this service is provided. + MN's and HMIPv6 Mobility Access Points (MAPs) form bindings to + control handover latency. Both the MN and MAP Basic Mode + implementations are supported from Draft 6 of the specification. + + HMIPv6 is latent until MN's receive a MAP Advertisement (in an RA), + on a supporting access network. + + In order to advertise MAP presence, a suitable userspace daemon + is requred. A modified RADVD is available at + http://www.ctie.monash.edu.au/hmipv6.htm + + This code is still experimental, and may not work with AH. + + If you don't use AH, and want to try HMIPv6, say Y here. + Kernel httpd acceleration CONFIG_KHTTPD The kernel httpd acceleration daemon (kHTTPd) is a (limited) web diff -rub --exclude=CVS --exclude=ExtendedMode.txt --exclude=Makefile.test --exclude=.* --exclude=*~ --exclude=*.detail --ignore-matching-lines=$Id: mipl-0.9.3/linux/include/net/addrconf.h mipl-0.9.3-hmipv6/linux/include/net/addrconf.h --- mipl-0.9.3/linux/include/net/addrconf.h Mon Jul 15 16:33:27 2002 +++ mipl-0.9.3-hmipv6/linux/include/net/addrconf.h Tue Aug 6 10:23:30 2002 @@ -106,6 +106,11 @@ struct prefix_info *pinfo, struct in6_addr *home_addr); +extern int addrconf_mipv6(int ifindex, + struct in6_addr *addr, + __u32 lifetime, + int plen,int ack); + /* Device notifier */ extern int register_inet6addr_notifier(struct notifier_block *nb); diff -rub --exclude=CVS --exclude=ExtendedMode.txt --exclude=Makefile.test --exclude=.* --exclude=*~ --exclude=*.detail --ignore-matching-lines=$Id: mipl-0.9.3/linux/include/net/mipv6.h mipl-0.9.3-hmipv6/linux/include/net/mipv6.h --- mipl-0.9.3/linux/include/net/mipv6.h Mon Jul 15 16:33:27 2002 +++ mipl-0.9.3-hmipv6/linux/include/net/mipv6.h Tue Aug 6 10:23:48 2002 @@ -87,6 +87,10 @@ #define MIPV6_BU_F_HOME 0x40 #define MIPV6_BU_F_SINGLE 0x20 #define MIPV6_BU_F_DAD 0x10 + +/* Binding update flag code for MAP option */ +#define MIPV6_BU_F_MAP 0x08 + /* * diff -rub --exclude=CVS --exclude=ExtendedMode.txt --exclude=Makefile.test --exclude=.* --exclude=*~ --exclude=*.detail --ignore-matching-lines=$Id: mipl-0.9.3/linux/include/net/ndisc.h mipl-0.9.3-hmipv6/linux/include/net/ndisc.h --- mipl-0.9.3/linux/include/net/ndisc.h Mon Jul 15 16:33:27 2002 +++ mipl-0.9.3-hmipv6/linux/include/net/ndisc.h Tue Aug 6 10:23:29 2002 @@ -25,6 +25,9 @@ #define ND_OPT_RTR_ADV_INTERVAL 7 #define ND_OPT_HOME_AGENT_INFO 8 +/* Temporary for HMIPv6 */ +#define ND_OPT_MAP 201 + #define MAX_RTR_SOLICITATION_DELAY HZ #define ND_REACHABLE_TIME (30*HZ) diff -rub --exclude=CVS --exclude=ExtendedMode.txt --exclude=Makefile.test --exclude=.* --exclude=*~ --exclude=*.detail --ignore-matching-lines=$Id: mipl-0.9.3/linux/net/ipv6/addrconf.c mipl-0.9.3-hmipv6/linux/net/ipv6/addrconf.c --- mipl-0.9.3/linux/net/ipv6/addrconf.c Mon Jul 15 16:33:27 2002 +++ mipl-0.9.3-hmipv6/linux/net/ipv6/addrconf.c Fri Jul 19 16:40:09 2002 @@ -57,6 +57,7 @@ #include #include #include +#include #include #include @@ -632,12 +633,23 @@ struct inet6_dev *idev; int err = -EADDRNOTAVAIL; + ADBG(("ipv6_get_lladdr:\n")); read_lock(&addrconf_lock); if ((idev = __in6_dev_get(dev)) != NULL) { struct inet6_ifaddr *ifp; + ADBG(("ipv6_get_lladdr: got device %s %p\n",dev->name, idev->addr_list)); read_lock_bh(&idev->lock); for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) { + ADBG(("ipv6_get_lladdr scan: %x:%x:%x:%x:%x:%x:%x:%x\n", + ntohs(ifp->addr.s6_addr16[0]), + ntohs(ifp->addr.s6_addr16[1]), + ntohs(ifp->addr.s6_addr16[2]), + ntohs(ifp->addr.s6_addr16[3]), + ntohs(ifp->addr.s6_addr16[4]), + ntohs(ifp->addr.s6_addr16[5]), + ntohs(ifp->addr.s6_addr16[6]), + ntohs(ifp->addr.s6_addr16[7]))); if (ifp->scope == IFA_LINK && !(ifp->flags&IFA_F_TENTATIVE)) { ipv6_addr_copy(addr, &ifp->addr); err = 0; @@ -1076,6 +1088,123 @@ in6_dev_put(in6_dev); } +#ifdef USE_IPV6_MOBILITY +/* SHARKEY :r addrconf.c.extra */ + + /* Configure up local home/care of addresses on */ + /* current interface (any intf if exists) */ + /* Required for HMIPv6 RCoA Configuration */ + + /* Install /128 routes to make sure we can reach */ + /* MAP/HA networks */ + /* */ + /* code adapted from ipv6_addr_add and */ + /* addrconf_prefix_recv */ + + /* TODO: uninstall ?? currently entries time out */ + /* set lifetime zero? */ + +int addrconf_mipv6(int ifindex, struct in6_addr *addr, __u32 lifetime, + int plen,int ack) +{ + struct rt6_info *rt; + int addr_type; + unsigned long rt_expires; + struct inet6_dev *in6_dev; + struct net_device *dev; + struct inet6_ifaddr * ifp; + + ASSERT_RTNL(); + + ADBG(("addrconf_mipv6\n")); + + dev = NULL; + + /* install local mipv6 addresses on dummy if */ + /* up and available */ + dev = __dev_get_by_name("dummy0"); + + if(dev) { + ADBG(("addrconf_mipv6: dev: %lx flags: %lx\n", + (unsigned long)dev , (unsigned long)dev->flags )); + } + /* if we don't already have a device */ + if (!(dev) && ((dev = __dev_get_by_index(ifindex)) == NULL)) + return -ENODEV; + + ADBG(("addrconf_mipv6: dev: %lx flags: %lx\n", + (unsigned long)dev , (unsigned long)dev->flags )); + + if (!(dev->flags&IFF_UP)) + return -ENETDOWN; + + if ((in6_dev = addrconf_add_dev(dev)) == NULL) + return -ENOBUFS; + + ADBG(("addrconf_mipv6: begin addrconf validation \n")); + ADBG(("%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx\n", + ntohs(addr->s6_addr16[0]), ntohs(addr->s6_addr16[1]), + ntohs(addr->s6_addr16[2]), ntohs(addr->s6_addr16[3]), + ntohs(addr->s6_addr16[4]), ntohs(addr->s6_addr16[5]), + ntohs(addr->s6_addr16[6]), ntohs(addr->s6_addr16[7]))); + + /* + * Validation checks ([ADDRCONF], page 19) + */ + + addr_type = ipv6_addr_type(addr); + + if (addr_type & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL)) + return -EADDRNOTAVAIL; + + /* configure the local interface */ + + ifp = ipv6_get_ifaddr(addr, NULL); + + if (ifp == NULL && lifetime) { + /* if ack, DAD already completed for RCoA/HOMEADDR */ + ifp = ipv6_add_addr(in6_dev, addr, plen, + addr_type&IPV6_ADDR_SCOPE_MASK, + (ack? 0 : IFA_F_TENTATIVE ) ); + + /* DAD must be done, but is NULL OP if */ + /* !(ifp->flags & IFA_F_TENTATIVE) */ + addrconf_dad_start(ifp); + } + + if (ifp && (! lifetime)) { + /* TODO: Check if the address is permanent */ + ipv6_del_addr(ifp); + ifp = NULL; + } + + if (ifp) { + int flags; + + spin_lock(&ifp->lock); + ifp->valid_lft = lifetime; + ifp->prefered_lft = lifetime; /* TODO: Check for DHAAD */ + ifp->tstamp = jiffies; + if(ack){ /* reset tentative if we receive a BAck */ + ifp->flags &= ~IFA_F_TENTATIVE; + } + flags = ifp->flags; + ifp->flags &= ~IFA_F_DEPRECATED; + spin_unlock(&ifp->lock); + + if (!(flags&IFA_F_TENTATIVE)) + ipv6_ifa_notify((flags&IFA_F_DEPRECATED) ? + 0 : RTM_NEWADDR, ifp); + in6_ifa_put(ifp); + } + in6_dev_put(in6_dev); + + return 0; +} + +/* /SHARKEY */ +#endif /* USE_IPV6_MOBILITY */ + int addrconf_pfx_adv_rcv(struct net_device *dev, struct prefix_info *pinfo, struct in6_addr *home_addr) { @@ -1567,7 +1696,7 @@ { struct inet6_dev *idev; struct inet6_ifaddr *ifa, **bifa; - struct list_head *head; + struct list_head *head, *tmp; struct prefix_element *p; int i; @@ -1634,7 +1763,7 @@ /* Step 5: Free up Prefix List */ spin_lock_bh(&idev->prefix_lock); - list_for_each(head, &idev->prefix_list) { + list_for_each_safe(head, tmp, &idev->prefix_list) { p = list_entry(head, struct prefix_element, list); kfree(p); } @@ -1868,7 +1997,7 @@ unsigned long now = jiffies; struct net_device *dev; struct inet6_dev *idev; - struct list_head *head; + struct list_head *head, *tmp; struct prefix_element *p; unsigned long age; @@ -1884,7 +2013,7 @@ read_unlock_bh(&idev->lock); continue; } - list_for_each(head, &idev->prefix_list) { + list_for_each_safe(head, tmp, &idev->prefix_list) { p = list_entry(head, struct prefix_element, list); if (p->pinfo.valid != INFINITE) { age = (now - p->timestamp) / HZ; diff -rub --exclude=CVS --exclude=ExtendedMode.txt --exclude=Makefile.test --exclude=.* --exclude=*~ --exclude=*.detail --ignore-matching-lines=$Id: mipl-0.9.3/linux/net/ipv6/ipv6_tunnel.c mipl-0.9.3-hmipv6/linux/net/ipv6/ipv6_tunnel.c --- mipl-0.9.3/linux/net/ipv6/ipv6_tunnel.c Mon Jul 15 16:33:27 2002 +++ mipl-0.9.3-hmipv6/linux/net/ipv6/ipv6_tunnel.c Fri Jul 19 11:08:16 2002 @@ -46,6 +46,8 @@ #include #include +#define TUNNEL_DEBUG + /* * IPv6 tunnel socket for flow control */ @@ -152,6 +154,21 @@ static int shutdown = 0; +#ifdef TUNNEL_DEBUG + +static void print_in6_addr(char *label, struct in6_addr *addr) +{ + printk("%s: %x:%x:%x:%x:%x:%x:%x:%x,\n", + label, ntohs(addr->s6_addr16[0]), + ntohs(addr->s6_addr16[1]), ntohs(addr->s6_addr16[2]), + ntohs(addr->s6_addr16[3]), ntohs(addr->s6_addr16[4]), + ntohs(addr->s6_addr16[5]), ntohs(addr->s6_addr16[6]), + ntohs(addr->s6_addr16[7])); +} + +#endif + + /** * ipv6_ipv6_tunnel_lookup - fetch tunnel matching the end-point addresses * @remote: the address of the tunnel exit-point @@ -177,6 +194,8 @@ #ifdef TUNNEL_DEBUG printk(KERN_DEBUG "ipv6_ipv6_tunnel_lookup\n"); + print_in6_addr("tun src ", remote); + print_in6_addr("tun dest ", local); #endif for (t = tunnels_r_l[h0 ^ h1]; t; t = t->next) { if (!ipv6_addr_cmp(local, &t->parms.saddr) && @@ -897,6 +916,9 @@ read_unlock(&ipv6_ipv6_lock); return 0; } +#ifdef TUNNEL_DEBUG + printk(KERN_DEBUG "ipv6_ipv6_rcv: lookup failed\n"); +#endif icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0, skb->dev); @@ -1852,6 +1874,9 @@ register_netdev(&ipv6_ipv6_fb_tunnel_dev); inet6_add_protocol(&ipv6_ipv6_protocol); +#ifdef TUNNEL_DEBUG + printk(KERN_DEBUG "ipv6_ipv6_tunnel_init\n"); +#endif return 0; } diff -rub --exclude=CVS --exclude=ExtendedMode.txt --exclude=Makefile.test --exclude=.* --exclude=*~ --exclude=*.detail --ignore-matching-lines=$Id: mipl-0.9.3/linux/net/ipv6/mobile_ip6/Config.in mipl-0.9.3-hmipv6/linux/net/ipv6/mobile_ip6/Config.in --- mipl-0.9.3/linux/net/ipv6/mobile_ip6/Config.in Mon Jul 15 16:33:27 2002 +++ mipl-0.9.3-hmipv6/linux/net/ipv6/mobile_ip6/Config.in Fri Jul 19 12:34:38 2002 @@ -3,5 +3,6 @@ if [ "$CONFIG_IPV6_MOBILITY" = "m" ]; then bool ' MIPv6: AH Support' CONFIG_IPV6_MOBILITY_AH bool ' MIPv6: Debug messages' CONFIG_IPV6_MOBILITY_DEBUG + bool ' Hierarchical Mobile IPv6 (HMIPv6)' CONFIG_IPV6_MOBILITY_HMIPV6 fi fi diff -rub --exclude=CVS --exclude=ExtendedMode.txt --exclude=Makefile.test --exclude=.* --exclude=*~ --exclude=*.detail --ignore-matching-lines=$Id: mipl-0.9.3/linux/net/ipv6/mobile_ip6/Makefile mipl-0.9.3-hmipv6/linux/net/ipv6/mobile_ip6/Makefile --- mipl-0.9.3/linux/net/ipv6/mobile_ip6/Makefile Mon Jul 15 16:33:27 2002 +++ mipl-0.9.3-hmipv6/linux/net/ipv6/mobile_ip6/Makefile Fri Jun 21 15:25:32 2002 @@ -14,6 +14,7 @@ sendopts.o stats.o access.o sysctl.o router.o \ dhaad.o halist.o ioctl.o util.o sadb.o ah_algo.o \ auth_subopt.o multiaccess_ctl.o mipv6_icmp.o \ + hierarchy.o map.o rcoa.o \ sortedlist.o prefix.o ifeq ($(CONFIG_IPV6_MOBILITY_DEBUG),y) diff -rub --exclude=CVS --exclude=ExtendedMode.txt --exclude=Makefile.test --exclude=.* --exclude=*~ --exclude=*.detail --ignore-matching-lines=$Id: mipl-0.9.3/linux/net/ipv6/mobile_ip6/TODO.hmip6 mipl-0.9.3-hmipv6/linux/net/ipv6/mobile_ip6/TODO.hmip6 --- mipl-0.9.3/linux/net/ipv6/mobile_ip6/TODO.hmip6 Wed Aug 7 11:06:04 2002 +++ mipl-0.9.3-hmipv6/linux/net/ipv6/mobile_ip6/TODO.hmip6 Wed Aug 7 10:48:10 2002 @@ -0,0 +1,191 @@ +# HMIPv6 Release 0.2 Change/Issue List + +20020318: When MAP receives binding update for MN's Home Address with + same RCoA as is bound by MAP on MN's behalf, packets are not + sent back to MN. + + Guess: binding table points to a local address (RCoA). + No second lookup being done on RCoA/AltCoA + First packet is returned before Bcache is updated and + doesn't go out dummy0. + + This occurs if communication is performed to another interface + on the map than the MAP Global Address. + + ACTION: 20021803 : wait until mergedown to MIPL CVS and retest. + procrcv.c is in flux. + ACTION: 2002-06-11: BU's not being sent to CNs. Wait for fix to + that issue before getting recursive BCache Lookups. + ACTION: 2002-07-04: BU's to CN's working. + recursive bcache lookups scheduled for 0.4 Release/Extended. +-------------------------------------------------------------------- + + +20020318: continuous router solicitation after mobile_ip6 module + loaded on MN + + After binding update, router solicitations are received continually. + + CAUSE: If no r_adv received within 6 seconds, send RS + Does not occur when max interval between r_adv is 3 seconds + + Function as designed. Checked in CVS MIPL. (same). + +----------------------------------------------------------------------- + + +2002-03-18: changing prefix on the same router (same LL address) does not + stimulate binding update to MAP + Guess: looks like interval timer is being ignored + try without link address + still same effect w/o link address + Analysis: looks like RA source address (link local) used for RADV + Need to use this and prefix + Action: Test again under MIPL CVS + RESULT 2002-07-04 No BU sent in HMIPL-0.9.3 + +------------------------------------------------------------------------- + + +2002-03-25: + BUs to previous MAPs when PBit is set do not contain RCoA: + effectively means previous MAP forwards to LCoA + Severity: Medium. + Guess: need to set case to be if (MapBu && MAP == current) + skip packet rewriting (currently if MapBu) + Action: modify for this release. + FIXED: 2002-06-11 BU to previous MAP uses RCoA if not current. + +------------------------------------------------------------------------- + + +2002-03-25: + + Incorrect reporting of CoA when Bu to HA in MAP coverage with + P bit set. the CoA effectively is the RCoA since the HA never + sees LCoA. (outbound packets are re-written). + Guess: + the same will happen with BUs to old MAPs and CNs. + Severity: Low. + Action: modify interface or modify bulist to know the effective + coa. + FIXED 2002-06-06 BUlist now refers to RCoA. + +------------------------------------------------------------------------- + + +2002-03-26: + Losing Binding updates after many renewals. + Unsure if BAcks are being received. + Guess: BUL is not rescheduling + Severity: Medium + Action: check after release, CVS diff r1.1, and also check under new + MIPL + Looks like using default BU lifetime instead of one received + in BAck or in RA. + 2002-05-15: fixed 2.4.16 m14/h5 needs update in m15/h5 + FIXED 2002-06-11 with new rebinding/timing code. + +------------------------------------------------------------------------- + + +2002-04-09: + Sending Binding Updates (with MAP) to MAP/HA/CN only + at DEFAULT_MAP_LIFETIME + needs to be ( min3(HA Lifetime, CN Lifetime, MAP BU lifetime) !! + or granted lifetime? + FIXED (2002-06-03 for MAPs) + Need to incorporate changes for CN/HA's into bug from 2002-05-08 + ACTION 2002-07-09: test for fix + +------------------------------------------------------------------------- + + +2002-05-23: + Not binding updating MAP on movement when it is acting as a CN. + (i.e. you are pinging the MAP when you move, BCache on MAP i + s not being updated) + Guess: general correspondent node issues when RCoA changes + Severity: Medium + Action: check after mergedown. + Findings: CN code deficient. other issues may exist on MAPs. + FIXED: 2002-07-04 ALL BU's being sent. callbacks working. + +------------------------------------------------------------------------- + + +2002-05-28: + Need to use granted lifetime of MAP to ensure BU's do not exceed + MAP lifetimes (hmip6-05 sec 6.1) + + use in BUL when sending bindupdates. + FIXED: 2002-06-11 All except Old MAP BU's, since this is not + covered in standard. Old MAP bu using default map lifetime. + +------------------------------------------------------------------------- + + +2002-06-11: + Discovered that no BU is sent to CN upon reception of packets + in HMIPv6 Mode. + Guess: no correspondent node bindings going out. + Action: Check packet recpetion routines after mergedown. + FIXED in MIPL 0.9.3 + +-------------------------------------------------------------------------- + + +2002-07-04: + MAP crashes after receiving binding update on mobile_ip6 + module restart. + It looks like a binding ack packet is being received on + tap0 before the MAP fails. + GUESS: tunnel state inconsistent after unload/reload of + mobile_ip6 module. + ACTION: investigate tap2/tap0 packet interaction. + DIAGNOSIS: ipv6tunnel output indicated that tunnels were + still present after mobile-ip6 module unloading. + also, on MAP ipv6_tunnel module was still loaded + while on HA it was unloaded. + FIXED 2002-07-08: bcache unloading failed to remove tunnel + for type BASIC_MAP. + +-------------------------------------------------------------------------- + + +2002-07-04: + After moving out of MAP cover, tunnels not reestablished to LCoA. + guess: Not removing old tunnels. + FIXED 2002-07-04: MAP tunnels now removed. + +-------------------------------------------------------------------- + + +2002-07-04: + Incorrect RCoA sent in MAP BU. + + DIAGNOSIS: + Occurs when map callback occurs and there is no valid router. + WORKAROUND 2002-07-04: return -1 from mn_get_care_of_address when + ipv6_get_lladdr fails. this is done after the processing of + the coa, to mask this change from calls which aren't checking + the return value of mipv6_get_care_of_address !! + ACTION: Monitor for introduced bugs. + +--------------------------------------------------------------------------- + + +2002-07-22: + Incorrect BU lifetime for CN with pre-exisiting binding. + HA is OK. + + binding exists before HMIPv6 MAP gc is called back. + + Also true if bul entry expires and ping6 cn is issued. + GUESS: + MAP handoff routing is not setting the binding timer to less than + MAP lifetime. + DIAGNOSIS: initialization of BU to CN didn't consider MAP + FIXED 2002-07-22 + + diff -rub --exclude=CVS --exclude=ExtendedMode.txt --exclude=Makefile.test --exclude=.* --exclude=*~ --exclude=*.detail --ignore-matching-lines=$Id: mipl-0.9.3/linux/net/ipv6/mobile_ip6/ah_algo.h mipl-0.9.3-hmipv6/linux/net/ipv6/mobile_ip6/ah_algo.h --- mipl-0.9.3/linux/net/ipv6/mobile_ip6/ah_algo.h Mon Jul 15 16:33:27 2002 +++ mipl-0.9.3-hmipv6/linux/net/ipv6/mobile_ip6/ah_algo.h Tue Aug 6 10:24:03 2002 @@ -3,7 +3,7 @@ * Authors: * Alexis Olivereau * - * $ + * $Id: ah_algo.h,v 1.1 2002/04/10 03:22:40 sharkey Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff -rub --exclude=CVS --exclude=ExtendedMode.txt --exclude=Makefile.test --exclude=.* --exclude=*~ --exclude=*.detail --ignore-matching-lines=$Id: mipl-0.9.3/linux/net/ipv6/mobile_ip6/bcache.c mipl-0.9.3-hmipv6/linux/net/ipv6/mobile_ip6/bcache.c --- mipl-0.9.3/linux/net/ipv6/mobile_ip6/bcache.c Mon Jul 15 16:33:27 2002 +++ mipl-0.9.3-hmipv6/linux/net/ipv6/mobile_ip6/bcache.c Fri Jul 19 16:40:09 2002 @@ -17,6 +17,7 @@ * * Nanno Langstraat : Timer code cleaned up, active socket * test rewritten + * Nick : Mods for MAP support */ #include @@ -75,6 +76,11 @@ #define BCACHE_BR_SEND_THRESHOLD 10 +#ifdef CONFIG_IPV6_MOBILITY_HMIPV6 +#define HOME_BCACHE_MASK (HOME_REGISTRATION|BASIC_MAP) +#else +#define HOME_BCACHE_MASK (HOME_REGISTRATION) +#endif /* * Internal functions. @@ -131,8 +137,8 @@ entry = (struct mipv6_bcache_entry *) mipv6_allocate_element(bcache->entry_pool); - if (entry == NULL && type == HOME_REGISTRATION) { - /* cache full, but need space for a home registration */ + if (entry == NULL && type != CACHE_ENTRY) { + /* cache full, but need space for a home registration etc */ args.entry = &entry; hashlist_iterate(bcache->entries, &args, find_first_cache_entry_iterator); @@ -163,19 +169,21 @@ static int is_valid_type(__u8 type) { - if (type != CACHE_ENTRY && type != HOME_REGISTRATION) - return 0; - else - return 1; + /* check it is a valid type, and that there's only + * one bit set. (type & (type - 1)) deletes rightmost + * bit. */ + return (type & VALID_TYPES) && (!(type & (type - 1))); } /* * Stop listening to the multicast value of the Home Address of a * MN when it's binding cache entry is being expired or freed up. + * Basic MAP mode needs this too. */ static inline void bcache_proxy_nd_rem(struct mipv6_bcache_entry *entry) { - if (entry->type == HOME_REGISTRATION) { + + if (entry->type & HOME_BCACHE_MASK) { if (mipv6_proxy_nd_rem(&entry->home_addr, entry->ifindex, entry->prefix, @@ -192,6 +200,7 @@ static __inline__ void del_proxy(struct in6_addr *home_addr, struct mipv6_bcache_entry *entry) { + DEBUG_FUNC(); bcache_proxy_nd_rem(entry); mipv6_del_tnl_to_mn(&entry->coa, &entry->our_addr, home_addr); } @@ -223,7 +232,7 @@ hashkey.a2 = &entry->our_addr; DEBUG((DBG_INFO, "expire(): an entry expired")); - if (entry->type & HOME_REGISTRATION) { + if (entry->type & HOME_BCACHE_MASK) { del_proxy(&entry->home_addr, entry); } hashlist_delete(bcache->entries, &hashkey); @@ -231,7 +240,7 @@ entry = NULL; } else if (entry->br_callback_time != 0 && entry->br_callback_time <= now && - entry->type & !HOME_REGISTRATION) { + entry->type & !HOME_BCACHE_MASK) { if (now - entry->last_used < BCACHE_BR_SEND_THRESHOLD * HZ) { struct br_addrs *tmp; @@ -400,9 +409,9 @@ * @single: single address bit * @type: type of entry * - * Adds an entry for this @home_addr_org in the Binding Cache. If entry - * already exists, old entry is updated. @type may be %CACHE_ENTRY or - * %HOME_REGISTRATION. + * Adds an entry for this @home_addr in the Binding Cache. If entry + * already exists, old entry is updated. @type must be a valid type + * (currently %CACHE_ENTRY, %HOME_REGISTRATION, %BASIC_MAP, %EXTENDED_MAP) **/ int mipv6_bcache_add(int ifindex, struct in6_addr *our_addr, @@ -474,18 +483,18 @@ DEBUG((DBG_INFO, "mipv6_bcache_add: updating an " "existing entry")); update = 1; - create_tunnel = (type == HOME_REGISTRATION && - (entry->type != HOME_REGISTRATION || + create_tunnel = ((type & HOME_BCACHE_MASK) && + (!(entry->type & HOME_BCACHE_MASK) || ipv6_addr_cmp(&entry->coa, coa) || entry->ifindex != ifindex || entry->prefix != prefix || entry->single != single)); - if (entry->type == HOME_REGISTRATION) { + if (entry->type & HOME_BCACHE_MASK) { if (create_tunnel || - type != HOME_REGISTRATION) { + !(type & HOME_BCACHE_MASK)) { del_proxy(&entry->home_addr, entry); - } else if (type == HOME_REGISTRATION && + } else if ((type & HOME_BCACHE_MASK) && entry->single != single) { /* proxy nd for link-local address should either be added or removed */ @@ -524,7 +533,7 @@ hashlist_delete(bcache->entries, &hashkey); } - create_tunnel = (type == HOME_REGISTRATION); + create_tunnel = (type & HOME_BCACHE_MASK); } ipv6_addr_copy(&(entry->our_addr), our_addr); @@ -539,7 +548,7 @@ hashkey.a1 = &entry->home_addr; hashkey.a2 = &entry->our_addr; - if (type == HOME_REGISTRATION) { + if (type & HOME_BCACHE_MASK) { entry->router = 0; entry->single = single; if (create_tunnel && @@ -565,7 +574,7 @@ entry->callback_time = EXPIRE_INFINITE; } else { entry->callback_time = now + lifetime * HZ; - if (entry->type & HOME_REGISTRATION) + if (entry->type & HOME_BCACHE_MASK) entry->br_callback_time = 0; else entry->br_callback_time = now + @@ -634,7 +643,7 @@ DEBUG((DBG_INFO, "__mipv6_bcache_delete: No such entry")); return 0; } - if (entry->type == HOME_REGISTRATION) { + if (entry->type & HOME_BCACHE_MASK) { del_proxy(&entry->home_addr, entry); } hashlist_delete(bcache->entries, &hashkey); @@ -1038,7 +1047,7 @@ DEBUG_FUNC(); /* hashlist_delete_first(bcache->entries); */ - if (entry->type == HOME_REGISTRATION) { + if (entry->type & HOME_BCACHE_MASK) { del_proxy(&entry->home_addr, entry); } hashlist_delete(bcache->entries, &hashkey); diff -rub --exclude=CVS --exclude=ExtendedMode.txt --exclude=Makefile.test --exclude=.* --exclude=*~ --exclude=*.detail --ignore-matching-lines=$Id: mipl-0.9.3/linux/net/ipv6/mobile_ip6/bcache.h mipl-0.9.3-hmipv6/linux/net/ipv6/mobile_ip6/bcache.h --- mipl-0.9.3/linux/net/ipv6/mobile_ip6/bcache.h Mon Jul 15 16:33:27 2002 +++ mipl-0.9.3-hmipv6/linux/net/ipv6/mobile_ip6/bcache.h Tue Aug 6 10:24:03 2002 @@ -20,9 +20,13 @@ #include #include "mempool.h" -#define CACHE_ENTRY 1 /* this and HOME_REGISTRATION are the entry types */ +/* bcache entry types are now a bitmap */ +#define CACHE_ENTRY 1 #define HOME_REGISTRATION 2 -#define ANY_ENTRY 3 +#define BASIC_MAP 4 +#define EXTENDED_MAP 8 +#define VALID_TYPES 15 +#define ANY_ENTRY VALID_TYPES #define EXPIRE_INFINITE 0xffffffff diff -rub --exclude=CVS --exclude=ExtendedMode.txt --exclude=Makefile.test --exclude=.* --exclude=*~ --exclude=*.detail --ignore-matching-lines=$Id: mipl-0.9.3/linux/net/ipv6/mobile_ip6/bul.c mipl-0.9.3-hmipv6/linux/net/ipv6/mobile_ip6/bul.c --- mipl-0.9.3/linux/net/ipv6/mobile_ip6/bul.c Mon Jul 15 16:33:27 2002 +++ mipl-0.9.3-hmipv6/linux/net/ipv6/mobile_ip6/bul.c Fri Jul 19 16:40:09 2002 @@ -41,6 +41,15 @@ #define TIMERDELAY HZ/10 #define MIPV6_BUL_HASHSIZE 32 #define HOME_RESEND_EXPIRE 3600 + + + +#ifdef CONFIG_IPV6_MOBILITY_HMIPV6 +#define HOME_BUL_FLAGS (MIPV6_BU_F_HOME|MIPV6_BU_F_MAP ) +#else +#define HOME_BUL_FLAGS (MIPV6_BU_F_HOME) +#endif + struct mipv6_bul { struct hashlist *entries; struct timer_list callback_timer; @@ -56,6 +65,7 @@ int length); #endif + static void set_timer(void); static struct mipv6_bul_entry *mipv6_bul_get_entry(void) @@ -73,7 +83,7 @@ static __inline__ int del_bul_entry_tnl(struct mipv6_bul_entry *entry) { - if (entry->flags & MIPV6_BU_F_HOME) { + if (entry->flags & HOME_BUL_FLAGS) { return mipv6_del_tnl_to_ha(&entry->cn_addr, &entry->coa, &entry->home_addr); @@ -357,19 +367,27 @@ /* if an entry for this cn_addr exists (with smaller * seq than the new entry's seq), update it */ + DEBUG((DBG_DATADUMP,"bul_add: e->cn_addr %x:%x:%x:%x:%x:%x:%x:%x ",NIPV6ADDR(&entry->cn_addr))); + DEBUG((DBG_DATADUMP,"bul_add: cn_addr %x:%x:%x:%x:%x:%x:%x:%x ",NIPV6ADDR(cn_addr))); + DEBUG((DBG_DATADUMP,"bul_add: e->home_addr %x:%x:%x:%x:%x:%x:%x:%x ",NIPV6ADDR(&entry->home_addr))); + DEBUG((DBG_DATADUMP,"bul_add: home_addr %x:%x:%x:%x:%x:%x:%x:%x ",NIPV6ADDR(home_addr))); + DEBUG((DBG_DATADUMP,"bul_add: e->coa %x:%x:%x:%x:%x:%x:%x:%x ",NIPV6ADDR(&entry->coa))); + DEBUG((DBG_DATADUMP,"bul_add: coa %x:%x:%x:%x:%x:%x:%x:%x ",NIPV6ADDR(coa))); + + // if existing entry is to LCoA, then add a new tunnel to the RCoA if (MOD256GT(seq, entry->seq)) { DEBUG((DBG_INFO, "mipv6_bul_add: updating an existing entry")); update = 1; - if ((entry->flags & MIPV6_BU_F_HOME) && - (!(flags & MIPV6_BU_F_HOME) || + if ((entry->flags & HOME_BUL_FLAGS) && + (!(flags & HOME_BUL_FLAGS) || ipv6_addr_cmp(&entry->coa, coa))) { /* old tunnel no longer valid */ mipv6_del_tnl_to_ha(&entry->cn_addr, &entry->coa, &entry->home_addr); - create_tunnel = flags & MIPV6_BU_F_HOME; - } else if (!(entry->flags & MIPV6_BU_F_HOME)) { - create_tunnel = flags & MIPV6_BU_F_HOME; + create_tunnel = flags & HOME_BUL_FLAGS; + } else if (!(entry->flags & HOME_BUL_FLAGS)) { + create_tunnel = flags & HOME_BUL_FLAGS; } } else { DEBUG((DBG_INFO, "mipv6_bul_add: smaller seq than existing, not updating")); @@ -385,15 +403,19 @@ } /* First BU send happens here, save count in the entry */ entry->consecutive_sends = 1; - create_tunnel = flags & MIPV6_BU_F_HOME; + create_tunnel = flags & HOME_BUL_FLAGS; } if (!update) { ipv6_addr_copy(&(entry->cn_addr), cn_addr); ipv6_addr_copy(&(entry->home_addr), home_addr); } + DEBUG((DBG_WARNING, "mipv6_bul_add, set coa %x:%x:%x:%x:%x:%x:%x:%x " + "%x:%x:%x:%x:%x:%x:%x:%x",NIPV6ADDR(&(entry->coa)), + NIPV6ADDR(coa))); ipv6_addr_copy(&(entry->coa), coa); entry->lifetime = lifetime; + entry->advlifetime = lifetime; if (lifetime) entry->expire = jiffies + lifetime * HZ; else if (flags & MIPV6_BU_F_ACK) diff -rub --exclude=CVS --exclude=ExtendedMode.txt --exclude=Makefile.test --exclude=.* --exclude=*~ --exclude=*.detail --ignore-matching-lines=$Id: mipl-0.9.3/linux/net/ipv6/mobile_ip6/bul.h mipl-0.9.3-hmipv6/linux/net/ipv6/mobile_ip6/bul.h --- mipl-0.9.3/linux/net/ipv6/mobile_ip6/bul.h Mon Jul 15 16:33:27 2002 +++ mipl-0.9.3-hmipv6/linux/net/ipv6/mobile_ip6/bul.h Thu Jul 4 21:06:07 2002 @@ -29,6 +29,8 @@ unsigned long expire; /* expiration time of this entry (jiffies) */ __u32 lifetime; /* lifetime sent in this BU */ + __u32 refresh; /* refresh timer of this BU */ + __u32 advlifetime; /* lifetime advertised for Agent */ __u32 lastsend; /* last time when BU was sent (jiffies) */ __u32 consecutive_sends; /* Number of consecutive BU's sent */ __u8 flags; /* BU send flags */ diff -rub --exclude=CVS --exclude=ExtendedMode.txt --exclude=Makefile.test --exclude=.* --exclude=*~ --exclude=*.detail --ignore-matching-lines=$Id: mipl-0.9.3/linux/net/ipv6/mobile_ip6/dstopts.c mipl-0.9.3-hmipv6/linux/net/ipv6/mobile_ip6/dstopts.c --- mipl-0.9.3/linux/net/ipv6/mobile_ip6/dstopts.c Mon Jul 15 16:33:27 2002 +++ mipl-0.9.3-hmipv6/linux/net/ipv6/mobile_ip6/dstopts.c Wed Apr 10 13:22:40 2002 @@ -130,6 +130,9 @@ if (sinfo && sinfo->fso_flags != 0) { int so_off; __u8 so_len = 0; + + DEBUG((DBG_DATADUMP, "Subopts present")); + if (sinfo->fso_uid) { so_off = mipv6_add_unique_id(opt, new_offset, &so_len, sinfo->uid); @@ -143,6 +146,9 @@ if (sinfo->fso_alt_coa) { so_off = mipv6_add_alternate_coa(opt, new_offset, &so_len, &sinfo->alt_coa); + + DEBUG((DBG_DATADUMP, "Attempting to add Alt CoA Subopt")); + if (so_off > 0) { new_offset = so_off; } else { diff -rub --exclude=CVS --exclude=ExtendedMode.txt --exclude=Makefile.test --exclude=.* --exclude=*~ --exclude=*.detail --ignore-matching-lines=$Id: mipl-0.9.3/linux/net/ipv6/mobile_ip6/hierarchy.c mipl-0.9.3-hmipv6/linux/net/ipv6/mobile_ip6/hierarchy.c --- mipl-0.9.3/linux/net/ipv6/mobile_ip6/hierarchy.c Tue Jul 16 15:51:56 2002 +++ mipl-0.9.3-hmipv6/linux/net/ipv6/mobile_ip6/hierarchy.c Mon Jul 22 15:50:51 2002 @@ -0,0 +1,2221 @@ +/*** net/ipv6/mobile_ip6/hierarchy.c +**** $Id: hierarchy.c,v 1.9 2002/07/22 05:50:51 gdaley Exp $ +**** Copyright (C) 2001 Greg Daley and Nick 'Sharkey' Moore +**** Authors: Greg Daley +**** & Nick Sharkey Moore +**** License: GPL +**** +**** +**** This program is free software; you can redistribute it and/or +**** modify it under the terms of the GNU General Public License +**** as published by the Free Software Foundation; either version +**** of the License, or (at your option) any later version. +**** +**** See the File COPYING which comes with this distribution. +**** Full text available at http://www.gnu.org/copyleft/gpl.html +**** +**** +***/ + + +#define HIERARCHY_INITIALIZATION 1 +#define NOT_HIERARCHY_INIT 0 + + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "hierarchy.h" +#include "mn.h" +#include "dstopts.h" +#include "sendopts.h" +#include "mdetect.h" +#include "bul.h" + +#include "debug.h" +#include "map.h" +#include "rcoa.h" + + +#ifdef CONFIG_IPV6_MOBILITY_HMIPV6 + +#define MEM_ALLOC(A) kmalloc(A, GFP_ATOMIC ) +#define MEM_FREE kfree + + + /* read-only hierarchy functions */ + /* lock hierarchy for reading */ + +inline int is_empty_map_hierarchy(struct map_hierarchy *hier); +struct map *find_map(struct map_hierarchy *hier, struct in6_addr *addr, + struct map *mapinfo); +inline struct map *highest_map(struct map_hierarchy *hier, + struct map *mapinfo); +inline struct map *nearest_map(struct map_hierarchy *hier, + struct map *mapinfo); + + /* writing hierarchy functions */ + /* lock hierarchy for writing */ + +int init_map_hierarchy(struct map_hierarchy *hier); +int destroy_map_hierarchy(struct map_hierarchy *hier); + +struct map *install_map(struct map_hierarchy *hier, struct map *tmp_map); +int uninstall_map(struct map_hierarchy *hier, struct map *tmp_map); +struct map *update_map(struct map_hierarchy *hier, struct map *tmp_map); + + + +struct map *mipv6_map_add(int ifindex, struct map *map); +int mipv6_hierarchy_init(int ifindex); +int mipv6_map_delete(int ifindex, struct map *map); +int mipv6_hierarchy_destroy(int ifindex); + +int mipv6_set_old_map(int ifindex); + +struct map *mipv6_get_old_map(int ifindex, struct map *tmp_map); +struct map *mipv6_highest_map(int ifindex, struct map *tmp_map); + +extern void destroy_map(struct map *dead_map); +extern int dump_map(struct map *map); +extern struct map *clone_map(struct map *tmp_map); + + +/** + * default_hierarchy: + * Currently only one hierarchy is supported. Partitions so that + * hierarchies are grouped by ifindex are expected in the future. + * + * The default hierarchy is selected with calls using + * ifindex -1; + */ + +static struct map_hierarchy default_hierarchy; + + + +/** + * is_empty_map_list + * + * returns + * 1 : map_list top contains entries + * 0 : map_list top contains no entries + * -1 : (error) top is NULL; + * + * TODO: use kernel lists? + */ + +static inline int is_empty_map_list(struct map_list *top) +{ + return (top) ? (top->next == top->next->next) : (-1); +} + + + +/** + * is_empty_map_hierarchy + * returns + * 1 : map_hierarchy hier contains entries + * 0 : map_hierarchy hier contains no entries + * -1 : (error) hier or hier->top is NULL; + * relies on: + * is_empty_map_list + * + * TODO: use kernel lists? + */ + +inline int is_empty_map_hierarchy(struct map_hierarchy *hier) +{ + int ret; + + DEBUG_FUNC(); + + if (!hier) + return -1; + + read_lock_bh(&(hier->lock)); + DEBUG((DBG_DATADUMP, "hierarchy read lock")); + + ret = is_empty_map_list(hier->map_top); + read_unlock_bh(&(hier->lock)); + DEBUG((DBG_DATADUMP, "hierarchy read unlock")); + + return ret; +} + + + +/** + * form_rcoa: + * + * Arguments: RCoA (out), LCoA(in), MAPPrefix (in) + * + * copies data from the LCoA and MAPPrefix structures into + * the RCoA + * + * Notes: Assumes all pointers point ot valid struct in6_addr's + * + * Returns: Pointer to RCoA + */ + +inline struct in6_addr *form_rcoa(struct in6_addr *RCoA, struct in6_addr *LCoA, + struct in6_addr *MAPPrefix) +{ + RCoA->s6_addr32[0] = MAPPrefix->s6_addr32[0]; + RCoA->s6_addr32[1] = MAPPrefix->s6_addr32[1]; + RCoA->s6_addr32[2] = LCoA->s6_addr32[2]; + RCoA->s6_addr32[3] = LCoA->s6_addr32[3]; + + DEBUG((DBG_DATADUMP, + "MAPP: %x:%x:%x:%x:%x:%x:%x:%x", NIPV6ADDR(MAPPrefix))); + DEBUG((DBG_DATADUMP, + "LCoA: %x:%x:%x:%x:%x:%x:%x:%x", NIPV6ADDR(LCoA))); + DEBUG((DBG_DATADUMP, + "RCoA: %x:%x:%x:%x:%x:%x:%x:%x", NIPV6ADDR(RCoA))); + return RCoA; +} + + + +/** + * new_map_list: + * + * create new list for map hierarchy. + * + * TODO: use kernel lists? + * + */ + +static struct map_list *new_map_list(struct map *tmp_map, int init) +{ + struct map_list *tmp_map_list; + struct map *map; + + DEBUG_FUNC(); + + if (tmp_map) { /* check if not NULL */ + if (!(map = clone_map(tmp_map))) { + DEBUG((DBG_ERROR, + "Unable to create map in new_map_list\n")); + return NULL; + } + } else if (!(init == HIERARCHY_INITIALIZATION)) { + DEBUG((DBG_WARNING, + "Not hierarchy initialization and NULL tmp_map\n")); + return NULL; + } else { /* initializing the hierarchy NULL map OK */ + map = tmp_map; /* == NULL */ + } + + if ((tmp_map_list = (struct map_list *) + MEM_ALLOC(sizeof(struct map_list))) == NULL) { + DEBUG((DBG_INFO, + "Unable to create map hierarchy list entry\n")); + return NULL; + } + /* Create end-of-list loops */ + tmp_map_list->prev = tmp_map_list; + tmp_map_list->next = tmp_map_list; + + tmp_map_list->map = map; + + return tmp_map_list; +} + + + +/** + * destroy_map_list + * + * Releases the resources associated with + * a map list which is no longer in the hierarchy. + * + * Makes sure that the maps are removed and destroyed. + * + * TODO: use kernel lists? + * + */ + +static void destroy_map_list(struct map_list *dead_map_list) +{ + + DEBUG_FUNC(); + + /* isolate effects to this node ?? */ + dead_map_list->next = NULL; + dead_map_list->prev = NULL; + + /* destroy the map */ + if (dead_map_list->map) + destroy_map(dead_map_list->map); + + /* clean up pointers */ + + dead_map_list->map = NULL; + + + MEM_FREE(dead_map_list); + + /* please remember to set pointer */ + /* to NULL on return */ +} + + + +/** + * insert_map_list: + * + * Inserts an initialised priority list entry (new_entry) + * in the appropriate place in the hierarchy. + * + * TODO: use kernel lists? + * + */ + +static struct map_list *insert_map_list(struct map_list *head, + struct map_list *new_entry) +{ + struct map_list *curr_entry; + + DEBUG_FUNC(); + + curr_entry = head; + + /* distance: high is good, goes to front of list */ + /* preference: low is good, goes to front of list */ + /* for that distance */ + + while (curr_entry->next->next != curr_entry->next) { + + if (curr_entry->next->map->distance <= + new_entry->map->distance) { + + /* map distance is better than next */ + if (curr_entry->next->map->distance < + new_entry->map->distance) + break; + + /* map preference is better than next */ + if (curr_entry->next->map->preference > + new_entry->map->preference) + break; + } + + curr_entry = curr_entry->next; + } + + new_entry->prev = curr_entry; + new_entry->next = curr_entry->next; + + curr_entry->next->prev = new_entry; + curr_entry->next = new_entry; + + return new_entry; +} + + + +/** + * remove_map_list + * + * Removes the (non-boundary marker ) + * map_list entry + * + * Assumes: doomed_entry is part of list. + * + * returns: + * NULL : Error, NULL args or empty list + * doomed_entry: removed entry (neighbours point to self); + * + * TODO use kernel lists? + * + */ + +static struct map_list *remove_map_list(struct map_list *head, + struct map_list *doomed_entry) +{ + DEBUG_FUNC(); + + if (!(head && doomed_entry)) { + DEBUG((DBG_ERROR, "NULL parameter in remove_map_list")); + return NULL; + } + + if (head->next->next == head->next) { + DEBUG((DBG_WARNING, + "Removal from empty list in remove_map_list")); + return NULL; + } + + doomed_entry->next->prev = doomed_entry->prev; + doomed_entry->prev->next = doomed_entry->next; + + doomed_entry->next = doomed_entry; + doomed_entry->prev = doomed_entry; + + return doomed_entry; + +} + + + +/** + * depopulate_map_list + * + * Iterates along the map_list, removing and releasing + * resources within each entry. + * + * Makes sure that the map_list entries are removed and + * destroyed. + * + * after completion, list is empty, with: + * head->next == tail && tail->prev ==head + * + * returns + * 1 : successful depopulation (all resources deleted) + * -1 : (error) head/tail NULL/unable to remove list entries; + * + * TODO: use kernel lists? + * + */ + +static int depopulate_map_list(struct map_list *head, + struct map_list *tail) +{ + struct map_list *tmp_map_list; + int retval; + + DEBUG_FUNC(); + + + if (!(head && tail)) { + DEBUG((DBG_ERROR, + "NULL parameter in depopulate_map_list")); + retval = -1; + } + retval = 1; + + while (head->next != tail) { + tmp_map_list = head->next; + if (!remove_map_list(head, tmp_map_list)) { + /* unable to remove map_list entry */ + /* Warn and continue (POSSIBLE MEMORY LEAK) */ + DEBUG((DBG_INFO, + "Unable to remove map priority list entry")); + retval = -1; + } + destroy_map_list(tmp_map_list); + } + tmp_map_list = NULL; + + return retval; +} + + + +/** + * find_map_list + * + * Iterates along the map_list, until it can find the map. + * + * returns: + * : pointer to map list entry + * : NULL + * + * TODO: Use kernel lists? + * + */ + +static struct map_list *find_map_list(struct map_list *head, + struct in6_addr *addr) +{ + struct map_list *cur_map_list; + + DEBUG_FUNC(); + cur_map_list = head; + + while (cur_map_list->next != cur_map_list->next->next) { + if (!ipv6_addr_cmp + (addr, &(cur_map_list->next->map->globaladdr))) { + return cur_map_list->next; + } + cur_map_list = cur_map_list->next; + } + return NULL; +} + + + +/** + * + * find_map: + * + * searches the hierarchy until it can find the map + * + * returns: + * : pointer to map list entry + * : NULL (entry doesn't exist) + * + * + */ + +struct map *find_map(struct map_hierarchy *hier, struct in6_addr *addr, + struct map *mapinfo) +{ + struct map_list *tmp_map_list; + + DEBUG_FUNC(); + + if (!(addr && hier && mapinfo)) + return NULL; + + read_lock_bh(&(hier->lock)); + DEBUG((DBG_DATADUMP, "hierarchy read lock")); + + if ((tmp_map_list = find_map_list(hier->map_top, addr))) { + copy_map(mapinfo, tmp_map_list->map); + } + read_unlock_bh(&(hier->lock)); + DEBUG((DBG_DATADUMP, "hierarchy read unlock")); + + return (tmp_map_list? tmp_map_list->map : NULL ); +} + + + +/** + * update_map_in_list + * + * Modifies an existing map in the hierarchy. + * it is idempotent.. + * + * If the parameters change, this may affect the + * hierarchy position + * + * TODO use kernel lists? + * + */ + +static struct map_list *update_map_in_list(struct map_list *head, + struct map_list *tmp_map_list, + struct map *tmp_map) +{ + + + DEBUG_FUNC(); + + + if (!(head && tmp_map && tmp_map_list)) { + DEBUG((DBG_ERROR, "NULL parameter in update_map_in_list")); + return NULL; + } + + if ((tmp_map->distance == tmp_map_list->map->distance) && + (tmp_map->preference == tmp_map_list->map->preference)) { + + DEBUG((DBG_DATADUMP, "map update with same metrics")); + } else { + /*better remove and re-instert, since metrics may */ + /* change hierarchy position */ + + if (!remove_map_list(head, tmp_map_list)) { + DEBUG((DBG_WARNING, "list removal failed")); + return NULL; + } + + tmp_map_list->map->distance = tmp_map->distance; + tmp_map_list->map->preference = tmp_map->preference; + + DEBUG((DBG_INFO, "about to reinsert MAP entry")); + insert_map_list(head, tmp_map_list); + } + + if (tmp_map->lifetime > tmp_map_list->map->lifetime) + tmp_map_list->map->lifetime = tmp_map->lifetime; + + if (tmp_map->interval) + tmp_map_list->map->interval = tmp_map->interval; + + if (tmp_map->lastupdate > tmp_map_list->map->lastupdate) { + DEBUG((DBG_INFO, "updating last update timer")); + tmp_map_list->map->lastupdate = tmp_map->lastupdate; + + } + return tmp_map_list; +} + + + +/** + * install_map_in_list + * + * Iterates along the map_list, until it can insert the map + * + * TODO use kernel lists? + * + */ + +static struct map_list *install_map_in_list(struct map_list *head, + struct map *tmp_map) +{ + struct map_list *tmp_map_list; + + DEBUG_FUNC(); + + if (!(head && tmp_map)) { + DEBUG((DBG_ERROR, + "NULL parameter in install_map_in_list")); + return NULL; + } + + if ((tmp_map_list = find_map_list(head, &(tmp_map->globaladdr)))) { + + if (!(tmp_map_list = + update_map_in_list(head, tmp_map_list, tmp_map))) { + DEBUG((DBG_WARNING, + "unable to update map, in update_map_in_list")); + return NULL; + } + return tmp_map_list; + } + + + if (!(tmp_map_list = new_map_list(tmp_map, NOT_HIERARCHY_INIT))) { + return NULL; + } + + insert_map_list(head, tmp_map_list); + + return tmp_map_list; +} + + + +/** + * uninstall_map_from_list + * + * finds if the item exists, and destroys it. + * + * returns: + * 0 : success + * -1 : failure (map not in list/invalid args) + * + * TODO use kernel lists? + * + */ + +static int uninstall_map_from_list(struct map_list *head, + struct map *tmp_map) +{ + struct map_list *tmp_map_list; + + DEBUG_FUNC(); + + if (!(head && tmp_map)) { + DEBUG((DBG_ERROR, + "NULL parameter in uninstall_map_from_list")); + return -1; + } + + if (!(tmp_map_list = find_map_list(head, &(tmp_map->globaladdr)))) { + DEBUG((DBG_WARNING, + " MAP is unknown in list, uninstall failed")); + return -1; + + } + if (!(tmp_map_list = remove_map_list(head, tmp_map_list))) { + DEBUG((DBG_WARNING, + "Unable to update map, in uninstall_map_from_list")); + return -1; + } + destroy_map_list(tmp_map_list); + + return 0; +} + + + +/** + * + * + * install_map installs the map in the hierarchy. + * it is idempotent, in the case where a map exists, + * and has the same parameters. + * + * If the parameters change, this may affect the hierarchy position + * + * returns: tmp_map + * : NULL; + * TODO: use kernel lists? + * + */ + +struct map *install_map(struct map_hierarchy *hier, struct map *tmp_map) +{ + struct map_list *tmp_map_list; + + DEBUG_FUNC(); + + if (!(hier && tmp_map)) { + DEBUG((DBG_ERROR, "NULL parameter in install_map")); + return NULL; + } + + write_lock_bh(&(hier->lock)); + DEBUG((DBG_DATADUMP, "hierarchy write lock")); + + if (!(tmp_map_list = install_map_in_list(hier->map_top, tmp_map))) { + + write_unlock_bh(&(hier->lock)); + DEBUG((DBG_DATADUMP, "hierarchy write unlock")); + return NULL; + } + + write_unlock_bh(&(hier->lock)); + DEBUG((DBG_DATADUMP, "hierarchy write unlock")); + return tmp_map; +} + + + +/** + * uninstall_map + * + * Removes a map from the hierarchy. + * it is idempotent, in the case where a map exists, + * and has the same parameters. + * + * if the parameters change, this may affect the + * hierarchy position + * + * + * returns: + * 0 : success + * -1 : failure (map not in list/invalid args) + * + */ + +int uninstall_map(struct map_hierarchy *hier, struct map *tmp_map) +{ + int ret; + + DEBUG_FUNC(); + + if (!(hier && tmp_map)) { + DEBUG((DBG_ERROR, "NULL parameter in uninstall_map")); + return -1; + } + write_lock_bh(&(hier->lock)); + DEBUG((DBG_DATADUMP, "hierarchy write lock")); + + ret = uninstall_map_from_list(hier->map_top, tmp_map); + + write_unlock_bh(&(hier->lock)); + DEBUG((DBG_DATADUMP, "hierarchy write unlock")); + + return ret; +} + + + +/** + * update_map: + * + * Modifies an existing map in the hierarchy. + * it is idempotent.. + * + * if the parameters change, this may affect the + * hierarchy position + * + */ + +struct map *update_map(struct map_hierarchy *hier, struct map *tmp_map) +{ + struct map_list *tmp_map_list; + + + DEBUG_FUNC(); + + if (!(hier && tmp_map)) { + DEBUG((DBG_ERROR, "NULL parameter in update_map")); + return NULL; + } + + write_lock_bh(&(hier->lock)); + DEBUG((DBG_DATADUMP, "hierarchy write lock")); + + if (!(tmp_map_list = find_map_list(hier->map_top, + &(tmp_map->globaladdr)))) { + DEBUG((DBG_WARNING, "unable to update map, not in list")); + } + + if (tmp_map_list && !(tmp_map_list = + update_map_in_list(hier->map_top, tmp_map_list, tmp_map))) { + DEBUG((DBG_WARNING, + "unable to update map, in update_map_in_list")); + } + + write_unlock_bh(&(hier->lock)); + DEBUG((DBG_DATADUMP, "hierarchy write unlock")); + + return (tmp_map_list? tmp_map: NULL); +} + + + +/** + * get_hmap: + * + * retrieves the map with best metric from the hierarchy. + * + * gets the best map and copies contents into mapinfo + * + * returns: pointer to tmp_map (success) + * NULL (failure) + * + * TODO: use kernel lists? + * + */ + +static struct map *get_hmap(struct map_hierarchy *hier, + struct map *mapinfo) +{ + DEBUG_FUNC(); + + if (!(hier && mapinfo)) + return NULL; + + if (hier->map_top->next == hier->map_bottom) { + return NULL; + } + + copy_map(mapinfo, hier->map_top->next->map); + DEBUG((DBG_DATADUMP, "get_hmap:s %lx", hier->map_top->next->map)); + DEBUG((DBG_DATADUMP, "get_hmap:d %lx", mapinfo)); + + return (mapinfo); +} + + + +/** + * highest_map: + * + * retrieve the map with best metric from the hierarchy + * + * gets the best map and copies contents into mapinfo + * + * returns: pointer to tmp_map (success) + * NULL (failure) + * + */ + +inline struct map *highest_map(struct map_hierarchy *hier, + struct map *mapinfo) +{ + struct map *tmp_map; + + DEBUG_FUNC(); + + if (!(hier && mapinfo)) + return NULL; + + read_lock_bh(&(hier->lock)); + + DEBUG((DBG_DATADUMP, "hierarchy read lock")); + + tmp_map = get_hmap(hier, mapinfo); + + read_unlock_bh(&(hier->lock)); + DEBUG((DBG_DATADUMP, "hierarchy read unlock")); + + return (tmp_map); +} + + + +/** + * get_old_hmap: + * + * Retrieve the previous map from the hierarchy. + * + * returns: pointer to mapinfo (success) + * NULL (no old map) + * NULL (Hierarchy or mapinfo not initialised ) + * + */ + +static inline struct map *get_old_hmap(struct map_hierarchy *hier, + struct map *mapinfo) +{ + DEBUG_FUNC(); + + if (!(hier && mapinfo)) + return NULL; + + if (hier->old_top == NULL) { + return NULL; + } + DEBUG((DBG_DATADUMP, "get_old_hmap:s %lx", hier->old_top)); + DEBUG((DBG_DATADUMP, "get_old_hmap:d %lx", mapinfo)); + copy_map(mapinfo, hier->old_top); + + return (mapinfo); +} + + + +/** + * read_old_top_map: + * + * retrieve the previous map from the hierarchy. + * + * returns: pointer to mapinfo (success) + * NULL (no old map) + * NULL (Hierarchy or mapinfo not initialised ) + * + */ + +inline struct map *get_old_top_map(struct map_hierarchy *hier, + struct map *mapinfo) +{ + struct map *tmp_map; + DEBUG_FUNC(); + + if (!(hier && mapinfo)) + return NULL; + DEBUG((DBG_DATADUMP, "oldmap (hierarchy) read lock")); + read_lock_bh(&(hier->oldlock)); + + tmp_map = get_old_hmap(hier, mapinfo); + + read_unlock_bh(&(hier->lock)); + DEBUG((DBG_DATADUMP, "oldmap (hierarchy) read unlock")); + + return (tmp_map); +} + + + +/** + * set_old_hmap_unsafe: + * + * set_old_hmap_unsafe:set the map with best metric as current. + * + * gets the best map and copies contents into hier->old_map + * + * returns: 1 (map present) + * 0 (no map) + * -1 failure + * + */ + +static inline int set_old_hmap_unsafe(struct map_hierarchy *hier) +{ + + DEBUG_FUNC(); + + if (!hier) + return -1; + + if (hier->map_top->next == hier->map_bottom) { + if (hier->old_top) { + /* remove the old_top map if present */ + destroy_map(hier->old_top); + hier->old_top = NULL; + } + /* we already have NULL map */ + return 0; + } + if (!hier->old_top) { + /* add the old_top map if not present */ + hier->old_top = clone_map(hier->map_top->next->map); + return (hier->old_top ? 1 : -1); + } + copy_map(hier->old_top, hier->map_top->next->map); + + return 1; +} + + + +/** + * set_old_hmap: + * + * set the map with best metric as current. + * + * gets the best map and copies contents into hier->old_map + * + * returns: 1 (map present) + * 0 (no map) + * -1 failure + * + */ + +static inline int set_old_hmap(struct map_hierarchy *hier) +{ + int ret; + + DEBUG_FUNC(); + + if (!hier) + return -1; + + DEBUG((DBG_DATADUMP, "oldmap (hierarchy) write lock")); + write_lock_bh(&(hier->oldlock)); + + ret = set_old_hmap_unsafe(hier); + + write_unlock_bh(&(hier->oldlock)); + + DEBUG((DBG_DATADUMP, "oldmap (hierarchy) write unlock")); + + return ret; +} + + + +/** + * set_old_hmap_exp_unsafe: + * + * set_old_hmap_exp_unsafe:set the top map as specified in args + * + * copies map contents into hier->old_map + * + * returns: 1 (map present) + * 0 (no map) + * -1 failure + * + */ + +static inline int set_old_hmap_exp_unsafe(struct map *map, + struct map_hierarchy *hier) +{ + + DEBUG_FUNC(); + + if (!hier) + return -1; + + if (!map) { + if (hier->old_top) { + /* remove the old_top map if present */ + destroy_map(hier->old_top); + hier->old_top = NULL; + } + /* we already have NULL map */ + return 0; + } + if (!hier->old_top) { + /* add the old_top map if not present */ + hier->old_top = clone_map(map); + return (hier->old_top ? 1 : -1); + } + copy_map(hier->old_top, map); + + return 1; +} + + + +/** + * set_old_hmap_explicit: + * + * Set the top map as specified in argument + * + * gets the best map and copies contents into hier->old_map + * + * returns: 1 (map present) + * 0 (no map) + * -1 failure + * + */ + +static inline int set_old_hmap_explicit(struct map *map, + struct map_hierarchy *hier) +{ + int ret; + + DEBUG_FUNC(); + + if (!hier) + return -1; + + DEBUG((DBG_DATADUMP, "oldmap (hierarchy) write lock")); + write_lock_bh(&(hier->oldlock)); + + ret = set_old_hmap_exp_unsafe(map, hier); + + write_unlock_bh(&(hier->oldlock)); + + DEBUG((DBG_DATADUMP, "oldmap (hierarchy) write unlock")); + + return ret; +} + + + +/** + * set_old_hierarchy_map: + * + * Set the map with best metric as current. + * + * gets the best map and copies contents into hier->old_map + * + * returns: 1 (map present) + * 0 (no map) + * -1 failure + * + */ + +inline int set_old_hierarchy_map(struct map_hierarchy *hier) +{ + int ret; + DEBUG_FUNC(); + + if (!hier) + return -1; + + DEBUG((DBG_DATADUMP, "hierarchy read lock")); + read_lock_bh(&(hier->lock)); + + ret = set_old_hmap(hier); + + read_unlock_bh((&hier->lock)); + DEBUG((DBG_DATADUMP, "hierarchy read unlock")); + + return ret; +} + + + +/** + * nearest_map: + * + * reads the nearest map (lowest distance) + * off the hierarchy. + * + * + */ + +inline struct map *nearest_map(struct map_hierarchy *hier, + struct map *mapinfo) +{ + struct map *best_this_metric; + struct map_list *tmp_map_list; + + DEBUG_FUNC(); + + if (!(hier && mapinfo)) + return NULL; + + read_lock_bh(&(hier->lock)); + + if (hier->map_top->next == hier->map_bottom) { + read_unlock_bh(&(hier->lock)); + DEBUG((DBG_DATADUMP, "hierarchy read unlock")); + return NULL; + } + tmp_map_list = hier->map_top->next; + best_this_metric = tmp_map_list->map; + + while (tmp_map_list != tmp_map_list->next) { + + /* on going down a level, record the best map */ + if (tmp_map_list->map->distance < + best_this_metric->distance) { + best_this_metric = tmp_map_list->map; + } + + tmp_map_list = tmp_map_list->next; + } + copy_map(mapinfo, best_this_metric); + + read_unlock_bh(&(hier->lock)); + DEBUG((DBG_DATADUMP, "hierarchy read unlock")); + + return (best_this_metric); +} + + + +/** + * mipv6_send_basic_map_bu + * + * sends a binding update with the MAP bit set. + * + * TODO: Make sure that MAP bit remains set for Basic MAP BU. + * + */ + +void mipv6_send_basic_map_bu(struct in6_addr *RCoA, + struct in6_addr *MAPaddr, + unsigned long lifetime, + struct in6_addr *Alt_CoA) +{ + struct mipv6_subopt_info sinfo; + + DEBUG_FUNC(); + + DEBUG((DBG_INFO, + "Sending REGISTRATION to (B)MAP: %x:%x:%x:%x:%x:%x:%x:%x", + NIPV6ADDR(MAPaddr))); + DEBUG((DBG_INFO, + "Sending MAP REGISTRATION from: %x:%x:%x:%x:%x:%x:%x:%x", + NIPV6ADDR(RCoA))); + + memset(&sinfo, 0, sizeof(struct mipv6_subopt_info)); + + /* not sure if should use RCoA as Source... */ + /* relying on modify_xmit_packets,get_care_of_address */ + + if (Alt_CoA) { + DEBUG((DBG_DATADUMP, + "Sending AlternateCoA: %x:%x:%x:%x:%x:%x:%x:%x", + NIPV6ADDR(Alt_CoA))); + memcpy(&(sinfo.alt_coa), Alt_CoA, sizeof(struct in6_addr)); + sinfo.fso_alt_coa = 1; + } + mipv6_send_upd_option(RCoA, MAPaddr, MAP_BU_DELAY, + INITIAL_BINDACK_TIMEOUT, MAX_BINDACK_TIMEOUT, + 1, + MIPV6_BU_F_ACK | MIPV6_BU_F_MAP | + MIPV6_BU_F_DAD, 64, lifetime, + (Alt_CoA ? &sinfo : NULL)); +} + + + +/** + * map_event: + * + * movement manager for HMIPv6 + * determines if an intermap movement event occurs, + * + * handles intermap movements. + * + * TODO: 2 tasks -> 2 functions? + * + * TODO pass hierarchy in map_event + * + * return 0 (success) + * -1 (fail, no event processing done). + */ + +int map_event(struct map_hierarchy *hier, struct map *old, struct map *new) +{ + struct in6_addr LCoA, RCoA; + struct in6_addr home_addr; + unsigned long lifetime = 0; + + DEBUG_FUNC(); + + DEBUG((DBG_DATADUMP, "map_event:new %lx", new)); + DEBUG((DBG_DATADUMP, "map_event:old %lx", old)); + + hier = &default_hierarchy; + + memset(&LCoA, 0,sizeof(struct in6_addr)); + + if (((old && new)) && !ipv6_addr_cmp(&(new->globaladdr), + &(old->globaladdr))) { + DEBUG((DBG_INFO, "Z bindings not changed %d %d", + old->lifetime, new->lifetime)); + DEBUG((DBG_DATADUMP, + "ZZ: %x:%x:%x:%x:%x:%x:%x:%x", + NIPV6ADDR(&(new->globaladdr)))); + return 0; + } + if (!(new || old)) { + DEBUG((DBG_INFO, "Z no maps at all!")); + return 0; + } + if (mipv6_mn_get_homeaddr(&home_addr) < 0) { + DEBUG((DBG_ERROR, "cannot use HMIPv6: no Home Address!")); + return -1; + } + if (mipv6_get_care_of_address(&home_addr, &LCoA) < 0) { + return -1; + } + + DEBUG((DBG_DATADUMP, + "ZZ: HADDR= %x:%x:%x:%x:%x:%x:%x:%x", + NIPV6ADDR(&home_addr))); + DEBUG((DBG_DATADUMP, "ZZ: LCoA= %x:%x:%x:%x:%x:%x:%x:%x", + NIPV6ADDR(&LCoA))); + + if (new) { + DEBUG((DBG_DATADUMP, "ZZ: %x:%x:%x:%x:%x:%x:%x:%x", + NIPV6ADDR(&(new->globaladdr)))); + lifetime = (new->lifetime - jiffies) / (HZ); + + DEBUG((DBG_INFO, "Z changed to new MAP (lifetime %d)", + lifetime)); + /* HMIPv6 BASIC MODE */ + + form_rcoa(&RCoA, &LCoA, &(new->globaladdr)); + DEBUG((DBG_DATADUMP, + "RCoA= %x:%x:%x:%x:%x:%x:%x:%x", + NIPV6ADDR(&RCoA))); + + /* since we have new, we know that the first + entry is in the list */ + memcpy(&(hier->map_top->next->map->rcoa), + &RCoA, sizeof(struct in6_addr)); + + DEBUG((DBG_DATADUMP, + "RCoA2= %x:%x:%x:%x:%x:%x:%x:%x", + NIPV6ADDR(&(hier->map_top->next->map->rcoa)))); + + /* make sure that the other functions can use the RCoA */ + set_old_hmap(hier); + + /* install tentative listener address for RCoA */ + /* don't do DAD on this address, since we want */ + /* to receive the MAP BAck, indicating DAD success */ + + /* TODO Basic Mode ?? */ + + DEBUG((DBG_INFO, "mipv6_rcoa_add_request map_event: %d",new->ifindex)); + mipv6_rcoa_add_request(new->ifindex, &RCoA, MAX_BINDACK_TIMEOUT, + 1); + + /* send BU to new MAP HomeAddr: RCoA,CoA = LCoA */ + + mipv6_hmipv6_map_ack_required(); + mipv6_send_basic_map_bu(&RCoA, &(new->globaladdr), + lifetime, NULL); + + /* the active CoA for BU's is a RCoA from MAP */ + } else { + DEBUG((DBG_INFO, "Z Moved out of MAP cover")); + /* TODO: ensure that BU doesn't exceed lifetime */ + /* received in New MAP BAck */ + lifetime = MAP_BU_DEF_LIFETIME; + /* we have no map, and we should tell the CN's, HA and oMAP */ + bul_iterate(map_handoff, NULL); + + /* don't tell old MAP, since LCoA is Bound */ + return 0; + } + if (old) { + DEBUG((DBG_INFO, "Z send BU to old MAP")); + /* send binding update to old map */ + mipv6_send_basic_map_bu(&old->rcoa, &old->globaladdr, + lifetime, NULL); + } + return 0; +} + + + +/** + * init_map_hierarchy: + * + * called when the module is initialised for MN function. + * It creates a structure which lists the most distant + * maps as those with the highest metric in the hierarchy. + * + * MAPS with the same distance/metric are tie broken by using priorities + * + * If distance and priority match, then the first discovered of the MAPS + * appears first in the hierarchy. + * + * Returns: + * 0 : Success + * -1: Failure (unable to allocate memory for hierarchy elements) + * + */ + +int init_map_hierarchy(struct map_hierarchy *tmp_hierarchy) +{ + + DEBUG_FUNC(); + + if (!tmp_hierarchy) { + DEBUG((DBG_WARNING, + "NULL Pointer aimed at init_map_hierarchy")); + return -1; + } + + write_lock_bh(&(tmp_hierarchy->lock)); + + DEBUG((DBG_DATADUMP, "hierarchy write lock")); + + tmp_hierarchy->old_top = NULL; + + if (!(tmp_hierarchy->map_top = + new_map_list(NULL, HIERARCHY_INITIALIZATION))) { + DEBUG((DBG_WARNING, + "Unable to create map hierarchy list (top)")); + + write_unlock_bh(&(tmp_hierarchy->lock)); + DEBUG((DBG_DATADUMP, "hierarchy write unlock")); + return -1; + } + + if (!(tmp_hierarchy->map_bottom = + new_map_list(NULL, HIERARCHY_INITIALIZATION))) { + DEBUG((DBG_WARNING, + "Unable to create map hierarchy list (bottom)")); + + write_unlock_bh(&(tmp_hierarchy->lock)); + DEBUG((DBG_DATADUMP, "hierarchy write unlock")); + return -1; + } + + /* Create end-of-list loops */ + tmp_hierarchy->map_top->prev = tmp_hierarchy->map_top; + tmp_hierarchy->map_bottom->next = tmp_hierarchy->map_bottom; + + /* set the metric list to be empty */ + + /* next of start == end of list */ + tmp_hierarchy->map_top->next = tmp_hierarchy->map_bottom; + /* previous of end == start of list */ + tmp_hierarchy->map_bottom->prev = tmp_hierarchy->map_top; + + tmp_hierarchy->refcount = 0; + + write_unlock_bh(&(tmp_hierarchy->lock)); + DEBUG((DBG_DATADUMP, "hierarchy write unlock")); + + DEBUG((DBG_INFO, "Starting GC")); + map_hierarchy_gc_init(tmp_hierarchy); + DEBUG((DBG_INFO, "Started GC")); + + return 0; +} + + + +/** + * destroy_map_hierarchy + * + * Is called when the module is removed in MN function. + * + * Releases the resources associated with the MAP + * hierarchy + * + * returns + * 1 : successful destruction (all resources deleted) + * -1 : (error) head/tail NULL/unable to remove list entries; + * + */ + +int destroy_map_hierarchy(struct map_hierarchy *hier) +{ + + DEBUG_FUNC(); + + if (!(hier)) { + DEBUG((DBG_INFO, + "NULL Pointer aimed at destroy_map_hierarchy")); + return -1; + } + + DEBUG((DBG_INFO, "Destroying GC")); + map_hierarchy_gc_destroy(hier); + DEBUG((DBG_INFO, "Destroyed GC")); + + write_lock_bh(&(hier->lock)); + + DEBUG((DBG_DATADUMP, "hierarchy write lock")); + if (!(hier->map_top && hier->map_bottom)) { + DEBUG((DBG_INFO, + "Unable to free all MAP Hierarchy resources")); + + write_unlock_bh(&(hier->lock)); + DEBUG((DBG_DATADUMP, "hierarchy write unlock")); + return -1; + } + + /* recursively remove list elements */ + if (depopulate_map_list(hier->map_top, hier->map_bottom) < 0) { + DEBUG((DBG_INFO, + "Unable to free all MAP Hierarchy resources (depop)")); + write_unlock_bh(&(hier->lock)); + DEBUG((DBG_DATADUMP, "hierarchy write unlock")); + return -1; + } + /* destroy head and tail elements */ + destroy_map_list(hier->map_top); + destroy_map_list(hier->map_bottom); + + /* destroy old_map entry */ + if (hier->old_top) { + destroy_map(hier->old_top); + } + /* clean up pointers */ + hier->map_top = NULL; + hier->map_bottom = NULL; + + write_unlock_bh(&(hier->lock)); + DEBUG((DBG_DATADUMP, "hierarchy write unlock")); + return 1; +} + + + +/** + * map_hierarchy_gc_init: + * + * For the moment, we only support a single Hierarchy, + * which is stored in hier. + * + * Garbage collection is via the timer GC_Timer. + * + * TODO: Support for multiple hierarchies to allow multi-homed + * mobile hosts. At the moment, each hierarchy has it's + * own timer, which seems inefficient. + * + * TODO: When initializing multiple hierarchies, check + * existence of GC_Timer + * + * TODO: Generalized the locked list routines into a + * lockedlist class. Not that any of the other + * kernel hackers have done this. + * + */ + +void map_hierarchy_gc_init(struct map_hierarchy *hier) +{ + + DEBUG_FUNC(); + + hier->gc_timer.function = map_hierarchy_gc_callback; + hier->gc_timer.expires = jiffies + HZ; + hier->gc_timer.data = (unsigned long) hier; + + add_timer(&(hier->gc_timer)); +} + + + +/** + * map_hierarchy_gc_destroy: + * + * destroys the gc system for a Hierarchy + * removes GC Timers + * + * TODO: Multiple hierarchies based on same GC timer. + * Use Ref counter to determine end of timer. + * + */ + +void map_hierarchy_gc_destroy(struct map_hierarchy *hier) +{ + + DEBUG_FUNC(); + +#ifdef CONFIG_SMP + del_timer(&(hier->gc_timer)); +#else + del_timer_sync(&(hier->gc_timer)); +#endif + hier->gc_timer.function = NULL; + hier->gc_timer.data = 0; + +} + + + +/** + * + * map_hierarchy_gc_callback: + * + * clears out expired MAP entries, sends BU's + * Adds timer for callback + * + * TODO: multiple hierarchies based on same GC timer. + * + */ + +void map_hierarchy_gc_callback(unsigned long data) +{ + struct map_hierarchy *hier = (struct map_hierarchy *) data; + + unsigned long next_gc_time; + struct map old_hmap; + struct map new_hmap; + struct map_list *me, *me_next; + struct map *old_map_ptr = NULL; + struct map *new_map_ptr = NULL; + + DEBUG_FUNC(); + + /* set the maximum time between GC runs */ + /* TODO: this should be a config variable somewhere */ + + next_gc_time = jiffies + MAX_HIER_GC_CALLBACK_WAIT; + + DEBUG((DBG_DATADUMP, "X gc started %u next_gc_time %u (max)", + jiffies, next_gc_time)); + + write_lock_bh(&(hier->lock)); + + /* get the first element of the list */ + me = hier->map_top->next; + + /* check old map state */ + if ((old_map_ptr = get_old_top_map(hier, &old_hmap)) != NULL) { + DEBUG((DBG_DATADUMP, "X copying old top map")); + DEBUG((DBG_DATADUMP, "XX: %x:%x:%x:%x:%x:%x:%x:%x", + NIPV6ADDR(&(old_hmap.globaladdr)))); + } + + DEBUG((DBG_DATADUMP, "old_map_ptr: %lx", old_map_ptr)); + DEBUG((DBG_DATADUMP, "old_map_addr %lx", &old_hmap)); + + /* me_next minds the value of me->next while we destroy me */ + + while ((me_next = me->next) != me) { + + DEBUG((DBG_DATADUMP, "Y Considering entry")); + if (me->map) { + DEBUG((DBG_DATADUMP, "YY: %x:%x:%x:%x:%x:%x:%x:%x", + NIPV6ADDR(&(me->map->globaladdr)))); + DEBUG((DBG_DATADUMP, "current jiffies: %lu", + jiffies)); + DEBUG((DBG_DATADUMP, "current map lifetime: %lu", + map_expiry(me->map))); + } + + if (time_after(jiffies, map_expiry(me->map))) { + + DEBUG((DBG_INFO, "Y Removing entry")); + + /* patch around this map_list */ + + me->prev->next = me_next; + me_next->prev = me->prev; + + destroy_map_list(me); + + } else { + /* if we _haven't_ gotten rid of this record, + consider it for the next round */ + + if (time_before(map_expiry(me->map), next_gc_time)) { + next_gc_time = map_expiry(me->map); + DEBUG((DBG_DATADUMP, + "Y Next GC time down to %u", + next_gc_time)); + } + DEBUG((DBG_DATADUMP, "Y Won't expire until %u", + map_expiry(me->map))); + } + me = me_next; + } + + /* get new top map */ + if ((new_map_ptr = get_hmap(hier, &new_hmap)) != NULL) { + DEBUG((DBG_DATADUMP, "X Copying new top map")); + DEBUG((DBG_DATADUMP, "XX: %x:%x:%x:%x:%x:%x:%x:%x", + NIPV6ADDR(&(new_hmap.globaladdr)))); + } + + DEBUG((DBG_DATADUMP, "new_map_ptr %lx", new_map_ptr)); + DEBUG((DBG_DATADUMP, "new_map_addr %lx", &new_hmap)); + + /* set the state for the next time round */ + + set_old_hmap(hier); + + /* send out binding updates ... okay so it looks stupid but at least + it is clear */ + + if (map_event(hier, old_map_ptr, new_map_ptr) < 0) { + DEBUG((DBG_INFO, "MAP_EVENT FAILED !! may lose movement")); + set_old_hmap_explicit(old_map_ptr, hier); + if (time_before(jiffies + HZ, next_gc_time)) { + next_gc_time = jiffies + HZ; + } + } + + /* schedule us back in for the next round */ + /* TODO: Consider case where timer has already expired */ + + + write_unlock_bh(&(hier->lock)); +#if 0 + gc_resched: +#endif + DEBUG((DBG_INFO, "at %u rescheduling for %u", jiffies, + next_gc_time + 1)); + + mod_timer(&(hier->gc_timer), next_gc_time + 1); +} + + + +/** + * mipv6_map_add: + * + * entry function from outside module + * + * adds a map to the interface's hierarchy + * + * TODO: multiple hierarchies based on AS specification for IFace. + * + * TODO: use ifindex to determine map_hierarchy + */ + +struct map *mipv6_map_add(int ifindex, struct map *map) +{ + struct map *tmp_map; + DEBUG_FUNC(); + + if (!map) { + DEBUG((DBG_WARNING, "invalid map in mipv6_map_add\n")); + return NULL; + } + + /* NO Specialised hierarchies found, use default */ + + tmp_map = install_map(&default_hierarchy, map); + + return tmp_map; +} + + + +/** + * mipv6_get_old_map: + * + * entry function from outside module + * + * reads the old map from the hierarchy for map movement detection + * + * TODO: multiple hierarchies based on AS specification for IFace. + * + */ + +struct map *mipv6_get_old_map(int ifindex, struct map *map) +{ + struct map *tmp_map; + DEBUG_FUNC(); + + /* Ignoring ifindex, uses default_hierarchy */ + + if (!map) { + DEBUG((DBG_WARNING, + "invalid map in mipv6_get_best_map\n")); + return NULL; + } + tmp_map = get_old_top_map(&default_hierarchy, map); + + if (tmp_map) { + DEBUG((DBG_DATADUMP, + "old map: %x:%x:%x:%x:%x:%x:%x:%x", + NIPV6ADDR(&(map->globaladdr)))); + } else { + DEBUG((DBG_DATADUMP, "old map: NULL")); + } + return tmp_map; +} + + + +/** + * mipv6_set_old_map: + * + * entry function from outside module + * + * saves the top map information into the hierarchy's + * old_map to aid map movement detection + * + * TODO: multiple hierarchies based on AS specification for IFace. + * + * TODO THIS modification is single shot. + * if the map comparison is done after 2 set_old_maps, the + * there is the possibility that the changed map information + * will be lost :- need to put into list or need to check trigger?? + * + */ + +int mipv6_set_old_map(int ifindex) +{ + int ret; + DEBUG_FUNC(); + + /* Ignoring ifindex, uses default_hierarchy */ + + ret = set_old_hierarchy_map(&default_hierarchy); + return ret; +} + + + +/** + * mipv6_hierarchy_init: + * + * entry function from outside module + * + * initialises the HMIPv6 MAP hierarchy for this interface. + * + * input (-1) (invalid interface) indicates that the default + * hierarchy is to be initialised. + * + * All other inputs will be ignored (Until TODO: multi hier complete) + * + * this is the minimum which must be called to initialse HMIPv6 MN + * + * + * outputs: + * -1: Hierarchy initialization failure + * else: success (0). + * + * + * TODO: multiple hierarchies based on AS specification for IFace. + * if multiple hierachies match IFaces' AS nums, do not recreate + * + */ + +int mipv6_hierarchy_init(int ifindex) +{ + int ret; + + DEBUG_FUNC(); + + ret = 0; + + /* TODO: use ifindex to determine map_hierarchy */ + + if (ifindex < 0) { + /* Default hierarchy */ + ret = init_map_hierarchy(&default_hierarchy); + } + + /* + else{ + * find hierarchy first * + if(!hierarchy){ + hierarchy = (struct map_hierarchy *) + MEM_ALLOC (sizeof(struct map_hierarchy)); + ret = init_map_hierarchy(hierarchy); + } + if(ret >= 0) hierarchy->refcount++; + + } + */ + + return ret; +} + + + +/** + * mipv6_map_delete: + * + * entry function from outside module + * + * deletes a map from the interface's hierarchy + * + * TODO: multiple hierarchies based on AS specification for IFace. + * + */ + +int mipv6_map_delete(int ifindex, struct map *map) +{ + int ret; + + DEBUG_FUNC(); + + if (!map) { + DEBUG((DBG_WARNING, "invalid map in mipv6_map_delete\n")); + return -1; + } + + /* TODO: use ifindex to determine map_hierarchy */ + + /* NO Specialised hierarchies found, use default */ + ret = uninstall_map(&default_hierarchy, map); + + return ret; +} + + + +/** + * mipv6_hierarchy_destroy: + * + * entry function from outside module + * + * deletes an interface's reference to the hierarchy. + * when all references are removed, delete hierarchy. + * + * please note that this is + * + * TODO: multiple hierarchies based on AS specification for IFace. + * + */ + +int mipv6_hierarchy_destroy(int ifindex) +{ + int ret; + DEBUG_FUNC(); + + ret = -1; + + /* TODO: use ifindex to determine map_hierarchy */ + + if (ifindex < 0) { + /* Default hierarchy */ + ret = destroy_map_hierarchy(&default_hierarchy); + } + + /* + else{ + * find hierarchy first * + hierarchy->refcount--; + if( hierarchy->refcount == 0){ + ret = destroy_map_hierarchy(hierarchy); + MEM_FREE(hierarchy); + } + } + */ + + return ret; +} + + + +/** + * mipv6_highest_map: + * + * entry function from outside module + * + * gets the best map and copies contents into tmp_map + * + * returns: pointer to tmp_map (success) + * NULL (failure) + * + * please note that this is currently assumes one hierarchy. + * + * TODO: multiple hierarchies based on AS specification for IFace. + * + */ + +struct map *mipv6_highest_map(int ifindex, struct map *tmp_map) +{ + int tmp; + DEBUG_FUNC(); + + /* TODO: use ifindex to determine map_hierarchy */ + + /* currently use Default hierarchy, ignore ifindex */ + tmp = ifindex; + + if (highest_map(&default_hierarchy, tmp_map)) { + DEBUG((DBG_DATADUMP, + "highest map: %x:%x:%x:%x:%x:%x:%x:%x", + NIPV6ADDR(&(tmp_map->globaladdr)))); + return tmp_map; + } + + DEBUG((DBG_DATADUMP, "highest map: NULL")); + return NULL; +} + + + +/** + * mipv6_hmipv6_is_rcoa: + * + * compares address with current RCoA + * + * returns:1 is same as current RCoA + * 0 error, no address, + * 0 no current map + * 0 different address to rcoa + * + * TODO: use correct map hierarchy for ifindex + */ + +int mipv6_hmipv6_is_rcoa( struct in6_addr *addr) +{ + struct map tmpmap; + DEBUG_FUNC(); + /* currently use Default hierarchy */ + if (!addr) + return 0; + + if (get_old_top_map(&default_hierarchy, &tmpmap)) { + return !(ipv6_addr_cmp(addr, &tmpmap.rcoa)); + } + + DEBUG((DBG_DATADUMP, "no current map: no rcoa")); + return 0; +} + + + +/** + * mipv6_hmipv6_get_rcoa: + * + * retrieves the rcoa for the current destination + * + * returns:NULL (error, no address) + * NULL (no MAP) + * RCoA in addr. + * + * TODO: use correct map hierarchy for destination/ifindex + */ + +struct in6_addr *mipv6_hmipv6_get_rcoa(struct in6_addr *dest, + struct in6_addr *addr) +{ + struct map tmpmap; + DEBUG_FUNC(); + /* currently use Default hierarchy */ + + if (!addr) + return NULL; + + if (get_old_top_map(&default_hierarchy, &tmpmap)) { + if (!ipv6_addr_cmp(&tmpmap.globaladdr, dest)) { + DEBUG((DBG_DATADUMP, + "this is current map: no RCOA")); + return NULL; + } + ipv6_addr_copy(addr, &tmpmap.rcoa); + + return addr; + } + + DEBUG((DBG_DATADUMP, "no current map: no rcoa")); + return NULL; + +} + + + +/** + * mipv6_hmipv6_map_ack_required: + * + * set state requiring a MAP ack. + * + * occurs on inter map movement + * + * TODO: set up for individual hierarchies. + * + */ + +void mipv6_hmipv6_map_ack_required(void) +{ + struct map_hierarchy *hier = &default_hierarchy; + + DEBUG_FUNC(); + + DEBUG((DBG_DATADUMP, "oldmap (hierarchy) write lock")); + write_lock_bh(&(hier->oldlock)); + + hier->ackstate |= MAP_ACK_STATE_REQUIRED; + + write_unlock_bh(&(hier->oldlock)); + + DEBUG((DBG_DATADUMP, "oldmap (hierarchy) write unlock")); +} + + + +/** + * mipv6_hmipv6_map_ack_refresh: + * + * occurs on map refresh + * + * TODO: set up for individual hierarchies. + * + */ + +void mipv6_hmipv6_map_ack_refresh(void) +{ + struct map_hierarchy *hier = &default_hierarchy; + + DEBUG_FUNC(); + + DEBUG((DBG_DATADUMP, "oldmap (hierarchy) write lock")); + write_lock_bh(&(hier->oldlock)); + + hier->ackstate |= MAP_ACK_STATE_REFRESH; + + write_unlock_bh(&(hier->oldlock)); + + DEBUG((DBG_DATADUMP, "oldmap (hierarchy) write unlock")); +} + + + +/** + * mipv6_hmipv6_map_ack_reset: + * + * occurs on reception of a MAP BU Ack + * indicates ack has been processed + * + * TODO: set up for individual hierarchies. + * + */ + +void mipv6_hmipv6_map_ack_reset(void) +{ + struct map_hierarchy *hier = &default_hierarchy; + + DEBUG_FUNC(); + + DEBUG((DBG_DATADUMP, "oldmap (hierarchy) write lock")); + write_lock_bh(&(hier->oldlock)); + + hier->ackstate = MAP_ACK_STATE_RESET; + + write_unlock_bh(&(hier->oldlock)); + + DEBUG((DBG_DATADUMP, "oldmap (hierarchy) write unlock")); +} + + + +/** + * mipv6_hmipv6_map_ack_state: + * + * retrieve map BU Ack processing state. + * used to determine if refresh timers are to be reset, or + * BU's are sent to HA's and CN's + * + * TODO: set up for individual hierarchies. + * + */ + +int mipv6_hmipv6_map_ack_state(void) +{ + int ret; + struct map_hierarchy *hier = &default_hierarchy; + + DEBUG_FUNC(); + + DEBUG((DBG_DATADUMP, "oldmap (hierarchy) write lock")); + write_lock_bh(&(hier->oldlock)); + + ret = hier->ackstate; + + write_unlock_bh(&(hier->oldlock)); + + DEBUG((DBG_DATADUMP, "oldmap (hierarchy) write unlock")); + + DEBUG((DBG_DATADUMP, "mipv6_hmipv6_map_ack_state", ret)); + return ret; +} + + + +/** + * mipv6_hmipv6_map_bulifetime + * + * returns map bu lifetime in seconds from now. + */ + +__u32 mipv6_hmipv6_map_bulifetime(int ifindex){ + __u32 lifetime; + struct map map; + struct mipv6_bul_entry *mapentry; + DEBUG_FUNC(); + + if(mipv6_get_old_map(ifindex, &map)<0){ + return 0; + } + if(!(mapentry=mipv6_bul_get(&map.globaladdr,&map.rcoa))){ + return 0; + } + lifetime = (mapentry->expire -jiffies) /HZ; + + mipv6_bul_put(mapentry); + + return lifetime; + } + +/** + * map_handoff - called for every bul entry to send BU to CN (except MAP) + * @rawentry: bul entry + * @args: handoff event + * @sortkey: + * + * Since MN can have many home addresses and home networks, every BUL + * entry needs to be checked + ** + */ + +int map_handoff(void *rawentry, void *args, unsigned long *sortkey) +{ + int state =MAP_ACK_STATE_RESET; + struct mipv6_bul_entry *entry = + (struct mipv6_bul_entry *) rawentry; + struct map_handoff_entry *ho_entry = (void *)args; + struct mipv6_bul_entry *mapentry = NULL; + + if(ho_entry) { + DEBUG((DBG_DATADUMP, "map_handoff: refresh state %d", + ho_entry->state)); + mapentry = ho_entry->mapentry; + state = ho_entry->state; + } + + if((state == MAP_ACK_STATE_REFRESH ) && + (entry->expire == entry->callback_time)){ + DEBUG((DBG_DATADUMP, "map_handoff: refresh not required %lu ", + entry->expire)); + return ITERATOR_CONT; + } + + if (entry->flags & MIPV6_BU_F_MAP) /* map entry */ + return ITERATOR_CONT; + + entry->lifetime = mipv6_mn_get_bulifetime(&entry->home_addr, + &entry->coa, + entry->flags); + + if (mapentry) + DEBUG((DBG_DATADUMP, + "map_handoff: e: %u m:%u %x:%x:%x:%x:%x:%x:%x:%x", + entry->lifetime, mapentry->lifetime, + NIPV6ADDR(&entry->cn_addr))); + + if (mapentry && entry->lifetime > mapentry->lifetime) + entry->lifetime = mapentry->lifetime; + + if (entry->flags & (MIPV6_BU_F_HOME | MIPV6_BU_F_MAP)) { + DEBUG((DBG_INFO, "Sending home registration for " + "home address: %x:%x:%x:%x:%x:%x:%x:%x\n" + "to home agent %x:%x:%x:%x:%x:%x:%x:%x, " + "with lifetime %ld, prefixlength %d", + NIPV6ADDR(&entry->home_addr), + NIPV6ADDR(&entry->cn_addr), entry->lifetime, + entry->prefix)); + mipv6_send_upd_option(&entry->home_addr, &entry->cn_addr, + HA_BU_DELAY, INITIAL_BINDACK_TIMEOUT, + MAX_BINDACK_TIMEOUT, 1, entry->flags, + entry->prefix, entry->lifetime, + NULL); + } else { + DEBUG((DBG_INFO, + "Sending BU for home address: %x:%x:%x:%x:%x:%x:%x:%x \n" + "to CN: %x:%x:%x:%x:%x:%x:%x:%x, " + "with lifetime %ld", NIPV6ADDR(&entry->home_addr), + NIPV6ADDR(&entry->cn_addr), entry->lifetime)); + mipv6_send_upd_option(&entry->home_addr, &entry->cn_addr, + CN_BU_DELAY, INITIAL_BINDACK_TIMEOUT, + MAX_BINDACK_TIMEOUT, 1, entry->flags, + entry->prefix, entry->lifetime, + NULL); + } + + return ITERATOR_CONT; +} + +#endif /* CONFIG_IPV6_MOBILITY_HMIPV6 */ diff -rub --exclude=CVS --exclude=ExtendedMode.txt --exclude=Makefile.test --exclude=.* --exclude=*~ --exclude=*.detail --ignore-matching-lines=$Id: mipl-0.9.3/linux/net/ipv6/mobile_ip6/hierarchy.h mipl-0.9.3-hmipv6/linux/net/ipv6/mobile_ip6/hierarchy.h --- mipl-0.9.3/linux/net/ipv6/mobile_ip6/hierarchy.h Tue Jul 16 15:51:58 2002 +++ mipl-0.9.3-hmipv6/linux/net/ipv6/mobile_ip6/hierarchy.h Tue Aug 6 10:24:03 2002 @@ -0,0 +1,125 @@ +/*** net/ipv6/mobile_ip6/hierarchy.h +**** $Id: hierarchy.h,v 1.8 2002/07/22 05:50:51 gdaley Exp $ +**** Copyright (C) 2001 Greg Daley and Nick 'Sharkey' Moore +**** Authors: Greg Daley +**** & Nick Sharkey Moore +**** License: GPL +**** +**** +**** +**** This program is free software; you can redistribute it and/or +**** modify it under the terms of the GNU General Public License +**** as published by the Free Software Foundation; either version 2 +**** of the License, or (at your option) any later version. +**** +**** See the File COPYING which comes with this distribution. +**** Full text available at http://www.gnu.org/copyleft/gpl.html +**** +**** +***/ + +#ifndef _HMIPV6_HIERARCHY_H +#define _HMIPV6_HIERARCHY_H + +#ifdef CONFIG_IPV6_MOBILITY_HMIPV6 + +#include +#include "map.h" +#include "bul.h" + +#define MAX_HIER_GC_CALLBACK_WAIT ( HZ * 2 ) + + + +#define MAP_ACK_STATE_REQUIRED 0x80 +#define MAP_ACK_STATE_REFRESH 0x40 + + /* to turn off flags */ +#define MAP_ACK_STATE_RESET 0x00 + +struct map_list { + struct map *map; + struct map_list *prev; + struct map_list *next; +}; + + +struct map_hierarchy { + struct map_list *map_top; + struct map_list *map_bottom; + rwlock_t lock; + rwlock_t oldlock; + struct map *old_top; + unsigned ackstate; /* set to MAP_ACK_STATE_RESET initially */ + int refcount; + struct timer_list gc_timer; +}; + + +struct map_handoff_entry{ + int state; + struct mipv6_bul_entry *mapentry; +}; + + /* read-only hierarchy functions */ + /* lock hierarchy for reading */ + +inline int is_empty_map_hierarchy(struct map_hierarchy *hier); +inline struct map * highest_map(struct map_hierarchy *hier, + struct map *mapinfo); +inline struct map * nearest_map(struct map_hierarchy *hier, + struct map *mapinfo); +struct map * find_map(struct map_hierarchy *hier, + struct in6_addr *addr, struct map *mapinfo); + + /* writing hierarchy functions */ + /* lock hierarchy for writing */ + +int init_map_hierarchy(struct map_hierarchy *hier); +int destroy_map_hierarchy(struct map_hierarchy *hier); +int uninstall_map(struct map_hierarchy *hier, struct map *tmp_map); + +struct map * install_map(struct map_hierarchy *hier, struct map *tmp_map); +struct map * update_map(struct map_hierarchy *hier, struct map *tmp_map); + + /* garbage collection stuff */ + +void map_hierarchy_gc_init(struct map_hierarchy *); +void map_hierarchy_gc_destroy(struct map_hierarchy *); +void map_hierarchy_gc_callback(unsigned long); + + + + /* everybody's interface to the hierarchy/ies */ + +struct map * mipv6_map_add(int ifindex, struct map *map); + +struct map * mipv6_highest_map(int ifindex, struct map *tmp_map); +struct map * mipv6_get_old_map(int ifindex, struct map *tmp_map); + +struct in6_addr *mipv6_hmipv6_get_rcoa(struct in6_addr *dest, + struct in6_addr *addr); + +int mipv6_form_rcoa(struct in6_addr *rcoa, struct in6_addr *lcoa, + struct in6_addr *mapaddr); +/* int mipv6_hmipv6_is_rcoa(int ifindex,struct in6_addr *addr); */ +int mipv6_hmipv6_is_rcoa(struct in6_addr *addr); + +__u32 mipv6_hmipv6_map_bulifetime(int ifindex); + +int mipv6_hierarchy_init(int ifindex); +int mipv6_map_delete(int ifindex, struct map *map); +int mipv6_hierarchy_destroy(int ifindex); +int mipv6_set_old_map(int ifindex); + +int mipv6_hmipv6_map_ack_state(void); +void mipv6_hmipv6_map_ack_required(void); +void mipv6_hmipv6_map_ack_refresh(void); +void mipv6_hmipv6_map_ack_reset(void); + +int map_event(struct map_hierarchy *hier, struct map *old, struct map *new); + +int map_handoff(void *rawentry, void *args, unsigned long *sortkey); + +#endif /* CONFIG_IPV6_MOBILITY_HMIPV6 */ +#endif /* _HMIPV6_HIERARCHY_H */ diff -rub --exclude=CVS --exclude=ExtendedMode.txt --exclude=Makefile.test --exclude=.* --exclude=*~ --exclude=*.detail --ignore-matching-lines=$Id: mipl-0.9.3/linux/net/ipv6/mobile_ip6/map.c mipl-0.9.3-hmipv6/linux/net/ipv6/mobile_ip6/map.c --- mipl-0.9.3/linux/net/ipv6/mobile_ip6/map.c Tue Jul 16 15:52:05 2002 +++ mipl-0.9.3-hmipv6/linux/net/ipv6/mobile_ip6/map.c Mon Jul 22 15:50:51 2002 @@ -0,0 +1,349 @@ +/*** net/ipv6/mobile_ip6/map.c +**** $Id: map.c,v 1.7 2002/07/22 05:50:51 gdaley Exp $ +**** Copyright (C) 2001 Greg Daley and Nick 'Sharkey' Moore +**** Authors: Greg Daley & Nick Sharkey Moore +**** License: GPL +**** +**** +**** This program is free software; you can redistribute it and/or +**** modify it under the terms of the GNU General Public License +**** as published by the Free Software Foundation; either version 2 +**** of the License, or (at your option) any later version. +**** +**** See the File COPYING which comes with this distribution. +**** Full text available at http://www.gnu.org/copyleft/gpl.html +**** +**** +***/ + +#include +#include +#include +#include "map.h" +#include "debug.h" +#include "mdetect.h" + + + + +#ifdef CONFIG_IPV6_MOBILITY_HMIPV6 + + +extern void *kmalloc(size_t, int); +extern void kfree(const void *); + +#define MEM_ALLOC(A) kmalloc(A, GFP_ATOMIC ) +#define MEM_FREE kfree + + +void destroy_map(struct map *dead_map); +int dump_map(struct map *map); + + +struct map *new_map(struct in6_addr *addr, int ifindex, + unsigned pref, unsigned dist, + unsigned long lifetime, unsigned long interval, + unsigned long lastupdate, unsigned flags); +int is_valid_map(struct in6_addr *addr, int ifindex, + unsigned pref, unsigned dist, + unsigned long lifetime, unsigned long interval, + unsigned long lastupdate, unsigned flags); + + +struct map *clone_map(struct map *tmp_map); +struct map *copy_map(struct map *dest, struct map *src); + + + + + +/** + * is_valid_map: + * + * tests MAP for inconsistencies. + * + * returns + * 1 : meets requirements for use as map + * 0 : does not meet requirements to be used as map + * -1 : (error) addr NULL; + * + */ + +int is_valid_map(struct in6_addr *addr, int ifindex, + unsigned pref, unsigned dist, + unsigned long lifetime, unsigned long interval, + unsigned long lastupdate, unsigned flags) +{ + + DEBUG_FUNC(); + + + + if (!addr) { + DEBUG((DBG_DATADUMP, "address points to NULL")); + return -1; + } + if ((addr->s6_addr16[0] == 0x0) && + ((ntohs(addr->s6_addr16[5]) == 0xffff) || + (addr->s6_addr16[6] == 0x0))) { + /* leading zero's and either IPv4 only */ + /* or IPv6 Unspec/Loopback */ + DEBUG((DBG_INFO, + "invalid address IPv4 only/loopback/unspec\n")); + return 0; + } + + if ((((ntohs(addr->s6_addr16[0]) & 0xff00) == 0xff00)) || + ((ntohs(addr->s6_addr16[0]) & 0xfe80) == 0xfe80)) { + /* site/link/multicast address */ + DEBUG((DBG_INFO, + "invalid address bad scope (multi/site/local)\n")); + return 0; + } + + if (pref < 0 || pref > 14) { + DEBUG((DBG_INFO, "invalid pref\n")); + return 0; + } + if ((lifetime < 0) || (dist < 1 || dist > 15)) { + DEBUG((DBG_INFO, "invalid lifetime or distance\n")); + return 0; + } + + if (ifindex < 0) { + DEBUG((DBG_INFO, "invalid interface for map\n")); + return 0; + + } + if ((flags & ND_OPT_MAP_FLAG_M) && (flags & ND_OPT_MAP_FLAG_R)) { + DEBUG((DBG_INFO, + "flags indicate conflicing HMIPv6 modes\n")); + return 0; + } + if ((flags & ND_OPT_MAP_FLAG_R) && (flags & + (ND_OPT_MAP_FLAG_T | + ND_OPT_MAP_FLAG_V))) { + DEBUG((DBG_INFO, "invalid flags for HMIPv6 basic mode\n")); + return 0; + } + if ((flags & ND_OPT_MAP_FLAG_M) && (flags & + (ND_OPT_MAP_FLAG_P | + ND_OPT_MAP_FLAG_I))) { + DEBUG((DBG_INFO, + "invalid flags for HMIPv6 extended mode\n")); + return 0; + } + + return 1; + +} + + + +/** + * dump_map: + * + * dumps debugging information to kernel logger + * + * returns + * 1 : meets requirements for use as map + * 0 : does not meet requirements to be used as map + * -1 : (error) map/globaladdr NULL; + * + */ + +int dump_map(struct map *map) +{ + + struct in6_addr *addr; + int ret; + DEBUG_FUNC(); + + if (!map) + return -1; + + + addr = &(map->globaladdr); + + if ((ret = is_valid_map(&(map->globaladdr), map->ifindex, + map->preference, map->distance, + map->lifetime, map->interval, + map->lastupdate, map->flags)) < 0) { + DEBUG((DBG_WARNING, "NULL HMIPv6 MAP option")); + return -1; + } else if (!ret) { + DEBUG((DBG_DATADUMP, "Invalid map ! %p",map)); + + } + + + DEBUG((DBG_DATADUMP, "MAP %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx", + NIPV6ADDR(addr))); + DEBUG((DBG_WARNING, "RCOA %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx", + NIPV6ADDR(&map->rcoa))); + DEBUG((DBG_DATADUMP, " interface %10u", map->ifindex)); + DEBUG((DBG_DATADUMP, " distance %10u", map->distance)); + DEBUG((DBG_DATADUMP, " preference %10u", map->preference)); + DEBUG((DBG_DATADUMP, " lifetime %10u", map->lifetime)); + DEBUG((DBG_DATADUMP, " interval %10u", map->interval)); + DEBUG((DBG_DATADUMP, " last updt %10u", map->lastupdate)); + DEBUG((DBG_DATADUMP, " flags %10u", map->flags)); + + + + return ret; + +} + + + +/** + * new_map + * + * new_map creates a new map instance allocates (atomically) + * kernel memory + * + * returns: MAP or NULL + * + */ + +struct map *new_map(struct in6_addr *addr, int ifindex, + unsigned pref, unsigned dist, + unsigned long lifetime, unsigned long interval, + unsigned long lastupdate, unsigned flags) +{ + struct map *tmp_map; + + DEBUG_FUNC(); + + if ((tmp_map = (struct map *) + MEM_ALLOC(sizeof(struct map))) == NULL) { + DEBUG((DBG_ERROR, "Unable to create (allocate) map\n")); + return NULL; + } + memcpy(&(tmp_map->globaladdr), addr, sizeof(struct in6_addr)); + memcpy(&(tmp_map->rcoa), &ipv6_addr_any, sizeof(struct in6_addr)); + tmp_map->preference = pref; + tmp_map->distance = dist; + tmp_map->ifindex = ifindex; + tmp_map->lifetime = lifetime; + tmp_map->interval = interval; + tmp_map->lastupdate = lastupdate; + tmp_map->flags = flags; + + return tmp_map; +} + + +/** + * destroy_map: + * + * releases the resources associated with a map. + * + * Makes sure that the maps are removed and destroyed + * removed. + * + */ + +void destroy_map(struct map *dead_map) +{ + DEBUG_FUNC(); + + MEM_FREE(dead_map); + + /* please remember to set pointer */ + /* to NULL on return */ +} + + + +/** + * clone_map: + * + * Copies a map instance and generates a new + * memory allocation for it. + * + * This memory allocation may be recovered using destroy_map() + * + * Returns: + * Null: new_map allocation failure + * else: pointer to newly allocated map + * + */ + +struct map *clone_map(struct map *tmp_map) +{ + struct map *ret_map; + + DEBUG_FUNC(); + + ret_map = new_map(&tmp_map->globaladdr, + tmp_map->ifindex, + tmp_map->preference, + tmp_map->distance, + tmp_map->lifetime, + tmp_map->interval, + tmp_map->lastupdate, tmp_map->flags); + + if (ret_map && !ipv6_addr_any(&tmp_map->rcoa)) { + memcpy(&ret_map->rcoa, &tmp_map->rcoa, + sizeof(struct in6_addr)); + } + return ret_map; +} + + + +/** + * copy_map + * + * copy_map copies a map instance from src into dest + * + * This memory allocation may be recovered using destroy_map() + * + * Returns: + * Null: invalid arguments (src or dest == NULL) + * else: pointer to dest + * + */ + +struct map *copy_map(struct map *dest, struct map *src) +{ + DEBUG_FUNC(); + + if (!(src && dest)) { + return NULL; + } + return memcpy(dest, src, sizeof(struct map)); +} + + + +/** + * map_expiry: + * + * Indicate when advertisements for this + * map are no longer valid. Uses Router Advertisement + * Interval (from MIPv6) if available + * + * returns time in jiffies when this map will expire + * + */ + +inline unsigned long map_expiry(struct map *map) +{ + DEBUG_FUNC(); + + if ((!map->interval) + || time_after(map->lastupdate + 2 * map->interval, + map->lifetime)) { + DEBUG((DBG_DATADUMP, "expiry absolute")); + return map->lifetime; + } else { + DEBUG((DBG_DATADUMP, "expiry interval: %lu %lu",map->lastupdate, map->interval)); + return map->lastupdate + 2 * map->interval; + } +} + + +#endif /* CONFIG_IPV6_MOBILITY_HMIPV6 */ diff -rub --exclude=CVS --exclude=ExtendedMode.txt --exclude=Makefile.test --exclude=.* --exclude=*~ --exclude=*.detail --ignore-matching-lines=$Id: mipl-0.9.3/linux/net/ipv6/mobile_ip6/map.h mipl-0.9.3-hmipv6/linux/net/ipv6/mobile_ip6/map.h --- mipl-0.9.3/linux/net/ipv6/mobile_ip6/map.h Tue Jul 16 15:52:08 2002 +++ mipl-0.9.3-hmipv6/linux/net/ipv6/mobile_ip6/map.h Tue Aug 6 10:24:03 2002 @@ -0,0 +1,79 @@ +/*** net/ipv6/mobile_ip6/map.h +**** $Id: map.h,v 1.5 2002/07/19 06:40:09 gdaley Exp $ +**** Copyright (C) 2001 Greg Daley and Nick 'Sharkey' Moore +**** Author: Greg Daley & Nick Sharkey Moore +**** License: GPL +**** +**** +**** This program is free software; you can redistribute it and/or +**** modify it under the terms of the GNU General Public License +**** as published by the Free Software Foundation; either version 2 +**** of the License, or (at your option) any later version. +**** +**** See the File COPYING which comes with this distribution. +**** Full text available at http://www.gnu.org/copyleft/gpl.html +**** +**** +***/ + +#ifndef MIPL_HMIP6_MAP +#define MIPL_HMIP6_MAP + +#include + + + +#ifdef CONFIG_IPV6_MOBILITY_HMIPV6 + +/* +** HMIPv6 MAP Information record for MN +*/ + +struct map { + int distance; + int preference; + struct in6_addr globaladdr; + struct in6_addr rcoa; + int prefixlen; + int ifindex; + unsigned flags; + unsigned long lifetime; /* expiry time when this MAP dies (jiffies) */ + unsigned long interval; /* time in jiffies between MAP Option RAdvs */ + unsigned long lastupdate; /* lastupdate for interval timer */ +}; + + + + /* Router Advertised MAP Option for HMIPv6 Draft 6 */ + +struct map_hdr { + uint8_t map_hdr_type; + uint8_t map_hdr_length; + uint8_t map_hdr_dist_pref; /* 4 bits dist (high), 4 bits pref (low) */ + uint8_t map_hdr_flags_reserved; + uint32_t map_hdr_valid_time; + struct in6_addr map_hdr_globaladdr; +}; + + + +extern void destroy_map(struct map *dead_map); +extern int dump_map(struct map *map); +extern struct map *new_map(struct in6_addr *addr, int ifindex, + unsigned pref, unsigned dist, + unsigned long lifetime, unsigned long interval, + unsigned long lastupdate, unsigned flags); +extern int is_valid_map(struct in6_addr *addr, int ifindex, + unsigned pref, unsigned dist, + unsigned long lifetime, unsigned long interval, + unsigned long lastupdate, unsigned flags); + +extern struct map *clone_map(struct map *tmp_map); + +extern struct map *copy_map(struct map *dest, struct map *src); + +unsigned long map_expiry(struct map *); + + +#endif /* CONFIG_IPV6_MOBILITY_HMIPV6 */ +#endif /* MIPL_HMIP6_MAP */ diff -rub --exclude=CVS --exclude=ExtendedMode.txt --exclude=Makefile.test --exclude=.* --exclude=*~ --exclude=*.detail --ignore-matching-lines=$Id: mipl-0.9.3/linux/net/ipv6/mobile_ip6/mdetect.c mipl-0.9.3-hmipv6/linux/net/ipv6/mobile_ip6/mdetect.c --- mipl-0.9.3/linux/net/ipv6/mobile_ip6/mdetect.c Mon Jul 15 16:33:27 2002 +++ mipl-0.9.3-hmipv6/linux/net/ipv6/mobile_ip6/mdetect.c Fri Jul 19 11:08:16 2002 @@ -45,6 +45,10 @@ #include "mn.h" #include "debug.h" #include "tunnel.h" + +#include "map.h" +#include "hierarchy.h" + #include "multiaccess_ctl.h" #define START 0 @@ -128,14 +132,18 @@ { struct net_device *dev; int ret; - if (plen != 64) + if ((plen != 64) || !coa) return -1; if ((dev = dev_get_by_index(ifindex)) == NULL) { DEBUG((DBG_WARNING, "Device is not present")); return -1; } - ipv6_get_lladdr(dev, coa); + if(ipv6_get_lladdr(dev, coa)){ + DEBUG((DBG_WARNING,"Unable to get lladdr %d " + " %x:%x:%x:%x:%x:%x:%x:%x", ifindex,NIPV6ADDR(coa))); + return -1; + } coa->s6_addr32[0] = pfix->s6_addr32[0]; coa->s6_addr32[1] = pfix->s6_addr32[1]; @@ -332,6 +340,14 @@ curr_router->ifindex); if (ret < 0) { DEBUG((DBG_ERROR, "handoff: Creation of coa failed")); + next_router=curr_router; + curr_router=tmp; + tmp=NULL; + /* GD: this is a hack: we're unable to signal while */ + /* the LLADDR is still tentative. */ + /* current workaround is to undo our changes, */ + /* and back out, waiting for next RA.... Maybe we */ + /* should get called back when the address is DAD'ed*/ goto unlock; } if (ret == 1) @@ -443,6 +459,7 @@ struct in6_addr *homeaddr, struct in6_addr *coaddr) { + int tmp; struct net_device *currdev; DEBUG_FUNC(); @@ -454,6 +471,8 @@ mipv6_prefix_compare(homeaddr, &curr_router->raddr, 64)) { DEBUG((DBG_INFO,"mipv6_get_care_of_address: returning home address")); + DEBUG((DBG_DATADUMP,"mipv6_get_care_of_address: p: %p", curr_router)); + DEBUG((DBG_DATADUMP,"mipv6_get_care_of_address: h: %d",mipv6_mn_is_at_home(homeaddr))); ipv6_addr_copy(coaddr, homeaddr); spin_unlock_bh(&router_lock); return 0; @@ -464,8 +483,7 @@ spin_unlock_bh(&router_lock); return -1; } - - ipv6_get_lladdr(currdev, coaddr); + tmp = ipv6_get_lladdr(currdev, coaddr); coaddr->s6_addr32[0] = curr_router->raddr.s6_addr32[0]; coaddr->s6_addr32[1] = curr_router->raddr.s6_addr32[1]; @@ -477,6 +495,10 @@ } dev_put(currdev); spin_unlock_bh(&router_lock); + if(tmp){ + /* GD experimental */ + return -1; + } return 0; } @@ -626,7 +648,7 @@ goto handoff; } /* Current router is not reachable anymore ? */ - if (crt->state == NOT_REACHABLE) { + if (crt->state == NOT_REACHABLE || !crt->is_current) { DEBUG((DEBUG_MDETECT, "Curr router not reachable -> handoff")); goto handoff; } diff -rub --exclude=CVS --exclude=ExtendedMode.txt --exclude=Makefile.test --exclude=.* --exclude=*~ --exclude=*.detail --ignore-matching-lines=$Id: mipl-0.9.3/linux/net/ipv6/mobile_ip6/mdetect.h mipl-0.9.3-hmipv6/linux/net/ipv6/mobile_ip6/mdetect.h --- mipl-0.9.3/linux/net/ipv6/mobile_ip6/mdetect.h Mon Jul 15 16:33:27 2002 +++ mipl-0.9.3-hmipv6/linux/net/ipv6/mobile_ip6/mdetect.h Tue Aug 6 10:24:03 2002 @@ -46,6 +46,16 @@ #define ND_RA_FLAG_OTHER 0x40 #define ND_RA_FLAG_HA 0x20 +/* RA MAP Option flags */ +#define ND_OPT_MAP_FLAG_R 0x80 +#define ND_OPT_MAP_FLAG_M 0x40 +#define ND_OPT_MAP_FLAG_I 0x20 +#define ND_OPT_MAP_FLAG_T 0x10 +#define ND_OPT_MAP_FLAG_P 0x08 +#define ND_OPT_MAP_FLAG_V 0x04 + +#define LL_PREFIX 0xfe80 + struct router { struct list_head list; struct in6_addr ll_addr; @@ -64,6 +74,9 @@ struct in6_addr CoA; /* care-off address used with this router */ int extra_addr_route; struct router *next; +#ifdef CONFIG_IPV6_MOBILITY_HMIPV6 + struct map *map; +#endif }; #define MIPV6_MDF_NONE 0x0 diff -rub --exclude=CVS --exclude=ExtendedMode.txt --exclude=Makefile.test --exclude=.* --exclude=*~ --exclude=*.detail --ignore-matching-lines=$Id: mipl-0.9.3/linux/net/ipv6/mobile_ip6/mipv6.c mipl-0.9.3-hmipv6/linux/net/ipv6/mobile_ip6/mipv6.c --- mipl-0.9.3/linux/net/ipv6/mobile_ip6/mipv6.c Mon Jul 15 16:33:27 2002 +++ mipl-0.9.3-hmipv6/linux/net/ipv6/mobile_ip6/mipv6.c Tue Aug 6 15:58:37 2002 @@ -80,6 +80,13 @@ #ifdef CONFIG_IPV6_MOBILITY_AH #include "ah.h" #endif + +#ifdef CONFIG_IPV6_MOBILITY_HMIPV6 +#include "map.h" +#include "hierarchy.h" +#include "rcoa.h" +#endif + #ifdef CONFIG_SYSCTL #include "sysctl.h" #endif /* CONFIG_SYSCTL */ @@ -89,6 +96,10 @@ #define MIPV6_BCACHE_SIZE 128 #define MIPV6_HALIST_SIZE 128 +#ifdef CONFIG_IPV6_MOBILITY_HMIPV6 +static int mipv6_contains_map_bu( struct ipv6hdr *hdr); +#endif + /** * mipv6_finalize_modify_xmit - Finalize packet modifications * @alloclist: pointer to allocated options list @@ -146,6 +157,75 @@ #define OPT_RQ 2 #define OPT_ACK 4 +#ifdef CONFIG_IPV6_MOBILITY_HMIPV6 +static int check_map_bu_dst_opt(struct ipv6_destopt_hdr *dohdr){ + unsigned tmpoptlen, tmpoptoffset; + struct mipv6_dstopt_bindupdate *buopt; + struct mipv6_dstopt_homeaddr *haopt; + int ret = 0; + + DEBUG_FUNC(); + DEBUG((DBG_DATADUMP, "doptions: next %hu",(__u8) dohdr->nexthdr)); + DEBUG((DBG_DATADUMP, "doptions: len %hu",(__u8) dohdr->hdrlen)); + tmpoptlen = (dohdr->hdrlen* 8) + 8 ; + tmpoptoffset = 2; + + while ( tmpoptoffset < tmpoptlen){ + DEBUG((DBG_DATADUMP, "doptions: tmpoffset %hu", tmpoptoffset)); + switch (((__u8 *) dohdr)[tmpoptoffset]){ + case 0 : /* 0 pad */ + DEBUG((DBG_DATADUMP, "doptions: tlv %hu", + ((__u8 *)dohdr)[tmpoptoffset])); + tmpoptoffset += 1; + break; + case MIPV6_TLV_HOMEADDR : + haopt = (struct mipv6_dstopt_homeaddr *) + &((__u8 * ) dohdr)[tmpoptoffset] ; + DEBUG((DBG_DATADUMP,"doptions: hatype %hu", + haopt->type)); + DEBUG((DBG_DATADUMP,"doptions: halen %hu", + haopt->length )); + DEBUG((DBG_DATADUMP,"doptions: addr: %x:%x:%x:%x:%x:%x:%x:%x", + NIPV6ADDR(&(haopt->addr)))); + + tmpoptoffset += ((__u8 *) dohdr)[tmpoptoffset+1]+2; + break; + case MIPV6_TLV_BINDUPDATE : + buopt = (struct mipv6_dstopt_bindupdate *) + &((__u8 * ) dohdr)[tmpoptoffset] ; + DEBUG((DBG_DATADUMP,"doptions: butype %hu", + buopt->type)); + DEBUG((DBG_DATADUMP,"doptions: bulen %hu", + buopt->length )); + DEBUG((DBG_DATADUMP,"doptions: bu_f_map: %hu", + (buopt->flags & MIPV6_BU_F_MAP)?1 :0)); + DEBUG((DBG_DATADUMP,"doptions: bu_f_dad: %hu", + (buopt->flags & MIPV6_BU_F_DAD)?1 :0)); + DEBUG((DBG_DATADUMP,"doptions: bu_f_home: %hu", + (buopt->flags & MIPV6_BU_F_HOME)?1 :0)); + DEBUG((DBG_DATADUMP,"doptions: bu_f_ack: %hu", + (buopt->flags & MIPV6_BU_F_ACK)?1 :0)); + + if (buopt->flags & MIPV6_BU_F_MAP){ + ret =1; + } + + tmpoptoffset += ((__u8 *) dohdr)[tmpoptoffset+1]+2; + break; + default: /* include padn */ + DEBUG((DBG_DATADUMP, "doptions: tlv %hu", + ((__u8 *) dohdr)[tmpoptoffset])); + DEBUG((DBG_DATADUMP, "doptions: tlvlen %hu", + ((__u8 *) dohdr)[tmpoptoffset+1])); + tmpoptoffset += ((__u8 *) dohdr)[tmpoptoffset+1]+2; + break; + } + /* DEBUG((DBG_DATADUMP, "doptions: tmpoffset %hu", tmpoptoffset)); */ + } + return ret; +} +#endif + /** * mipv6_modify_xmit_packets - Modify outgoing packets * @sk: socket @@ -203,6 +283,8 @@ memset(&coaddr, 0, sizeof(struct in6_addr)); newdo1hdr = mipv6_add_dst1opts(saddr, daddr, &coaddr, olddo1hdr, &ops); + DEBUG((DBG_DATADUMP, "and c of address: %x:%x:%x:%x:%x:%x:%x:%x", NIPV6ADDR(&coaddr))); + if (mipv6_bcache_get(daddr, saddr, &bc_entry) == 0 || (ops & OPT_ACK)) { if (ipv6_addr_any(&coaddr)) { ipv6_addr_copy(&coaddr, &bc_entry.coa); @@ -248,6 +330,12 @@ } +/* GDALEY patch */ + mipv6_get_care_of_address(saddr, &coaddr); + DEBUG((DBG_DATADUMP, " XMIT: Saddr %x:%x:%x:%x:%x:%x:%x:%x", NIPV6ADDR(saddr))); + DEBUG((DBG_DATADUMP, " XMIT: Coa %x:%x:%x:%x:%x:%x:%x:%x", NIPV6ADDR(&coaddr))); + DEBUG((DBG_DATADUMP, " XMIT: daddr %x:%x:%x:%x:%x:%x:%x:%x", NIPV6ADDR(daddr))); +/* /GDALEY PATCH */ /* Add ha_option if */ add_ha = (mipv6_is_mn && mipv6_mn_is_home_addr(saddr) && !mipv6_mn_is_at_home(saddr) && mipv6_mn_hashomereg(saddr) && @@ -350,16 +438,62 @@ const struct net_device *out, int (*okfn) (struct sk_buff *)) { +#ifdef CONFIG_IPV6_MOBILITY_HMIPV6 + struct map map; +#endif struct ipv6hdr *hdr = (*skb) ? (*skb)->nh.ipv6h : NULL; + DEBUG_FUNC(); if (hdr == NULL) return NF_ACCEPT; - if (!mipv6_mn_is_at_home(&hdr->saddr) && - mipv6_mn_is_home_addr(&hdr->saddr) && - (!mipv6_reverse_tunnel || daddr_is_ha(&hdr->saddr, &hdr->daddr))) { +#ifdef CONFIG_IPV6_MOBILITY_HMIPV6 + if (mipv6_mn_is_at_home(&hdr->saddr) || + (ipv6_addr_type(&hdr->daddr) & IPV6_ADDR_LINKLOCAL) || + !(mipv6_mn_is_home_addr(&hdr->saddr)||mipv6_hmipv6_is_rcoa(&hdr->saddr)||mipv6_contains_map_bu(hdr))|| + (mipv6_reverse_tunnel && !daddr_is_ha(&hdr->saddr, &hdr->daddr))) { + + DEBUG((DBG_DATADUMP,"modify_xmit_addrs (AT HOME) %d %d %d %d", + mipv6_mn_is_at_home(&hdr->saddr), + ipv6_addr_type(&hdr->daddr) & IPV6_ADDR_LINKLOCAL, + !( mipv6_mn_is_home_addr(&hdr->saddr) || mipv6_hmipv6_is_rcoa(&hdr->saddr) || mipv6_contains_map_bu(hdr)), + (mipv6_reverse_tunnel && !daddr_is_ha(&hdr->saddr, &hdr->daddr)))); + +#else + if (mipv6_mn_is_at_home(&hdr->saddr) || + !mipv6_mn_is_home_addr(&hdr->saddr) || + (mipv6_reverse_tunnel && !daddr_is_ha(&hdr->saddr, &hdr->daddr))) { + DEBUG((DBG_DATADUMP,"modify_xmit_addrs (AT HOME) %d %d %d", + mipv6_mn_is_at_home(&hdr->saddr), + !mipv6_mn_is_home_addr(&hdr->saddr), + (mipv6_reverse_tunnel && !daddr_is_ha(&hdr->saddr, &hdr->daddr)))); + +#endif + DEBUG((DBG_DATADUMP, "saddr %x:%x:%x:%x:%x:%x:%x:%x", NIPV6ADDR(&hdr->saddr))); + return NF_ACCEPT; + } + DEBUG((DBG_INFO, + "Replace source address (home-address => care-of-address)")); + DEBUG((DBG_DATADUMP, "bef %x:%x:%x:%x:%x:%x:%x:%x", NIPV6ADDR(&hdr->saddr))); + + + /* if we have a P bit MAP, and this is not a BU to that MAP */ + /* rewrite the packet with the RCoA as the source */ +#ifdef CONFIG_IPV6_MOBILITY_HMIPV6 + if(mipv6_get_old_map(-1, &map) && (map.flags & ND_OPT_MAP_FLAG_P) && + (!mipv6_contains_map_bu(hdr) || + ipv6_addr_cmp(&(map.globaladdr),&hdr->daddr))){ + DEBUG((DBG_DATADUMP, "MAP P flag set")); + /* use known MAP's RCoA */ + memcpy(&hdr->saddr, &(map.rcoa), sizeof(struct in6_addr)); + } + else{ +#endif mipv6_get_care_of_address(&hdr->saddr, &hdr->saddr); DEBUG((DBG_DATADUMP, "Replace source address with CoA ")); +#ifdef CONFIG_IPV6_MOBILITY_HMIPV6 } +#endif + DEBUG((DBG_DATADUMP, "after %x:%x:%x:%x:%x:%x:%x:%x", NIPV6ADDR(&hdr->saddr))); return NF_ACCEPT; } @@ -777,6 +911,14 @@ }; struct hal *ha_queue = NULL; +#ifdef CONFIG_IPV6_MOBILITY_HMIPV6 + struct map_l { + struct map *map; + struct map_l *next; + }; + struct map_l *map_queue = NULL; +#endif + __u8 * opt = (__u8 *)(ra + 1); DEBUG_FUNC(); @@ -896,6 +1038,99 @@ "received home agent info with preference : %d and lifetime : %d", ha_info_pref, ha_info_lifetime)); } + +#ifdef CONFIG_IPV6_MOBILITY_HMIPV6 + if (opt[0] == ND_OPT_MAP){ + /* distance is 0-15, 15 is unused */ + __u8 tmp_dist, tmp_pref; + unsigned tmp_flags; + struct in6_addr *tmp_addr; + struct map_l *tmp_map_l =NULL; + struct map_hdr *mapinfo; + __u32 tmp_lifetime; + + if (len < sizeof(struct map_hdr)) return 1; + + mapinfo = (struct map_hdr *) opt; + + tmp_dist=(mapinfo->map_hdr_dist_pref >>4 ) & 0x0f; + tmp_pref=(mapinfo->map_hdr_dist_pref) & 0x0f; + + tmp_lifetime = ntohl(mapinfo->map_hdr_valid_time); + + tmp_addr = &mapinfo->map_hdr_globaladdr; + tmp_flags = mapinfo->map_hdr_flags_reserved; + + tmp_map_l = kmalloc(sizeof(struct map_l), GFP_ATOMIC); + if (tmp_map_l == NULL) + return -ENOMEM; + + if(!(tmp_map_l->map = new_map(tmp_addr, + ifi, tmp_pref, tmp_dist, + jiffies + (tmp_lifetime * HZ ), + 0, /* interval not known until RADV processed */ + jiffies /* last update */, tmp_flags))){ + + DEBUG((DBG_WARNING, "unable to allocate MAP")); + return -ENOMEM; + } + tmp_map_l->next = map_queue; + map_queue = tmp_map_l; + + /* pref is 0-15, 15 is unused */ + DEBUG((DBG_DATADUMP, + "received HMIP6 MAP option with")); + DEBUG((DBG_DATADUMP, + " distance : %u", + tmp_map_l->map->distance)); + DEBUG((DBG_DATADUMP, + " preference : %u", + tmp_map_l->map->preference)); + DEBUG((DBG_DATADUMP, + " lifetime: %lu", + tmp_lifetime)); + DEBUG((DBG_DATADUMP, + " lifetime(Jiffies): %lu", + (tmp_lifetime * HZ))); + DEBUG((DBG_DATADUMP, + " jiffies (lifetime): %lu", + jiffies)); + DEBUG((DBG_DATADUMP, + " lifetime(J): %lu", + jiffies + (tmp_lifetime * HZ) )); + DEBUG((DBG_DATADUMP, + " lifetime: %lu", + tmp_map_l->map->lifetime)); + DEBUG((DBG_DATADUMP, + " flag: RCoAPrefix - %u", + ( (tmp_map_l->map->flags + & ND_OPT_MAP_FLAG_R )? 1 : 0 ))); + DEBUG((DBG_DATADUMP, + " flag: ExtendedMode - %u", + ( (tmp_map_l->map->flags + & ND_OPT_MAP_FLAG_M )? 1 : 0 ))); + DEBUG((DBG_DATADUMP, + " flag: Privacy - %u", + ( (tmp_map_l->map->flags + & ND_OPT_MAP_FLAG_I )? 1 : 0 ))); + DEBUG((DBG_DATADUMP, + " flag: Topology - %u", + ( (tmp_map_l->map->flags + & ND_OPT_MAP_FLAG_T )? 1 : 0 ))); + DEBUG((DBG_DATADUMP, + " flag: PacketSource - %u", + ( (tmp_map_l->map->flags + & ND_OPT_MAP_FLAG_P )? 1 : 0 ))); + DEBUG((DBG_DATADUMP, + " flag: ReverseTunnel - %u", + ( (tmp_map_l->map->flags + & ND_OPT_MAP_FLAG_V )? 1 : 0 ))); + DEBUG((DBG_DATADUMP, "Address of the received " + "map option: %x:%x:%x:%x:%x:%x:%x:%x", + NIPV6ADDR(&(tmp_map_l->map->globaladdr)))); + } +#endif + nextopt: optlen -= len; opt += len; @@ -916,6 +1151,34 @@ ha_queue = tmp; } +#ifdef CONFIG_IPV6_MOBILITY_HMIPV6 + while (map_queue) { + struct map_l *tmp = map_queue->next; + + if (ha_info_lifetime) { + if (nrt.interval) + map_queue->map->interval = nrt.interval; + DEBUG((DBG_INFO, "mipv6_map_add about to add" + " MAP %x:%x:%x:%x:%x:%x:%x:%x", + NIPV6ADDR(&(map_queue->map->globaladdr)) + )); + /* dump_map(map_queue->map); */ + mipv6_map_add(ifi, map_queue->map); + } else { + if (mipv6_map_delete(ifi, map_queue->map) < 0) { + DEBUG((DBG_INFO, "mipv6_ra_rcv_ptr: Not able " + "to delete MAP %x:%x:%x:%x:%x:%x:%x:%x", + NIPV6ADDR(&(map_queue->map->globaladdr)))); + } + } + DEBUG((DBG_INFO, "freeing map resources from r adv ")); + destroy_map(map_queue->map); + map_queue->map = NULL; + map_queue->next = NULL; + kfree(map_queue); + map_queue = tmp; + } +#endif if (mipv6_is_mn) return mipv6_router_event(&nrt); @@ -991,6 +1254,9 @@ mipv6_initialize_halist(MIPV6_HALIST_SIZE); mipv6_initialize_icmpv6(); mipv6_initialize_pfx_icmpv6(); +#ifdef CONFIG_IPV6_MOBILITY_HMIPV6 + mipv6_initialize_rcoa_install(); +#endif } if (mipv6_is_ha) { @@ -1003,6 +1269,9 @@ } if (mipv6_is_mn) { mipv6_initialize_bul(MIPV6_BUL_SIZE); +#ifdef CONFIG_IPV6_MOBILITY_HMIPV6 + mipv6_init_map_hierarchy(); +#endif mipv6_initialize_mn(); mipv6_initialize_mdetect(); @@ -1081,6 +1350,9 @@ if (mipv6_is_ha || mipv6_is_mn) { mipv6_shutdown_halist(); +#ifdef CONFIG_IPV6_MOBILITY_HMIPV6 + mipv6_shutdown_rcoa_install(); +#endif mipv6_shutdown_pfx_icmpv6(); mipv6_shutdown_icmpv6(); } @@ -1088,6 +1360,9 @@ if (mipv6_is_mn) { nf_unregister_hook(&addr_modify_hook_ops); mipv6_shutdown_mdetect(); +#ifdef CONFIG_IPV6_MOBILITY_HMIPV6 + mipv6_shutdown_map_hierarchy(); +#endif mipv6_shutdown_mn(); mipv6_shutdown_bul(); } @@ -1101,4 +1376,116 @@ mipv6_shutdown_tunnel(); } +#ifdef CONFIG_IPV6_MOBILITY_HMIPV6 +static int mipv6_contains_map_bu( struct ipv6hdr *hdr) +{ + __u8 hdrtype; + __u8 *posthdr; + int ret = 0; + + DEBUG_FUNC(); + DEBUG((DBG_DATADUMP, " Parsing header, to check for Map BU")); + + if(!hdr) { + + DEBUG((DBG_DATADUMP, " No Header found ")); + return 0; + } + + + DEBUG((DBG_DATADUMP, + " Found IPv6hdr : nexthdr %u" , + (unsigned char) hdr->nexthdr)); + DEBUG((DBG_DATADUMP, + " : payload_len %u", + (unsigned char) hdr->payload_len)); + + hdrtype = hdr->nexthdr; + posthdr = &( ((__u8 *)(hdr))[40] ) /* 5 * 8octets */ ; + + while(hdrtype != NEXTHDR_NONE){ + DEBUG((DBG_DATADUMP, + " looking for MAPBU: currhdr = %u",hdrtype)); + switch (hdrtype) { + + case NEXTHDR_DEST: + DEBUG((DBG_DATADUMP, + " Found Desthdr looking for MapBU")); + + DEBUG((DBG_DATADUMP, + " In Desthdr : nexthdr %u" , + (unsigned char) ((struct + ipv6_destopt_hdr *)posthdr)->nexthdr )); + /* DEBUG((DBG_DATADUMP, + " In Desthdr : posthdr[0] %u" , + (unsigned char) ((u8 *)posthdr)[0] )); */ + DEBUG((DBG_DATADUMP, + " In Desthdr : len %u", + (unsigned char) ((struct + ipv6_destopt_hdr *)posthdr)->hdrlen )); + /* DEBUG((DBG_DATADUMP, + " In Desthdr : posthdr[1] %u" , + (unsigned char) ((u8 *)posthdr)[1] )); */ + DEBUG((DBG_DATADUMP, + " In Desthdr : len(oct)%u", + (unsigned char) ipv6_optlen((struct + ipv6_destopt_hdr *)posthdr))); + + if(check_map_bu_dst_opt( + (struct ipv6_opt_hdr *)posthdr)){ + DEBUG((DBG_DATADUMP," Found MapBU")); + ret = 1; + } + /*ret = 1; */ + hdrtype = + ((struct + ipv6_destopt_hdr *)posthdr)->nexthdr; + + DEBUG((DBG_DATADUMP, + " nexthdr for MAPBU: nexthdr = %u , (none=%u)", + hdrtype,NEXTHDR_NONE)); + posthdr = posthdr + (unsigned char) + ipv6_optlen((struct ipv6_destopt_hdr *)posthdr); + /* hdrtype = NEXTHDR_NONE; */ + break; + case NEXTHDR_HOP: + case NEXTHDR_ROUTING: + DEBUG((DBG_DATADUMP, + " In Otherhdr : posthdr[0] %u" , + (unsigned char) ((u8 *)posthdr)[0] )); + + DEBUG((DBG_DATADUMP, + " In Desthdr : posthdr[1] %u" , + (unsigned char) ((u8 *)posthdr)[1] )); + hdrtype = posthdr[0]; + posthdr = posthdr + ( posthdr[1]); + hdrtype = NEXTHDR_NONE; + break; + case NEXTHDR_IPV6: + hdrtype = ((struct ipv6hdr *)posthdr)->nexthdr ; + posthdr = &( ((__u8 *)(posthdr))[40] )/* 5 * 8octets */; + break; +#ifdef CONFIG_IPV6_MOBILITY_AH + case NEXTHDR_AUTH: /* GD TODO Testing */ + /* status 25-03-2002 AH suspect */ + DEBUG((DBG_DATADUMP, + " In AH : nextheader %u" , + ((struct mipv6_ah *)posthdr)->ah_nh)); + DEBUG((DBG_DATADUMP, + " In AH : headerlen %u" , + ((struct mipv6_ah *)posthdr)->ah_nh )); + hdrtype = + ((struct mipv6_ah *)posthdr)->ah_nh; + posthdr = posthdr + /* 4 octets per 32bit word */ + (((struct mipv6_ah *)posthdr)->ah_hl * 4); + break; +#endif /*def CONFIG_IPV6_MOBILITY_AH */ + default: /* jump out */ + hdrtype = NEXTHDR_NONE; + break; + } + } + return ret; +} +#endif /* def CONFIG_IPV6_MOBILITY_HMIPV6 */ diff -rub --exclude=CVS --exclude=ExtendedMode.txt --exclude=Makefile.test --exclude=.* --exclude=*~ --exclude=*.detail --ignore-matching-lines=$Id: mipl-0.9.3/linux/net/ipv6/mobile_ip6/mn.c mipl-0.9.3-hmipv6/linux/net/ipv6/mobile_ip6/mn.c --- mipl-0.9.3/linux/net/ipv6/mobile_ip6/mn.c Mon Jul 15 16:33:27 2002 +++ mipl-0.9.3-hmipv6/linux/net/ipv6/mobile_ip6/mn.c Mon Jul 22 15:50:51 2002 @@ -42,6 +42,7 @@ #include "debug.h" #include "mn.h" #include "dhaad.h" +#include "hierarchy.h" #include "multiaccess_ctl.h" #include "prefix.h" #include "tunnel.h" @@ -151,6 +152,8 @@ { struct mn_info *minfo; int ret = 0; + DEBUG_FUNC(); + read_lock_bh(&mn_info_lock); if ((minfo = mipv6_mn_get_info(home_addr)) != NULL) { ret = minfo->is_at_home; @@ -524,6 +527,10 @@ } if (flags & MIPV6_BU_F_HOME) lifetime = HA_BU_DEF_LIFETIME; +#ifdef CONFIG_IPV6_MOBILITY_HMIPV6 + else if (flags & MIPV6_BU_F_MAP) + lifetime = MAP_BU_DEF_LIFETIME; +#endif else lifetime = CN_BU_DEF_LIFETIME; @@ -551,6 +558,10 @@ struct ipv6hdr *inner = (struct ipv6hdr *)skb->h.raw; struct ipv6hdr *outer = skb->nh.ipv6h; struct mn_info *minfo = NULL; +#ifdef CONFIG_IPV6_MOBILITY_HMIPV6 + int ifindex = skb->dev->ifindex; + __u32 maplifetime; +#endif __u32 lifetime; DEBUG_FUNC(); @@ -597,6 +608,13 @@ DEBUG((DBG_INFO, "Received tunneled packet without dst_opts")); lifetime = mipv6_mn_get_bulifetime(&inner->daddr, &outer->daddr, 0); + +#ifdef CONFIG_IPV6_MOBILITY_HMIPV6 + if((maplifetime = mipv6_hmipv6_map_bulifetime(ifindex))&& + (lifetime > maplifetime)){ + lifetime = maplifetime; + } +#endif if(lifetime) /* max wait 1000 ms before sending an empty packet with BU */ mipv6_send_upd_option(&inner->daddr,&inner->saddr, @@ -717,6 +735,7 @@ * * Since MN can have many home addresses and home networks, every BUL * entry needs to be checked + GD Check: What if the MAP is valid?? **/ DEBUG_STATIC int mn_handoff(void *rawentry, void *args, unsigned long *sortkey) { @@ -856,11 +875,18 @@ * * Event for handoff. Sends BUs everyone on Binding Update List. **/ + +/* XXX SHARKEY - This needs patching for HMIP but not sure how */ + int mipv6_mobile_node_moved(struct handoff *ho) { struct list_head *lh; struct mn_info *minfo = NULL; int bu_to_prev_router = 1; +#ifdef CONFIG_IPV6_MOBILITY_HMIPV6 + struct map map; +#endif + unsigned lifetime; int dummy; DEBUG_FUNC(); @@ -871,8 +897,37 @@ ma_ctl_upd_iface(ho->rtr_new.ifindex, MA_IFACE_CURRENT | MA_IFACE_HAS_ROUTER, &dummy); +#ifdef CONFIG_IPV6_MOBILITY_HMIPV6 /* First send BUs to all nodes which are on BU list */ + /* for HMIP6, only do the handoff if the map is not */ + /* in charge ** Watch out if at home ** */ + if(mipv6_get_old_map(-1, &map)){ + DEBUG((DBG_INFO, "mn moved: Map exists %x:%x:%x:%x:%x:%x:%x:%x", + NIPV6ADDR(&(map.globaladdr)))); + DEBUG((DBG_INFO, "mn moved: no mipv6 ha signalling")); + DEBUG((DBG_INFO, "mn moved: mapRCoA %x:%x:%x:%x:%x:%x:%x:%x", + NIPV6ADDR(&(map.rcoa)))); + + if((lifetime = ((map.lifetime - jiffies)/HZ)) < 0){ + lifetime = 0; + } + mipv6_send_upd_option( &(map.rcoa), &(map.globaladdr), + MAP_BU_DELAY, INITIAL_BINDACK_TIMEOUT, + MAX_BINDACK_TIMEOUT, 1, + MIPV6_BU_F_MAP | MIPV6_BU_F_DAD | MIPV6_BU_F_ACK, + 64, + lifetime, NULL); + + /* BU to previous router */ + /* mipv6_bu_to_prev_router(prev_router, plen); */ + } + else{ +#endif bul_iterate(mn_handoff, (void *)ho); +#ifdef CONFIG_IPV6_MOBILITY_HMIPV6 + } +#endif + /* Then go through the home infos to see if there's a new one * which has not been registered @@ -1032,6 +1087,9 @@ list_for_each(lh, &mn_info_list) { minfo = list_entry(lh, struct mn_info, list); + if (!minfo) { + continue; + } if (mipv6_prefix_compare(&rtr->raddr, &minfo->home_addr, minfo->home_plen)) { @@ -1258,3 +1316,17 @@ } write_unlock_bh(&mn_info_lock); } + +#ifdef CONFIG_IPV6_MOBILITY_HMIPV6 +void mipv6_init_map_hierarchy(void){ + /* Initialise the default hierarchy */ + mipv6_hierarchy_init(-1); + +} + +void mipv6_shutdown_map_hierarchy(void){ + /* destroy the default hierarchy */ + mipv6_hierarchy_destroy(-1); +} + +#endif diff -rub --exclude=CVS --exclude=ExtendedMode.txt --exclude=Makefile.test --exclude=.* --exclude=*~ --exclude=*.detail --ignore-matching-lines=$Id: mipl-0.9.3/linux/net/ipv6/mobile_ip6/mn.h mipl-0.9.3-hmipv6/linux/net/ipv6/mobile_ip6/mn.h --- mipl-0.9.3/linux/net/ipv6/mobile_ip6/mn.h Mon Jul 15 16:33:27 2002 +++ mipl-0.9.3-hmipv6/linux/net/ipv6/mobile_ip6/mn.h Tue Aug 6 10:24:03 2002 @@ -21,7 +21,10 @@ /* constants for sending of BUs*/ #define HA_BU_DELAY 0 +#define MAP_BU_DELAY 0 + #define HA_BU_DEF_LIFETIME 10000 +#define MAP_BU_DEF_LIFETIME 120 #define CN_BU_DELAY 500 /* In case there is some data pckets to add the bu to */ #define CN_BU_DEF_LIFETIME 1000 /* 60s is short, could be longer */ #define DUMB_CN_BU_LIFETIME 600 /* BUL entry lifetime in case of dumb CN */ @@ -71,6 +74,9 @@ void mipv6_check_tunneled_packet(struct sk_buff *skb); +void mipv6_init_map_hierarchy(void); +void mipv6_shutdown_map_hierarchy(void); + void mipv6_mn_send_home_na(struct in6_addr *haddr); /* Init home reg. with coa */ int init_home_registration(struct mn_info *hinfo, struct in6_addr *coa); diff -rub --exclude=CVS --exclude=ExtendedMode.txt --exclude=Makefile.test --exclude=.* --exclude=*~ --exclude=*.detail --ignore-matching-lines=$Id: mipl-0.9.3/linux/net/ipv6/mobile_ip6/prefix.c mipl-0.9.3-hmipv6/linux/net/ipv6/mobile_ip6/prefix.c --- mipl-0.9.3/linux/net/ipv6/mobile_ip6/prefix.c Mon Jul 15 16:33:27 2002 +++ mipl-0.9.3-hmipv6/linux/net/ipv6/mobile_ip6/prefix.c Fri Jul 19 11:08:16 2002 @@ -73,7 +73,7 @@ __u16 id, int iif, int send_br) { int count; - struct prefix_info *plist; + struct prefix_info *plist = NULL; DEBUG_FUNC(); diff -rub --exclude=CVS --exclude=ExtendedMode.txt --exclude=Makefile.test --exclude=.* --exclude=*~ --exclude=*.detail --ignore-matching-lines=$Id: mipl-0.9.3/linux/net/ipv6/mobile_ip6/procrcv.c mipl-0.9.3-hmipv6/linux/net/ipv6/mobile_ip6/procrcv.c --- mipl-0.9.3/linux/net/ipv6/mobile_ip6/procrcv.c Mon Jul 15 16:33:27 2002 +++ mipl-0.9.3-hmipv6/linux/net/ipv6/mobile_ip6/procrcv.c Fri Jul 19 16:40:09 2002 @@ -73,7 +73,7 @@ * these print the contents of several destination options. */ void dump_bu(__u8 opt, __u8 ack, __u8 home, __u8 single, __u8 dad, - __u8 plength, __u8 sequence, __u32 lifetime, + __u8 map, __u8 plength, __u8 sequence, __u32 lifetime, struct mipv6_subopt_info sinfo) { DEBUG((DBG_INFO, "Binding Update Destination Option:")); @@ -87,6 +87,9 @@ DEBUG((DBG_INFO, "Single Address bit is set.")); if (dad) DEBUG((DBG_INFO, "DAD bit is set.")); + if (map) + DEBUG((DBG_INFO, "MAP bit is set.")); + DEBUG((DBG_INFO, "Prefix length: %d", plength)); DEBUG((DBG_INFO, "Sequence number: %d", sequence)); DEBUG((DBG_INFO, "Lifetime: %d", lifetime)); @@ -303,9 +306,10 @@ __u32 maxdelay, int plength, __u16 sequence, struct in6_addr *saddr, struct in6_addr *daddr, struct in6_addr *haddr, struct in6_addr *coa, - int ifindex, int single) + int ifindex, int single, int added_type) { struct in6_addr *reply_addr; + int bcache_type; int err; if (ba_status >= REASON_UNSPECIFIED) { @@ -318,9 +322,39 @@ ba_lifetime = get_min_lifetime(ifp, ba_lifetime); ba_lifetime = mipv6_lifetime_check(ba_lifetime); + /* SHARKEY - Actually, this gets kind of complex. I think + I prefer my previous version! I haven't checked the + logic of which return code goes where yet, so they're + probably wrong. + + ??GREG Hacked second if statement to make sure valid return */ + + bcache_type = mipv6_bcache_exists(haddr, daddr); + if (bcache_type != added_type) { + + if (bcache_type > 0 && bcache_type != CACHE_ENTRY) { + + /* the thing in the cache is some other type + of binding! What should be do? */ + ba_status = REASON_UNSPECIFIED; + reply_addr = saddr; + DEBUG((DBG_INFO, + "%s:mipv6_bu_finish: entry of other type (%d)", + __FILE__, bcache_type)); + + goto out; + } + + if (mipv6_proxy_nd(haddr, ifindex, plength, single) == 0) + DEBUG((DBG_INFO, "%s:bu_finish:proxy_nd succ", + __FILE__)); + else + DEBUG((DBG_WARNING, "%s:bu_finish:proxy_nd fail", + __FILE__)); + } if ((err =mipv6_bcache_add (ifindex, daddr, haddr, coa, ba_lifetime, plength, sequence, - single, HOME_REGISTRATION)) != 0 ) { + single, added_type)) != 0 ) { if (err == -ENOMEDIUM) { if (ifp) in6_ifa_put(ifp); @@ -446,7 +480,7 @@ * request for 'haddr' - reject the BU. */ mipv6_bu_finish(&ifp, DUPLICATE_ADDR_DETECT_FAIL, 0, 0, 0, 0, seq, - &saddr, &daddr, &haddr, &coa, 0, 0); + &saddr, &daddr, &haddr, &coa, 0, 0, 0); return; } @@ -521,6 +555,7 @@ int plength; __u16 sequence; int sin