diff --git a/include/linux/pfkeyv2.h b/include/linux/pfkeyv2.h
index d9db5f6..75e6c9a 100644
--- a/include/linux/pfkeyv2.h
+++ b/include/linux/pfkeyv2.h
@@ -226,6 +226,21 @@ struct sadb_x_sec_ctx {
 } __attribute__((packed));
 /* sizeof(struct sadb_sec_ctx) = 8 */
 
+/* Provides the packet (or part of it) that triggered the ACQUIRE msg.
+ * Used by a MIPv6-aware kernel when performing ACQUIRE for protecting
+ * a Binding Update message.
+ * XXX Does not follow draft-sugimoto-mip6-pfkey-migrate-03.txt : added
+ * XXX a copylen field providing the length of the citation in bytes -- arno
+ */
+struct sadb_x_packet {
+        uint16_t        sadb_x_packet_len;
+        uint16_t        sadb_x_packet_exttype;
+        uint32_t        sadb_x_packet_copylen;
+} __attribute__((packed));
+/* sizeof(struct sadb_x_packet) == 8 */
+/* followed by an IP packet header which triggered the SADB_ACQUIRE message */
+
+
 /* Message types */
 #define SADB_RESERVED		0
 #define SADB_GETSPI		1
@@ -339,7 +354,8 @@ struct sadb_x_sec_ctx {
 #define SADB_X_EXT_NAT_T_DPORT		22
 #define SADB_X_EXT_NAT_T_OA		23
 #define SADB_X_EXT_SEC_CTX		24
-#define SADB_EXT_MAX			24
+#define SADB_X_EXT_PACKET		27
+#define SADB_EXT_MAX			27
 
 /* Identity Extension values */
 #define SADB_IDENTTYPE_RESERVED	0
diff --git a/include/net/dst.h b/include/net/dst.h
index 82270f9..f4a5000 100644
--- a/include/net/dst.h
+++ b/include/net/dst.h
@@ -272,9 +272,9 @@ static inline int __xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl,
 }
 #else
 extern int xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl,
-		       struct sock *sk, int flags);
+		       struct sock *sk, int flags, struct msghdr *trig_pkt);
 extern int __xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl,
-			 struct sock *sk, int flags);
+			 struct sock *sk, int flags, struct msghdr *trig_pkt);
 #endif
 #endif
 
diff --git a/include/net/mip6.h b/include/net/mip6.h
index 6327261..c955a28 100644
--- a/include/net/mip6.h
+++ b/include/net/mip6.h
@@ -54,4 +54,46 @@ struct ip6_mh {
 #define IP6_MH_TYPE_BERROR	7   /* Binding Error */
 #define IP6_MH_TYPE_MAX		IP6_MH_TYPE_BERROR
 
+struct ip6_mh_binding_update {
+        struct ip6_mh   ip6mhbu_hdr;
+        __u16           ip6mhbu_seqno;     /* Sequence Number */
+        __u16           ip6mhbu_flags;     /* See below */
+        __u16           ip6mhbu_lifetime;  /* Time in unit of 4 sec */
+        /* Followed by optional Mobility Options */
+} __attribute__ ((packed));
+
+#define IP6_MH_BU_ACK           0x8000  /* Request a binding ack */
+#define IP6_MH_BU_HOME          0x4000  /* Home Registration */
+#define IP6_MH_BU_LLOCAL        0x2000  /* Link-local compatibility */
+#define IP6_MH_BU_KEYM          0x1000  /* Key management mobility */
+#define IP6_MH_BU_MAP           0x0800  /* HMIPv6 MAP Registration */
+#define IP6_MH_BU_MR            0x0400  /* NEMO MR Registration */
+
+struct ip6_mh_opt_altcoa {
+       __u8            ip6moa_type;
+       __u8            ip6moa_len;
+       struct in6_addr ip6moa_addr; /* Alternate CoA */
+} __attribute__ ((packed));
+
+/*
+ *     Mobility Header Message Option Types
+ */
+#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 */
+
+/*
+ * TLV for HAO (used in DestOpt). Defined in RFC 3775 but structure
+ * is not defined by Advanced API or MIPv6 API --arno
+ */
+struct destopt_hao {
+       __u8            ip6hao_type;
+       __u8            ip6hao_len;
+       struct in6_addr ip6hao_hoa;
+} __attribute__ ((packed));
+
 #endif
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index bc5cd77..8631f64 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -260,7 +260,7 @@ extern void km_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c
 extern void km_state_notify(struct xfrm_state *x, struct km_event *c);
 
 struct xfrm_tmpl;
-extern int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol);
+extern int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol, struct msghdr *trig_pkt);
 extern void km_state_expired(struct xfrm_state *x, int hard, u32 pid);
 extern int __xfrm_state_delete(struct xfrm_state *x);
 
@@ -417,7 +417,7 @@ struct xfrm_mgr
 	struct list_head	list;
 	char			*id;
 	int			(*notify)(struct xfrm_state *x, struct km_event *c);
