$Id: ns-233-mobiwan-rfc3775-1.patch 192 2008-05-06 05:59:58Z omehani $
Adapation of the ns-2.32 patch [0] adding more RFC3775 compliance (based on [1])
to ns-2.33.  Olivier Mehani <olivier.mehani@nicta.com.au>.

[0] http://mobqos.ee.unsw.edu.au/~omehani/ns/ns-232-mobiwan-rfc3775.patch
[1] http://www.arcst.whu.edu.cn/center/kongrs/mobiwan_ext.htm
====
diff -urNU5 ns-2.33-mobiwan/mobiwan/ipv6.cc ns-2.33-mobiwan-rfc3775/mobiwan/ipv6.cc
--- ns-2.33-mobiwan/mobiwan/ipv6.cc	2008-05-06 15:13:32.000000000 +1000
+++ ns-2.33-mobiwan-rfc3775/mobiwan/ipv6.cc	2008-05-06 15:13:58.000000000 +1000
@@ -45,10 +45,11 @@
 #include "classifier-hash.h"
 #include "classifier-src.h"
 #include "ipv6.h"
 #include "ipv6-routing.h"
 
+
 // Check if I need the following include
 extern "C" {
 #include <stdarg.h>
 };
 
@@ -87,10 +88,19 @@
 					    sizeof(hdr_rtext)) {
 		bind_offset(&hdr_rtext::offset_);
 	}
 } class_rtexthdr;
 
+int hdr_dstext::offset_;
+static class DstExtHeaderClass : public PacketHeaderClass {
+public:
+        DstExtHeaderClass() : PacketHeaderClass("PacketHeader/Dst",
+					    sizeof(hdr_dstext)) {
+		bind_offset(&hdr_dstext::offset_);
+	}
+} class_dstexthdr;
+
 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Source Routing Extensions.
 // This class inserts a routing header in the packets
 // The Routing Header contains a list of nodes where the packet
 // must transit prior to reaching its final destination.
@@ -104,11 +114,11 @@
 } class_srcrouting;
 
 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Source Routing class definition 
 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-SrcRouting::SrcRouting() : Connector(), node_(0) 
+SrcRouting::SrcRouting() : Connector(), node_(0) ,belong_to_mobile_node_(0)
 {
        bind("port_", &port_);
 }
 
 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -123,11 +133,12 @@
    Tcl& tcl = Tcl::instance();
    hdr_ip* iph = HDR_IP(p);
    hdr_cmn* cmh = HDR_CMN(p);
    hdr_rtext* rth = HDR_ROUTING(p);
 
-   if ( iph->saddr() == node_->address() ) {
+   if ((iph->saddr() == node_->address()) ||
+	(belong_to_mobile_node_ && (iph->saddr() == ((MobileNode*)(node_))->coa()))) {
 
 	// I need to insert an address in the header
 	// Get destination address recorded in Binding Cache:
 	// XXX: should rather access directly to the B Cache,
 	// XXX  instead of calling OTcl.  Change this later. 
@@ -167,24 +178,120 @@
 }
 
 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 int SrcRouting::command(int argc, const char*const* argv)
 {
-   if (argc == 3) {
-      if (strcmp(argv[1], "node") == 0) {
-        node_ = (Node*)TclObject::lookup(argv[2]);
-	if (node_ == 0) {
-           fprintf (stderr, "%s: %s lookup of %s failed\n", __FILE__, argv[1], 
-argv[2]);
-           return TCL_ERROR;
+	if (argc == 3) {
+		if (strcmp(argv[1], "node") == 0) {
+			node_ = (Node*)TclObject::lookup(argv[2]);
+			if (node_ == 0) {
+				fprintf (stderr, "%s: %s lookup of %s failed\n", __FILE__, argv[1], argv[2]);
+				return TCL_ERROR;
+			}
+			return TCL_OK;
+		} else if (strcmp(argv[1], "belong-to-mobile-node") == 0) {
+			belong_to_mobile_node_ = atoi(argv[2]);
+			return TCL_OK;
+		}
+	}
+	return (Connector::command(argc, argv));
+}
+
+
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Destination Option Header Processor
+// Used to process the Home Address Destination Option
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static class DstHeaderClass : public TclClass {
+public:
+        DstHeaderClass() : TclClass("DstHeader") {}
+        TclObject* create(int, const char*const*) {
+                return (new DstHeader());
         }
-        return TCL_OK;
-      }
-   }
-   return (Connector::command(argc, argv));
+} class_dstheader;
+
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Source Routing class definition 
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+DstHeader::DstHeader() : Connector(), node_(0), src_rt_(0), mipagent_(0), belong_to_mobile_node_(0)
+{
+       bind("port_", &port_);
 }
- 
+
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// If local node is the source of the packet, we have to insert
+// the routing header - this also means we have an entry in the
+// Binding Cache corresponding to destination.	
+// XXX:  For now, only tested with one address in the routing header.
+// XXX   Should also work with more than one (to be checked) 
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+void DstHeader::recv(Packet* p, Handler *h)
+{
+//	Tcl& tcl = Tcl::instance();
+	hdr_ip* iph = HDR_IP(p);
+	hdr_cmn* cmh = HDR_CMN(p);
+	hdr_dstext* dsth = HDR_DST(p);
+
+	if ((iph->saddr() == node_->address()) && belong_to_mobile_node_ ) {
+		// here is MN, and the packet will be sent to CN,
+		// home address destination option will be added to the packet
+		int saddr = Address::instance().get_nodeaddr(iph->saddr());
+
+		dsth->actual_src_address = saddr;
+		dsth->actual_dst_port = iph->dport();
+		iph->saddr() = ((MobileNode *)(node_))->coa();
+		iph->dport() = port_;
+		cmh->size() += DST_HDR_SIZE;
+
+		Entry *n = mipagent_->lookup_entry(iph->daddr(), mipagent_->head(mipagent_->bcache_head_));
+		if (n && n->expire() > NOW ) {
+			src_rt_->recv(p,h);
+			return;
+		}
+
+	} else {
+		// here is CN, and the packet was sent by an optimized MN
+		// home address and the actual port will be restored
+		iph->saddr() = dsth->actual_src_address;
+		iph->dport() = dsth->actual_dst_port;
+	} 
+	// Pass packet to next object. 
+	target_->recv(p,h);
+}
+
+int DstHeader::command(int argc, const char*const* argv)
+{
+	if (argc == 3) {
+		if (strcmp(argv[1], "node") == 0) {
+			node_ = (Node*)TclObject::lookup(argv[2]);
+			if (node_ == 0) {
+				fprintf (stderr, "%s: %s lookup of %s failed\n", __FILE__, argv[1], argv[2]);
+				return TCL_ERROR;
+			}
+			return TCL_OK;
+		} else if (strcmp(argv[1], "src-routing") == 0) {
+			src_rt_ = (SrcRouting*)TclObject::lookup(argv[2]);
+			if (src_rt_ == 0) {
+				fprintf (stderr, "%s: %s lookup of %s failed\n", __FILE__, argv[1], argv[2]);
+				return TCL_ERROR;
+			}
+			return TCL_OK;
+		} else if (strcmp(argv[1], "mipagent") == 0) {
+			mipagent_ = (MIPv6Agent*)TclObject::lookup(argv[2]);
+			if (mipagent_ == 0) {
+				fprintf (stderr, "%s: %s lookup of %s failed\n", __FILE__, argv[1], argv[2]);
+				return TCL_ERROR;
+			}
+			return TCL_OK;
+		} else if (strcmp(argv[1], "belong-to-mobile-node") == 0) {
+			belong_to_mobile_node_ = atoi(argv[2]);
+			return TCL_OK;
+		}
+	}
+	return (Connector::command(argc, argv));
+}
+
 // **************************************************************
 // Classification by source address
 // Adapted from classifier-hash.cc
 // **************************************************************
 static class SrcHashClassifierClass : public TclClass {
@@ -418,94 +525,136 @@
 
 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 void
 NetworkMN::recv (Packet * p, Handler *)
 {
-  hdr_ip *iph = HDR_IP(p);
-  hdr_cmn *cmh = HDR_CMN(p);
-  int src = Address::instance().get_nodeaddr(iph->saddr());
-
-  if (src == myaddr_) {
-     // Packet I'm originating
-     if (cmh->num_forwards() != 0) {
-        // I received a packet that I sent.  
-        // Probably  a routing loop.
-	if (print_info_) cout << "\tNetworkMN - Routing Loop - drop\n";
-        drop(p, DROP_RTR_ROUTE_LOOP);
-        return;
-     }
-     else {
-        // set direction of pkt to -1 , i.e downward
-        cmh->direction() = hdr_cmn::DOWN;
-        cmh->prev_hop_ = myaddr_;
-        iph->ttl_ = IP_DEF_TTL;
-                
-        if ( iph->daddr() == IP_BROADCAST) {
-           sendOutBCastPkt(p);
-        }
-        else {
-	   // I am a Mobile IPv6 Node
-	   // Forward DTG to my current base station
-	   if (print_info_) 
-		cout << "\tNetworkMN " << PRINTADDR(myaddr_)
-		<< " from " << PRINTADDR(src)
-		<< " forward to BS " << PRINTADDR(node_->base_stn()) << "\n";
-           
-           cmh->addr_type_ = NS_AF_INET;
-           cmh->xmit_failure_ = mac_callback;
-           cmh->xmit_failure_data_ = this;
-	   cmh->next_hop_ = node_->base_stn();
-           assert (!HDR_CMN (p)->xmit_failure_ ||
-                HDR_CMN (p)->xmit_failure_ == mac_callback);
-           target_->recv(p, (Handler *)0);
-        }
-     }  
-  } 
-  else {
-        // Packet I receive
-   	if (print_info_) {
-		cout << "\tNetworkMN " << PRINTADDR(myaddr_)
-		<< " from " << PRINTADDR(src) << " to " 
-		<< PRINTADDR(iph->daddr());
-   	} 
-
-        if (--iph->ttl_ == 0) {
-           // Packet I'm forwarding...   
-           // Check the TTL.  If it is zero, then discard.
-	   if (print_info_) cout << " - TTL expired - drop\n";
-           drop(p, DROP_RTR_TTL);
-           return;
-        } 
-        else  if ((u_int32_t) iph->daddr() == IP_BROADCAST) {
-           // Broadcast that I receive 
-	   // (Likely a Router Advertisement)
-           // hand it over to the port-demux
-	   if (print_info_) cout << " - receiving BROADCAST\n";
-           port_dmux_->recv(p, (Handler*)0);
-           }
-        else {
-	   // DTG for myself
-	   // Probably a packet with destination = COA (with routing header 
-	   // or encapsulation) otherwise may have not reach here 
-	   if (print_info_) cout << " - receiving DTG " << cmh->ptype_ <<"\n";
-
-	   // If it comes encapsulated, we may want to send BU to 
-	   // src addr in the encapsulated header.  We add the 
-	   // source in the Binding List.
-	   // XXX: not very cool: we check inside header before
-	   // packet is effectively decapsulated ... 
-	   if ( iph->dport() == decap_port_ ) {
-	      hdr_ipinip **ppinhdr = (hdr_ipinip **)hdr_ipinip::access(p);
-	      hdr_ip *pinhdr = &(*ppinhdr)->hdr_;
-	      mipagent_->add_bulist(pinhdr->saddr(), BU_CN, ON);
-	   } else {
-	      mipagent_->add_bulist(iph->saddr(), BU_CN, ON);
-	   } 
-	   port_dmux_->recv(p, (Handler*)0);
-        }
-  }
-return;
+ 	hdr_ip *iph = HDR_IP(p);
+ 	hdr_mipv6 *miph = HDR_MIPv6(p);
+ 	hdr_cmn *cmh = HDR_CMN(p);
+ 	hdr_rtext *rth = HDR_ROUTING(p);
+ 	int src = Address::instance().get_nodeaddr(iph->saddr());
+ 
+ 	if ((src == myaddr_)||(src == node_->coa())
+ 		||((src == 0)&&(miph->haddr() == node_->address()))) {
+ 		// Packet I'm originating
+ 		if (cmh->num_forwards() != 0) {
+ 			// I received a packet that I sent.  
+ 			// Probably  a routing loop.
+ 			if (print_info_) cout << "\tNetworkMN - Routing Loop - drop\n";
+ 			drop(p, DROP_RTR_ROUTE_LOOP);
+ 			return;
+ 		}
+ 		else {
+ 			// set direction of pkt to -1 , i.e downward
+ 			cmh->direction() = hdr_cmn::DOWN;
+ 			cmh->prev_hop_ = myaddr_;
+ 			iph->ttl_ = IP_DEF_TTL;
+ 					
+ 			if ( iph->daddr() == IP_BROADCAST) {
+ 				sendOutBCastPkt(p);
+ 			}
+ 			else {
+ 				// I am a Mobile IPv6 Node
+ 				// Forward DTG to my current base station
+ 				if (print_info_) 
+ 				cout << "\tNetworkMN " << PRINTADDR(myaddr_)
+ 					<< " from " << PRINTADDR(src)
+ 					<< " forward to BS " << PRINTADDR(node_->base_stn()) << "\n";
+ 
+ 				if ((cmh->ptype_ != PT_BU) && (cmh->ptype_ != PT_BACK)) {
+ 					if ( iph->dport() == decap_port_ ) {
+ 						hdr_ipinip **ppinhdr = (hdr_ipinip **)hdr_ipinip::access(p);
+ 						hdr_ip *pinhdr = &(*ppinhdr)->hdr_;
+ 						if (pinhdr->dport() == src_rt_port_) {
+ 							mipagent_->add_bulist(rth->nexthop_->dst_.addr_, BU_CN, ON);
+ 						} else {
+ 							mipagent_->add_bulist(pinhdr->daddr(), BU_CN, ON);
+ 						}
+ 	
+ 					} else if (iph->dport() == src_rt_port_) {
+ 						mipagent_->add_bulist(rth->nexthop_->dst_.addr_, BU_CN, ON);
+ 
+ 					} else {
+ 						mipagent_->add_bulist(iph->daddr(), BU_CN, ON);
+ 					}
+ 				}
+ 
+ 				cmh->addr_type_ = NS_AF_INET;
+ 				cmh->xmit_failure_ = mac_callback;
+ 				cmh->xmit_failure_data_ = this;
+ 				cmh->next_hop_ = node_->base_stn();
+ 				assert (!HDR_CMN (p)->xmit_failure_ ||
+ 						HDR_CMN (p)->xmit_failure_ == mac_callback);
+ 				target_->recv(p, (Handler *)0);
+ 			}
+ 		}
+ 	}
+ 	else {
+ 		// Packet I receive
+ 		if (print_info_) {
+ 			cout << "\tNetworkMN " << PRINTADDR(myaddr_)
+ 			<< " from " << PRINTADDR(src) << " to " 
+ 			<< PRINTADDR(iph->daddr());
+ 		}
+ 
+ 		if (--iph->ttl_ == 0) {
+ 			// Packet I'm forwarding...   
+ 			// Check the TTL.  If it is zero, then discard.
+ 			if (print_info_) cout << " - TTL expired - drop\n";
+ 			drop(p, DROP_RTR_TTL);
+ 			return;
+ 		} 
+ 		else if ((u_int32_t) iph->daddr() == IP_BROADCAST) {
+ 			// Broadcast that I receive 
+ 			// (Likely a Router Advertisement)
+ 			// hand it over to the port-demux
+ 			if (print_info_) cout << " - receiving BROADCAST\n";
+ 			port_dmux_->recv(p, (Handler*)0);
+ 		}
+ 		else if (iph->daddr() == node_->coa()) {
+ 			if (print_info_) cout << " - receiving DTG " << cmh->ptype_ <<"\n";
+ 
+ 			// If it comes encapsulated, we may want to send BU to 
+ 			// src addr in the encapsulated header.  We add the 
+ 			// source in the Binding List.
+ 			// XXX: not very cool: we check inside header before
+ 			// packet is effectively decapsulated ... 
+ 			if ((cmh->ptype_ != PT_BU) && (cmh->ptype_ != PT_BACK)) {
+ 				if ( iph->dport() == decap_port_ ) {
+ 					hdr_ipinip **ppinhdr = (hdr_ipinip **)hdr_ipinip::access(p);
+ 					hdr_ip *pinhdr = &(*ppinhdr)->hdr_;
+ 					if (pinhdr->dport() == dest_hdr_port_) {
+ 						hdr_dstext *dsth = HDR_DST(p);
+ 						mipagent_->add_bulist(dsth->actual_src_address, BU_CN, ON);
+ 					} else {
+ 						mipagent_->add_bulist(pinhdr->saddr(), BU_CN, ON);
+ 					}
+ 
+ 				} else if (iph->dport() == dest_hdr_port_) {
+ 					hdr_dstext *dsth = HDR_DST(p);
+ 					mipagent_->add_bulist(dsth->actual_src_address, BU_CN, ON);
+ 
+ 				} else if ((iph->dport() == src_rt_port_) && (rth->nexthop_->dst_.port_ == dest_hdr_port_)) {
+ 					// in this case, it means the correspondent is another MN,
+ 					// and both MNs have set up optimization with each other,
+ 					// thus we should find the HoA of the correspondent first,
+ 					// and add its HoA into the bulist.
+ 					hdr_dstext *dsth = HDR_DST(p);
+ 					mipagent_->add_bulist(dsth->actual_src_address, BU_CN, ON);
+ 
+ 				} else {
+ 					mipagent_->add_bulist(iph->saddr(), BU_CN, ON);
+ 				}
+ 			}
+ 			port_dmux_->recv(p, (Handler*)0);
+ 		}
+ 		else {
+ 			//No! Impossible!
+ 			Packet::free(p);
+ 		}
+ 	}
+ 	return;
 }
 
 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 int NetworkMN::command (int argc, const char *const *argv)
 {
@@ -516,10 +665,18 @@
      }
      if (strcmp(argv[1], "decap-port") == 0) {
         decap_port_ = atoi(argv[2]); 
         return TCL_OK;
      }
+     if (strcmp(argv[1], "dest-hdr-port") == 0) {
+        dest_hdr_port_ = atoi(argv[2]);
+        return TCL_OK;
+     }
+     if (strcmp(argv[1], "src-rt-port") == 0) {
+        src_rt_port_ = atoi(argv[2]);
+        return TCL_OK;
+     }
   }
   return (NetworkAgent::command (argc, argv));
   
 }
 
diff -urNU5 ns-2.33-mobiwan/mobiwan/ipv6.h ns-2.33-mobiwan-rfc3775/mobiwan/ipv6.h
--- ns-2.33-mobiwan/mobiwan/ipv6.h	2008-05-06 15:13:32.000000000 +1000
+++ ns-2.33-mobiwan-rfc3775/mobiwan/ipv6.h	2008-05-06 15:13:58.000000000 +1000
@@ -82,17 +82,18 @@
 // **************************************************************************
 // IPv6 Routing Header
 // **************************************************************************
 #define ROUTE_HDR_SIZE		16
 #define IPv6_RTHDR_SIZE(n)	16 * n +8 
+#define DST_HDR_SIZE		20
 
 // Multiple hops OK
 typedef struct ns_hop_list {
 	ns_addr_t       dst_;	
 	struct ns_hop_list *next_;
 } ns_hop;
-	
+
 #define HDR_ROUTING(p)	((struct hdr_rtext*)(p)->access(hdr_rtext::offset_))
 struct hdr_rtext {
 	ns_hop *nexthop_;    // Next hop, not "next header"	
 	int nb_;
 	static int offset_;
@@ -102,10 +103,21 @@
                 return (hdr_rtext*) p->access(offset_);
         }
 	inline int& nb() { return nb_ ; }
 };
 
