diff -u -r -N kame/freebsd5/sys/conf/options kame-tarzan/freebsd5/sys/conf/options
--- kame/freebsd5/sys/conf/options	Fri May 13 03:37:03 2005
+++ kame-tarzan/freebsd5/sys/conf/options	Fri Jul 29 00:02:06 2005
@@ -363,6 +363,7 @@
 SCOPEDEBUG		opt_inet6.h	# for debug only.  don't merge it.
 LARGE_LOMTU		opt_inet6.h
 MIP6			opt_mip6.h
+FMIP6			opt_mip6.h
 MIP6_MCOA		opt_mip6.h
 NATPT			opt_natpt.h
 NATPT_NAT		opt_natpt.h
diff -u -r -N kame/freebsd5/usr.sbin/shisad/mnd/Makefile kame-tarzan/freebsd5/usr.sbin/shisad/mnd/Makefile
--- kame/freebsd5/usr.sbin/shisad/mnd/Makefile	Wed May 25 10:55:14 2005
+++ kame-tarzan/freebsd5/usr.sbin/shisad/mnd/Makefile	Fri Jul 29 00:02:06 2005
@@ -31,6 +31,7 @@
 	fsm.c binding.c network.c  common.c fdlist.c command.c util.c
 SRCS+=	config.c cfparse.y cftoken.l
 CFLAGS+= -g -Wall -Werror -DMIP_MN
+CFLAGS+= -DFMIP6
 CFLAGS+= -I${.OBJDIR} -I${SRCDIR}
 
 LDADD+=	-L${.OBJDIR}/../../../lib/libinet6 \
diff -u -r -N kame/kame/kame/shisad/binding.c kame-tarzan/kame/kame/shisad/binding.c
--- kame/kame/kame/shisad/binding.c	Wed May 25 10:49:23 2005
+++ kame-tarzan/kame/kame/shisad/binding.c	Fri Jul 29 00:02:06 2005
@@ -561,8 +561,13 @@
 	
         bul = bul_get(&hoainfo->hinfo_hoa, peeraddr);
         if (bul != NULL) {
-		if (bid == 0) 
+		if (bid == 0)
+#ifndef FMIP6
 			return (bul);
+#else
+			if (IN6_ARE_ADDR_EQUAL(&bul->bul_coa, coa))
+				return (bul);
+#endif /* FMIP6 */
 #ifdef MIP_MCOA
 		else {
 			struct binding_update_list *bul2;
@@ -665,6 +670,10 @@
 		};
 	};
 #endif /* MIP_MCOA */
+#ifdef FMIP6
+	if (mipsock_bul_request(bul, MIPM_BUL_REMOVE))
+		syslog(LOG_ERR, "removing bul entry from kernel failed.\n");
+#endif /* FMIP6 */
 
 	LIST_REMOVE(bul, bul_entry);
 	free(bul);
diff -u -r -N kame/kame/kame/shisad/fsm.c kame-tarzan/kame/kame/shisad/fsm.c
--- kame/kame/kame/shisad/fsm.c	Thu Apr 14 15:22:35 2005
+++ kame-tarzan/kame/kame/shisad/fsm.c	Fri Jul 29 00:02:06 2005
@@ -1105,11 +1105,18 @@
 
 		case MIP6_BUL_FSM_EVENT_MOVEMENT:
 			/* in MIP6_BUL_REG_FSM_STATE_WAITAR */
+#ifdef FMIP6
+			if (bul->bul_state & MIP6_BUL_STATE_FMIP6)
+				goto skip_bul_remove;
+#endif /* FMIP6 */
 			if (mipsock_bul_request(bul, MIPM_BUL_REMOVE)) {
 				syslog(LOG_ERR,
 				    "removing bul entry from kernel "
 				    "failed.\n");
 			}
