diff -Nur racoon2-20070817cvs/lib/if_pfkeyv2.c racoon2-patched/lib/if_pfkeyv2.c
--- racoon2-20070817cvs/lib/if_pfkeyv2.c	2007-08-17 10:57:42.000000000 +0900
+++ racoon2-patched/lib/if_pfkeyv2.c	2007-08-17 11:52:12.000000000 +0900
@@ -1894,12 +1894,11 @@
 	struct sadb_x_packet *pkt;
 	struct ip6_hdr *ip;
 	struct ip6_ext *ep;
-	struct ip6_opt *op;
-	struct ip6_opt_home_address *hao = NULL;
+	struct ip6_mh_opt_altcoa *altcoa=NULL;
 	struct ip6_mh *mh = NULL;
 	struct ip6_mh_binding_update *hrbu = NULL;
 	struct sockaddr_in6 *src6;
-	int len, nxt, l;
+	int len, nxt, l=0;
 #endif
 
 	/* ignore this message in the case of the local test mode. */
@@ -1959,19 +1958,18 @@
 	 * Decode the triggering packet for the case it is
 	 * a MIPv6 home registration binding update.
 	 */
-#define HRBU_MIN_LEN	(40 + 24 + 12)
 	if (mhp[SADB_X_EXT_PACKET] == 0)
 		goto skippa;
 	pkt = (struct sadb_x_packet *)mhp[SADB_X_EXT_PACKET];
 	ip = (struct ip6_hdr *)(pkt + 1);
 	ep = (struct ip6_ext *)(ip + 1);
 
-	if (pkt->sadb_x_packet_copylen < HRBU_MIN_LEN)
+	if (pkt->sadb_x_packet_copylen < sizeof( struct ip6_hdr))
 		goto skippa;
 	if ((ip->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) 
 		goto skippa;
 
-	/* chasing for HOA and HRBU */
+	/* chasing for HRBU */
 
 	len = ntohs(ip->ip6_plen) + sizeof(*ip);
 	if (len > pkt->sadb_x_packet_copylen)
@@ -1983,6 +1981,7 @@
 		case IPPROTO_HOPOPTS:
 		case IPPROTO_ROUTING:
 		case IPPROTO_FRAGMENT:
+		case IPPROTO_DSTOPTS:
 			l = (ep->ip6e_len + 1) << 3;
 		skip:
 			nxt = ep->ip6e_nxt;
@@ -2000,31 +1999,6 @@
 		default:
 			goto skippa;
 
-		case IPPROTO_DSTOPTS:
-			l = (ep->ip6e_len + 1) << 3;
-			if (l > len)
-				goto skippa;
-			op = (struct ip6_opt *)(ep + 1);
-			l -= sizeof(*ep);
-			while (l > 0)
-				switch (op->ip6o_type) {
-				case IP6OPT_PAD1:
-					l -= 1;
-					op = (struct ip6_opt *)((caddr_t)op + 1);
-					break;
-
-				case IP6OPT_HOME_ADDRESS:
-					hao = (struct ip6_opt_home_address *)op;
-					/* fall into */
-
-				case IP6OPT_PADN:
-				default:
-					l -= 2 + op->ip6o_len;
-					op = (struct ip6_opt *)((caddr_t)op + 2 + op->ip6o_len);
-				}
-			l = (ep->ip6e_len + 1) << 3;
-			goto skip;
-
 		case IPPROTO_MH:
 			l = (ep->ip6e_len + 1) << 3;
 			hrbu = (struct ip6_mh_binding_update *)ep;
@@ -2034,28 +2008,54 @@
 			if (mh->ip6mh_type != IP6_MH_TYPE_BU ||
 			    (hrbu->ip6mhbu_flags & IP6_MH_BU_HOME) == 0) {
 				hrbu = NULL;
-				goto skip;
+				goto skippa;
 			}
+			altcoa = (struct ip6_mh_opt_altcoa *)(hrbu + 1);
+			
 			/* force exit */
 			len = 0;
 		}
 