+#define HDR_DST(p)	((struct hdr_dstext*)(p)->access(hdr_dstext::offset_))
+struct hdr_dstext {
+	int actual_src_address;
+	int actual_dst_port;
+	static int offset_;
+        inline static int& offset() { return offset_; }
+
+	inline static hdr_dstext* access(Packet* p) {
+                return (hdr_dstext*) p->access(offset_);
+        }
+};
 
 // >----------------------------------------------------------------------<
 // >                          Network Agent                               <
 // >----------------------------------------------------------------------<
 // taken from dsdv agent
@@ -145,10 +157,12 @@
 
 protected:
   virtual void recv(Packet *, Handler *);
   MNAgent *mipagent_;
   int decap_port_;
+  int dest_hdr_port_;
+  int src_rt_port_;
   int off_ipinip_;
 };
 
 #endif
 
diff -urNU5 ns-2.33-mobiwan/mobiwan/ipv6-routing.h ns-2.33-mobiwan-rfc3775/mobiwan/ipv6-routing.h
--- ns-2.33-mobiwan/mobiwan/ipv6-routing.h	2008-05-06 15:13:32.000000000 +1000
+++ ns-2.33-mobiwan-rfc3775/mobiwan/ipv6-routing.h	2008-05-06 15:13:58.000000000 +1000
@@ -41,12 +41,27 @@
         void recv(Packet *p, Handler *h);
 protected:
 	int command(int argc, const char*const*argv);
 	int port_;
 	Node *node_;
+	int belong_to_mobile_node_;
   //   	int mask_;
   // 	int shift_;
   //   	int off_ip_;
   //   	int off_ipinip_;
 };
 
 
+// Destination Option Header Processor
+class DstHeader : public Connector {
+public:
+        DstHeader();
+        void recv(Packet *p, Handler *h);
+protected:
+	int command(int argc, const char*const*argv);
+	int port_;
+	Node *node_;
+	SrcRouting *src_rt_;
+	MIPv6Agent *mipagent_;
+	int belong_to_mobile_node_;
+};
+
diff -urNU5 ns-2.33-mobiwan/mobiwan/mipv6.cc ns-2.33-mobiwan-rfc3775/mobiwan/mipv6.cc
--- ns-2.33-mobiwan/mobiwan/mipv6.cc	2008-05-06 15:13:32.000000000 +1000
+++ ns-2.33-mobiwan-rfc3775/mobiwan/mipv6.cc	2008-05-06 15:13:58.000000000 +1000
@@ -86,11 +86,11 @@
         }
 } class_mipv6agent;
 
 
 MIPv6Agent::MIPv6Agent() : Agent(PT_UDP), bcast_target_(0), timer_(this),