-	int			(*acquire)(struct xfrm_state *x, struct xfrm_tmpl *, struct xfrm_policy *xp, int dir);
+	int			(*acquire)(struct xfrm_state *x, struct xfrm_tmpl *, struct xfrm_policy *xp, int dir, struct msghdr *trig_pkt);
 	struct xfrm_policy	*(*compile_policy)(struct sock *sk, int opt, u8 *data, int len, int *dir);
 	int			(*new_mapping)(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport);
 	int			(*notify_policy)(struct xfrm_policy *x, int dir, struct km_event *c);
@@ -940,7 +940,8 @@ extern struct xfrm_state *xfrm_state_alloc(void);
 extern struct xfrm_state *xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, 
 					  struct flowi *fl, struct xfrm_tmpl *tmpl,
 					  struct xfrm_policy *pol, int *err,
-					  unsigned short family);
+					  unsigned short family,
+					  struct msghdr *trig_pkt);
 extern int xfrm_state_check_expire(struct xfrm_state *x);
 extern void xfrm_state_insert(struct xfrm_state *x);
 extern int xfrm_state_add(struct xfrm_state *x);
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c
index 31737cd..876e885 100644
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -156,7 +156,7 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
 				goto out;
 			}
 
-			err = xfrm_lookup(&dst, &fl, sk, 0);
+			err = xfrm_lookup(&dst, &fl, sk, 0, NULL);
 			if (err < 0) {
 				sk->sk_err_soft = -err;
 				goto out;
@@ -280,7 +280,7 @@ static int dccp_v6_send_response(struct sock *sk, struct request_sock *req,
 		if (final_p)
 			ipv6_addr_copy(&fl.fl6_dst, final_p);
 
-		err = xfrm_lookup(&dst, &fl, sk, 0);
+		err = xfrm_lookup(&dst, &fl, sk, 0, NULL);
 		if (err < 0)
 			goto done;
 	}
@@ -369,7 +369,7 @@ static void dccp_v6_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb)
 
 	/* sk = NULL, but it is safe for now. RST socket required. */
 	if (!ip6_dst_lookup(NULL, &skb->dst, &fl)) {
-		if (xfrm_lookup(&skb->dst, &fl, NULL, 0) >= 0) {
+		if (xfrm_lookup(&skb->dst, &fl, NULL, 0, NULL) >= 0) {
 			ip6_xmit(dccp_v6_ctl_socket->sk, skb, &fl, NULL, 0);
 			DCCP_INC_STATS_BH(DCCP_MIB_OUTSEGS);
 			DCCP_INC_STATS_BH(DCCP_MIB_OUTRSTS);
@@ -605,7 +605,7 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk,
 		if (final_p)
 			ipv6_addr_copy(&fl.fl6_dst, final_p);
 
-		if ((xfrm_lookup(&dst, &fl, sk, 0)) < 0)
+		if ((xfrm_lookup(&dst, &fl, sk, 0, NULL)) < 0)
 			goto out;
 	}
 
@@ -1043,7 +1043,7 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
 	if (final_p)
 		ipv6_addr_copy(&fl.fl6_dst, final_p);
 
-	err = __xfrm_lookup(&dst, &fl, sk, 1);
+	err = __xfrm_lookup(&dst, &fl, sk, 1, NULL);
 	if (err < 0) {
 		if (err == -EREMOTE)
 			err = ip6_dst_blackhole(sk, &dst, &fl);
diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c
index a8bf106..571bc8e 100644
--- a/net/decnet/dn_route.c
+++ b/net/decnet/dn_route.c
@@ -1198,7 +1198,7 @@ static int dn_route_output_key(struct dst_entry **pprt, struct flowi *flp, int f
 
 	err = __dn_route_output_key(pprt, flp, flags);
 	if (err == 0 && flp->proto) {
-		err = xfrm_lookup(pprt, flp, NULL, 0);
+		err = xfrm_lookup(pprt, flp, NULL, 0, NULL);
 	}
 	return err;
 }
@@ -1209,7 +1209,7 @@ int dn_route_output_sock(struct dst_entry **pprt, struct flowi *fl, struct sock
 
 	err = __dn_route_output_key(pprt, fl, flags & MSG_TRYHARD);
 	if (err == 0 && fl->proto) {
-		err = xfrm_lookup(pprt, fl, sk, !(flags & MSG_DONTWAIT));
+		err = xfrm_lookup(pprt, fl, sk, !(flags & MSG_DONTWAIT), NULL);
 	}
 	return err;
 }
diff --git a/net/ipv4/netfilter.c b/net/ipv4/netfilter.c
index b441929..d902d1c 100644
--- a/net/ipv4/netfilter.c
+++ b/net/ipv4/netfilter.c
@@ -60,7 +60,7 @@ int ip_route_me_harder(struct sk_buff **pskb, unsigned addr_type)
 #ifdef CONFIG_XFRM
 	if (!(IPCB(*pskb)->flags & IPSKB_XFRM_TRANSFORMED) &&
 	    xfrm_decode_session(*pskb, &fl, AF_INET) == 0)
-		if (xfrm_lookup(&(*pskb)->dst, &fl, (*pskb)->sk, 0))
+		if (xfrm_lookup(&(*pskb)->dst, &fl, (*pskb)->sk, 0, NULL))
 			return -1;
 #endif
 
@@ -99,7 +99,7 @@ int ip_xfrm_me_harder(struct sk_buff **pskb)
 		dst = ((struct xfrm_dst *)dst)->route;
 	dst_hold(dst);
 
-	if (xfrm_lookup(&dst, &fl, (*pskb)->sk, 0) < 0)
+	if (xfrm_lookup(&dst, &fl, (*pskb)->sk, 0, NULL) < 0)
 		return -1;
 
 	dst_release((*pskb)->dst);
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 29ca63e..688d80c 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -2673,7 +2673,7 @@ int ip_route_output_flow(struct rtable **rp, struct flowi *flp, struct sock *sk,
 			flp->fl4_src = (*rp)->rt_src;
 		if (!flp->fl4_dst)
 			flp->fl4_dst = (*rp)->rt_dst;
-		err = __xfrm_lookup((struct dst_entry **)rp, flp, sk, flags);
+		err = __xfrm_lookup((struct dst_entry **)rp, flp, sk, flags, NULL);
 		if (err == -EREMOTE)
 			err = ipv4_dst_blackhole(rp, flp, sk);
 
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index eed0937..965613b 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -673,7 +673,7 @@ int inet6_sk_rebuild_header(struct sock *sk)
 		if (final_p)
 			ipv6_addr_copy(&fl.fl6_dst, final_p);
 
-		if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) {
+		if ((err = xfrm_lookup(&dst, &fl, sk, 0, NULL)) < 0) {
 			sk->sk_err_soft = -err;
 			return err;
 		}
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c
index ba1386d..c6628c2 100644
--- a/net/ipv6/datagram.c
+++ b/net/ipv6/datagram.c
@@ -177,7 +177,7 @@ ipv4_connected:
 	if (final_p)
 		ipv6_addr_copy(&fl.fl6_dst, final_p);
 
-	if ((err = __xfrm_lookup(&dst, &fl, sk, 1)) < 0) {
+	if ((err = __xfrm_lookup(&dst, &fl, sk, 1, NULL)) < 0) {
 		if (err == -EREMOTE)
 			err = ip6_dst_blackhole(sk, &dst, &fl);
 		if (err < 0)
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
index 4765a29..1ad2f96 100644
--- a/net/ipv6/icmp.c
+++ b/net/ipv6/icmp.c
@@ -416,7 +416,7 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info,
 		goto out_dst_release;
 	}
 
-	if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0)
+	if ((err = xfrm_lookup(&dst, &fl, sk, 0, NULL)) < 0)
 		goto out;
 
 	if (ipv6_addr_is_multicast(&fl.fl6_dst))
@@ -515,7 +515,7 @@ static void icmpv6_echo_reply(struct sk_buff *skb)
 	err = ip6_dst_lookup(sk, &dst, &fl);
 	if (err)
 		goto out;
-	if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0)
+	if ((err = xfrm_lookup(&dst, &fl, sk, 0, NULL)) < 0)
 		goto out;
 
 	if (ipv6_addr_is_multicast(&fl.fl6_dst))
diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c
index 116f94a..47e9354 100644
--- a/net/ipv6/inet6_connection_sock.c
+++ b/net/ipv6/inet6_connection_sock.c
@@ -180,7 +180,7 @@ int inet6_csk_xmit(struct sk_buff *skb, int ipfragok)
 		if (final_p)
 			ipv6_addr_copy(&fl.fl6_dst, final_p);
 
-		if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) {
+		if ((err = xfrm_lookup(&dst, &fl, sk, 0, NULL)) < 0) {
 			sk->sk_route_caps = 0;
 			kfree_skb(skb);
 			return err;
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index a0902fb..ff831f5 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -849,7 +849,7 @@ static int ip6_tnl_xmit2(struct sk_buff *skb,
 	else {
 		dst = ip6_route_output(NULL, fl);
 
-		if (dst->error || xfrm_lookup(&dst, fl, NULL, 0) < 0)
+		if (dst->error || xfrm_lookup(&dst, fl, NULL, 0, NULL) < 0)
 			goto tx_err_link_failure;
 	}
 
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index 0358e60..61fd244 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -450,7 +450,7 @@ static void __ndisc_send(struct net_device *dev,
 	if (!dst)
 		return;
 
-	err = xfrm_lookup(&dst, &fl, NULL, 0);
+	err = xfrm_lookup(&dst, &fl, NULL, 0, NULL);
 	if (err < 0)
 		return;
 
@@ -1357,7 +1357,7 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh,
 	if (dst == NULL)
 		return;
 
-	err = xfrm_lookup(&dst, &fl, NULL, 0);
+	err = xfrm_lookup(&dst, &fl, NULL, 0, NULL);
 	if (err)
 		return;
 
diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c
index 38b1496..b3e4771 100644
--- a/net/ipv6/netfilter.c
+++ b/net/ipv6/netfilter.c
@@ -27,7 +27,7 @@ int ip6_route_me_harder(struct sk_buff *skb)
 #ifdef CONFIG_XFRM
 	if (!(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) &&
 	    xfrm_decode_session(skb, &fl, AF_INET6) == 0)
-		if (xfrm_lookup(&skb->dst, &fl, skb->sk, 0))
+		if (xfrm_lookup(&skb->dst, &fl, skb->sk, 0, NULL))
 			return -1;
 #endif
 
diff --git a/net/ipv6/netfilter/ip6t_REJECT.c b/net/ipv6/netfilter/ip6t_REJECT.c
index cb3d241..07182cd 100644
--- a/net/ipv6/netfilter/ip6t_REJECT.c
+++ b/net/ipv6/netfilter/ip6t_REJECT.c
@@ -101,7 +101,7 @@ static void send_reset(struct sk_buff *oldskb)
 	dst = ip6_route_output(NULL, &fl);
 	if (dst == NULL)
 		return;
-	if (dst->error || xfrm_lookup(&dst, &fl, NULL, 0))
+	if (dst->error || xfrm_lookup(&dst, &fl, NULL, 0, NULL))
 		return;
 
 	hh_len = (dst->dev->hard_header_len + 15)&~15;
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index aac6aeb..34c9992 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -842,7 +842,11 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
 	if (final_p)
 		ipv6_addr_copy(&fl.fl6_dst, final_p);
 
+#ifdef CONFIG_SADB_X_EXT_PACKET
+	if ((err = __xfrm_lookup(&dst, &fl, sk, 1, msg)) < 0) {
+#else
 	if ((err = __xfrm_lookup(&dst, &fl, sk, 1)) < 0) {
+#endif
 		if (err == -EREMOTE)
 			err = ip6_dst_blackhole(sk, &dst, &fl);
 		if (err < 0)
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 193d9d6..46dff42 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -265,7 +265,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
 	if (final_p)
 		ipv6_addr_copy(&fl.fl6_dst, final_p);
 
-	if ((err = __xfrm_lookup(&dst, &fl, sk, 1)) < 0) {
+	if ((err = __xfrm_lookup(&dst, &fl, sk, 1, NULL)) < 0) {
 		if (err == -EREMOTE)
 			err = ip6_dst_blackhole(sk, &dst, &fl);
 		if (err < 0)
@@ -393,7 +393,7 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
 				goto out;
 			}
 
-			if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) {
+			if ((err = xfrm_lookup(&dst, &fl, sk, 0, NULL)) < 0) {
 				sk->sk_err_soft = -err;
 				goto out;
 			}
@@ -507,7 +507,7 @@ static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req,
 			goto done;
 		if (final_p)
 			ipv6_addr_copy(&fl.fl6_dst, final_p);
-		if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0)
+		if ((err = xfrm_lookup(&dst, &fl, sk, 0, NULL)) < 0)
 			goto done;
 	}
 
@@ -1073,7 +1073,7 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb)
 	/* sk = NULL, but it is safe for now. RST socket required. */
 	if (!ip6_dst_lookup(NULL, &buff->dst, &fl)) {
 
-		if (xfrm_lookup(&buff->dst, &fl, NULL, 0) >= 0) {
+		if (xfrm_lookup(&buff->dst, &fl, NULL, 0, NULL) >= 0) {
 			ip6_xmit(tcp6_socket->sk, buff, &fl, NULL, 0);
 			TCP_INC_STATS_BH(TCP_MIB_OUTSEGS);
 			TCP_INC_STATS_BH(TCP_MIB_OUTRSTS);
@@ -1172,7 +1172,7 @@ static void tcp_v6_send_ack(struct tcp_timewait_sock *tw,
 	security_skb_classify_flow(skb, &fl);
 
 	if (!ip6_dst_lookup(NULL, &buff->dst, &fl)) {
-		if (xfrm_lookup(&buff->dst, &fl, NULL, 0) >= 0) {
+		if (xfrm_lookup(&buff->dst, &fl, NULL, 0, NULL) >= 0) {
 			ip6_xmit(tcp6_socket->sk, buff, &fl, NULL, 0);
 			TCP_INC_STATS_BH(TCP_MIB_OUTSEGS);
 			return;
@@ -1425,7 +1425,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
 		if (final_p)
 			ipv6_addr_copy(&fl.fl6_dst, final_p);
 
-		if ((xfrm_lookup(&dst, &fl, sk, 0)) < 0)
+		if ((xfrm_lookup(&dst, &fl, sk, 0, NULL)) < 0)
 			goto out;
 	}
 
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 4210951..5cd5459 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -748,7 +748,7 @@ do_udp_sendmsg:
 	if (final_p)
 		ipv6_addr_copy(&fl.fl6_dst, final_p);
 
-	if ((err = __xfrm_lookup(&dst, &fl, sk, 1)) < 0) {
+	if ((err = __xfrm_lookup(&dst, &fl, sk, 1, NULL)) < 0) {
 		if (err == -EREMOTE)
 			err = ip6_dst_blackhole(sk, &dst, &fl);
 		if (err < 0)
diff --git a/net/key/af_key.c b/net/key/af_key.c
index 0f8304b..c3e9c9c 100644
--- a/net/key/af_key.c
+++ b/net/key/af_key.c
@@ -31,6 +31,10 @@
 
 #include <net/sock.h>
 
+#ifdef CONFIG_SADB_X_EXT_PACKET
+#include <net/mip6.h>
+#endif
+
 #define _X2KEY(x) ((x) == XFRM_INF ? 0 : (x))
 #define _KEY2X(x) ((x) == 0 ? XFRM_INF : (x))
 
@@ -337,6 +341,9 @@ static u8 sadb_ext_min_len[] = {
 	[SADB_X_EXT_NAT_T_DPORT]	= (u8) sizeof(struct sadb_x_nat_t_port),
 	[SADB_X_EXT_NAT_T_OA]		= (u8) sizeof(struct sadb_address),
 	[SADB_X_EXT_SEC_CTX]		= (u8) sizeof(struct sadb_x_sec_ctx),
+#ifdef CONFIG_SADB_X_EXT_PACKET
+	[SADB_X_EXT_PACKET]		= (u8) sizeof(struct sadb_x_packet),
+#endif
 };
 
 /* Verify sadb_address_{len,prefixlen} against sa_family.  */
@@ -2990,7 +2997,176 @@ static u32 get_acqseq(void)
 	return res;
 }
 
-static int pfkey_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *xp, int dir)
+#ifdef CONFIG_SADB_X_EXT_PACKET
+
+/* Parse msghdr, looking for a Binding Update with H flag set and an
+ * Alternate CoA option in the message:
+ *
+ *  - If found, the length of the sadb_x_packet extension that will
+ *    result from a call to add_sadb_x_packet_from_msghdr() is
+ *    returned (extension followed by the BU and options, with
+ *    reconstructed IPv6 header and Destination Option Header).
+ *  - If not found, 0 is returned.
+ */
+static int sadb_x_packet_size_from_msghdr(struct msghdr *msg)
+{
+        int i, found = 0, mh_len, size = 0;
+	struct ip6_mh_opt_altcoa *cur;
+	struct iovec *iov;
+	struct ip6_mh_binding_update *ip6mhbu_msg;
+	struct sockaddr_in6 *daddr;
+
+	if (!msg)
+	        return 0;
+
+	iov = msg->msg_iov;
+	if(!(iov && iov[0].iov_base))
+	        return 0;
+
+	daddr = (struct sockaddr_in6 *)msg->msg_name;
+	if (!(msg->msg_namelen == sizeof(*daddr) &&
+	      daddr &&
+	      daddr->sin6_family == AF_INET6 &&
+	      daddr->sin6_port == htons(NEXTHDR_MOBILITY)))
+	        return 0;
+
+	/* XXX Validate msg.cmsg_level, cmsg_type and cmsg_len ? --arno */
+
+	if (iov[0].iov_len < sizeof(struct ip6_mh_binding_update))
+	        return 0;
+
+	ip6mhbu_msg = (struct ip6_mh_binding_update *)iov[0].iov_base;
+	if (!(ip6mhbu_msg &&
+	      (ip6mhbu_msg->ip6mhbu_hdr.ip6mh_type == IP6_MH_TYPE_BU) &&
+	      (ntohs(ip6mhbu_msg->ip6mhbu_flags) & (IP6_MH_BU_HOME))))
+	        return 0;
+
+#ifdef CONFIG_SADB_X_EXT_PACKET_DEBUG
+	printk("SADB_X_EXT_PACKET_DEBUG: "
+	       "Found a triggering BU message.\n");
+#endif
+
+	/* Look for Alternate CoA Mobility Option in iov */
+	for (i = 1; i < msg->msg_iovlen ; i++) {
+	        cur = (struct ip6_mh_opt_altcoa *)iov[i].iov_base;
+		if ((iov[i].iov_len == sizeof(struct ip6_mh_opt_altcoa)) &&
+		    (cur && (cur->ip6moa_type == IP6_MHOPT_ALTCOA))) {
+		         found = 1;
+			 break;
+		}
+	}
+
+	if (!found) {
+#ifdef CONFIG_SADB_X_EXT_PACKET_DEBUG
+	        printk("SADB_X_EXT_PACKET_DEBUG: BU does not "
+		       "contain AltCoA option. Not considering.\n");
+#endif
+	        return 0;
+	}
+
+	/* Compute size of SADB_X_EXT_PACKET extension including
+	   simplified raw packet */
+	mh_len = (ip6mhbu_msg->ip6mhbu_hdr.ip6mh_hdrlen + 1) << 3;
+	size = sizeof(struct sadb_x_packet) + sizeof(struct ipv6hdr) +
+	       + mh_len;
+	size = PFKEY_ALIGN8(size);
+
+#ifdef CONFIG_SADB_X_EXT_PACKET_DEBUG
+	printk("SADB_X_EXT_PACKET_DEBUG: sadb_x_packet "
+	       "extension will have size %d.\n", size);
+#endif
+
+	return size;
+}
+
+/* Construct the sadb_x_packet extension containing the Binding Update packet
+ * based on stub found in msg. IPv6 header is faked. As their is no specific
+ * use to pass Destination Option Header with the HAO, MH is directly stacked
+ * over IPv6 layer. (Userland will use content of AltCoA option to get the
+ * CoA, not the content of HAO)
+ *
+ * Built extension is added at the end of skb. It is expected that enough room
+ * has been allocated in skb to hold the extension (additional size been
+ * provided by a previous call to sadb_x_packet_size_from_msghdr())
+ *
+ *  -1 is returned on error. 0 otherwise (including NULL msg case).
+ */
+static int add_sadb_x_packet_from_msghdr(struct sk_buff *skb, struct msghdr *msg)
+{
+        struct sadb_x_packet * ext;
+	struct ip6_mh_binding_update *ip6mhbu_msg;
+	struct sockaddr_in6* daddr;
+	struct in6_pktinfo *pinfo;
+#ifdef CONFIG_SADB_X_EXT_PACKET_DEBUG
+	struct ip6_mh_opt_altcoa *altcoa = NULL;
+#endif
+	struct ipv6hdr *ipv6h;
+	struct iovec *iov;
+	uint16_t pktlen, extlen, mh_len;
+	int i;
+
+	if (!msg)
+	        return 0;
+
+	/* Checks have been made in sadb_x_packet_size_from_msghdr() */
+	iov = msg->msg_iov;
+	ip6mhbu_msg = (struct ip6_mh_binding_update *)iov[0].iov_base;
+	mh_len = (ip6mhbu_msg->ip6mhbu_hdr.ip6mh_hdrlen + 1) << 3;
+	pktlen = sizeof(struct ipv6hdr) + mh_len;
+	extlen = PFKEY_ALIGN8(sizeof(struct sadb_x_packet) + pktlen);
+
+	ext = (struct sadb_x_packet *)skb_put(skb, sizeof(*ext));
+	ext->sadb_x_packet_len = (extlen / sizeof(uint64_t));
+	ext->sadb_x_packet_exttype = SADB_X_EXT_PACKET;
+	ext->sadb_x_packet_copylen = pktlen;
+
+	/* Construct IPv6 packet */
+	daddr = (struct sockaddr_in6 *)msg->msg_name;
+	pinfo = (struct in6_pktinfo *)CMSG_DATA(msg->msg_control);
+	ipv6h = (struct ipv6hdr *)skb_put(skb,sizeof(struct ipv6hdr));
+	ipv6h->version = 0x6;
+	ipv6h->priority = 0x0;
+	ipv6h->payload_len = htons(pktlen - sizeof(struct ipv6hdr));
+	ipv6h->nexthdr = NEXTHDR_MOBILITY; /* 135 */
+	ipv6h->hop_limit = 64;
+	ipv6_addr_copy(&ipv6h->daddr, &daddr->sin6_addr); /* HA @ */
+	ipv6_addr_copy(&ipv6h->saddr, &pinfo->ipi6_addr); /* HoA  */
+
+	/* Finally stack MH BU and options, including the Alt CoA */
+	ip6mhbu_msg = (struct ip6_mh_binding_update*)skb_put(skb, mh_len);
+	if (memcpy_fromiovecend((unsigned char *)ip6mhbu_msg, iov, 0, mh_len))
+   	        return -1;
+
+#ifdef CONFIG_SADB_X_EXT_PACKET_DEBUG
+#define ADDR6TOSTR(x) \
+	"%02X%02X:%02X%02X:%02X%02X:%02X%02X:"   \
+	"%02X%02X:%02X%02X:%02X%02X:%02X%02X\n", \
+	 x.s6_addr[0],  x.s6_addr[1], x.s6_addr[2],  x.s6_addr[3],  \
+	 x.s6_addr[4],  x.s6_addr[5], x.s6_addr[6],  x.s6_addr[7],  \
+	 x.s6_addr[8],  x.s6_addr[9], x.s6_addr[10], x.s6_addr[11], \
+	 x.s6_addr[12], x.s6_addr[13], x.s6_addr[14], x.s6_addr[15]
+
+	for (i = 1; i < msg->msg_iovlen ; i++) {
+		altcoa = (struct ip6_mh_opt_altcoa *)iov[i].iov_base;
+		if (altcoa->ip6moa_type == IP6_MHOPT_ALTCOA) {
+			break;
+		}
+	}
+
+	printk("SADB_X_EXT_PACKET_DEBUG: "
+	       "BU created successfully with:\n");
+	printk("SADB_X_EXT_PACKET_DEBUG: "
+	       "src address " ADDR6TOSTR(ipv6h->saddr));
+	printk("SADB_X_EXT_PACKET_DEBUG: "
+	       "dst address " ADDR6TOSTR(ipv6h->daddr));
+	printk("SADB_X_EXT_PACKET_DEBUG: "
+	       "Alt CoA     " ADDR6TOSTR(altcoa->ip6moa_addr));
+#endif
+	return 0;
+}
+#endif
+
+static int pfkey_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *xp, int dir, struct msghdr *trig_pkt)
 {
 	struct sk_buff *skb;
 	struct sadb_msg *hdr;
@@ -3005,6 +3181,9 @@ static int pfkey_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *t, struct
 	struct sadb_x_sec_ctx *sec_ctx;
 	struct xfrm_sec_ctx *xfrm_ctx;
 	int ctx_size = 0;
+#ifdef CONFIG_SADB_X_EXT_PACKET
+	int sadb_x_packet_size = sadb_x_packet_size_from_msghdr(trig_pkt);
+#endif
 
 	sockaddr_size = pfkey_sockaddr_size(x->props.family);
 	if (!sockaddr_size)
@@ -3025,6 +3204,9 @@ static int pfkey_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *t, struct
 		size +=  sizeof(struct sadb_x_sec_ctx) + ctx_size;
 	}
 
+#ifdef CONFIG_SADB_X_EXT_PACKET
+	size += sadb_x_packet_size ; /* add 0 if no BU in msg */
+#endif
 	skb =  alloc_skb(size + 16, GFP_ATOMIC);
 	if (skb == NULL)
 		return -ENOMEM;
@@ -3134,6 +3316,10 @@ static int pfkey_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *t, struct
 		       xfrm_ctx->ctx_len);
 	}
 
+#ifdef CONFIG_SADB_X_EXT_PACKET
+	if (sadb_x_packet_size)
+  	        add_sadb_x_packet_from_msghdr(skb, trig_pkt);
+#endif
 	return pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_REGISTERED, NULL);
 }
 
diff --git a/net/xfrm/Kconfig b/net/xfrm/Kconfig
index b4fb2e4..625a169 100644
--- a/net/xfrm/Kconfig
+++ b/net/xfrm/Kconfig
@@ -71,3 +71,24 @@ config NET_KEY_MIGRATE
 
 	  If unsure, say N.
 
+config SADB_X_EXT_PACKET
+	bool "SADB_X_EXT_PACKET support (EXPERIMENTAL)"
+	depends on NET_KEY && XFRM && EXPERIMENTAL
+	---help---
+	  Support for SADB_X_PACKET extension used for passing triggering
+	  packet in the ACQUIRE message sent to registered key managers.
+	  One use of the extension is in bootstrapping in Mobile IPv6
+	  environments where IPsec is used with dynamic keying (IKE) for
+	  traffic protection.
+	  Information can be found in <draft-sugimoto-mip6-pfkey-migrate>
+
+	  If unsure, say N.
+
+config SADB_X_EXT_PACKET_DEBUG
+	bool "SADB_X_EXT_PACKET debug messages (EXPERIMENTAL)"
+	depends on NET_KEY && SADB_X_EXT_PACKET && XFRM && EXPERIMENTAL
+	---help---
+	  Provides debug messages associated with SADB_X_EXT_PACKET
+	  extension operations.
+
+	  If unsure, say N.
\ No newline at end of file
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 53f0c90..015400b 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -1287,7 +1287,7 @@ xfrm_get_saddr(xfrm_address_t *local, xfrm_address_t *remote,
 static int
 xfrm_tmpl_resolve_one(struct xfrm_policy *policy, struct flowi *fl,
 		      struct xfrm_state **xfrm,
-		      unsigned short family)
+		      unsigned short family, struct msghdr *trig_pkt)
 {
 	int nx;
 	int i, error;
@@ -1313,7 +1313,7 @@ xfrm_tmpl_resolve_one(struct xfrm_policy *policy, struct flowi *fl,
 			}
 		}
 
-		x = xfrm_state_find(remote, local, fl, tmpl, policy, &error, family);
+		x = xfrm_state_find(remote, local, fl, tmpl, policy, &error, family, trig_pkt);
 
 		if (x && x->km.state == XFRM_STATE_VALID) {
 			xfrm[nx++] = x;
@@ -1341,7 +1341,7 @@ fail:
 static int
 xfrm_tmpl_resolve(struct xfrm_policy **pols, int npols, struct flowi *fl,
 		  struct xfrm_state **xfrm,
-		  unsigned short family)
+		  unsigned short family, struct msghdr *trig_pkt)
 {
 	struct xfrm_state *tp[XFRM_MAX_DEPTH];
 	struct xfrm_state **tpp = (npols > 1) ? tp : xfrm;
@@ -1356,7 +1356,7 @@ xfrm_tmpl_resolve(struct xfrm_policy **pols, int npols, struct flowi *fl,
 			goto fail;
 		}
 
-		ret = xfrm_tmpl_resolve_one(pols[i], fl, &tpp[cnx], family);
+		ret = xfrm_tmpl_resolve_one(pols[i], fl, &tpp[cnx], family, trig_pkt);
 		if (ret < 0) {
 			error = ret;
 			goto fail;
@@ -1454,7 +1454,7 @@ static int stale_bundle(struct dst_entry *dst);
  * on interfaces with disabled IPsec.
  */
 int __xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl,
-		  struct sock *sk, int flags)
+		  struct sock *sk, int flags, struct msghdr *trig_pkt)
 {
 	struct xfrm_policy *policy;
 	struct xfrm_policy *pols[XFRM_POLICY_TYPE_MAX];
@@ -1576,7 +1576,7 @@ restart:
 		}
 
 #endif
-		nx = xfrm_tmpl_resolve(pols, npols, fl, xfrm, family);
+		nx = xfrm_tmpl_resolve(pols, npols, fl, xfrm, family, trig_pkt);
 
 		if (unlikely(nx<0)) {
 			err = nx;
@@ -1596,7 +1596,7 @@ restart:
 				set_current_state(TASK_RUNNING);
 				remove_wait_queue(&km_waitq, &wait);
 
-				nx = xfrm_tmpl_resolve(pols, npols, fl, xfrm, family);
+				nx = xfrm_tmpl_resolve(pols, npols, fl, xfrm, family, trig_pkt);
 
 				if (nx == -EAGAIN && signal_pending(current)) {
 					XFRM_INC_STATS(XFRM_MIB_OUTNOSTATES);
@@ -1685,9 +1685,9 @@ error:
 EXPORT_SYMBOL(__xfrm_lookup);
 
 int xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl,
-		struct sock *sk, int flags)
+		struct sock *sk, int flags, struct msghdr *trig_pkt)
 {
-	int err = __xfrm_lookup(dst_p, fl, sk, flags);
+	int err = __xfrm_lookup(dst_p, fl, sk, flags, trig_pkt);
 
 	if (err == -EREMOTE) {
 		dst_release(*dst_p);
@@ -1960,7 +1960,7 @@ int __xfrm_route_forward(struct sk_buff *skb, unsigned short family)
 		return 0;
 	}
 
-	return xfrm_lookup(&skb->dst, &fl, NULL, 0) == 0;
+	return xfrm_lookup(&skb->dst, &fl, NULL, 0, NULL) == 0;
 }
 EXPORT_SYMBOL(__xfrm_route_forward);
 
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index 91b3d3a..08c3a57 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -186,7 +186,7 @@ static DEFINE_SPINLOCK(xfrm_state_gc_lock);
 
 int __xfrm_state_delete(struct xfrm_state *x);
 
-int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol);
+int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol, struct msghdr *trig_pkt);
 void km_state_expired(struct xfrm_state *x, int hard, u32 pid);
 
 static void xfrm_state_gc_destroy(struct xfrm_state *x)
@@ -579,7 +579,7 @@ struct xfrm_state *
 xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr,
 		struct flowi *fl, struct xfrm_tmpl *tmpl,
 		struct xfrm_policy *pol, int *err,
-		unsigned short family)
+		unsigned short family, struct msghdr *trig_pkt)
 {
 	unsigned int h = xfrm_dst_hash(daddr, saddr, tmpl->reqid, family);
 	struct hlist_node *entry;
@@ -656,7 +656,7 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr,
 			goto out;
 		}
 
-		if (km_query(x, tmpl, pol) == 0) {
+		if (km_query(x, tmpl, pol, trig_pkt) == 0) {
 			x->km.state = XFRM_STATE_ACQ;
 			hlist_add_head(&x->bydst, xfrm_state_bydst+h);
 			h = xfrm_src_hash(daddr, saddr, family);
@@ -1509,14 +1509,15 @@ EXPORT_SYMBOL(km_state_expired);
  * We send to all registered managers regardless of failure
  * We are happy with one success
 */
-int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol)
+int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, 
+	     struct xfrm_policy *pol, struct msghdr *trig_pkt)
 {
 	int err = -EINVAL, acqret;
 	struct xfrm_mgr *km;
 
 	read_lock(&xfrm_km_lock);
 	list_for_each_entry(km, &xfrm_km_list, list) {
-		acqret = km->acquire(x, t, pol, XFRM_POLICY_OUT);
+		acqret = km->acquire(x, t, pol, XFRM_POLICY_OUT, trig_pkt);
 		if (!acqret)
 			err = acqret;
 	}
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index c06883b..dfacc39 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -1733,7 +1733,7 @@ static int xfrm_add_acquire(struct sk_buff *skb, struct nlmsghdr *nlh,
 		t->aalgos = ua->aalgos;
 		t->ealgos = ua->ealgos;
 		t->calgos = ua->calgos;
-		err = km_query(x, t, xp);
+		err = km_query(x, t, xp, NULL);
 
 	}
 
@@ -2256,7 +2256,8 @@ nlmsg_failure:
 }
 
 static int xfrm_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *xt,
-			     struct xfrm_policy *xp, int dir)
+			     struct xfrm_policy *xp, int dir, 
+			     struct msghdr *trig_pkt)
 {
 	struct sk_buff *skb;
 	size_t len;