+#ifdef FMIP6
+skip_bul_remove:
+#endif /* FMIP6 */
 			if ((bul->bul_flags & IP6_MH_BU_HOME) != 0) {
 				error = send_bu(bul);
 				if (error) {
@@ -1839,6 +1846,26 @@
 			break;
 		}
 		break;
+
+#ifdef FMIP6
+	case MIP6_BUL_REG_FSM_STATE_FMIP6:
+		switch (event) {
+		case MIP6_BUL_FSM_EVENT_MOVEMENT:
+			bul_set_expire_timer(bul, bul->bul_lifetime << 2);
+			break;
+		case MIP6_BUL_FSM_EVENT_EXPIRE_TIMER:
+			bul_stop_timers(bul);
+
+			bul_remove(bul);
+			bul = NULL;
+
+			break;
+                default:
+			break;
+		}
+
+		break;
+#endif /* FMIP6 */
 
 	default:
 		syslog(LOG_ERR, "the state of the primary fsm is unknown.");
diff -u -r -N kame/kame/kame/shisad/fsm.h kame-tarzan/kame/kame/shisad/fsm.h
--- kame/kame/kame/shisad/fsm.h	Wed May 25 10:49:24 2005
+++ kame-tarzan/kame/kame/shisad/fsm.h	Fri Jul 29 00:02:06 2005
@@ -41,6 +41,7 @@
 #define MIP6_BUL_REG_FSM_STATE_WAITD		6
 #define MIP6_BUL_REG_FSM_STATE_BOUND		7
 #define MIP6_BUL_REG_FSM_STATE_DHAAD		8
+#define MIP6_BUL_REG_FSM_STATE_FMIP6            9
 
 /* states for the secondary fsm. */
 #define MIP6_BUL_RR_FSM_STATE_START	0
diff -u -r -N kame/kame/kame/shisad/mnd.c kame-tarzan/kame/kame/shisad/mnd.c
--- kame/kame/kame/shisad/mnd.c	Tue May 24 19:16:19 2005
+++ kame-tarzan/kame/kame/shisad/mnd.c	Fri Jul 29 00:02:06 2005
@@ -685,6 +685,10 @@
 #ifdef MIP_MCOA
 	struct binding_update_list *mbul;
 #endif /* MIP_MCOA */
+#ifdef FMIP6
+	struct binding_update_list *nbul;
+	u_int16_t coaifindex, pcoaifindex;
+#endif /* FMIP6 */
 
 	hoainfo = hoainfo_find_withhoa(hoa);
 	if (hoainfo == NULL)
@@ -783,7 +787,52 @@
 #endif /* MIP_MCOA */
 
 		/* update CoA */
+#ifndef FMIP6
 		memcpy(&bul->bul_coa, coa, sizeof(*coa));
+#else
+                /*
+                 *  1. set the state of binding as STATE_FMIP6
+                 *  2. create new binding with NCoA
+                 */
+
+                coaifindex = get_ifindex_from_address(coa);
+                pcoaifindex = get_ifindex_from_address(&bul->bul_coa);
+
+                if (bul->bul_state & MIP6_BUL_STATE_FMIP6) {
+                        syslog(LOG_INFO, "this bu is in STATE_FMIP6\n");
+                        continue;
+                }
+
+                if (is_in6_addr_loopback(coa)) {
+                        syslog(LOG_INFO, "this coa is loopback\n");
+                        continue;
+                }
+
+                if (((coaifindex == pcoaifindex) || is_in6_addr_loopback(&bul->bul_coa))
+                    && !IN6_ARE_ADDR_EQUAL(coa, &bul->bul_coa)) { 
+                        syslog(LOG_INFO, "coaifindex equal pcoaifindex");
+                        /* create new binding with NCoA */
+                        nbul = bul_insert(hoainfo, &bul->bul_peeraddr, coa, bul->bul_flags, 0);
+                        nbul->bul_lifetime = set_default_bu_lifetime(bul->bul_hoainfo);
+                        nbul->bul_state = bul->bul_state;
+                        /* nbul->bul_state |= MIP6_BUL_STATE_FMIP6; */
+                        nbul->bul_reg_fsm_state = bul->bul_reg_fsm_state;
+                        syslog(LOG_INFO, "change fsm MIP6_BUL_FSM_EVENT_MOVEMENT\n");
+                        if (bul_kick_fsm(nbul, MIP6_BUL_FSM_EVENT_MOVEMENT, NULL) == -1) {
+                                syslog(LOG_ERR, "fsm processing of movement detection " "failed.\n");
+                        }
+
+                        /* state update */
+                        bul->bul_lifetime = set_default_bu_lifetime(bul->bul_hoainfo);
+                        bul->bul_state |= MIP6_BUL_STATE_FMIP6;
+                        bul->bul_reg_fsm_state = MIP6_BUL_REG_FSM_STATE_FMIP6;
+                        syslog(LOG_INFO, "change fsm MIP6_BUL_FSM_EVENT_MOVEMENT\n");
+                } else {
+                        syslog(LOG_INFO, "coaifindex(%d) not equal pcoaifindex(%d)", coaifindex, pcoaifindex);
+                        /* update CoA */
+                        memcpy(&bul->bul_coa, coa, sizeof(*coa));
+		}
+#endif /* FMIP6 */
 
 		syslog(LOG_INFO, "change fsm MIP6_BUL_FSM_EVENT_MOVEMENT\n");
 		if (bul_kick_fsm(bul, MIP6_BUL_FSM_EVENT_MOVEMENT,
diff -u -r -N kame/kame/kame/shisad/network.c kame-tarzan/kame/kame/shisad/network.c
--- kame/kame/kame/shisad/network.c	Wed May 25 10:49:24 2005
+++ kame-tarzan/kame/kame/shisad/network.c	Fri Jul 29 00:02:06 2005
@@ -914,6 +914,47 @@
 }
 
 
+#ifdef FMIP6
+/* get an ifindex of the address */
+int 
+is_in6_addr_loopback(address)
+        struct in6_addr *address;
+{
+        struct ifaddrs *ifa, *ifap;
+        u_int16_t index = -1;
+        struct sockaddr *sa;
+
+        if (getifaddrs(&ifap) != 0) {
+                syslog(LOG_ERR, "%s\n", strerror(errno));
+                return (0);
+        }
+        for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+                sa = ifa->ifa_addr;
+                
+                if (sa->sa_family != AF_INET6)
+                        continue;
+                if (ifa->ifa_addr == NULL)
+                        continue;
+                if (address == NULL)
+                        continue;
+                
+                if (IN6_ARE_ADDR_EQUAL(&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr, address)) {
+                        index = if_nametoindex(ifa->ifa_name);
+  
+                        if (ifa->ifa_flags & IFF_LOOPBACK) {
+                                freeifaddrs(ifap);
+                                return (index);
+                        } else {
+                                freeifaddrs(ifap);
+                                return (0);
+                        }
+                }
+        }
+        freeifaddrs(ifap);
+        return (0);
+}
+#endif /* FMIP6 */
+
 
 #if 0
 int
diff -u -r -N kame/kame/kame/shisad/shisad.h kame-tarzan/kame/kame/shisad/shisad.h
--- kame/kame/kame/shisad/shisad.h	Mon Jun 20 17:37:30 2005
+++ kame-tarzan/kame/kame/shisad/shisad.h	Fri Jul 29 00:02:06 2005
@@ -235,6 +235,7 @@
 
 #define MIP6_BUL_STATE_DISABLE    0x01
 /*#define MIP6_BUL_STATE_NEEDTUNNEL (MIP6_BUL_STATE_DISABLE)*/
+#define MIP6_BUL_STATE_FMIP6      0x02
 
 /* 
  * it contains host information for which mnd does not run Route
@@ -454,13 +455,14 @@
 /* network.c */
 int set_ip6addr(char *, struct in6_addr *, int, int);
 int delete_ip6addr(char *, struct in6_addr *, int);
+int is_in6_addr_loopback(struct in6_addr *);
+u_int16_t  get_ifindex_from_address(struct in6_addr *);
 #ifdef MIP_NEMO
 int nemo_tun_set(struct sockaddr *, struct sockaddr *, u_int16_t, int);
 int nemo_tun_del(char *);
 int route_add(struct in6_addr *, struct in6_addr *, 
 	      struct in6_addr *, int, u_int16_t);
 int route_del(u_int16_t);
-u_int16_t  get_ifindex_from_address(struct in6_addr *);
 struct sockaddr_in6 *nemo_ar_get(struct in6_addr *coa, 
 				 struct sockaddr_in6 *);
 int nemo_gif_ar_set(char *, struct in6_addr *);
diff -u -r -N kame/kame/sys/net/mipsock.c kame-tarzan/kame/sys/net/mipsock.c
--- kame/kame/sys/net/mipsock.c	Sun Jul 17 00:35:13 2005
+++ kame-tarzan/kame/sys/net/mipsock.c	Fri Jul 29 00:02:06 2005
@@ -515,7 +515,9 @@
 		bcopy(&((struct sockaddr_in6 *)MIPU_COA(mipu))->sin6_port,
 		      &bid, sizeof(bid));
 #endif /* MIP6_MCOA */
-		mbul = mip6_bul_get(&((struct sockaddr_in6 *)&hoa)->sin6_addr, &((struct sockaddr_in6 *)&cnaddr)->sin6_addr, bid);
+		mbul = mip6_bul_get(&((struct sockaddr_in6 *)&hoa)->sin6_addr,
+			    &((struct sockaddr_in6 *)&cnaddr)->sin6_addr,
+			    bid, &((struct sockaddr_in6 *)MIPU_COA(mipu))->sin6_addr);
 		if (mbul == NULL) 
 			return (ENOENT);
 
diff -u -r -N kame/kame/sys/netinet6/in6_var.h kame-tarzan/kame/sys/netinet6/in6_var.h
--- kame/kame/sys/netinet6/in6_var.h	Fri Jun 17 03:29:28 2005
+++ kame-tarzan/kame/sys/netinet6/in6_var.h	Fri Jul 29 00:28:04 2005
@@ -476,6 +476,7 @@
 #define IN6_IFF_TEMPORARY	0x80	/* temporary (anonymous) address. */
 #define IN6_IFF_HOME		0x100	/* MIP6:home address */
 #define IN6_IFF_DEREGISTERING	0x200	/* MIP6:deregistering address */
+#define IN6_IFF_DADED		0x400	/* FMIP:already DADed */
 
 /* do not input/output */
 #define IN6_IFF_NOTREADY (IN6_IFF_TENTATIVE|IN6_IFF_DUPLICATED)
diff -u -r -N kame/kame/sys/netinet6/ip6_output.c kame-tarzan/kame/sys/netinet6/ip6_output.c
--- kame/kame/sys/netinet6/ip6_output.c	Fri Jul 22 13:58:55 2005
+++ kame-tarzan/kame/sys/netinet6/ip6_output.c	Fri Jul 29 00:02:06 2005
@@ -444,7 +444,7 @@
 	 * destination with a Home Address Option.  Except a caller
 	 * didn't specify a Home Address Option explicitly.
 	 */
-	mbul = mip6_bul_get(&ip6->ip6_src, &ip6->ip6_dst, 0/* XXX */);
+	mbul = mip6_bul_get(&ip6->ip6_src, &ip6->ip6_dst, 0, 0);
 	/* 
 	 * Route Optimization: appending a HoA option. 
 	 */
diff -u -r -N kame/kame/sys/netinet6/mip6.c kame-tarzan/kame/sys/netinet6/mip6.c
--- kame/kame/sys/netinet6/mip6.c	Wed Jul 20 21:56:18 2005
+++ kame-tarzan/kame/sys/netinet6/mip6.c	Fri Jul 29 00:02:06 2005
@@ -350,7 +350,7 @@
 		 * registration, make sure the packet is protected by
 		 * IPsec.
 		 */
-		mbul = mip6_bul_get(&ip6->ip6_src, &ip6->ip6_dst, 0 /* XXX */);
+		mbul = mip6_bul_get(&ip6->ip6_src, &ip6->ip6_dst, 0, 0);
 		if (mbul != NULL
 		    && (mbul->mbul_flags & IP6_MH_BU_HOME) != 0
 		    && mip6ctl_use_ipsec) {
@@ -429,7 +429,7 @@
 		bul = mip6_bul_get_home_agent(&dst);
 		if (bul == NULL)
 			goto dontstartrr;
-		cnbul = mip6_bul_get(&dst, &src, 0);
+		cnbul = mip6_bul_get(&dst, &src, 0, 0);
 		if (cnbul != NULL)
 			goto dontstartrr;
 
@@ -884,7 +884,7 @@
 	 * first. Then, the requested bul will be added right after
 	 * this deletion.  
 	 */
-	mbul = mip6_bul_get(hoa, peeraddr, bid);
+	mbul = mip6_bul_get(hoa, peeraddr, bid, coa);
 	if (mbul) 
 		mip6_bul_remove(mbul);
 
@@ -1035,9 +1035,10 @@
 }
 
 struct mip6_bul_internal *
-mip6_bul_get(src, dst, bid)
+mip6_bul_get(src, dst, bid, coa)
 	const struct in6_addr *src, *dst;
 	u_int16_t bid;
+	const struct in6_addr *coa;
 {
 	struct in6_ifaddr *ia6_src;
 	struct mip6_bul_internal *mbul;
@@ -1052,7 +1053,13 @@
 		if (bid && (bid =! mbul->mbul_bid))
 			continue;
 #endif /* MIP6_MCOA */
-
+#ifdef FMIP6
+		if (coa)
+			if (IN6_ARE_ADDR_EQUAL(src, &mbul->mbul_hoa)
+			    && IN6_ARE_ADDR_EQUAL(dst, &mbul->mbul_peeraddr)
+			    && IN6_ARE_ADDR_EQUAL(coa, &mbul->mbul_coa))
+				return (mbul);
+#endif /* FMIP6 */
 		if (IN6_ARE_ADDR_EQUAL(src, &mbul->mbul_hoa)
 		    && IN6_ARE_ADDR_EQUAL(dst, &mbul->mbul_peeraddr))
 			return (mbul);
diff -u -r -N kame/kame/sys/netinet6/mip6_var.h kame-tarzan/kame/sys/netinet6/mip6_var.h
--- kame/kame/sys/netinet6/mip6_var.h	Wed Jul 20 21:56:18 2005
+++ kame-tarzan/kame/sys/netinet6/mip6_var.h	Fri Jul 29 00:02:06 2005
@@ -172,7 +172,7 @@
 int mip6_bul_add(const struct in6_addr *, const struct in6_addr *,
     const struct in6_addr *, u_short, u_int16_t, u_int8_t, u_int16_t);
 struct mip6_bul_internal *mip6_bul_get(const struct in6_addr *,
-    const struct in6_addr *, u_int16_t);
+    const struct in6_addr *, u_int16_t, const struct in6_addr *);
 void mip6_bul_remove(struct mip6_bul_internal *);
 void mip6_bul_remove_all(void);
 struct mip6_bul_internal *mip6_bul_get_home_agent(const struct in6_addr *);
diff -u -r -N kame/kame/sys/netinet6/nd6.c kame-tarzan/kame/sys/netinet6/nd6.c
--- kame/kame/sys/netinet6/nd6.c	Thu Jul 14 23:15:00 2005
+++ kame-tarzan/kame/sys/netinet6/nd6.c	Fri Jul 29 00:02:06 2005
@@ -2357,7 +2357,7 @@
 				goto dontstartrr;
 			if (IN6_IS_ADDR_LINKLOCAL(&in6_dst))
 				goto dontstartrr;
-			cnbul = mip6_bul_get(&in6_src, &in6_dst, 0);
+			cnbul = mip6_bul_get(&in6_src, &in6_dst, 0, 0);
 			if (cnbul != NULL)
 				goto dontstartrr;
 
diff -u -r -N kame/kame/sys/netinet6/nd6_rtr.c kame-tarzan/kame/sys/netinet6/nd6_rtr.c
--- kame/kame/sys/netinet6/nd6_rtr.c	Thu Jun  9 11:16:11 2005
+++ kame-tarzan/kame/sys/netinet6/nd6_rtr.c	Fri Jul 29 00:26:20 2005
@@ -1665,7 +1665,12 @@
 			if (!(ifa->ia6_flags & IN6_IFF_AUTOCONF)
 #if defined(MIP6) && NMIP > 0
 			    /* see the comment above. */
-			    && !((ifa->ia6_flags & IN6_IFF_HOME) && (ifa->ia_ifp->if_type != IFT_MIP)) 
+#ifdef FMIP6
+			    && !((ifa->ia6_flags & IN6_IFF_HOME) && (ifa->ia_ifp->if_type != IFT_MIP)) && !(ifa->ia6_flags & IN6_IFF_DADED)
+#else
+			    && !((ifa->ia6_flags & IN6_IFF_HOME) && (ifa->ia_ifp
+->if_type != IFT_MIP))
+#endif
 #endif /* MIP6 && NMIP > 0 */
 				)
 				continue;
@@ -1684,6 +1689,9 @@
 					    0);
 				}
 			} else {
+#ifdef FMIP6
+				if (!(ifa->ia6_flags & IN6_IFF_DADED))
+#endif /* FMIP6 */
 				ifa->ia6_flags |= IN6_IFF_DETACHED;
 #if defined(MIP6) && NMIP > 0
 				rt_addrinfomsg((struct ifaddr *)ifa);
@@ -1696,6 +1704,9 @@
 			if ((ifa->ia6_flags & IN6_IFF_AUTOCONF) == 0)
 				continue;
 #if defined(MIP6) && NMIP > 0
+#ifdef FMIP6
+			if (!(ifa->ia6_flags & IN6_IFF_DADED))
+#endif
 			ifa->ia6_flags |= IN6_IFF_DETACHED;
 			rt_addrinfomsg((struct ifaddr *)ifa);
 #else /* defined(MIP6) && NMIP > 0 */