-beacon_(1.0), print_info_(0)
+bs_beacon_(1.0), print_info_(0)
 {
 	// Binding Cache - mostly to collect statistics
         LIST_INIT(&bcache_head_);
         
 	bind("print_info_", &print_info_);
@@ -100,41 +100,68 @@
 // Recipient may altrenatively be a Base Station, a Home Agent, or a 
 // simple Correspondent Node
 // *************************************************************************
 void MIPv6Agent::recv(Packet* p, Handler *)
 {
-   hdr_mipv6 *miph = HDR_MIPv6(p);
-   hdr_cmn *hdrc = HDR_CMN(p);
-   //printf("MIPv^AGENT:recv at %s\n", name());
-   switch (hdrc->ptype()) {
-      case PT_BU:
-          if (miph->H() == ON) {
-	     // Home Registration
-	     // XXX: No distinction in the simulation
-	     strcpy( node_info_, "HA");
-	     mn_registration(p);
-	  } else
-	     mn_registration(p);
-	  break;
-
-      case PT_SOL:
-	  // Process Solicitations from MN
-	  send_ads();
-	  timer_.resched(Random::uniform(0, beacon_));
-	  //timer_.resched(beacon_);
-	  break;
-
-      case PT_RADS:
- 	  // Advertisement from other BSs.  Just ignore
-	  break;
-
-      default:
-	  fprintf(stderr, "%s received packet with wrong type\n", node_info_);
-	  // exit(1); 
-	  break;
+	hdr_mipv6 *miph = HDR_MIPv6(p);
+	hdr_ip *iph = HDR_IP(p);
+	hdr_cmn *hdrc = HDR_CMN(p);
+	//printf("MIPv^AGENT:recv at %s\n", name());
+	switch (hdrc->ptype()) {
+		case PT_BU:
+			switch (miph->type())
+			{
+				case HoTI: {
+					Packet *hot = p->copy();
+					HDR_CMN(hot)->num_forwards() = 0;
+					HDR_IP(hot)->daddr() = iph->saddr();
+					HDR_IP(hot)->saddr() = iph->daddr();
+					HDR_MIPv6(hot)->type() = HoT;
+					send_packet(hot);
+					break;
+				}
+				case CoTI: {
+					Packet *cot = p->copy();
+					HDR_CMN(cot)->num_forwards() = 0;
+					HDR_IP(cot)->daddr() = iph->saddr();
+					HDR_IP(cot)->saddr() = iph->daddr();
+					HDR_MIPv6(cot)->type() = CoT;
+					send_packet(cot);
+					break;
+				}
+				case BU:
+					if (miph->H() == ON) {
+						// Home Registration
+						// XXX: No distinction in the simulation
+						strcpy( node_info_, "HA");
+						mn_registration(p, ON);
+					} else
+						mn_registration(p, OFF);
+					break;
+				default:
+					break;
+			}
+			break;
+
+		case PT_SOL:
+			// Process Solicitations from MN
+			send_ads();
+			if (timer_.status() == TIMER_PENDING) timer_.cancel();
+			timer_.resched(Random::uniform(0, bs_beacon_));
+			//timer_.resched(beacon_);
+			break;
+
+		case PT_RADS:
+			// Advertisement from other BSs.  Just ignore
+			break;
+
+		default:
+			fprintf(stderr, "%s received packet with wrong type\n", node_info_);
+			// exit(1); 
+			break;
 	}
-   Packet::free(p);
+	Packet::free(p);
 }
 
 // *************************************************************************
 // Send the Mobile IPv6 Packet  
 // *************************************************************************
@@ -169,14 +196,14 @@
 // *************************************************************************
 // XXX: temporary.
 // Encapsulator should make use of Binding Cache.  This still require
 // some modification.  Will do it later.
 // *************************************************************************
-void MIPv6Agent::encap_route(int fromaddr, int toaddr, double lft)
+void MIPv6Agent::encap_route(int home_reg, int fromaddr, int toaddr, double lft)
 {
-   Tcl& tcl = Tcl::instance();
-   tcl.evalf("%s encap-route %d %d %lf", name_, fromaddr, toaddr, lft);
+	Tcl& tcl = Tcl::instance();
+	tcl.evalf("%s encap-route %d %d %d %lf", name_, home_reg, fromaddr, toaddr, lft);
 }
 
 // *************************************************************************
 // *************************************************************************
 void MIPv6Agent::delete_route(int addr) 
@@ -199,60 +226,63 @@
 // *************************************************************************
 // CN or former default router (previous BS) is instructed 
 // to redirect DTG towards current COA
 // If CoA = Home Address, this is a de-registration (probably back to home)
 // *************************************************************************
-void MIPv6Agent::mn_registration(Packet *p)
+void MIPv6Agent::mn_registration(Packet *p, int home_reg)
 {
-   hdr_mipv6 *miph = HDR_MIPv6(p);
+	hdr_mipv6 *miph = HDR_MIPv6(p);
 
-   if (miph->coa() == miph->haddr()) { 
-     // De-registration 
-     print_info(p, '-', "DEREG");
-     update_bcache(p, OFF);
-   }
-   else {
-     // Registration 
-     print_info(p, '-', "REG");
-     update_bcache(p, ON);
-   }    
-   if (miph->A() == ON)
-	send_ack(p);
+	if (miph->coa() == miph->haddr()) { 
+		// De-registration
+		print_info(p, '-', "DEREG");
+		update_bcache(p, home_reg, OFF);
+	}
+	else {
+		// Registration
+		print_info(p, '-', "REG");
+		update_bcache(p, home_reg, ON);
+	}
+	if (miph->A() == ON)
+		send_ack(p, home_reg);
 }
 
 // *************************************************************************
 // *************************************************************************
-void MIPv6Agent::send_ack(Packet *p)
+void MIPv6Agent::send_ack(Packet *p, int home_reg)
 {
    hdr_mipv6 *miph = HDR_MIPv6(p);
-   send_packet(set_ack_packet(miph->haddr(), miph->coa(), miph->seqno()));
+   send_packet(set_ack_packet(miph->haddr(), miph->coa(), miph->seqno(), home_reg));
 }
 
 // *************************************************************************
 // Set the packet containing the Binding Acknowledgment
 // *************************************************************************
-Packet* MIPv6Agent::set_ack_packet(int final_dst, int via_hop, int seqno)
+Packet* MIPv6Agent::set_ack_packet(int final_dst, int via_hop, int seqno, int home_reg)
 {
-   Packet *p = allocpkt();
-   set_ipv6_hdr(p, final_dst);   
-   set_back_hdr(p, seqno);     
-   return(p);
+	Packet *p = allocpkt();
+	set_ipv6_hdr(p, final_dst);   
+	hdr_ip *iph = HDR_IP(p);
+	iph->daddr() = via_hop;
+	set_back_hdr(p, seqno, home_reg);
+	return(p);
 }
 
 // *************************************************************************
 // Fill the Binding Acknowledgment Option
 // *************************************************************************
-void MIPv6Agent::set_back_hdr(Packet *p, int seqno)
+void MIPv6Agent::set_back_hdr(Packet *p, int seqno, int home_reg)
 {
-   hdr_mipv6 *h = HDR_MIPv6(p);
-   hdr_cmn *hdrc = HDR_CMN(p);
+	hdr_mipv6 *h = HDR_MIPv6(p);
+	hdr_cmn *hdrc = HDR_CMN(p);
 
-   hdrc->size() += BACK_SIZE;
-   hdrc->ptype() = PT_BACK;
-   h->type() = BACK;
-   h->seqno() = seqno;
-   h->lifetime() = 0; 
+	hdrc->size() += BACK_SIZE;
+	hdrc->ptype() = PT_BACK;
+	h->type() = BACK;
+	h->seqno() = seqno;
+	h->H() = home_reg;
+	h->lifetime() = 0; 
 }
 
 // *************************************************************************
 // Fill the IPv6 header
 // *************************************************************************
@@ -366,29 +396,30 @@
 // Add a new node in the Binding Cache
 // XXX: Binding Cache should be used by Encapsulator and Decapsulator objects
 // XXX  direclly - this will be added later.
 // XXX  Now, Binding Cahce is only used to dump what is received by a node 
 // *************************************************************************
-Entry* MIPv6Agent::update_bcache(Packet *p, int flag)
+Entry* MIPv6Agent::update_bcache(Packet *p, int home_reg, int flag)
 {
-   hdr_mipv6 *h = HDR_MIPv6(p);
+	hdr_mipv6 *h = HDR_MIPv6(p);
 
-   // Check if an entry does already exists for the source address
-   Entry *n = lookup_entry(h->haddr(), head(bcache_head_));
+	// Check if an entry does already exists for the source address
+	Entry *n = lookup_entry(h->haddr(), head(bcache_head_));
 
-   if ( !n ) {
-      n = new Entry(h->haddr(), BU_MN, flag);
-      n->insert_entry(&bcache_head_);
-   }
+	if ( !n ) {
+		n = new Entry(h->haddr(), BU_MN, flag);
+		n->insert_entry(&bcache_head_);
+	}
 
-   if ( flag == ON )
-     encap_route(h->haddr(), h->coa(), h->lifetime());
-   else 
-     delete_route(h->haddr());
-   n->update_entry(h->seqno(), h->haddr(), h->coa(), NOW, h->lifetime());
-   
-   return n;
+	if ( flag == ON )
+		encap_route(home_reg, h->haddr(), h->coa(), h->lifetime());
+	else 
+		delete_route(h->haddr());
+
+	n->update_entry(h->seqno(), h->haddr(), h->coa(), NOW, h->lifetime());
+
+	return n;
 }
 
 // *************************************************************************
 // >----------------------------------------------------------------------<
 // MIPv6 Base Stations and Home Agent
@@ -412,11 +443,11 @@
 
 // *************************************************************************
 void BSAgent::timeout(int )
 {
 	send_ads();
-	timer_.resched(Random::uniform(0, beacon_));
+	timer_.resched(Random::uniform(0, bs_beacon_));
 	//timer_.resched(beacon_);
 }
 
 // *************************************************************************
 int BSAgent::command(int argc, const char*const* argv)
@@ -425,26 +456,26 @@
 		if (strcmp(argv[1], "stop-beacon") == 0) {
 			timer_.cancel();
 			return TCL_OK;
 		}
 		else if (strcmp(argv[1], "start-beacon") == 0) {
-			timer_.resched(Random::uniform(0, beacon_));
+			timer_.resched(Random::uniform(0, bs_beacon_));
 			return TCL_OK;
 		}
       		else if (strcmp(argv[1], "dump") == 0) {
 			dump();
 			return TCL_OK;
 		}
 	}
 	if (argc == 3) {
 		if (strcmp(argv[1], "set-beacon-period") == 0) {
-			beacon_ = atof(argv[2]);
+			bs_beacon_ = atof(argv[2]);
 			return TCL_OK;
 		}
 		if (strcmp(argv[1], "beacon-period") == 0) {
-			beacon_ = atof(argv[2]);
-			timer_.resched(Random::uniform(0, beacon_));
+			bs_beacon_ = atof(argv[2]);
+			timer_.resched(Random::uniform(0, bs_beacon_));
 			return TCL_OK;
 		}
 		if (strcmp(argv[1], "ragent") == 0) {
 		  	ragent_ = (NsObject *)TclObject::lookup(argv[2]);
 			return TCL_OK;
@@ -504,15 +535,15 @@
 
 // *************************************************************************
 // MNAgent Creator
 // *************************************************************************
 MNAgent::MNAgent() : MIPv6Agent(), ha_(NONE), bs_(NONE), oldbs_(NONE),
-	coa_(NONE), oldcoa_(NONE), coalost_(TRUE), nbu_(0),
+	coa_(NONE), oldcoa_(NONE), coalost_(TRUE), nbu_(0), 
 	reglftm_(~0), adlftm_(0.0), node_ (0), bu_policy_(DEF_BU), 
 	rt_opti_(1), bs_forwarding_(1), decap_port_(-1), 
 	bslist_timer_(this), bu_timer_(this)
-{	
+{
 	// Binding Update List Management 
         LIST_INIT(&bulist_head_);
 
 	// List of Base Station
 	LIST_INIT(&bslist_head_);
@@ -532,70 +563,139 @@
 // *************************************************************************
 // MNAgent Recv
 // *************************************************************************
 void MNAgent::recv(Packet* p, Handler *)
 {
-   hdr_cmn *hdrc = HDR_CMN(p);
-   hdr_ip *iph = HDR_IP(p);
-
-   if (print_info_) 
-	cout << "- " << node_info_ << " "  <<  MYNUM << " at " << NOW 
-	<< " from " << PRINTADDR(iph->saddr());
- 
-   if (iph->dport() == port() ) {
-     // This packet is intended for MIPv6 specifically
-
-     switch (hdrc->ptype()) {
-      case PT_RADS:
-	   if (print_info_) cout << " -- Router ADS";
-	recv_ads(p);
-	   if (print_info_) cout << "\n";
-	Packet::free(p);
-	break;
-
-      case PT_BU:
-	   if (print_info_) cout << " -- BU\n";
-	// fprintf(stderr, "MIPv6 MN: processing BU from another MN not yet implemented");
-	cout << NOW << " MIPv6 MN: processing BU from another MN not yet implemented\n";
-
-//	exit(1);
-	// recv_bu(p);
-	Packet::free(p);
-	break;
+	hdr_cmn *hdrc = HDR_CMN(p);
+	hdr_ip *iph = HDR_IP(p);
+	hdr_mipv6 *mipv6h = HDR_MIPv6(p);
 
-      case PT_BACK:
-	   if (print_info_) cout << " -- BACK\n";
-	recv_back(p);
-	Packet::free(p);
-	break;
+	Entry *n, *m;
 
-      case PT_BREQ:
-	   if (print_info_) cout << " -- BREQ\n";
-	// recv_breq(p);
-	fprintf(stderr, "MIPv6: BINDING REQUEST not yet implemented");
-	exit(1);
-	Packet::free(p);
-	break;
+	if (print_info_) 
+		cout << "- " << node_info_ << " "  <<  MYNUM << " at " << NOW 
+		<< " from " << PRINTADDR(iph->saddr());
 
-      case PT_SOL:
-           // Recv Solicitation from an other MN - discard   
-           Packet::free(p);
-           break;
+	if (iph->dport() == port() ) {
+		// This packet is intended for MIPv6 specifically
 
-      default:
-	fprintf(stderr, "MIPv6: Packet Type %d not supported\n", hdrc->ptype());
-	Packet::free(p);
-	break;
-     } // switch
-
-   } else {
-        // XXX Once we add piggybacking, this should be processed here.
-        // Keep forwarding this packet
+		switch (hdrc->ptype()) {
+			case PT_RADS:
+				if (print_info_) cout << " -- Router ADS";
+				recv_ads(p);
+				if (print_info_) cout << "\n";
+				Packet::free(p);
+				break;
+
+			case PT_BU:
+				if (print_info_) cout << " -- BU\n";
+
+				switch (mipv6h->type())
+				{
+					case HoTI: {
+						Packet *hot = p->copy();
+						HDR_CMN(hot)->num_forwards() = 0;
+						HDR_IP(hot)->daddr() = iph->saddr();
+						HDR_IP(hot)->saddr() = iph->daddr();
+						HDR_MIPv6(hot)->type() = HoT;
+						send_packet(hot);
+						break;
+					}
+					case CoTI: {
+						Packet *cot = p->copy();
+						HDR_CMN(cot)->num_forwards() = 0;
+						HDR_IP(cot)->daddr() = iph->saddr();
+						HDR_IP(cot)->saddr() = iph->daddr();
+						HDR_MIPv6(cot)->type() = CoT;
+						send_packet(cot);
+						break;
+					}
+					case HoT:
+						cout << NOW << " HoT received\n";
+						n = lookup_entry(iph->saddr(), head(bulist_head_));
+						if (n->seqno == mipv6h->seqno()) {
+							n->binding_stage |= CN_OPT_HoT;
+						}
+						if ((n->binding_stage & CN_OPT_HoT) && (n->binding_stage & CN_OPT_CoT)) {
+							cout << NOW << " Send BU to CN\n";
+							send_bu(BU_CN, n->addr);
+							n->binding_stage = CN_OPT_BU;
+						}
+						break;
+
+					case CoT:
+						cout << NOW << " CoT received\n";
+						n = lookup_entry(iph->saddr(), head(bulist_head_));
+						if (n->seqno == mipv6h->seqno()) {
+							n->binding_stage |= CN_OPT_CoT;
+						}
+						if ((n->binding_stage & CN_OPT_HoT) && (n->binding_stage & CN_OPT_CoT)) {
+							cout << NOW << " Send BU to CN\n";
+							send_bu(BU_CN, n->addr);
+							n->binding_stage = CN_OPT_BU;
+						}
+						break;
+
+					case BU: {
+						Tcl& tcl = Tcl::instance();
+						tcl.evalf("%s set-tunnel-exit %d %d", name_, mipv6h->haddr(), mipv6h->coa());
+
+						n = lookup_entry(mipv6h->haddr(), head(bcache_head_));
+						if (!n || n->expire() < NOW) {
+							if (!n) {
+								n = new Entry(mipv6h->haddr(), BU_MN, ON);
+								n->insert_entry(&bcache_head_);
+							}
+
+							m = lookup_entry(mipv6h->haddr(), head(bulist_head_));
+							if (!m || m->binding_stage != CN_OPT_BACK) {
+								tcl.evalf("%s bind-as-cn %d", name_, mipv6h->haddr());
+							}
+						}
+						if (mipv6h->A() == ON) send_ack(p, OFF);
+						n->update_entry(mipv6h->seqno(), mipv6h->haddr(), mipv6h->coa(), NOW, mipv6h->lifetime());
+						break;
+					}
+					default:
+						break;
+				}
+
+				Packet::free(p);
+				break;
+
+			case PT_BACK:
+				if (print_info_) cout << " -- BACK\n";
+				recv_back(p);
+				Packet::free(p);
+				break;
+
+			case PT_BREQ:
+				if (print_info_) cout << " -- BREQ\n";
+				// recv_breq(p);
+				fprintf(stderr, "MIPv6: BINDING REQUEST not yet implemented");
+				exit(1);
+				Packet::free(p);
+				break;
+
+			case PT_SOL:
+				// Recv Solicitation from an other MN - discard   
+				Packet::free(p);
+				break;
+
+			default:
+				fprintf(stderr, "MIPv6: Packet Type %d not supported\n", hdrc->ptype());
+				Packet::free(p);
+				break;
+		} // switch
+
+	} else {
+		// XXX Once we add piggybacking, this should be processed here.
+		// Keep forwarding this packet
 	// send(p, 0);
 	fprintf(stderr, "Piggybacking not yet supported\n");
 	Packet::free(p);
-   }
+	}
 }
 
 // *************************************************************************
 // If we received an encapsulated packet, we probably need to send a BU 
 // to sender because it doesn't have the careof-address.
@@ -615,161 +715,303 @@
 // Stop sending BUs if we are back to home and ACK from HA for the right CoA
 // XXX: should do it on a per CN or HA basis, not for everyone.  
 // *************************************************************************
 void MNAgent::recv_back(Packet *p)
 { 
-   hdr_mipv6 *miph = HDR_MIPv6(p);
-   hdr_ip *iph = HDR_IP(p);
+	hdr_mipv6 *miph = HDR_MIPv6(p);
+	hdr_ip *iph = HDR_IP(p);
+
+	Entry *n = lookup_entry(iph->saddr(), head(bulist_head_));
 
-   Entry *n = lookup_entry(iph->saddr(), head(bulist_head_));
-   if ( n != NULL ) {
-      if ( n->seqno == miph->seqno() && n->caddr == coa_ && iph->saddr() == ha_ && coa_ == HADDR) { 
-	if (bu_timer_.status() == TIMER_PENDING) {
-		bu_timer_.cancel();
+	if ( n == NULL ) return;
+	if ( n->seqno != miph->seqno() || n->caddr != coa_ ) return;
+
+	if (coa_ == HADDR && iph->saddr() == ha_) {					//just go back home
+
+		Entry *entry = head(bulist_head_); 
+		for ( ; entry; entry = entry->next_entry()) {
+			if (entry->type == BU_HA) {
+				entry->binding_stage = HA_TUNNEL_LOST;
+			} else if (entry->type == BU_CN) {
+				entry->binding_stage = CN_OPT_INIT;
+			}
+		}
+		// we don't have to configure the src_classifier_ now, because
+		// this work has been done before sending BU_HA. see reg_new_coa().
+		// Tcl& tcl = Tcl::instance();
+		// tcl.evalf("%s go-back-home %d", name_, HADDR);
+
+	} else if ( miph->H() ) {				//roaming, just finished or refreshed home reg
+
+		if (n->binding_stage == HA_TUNNEL_BU) {		// just finished home reg
+			Tcl& tcl = Tcl::instance();
+			tcl.evalf("%s finish-home-reg %d", name_, HADDR);
+
+			n->binding_stage = HA_TUNNEL_BACK;
+			if ( rt_opti_ ) {
+				Entry *entry = head(bulist_head_);
+				for ( ; entry; entry = entry->next_entry()) {
+					if (entry->type == BU_CN) {
+						if (entry->binding_stage == CN_OPT_INIT) {
+							return_routability(entry->addr);
+							entry->binding_stage = CN_OPT_TEST_INIT;
+						}
+					}
+				}
+			}
+			if ( bs_forwarding_) send_bu(BU_BS, oldbs_);
+		}
+
+	} else {								//roaming, just finished or refreshed crspondnt reg
+		if (n->binding_stage == CN_OPT_BU) {
+			Tcl& tcl = Tcl::instance();
+			tcl.evalf("%s bind-as-mn %d", name_, iph->saddr());
+			n->binding_stage = CN_OPT_BACK;
+		}
 	}
-      }
-   }
 }
 
 // *************************************************************************
 // Processing of Router Advertisement
 // *************************************************************************
 void MNAgent::recv_ads(Packet *p)
 {
-   hdr_ip *iph = HDR_IP(p);
-   hdr_rtads *rh = HDR_RTADS(p);
+	hdr_ip *iph = HDR_IP(p);
+	hdr_rtads *rh = HDR_RTADS(p);
 
-   // We search in list of BSs to check if we know about this BS
-   Entry *node = lookup_entry(iph->saddr(), head(bslist_head_));
-   if ( node ) { 
-      // We already have this BS in the list - Reset its expire time 
-      // No need to send BU 
-
-      node->update_entry(NONE, iph->saddr(), NONE, NOW, rh->lifetime());
-
-   } else { 
-      // New ads.  This BS is not yet recorded in our BS list
-      // Record it in front of list. This BS will become current BS
-      // We need a new COA on the BS's subnet and we need 
-      // to register BS in list and new binding with HA / CN.
-      
-      if (print_info_) cout << " ***  new BS ***"; 
-      Entry *pbs = add_bs(iph->saddr());
-
-      // XXX: I should send a request to obtain a COA 
-      pbs->update_entry(NONE, NONE, get_coa(iph->saddr()), NOW, rh->lifetime());
-      coalost_ = TRUE;
-      reg();
-   }
+	// We search in list of BSs to check if we know about this BS
+	Entry *node = lookup_entry(iph->saddr(), head(bslist_head_));
+	if ( node ) {
+		// We already have this BS in the list - Reset its expire time 
+		// No need to send BU 
+
+		node->update_entry(NONE, iph->saddr(), NONE, NOW, rh->lifetime());
+
+	} else {
+		// New ads.  This BS is not yet recorded in our BS list
+		// Record it in front of list. This BS will become current BS
+		// We need a new COA on the BS's subnet and we need 
+		// to register BS in list and new binding with HA / CN.
+
+		if (print_info_) cout << " ***  new BS ***"; 
+		Entry *pbs = add_bs(iph->saddr());
+
+		// XXX: I should send a request to obtain a COA 
+		pbs->update_entry(NONE, NONE, get_coa(iph->saddr()), NOW, rh->lifetime());
+	}
 }
 
 // *************************************************************************
 // Timer
 // *************************************************************************
 void MNAgent::timeout(int tno)
 {
-   switch (tno) {
-   case MIP_TIMER_BU:
-	// Happens if no BU sent during max_rate_ or slow_rate interval
-	if (print_info_) 
-	   cout << "* MN " << MYNUM << " Timer BU " 
-		<< max_rate_ << " expired at " << NOW << "\n";
-	reg();
-	break;
-
-   case MIP_TIMER_BSLIST: {
-	// Check expiration time for each BS
-	// If expired, delete it since no ads for too long
-	// If this is the current BS, register with a new one.
+	switch (tno) {
+		case MIP_TIMER_BU: {
+			// Happens if no BU sent during max_rate_ or slow_rate interval
+			if (print_info_)
+				cout << "* MN " << MYNUM << " Timer BU " 
+				<< max_rate_ << " expired at " << NOW << "\n";
+
+			int home_reg_complete = 0;
+
+			Entry *entry = head(bulist_head_);
+			for ( ; entry; entry = entry->next_entry()) {
+				if (entry->type == BU_HA) {
+					if ((entry->binding_stage == HA_TUNNEL_BU) && (entry->time + RETRANSMISSION_TIMEOUT < NOW)) {
+						// BU has been sent to HA for long, but no BACK return
+						send_bu(BU_HA, entry->addr);
+					} else if (entry->binding_stage == HA_TUNNEL_BACK) {
+						// tunnel already exists
+						if (entry->expire() > NOW) {
+							// tunnel is OK, should be refreshed
+							send_bu(BU_HA, entry->addr);
+							if (entry->addr == ha_) home_reg_complete = 1;
+						} else {
+							// tunnel expired
+							send_bu(BU_HA, entry->addr);
+							entry->binding_stage = HA_TUNNEL_BU;
+							Tcl& tcl = Tcl::instance();
+							tcl.evalf("%s lost-ha %d", name_, HADDR);
+						}
+					}
+				}
+			}
+
+			if (home_reg_complete && rt_opti_) {
+				entry = head(bulist_head_);
+				for ( ; entry; entry = entry->next_entry()) {
+					if (entry->type == BU_CN) {
+						if (entry->binding_stage == CN_OPT_INIT) {
+							// optimization not started
+							return_routability(entry->addr);
+							entry->binding_stage = CN_OPT_TEST_INIT;
+						} else if (((entry->binding_stage & CN_OPT_TEST_INIT)
+									||(entry->binding_stage & CN_OPT_HoT)
+									||(entry->binding_stage & CN_OPT_CoT))
+									&& (entry->time + RETRANSMISSION_TIMEOUT < NOW)) {
+							// HoTI and CoTI have been been sent to CN for long,
+							// but HoT or CoT has not been received
+							return_routability(entry->addr);
+							entry->binding_stage = CN_OPT_TEST_INIT;
+						} else if ((entry->binding_stage == CN_OPT_BU) && (entry->time + RETRANSMISSION_TIMEOUT < NOW)) {
+							// BU has been sent to CN for long, but no BACK return.
+							// maybe I should restart the return routability procedure?
+							send_bu(BU_CN, entry->addr);
+						} else if (entry->binding_stage == CN_OPT_BACK) {
+							// optimization already exists
+							if (entry->expire() > NOW) {
+								// optimized session is OK, should be refreshed
+								send_bu(BU_CN, entry->addr);
+							} else {
+								// optimization expired
+								return_routability(entry->addr);
+								entry->binding_stage = CN_OPT_TEST_INIT;
+								Entry *n = lookup_entry(entry->addr, head(bcache_head_));
+								Tcl& tcl = Tcl::instance();
+								if (n && n->expire() > NOW) {
+									tcl.evalf("%s bind-as-cn %d", name_, n->haddr);
+								} else {
+									tcl.evalf("%s clear-reg-as-mn %d", name_, entry->addr);
+								}
+							}
+						}
+					}
+				} // for
+			}
+
+			entry = head(bcache_head_);
+			for ( ; entry; entry = entry->next_entry()) {
+				if (entry->expire() < NOW) {
+					Entry *n = lookup_entry(entry->haddr, head(bulist_head_));
+					if (!n || (n->type == BU_CN && n->binding_stage != CN_OPT_BACK)) {
+						Tcl& tcl = Tcl::instance();
+						tcl.evalf("%s clear-reg-as-cn %d", name_, entry->haddr);
+					}
+				}
+			}
 
-	if (print_info_) 
-	cout << "* MN " << MYNUM << " Timer BSList expired at " << NOW << "\n";
+			bu_timer_.resched(bu_beacon_);
+			break;
+		}
 
-	// Remove entries that have expired
-	Entry *entry = head(bslist_head_); 
-   	for ( ; entry; entry = entry->next_entry()) {
-	   if (entry->expire() < NOW) {
-	   	if ( entry->caddr == coa_) {
-		   // We have lost the current BS
-		   // We will need to register with a new one 
-		   coalost_ = TRUE;
-		}
-		entry->remove_entry();
-		delete entry;
-	   }
-	}
-	bslist_timer_.resched(beacon_);
-	
-	if (coalost_ == TRUE) {
-	   if (print_info_) cout << "* MN lost contact with current BS" << "\n";
-	   reg();
-	}
-	break;
-   }
-   default:
-	break;
-   }
+		case MIP_TIMER_BSLIST: {
+			// Check expiration time for each BS
+			// If expired, delete it since no ads for too long
+			// If this is the current BS, register with a new one.
+
+			if (print_info_) 
+			cout << "* MN " << MYNUM << " Timer BSList expired at " << NOW << "\n";
+
+			// Remove entries that have expired
+			Entry *entry = head(bslist_head_); 
+			int num_of_bs_in_list_ = 0;
+			for ( ; entry; entry = entry->next_entry()) {
+				if (entry->expire() < NOW) {
+					if ( entry->caddr == coa_) {
+						// We have lost the current BS
+						// We will need to register with a new one 
+						cout << NOW << " Lost contact with current BS: " << PRINTADDR(entry->addr) << ":" << entry->addr
+							<< " Current location: " << node_->X() << ", " << node_->Y()
+							<< " Destination: " << node_->destX() << ", " << node_->destY() << "\n";
+						coalost_ = TRUE;
+						lost_HA();
+					}
+					entry->remove_entry();
+					delete entry;
+				}
+				num_of_bs_in_list_++;
+			}
+			if (!coalost_) {						//still in current BS
+				// if num_of_bs_in_list_ > 1, it means the MN can receive the RADS message from
+				// more than 1 BSs, which means the MN is in the overlapped area of multiple BSs.
+				// So we should be alert to the handoff, and should check the BS list more often.
+				if (num_of_bs_in_list_ == 1) bslist_timer_.resched(bs_beacon_);
+				else bslist_timer_.resched(max_rate_);
+			} else if (!head(bslist_head_)) {					//left current BS,
+				bslist_timer_.resched(max_rate_);	//and no BS in bslist
+				send_sols();
+			} else {								//left current BS,
+				reg_new_coa();						//but there's another BS in bslist
+				bslist_timer_.resched(bs_beacon_);
+			}
+
+			if (coalost_ == TRUE) {
+				if (print_info_) cout << "* MN lost contact with current BS" << "\n";
+			}
+			break;
+		}
+		default:
+			break;
+	}//switch
 }
 
 // *************************************************************************
 // Interface to the OTcl interpreter
 // *************************************************************************
 int MNAgent::command(int argc, const char*const* argv)
 {
-   if (argc == 2) {
-      if (strcmp(argv[1], "dump") == 0) {
-	dump();
-	return TCL_OK;
-      }
-   } else if (argc == 3) {
-      if (strcmp(argv[1], "check-beacon") == 0) {
-	// We check if we are still attached to the BS every <beacon_> sec.
-	beacon_ = atof(argv[2]);
-	timeout(MIP_TIMER_BSLIST);
-	bslist_timer_.resched(beacon_);
-	return TCL_OK;
-      }
-      else if (strcmp(argv[1], "set_max_rate") == 0) {
-	max_rate_ = atof(argv[2]);
-	bu_timer_.resched(max_rate_);
-	return TCL_OK;
-      }
-      else if (strcmp(argv[1], "set_slow_rate") == 0) {
-	slow_rate_ = atof(argv[2]);
-	return TCL_OK;
-      } else if (strcmp(argv[1], "decap-port") == 0) {
-	decap_port_ = atoi(argv[2]);
-	return TCL_OK;
-      } else if (strcmp (argv[1], "node") == 0) {
-	node_ = (MobileNode*)TclObject::lookup(argv[2]);
-	if (node_ == 0) {
-	   fprintf (stderr, "%s: %s lookup of %s failed\n", __FILE__, argv[1], argv[2]);
-	   return TCL_ERROR;
+	if (argc == 2) {
+		if (strcmp(argv[1], "dump") == 0) {
+			dump();
+			return TCL_OK;
+		}
+	} else if (argc == 3) {
+		if (strcmp(argv[1], "check-bs-beacon") == 0) {
+			// We check if we are still attached to the BS every <beacon_> sec.
+			bs_beacon_ = atof(argv[2]);
+			timeout(MIP_TIMER_BSLIST);
+			return TCL_OK;
+		}
+		if (strcmp(argv[1], "check-bu-beacon") == 0) {
+			// We check if we are still attached to the BS every <beacon_> sec.
+			bu_beacon_ = atof(argv[2]);
+			timeout(MIP_TIMER_BU);
+			return TCL_OK;
+		}
+		else if (strcmp(argv[1], "set_max_rate") == 0) {
+			max_rate_ = atof(argv[2]);
+			bu_timer_.resched(max_rate_);
+			return TCL_OK;
+		}
+		else if (strcmp(argv[1], "set_slow_rate") == 0) {
+			slow_rate_ = atof(argv[2]);
+			return TCL_OK;
+		}
+		else if (strcmp(argv[1], "decap-port") == 0) {
+			decap_port_ = atoi(argv[2]);
+			return TCL_OK;
+		}
+		else if (strcmp (argv[1], "node") == 0) {
+			node_ = (MobileNode*)TclObject::lookup(argv[2]);
+			if (node_ == 0) {
+				fprintf (stderr, "%s: %s lookup of %s failed\n", __FILE__, argv[1], argv[2]);
+				return TCL_ERROR;
+			}
+			return TCL_OK;
+		}
+		else if (strcmp (argv[1], "add-cn") == 0) {
+			Entry *nn = add_bulist(atoi(argv[2]), BU_CN, ON);
+			nn->activate_entry(NOW, TIME_INFINITY);
+			return TCL_OK;
+		}
+		else if (strcmp (argv[1], "remove-cn") == 0) {
+			remove_bulist(atoi(argv[2]), BU_CN );
+			return TCL_OK;
+		}
+		else if (strcmp (argv[1], "add-group") == 0) {
+			Entry *nn = add_bulist(atoi(argv[2]), BU_RP, ON );
+			nn->activate_entry(NOW, TIME_INFINITY);
+			return TCL_OK;
+		}
+		else if (strcmp(argv[1], "set-ha") == 0) {
+			Entry *nn = add_bulist(ha_=atoi(argv[2]), BU_HA, ON);
+			nn->activate_entry(NOW, TIME_INFINITY);
+			return TCL_OK;
+		}
 	}
-	return TCL_OK;
-      }
-      else if (strcmp (argv[1], "add-cn") == 0) {
-	   Entry *nn = add_bulist(atoi(argv[2]), BU_CN, ON);
-           nn->activate_entry(NOW, TIME_INFINITY);
-	   return TCL_OK;
-      }
-      else if (strcmp (argv[1], "remove-cn") == 0) {
-	   remove_bulist(atoi(argv[2]), BU_CN );
-	   return TCL_OK;
-      }
-      else if (strcmp (argv[1], "add-group") == 0) {
-	   Entry *nn = add_bulist(atoi(argv[2]), BU_RP, ON );
-           nn->activate_entry(NOW, TIME_INFINITY);
-	   return TCL_OK;
-      }
-      else if (strcmp(argv[1], "set-ha") == 0) {
-	 Entry *nn = add_bulist(ha_=atoi(argv[2]), BU_HA, ON);
-         nn->activate_entry(NOW, TIME_INFINITY);
-	 return TCL_OK;
-      }
-   }
-   return (Agent::command(argc, argv));
+	return (Agent::command(argc, argv));
 }
 
 // *************************************************************************
 // Add a new node in the Binding Update List
 // If node already exists, just activate the entry 
@@ -840,21 +1082,26 @@
 // XXX: for now, call TCL interpreter, but we need something like DHCPv6
 // XXX: Interpreter returns a COA with BS's prefix
 // *************************************************************************
 int MNAgent::get_coa(int new_bs)
 {
-   Tcl& tcl = Tcl::instance();
+	Tcl& tcl = Tcl::instance();
 
-   if ( new_bs == ha_ )
-	// We are back to home.  
-	// We still need to (de-)register with coa = home_address
-	return HADDR;
-   else {
-cout << NOW << " get_coa for BS " << PRINTADDR(new_bs) << ":" << new_bs << "\n";
-	tcl.evalf("%s get-coa %s", name_, PRINTADDR(new_bs) );
-	return(atoi(tcl.result()));
-   }
+	if ( new_bs == ha_ ) {
+		// We are back to home.  
+		// We still need to (de-)register with coa = home_address
+		cout << NOW << " return home " << PRINTADDR(new_bs) << ":" << new_bs
+			<< " Current location: " << node_->X() << ", " << node_->Y()
+			<< " Destination: " << node_->destX() << ", " << node_->destY() << "\n";
+		return HADDR;
+	} else {
+		cout << NOW << " get_coa for BS " << PRINTADDR(new_bs) << ":" << new_bs
+			<< " Current location: " << node_->X() << ", " << node_->Y()
+			<< " Destination: " << node_->destX() << ", " << node_->destY() << "\n";
+		tcl.evalf("%s get-coa %s", name_, PRINTADDR(new_bs) );
+		return(atoi(tcl.result()));
+	}
 }
 
 // *************************************************************************
 // We are now attached to a new subnet 
 // The MNagent now should update the Mobilenode about the changed coa_ 
@@ -867,11 +1114,11 @@
 	node_->set_base_stn(bs_);
 	if (print_info_) {
 		cout << " MN " << node_->address();
 		cout << " has COA " << PRINTADDR(node_->coa()) << "\n"; 
 	}
-}      
+}
 
 // *************************************************************************
 // Registration with HA, CNs, previous default router
 // When ?
 // => New BS
@@ -884,38 +1131,28 @@
 // - CNs if we have some in the Binding List
 // [MIPv6] says that BUs are generally sent to CNs 
 // when a BU containing a new COA is sent to the HA.
 // Here, we send BUs to CNS whenever we send a BU to HA. 
 // *************************************************************************
-void MNAgent::reg()
+void MNAgent::reg_new_coa()
 {
-   // Check if we are still attached to a BS
-   if ( ! head(bslist_head_) ) {
-   	// We do not have BS at all in the BS list 
-	bu_timer_.resched(max_rate_);
-	send_sols();
-	return;
-   }
-   
-   // Check if we have an active care-of address
-   if (coalost_ == TRUE) {
 	// We have BSs in the list, but we have lost contact with current BS
-	// because TIMER_BSLIST has expired. 
-	// Choose new BS = first on list since we have deleted the former one 
-	// and register with it                         
+	// because TIMER_BSLIST has expired.
+	// Choose new BS = first on list since we have deleted the former one
+	// and register with it
 
-        // Stop sending BUs at "previous previous" BS if still in BU List 
+	// Stop sending BUs at "previous previous" BS if still in BU List
 	// XXX: this should be automatic - we don't keep it very long (?)
-        remove_bulist(oldbs_, BU_BS);
+	remove_bulist(oldbs_, BU_BS);
 
 	Entry *pbs = head(bslist_head_); 
 	oldbs_ = bs_;
 	bs_ = pbs->addr;
-	oldcoa_ = coa_; 
+	oldcoa_ = coa_;
 	coa_ = pbs->caddr;
 	adlftm_ = pbs->lifetime();
-      
+
 	// Set the new BS as the gateway to the Internet
 	set_subnet();
 	coalost_ = FALSE;
 	nbu_ = 0; 
 
@@ -926,117 +1163,187 @@
 	// XXX: if ( oldbs_ != NONE && oldbs_ != ha_ ) {
 	if ( oldbs_ != NONE ) {
 		Entry *nn = add_bulist(oldbs_, BU_BS, ON);
 		nn->update_entry(NONE, oldcoa_, coa_, NOW, reglftm_);
 	}
-   }
 
-   // As specified in Mobile IPv6, periodic BU should be sent 
-   // with longer interval after 5 transmissions
-   if ( nbu_++ < MAX_FAST_UPDATES ) 
-	bu_timer_.resched(max_rate_);
-   else
-	bu_timer_.resched(slow_rate_);
-
-   send_standard_bu(BU_HA);
-   if ( rt_opti_ ) send_standard_bu(BU_CN);
-   if ( bs_forwarding_) send_standard_bu(BU_BS);
+	Entry *entry = head(bulist_head_);
+	for ( ; entry; entry = entry->next_entry()) {
+		if ( entry->type == BU_HA) {
+			cout << NOW << " Send BU to HA\n";
+			if (HADDR == coa_) {
+				// Commonly, this work should be done after receiving
+				// the BACK, but in this case, the BU's src addr equals
+				// to MN's HoA. On the other hand, at this point of time,
+				// the handoff is not finished, and the src_classifier_
+				// will lead those packets who have HoA as src addr to
+				// NullAgent. Thus, BU won't be sent out, and we have to
+				// configure the src_classifier_ before sending BU to HA.
+				Tcl& tcl = Tcl::instance();
+				tcl.evalf("%s go-back-home %d", name_, HADDR);
+			}
+			send_bu(BU_HA, entry->addr);
+			entry->binding_stage = HA_TUNNEL_BU;
+		}
+	}
 }
 
+void MNAgent::lost_HA()
+{
+	Tcl& tcl = Tcl::instance();
+	tcl.evalf("%s lost-ha %d", name_, HADDR);
+
+	// when handoff, HA is lost,
+	// and all optimization sessions have to be restarted
+	Entry *entry = head(bulist_head_); 
+	for ( ; entry; entry = entry->next_entry()) {
+		if (entry->type == BU_HA) {
+			entry->binding_stage = HA_TUNNEL_LOST;
+		} else if (entry->type == BU_CN) {
+			if (entry->binding_stage == CN_OPT_BACK) {
+				Entry *n = lookup_entry(entry->addr, head(bcache_head_));
+				Tcl& tcl = Tcl::instance();
+				if (n && n->expire() > NOW) {
+					tcl.evalf("%s bind-as-cn %d", name_, n->haddr);
+				} else {
+					tcl.evalf("%s clear-reg-as-mn %d", name_, entry->addr);
+				}
+			}
+			entry->binding_stage = CN_OPT_INIT;
+		}
+	}
+}
 // *************************************************************************
 // Send standard Mobile IPv6 Binding Update  
 // XXX: Here, we may decide to send BUs to CNs and HAs at 
 // XXX: different frequency, depending on local policy
 // XXX: For now, send BU to everyone at the same time
 // *************************************************************************
-void MNAgent::send_standard_bu(Mipv6RegType type) 
+void MNAgent::send_bu(Mipv6RegType type, int dst)
 {
-   Entry *n = head(bulist_head_); 
-   Entry *nn;
-   Packet *p;
-   hdr_mipv6 *h;
-   while ( n ) { 
-      nn=n;	
-      n=n->next_entry();
-      if ( nn->activated(NOW) && (nn->type == type) ) {
-	p = set_bu_packet(type, nn->addr, coa_);
-	h = HDR_MIPv6(p);
-
-	// Update Binding Update List
-	nn->update_entry(h->seqno(), h->haddr(), h->coa(), NOW, h->lifetime());
-	send_packet(p);
-      }
-   }
+	Entry *n = lookup_entry(dst, head(bulist_head_));
+	Packet *p;
+	hdr_mipv6 *h;
+	if ( n->activated(NOW) && (n->type == type) ) {
+		p = set_bu_packet(type, n->addr, coa_);
+		h = HDR_MIPv6(p);
+
+		// Update Binding Update List
+		n->update_entry(h->seqno(), h->haddr(), h->coa(), NOW, h->lifetime());
+
+		send_packet(p);
+	}
+}
+
+// *************************************************************************
+// Send HoTI and CoTI to CN
+// *************************************************************************
+void MNAgent::return_routability(int dst)
+{
+	Entry *n = lookup_entry(dst, head(bulist_head_));
+	hdr_cmn *hdrc;
+	hdr_ip *hip;
+	hdr_mipv6 *hmipv6;
+
+	Packet *hoti = allocpkt();
+	set_ipv6_hdr(hoti, dst);
+	hmipv6 = HDR_MIPv6(hoti);
+	hmipv6->type() = HoTI;
+	hmipv6->seqno() = ++m_seqno_;
+	hdrc = HDR_CMN(hoti);
+	hdrc->size() += BU_SIZE;
+	hdrc->ptype() = PT_BU;
+
+	Packet *coti = allocpkt();
+	set_ipv6_hdr(coti, dst);
+	hip = HDR_IP(coti);
+	hip->saddr() = coa_;
+	hmipv6 = HDR_MIPv6(coti);
+	hmipv6->type() = CoTI;
+	hmipv6->seqno() = m_seqno_;		//HoTI and CoTI have the same sequence
+	hdrc = HDR_CMN(coti);
+	hdrc->size() += BU_SIZE;
+	hdrc->ptype() = PT_BU;
+
+	n->seqno = m_seqno_;
+	n->time = NOW;
+	n->binding_stage = CN_OPT_TEST_INIT;
+
+	send_packet(hoti);
+	send_packet(coti);
+	cout << NOW << " Send HoTI and CoTI to CN\n";
 }
 
 // *************************************************************************
 // Fill Binding Update = IPv6 header + Binding Update Option header
 // *************************************************************************
 Packet* MNAgent::set_bu_packet(Mipv6RegType type, int dst, int newad)
 {
-        Packet *p = allocpkt();
-	set_ipv6_hdr(p, dst);	
-	set_bu_hdr(p, type, newad);	
+	Packet *p = allocpkt();
+	hdr_ip *hip = HDR_IP(p);
+	set_ipv6_hdr(p, dst);
+	hip->saddr() = coa_;
+	set_bu_hdr(p, type, newad);
 	return(p);
 }
 
 // *************************************************************************
 // Fill the Binding Update Option Header 
 // *************************************************************************
 void MNAgent::set_bu_hdr(Packet *p, Mipv6RegType type, int newad) 
 {
 	hdr_cmn *hdrc = HDR_CMN(p);
-        hdr_mipv6 *h = HDR_MIPv6(p);
-	
-	// By default, set flags to OFF.
+	hdr_mipv6 *h = HDR_MIPv6(p);
+
+	// By default
 	h->H() = OFF;
-	h->A() = OFF;
-	
+	h->A() = ON;
+
 	if ( type != BU_BS ) {
-        	h->haddr() = HADDR; 
+        h->haddr() = HADDR;
 	}
 	else {
-        // Former BS establish forwarding from previous coa to new coa
+	// Former BS establish forwarding from previous coa to new coa
 	// XXX: we should better take the address recorded in BU List
 		h->haddr() = oldcoa_;
 	}
 
 	if ( type == BU_HA ) {
 		h->H() = ON;
-		h->A() = ON;
 	}
-        h->coa() = newad;
-        h->type() = BU;
-        h->lifetime() = LIFETIME;
+	h->coa() = newad;
+	h->type() = BU;
+	h->lifetime() = LIFETIME;
 	h->seqno() = ++m_seqno_;
-   
+
 	hdrc->size() += BU_SIZE;
 	hdrc->ptype() = PT_BU;
 }
 
 // *************************************************************************
 // When the MN does not have a registered BS, it needs to enquire for one
 // XXX: should be done in the NETWORK Agent, not in MIP - just needs an API
 // *************************************************************************
 void MNAgent::send_sols()
 {
-   Packet *p = allocpkt();
-   hdr_ip *iph = HDR_IP(p);
-   hdr_mipv6 *h = HDR_MIPv6(p);
-   hdr_cmn *hdrc = HDR_CMN(p);
-
-   h->haddr() = HADDR;
-   hdrc->ptype() = PT_SOL;
-   iph->daddr() = IP_BROADCAST;
-   iph->dport() = port();
-   hdrc->size() = PT_RSOL_SIZE;
-
-   if (print_info_) cout << "+ MN send SOLICITATION at " << NOW << "\n";
+	Packet *p = allocpkt();
+	hdr_ip *iph = HDR_IP(p);
+	hdr_mipv6 *h = HDR_MIPv6(p);
+	hdr_cmn *hdrc = HDR_CMN(p);
 
-   if (bcast_target_) bcast_target_->recv(p, (Handler*) 0);
-   else if (target_) send(p, 0);
-   else Packet::free(p);
+	h->haddr() = HADDR;
+	hdrc->ptype() = PT_SOL;
+	iph->saddr() = 0;
+	iph->daddr() = IP_BROADCAST;
+	iph->dport() = port();
+	hdrc->size() = PT_RSOL_SIZE;
+
+	if (print_info_) cout << "+ MN send SOLICITATION at " << NOW << "\n";
+
+	if (bcast_target_) bcast_target_->recv(p, (Handler*) 0);
+	else if (target_) send(p, 0);
+	else Packet::free(p);
 }
 
 // *************************************************************************
 // >----------------------------------------------------------------------<
 // Mobile IPv6 Correspondent Node
@@ -1081,5 +1388,134 @@
 // *************************************************************************
 void CNAgent::dump()
 {
    dump_list(head(bcache_head_), "Binding Cache");
 }
+
+
+static class MIPEncapsulatorToMNClass : public TclClass {
+public:
+	MIPEncapsulatorToMNClass() : TclClass("MIPEncapsulatorToMN") {}
+	TclObject* create(int, const char*const*) {
+		return (new MIPEncapsulatorToMN());
+	}
+} class_mipencapsulator_to_mn;
+
+MIPEncapsulatorToMN::MIPEncapsulatorToMN() : Connector(),/* mask_(0xffffffff), 
+	shift_(8),*/ defttl_(32)
+{
+	bind("addr_", (int*)&(here_.addr_));
+	bind("port_", (int*)&(here_.port_));
+//	bind("shift_", &shift_);
+//	bind("mask_", &mask_);
+	bind("ttl_", &defttl_);
+}
+
+void MIPEncapsulatorToMN::recv(Packet* p, Handler *h)
+{
+	Tcl& tcl = Tcl::instance();
+
+	hdr_ip* hdr = hdr_ip::access(p);
+	hdr_ipinip **ppinhdr = (hdr_ipinip**)hdr_ipinip::access(p);
+	if (--hdr->ttl_ <= 0) {
+		/*
+		 * XXX this should be "dropped" somehow.  Right now,
+		 * these events aren't traced.
+		 */
+		hdr_ipinip *ptr = *ppinhdr, *temp;
+		while (ptr != NULL) {
+			temp = ptr;
+			ptr = ptr->next_;
+			delete temp;
+		}
+		*ppinhdr = NULL;
+		Packet::free(p);
+		return;
+	}
+	hdr_ipinip *inhdr = new hdr_ipinip;
+	//int dst = ((hdr->dst() >> shift_) & mask_);
+	int dst = Address::instance().get_nodeaddr(hdr->daddr());
+	tcl.evalf("%s tunnel-exit %d", name_, dst);
+	int te = atoi(tcl.result());
+
+	inhdr->next_ = *ppinhdr;
+	*ppinhdr = inhdr;
+	inhdr->hdr_ = *hdr;
+
+	hdr->saddr() = here_.addr_;
+	hdr->sport() = here_.port_;
+	//hdr->dst() = addr_ & ~(~(nsaddr_t)0 << shift_) | (te & mask_) << shift_;;
+	hdr->daddr() = te;
+	hdr->dport() = 1;
+	hdr->ttl() = defttl_;
+	//((hdr_cmn*)p->access(off_cmn_))->size() += IP_HEADER_SIZE;
+	hdr_cmn::access(p)->size() += IP_HEADER_SIZE;
+
+	target_->recv(p,h);
+}
+
+static class MIPEncapsulatorFromMNClass : public TclClass {
+public:
+	MIPEncapsulatorFromMNClass() : TclClass("MIPEncapsulatorFromMN") {}
+	TclObject* create(int, const char*const*) {
+		return (new MIPEncapsulatorFromMN());
+	}
+} class_mipencapsulator_from_mn;
+
+MIPEncapsulatorFromMN::MIPEncapsulatorFromMN() : Connector(), /*mask_(0xffffffff), 
+	shift_(8), */defttl_(32)
+{
+	bind("addr_", (int*)&(here_.addr_));
+	bind("port_", (int*)&(here_.port_));
+//	bind("shift_", &shift_);
+//	bind("mask_", &mask_);
+	bind("ttl_", &defttl_);
+}
+
+void MIPEncapsulatorFromMN::recv(Packet* p, Handler *h)
+{
+	Tcl& tcl = Tcl::instance();
+
+	hdr_ip* hdr = hdr_ip::access(p);
+	hdr_ipinip **ppinhdr = (hdr_ipinip**)hdr_ipinip::access(p);
+	if (--hdr->ttl_ <= 0) {
+		/*
+		 * XXX this should be "dropped" somehow.  Right now,
+		 * these events aren't traced.
+		 */
+		hdr_ipinip *ptr = *ppinhdr, *temp;
+		while (ptr != NULL) {
+			temp = ptr;
+			ptr = ptr->next_;
+			delete temp;
+		}
+		*ppinhdr = NULL;
+		Packet::free(p);
+		return;
+	}
+	hdr_ipinip *inhdr = new hdr_ipinip;
+
+	inhdr->next_ = *ppinhdr;
+	*ppinhdr = inhdr;
+	inhdr->hdr_ = *hdr;
+
+	hdr->saddr() = mipagent_->coa();
+	hdr->sport() = here_.port_;
+	hdr->daddr() = mipagent_->ha();
+	hdr->dport() = 1;
+	hdr->ttl() = defttl_;
+
+	hdr_cmn::access(p)->size() += IP_HEADER_SIZE;
+
+	target_->recv(p,h);
+}
+
+int MIPEncapsulatorFromMN::command(int argc, const char*const*argv)
+{
+	if (argc == 3) {
+		if (strcmp(argv[1], "mipagent") == 0) {
+			mipagent_ = (MNAgent*)TclObject::lookup(argv[2]);
+			return TCL_OK;
+		}
+	}
+	return (Connector::command(argc, argv));
+}
diff -urNU5 ns-2.33-mobiwan/mobiwan/mipv6.h ns-2.33-mobiwan-rfc3775/mobiwan/mipv6.h
--- ns-2.33-mobiwan/mobiwan/mipv6.h	2008-05-06 15:13:33.000000000 +1000
+++ ns-2.33-mobiwan-rfc3775/mobiwan/mipv6.h	2008-05-06 15:13:58.000000000 +1000
@@ -56,21 +56,36 @@
 #define	MAX_UPDATE_RATE		1	// sec
 #define	SLOW_UPDATE_RATE	10	// sec
 #define	MAX_FAST_UPDATES	5	// transmissions
 #define	MAX_ADVERT_REXMIT	3	// transmissions
 
-#define BU_OPT_SIZE		10		// + sub_option
+#define BU_OPT_SIZE			10		// + sub_option
 #define BU_ACK_OPT_SIZE		13		// + sub_option 
 #define	BU_REQ_OPT_SIZE		2		// + sub_option
 #define HOME_OPT_SIZE		18		// + sub_option  
 #define	BU_SIZE	   DEST_HDR_PREFIX_SIZE + BU_OPT_SIZE + HOME_OPT_SIZE
 #define BACK_SIZE  DEST_HDR_PREFIX_SIZE + BU_ACK_OPT_SIZE
-#define BREQ_SIZE  DEST_HDR_PREFIX_SIZE + BU_REQ_OPT_SIZE	
+#define BREQ_SIZE  DEST_HDR_PREFIX_SIZE + BU_REQ_OPT_SIZE
+
+// stage of optimization with CN
+#define CN_OPT_INIT			0	// optimization not started
+#define CN_OPT_TEST_INIT	1	// HoTI and CoTI have been sent
+#define CN_OPT_HoT			2	// HoT received
+#define CN_OPT_CoT			4	// CoT received
+#define CN_OPT_BU			8	// BU sent
+#define CN_OPT_BACK			16	// optimization OK
+
+// stage of home registration
+#define HA_TUNNEL_LOST		0	// MN_HA tunnel not exist
+#define HA_TUNNEL_BU		1	// BU has been sent to HA
+#define HA_TUNNEL_BACK		2	// tunnel OK
+
+#define RETRANSMISSION_TIMEOUT 3
 
 typedef enum {
-	BREQ, BU, BACK, 
-	BU_HA, BU_BS,  BU_CN, BU_RP, BU_MN,
+	BREQ, BU, BACK, HoTI, HoT, CoTI, CoT, 
+	BU_HA, BU_BS,  BU_CN, BU_RP, BU_MN, 
 	BS_ADS, BS_SOL
 } Mipv6RegType;
 
 typedef enum {
         DEF_BU, LBM_BU, MBU_CN, MBU_ALL, LBM_BU_ALL, LBM_BU_CN, TEST
@@ -89,43 +104,43 @@
 // **************************************************************************
 class Entry;
 LIST_HEAD(entry, Entry);
 
 class Entry {
- public:
-        Entry(int address, Mipv6RegType t, int f)  { 
-		addr = address;	
+public:
+	Entry(int address, Mipv6RegType t, int f) {
+		addr = address;
 		haddr = -1;
 		caddr = -1;
-		seqno = -1; 
+		seqno = -1;
 		flag  = f;
-		lftm = 0;  
-		time = -1;		
+		lftm = 0;
+		time = -1;
 		active_expire = 0;
 		nbbu = 0;
 		type = t;
-		
+
 		switch ( t ) {
-		   case BU_HA:
-			strcpy(info, "HA");   break;
-		   case BU_BS:
-			strcpy(info, "BS");   break;
-		   case BU_MN:
-			strcpy(info, "MN");   break;
-		   case BS_ADS:
-			strcpy(info, "BS");   break;
-		   case BU_RP:
-			strcpy(info, "RP");   break;
-		   default:
-			strcpy(info, "CN");   break;
-		}	
-	}  
-        ~Entry() { ; }
+			case BU_HA:
+				strcpy(info, "HA"); binding_stage = HA_TUNNEL_LOST; break;
+			case BU_BS:
+				strcpy(info, "BS"); break;
+			case BU_MN:
+				strcpy(info, "MN"); break;
+			case BS_ADS:
+				strcpy(info, "BS"); break;
+			case BU_RP:
+				strcpy(info, "RP"); break;
+			default:
+				strcpy(info, "CN"); binding_stage = CN_OPT_INIT; break;
+		}
+	}
+	~Entry() {}
 
 	// Chain element to the list
 	inline void insert_entry(struct entry *head) {
-        	LIST_INSERT_HEAD(head, this, link);
+		LIST_INSERT_HEAD(head, this, link);
 	}
 
 	inline void update_entry(int seq, int h, int c, double t, double life) {
 		seqno=seq;
 		haddr=h;
@@ -140,51 +155,52 @@
 	inline int activated(double now) { 
 		return ( (flag==ON) && (now<active_expire)) ? TRUE : FALSE; 
 	}
 	
 	inline void activate_entry(double now, double life) {
-	// We want to send BU and we want to keep doing this
-	// until current time > active_expire_time 
+		// We want to send BU and we want to keep doing this
+		// until current time > active_expire_time 
 		flag=ON;
 		if ( (now+life) > active_expire) active_expire = now + life ;
 	}
 
 	// Return next element in the chained list
-        Entry* next_entry(void) const { return link.le_next; }
+	Entry* next_entry(void) const { return link.le_next; }
 	
 	inline void remove_entry() { LIST_REMOVE(this, link); }
 
 	inline void remove_entry(struct entry *newhead) {
-	    LIST_REMOVE(this, link);
-            LIST_INSERT_HEAD(newhead, this, link);
+		LIST_REMOVE(this, link);
+		LIST_INSERT_HEAD(newhead, this, link);
 	}
 
 	inline void deactivate_entry() {
 		// We don't want to send BU to this node anymore
 		// but we want to keep it in the list
 		flag=OFF;
 	}
 	// Fields as described in the Mobile IPv6 spec.
-       	int 		addr;		// address (key)
-	int 		haddr;		// Last Home address sent
-        int       	caddr;		// Last COA sent 
-	double		lftm; 		// lifetime of this entry 
-	double		time; 		// time at which entry was updated 
-        int       	seqno;		// Last BU's sequence number
-        int       	flag;		// Do not send BU if set to ON 
+	int 	addr;		// address (key)
+	int 	haddr;		// Last Home address sent
+	int		caddr;		// Last COA sent 
+	double	lftm; 		// lifetime of this entry 
+	double	time; 		// time at which entry was updated 
+	int		seqno;		// Last BU's sequence number
+	int		flag;		// Do not send BU if set to ON 
+	int		binding_stage;
 
 	// XXX: Other fields that may be included as in the spec: 
 	// int       	state;		// State of retransmission
 
 	// For statistic and display purposes only  
-	double		active_expire;	// term of activation
-	int 		nbbu;		// Total nb BU sent to this node
-	Mipv6RegType	type;		// BU_HA / BU_CN / BU_REDIRECT ...  
-	char		info[10];	// To distinguish between CN, HA, BS
+	double	active_expire;	// term of activation
+	int 	nbbu;			// Total nb BU sent to this node
+	Mipv6RegType	type;	// BU_HA / BU_CN / BU_REDIRECT ...  
+	char	info[10];		// To distinguish between CN, HA, BS
 
- protected:
-        LIST_ENTRY(Entry) link;
+protected:
+	LIST_ENTRY(Entry) link;
 }; 
 
 // **************************************************************************
 // MIPv6 messages
 // **************************************************************************
@@ -200,83 +216,84 @@
 	int coaddr_;	
 
 	// XXX: Following will be needed for ns-2b.7 with some modification
 	// - required by PacketHeaderManager
 	static int offset_;
-        inline static int& offset() { return offset_; }
-        inline static hdr_mipv6* access(Packet* p) {
-                return (hdr_mipv6*) p->access(offset_);
-        }
+	inline static int& offset() { return offset_; }
+	inline static hdr_mipv6* access(Packet* p) {
+		return (hdr_mipv6*) p->access(offset_);
+	}
 
 	// New 02/01
- 	inline Mipv6RegType& type() { return optype_; }
- 	inline int& A() { return A_; }
- 	inline int& H() { return H_; }
- 	inline int& seqno() { return seq_; } 
- 	inline double& lifetime() { return lftm_; }
- 	inline int& coa() { return coaddr_; }
-        inline int& haddr() { return homeaddr_; }
+	inline Mipv6RegType& type() { return optype_; }
+	inline int& A() { return A_; }
+	inline int& H() { return H_; }
+	inline int& seqno() { return seq_; } 
+	inline double& lifetime() { return lftm_; }
+	inline int& coa() { return coaddr_; }
+	inline int& haddr() { return homeaddr_; }
 };
 
 // **************************************************************************
 // Timers
 // **************************************************************************
 class BUTimer : public TimerHandler {
- public:
-        BUTimer(Agent *a) : TimerHandler() { a_ = a; }
- protected:
-        inline void expire(Event *) { a_->timeout(MIP_TIMER_BU); }
-        Agent *a_;
+public:
+	BUTimer(Agent *a) : TimerHandler() { a_ = a; }
+protected:
+	inline void expire(Event *) { a_->timeout(MIP_TIMER_BU); }
+	Agent *a_;
 };
 
 // Timer to reset BS's advertisement recorded at MN
 class MNAgent;
 class BSListTimer : public TimerHandler {
- public: 
-        BSListTimer(MNAgent *a) : TimerHandler() { a_ = a; }
- protected:
-        void expire(Event *e);
-        MNAgent *a_;
+public: 
+	BSListTimer(MNAgent *a) : TimerHandler() { a_ = a; }
+protected:
+	void expire(Event *e);
+	MNAgent *a_;
 };
 
 // **************************************************************************
 // Mobile IPv6 Base Agent
 // **************************************************************************
 class MIPv6Agent : public Agent {
 public:
 	MIPv6Agent();
-	struct entry bcache_head_;	
+	struct entry bcache_head_;
+	// List Management
+	Entry* lookup_entry(int, Entry *);	
+	Entry* head(struct entry head) { return head.lh_first; }
+
 protected:
 	int command(int argc, const char*const*argv);
 	NsObject *bcast_target_; 	// where to send solicitations / ads
 	BUTimer timer_;
-	double beacon_;			// Beacon interval
+	double bs_beacon_;		// Beacon interval for BS List checking
+	double bu_beacon_;		// Beacon interval for BU retransmission checking
 	int print_info_;
-	char	node_info_[8];
+	char node_info_[8];
 
 	void send_packet(Packet *p);
 	void set_ipv6_hdr(Packet *p, int);	
-	void send_ack(Packet *p);
-	Packet* set_ack_packet(int, int, int);
-	void set_back_hdr(Packet *p, int);
-	void encap_route(int, int, double);
+	void send_ack(Packet *p, int);
+	Packet* set_ack_packet(int, int, int, int);
+	void set_back_hdr(Packet *p, int, int);
+	void encap_route(int, int, int, double);
 	void decap_route(int, double);
 	void delete_route(int);
 	void print_info(Packet *p, char, char *);
 	void recv(Packet *, Handler *);
-	void mn_registration(Packet *p); 
+	void mn_registration(Packet *p, int home_reg); 
 	virtual void send_ads() { 
-	        fprintf(stderr, "%s: Router Ads not allowed",node_info_); 
+		fprintf(stderr, "%s: Router Ads not allowed",node_info_); 
 	}
 	// Binding Cache
-	Entry* update_bcache(Packet *, int);
+	Entry* update_bcache(Packet *, int home_reg, int);
  	// Entry* bcache_head()	{ return bcach_head_.lh_first; }
 
-	// List Management
-	Entry* lookup_entry(int, Entry *);	
- 	Entry* head(struct entry head) { return head.lh_first; }
-
 	// Display
 	void dump();
 	void dump_list(Entry *, char *);
 
 };
@@ -306,11 +323,14 @@
 	MNAgent();
 	void recv(Packet *, Handler *);
 	void timeout(int);
 	struct entry bulist_head_;	
 	struct entry bslist_head_;	
-	struct entry history_head_;	
+	struct entry history_head_;
+
+	inline int& ha() { return ha_; }
+	inline int& coa() { return coa_; } 
 
 	void dump();
 
 	// Binding Update List
 	Entry* add_bulist(int, Mipv6RegType, int);
@@ -319,41 +339,43 @@
 	void recv_ads(Packet *);
 	void recv_decap(Packet *);
 	void recv_back(Packet *);
 	void set_subnet();
 	int get_coa(int);
-	void reg();
+	void reg_new_coa();
+	void lost_HA();
 	void send_sols();
 	int ha_;
 	int bs_;
 	int oldbs_;  
 	int coa_;
-        int oldcoa_;
+	int oldcoa_;
 	int coalost_;
 	int nbu_;
 	double max_rate_;		// Max Binding Update interval
 	double slow_rate_;		// Slow Binding Update interval
-	int m_seqno_;		/* current registration seqno */
-	double reglftm_;	/* registration lifetime */
-	double adlftm_;		/* advertisement lifetime */
-	MobileNode *node_;      /* ptr to my mobilenode,if appl. */
+	int m_seqno_;			/* current registration seqno */
+	double reglftm_;		/* registration lifetime */
+	double adlftm_;			/* advertisement lifetime */
+	MobileNode *node_;		/* ptr to my mobilenode,if appl. */
 	int bu_policy_;	
-	int rt_opti_;		// Route Optimization
-	int bs_forwarding_;	// Previous BS forwarding
+	int rt_opti_;			// Route Optimization
+	int bs_forwarding_;		// Previous BS forwarding
 	int decap_port_;
 
-	void send_standard_bu(Mipv6RegType type);
-	Packet* set_bu_packet(Mipv6RegType, int, int);	
-	void set_bu_hdr(Packet *p, Mipv6RegType, int);	
+	void send_bu(Mipv6RegType type, int dst);
+	void return_routability(int dst);
+	Packet* set_bu_packet(Mipv6RegType, int, int);
+	void set_bu_hdr(Packet *p, Mipv6RegType, int);
 
 	// Base Station List
- 	// Entry* bslist_head()	{ return bslist_head_.lh_first; }
+	// Entry* bslist_head()	{ return bslist_head_.lh_first; }
 	Entry* add_bs(int);
 	BSListTimer bslist_timer_;
 
 	// Binding Update List
- 	// Entry* bulist_head()	{ return bulist_head_.lh_first; }
+	// Entry* bulist_head()	{ return bulist_head_.lh_first; }
 	BUTimer bu_timer_;
 	void remove_bulist(int,  Mipv6RegType);
 
 	// Display
 	// void dump();
@@ -373,6 +395,34 @@
 
 	// Display
 	void dump();
 };
 
+
+class MIPEncapsulatorToMN : public Connector {
+public:
+	MIPEncapsulatorToMN();
+	void recv(Packet *p, Handler *h);
+protected:
+	ns_addr_t here_;
+//	int mask_;
+//	int shift_;
+	int off_ip_;
+	int off_ipinip_;
+	int defttl_;
+};
+
+class MIPEncapsulatorFromMN : public Connector {
+public:
+	MIPEncapsulatorFromMN();
+	void recv(Packet *p, Handler *h);
+protected:
+	int command(int argc, const char*const*argv);
+	MNAgent *mipagent_;
+	ns_addr_t here_;
+//	int mask_;
+//	int shift_;
+	int off_ip_;
+	int off_ipinip_;
+	int defttl_;
+};
 #endif
diff -urNU5 ns-2.33-mobiwan/tcl/lib/ns-default.tcl ns-2.33-mobiwan-rfc3775/tcl/lib/ns-default.tcl
--- ns-2.33-mobiwan/tcl/lib/ns-default.tcl	2008-05-06 15:13:33.000000000 +1000
+++ ns-2.33-mobiwan-rfc3775/tcl/lib/ns-default.tcl	2008-05-06 15:13:58.000000000 +1000
@@ -570,10 +570,12 @@
 #Classifier/Addr/MIPDecapsulator set off_ip_ 0
 # SRCRouting
 
 SrcRouting set debug_ false 
 
+DstHeader set debug_ false
+
 # Default settings for Hierarchical topology
 #
 # Bits are allocated for different fields like port, nodeid, mcast, 
 # hierarchical-levels. 
 # All Mask and Shift values are stored in Class AddrParams.
@@ -652,10 +654,20 @@
 MIPEncapsulator set ttl_ 32
 MIPEncapsulator set debug_ false
 #MIPEncapsulator set off_ip_ 0
 #MIPEncapsulator set off_ipinip_ 0
 
+MIPEncapsulatorToMN set addr_ 0
+MIPEncapsulatorToMN set port_ 0
+MIPEncapsulatorToMN set ttl_ 32
+MIPEncapsulatorToMN set debug_ false
+
+MIPEncapsulatorFromMN set addr_ 0
+MIPEncapsulatorFromMN set port_ 0
+MIPEncapsulatorFromMN set ttl_ 32
+MIPEncapsulatorFromMN set debug_ false
+
 #Agent/Network/NetworkMN set off_ipinip_ 0
 
 # GAF
  
 GAFPartner set addr_ 0
diff -urNU5 ns-2.33-mobiwan/tcl/lib/ns-mipv6.tcl ns-2.33-mobiwan-rfc3775/tcl/lib/ns-mipv6.tcl
--- ns-2.33-mobiwan/tcl/lib/ns-mipv6.tcl	2008-05-06 15:13:33.000000000 +1000
+++ ns-2.33-mobiwan-rfc3775/tcl/lib/ns-mipv6.tcl	2008-05-06 15:13:58.000000000 +1000
@@ -46,10 +46,11 @@
 # Defaults settings
 # ############################################################################
 Simulator set MIPv6_PORT	0	
 Simulator set DECAP_PORT	1	
 Simulator set RT_HDR_PORT	2
+Simulator set DEST_HDR_PORT	3
 
 Agent/MIPv6 set print_info_	0	;# output display
 Agent/MIPv6/MN set print_info_  0	;# output display
 Agent/MIPv6/BS set print_info_	0	;# output display
 Agent/MIPv6/CN set print_info_	0	;# output display
@@ -138,11 +139,11 @@
 # o Currently, only MN needs a decapsulator
 # (XXX: This may be wrong if we use HMIP)
 # o All agent including MIPDecapsulator's default target is
 # MIPv6 Agent 
 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Node/MobileNode instproc attach-decapsulator {} {
+Node instproc attach-decapsulator {} {
     $self instvar decap_ dmux_ agents_ regagent_
     
     set decap_ [new Classifier/Addr/MIPDecapsulator]
     lappend agents_ $decap_
     
@@ -186,10 +187,13 @@
 # Routing Header Extensions
 # ##########################################################################
 SrcRouting set port_ [Simulator set RT_HDR_PORT]
 SrcRouting set addr_ 0
 
+DstHeader set port_ [Simulator set DEST_HDR_PORT]
+DstHeader set addr_ 0
+
 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 # Return the care-of address corresponding to the home address
 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 SrcRouting instproc lookup-binding-cache mhaddr {
     $self instvar node_
@@ -239,38 +243,53 @@
 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 # Base Stations and HA are able to encapsulate
 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 Node/MobileNode instproc makemip-NewBS {} {
     
-    $self instvar regagent_ encap_ agents_ address_ dmux_ id_ classifier_hier_
-    $self instvar bcache_classifier_
-    set mipagent_ [[Simulator instance] set mipagent_]
-    
-    $self test-mcast
-    
-    set bcache_classifier_ [new Classifier/Hash/Dest 8]
-    $bcache_classifier_ set mask_ 0xffffffff
-    $bcache_classifier_ set shift_ 0
-    
-    $self insert-entry [$self get-module Hier] $bcache_classifier_ 0
-    $bcache_classifier_ defaulttarget $classifier_hier_
-    
-    if { $dmux_ == "" } {
-	set dmux_ [new Classifier/Port/Reserve]
-	$dmux_ set mask_ 0x7fffffff
-	$dmux_ set shift_ 0
-	
-	if [Simulator set EnableHierRt_] {  
-	    $classifier_hier_ install $address_ $dmux_
-	    #$self add-hroute $address_ $dmux_
-	} else {
-	    $self add-route $address_ $dmux_
+	$self instvar regagent_ decap_ dmux_ address_ classifier_hier_ 
+	$self instvar src_classifier_ bcache_classifier_ src_routing_
+
+	set mipagent_ [[Simulator instance] set mipagent_]
+
+	$self test-mcast
+
+	set bcache_classifier_ [new Classifier/Hash/Dest 8]
+	$bcache_classifier_ set mask_ 0xffffffff
+	$bcache_classifier_ set shift_ 0
+
+	$self insert-entry [$self get-module Hier] $bcache_classifier_ 0
+	$bcache_classifier_ defaulttarget $classifier_hier_
+
+	if { $dmux_ == "" } {
+		set dmux_ [new Classifier/Port/Reserve]
+		$dmux_ set mask_ 0x7fffffff
+		$dmux_ set shift_ 0
+
+		if [Simulator set EnableHierRt_] {  
+			$classifier_hier_ install $address_ $dmux_
+			set nodeaddr [AddrParams addr2id $address_]
+			#$self add-hroute $address_ $dmux_
+		} else {
+			$self add-route $address_ $dmux_
+			set nodeaddr [expr ( $address_ &			\
+				[AddrParams set NodeMask 1] ) <<		\
+				[AddrParams set NodeShift 1]]
+		}
 	}
-    } 
-    $self attach-redirect
-    set regagent_ [new Agent/MIPv6/$mipagent_ $self]
-    $self attach $regagent_ [Simulator set MIPv6_PORT]
+	$self attach-redirect "BS"
+
+	set src_classifier_ [new Classifier/Hash/Src 2]
+	$src_classifier_ set mask_ 0xffffffff
+	$src_classifier_ set shift_ 0 
+	$src_classifier_ defaulttarget $classifier_hier_
+	$src_classifier_ install $nodeaddr $src_routing_
+
+	set regagent_ [new Agent/MIPv6/$mipagent_ $self]
+	$self attach $regagent_ [Simulator set MIPv6_PORT]
+
+	# $self attach-decap
+	$self attach-decapsulator
 
 }
 
 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 Node instproc set-node-addressBS { args } {
@@ -302,44 +321,74 @@
 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 # MN is able to decapsulate (encap not necessarily needed) 
 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 Node/MobileNode instproc makemip-NewMN {} {
    
-    $self instvar regagent_ decap_ dmux_ address_ classifier_hier_ 
-    $self instvar bcache_classifier_
-    
-    set mipagent_ [[Simulator instance] set mipagent_]
+	$self instvar regagent_ decap_ dmux_ address_ classifier_hier_
+	$self instvar src_classifier_ null_agent_when_lose_HA_
+	$self instvar bcache_classifier_roaming_ bcache_classifier_at_home_
 
-    $self test-mcast
+	set mipagent_ [[Simulator instance] set mipagent_]
 
-    set bcache_classifier_ [new Classifier/Hash/Dest 8]
-    $bcache_classifier_ set mask_ 0xffffffff
-    $bcache_classifier_ set shift_ 0
-    
-    $self insert-entry [$self get-module Hier] $bcache_classifier_ 0
-    $bcache_classifier_ defaulttarget $classifier_hier_    
-    
-    if { $dmux_ == "" } {
-        set dmux_ [new Classifier/Port/Reserve]
-        $dmux_ set mask_ 0x7fffffff
-        $dmux_ set shift_ 0
-        
-        if [Simulator set EnableHierRt_] {  
-	    $classifier_hier_ install $address_ $dmux_
-            #$self add-hroute $address_ $dmux_
-        } else {
-            $self add-route $address_ $dmux_
-        }
-    } 
-    $self attach-redirect
-    
-    set regagent_ [new Agent/MIPv6/$mipagent_ $self]
-    $self attach $regagent_ [Simulator set MIPv6_PORT]
-    $regagent_ node $self
+	$self test-mcast
+
+	# src_classifier_ swithes among bcache_classifier_roaming_ ,
+	# bcache_classifier_at_home_ , and null_agent_when_lose_HA_
+	set bcache_classifier_roaming_ [new Classifier/Hash/Dest 8]
+	$bcache_classifier_roaming_ set mask_ 0xffffffff
+	$bcache_classifier_roaming_ set shift_ 0
+
+	set bcache_classifier_at_home_ [new Classifier/Hash/Dest 8]
+	$bcache_classifier_at_home_ set mask_ 0xffffffff
+	$bcache_classifier_at_home_ set shift_ 0
+
+	set null_agent_when_lose_HA_ [new Agent/Null]
+
+	set src_classifier_ [new Classifier/Hash/Src 2]
+	$src_classifier_ set mask_ 0xffffffff
+	$src_classifier_ set shift_ 0
+
+	if [Simulator set EnableHierRt_] {
+		set nodeaddr [AddrParams addr2id $address_]
+	} else {
+		set nodeaddr [expr ( $address_ &				\
+				[AddrParams set NodeMask 1] ) <<		\
+				[AddrParams set NodeShift 1]]
+	}
+	# MN should not communicate using its hoa before registering
+	$src_classifier_ install $nodeaddr $null_agent_when_lose_HA_
 
-    # $self attach-decap
-    $self attach-decapsulator
+	$self insert-entry [$self get-module Hier] $src_classifier_ 0
+	$src_classifier_ defaulttarget $classifier_hier_
+
+	if { $dmux_ == "" } {
+		set dmux_ [new Classifier/Port/Reserve]
+		$dmux_ set mask_ 0x7fffffff
+		$dmux_ set shift_ 0
+
+		if [Simulator set EnableHierRt_] {  
+		$classifier_hier_ install $address_ $dmux_
+			#$self add-hroute $address_ $dmux_
+		} else {
+			$self add-route $address_ $dmux_
+		}
+	}
+	$self attach-redirect "MN"
+
+	set regagent_ [new Agent/MIPv6/$mipagent_ $self]
+	$self attach $regagent_ [Simulator set MIPv6_PORT]
+	$regagent_ node $self
+
+	set dst_header [$self set dst_header_]
+	set encap [$self set encap_]
+	$bcache_classifier_roaming_ defaulttarget $encap
+	$bcache_classifier_at_home_ defaulttarget $classifier_hier_
+	$dst_header mipagent $regagent_
+	$encap mipagent $regagent_
+
+	# $self attach-decap
+	$self attach-decapsulator
 }
 
 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 Node instproc set-node-addressMN { args } {
 }
@@ -418,93 +467,112 @@
 # are mobile IPv6-enable and able to encapsulate 
 # XXX: makemip-NewBS and MN should call makemip-NewHier directly
 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 Node instproc makemip-NewHier {} {
     
-    $self instvar regagent_ encap_ agents_ address_ dmux_ id_ classifier_hier_
-    $self instvar bcache_classifier_
-    set mipagent_ [[Simulator instance] set mipagent_]
-    $self test-mcast
-    
-    set bcache_classifier_ [new Classifier/Hash/Dest 8]
-    $bcache_classifier_ set mask_ 0xffffffff
-    $bcache_classifier_ set shift_ 0
-    
-    $self insert-entry [$self get-module Hier] $bcache_classifier_ 0
-    $bcache_classifier_ defaulttarget $classifier_hier_
-    
-    if { $dmux_ == "" } {
-	set dmux_ [new Classifier/Port/Reserve]
-	$dmux_ set mask_ 0x7fffffff
-	$dmux_ set shift_ 0
+	$self instvar regagent_ decap_ dmux_ address_ classifier_hier_ 
+	$self instvar src_classifier_ bcache_classifier_ src_routing_
 
-	if [Simulator set EnableHierRt_] {
-	    $classifier_hier_ install $address_ $dmux_
-	    #$self add-hroute $address_ $dmux_
-	} else {
-	    $self add-route $address_ $dmux_
+	set mipagent_ [[Simulator instance] set mipagent_]
+
+	$self test-mcast
+
+	set bcache_classifier_ [new Classifier/Hash/Dest 8]
+	$bcache_classifier_ set mask_ 0xffffffff
+	$bcache_classifier_ set shift_ 0
+
+	$self insert-entry [$self get-module Hier] $bcache_classifier_ 0
+	$bcache_classifier_ defaulttarget $classifier_hier_
+
+	if { $dmux_ == "" } {
+		set dmux_ [new Classifier/Port/Reserve]
+		$dmux_ set mask_ 0x7fffffff
+		$dmux_ set shift_ 0
+
+		if [Simulator set EnableHierRt_] {  
+			$classifier_hier_ install $address_ $dmux_
+			set nodeaddr [AddrParams addr2id $address_]
+			#$self add-hroute $address_ $dmux_
+		} else {
+			$self add-route $address_ $dmux_
+			set nodeaddr [expr ( $address_ &			\
+				[AddrParams set NodeMask 1] ) <<		\
+				[AddrParams set NodeShift 1]]
+		}
 	}
-    }
-    $self attach-redirect
-    set regagent_ [new Agent/MIPv6/$mipagent_ $self]
-    $self attach $regagent_ [Simulator set MIPv6_PORT]
-    
+	$self attach-redirect "CN"
+
+	set src_classifier_ [new Classifier/Hash/Src 2]
+	$src_classifier_ set mask_ 0xffffffff
+	$src_classifier_ set shift_ 0 
+	$src_classifier_ defaulttarget $classifier_hier_
+	$src_classifier_ install $nodeaddr $src_routing_
+
+	set regagent_ [new Agent/MIPv6/$mipagent_ $self]
+	$self attach $regagent_ [Simulator set MIPv6_PORT]
+
+	# $self attach-decap
+	$self attach-decapsulator
+
 }
 
 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 # This procedure allows the node to redirect packets.
 # (Source routing or tunneling)
 # NodeMobileNode and Node both call this proc. 
 # XXX: originally Node instproc attach-encap
 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Node instproc attach-redirect {} {
-    
-    $self instvar encap_ address_ classifiers_ bcache_classifier_
-    $self instvar src_routing_ src_classifier_ classifier_ classifier_hier_
-    
-    
-    if [Simulator set EnableHierRt_] {
-        set nodeaddr [AddrParams addr2id $address_]
-    } else {
-        set nodeaddr [expr ( $address_ &                        \
-				 [AddrParams set NodeMask 1] ) <<      \
-			  [AddrParams set NodeShift 1]]
-    }
+Node instproc attach-redirect { nodetype_ } {
     
-    # For Routing header insertion
-    set src_routing_ [new SrcRouting]
-    $src_routing_ set port_ [Simulator set RT_HDR_PORT] 
-    $src_routing_ set node_ $self
-    $self attach $src_routing_ [Simulator set RT_HDR_PORT]
-    $src_routing_ node $self
-    
-    # For Encapsulation
-    set encap_ [new MIPEncapsulator]
-    $encap_ set addr_ $nodeaddr
-    $encap_ set port_ 1
-    #$encap_ target $classifiers_(1)
-    $encap_ target $classifier_hier_ 
-    $encap_ set node_ $self
-    
-    # To decide (in case we have an entry in the binding cache)
-    # if packet should be sent using a routing header 
-    # (source = local node) or using tunneling 
-    set src_classifier_ [new Classifier/Hash/Src 2]
-    $src_classifier_ set mask_ 0xffffffff
-    $src_classifier_ set shift_ 0 
-    $src_classifier_ defaulttarget $encap_
-    $src_classifier_ install $nodeaddr $src_routing_
-    
-    
-    set ns_ [Simulator instance]
-    if { [$self lbmcast?] || [$ns_ multicast?] } {
-        $self instvar switch_
+	$self instvar address_ classifier_hier_ src_classifier_
+	$self instvar encap_ src_routing_ dst_header_
 
-    	# Link switch to bcache_classifier instead of classifier_
-    	$switch_ install 0 $bcache_classifier_
-    }
+	if [Simulator set EnableHierRt_] {
+		set nodeaddr [AddrParams addr2id $address_]
+	} else {
+		set nodeaddr [expr ( $address_ &				\
+				[AddrParams set NodeMask 1] ) <<		\
+				[AddrParams set NodeShift 1]]
+	}
+
+	# For Routing header insertion
+	set src_routing_ [new SrcRouting]
+	$src_routing_ set port_ [Simulator set RT_HDR_PORT] 
+	$src_routing_ set node_ $self
+	$self attach $src_routing_ [Simulator set RT_HDR_PORT]
+	$src_routing_ node $self
+
+	set dst_header_ [new DstHeader]
+	$dst_header_ set port_ [Simulator set DEST_HDR_PORT]
+	$dst_header_ set node_ $self
+	$self attach $dst_header_ [Simulator set DEST_HDR_PORT]
+	$dst_header_ node $self
+	$dst_header_ src-routing $src_routing_
 
+	# For Encapsulation
+	if { $nodetype_ == "MN" } {
+		set encap_ [new MIPEncapsulatorFromMN]
+		$src_routing_ belong-to-mobile-node 1
+		$dst_header_ belong-to-mobile-node 1
+	} else {
+		set encap_ [new MIPEncapsulatorToMN]
+		$src_routing_ belong-to-mobile-node 0
+		$dst_header_ belong-to-mobile-node 0
+	}
+	$encap_ set addr_ $nodeaddr
+	$encap_ set port_ 1
+	#$encap_ target $classifiers_(1)
+	$encap_ target $classifier_hier_ 
+	$encap_ set node_ $self
+
+	set ns_ [Simulator instance]
+	if { [$self lbmcast?] || [$ns_ multicast?] } {
+		$self instvar switch_
+
+		# Link switch to bcache_classifier instead of classifier_
+		$switch_ install 0 $src_classifier_
+	}
 }
 
 
 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 Agent/MIPv6 instproc init args {
@@ -532,25 +600,31 @@
     eval $self next $args
     $self set-beacon-period 1.0; # default value
 }
 
 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Agent/MIPv6/BS instproc encap-route { mhaddr coa lifetime } {
-    $self instvar node_ TunnelExit_ RegTimer_
-    
-    set ns [Simulator instance]
-    set bcache [$node_ set bcache_classifier_]
-    set target [$node_ set src_classifier_]
-    
-    # Make slot points to src_classifier if packet ought to be redirected 
-    $bcache install $mhaddr $target
-    
-    set TunnelExit_($mhaddr) $coa
-    if { [info exists RegTimer_($mhaddr)] && $RegTimer_($mhaddr) != "" } {
-	$ns cancel $RegTimer_($mhaddr)
-    }
-    set RegTimer_($mhaddr) [$ns at [expr [$ns now] + $lifetime] \
+Agent/MIPv6/BS instproc encap-route { homereg mhaddr coa lifetime } {
+	$self instvar node_ TunnelExit_ RegTimer_
+
+	set ns [Simulator instance]
+	set bcache [$node_ set bcache_classifier_]
+	set src_clsfr [$node_ set src_classifier_]
+	set encap [$node_ set encap_]
+
+	# Make slot points to encap_ if the BS is registered as a CN
+	# Make slot points to src_classifier_ if the BS is registered as an HA
+	if {$homereg != 0} {
+		$bcache install $mhaddr $encap
+	} else {
+		$bcache install $mhaddr $src_clsfr
+	}
+
+	set TunnelExit_($mhaddr) $coa
+	if { [info exists RegTimer_($mhaddr)] && $RegTimer_($mhaddr) != "" } {
+		$ns cancel $RegTimer_($mhaddr)
+	}
+	set RegTimer_($mhaddr) [$ns at [expr [$ns now] + $lifetime] \
 				"$self clear-reg $mhaddr"]
 }
 
 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 Agent/MIPv6/BS instproc clear-reg mhaddr {
@@ -571,16 +645,17 @@
 # Agent MN (Mobile Node)
 # ##########################################################################
 
 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 Agent/MIPv6/MN instproc init args {
-    
-    eval $self next $args
 
-    # Set beacon period and starts the beacon timer.
-    # Allow one beacon to be lost before deciding we have lost contact
-    $self check-beacon 2.3     ;# default value
+	eval $self next $args
+
+	# Set beacon period and starts the beacon timer.
+	# Allow one beacon to be lost before deciding we have lost contact
+	$self check-bs-beacon 2.3
+	$self check-bu-beacon 5
 }
 
 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 # Return the careof address = prefix of base station + node id % 128.
 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -589,36 +664,96 @@
     set prefix [get_subnet_prefix $bs_addr]
     set suffix [expr [$node_ set id_] % 128]
     return [AddrParams set-hieraddr $prefix.$suffix]
 }
 
+Agent/MIPv6/MN instproc lost-ha { hoa } {
+	$self instvar node_
+	set null_agent_ [$node_ set null_agent_when_lose_HA_]
+	set src_classifier_ [$node_ set src_classifier_]
+	$src_classifier_ install $hoa $null_agent_
+}
+
+Agent/MIPv6/MN instproc finish-home-reg { hoa } {
+	$self instvar node_
+	set bcache_classifier_ [$node_ set bcache_classifier_roaming_]
+	set src_classifier_ [$node_ set src_classifier_]
+	$src_classifier_ install $hoa $bcache_classifier_
+}
+
+Agent/MIPv6/MN instproc go-back-home { hoa } {
+	$self instvar node_
+	set bcache_classifier_ [$node_ set bcache_classifier_at_home_]
+	set src_classifier_ [$node_ set src_classifier_]
+	$src_classifier_ install $hoa $bcache_classifier_
+}
+
+Agent/MIPv6/MN instproc set-tunnel-exit { mhaddr coa } {
+	$self instvar TunnelExit_
+	set TunnelExit_($mhaddr) $coa
+}
+
+Agent/MIPv6/MN instproc bind-as-cn { mhaddr } {
+	$self instvar node_
+	set bcache_roaming [$node_ set bcache_classifier_roaming_]
+	set bcache_at_home [$node_ set bcache_classifier_at_home_]
+	set src_rt [$node_ set src_routing_]
+	$bcache_roaming install $mhaddr $src_rt
+	$bcache_at_home install $mhaddr $src_rt
+}
+
+Agent/MIPv6/MN instproc bind-as-mn { mhaddr } {
+	$self instvar node_
+	set bcache [$node_ set bcache_classifier_roaming_]
+	set dst_hdr [$node_ set dst_header_]
+	$bcache install $mhaddr $dst_hdr
+}
+
+Agent/MIPv6/MN instproc clear-reg-as-mn { mhaddr } {
+	$self instvar node_ encap_
+	set bcache [$node_ set bcache_classifier_roaming_]
+	set target [$node_ set encap_]
+	$bcache install $mhaddr $target
+}
+
+Agent/MIPv6/MN instproc clear-reg-as-cn { mhaddr } {
+	$self instvar node_ encap_
+	set bcache_roaming [$node_ set bcache_classifier_roaming_]
+	set bcache_at_home [$node_ set bcache_classifier_at_home_]
+	set target [$node_ set encap_]
+	$bcache_roaming install $mhaddr $target
+	$bcache_at_home install $mhaddr $target
+}
+
 # ##########################################################################
 # Agent CN (Correspondent Node)
 # ##########################################################################
 
 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 Agent/MIPv6/CN instproc init args {	
     eval $self next $args
 }
 
 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Agent/MIPv6/CN instproc encap-route { mhaddr coa lifetime } {
-    $self instvar node_ TunnelExit_ RegTimer_
-    
-    set ns [Simulator instance]
-    set bcache [$node_ set bcache_classifier_]
-    set target [$node_ set src_classifier_]
-    
-    # Make slot points to src_classifier if packet ought to be redirected 
-    $bcache install $mhaddr $target
-    
-    set TunnelExit_($mhaddr) $coa
-    if { [info exists RegTimer_($mhaddr)] && $RegTimer_($mhaddr) != "" } {
-        $ns cancel $RegTimer_($mhaddr)
-    }
-    set RegTimer_($mhaddr) [$ns at [expr [$ns now] + $lifetime] \
-				"$self clear-reg $mhaddr"]
+Agent/MIPv6/CN instproc encap-route { homereg mhaddr coa lifetime } {
+	$self instvar node_ TunnelExit_ RegTimer_
+
+	set ns [Simulator instance]
+	set bcache [$node_ set bcache_classifier_]
+	set target [$node_ set src_classifier_]
+
+	if { $homereg == 0 } {
+		# Make slot points to src_classifier if packet ought to be redirected 
+		$bcache install $mhaddr $target
+
+		set TunnelExit_($mhaddr) $coa
+		if { [info exists RegTimer_($mhaddr)] && $RegTimer_($mhaddr) != "" } {
+			$ns cancel $RegTimer_($mhaddr)
+		}
+		set RegTimer_($mhaddr) [$ns at [expr [$ns now] + $lifetime] \
+					"$self clear-reg $mhaddr"]
+	}
 }
 
 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 # Clear Binding between MN's home address and MN's COA.
 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -664,10 +799,12 @@
     } else {
 	if { $nodetype_ == "MN" } {
 	    set ragent [new Agent/Network/NetworkMN]
 	    $ragent mip-agent [$node set regagent_]
 	    $ragent decap-port [Simulator set DECAP_PORT]
+		$ragent dest-hdr-port [Simulator set DEST_HDR_PORT]
+		$ragent src-rt-port [Simulator set RT_HDR_PORT]
 	} else {
 	    puts "Wrong Routing Agent"
 	}
     }
     
@@ -691,6 +828,9 @@
     
     return $ragent
 }
 
 
-
+MIPEncapsulatorToMN instproc tunnel-exit mhaddr {
+	$self instvar node_
+	return [[$node_ set regagent_] set TunnelExit_($mhaddr)]
+}
diff -urNU5 ns-2.33-mobiwan/tcl/lib/ns-packet.tcl ns-2.33-mobiwan-rfc3775/tcl/lib/ns-packet.tcl
--- ns-2.33-mobiwan/tcl/lib/ns-packet.tcl	2008-05-06 15:13:25.000000000 +1000
+++ ns-2.33-mobiwan-rfc3775/tcl/lib/ns-packet.tcl	2008-05-06 15:13:58.000000000 +1000
@@ -163,16 +163,20 @@
 # Mobility, Ad-Hoc Networks, Sensor Nets:
 	AODV 	# routing protocol for ad-hoc networks
 	Diffusion 	# diffusion/diffusion.cc
 	IMEP 	# Internet MANET Encapsulation Protocol, for ad-hoc networks
         MIP 	# Mobile IP, mobile/mip-reg.cc
+	MIPv6
 	Smac 	# Sensor-MAC
 	TORA 	# routing protocol for ad-hoc networks
 # Other:
 	Encap 	# common/encap.cc
         IPinIP 	# IP encapsulation 
 	HDLC 	# High Level Data Link Control
+	Dst
+	RTADS
+	Routing
 } {
 	add-packet-header $prot
 }
 
 proc PktHdr_offset { hdrName {field ""} } {
diff -urNU5 ns-2.33-mobiwan/tcl/mobiwan/mobiwan_test_bidirct.tcl ns-2.33-mobiwan-rfc3775/tcl/mobiwan/mobiwan_test_bidirct.tcl
--- ns-2.33-mobiwan/tcl/mobiwan/mobiwan_test_bidirct.tcl	1970-01-01 10:00:00.000000000 +1000
+++ ns-2.33-mobiwan-rfc3775/tcl/mobiwan/mobiwan_test_bidirct.tcl	2008-05-06 15:13:58.000000000 +1000
@@ -0,0 +1,175 @@
+# Basic Mobile IPv6 example without using ns-topoman
+# Needs proc defined in file proc-mipv6-config.tcl
+
+Agent/MIPv6/MN set bs_forwarding_     0       ; # 1 if forwarding from previous BS
+################################################################
+proc log-mn-movement_no_topo { } {
+  global logtimer ns
+  Class LogTimer -superclass Timer
+  LogTimer instproc timeout {} {
+ 	global mobile_
+        $mobile_ log-movement 
+        $self sched 1 
+  }
+  set logtimer [new LogTimer]
+  $logtimer sched 1  
+}
+
+################################################################
+# Create Topology
+################################################################
+proc create-my-topo {} {
+  global ns opt topo mobile_ cn_ mnn_nodes_
+
+  # Create and define topography
+  set topo        [new Topography]
+  #   set prop        [new $opt(prop)]
+  #   $prop topography $topo
+  $topo load_flatgrid 800 800 
+
+  # god is a necessary object when wireless is used
+  # set to a value equal to the number of mobile nodes
+  create-god 5 
+
+  # Call node-config
+  $ns node-config \
+        -addressType hierarchical \
+ 	-agentTrace ON \
+ 	-routerTrace ON 
+
+  # Set NS Addressing
+  AddrParams set domain_num_ 2 
+  AddrParams set cluster_num_ {1 5}
+  AddrParams set nodes_num_ {1 1 2 1 1 1}
+
+  # Create Nodes
+  set cn_ [create-router 0.0.0]
+  set router_ [create-router 1.0.0]
+  set bs1_ [create-base-station 1.1.0 1.0.0 200 200 0]
+  set bs2_ [create-base-station 1.2.0 1.0.0 200 600 0]
+  set bs3_ [create-base-station 1.3.0 1.0.0 600 200 0]
+  set bs4_ [create-base-station 1.4.0 1.0.0 600 600 0]
+  set mobile_ [create-mobile 1.1.1 1.1.0 190 190 0 0 0.01]
+
+
+  # Create Links
+  $ns duplex-link $cn_ $router_ 100Mb 1.80ms DropTail
+  $ns duplex-link $router_ $bs1_ 100Mb 1.80ms DropTail
+  $ns duplex-link $router_ $bs2_ 100Mb 1.80ms DropTail
+
+  display_ns_addr_domain
+}
+
+################################################################
+# End of Simulation
+################################################################
+proc finish { } {
+  global tracef ns namf opt mobile_ cn_
+  
+  puts "Simulation finished" 
+  # Dump the Binding Update List of MN and Binding Cache of HA
+  [[$mobile_ set ha_] set regagent_] dump
+  [$cn_ set regagent_] dump
+  [$mobile_ set regagent_] dump
+
+  $ns flush-trace
+  flush $tracef
+  close $tracef
+  close $namf
+  #puts "running nam with $opt(namfile) ... "
+  #exec nam $opt(namfile) &
+  exit 0
+}
+
+
+################################################################
+# Main 
+################################################################
+proc main { } {
+   global opt ns TOPOM namf n tracef mobile_ cn_ 
+   # Source Files
+   # source set-def-options.tcl 
+   # set BASEDIR to your own correct path
+   set BASEDIR ../..
+   source $BASEDIR/tcl/lib/proc-mipv6-config.tcl
+   source $BASEDIR/tcl/lib/proc-tools.tcl
+   source $BASEDIR/tcl/lib/proc-topo.tcl
+   source $BASEDIR/tcl/lib/ns-topoman.tcl
+   source $BASEDIR/tcl/lib/proc-mobi-global.tcl
+   source $BASEDIR/tcl/lib/proc-mobi-config.tcl
+   source $BASEDIR/tcl/mobility/timer.tcl
+
+   set NAMF out.nam
+   set TRACEF out.tr
+   set INFOF out.info
+
+   set opt(mactrace) ON
+   set opt(NAM) 1 
+   set opt(namfile) $NAMF
+   set opt(stop) 175
+   set opt(tracefile) $TRACEF
+   
+   #>--------------- Extract options from command line ---------------<
+   #Getopt	; # Get option from the command line	
+   #DisplayCommandLine
+   
+   #>---------------------- Simulator Settings ----------------------<
+   set ns [new Simulator]
+   #>------------------------ Open trace files ----------------------<
+   exec rm -f $opt(tracefile)
+   set tracef [open $opt(tracefile) w]
+   #... dump the file
+   $ns trace-all $tracef
+    
+   set namf [open $opt(namfile) w]
+   $ns namtrace-all $namf
+
+   #>------------- Protocol and Topology Settings -------------------<
+   create-my-topo
+   log-mn-movement_no_topo
+   
+   set-cbr
+   # set-ping-int 0.1 $cn_ $mobile_ 10 $opt(stop)
+
+
+   #>----------------------- Run Simulation -------------------------<
+   $ns at $opt(stop) "finish"
+	$mobile_ setdest 210 610 4
+	$ns at 100 "$mobile_ setdest 190 190 5"
+   $ns run
+
+   $ns dump-topology $namf
+   close $namf
+   #puts "running nam with $opt(namfile) ... "
+   #exec nam $opt(namfile) &
+}
+
+proc set-cbr { } {
+	global ns cn_ mobile_
+	set udp1 [new Agent/UDP]
+	set udp2 [new Agent/UDP]
+	$ns attach-agent $cn_ $udp1
+	$ns attach-agent $mobile_ $udp2
+
+	set dst1 [new Agent/Null]
+	set dst2 [new Agent/Null]
+	$ns attach-agent $mobile_ $dst1
+	$ns attach-agent $cn_ $dst2
+	$ns connect $udp1 $dst1
+	$ns connect $udp2 $dst2
+
+	set src1 [new Application/Traffic/CBR]
+	set src2 [new Application/Traffic/CBR]
+	$src1 set packetSize_ 1000
+	$src1 set rate_ 100k
+	$src1 set interval_ 0.05
+	$src1 attach-agent $udp1
+	$src2 set packetSize_ 500
+	$src2 set rate_ 50k
+	$src2 set interval_ 0.1
+	$src2 attach-agent $udp2
+	$ns at 20.0 "$src1 start"
+	$ns at 30.0 "$src2 start"
+}
+
+main
diff -urNU5 ns-2.33-mobiwan/tcl/mobiwan/mobiwan_test_faster.tcl ns-2.33-mobiwan-rfc3775/tcl/mobiwan/mobiwan_test_faster.tcl
--- ns-2.33-mobiwan/tcl/mobiwan/mobiwan_test_faster.tcl	1970-01-01 10:00:00.000000000 +1000
+++ ns-2.33-mobiwan-rfc3775/tcl/mobiwan/mobiwan_test_faster.tcl	2008-05-06 15:13:58.000000000 +1000
@@ -0,0 +1,162 @@
+# Basic Mobile IPv6 example without using ns-topoman
+# Needs proc defined in file proc-mipv6-config.tcl
+
+Agent/MIPv6/MN set bs_forwarding_     0       ; # 1 if forwarding from previous BS
+################################################################
+proc log-mn-movement_no_topo { } {
+  global logtimer ns
+  Class LogTimer -superclass Timer
+  LogTimer instproc timeout {} {
+ 	global mobile_
+        $mobile_ log-movement 
+        $self sched 1 
+  }
+  set logtimer [new LogTimer]
+  $logtimer sched 1  
+}
+
+################################################################
+# Create Topology
+################################################################
+proc create-my-topo {} {
+  global ns opt topo mobile_ cn_ mnn_nodes_
+
+  # Create and define topography
+  set topo        [new Topography]
+  #   set prop        [new $opt(prop)]
+  #   $prop topography $topo
+  $topo load_flatgrid 800 800 
+
+  # god is a necessary object when wireless is used
+  # set to a value equal to the number of mobile nodes
+  create-god 5 
+
+  # Call node-config
+  $ns node-config \
+        -addressType hierarchical \
+ 	-agentTrace ON \
+ 	-routerTrace ON 
+
+  # Set NS Addressing
+  AddrParams set domain_num_ 2 
+  AddrParams set cluster_num_ {1 5}
+  AddrParams set nodes_num_ {1 1 3 1 1 1}
+
+  # Create Nodes
+  set cn_ [create-router 0.0.0]
+  set router_ [create-router 1.0.0]
+  set bs1_ [create-base-station 1.1.0 1.0.0 200 200 0]
+  set bs2_ [create-base-station 1.2.0 1.0.0 200 600 0]
+  set bs3_ [create-base-station 1.3.0 1.0.0 600 200 0]
+  set bs4_ [create-base-station 1.4.0 1.0.0 600 600 0]
+  set mobile_ [create-mobile 1.1.1 1.1.0 190 190 0 1 0.01]
+
+
+  # Create Links
+  $ns duplex-link $cn_ $router_ 100Mb 1.80ms DropTail
+  $ns duplex-link $router_ $bs1_ 100Mb 1.80ms DropTail
+  $ns duplex-link $router_ $bs2_ 100Mb 1.80ms DropTail
+
+  display_ns_addr_domain
+}
+
+################################################################
+# End of Simulation
+################################################################
+proc finish { } {
+  global tracef ns namf opt mobile_ cn_
+  
+  puts "Simulation finished" 
+  # Dump the Binding Update List of MN and Binding Cache of HA
+  [[$mobile_ set ha_] set regagent_] dump
+  [$cn_ set regagent_] dump
+  [$mobile_ set regagent_] dump
+
+  $ns flush-trace
+  flush $tracef
+  close $tracef
+  close $namf
+  #puts "running nam with $opt(namfile) ... "
+  #exec nam $opt(namfile) &
+  exit 0
+}
+
+
+################################################################
+# Main 
+################################################################
+proc main { } {
+   global opt ns TOPOM namf n tracef mobile_ cn_ 
+   # Source Files
+   # source set-def-options.tcl 
+   # set BASEDIR to your own correct path
+   set BASEDIR ../..
+   source $BASEDIR/tcl/lib/proc-mipv6-config.tcl
+   source $BASEDIR/tcl/lib/proc-tools.tcl
+   source $BASEDIR/tcl/lib/proc-topo.tcl
+   source $BASEDIR/tcl/lib/ns-topoman.tcl
+   source $BASEDIR/tcl/lib/proc-mobi-global.tcl
+   source $BASEDIR/tcl/lib/proc-mobi-config.tcl
+   source $BASEDIR/tcl/mobility/timer.tcl
+
+   set NAMF out.nam
+   set TRACEF out.tr
+   set INFOF out.info
+
+   set opt(mactrace) ON
+   set opt(NAM) 1 
+   set opt(namfile) $NAMF
+   set opt(stop) 100
+   set opt(tracefile) $TRACEF
+   
+   #>--------------- Extract options from command line ---------------<
+   #Getopt	; # Get option from the command line	
+   #DisplayCommandLine
+   
+   #>---------------------- Simulator Settings ----------------------<
+   set ns [new Simulator]
+   #>------------------------ Open trace files ----------------------<
+   exec rm -f $opt(tracefile)
+   set tracef [open $opt(tracefile) w]
+   #... dump the file
+   $ns trace-all $tracef
+    
+   set namf [open $opt(namfile) w]
+   $ns namtrace-all $namf
+
+   #>------------- Protocol and Topology Settings -------------------<
+   create-my-topo
+   log-mn-movement_no_topo
+   
+   set-cbr
+   # set-ping-int 0.1 $cn_ $mobile_ 10 $opt(stop)
+
+
+   #>----------------------- Run Simulation -------------------------<
+   $ns at $opt(stop) "finish"
+   $ns run
+
+   $ns dump-topology $namf
+   close $namf
+   #puts "running nam with $opt(namfile) ... "
+   #exec nam $opt(namfile) &
+}
+
+proc set-cbr { } {
+   global ns cn_ mobile_
+   set udp [new Agent/UDP]
+   $ns attach-agent $cn_ $udp
+   
+   set dst [new Agent/Null]
+   $ns attach-agent $mobile_ $dst
+   $ns connect $udp $dst
+
+   set src [new Application/Traffic/CBR]
+   $src set packetSize_ 1000
+   $src set rate_ 100k
+   $src set interval_ 0.01
+   $src attach-agent $udp
+   $ns at 20.0 "$src start"
+} 
+
+main
diff -urNU5 ns-2.33-mobiwan/tcl/mobiwan/mobiwan_test_mntomn.tcl ns-2.33-mobiwan-rfc3775/tcl/mobiwan/mobiwan_test_mntomn.tcl
--- ns-2.33-mobiwan/tcl/mobiwan/mobiwan_test_mntomn.tcl	1970-01-01 10:00:00.000000000 +1000
+++ ns-2.33-mobiwan-rfc3775/tcl/mobiwan/mobiwan_test_mntomn.tcl	2008-05-06 15:13:58.000000000 +1000
@@ -0,0 +1,180 @@
+# Basic Mobile IPv6 example without using ns-topoman
+# Needs proc defined in file proc-mipv6-config.tcl
+
+Agent/MIPv6/MN set bs_forwarding_     0       ; # 1 if forwarding from previous BS
+################################################################
+proc log-mn-movement_no_topo { } {
+  global logtimer ns
+  Class LogTimer -superclass Timer
+  LogTimer instproc timeout {} {
+	global mobile1_ mobile2_
+	$mobile1_ log-movement
+	$mobile2_ log-movement
+        $self sched 1
+  }
+  set logtimer [new LogTimer]
+  $logtimer sched 1
+}
+
+################################################################
+# Create Topology
+################################################################
+proc create-my-topo {} {
+  global ns opt topo mobile1_ mobile2_ cn_ mnn_nodes_
+
+  # Create and define topography
+  set topo        [new Topography]
+  #   set prop        [new $opt(prop)]
+  #   $prop topography $topo
+  $topo load_flatgrid 800 800 
+
+  # god is a necessary object when wireless is used
+  # set to a value equal to the number of mobile nodes
+  create-god 6
+
+  # Call node-config
+  $ns node-config \
+        -addressType hierarchical \
+ 	-agentTrace ON \
+ 	-routerTrace ON 
+
+  # Set NS Addressing
+  AddrParams set domain_num_ 2 
+  AddrParams set cluster_num_ {1 5}
+  AddrParams set nodes_num_ {1 1 2 1 2 1}
+
+  # Create Nodes
+  set cn_ [create-router 0.0.0]
+  set router_ [create-router 1.0.0]
+  set bs1_ [create-base-station 1.1.0 1.0.0 200 200 0]
+  set bs2_ [create-base-station 1.2.0 1.0.0 200 600 0]
+  set bs3_ [create-base-station 1.3.0 1.0.0 600 200 0]
+  set bs4_ [create-base-station 1.4.0 1.0.0 600 600 0]
+	set mobile1_ [create-mobile 1.1.1 1.1.0 190 190 0 0 0.01]
+	set mobile2_ [create-mobile 1.3.1 1.3.0 590 590 0 0 0.01]
+
+	$mobile1_ setdest 210 610 4
+	$mobile2_ setdest 610 610 0.28
+
+
+  # Create Links
+  $ns duplex-link $cn_ $router_ 100Mb 1.80ms DropTail
+  $ns duplex-link $router_ $bs1_ 100Mb 1.80ms DropTail
+  $ns duplex-link $router_ $bs2_ 100Mb 1.80ms DropTail
+
+  display_ns_addr_domain
+}
+
+################################################################
+# End of Simulation
+################################################################
+proc finish { } {
+  global tracef ns namf opt mobile1_ mobile2_ cn_
+  
+  puts "Simulation finished" 
+  # Dump the Binding Update List of MN and Binding Cache of HA
+	[[$mobile1_ set ha_] set regagent_] dump
+	[[$mobile2_ set ha_] set regagent_] dump
+	[$cn_ set regagent_] dump
+	[$mobile1_ set regagent_] dump
+	[$mobile2_ set regagent_] dump
+
+  $ns flush-trace
+  flush $tracef
+  close $tracef
+  close $namf
+  #puts "running nam with $opt(namfile) ... "
+  #exec nam $opt(namfile) &
+  exit 0
+}
+
+
+################################################################
+# Main 
+################################################################
+proc main { } {
+   global opt ns TOPOM namf n tracef mobile1_ mobile2_ cn_ 
+   # Source Files
+   # source set-def-options.tcl 
+   # set BASEDIR to your own correct path
+   set BASEDIR ../..
+   source $BASEDIR/tcl/lib/proc-mipv6-config.tcl
+   source $BASEDIR/tcl/lib/proc-tools.tcl
+   source $BASEDIR/tcl/lib/proc-topo.tcl
+   source $BASEDIR/tcl/lib/ns-topoman.tcl
+   source $BASEDIR/tcl/lib/proc-mobi-global.tcl
+   source $BASEDIR/tcl/lib/proc-mobi-config.tcl
+   source $BASEDIR/tcl/mobility/timer.tcl
+
+   set NAMF out.nam
+   set TRACEF out.tr
+   set INFOF out.info
+
+   set opt(mactrace) ON
+   set opt(NAM) 1 
+   set opt(namfile) $NAMF
+   set opt(stop) 100
+   set opt(tracefile) $TRACEF
+   
+   #>--------------- Extract options from command line ---------------<
+   #Getopt	; # Get option from the command line	
+   #DisplayCommandLine
+   
+   #>---------------------- Simulator Settings ----------------------<
+   set ns [new Simulator]
+   #>------------------------ Open trace files ----------------------<
+   exec rm -f $opt(tracefile)
+   set tracef [open $opt(tracefile) w]
+   #... dump the file
+   $ns trace-all $tracef
+    
+   set namf [open $opt(namfile) w]
+   $ns namtrace-all $namf
+
+   #>------------- Protocol and Topology Settings -------------------<
+   create-my-topo
+   log-mn-movement_no_topo
+   
+   set-cbr
+   # set-ping-int 0.1 $cn_ $mobile_ 10 $opt(stop)
+
+
+   #>----------------------- Run Simulation -------------------------<
+   $ns at $opt(stop) "finish"
+   $ns run
+
+   $ns dump-topology $namf
+   close $namf
+   #puts "running nam with $opt(namfile) ... "
+   #exec nam $opt(namfile) &
+}
+
+proc set-cbr { } {
+	global ns mobile1_ mobile2_
+	set udp1 [new Agent/UDP]
+	set udp2 [new Agent/UDP]
+	$ns attach-agent $mobile1_ $udp1
+	$ns attach-agent $mobile2_ $udp2
+
+	set dst1 [new Agent/Null]
+	set dst2 [new Agent/Null]
+	$ns attach-agent $mobile2_ $dst1
+	$ns attach-agent $mobile1_ $dst2
+	$ns connect $udp1 $dst1
+	$ns connect $udp2 $dst2
+
+	set src1 [new Application/Traffic/CBR]
+	set src2 [new Application/Traffic/CBR]
+	$src1 set packetSize_ 500
+	$src1 set rate_ 100k
+	$src1 set interval_ 0.1
+	$src1 attach-agent $udp1
+	$src2 set packetSize_ 500
+	$src2 set rate_ 50k
+	$src2 set interval_ 0.1
+	$src2 attach-agent $udp2
+	$ns at 20.0 "$src1 start"
+	$ns at 30.0 "$src2 start"
+}
+
+main