-	/* found? */
-
-	if (hao == NULL || hrbu == NULL)
-		goto skippa;
-	if (hao->ip6oh_len < 16)
+	/* found mobility header? */
+	if (! altcoa)
 		goto skippa;
-
-	/* cache the right address to use in src2 */
-	rc->sa2_src = (struct sockaddr *)&rc->sa2_src_storage;
-	src6 = (struct sockaddr_in6 *)rc->sa2_src;
-	bzero(src6, sizeof(struct sockaddr_in6));
-	src6->sin6_family = AF_INET6;
-#ifdef HAVE_SA_LEN
-	src6->sin6_len = sizeof(*src6);
-#endif
-	memcpy(&src6->sin6_addr, hao->ip6oh_addr, sizeof(hao->ip6oh_addr));
+	
+	len = l - sizeof(*hrbu);
+	
+	/* Parse the MH options -- we are looking for ALTCOA */
+	while (len > 0)
+		switch (altcoa->ip6moa_type){
+		case IP6_MHOPT_PAD1:
+			len -= 1;
+			altcoa = (struct ip6_mh_opt_altcoa *)((caddr_t)altcoa + 1);
+			break;
+
+		case IP6_MHOPT_PADN:
+			len -= 2 + altcoa->ip6moa_len;
+			altcoa = (struct ip6_mh_opt_altcoa *)((caddr_t)altcoa + 2 + altcoa->ip6moa_len);
+			break;
+		
+		case IP6_MHOPT_ALTCOA:
+			/* This is what we were looking for. We save CoA in sa2_src */
+			if (len < sizeof (*altcoa))
+				goto skippa;
+			
+			/* cache the right address to use in src2 */
+			rc->sa2_src = (struct sockaddr *)&rc->sa2_src_storage;
+			src6 = (struct sockaddr_in6 *)rc->sa2_src;
+			bzero(src6, sizeof(struct sockaddr_in6));
+			src6->sin6_family = AF_INET6;
+			#ifdef HAVE_SA_LEN
+			src6->sin6_len = sizeof(*src6);
+			#endif
+
+			memcpy(&src6->sin6_addr, &altcoa->ip6moa_addr, sizeof(altcoa->ip6moa_addr));
+			goto skippa; /* we are done here */
+		
+		default:
+			/* not implemented yet */
+			goto skippa;
+		}
 
     skippa:
 #endif
diff -Nur racoon2-20070817cvs/lib/mipv6aux.h racoon2-patched/lib/mipv6aux.h
--- racoon2-20070817cvs/lib/mipv6aux.h	2007-08-17 10:57:42.000000000 +0900
+++ racoon2-patched/lib/mipv6aux.h	2007-08-17 11:52:12.000000000 +0900
@@ -103,6 +103,26 @@
 	/* followed by mobility options */
 } __attribute__((__packed__));
 
-#define IP6_MH_BU_HOME		0x4000	/* home registration */
+/* ip6mhbu_flags */
+#if BYTE_ORDER == BIG_ENDIAN
+#define IP6_MH_BU_HOME		0x4000	/* Home Registration */
+#else				/* BYTE_ORDER == LITTLE_ENDIAN */
+#define IP6_MH_BU_HOME		0x0040	/* Home Registration */
+#endif
+
+#define IP6_MHOPT_PAD1		0x00	/* PAD1 */
+#define IP6_MHOPT_PADN		0x01	/* PADN */
+#define IP6_MHOPT_BREFRESH	0x02	/* Binding Refresh */
+#define IP6_MHOPT_ALTCOA	0x03	/* Alternate COA */
+#define IP6_MHOPT_NONCEID	0x04	/* Nonce Index */
+#define IP6_MHOPT_BAUTH		0x05	/* Binding Auth Data */
+#define IP6_MHOPT_MOB_NET_PRFX	0x06	/* Mobile Network Prefix */
+
+struct ip6_mh_opt_altcoa {
+	uint8_t		ip6moa_type;
+	uint8_t		ip6moa_len;
+	struct in6_addr	ip6moa_addr;		/* Alternate Care-of Address */
+} __attribute__ ((packed));
+
 
 #endif
