[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

(usagi-users 03928) RACOON/UMIP/KERNEL Patches



Hi,

I have attached to this mail a set of patches providing/improving
mobility support for umip, linux kernel and racoon. This allows to use
racoon and umip together (with suitable kernel):

 - by allowing the initial dynamic negotiation of SA between the HA and
   its MNs to be done using IKE, through addition of SADB_X_EXT_PACKET
   support in both racoon and the kernel (MN only needs it but it is
   transparent on HA).
 - by providing support for MIGRATE in racoon to allow the daemon to
   update its Phase 1 and Phase 2 states w.r.t. the change of CoA. This
   is needed to allow the MN and its HA to perform rekeying. 

Note that racoon's code is based on an initial patch provided by
Francis, modified by Yves-Alexis Perez during an internship at EADS and
then further improved and debugged by your french servant to get it
stable ;-)

Anyway, it is now a _maintained_ set of patches against the latest CVS
version of racoon that works with current umip and latest
SADB_X_EXT_PACKET-patched linux-ipv6.org kernel (2.6.23-rc3). 

The set of patches also contains some for umip that adds better support
for user defined preference option and default route preference option
(RFC4191), and also more dynamic interfaces use.

The goal of this public release is to make the patches available for
further testing and comments before parts eventually get mainline in the
different projects.

I must confess that (IMHO) there are still open points in the expected
relationship between IKE daemons and MIPv6 stack, even if everything
works fine 99.9% of the time. This includes various situations where
movement occurs at a bad moment (Phase 2 rekeying) or simply HL2FL or
FL2HL w.r.t. SA/SP states handling in racoon.

Regards,

a+


-- Arnaud Ebalard
EADS Innovation Works - IT Security Research Engineer
PGP KeyID:047A5026 FingerPrint: 47EB85FEB99AAB85FD0946F30255957C047A5026



ps:     The SADB_X_EXT_PACKET support has also been tested by Sebastien
        using racoon2 as KM.
pps:    Detailed comments on every patch are provided below.
ppps:   Questions and bug reports are obviously welcome.
pppps:  Given the amount of required changes to racoon, i don't expect
        to get patches applied before a while. Yvan, i would appreciate
        comments against the patches to make that happen. I'll take the
        time to answer all questions on the logic behind the changes and
        corrections associated with possible mistakes.
ppppps: Sebastien, i have taken a quick look at your howto. Good
        work. I'll try to update it soon with a section on racoon
        configuration (most notably identity handling).
pp..ps: Martin, Sebastien, sorry for the delay.
pp..ps: I don't use git for the dev. I maintains for every project a hg
        rep for the set of patches managed with quilt.
pp..ps: Sorry for remaining typos/errors and for the length of the mail.

---

Here are precise comments for every patch that [IMHO] will at least
provide pointers to the curious reader and possibly spare him funny
hours of digging in the code:

 o Against the most recent branch of umip development git tree
   ( 0.4rc2 ) 
   
   - router_preference_support.patch: 

     Rationale: when umip is used with multiplee interface and gets
     default route information from RA on the link, all defaults routes
     get the same metric: 1024. This results in packets using the right
     CoA as source (the one associated with the preferred interface as
     set by the user through MnIfPreference value, chosen by umip) but
     going through the wrong default iface (linux kernel routing
     logic). One way to reproduce that is with 2 interfaces up,
     providing  2 default routers with same metric. 

     Another problem is that umip only creates one default route entry
     for a given interface, not two and is not able to deal with default
     router preference value (RFC4191).  

     Changes: based on MnIfPreference values set by users, the patch
     sets different metric for added default routes on every
     interfaces. The metric is also "sub-modulated" by the addition of
     _limited_ support for Default Router Preference value
     (RFC4191). iface pref value is now limited to [0,10] (with warnings
     to user if outside the range). man page is also updated.

     An example will clarify things. A mobile node with 3 interfaces,
     eth0, ath0 and bnep0 (respectively ethernet, wifi and bluetooth
     acting as PANU). Preferences are respectively set to 1, 2 and
     3. Let's assume that 2 default routers are available via ath0 with
     different default router preference values (low and medium). Other
     interfaces provide each one a single default router. If all
     interfaces are available at the same time, 3 default routes are
     available (996, 999, 1002) and eth0 will be preferred
     (1023-3*(10-1)=996 for the metric). If cable is unplugged, ath0 is
     used. It has 2 default routers but umip will end up selecting the 
     best one based on default router preference and creating a default
     route with a computed metic for this router (999). If the route via
     the medium default router is removed, low one will be selected is
     still preferred (still the best iface) over the bluetooth path
     (metric of 1023-3*(10-2), i.e. 1002). 

     Note that the code also changes the logic of MnRouterProbes
     configuration parameter. Basically, if a RA is received coming from
     a new router on an iface for which we already have a default
     router, we update our default router. Now, if received RA has a
     lower default router preference and MrRouterProbes is 0, we do
     nothing. If it has a non null value, we probe our router before
     possibly switching.

     Please note that you probably don't want to include this patch
     (even if it works fine in described contexts), for following
     reasons: 

       - i have not added support for the other part of RFC 4191 (More
         specific route). If you think there is a _real_ need, I can
         spend some time on that. 
       - Linux kernel does not expect userland to provide the preference
         value and has no way to do that (AFAIK). The preference value
         is used directly inside the kernel in rt6_score_route()
         (net/ipv6/route.c) but does not change the metric value of a
         route. The only way i have seen to deal with that is _via_ the
         metric.
       - RFC 4191 clearly states that default router preference values
         are not routing metric. For that reason, I do not use them
         directly as metrics for default route but only to
         "sub-modulate" a metric value (derived from MnIfPreference).
       - More tests are required in different environments.


   - netlink_flooding_prevention.patch: this patch prevents a netlink
     flooding that occurs when coming back to the HL, generated by an
     address update (valid lifetime update) by umip that is taken into
     account by umip to generate another update which ... To make it
     simple, umip keeps updating the lifetime (i've attached a stupid
     program that monitor netlink messages, netlink_listener.c. Just
     compile it, launch it and move from FL to HL)

     At the moment, i've just workaround the bug by testing the fact
     that the hai->home_reg_status is HOME_REG_VALID, but i don't think
     this is the correct behavior, as there might be a window during
     which the lifetime gets zero and is not updated because
     hai->home_reg_status is still HOME_REG_VALID. I'm not familiar with
     that part of the code. 

     Also note that the "if (A) ... else if (!A) ..." structure in
     process_link() is suspect in the initial code ;-) 

   - allow_interface_addition_removal.patch: when mip6d.conf file has
     information for multiple interfaces, all those interfaces must be
     present when the daemon is started. This is extremely annoying on
     MN, for instance when you use bluetooth interfaces in NAP/PANU mode
     as they are created only when the dongle is present and association
     is done. Same if you activate the bluetooth only later (i.e. iface
     does not exist initially).

     The patch adds "available" flag in net_iface structure
     (representing an interface element in the list maintained in conf
     structure) which is set to 0 when the interface is not available
     during parsing, i.e. the ifindex element is not valid. Then, the
     rest of the patch prevents the interface to be considered when not
     available. On netlink RTM_NEWLINK/RTM_DELLINK signal, if the
     interface is one of those that were not available, we update its
     ifindex and mark it as available.

     The feature is not for HA.

     Note that:
      - i've removed process_new_link() to replace the only call by one to
        process_new_inet6_iface(), in case of RTM_NEWLINK. This is also
        what is done in process_inet6_iface() ("else" case in
        process_link()). Tell me if I missed a point.
      - i could have used "ifindex" with a negative value to mark
        availability instead of adding "available", but this is clearer
        that way (IMHO).
      - there is a direct call to fprintf() during parsing if an
        expected interface is not available yet in MN/CN case. There's
        no warning function to do that. Should i use uerror() ?


 o Against the most recent branch of linux-ipv6.org kernel git tree
   ( linux-2.6-mip6-2.6.23-rc3 ) 

   - SADB_X_EXT_PACKET_linux-2.6-mip6-2.6.23rc3.diff: some among you
     already use it. It adds support for SADB_X_EXT_PACKET as defined in 
     draft-sugimoto-mip6-pfkey-migrate-03.txt. Updated for that
     particular version.


     Notes:
       - Following discussions with Shinta, the format of the extension
         is modified to include a copylen field providing the real
         length of the  citation. Next version of the draft is expected
         to include that change. 
       - The support is limited only to Home Registration Binding Update
         (MH of type BU with H bit flag set). This reflects the fact
         that having a _generic_ version capable of providing a citation
         for all kinds of packets (TCP,UDP,Raw,...) requires quite some
         work and would complicates things a lot without any real
         benefit.

 o Against current CVS version of raccon (to be applied in that order)
 
   - 00_pk_recv_sanity_check.patch: sanity check against received PF_KEY
     messages with an obvious wrong advertised value (shorter than
     PF_KEY message header). 

   - 01_getsp_r_better_match.patch: getsp_r() performs a non-exact match
     against policy table. Without that patch, the first non-exact SP
     match result found in the sptree is returned, even if there is a
     perfect match found after that point. The patch modifies that
     behavior to allow perfect matches to be returned instead of
     first.

     The only 2 uses of this function are in get_proposal_r() in
     isakmp_quick.c (used only by responder) to get best inbound and
     outbound policies from SPD to reply to initiator.

   - 02_match_subnets.patch: this patch adds a line of information log
     in debug level V that allow detecting a mismatch in ID payload
     types or family. Useful as a hint to start understanding that your
     peer send a /128 subnet instead of an ipv6 address type ;-)

   - 03_add_scopeid_test_in_cmpsaddr.patch: This patch adds support for
     scope id test that was lacking in address comparison
     functions. This has an impact on link local addresses
     comparison. This is not a required patch. It is included mainly to
     have comments on its usefulness.

   - 04_ip6mh_header_file.patch: this patch adds definition of lacking
     MIPv6 structures. At the moment, it also include definition of
     structures and constants which belongs to ip6.h but are not yet
     available there (at least in recent version of Linux kernel). Like
     it is done for umip, some autoconf magic should be used to test
     availability. As racoon has support for far more architecture and
     system than umip, I think it is wise to wait for some autfoconf
     wizard to help us on that.

   - 05_addresses_update.patch: this patch _deeply_ changes the way
     racoon deals with update of addresses and sockets to better support
     mobility. 

     Basically, when racoon has to update its addresses, its closes
     everything and starts again. In session.c, check_rtsock() function
     had: 

     ...
     isakmp_close();
     grab_myaddrs();
     autoconf_myaddrsport();
     isakmp_open();
     ...

     This patch prevents that to happen by modifying global lcconf
     structure: it adds the oldaddrs parameter to the
     structure. isakmp_close() is now passed a myaddr structure to
     close a specific set of addresses. When an update is required, new
     addresses are grabbed, old unused sockets are closed, the ones
     still valid are reused and missing ones are initialized.

     Most changes to grabmyaddr.c are self explanatory with previous
     comment.
     

   - 06_sadb_x_ext_packet_support.patch: this patch adds support for
     SADB_X_EXT_PACKET extension in racoon. First note: as stated in
     first hunk, inclusion of netinet/ip6.h and netinet/ip6mh.h should
     be done differently. Some autoconf wizard, please.

     The patch only modifies pfkey.c by adding some changes to:
       - allow the Phase 1 exchange to start when initiator, as racoon
         has some early checks to prevent anything to happen if we are
         not listening on source address of SA.
       - allow the source and destination addresses used by
         pk_sendgetspi(), pk_sendupdate() and pk_sendadd() to be set
         correctly.
       - correct racoon behavior w.r.t to ID handling and the associated
         support_proxy configuration knob.
       - add mip6_remap() function that will parse the packet passed as
         second parameter to find out if it is a HRBU, extract the 2
         addresses of interest and act using that information.

     There are (at least) 3 sets of src/dst addresses maintained by
     raccon w.r.t. Phase 2 (ph2handle structure, generally referenced
     through iph2 in the code): 

       - iph2->id and iph2->id_p: they are respectively our ID and the
         peer's ID minus the general header. For the initiator case,
         they are created using ipsecdoi_setid2(). For the responder,
         they are initialized with the content of the phase 2 ID
         payloads sent by the initiator. In MIPv6 context, during
         bootstrapping, those ID payloads are naturally filled by 
         racoon on the MN using the content of source and destination
         address in the SP (i.e. HoA and HA @) while the
         SADB_X_EXT_PACKET code will force the source of emission to be
         the CoA (available in BU citation).

         On the responder, in the call to get_proposal_r(), the
         policyindex structure created to look for an inbound SP is
         filled with the content of iph2->id and iph2->id_p,
         respectively as destination and source of searched SP, iif they
         are both of type address or subnet (IPv4 or IPv6). Then,
         if both ID are IP addresses of same family (either v4 or v6),
         they are respectively copied in iph2->src and iph2->dst.

       - iph2->src_id and iph2->dst_id: as commented in previous item,
         those parameters are filled on the responder with the content
         of ID payloads when both are addresses of same type.

       - iph2->src and iph2->dst: the local addresses used for this SA,
         i.e. the addresses that will be used as source and destination
         for the negotiation. 

     But racoon also provide the ability to limit sainfo information to
     specific peer using the "from idtype string" statement for the
     sainfo definition in the racoon.conf file. When no idtype is
     specified and string is an IPv6 address, during the parsing of
     racoon.conf file, racoon stores the identifier (as an ID payload)
     in sainfo->id_i. This value will be use to further discriminate a
     peer when looking for a valid Phase 2 information. This part is
     obviously of interest only for the receiver. I removed some checks
     in pfkey.c file regarding the activation of proxy mode on the
     receiver that prevented proxy mode to be activated (i.e. ID
     payloads to be considered in the discussion) when no "from idtype
     string" was specified for Phase 2 parameters. Please, note that it
     does not prevent checks to be done when it is available and
     possible. 

     Prototype of the function is the following:

     struct sainfo *
     getsainfo(loc, rmt, peer, remoteid)
             const vchar_t *loc, *rmt, *peer;
             int remoteid;

     The function is mostly used twice: one is in responder case and the
     other in initiator case. 

     The initiator case is in pk_recvacquire(), when racoon gets a demand
     for negotiating an SA. In that case, the peer parameter is
     explicitly set to NULL. Only source and destination addresses found
     in the ACQUIRE are used to get both remote peer parameters and also
     find the SA by the call to getsainfo(). SADB_X_EXT_PACKET specific
     code only allows to bypass some initial checks (that verify we are
     listening on the source address in the ACQUIRE) when proxy mode is
     activated for the remote peer we will contact and the ACQUIRE
     contains an SADB_X_EXT_PACKET extension. 

     The responder case is in isakmp_quick.c, in get_sainfo_r(). This
     function is mainly a wrapper to getsainfo() that preferentially
     selects iph2->id and iph2->id_p as loc and rmt values to use for
     the call to getsainfo(). When those are available, they contain the
     content of Phase 2 ID payloads provided by the peer. In our case,
     the MN provides HoA and HA@. But the most interesting part is that
     the peer parameter is set to iph2->iph1->id_p, which is the Phase 1
     ID passed by the MN. The good thing is that this parameter is
     compared against id_i field in sainfo structures (if defined,
     i.e. not NULL), which reflects what the user provided in the "from
     idtype string" statement for the sainfo. When certificates are used
     and a 'peers_identifier asn1dn "C=FR, ST=FRANCE, ...., CN=*"' is
     defined in remote statement for anonymous destination on the HA, it
     is possible to select the sainfo based on source and destination
     addresses (HoA and HA@) AND the asn1dn in the certificate
     (provided during Phase 1 by the MN). This allows to perfectly
     associate the peer's identity (its certificate) with its address
     (HoA). 


   - 07_sadb_x_migrate.patch: this patch adds support for PF_KEY MIGRATE
     message in racoon, by providing pk_recvmigrate() handler. The
     handler performs the parsing of the message and then uses two
     helpers (isakmp_ph1migrate() and isakmp_ph2migrate()) to perform
     the required migration work.

     isakmp_ph1migrate() gets the ph1handle associated with old source
     and destination addresses and remap them. Note that this step
     occurs before even considering Phase 2 elements, i.e. on the Phase
     1 state for this specific (src, dst). Then all Phase 2 elements
     that use this Phase 1 are considered by isakmp_ph2migrate().

     isakmp_ph2migrate() simply remap old iph2->src and iph2->dst with
     their updated version. No test is done as those addresses are
     in sync with the source and destination addresses used by the Phase
     1 handle. 

     From a global standpoint, the patch also provides changes to keep
     the binding between Phase 1 and Phase 2 handles where it is
     normally destroyed in current version of racoon. Without that
     change, Phase 1 handles are searched by address when needed. Now,
     we simply access iph2->ph1 when available. Basically, the only
     moment when this value is NULL is when Phase 1 is being
     negotiated (i.e. initial negotiation). This change is for instance
     useful for rekeying, most notably, for the initial transport mode
     SA pair protecting BU/BA traffic. As the rekeying does not provide
     any packet, the selection of addresses to be put in ID payload
     would be wrong. With that, we simply continue using the iinitial
     one (it is fine for both transport with and without PROXY/PACKET
     and tunnel mode endpoints) 

     The last part of the patch deals with ID information in Phase 2
     handle. The structure contains id and id_p fields which contain the
     ID passed during Phase 2. During rekeying, we avoid a clearing of
     those ID and reuse them directly when available. This avoid the
     call to ipsecdoi_setid2().

     Discussion: one of the expected (positive) side effect is that the
     rekeying of the SA is still performed even if the associated SP has
     been deleted. This is because ipsecdoi_setid2() contains a call to
     getspbyspid() which makes the function return if no SP is
     associated with the the SA. In the case of tunnel mode SA, when
     returning home, the SP gets removed, which normally means that next
     rekeying will simply not work. I don't know if it is the expected
     behavior of racoon to have next rekeying not working or if it is
     just a bug. More generally, what is the expected behavior a KM
     should have on that point. How does racoon2 handles that ?

   
Index: mipv6-daemon/src/conf.h
===================================================================
--- mipv6-daemon.orig/src/conf.h	2007-08-27 11:27:32.199089885 +0200
+++ mipv6-daemon/src/conf.h	2007-08-27 11:40:02.969873874 +0200
@@ -64,6 +64,7 @@
 	int is_rtr;
 	int mip6_if_entity;
 	int mn_if_preference;
+	int available;
 };
 
 extern struct mip6_config conf;
Index: mipv6-daemon/src/gram.y
===================================================================
--- mipv6-daemon.orig/src/gram.y	2007-08-27 11:27:32.203090113 +0200
+++ mipv6-daemon/src/gram.y	2007-08-27 11:40:02.973874102 +0200
@@ -322,18 +322,27 @@
 ifacedef	: QSTRING ifacesub
 		{
 			struct net_iface *nni;
+			int available = 1;
 			strncpy(ni.name, $1, IF_NAMESIZE - 1);
 			ni.ifindex = if_nametoindex($1);
-			free($1);
 			if (ni.ifindex <= 0) {
-				uerror("invalid interface");
-				return -1;
+				if (is_if_ha(&ni)) {
+					/* We do not allow unavailable ifaces for HA ... */
+					uerror("HA interface %s unavailable", $1);
+					free($1);
+					return -1;
+				}
+				/* ... but allow them for CN and MN */
+				available = 0;
+				fprintf(stderr, "Interface %s unavailable yet. Skipping ...\n", $1);
+				free($1);
 			}
 			nni = malloc(sizeof(struct net_iface));
 			if (nni == NULL) {
 				uerror("out of memory");
 				return -1;
 			}
+			ni.available = available;
 			memcpy(nni, &ni, sizeof(struct net_iface));
 			list_add_tail(&nni->list, &conf.net_ifaces);
 			if (is_if_ha(nni))
Index: mipv6-daemon/src/movement.c
===================================================================
--- mipv6-daemon.orig/src/movement.c	2007-08-27 11:27:32.207090341 +0200
+++ mipv6-daemon/src/movement.c	2007-08-27 11:40:02.973874102 +0200
@@ -667,6 +667,25 @@
 	struct md_inet6_iface *iface;
 	if ((iface = md_get_inet6_iface(&ifaces, ifi->ifi_index)) == NULL) {
 		unsigned int pref;
+		char ifname[IF_NAMESIZE];
+
+		/*
+		 * Let's update ifindex and mark the interface as
+		 * available if the user expects it to be used
+		 */
+		if (if_indextoname(ifi->ifi_index, ifname) != NULL) {
+			struct list_head *list;
+			list_for_each(list, &conf.net_ifaces) {
+				struct net_iface *nif;
+				nif = list_entry(list, struct net_iface, list);
+				if (!(nif->available) &&
+				    strncmp(ifname, nif->name, IF_NAMESIZE-1) == 0) {
+					nif->ifindex = ifi->ifi_index;
+					nif->available = 1;
+					break;
+				}
+			}
+		}
 		if ((pref = conf.pmgr.accept_inet6_iface(ifi->ifi_index)) &&
 		    (iface = md_create_inet6_iface(ifi, rta_tb)) != NULL) {
 			MDBG2("adding iface %s (%d)\n",
@@ -692,9 +711,22 @@
 {
        	struct md_inet6_iface *iface;
 	if ((iface = md_get_inet6_iface(&ifaces, ifi->ifi_index)) != NULL) {
+		struct list_head *list;
 		MDBG2("deleting iface %s (%d)\n", iface->name, iface->ifindex);
 		md_expire_inet6_iface(iface);
 		md_free_inet6_iface(iface);
+
+		/* Mark interface as unavailable */
+		list_for_each(list, &conf.net_ifaces) {
+			struct net_iface *nif;
+			nif = list_entry(list, struct net_iface, list);
+			if ((nif->available) &&
+			    nif->ifindex == ifi->ifi_index) {
+				nif->available = 0;
+				nif->ifindex = 0;
+				break;
+			}
+		}
 	}
 	return 0;
 }
@@ -722,21 +754,6 @@
 	return 0;
 }
 
-static int process_new_link(struct ifinfomsg *ifi, struct rtattr **rta_tb)
-{
-	struct md_inet6_iface *iface;
-	if ((iface = md_get_inet6_iface(&ifaces, ifi->ifi_index)) != NULL &&
-	    link_flags_changed(ifi->ifi_flags, iface->link_flags)) {
-		iface->link_flags = ifi->ifi_flags;
-		if (md_is_link_up(iface))
-			md_link_up(iface);
-		else 
-			md_link_down(iface);
-	}
-	return 0;
-}
-
-
 static int process_link(struct nlmsghdr *n, void *arg)
 {
 	struct ifinfomsg *ifi;
@@ -761,7 +778,7 @@
 	pthread_mutex_lock(&iface_lock);
 	if (ifi->ifi_family == AF_UNSPEC) {
 		if (n->nlmsg_type == RTM_NEWLINK)
-			process_new_link(ifi, rta_tb);
+			process_new_inet6_iface(ifi, rta_tb);
 		else if (n->nlmsg_type == RTM_DELLINK)
 			process_del_inet6_iface(ifi, rta_tb);
 	} else
Index: mipv6-daemon/man/mip6d.conf.tmpl
===================================================================
--- mipv6-daemon.orig/man/mip6d.conf.tmpl	2007-08-27 11:27:32.219091025 +0200
+++ mipv6-daemon/man/mip6d.conf.tmpl	2007-08-27 11:40:02.973874102 +0200
@@ -68,7 +68,10 @@
 agent to function properly, a Router Advertisement daemon (e.g. radvd)
 must broadcast advertisements with the Home Agent bit and Home Agent
 Information Option set on these interfaces.  This option is also
-used by multihomed Mobile Nodes to define which interfaces are used by it.
+used by multihomed Mobile Nodes to define which interfaces are used by
+it. For MN and CN, it is posible to provide interfaces that are not
+already available when the daemon is started. Those will be used when
+available.
 
 .B MnIfPreference
 sets the interface preference value for an interface in a multi-homed
Index: mipv6-daemon/src/mn.c
===================================================================
--- mipv6-daemon.orig/src/mn.c	2007-08-27 11:23:38.501772234 +0200
+++ mipv6-daemon/src/mn.c	2007-08-27 11:27:53.468301948 +0200
@@ -1471,11 +1471,11 @@
 			addr_do(&hai->hoa.addr, plen,
 				hai->hoa.iif, &arg, flag_hoa);
 		}
-	} else if (hai->home_reg_status != HOME_REG_NONE) {
-		if (hai->hoa.valid_time.tv_sec)
+	} else if (hai->home_reg_status != HOME_REG_VALID) {
+		if (hai->hoa.valid_time.tv_sec) {
 			addr_do(&hai->hoa.addr, 128, hai->hoa.iif, 
 				hai, update_hoa);
-		else
+		} else
 			addr_del(&hai->hoa.addr, 128, hai->hoa.iif);
 	}
 
#include <sys/types.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <linux/rtnetlink.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <strings.h>

#define SIZ 5200

int
main(int argc, char *argv[]) {

	struct sockaddr_nl nl;
	u_int addr_len;
	fd_set rfds;
	static int nfds=0;
	int error;
	char msg[SIZ];
	int len;
	__u16 nlmsg_type;
	int rtsock;
	struct nlmsghdr *h = (void*)msg;
	int i = 0, j = 0;


	memset(&nl, 0, sizeof(nl));
	nl.nl_family = AF_NETLINK;
	nl.nl_groups = RTMGRP_IPV4_IFADDR|RTMGRP_LINK|RTMGRP_IPV6_IFADDR;

	rtsock = socket(PF_ROUTE, SOCK_RAW, PF_UNSPEC);
	if (rtsock < 0) {
		fprintf(stderr, "Unable to get netlink socket.\n");
		exit(1);
	}
	if (bind(rtsock, (struct sockaddr*)&nl, sizeof(nl)) < 0) {
		fprintf(stderr, "Unable to bind netlink socket.\n");
		exit(1);
	}

	nfds = rtsock + 1;
	FD_SET(rtsock, &rfds);

	while (1) {
		i++;
		error = select(nfds, &rfds, (fd_set *)0, (fd_set *)0, 0);
		if (error < 0) {
			fprintf(stderr, "Error on select.\n");
			continue;
		}
		
		if (FD_ISSET(rtsock, &rfds)) {
			len=read(rtsock, msg, sizeof(msg));
			if (len < 0)
				continue;

			if (len < sizeof(*h))
				continue;

			if (h->nlmsg_pid) /* not from kernel! */
				continue;

			nlmsg_type = h->nlmsg_type;
			if (!(nlmsg_type == RTM_NEWADDR || 
			      nlmsg_type == RTM_DELADDR))
				continue;
			
			fprintf(stderr, "Netlink %d %d ", i, nlmsg_type);

			for (j=0; j<len; j++) {
				fprintf(stderr, "%02x", msg[j]);
			}

			fprintf(stderr, "\n");

			FD_SET(rtsock, &rfds);
		}
		FD_SET(rtsock, &rfds);
	}

	exit(0);
}
Index: mipv6-daemon/src/conf.h
===================================================================
--- mipv6-daemon.orig/src/conf.h	2007-08-27 11:27:32.199089885 +0200
+++ mipv6-daemon/src/conf.h	2007-08-27 11:40:02.969873874 +0200
@@ -64,6 +64,7 @@
 	int is_rtr;
 	int mip6_if_entity;
 	int mn_if_preference;
+	int available;
 };
 
 extern struct mip6_config conf;
Index: mipv6-daemon/src/gram.y
===================================================================
--- mipv6-daemon.orig/src/gram.y	2007-08-27 11:27:32.203090113 +0200
+++ mipv6-daemon/src/gram.y	2007-08-27 11:40:02.973874102 +0200
@@ -322,18 +322,27 @@
 ifacedef	: QSTRING ifacesub
 		{
 			struct net_iface *nni;
+			int available = 1;
 			strncpy(ni.name, $1, IF_NAMESIZE - 1);
 			ni.ifindex = if_nametoindex($1);
-			free($1);
 			if (ni.ifindex <= 0) {
-				uerror("invalid interface");
-				return -1;
+				if (is_if_ha(&ni)) {
+					/* We do not allow unavailable ifaces for HA ... */
+					uerror("HA interface %s unavailable", $1);
+					free($1);
+					return -1;
+				}
+				/* ... but allow them for CN and MN */
+				available = 0;
+				fprintf(stderr, "Interface %s unavailable yet. Skipping ...\n", $1);
+				free($1);
 			}
 			nni = malloc(sizeof(struct net_iface));
 			if (nni == NULL) {
 				uerror("out of memory");
 				return -1;
 			}
+			ni.available = available;
 			memcpy(nni, &ni, sizeof(struct net_iface));
 			list_add_tail(&nni->list, &conf.net_ifaces);
 			if (is_if_ha(nni))
Index: mipv6-daemon/src/movement.c
===================================================================
--- mipv6-daemon.orig/src/movement.c	2007-08-27 11:27:32.207090341 +0200
+++ mipv6-daemon/src/movement.c	2007-08-27 11:40:02.973874102 +0200
@@ -667,6 +667,25 @@
 	struct md_inet6_iface *iface;
 	if ((iface = md_get_inet6_iface(&ifaces, ifi->ifi_index)) == NULL) {
 		unsigned int pref;
+		char ifname[IF_NAMESIZE];
+
+		/*
+		 * Let's update ifindex and mark the interface as
+		 * available if the user expects it to be used
+		 */
+		if (if_indextoname(ifi->ifi_index, ifname) != NULL) {
+			struct list_head *list;
+			list_for_each(list, &conf.net_ifaces) {
+				struct net_iface *nif;
+				nif = list_entry(list, struct net_iface, list);
+				if (!(nif->available) &&
+				    strncmp(ifname, nif->name, IF_NAMESIZE-1) == 0) {
+					nif->ifindex = ifi->ifi_index;
+					nif->available = 1;
+					break;
+				}
+			}
+		}
 		if ((pref = conf.pmgr.accept_inet6_iface(ifi->ifi_index)) &&
 		    (iface = md_create_inet6_iface(ifi, rta_tb)) != NULL) {
 			MDBG2("adding iface %s (%d)\n",
@@ -692,9 +711,22 @@
 {
        	struct md_inet6_iface *iface;
 	if ((iface = md_get_inet6_iface(&ifaces, ifi->ifi_index)) != NULL) {
+		struct list_head *list;
 		MDBG2("deleting iface %s (%d)\n", iface->name, iface->ifindex);
 		md_expire_inet6_iface(iface);
 		md_free_inet6_iface(iface);
+
+		/* Mark interface as unavailable */
+		list_for_each(list, &conf.net_ifaces) {
+			struct net_iface *nif;
+			nif = list_entry(list, struct net_iface, list);
+			if ((nif->available) &&
+			    nif->ifindex == ifi->ifi_index) {
+				nif->available = 0;
+				nif->ifindex = 0;
+				break;
+			}
+		}
 	}
 	return 0;
 }
@@ -722,21 +754,6 @@
 	return 0;
 }
 
-static int process_new_link(struct ifinfomsg *ifi, struct rtattr **rta_tb)
-{
-	struct md_inet6_iface *iface;
-	if ((iface = md_get_inet6_iface(&ifaces, ifi->ifi_index)) != NULL &&
-	    link_flags_changed(ifi->ifi_flags, iface->link_flags)) {
-		iface->link_flags = ifi->ifi_flags;
-		if (md_is_link_up(iface))
-			md_link_up(iface);
-		else 
-			md_link_down(iface);
-	}
-	return 0;
-}
-
-
 static int process_link(struct nlmsghdr *n, void *arg)
 {
 	struct ifinfomsg *ifi;
@@ -761,7 +778,7 @@
 	pthread_mutex_lock(&iface_lock);
 	if (ifi->ifi_family == AF_UNSPEC) {
 		if (n->nlmsg_type == RTM_NEWLINK)
-			process_new_link(ifi, rta_tb);
+			process_new_inet6_iface(ifi, rta_tb);
 		else if (n->nlmsg_type == RTM_DELLINK)
 			process_del_inet6_iface(ifi, rta_tb);
 	} else
Index: mipv6-daemon/man/mip6d.conf.tmpl
===================================================================
--- mipv6-daemon.orig/man/mip6d.conf.tmpl	2007-08-27 11:27:32.219091025 +0200
+++ mipv6-daemon/man/mip6d.conf.tmpl	2007-08-27 11:40:02.973874102 +0200
@@ -68,7 +68,10 @@
 agent to function properly, a Router Advertisement daemon (e.g. radvd)
 must broadcast advertisements with the Home Agent bit and Home Agent
 Information Option set on these interfaces.  This option is also
-used by multihomed Mobile Nodes to define which interfaces are used by it.
+used by multihomed Mobile Nodes to define which interfaces are used by
+it. For MN and CN, it is posible to provide interfaces that are not
+already available when the daemon is started. Those will be used when
+available.
 
 .B MnIfPreference
 sets the interface preference value for an interface in a multi-homed
Index: linux-2.6-mip6-work/include/linux/pfkeyv2.h
===================================================================
--- linux-2.6-mip6-work.orig/include/linux/pfkeyv2.h	2007-08-22 10:12:26.432918477 +0200
+++ linux-2.6-mip6-work/include/linux/pfkeyv2.h	2007-08-22 10:37:50.379763258 +0200
@@ -226,6 +226,21 @@
 } __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 @@
 #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
Index: linux-2.6-mip6-work/include/net/dst.h
===================================================================
--- linux-2.6-mip6-work.orig/include/net/dst.h	2007-08-22 10:35:50.708943607 +0200
+++ linux-2.6-mip6-work/include/net/dst.h	2007-08-22 10:37:50.379763258 +0200
@@ -271,9 +271,9 @@
 }
 #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
 
Index: linux-2.6-mip6-work/include/net/mip6.h
===================================================================
--- linux-2.6-mip6-work.orig/include/net/mip6.h	2007-08-22 10:35:54.809177266 +0200
+++ linux-2.6-mip6-work/include/net/mip6.h	2007-08-22 10:37:50.379763258 +0200
@@ -54,4 +54,46 @@
 #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
Index: linux-2.6-mip6-work/include/net/xfrm.h
===================================================================
--- linux-2.6-mip6-work.orig/include/net/xfrm.h	2007-08-22 10:35:55.165197554 +0200
+++ linux-2.6-mip6-work/include/net/xfrm.h	2007-08-22 10:37:50.379763258 +0200
@@ -260,7 +260,7 @@
 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);
 
@@ -416,7 +416,7 @@
 	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);
@@ -938,7 +938,8 @@
 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 struct xfrm_state * xfrm_stateonly_find(xfrm_address_t *daddr,
 					       xfrm_address_t *saddr,
 					       unsigned short family,
Index: linux-2.6-mip6-work/net/decnet/dn_route.c
===================================================================
--- linux-2.6-mip6-work.orig/net/decnet/dn_route.c	2007-08-22 10:36:10.198054228 +0200
+++ linux-2.6-mip6-work/net/decnet/dn_route.c	2007-08-22 10:37:50.379763258 +0200
@@ -1198,7 +1198,7 @@
 
 	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 @@
 
 	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;
 }
Index: linux-2.6-mip6-work/net/ipv4/netfilter.c
===================================================================
--- linux-2.6-mip6-work.orig/net/ipv4/netfilter.c	2007-08-22 10:36:10.834090474 +0200
+++ linux-2.6-mip6-work/net/ipv4/netfilter.c	2007-08-22 10:37:50.379763258 +0200
@@ -60,7 +60,7 @@
 #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 @@
 		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);
Index: linux-2.6-mip6-work/net/ipv4/route.c
===================================================================
--- linux-2.6-mip6-work.orig/net/ipv4/route.c	2007-08-22 10:36:11.190110762 +0200
+++ linux-2.6-mip6-work/net/ipv4/route.c	2007-08-22 10:37:50.383763486 +0200
@@ -2440,7 +2440,7 @@
 			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);
 
Index: linux-2.6-mip6-work/net/ipv6/af_inet6.c
===================================================================
--- linux-2.6-mip6-work.orig/net/ipv6/af_inet6.c	2007-08-22 10:36:11.606134470 +0200
+++ linux-2.6-mip6-work/net/ipv6/af_inet6.c	2007-08-22 10:37:50.383763486 +0200
@@ -673,7 +673,7 @@
 		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;
 		}
Index: linux-2.6-mip6-work/net/ipv6/datagram.c
===================================================================
--- linux-2.6-mip6-work.orig/net/ipv6/datagram.c	2007-08-22 10:36:11.610134698 +0200
+++ linux-2.6-mip6-work/net/ipv6/datagram.c	2007-08-22 10:37:50.383763486 +0200
@@ -177,7 +177,7 @@
 	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)
Index: linux-2.6-mip6-work/net/ipv6/icmp.c
===================================================================
--- linux-2.6-mip6-work.orig/net/ipv6/icmp.c	2007-08-22 10:36:11.630135838 +0200
+++ linux-2.6-mip6-work/net/ipv6/icmp.c	2007-08-22 10:37:50.383763486 +0200
@@ -416,7 +416,7 @@
 		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 @@
 	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))
Index: linux-2.6-mip6-work/net/ipv6/inet6_connection_sock.c
===================================================================
--- linux-2.6-mip6-work.orig/net/ipv6/inet6_connection_sock.c	2007-08-22 10:36:11.642136522 +0200
+++ linux-2.6-mip6-work/net/ipv6/inet6_connection_sock.c	2007-08-22 10:37:50.383763486 +0200
@@ -210,7 +210,7 @@
 		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;
Index: linux-2.6-mip6-work/net/ipv6/ip6_tunnel.c
===================================================================
--- linux-2.6-mip6-work.orig/net/ipv6/ip6_tunnel.c	2007-08-22 10:36:11.666137889 +0200
+++ linux-2.6-mip6-work/net/ipv6/ip6_tunnel.c	2007-08-22 10:37:50.383763486 +0200
@@ -848,7 +848,7 @@
 	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;
 	}
 
Index: linux-2.6-mip6-work/net/ipv6/ndisc.c
===================================================================
--- linux-2.6-mip6-work.orig/net/ipv6/ndisc.c	2007-08-22 10:36:11.702139941 +0200
+++ linux-2.6-mip6-work/net/ipv6/ndisc.c	2007-08-22 10:37:50.387763714 +0200
@@ -450,7 +450,7 @@
 	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 @@
 	if (dst == NULL)
 		return;
 
-	err = xfrm_lookup(&dst, &fl, NULL, 0);
+	err = xfrm_lookup(&dst, &fl, NULL, 0, NULL);
 	if (err)
 		return;
 
Index: linux-2.6-mip6-work/net/ipv6/netfilter.c
===================================================================
--- linux-2.6-mip6-work.orig/net/ipv6/netfilter.c	2007-08-22 10:36:11.714140625 +0200
+++ linux-2.6-mip6-work/net/ipv6/netfilter.c	2007-08-22 10:37:50.387763714 +0200
@@ -27,7 +27,7 @@
 #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
 
Index: linux-2.6-mip6-work/net/ipv6/netfilter/ip6t_REJECT.c
===================================================================
--- linux-2.6-mip6-work.orig/net/ipv6/netfilter/ip6t_REJECT.c	2007-08-22 10:36:11.738141993 +0200
+++ linux-2.6-mip6-work/net/ipv6/netfilter/ip6t_REJECT.c	2007-08-22 10:37:50.387763714 +0200
@@ -96,7 +96,7 @@
 	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;
Index: linux-2.6-mip6-work/net/ipv6/raw.c
===================================================================
--- linux-2.6-mip6-work.orig/net/ipv6/raw.c	2007-08-22 10:36:11.850148376 +0200
+++ linux-2.6-mip6-work/net/ipv6/raw.c	2007-08-22 10:37:50.387763714 +0200
@@ -842,7 +842,11 @@
 	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)
Index: linux-2.6-mip6-work/net/ipv6/tcp_ipv6.c
===================================================================
--- linux-2.6-mip6-work.orig/net/ipv6/tcp_ipv6.c	2007-08-22 10:36:11.886150427 +0200
+++ linux-2.6-mip6-work/net/ipv6/tcp_ipv6.c	2007-08-22 10:37:50.387763714 +0200
@@ -265,7 +265,7 @@
 	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 @@
 				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;
 			}
@@ -496,7 +496,7 @@
 			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;
 	}
 
@@ -1063,7 +1063,7 @@
 	/* 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);
@@ -1162,7 +1162,7 @@
 	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;
@@ -1406,7 +1406,7 @@
 		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;
 	}
 
Index: linux-2.6-mip6-work/net/ipv6/udp.c
===================================================================
--- linux-2.6-mip6-work.orig/net/ipv6/udp.c	2007-08-22 10:36:11.910151795 +0200
+++ linux-2.6-mip6-work/net/ipv6/udp.c	2007-08-22 10:37:50.387763714 +0200
@@ -748,7 +748,7 @@
 	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)
Index: linux-2.6-mip6-work/net/key/af_key.c
===================================================================
--- linux-2.6-mip6-work.orig/net/key/af_key.c	2007-08-22 10:36:17.454467748 +0200
+++ linux-2.6-mip6-work/net/key/af_key.c	2007-08-22 12:11:27.026576437 +0200
@@ -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 @@
 	[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.  */
@@ -2993,7 +3000,178 @@
 	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;
+
+	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->flow_lbl[0] = 0x00;
+	ipv6h->flow_lbl[1] = 0x00;
+	ipv6h->flow_lbl[2] = 0x00;
+	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;
@@ -3008,6 +3186,9 @@
 	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)
@@ -3028,6 +3209,9 @@
 		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;
@@ -3137,6 +3321,10 @@
 		       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);
 }
 
Index: linux-2.6-mip6-work/net/xfrm/Kconfig
===================================================================
--- linux-2.6-mip6-work.orig/net/xfrm/Kconfig	2007-08-22 10:12:26.560925772 +0200
+++ linux-2.6-mip6-work/net/xfrm/Kconfig	2007-08-22 10:37:50.391763942 +0200
@@ -71,3 +71,24 @@
 
 	  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
Index: linux-2.6-mip6-work/net/xfrm/xfrm_policy.c
===================================================================
--- linux-2.6-mip6-work.orig/net/xfrm/xfrm_policy.c	2007-08-22 10:36:20.546643961 +0200
+++ linux-2.6-mip6-work/net/xfrm/xfrm_policy.c	2007-08-22 10:37:50.391763942 +0200
@@ -1287,7 +1287,7 @@
 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;
@@ -1314,7 +1314,7 @@
 			}
 		}
 
-		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;
@@ -1342,7 +1342,7 @@
 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;
@@ -1357,7 +1357,7 @@
 			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;
@@ -1455,7 +1455,7 @@
  * 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];
@@ -1579,7 +1579,7 @@
 		}
 
 #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;
@@ -1599,7 +1599,7 @@
 				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);
@@ -1688,9 +1688,9 @@
 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);
@@ -1965,7 +1965,7 @@
 		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);
 
Index: linux-2.6-mip6-work/net/xfrm/xfrm_state.c
===================================================================
--- linux-2.6-mip6-work.orig/net/xfrm/xfrm_state.c	2007-08-22 10:36:20.558644645 +0200
+++ linux-2.6-mip6-work/net/xfrm/xfrm_state.c	2007-08-22 10:37:50.391763942 +0200
@@ -186,7 +186,7 @@
 
 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 @@
 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 @@
 			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);
@@ -1540,14 +1540,15 @@
  * 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;
 	}
Index: linux-2.6-mip6-work/net/xfrm/xfrm_user.c
===================================================================
--- linux-2.6-mip6-work.orig/net/xfrm/xfrm_user.c	2007-08-22 10:36:20.570645328 +0200
+++ linux-2.6-mip6-work/net/xfrm/xfrm_user.c	2007-08-22 10:37:50.391763942 +0200
@@ -1740,7 +1740,7 @@
 		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);
 
 	}
 
@@ -2263,7 +2263,8 @@
 }
 
 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;
Index: linux-2.6-mip6-work/net/dccp/ipv6.c
===================================================================
--- linux-2.6-mip6-work.orig/net/dccp/ipv6.c	2007-08-22 10:36:10.078047389 +0200
+++ linux-2.6-mip6-work/net/dccp/ipv6.c	2007-08-22 10:37:50.391763942 +0200
@@ -156,7 +156,7 @@
 				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;
Index: ipsec-tools/src/racoon/pfkey.c
===================================================================
--- ipsec-tools.orig/src/racoon/pfkey.c	2007-07-18 14:07:52.000000000 +0200
+++ ipsec-tools/src/racoon/pfkey.c	2007-08-21 18:59:22.673409590 +0200
@@ -2833,6 +2833,11 @@
 		return NULL;
 
 	reallen = PFKEY_UNUNIT64(buf.sadb_msg_len);
+	if (reallen < sizeof(buf)) {
+		*lenp = -1;
+		errno = EIO;
+		return NULL;    /*fatal*/
+	}
 	if ((newmsg = racoon_calloc(1, reallen)) == NULL)
 		return NULL;
 
Index: ipsec-tools/src/racoon/policy.c
===================================================================
--- ipsec-tools.orig/src/racoon/policy.c	2007-07-18 14:07:52.000000000 +0200
+++ ipsec-tools/src/racoon/policy.c	2007-08-21 18:59:56.707349074 +0200
@@ -91,13 +91,17 @@
 	struct policyindex *spidx;
 {
 	struct secpolicy *p;
+	struct secpolicy *found = NULL;
 
 	for (p = TAILQ_FIRST(&sptree); p; p = TAILQ_NEXT(p, chain)) {
-		if (!cmpspidxwild(spidx, &p->spidx))
+		if (!cmpspidxstrict(spidx, &p->spidx))
 			return p;
+
+		if (!found && !cmpspidxwild(spidx, &p->spidx))
+			found = p;
 	}
 
-	return NULL;
+	return found;
 }
 #else
 struct secpolicy *
Index: ipsec-tools/src/racoon/isakmp_quick.c
===================================================================
--- ipsec-tools.orig/src/racoon/isakmp_quick.c	2007-07-18 14:07:51.000000000 +0200
+++ ipsec-tools/src/racoon/isakmp_quick.c	2007-08-21 19:00:29.633225412 +0200
@@ -2039,7 +2039,14 @@
 				    "buffer allocation failed.\n");
 				return ISAKMP_INTERNAL_ERROR;
 			}
-		}
+		} else {
+                        plog(LLV_DEBUG, LOCATION, NULL,
+			     "Family (%d - %d) or types (%d - %d) of ID"
+			     "from initiator differ. Not filling"
+			     "iph2->src_id and iph2->dst_id.\n",
+			     spidx.src.ss_family, spidx.dst.ss_family,
+			     _XIDT(iph2->id_p),idi2type);
+	       }
 
 	} else {
 		plog(LLV_DEBUG, LOCATION, NULL,
Index: ipsec-tools/src/racoon/sockmisc.c
===================================================================
--- ipsec-tools.orig/src/racoon/sockmisc.c	2007-07-18 14:07:52.000000000 +0200
+++ ipsec-tools/src/racoon/sockmisc.c	2007-08-21 19:02:41.396734187 +0200
@@ -85,6 +85,9 @@
 	const struct sockaddr *addr2;
 {
 	caddr_t sa1, sa2;
+#ifdef INET6
+	struct in6_addr *saddr1, *saddr2;
+#endif
 
 	if (addr1 == 0 && addr2 == 0)
 		return 0;
@@ -110,12 +113,19 @@
 		break;
 #ifdef INET6
 	case AF_INET6:
-		sa1 = (caddr_t)&((struct sockaddr_in6 *)addr1)->sin6_addr;
-		sa2 = (caddr_t)&((struct sockaddr_in6 *)addr2)->sin6_addr;
+	        saddr1 = &((struct sockaddr_in6 *) addr1)->sin6_addr;
+		saddr2 = &((struct sockaddr_in6 *) addr2)->sin6_addr;
+		sa1 = (caddr_t)saddr1;
+		sa2 = (caddr_t)saddr2;
+
 		if (memcmp(sa1, sa2, sizeof(struct in6_addr)) != 0)
 			return 1;
-		if (((struct sockaddr_in6 *)addr1)->sin6_scope_id !=
-		    ((struct sockaddr_in6 *)addr2)->sin6_scope_id)
+
+		/* Scope ID is not supported except for ll addr */
+                if ((IN6_IS_ADDR_LINKLOCAL(saddr1) &&
+		     IN6_IS_ADDR_LINKLOCAL(saddr2)) &&
+		    (((struct sockaddr_in6 *)addr1)->sin6_scope_id !=
+		     ((struct sockaddr_in6 *)addr2)->sin6_scope_id))
 			return 1;
 		break;
 #endif
@@ -139,7 +149,9 @@
 {
 	caddr_t sa1, sa2;
 	u_short port1, port2;
-
+#ifdef INET6
+        struct in6_addr *saddr1, *saddr2;
+#endif
 	if (addr1 == 0 && addr2 == 0)
 		return 0;
 	if (addr1 == 0 || addr2 == 0)
@@ -170,8 +182,10 @@
 		break;
 #ifdef INET6
 	case AF_INET6:
-		sa1 = (caddr_t)&((struct sockaddr_in6 *)addr1)->sin6_addr;
-		sa2 = (caddr_t)&((struct sockaddr_in6 *)addr2)->sin6_addr;
+	        saddr1 = &((struct sockaddr_in6 *) addr1)->sin6_addr;
+		saddr2 = &((struct sockaddr_in6 *) addr2)->sin6_addr;
+		sa1 = (caddr_t)saddr1;
+		sa2 = (caddr_t)saddr2;
 		port1 = ((struct sockaddr_in6 *)addr1)->sin6_port;
 		port2 = ((struct sockaddr_in6 *)addr2)->sin6_port;
 		if (!(port1 == IPSEC_PORT_ANY ||
@@ -180,8 +194,12 @@
 			return 1;
 		if (memcmp(sa1, sa2, sizeof(struct in6_addr)) != 0)
 			return 1;
-		if (((struct sockaddr_in6 *)addr1)->sin6_scope_id !=
-		    ((struct sockaddr_in6 *)addr2)->sin6_scope_id)
+
+		/* Scope ID is not supported except for ll addr */
+                if ((IN6_IS_ADDR_LINKLOCAL(saddr1) &&
+		     IN6_IS_ADDR_LINKLOCAL(saddr2)) &&
+		    (((struct sockaddr_in6 *)addr1)->sin6_scope_id !=
+		     ((struct sockaddr_in6 *)addr2)->sin6_scope_id))
 			return 1;
 		break;
 #endif
Index: ipsec-tools/src/include-glibc/netinet/ip6mh.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ ipsec-tools/src/include-glibc/netinet/ip6mh.h	2007-08-14 17:42:36.434751516 +0200
@@ -0,0 +1,230 @@
+#ifndef _NETINET_IP6MH_H
+#define _NETINET_IP6MH_H 1
+
+#include <inttypes.h>
+#include <netinet/in.h>
+
+struct ip6_mh {
+	uint8_t		ip6mh_proto;	/* NO_NXTHDR by default */
+	uint8_t		ip6mh_hdrlen;	/* Header Len in unit of 8 Octets
+				   excluding the first 8 Octets */
+	uint8_t		ip6mh_type;	/* Type of Mobility Header */
+	uint8_t		ip6mh_reserved;	/* Reserved */
+	uint16_t	ip6mh_cksum;	/* Mobility Header Checksum */
+	/* Followed by type specific messages */
+} __attribute__ ((packed));
+
+struct ip6_mh_binding_request {
+	struct ip6_mh	ip6mhbr_hdr;
+	uint16_t	ip6mhbr_reserved;
+	/* Followed by optional Mobility Options */
+} __attribute__ ((packed));
+
+struct ip6_mh_home_test_init {
+	struct ip6_mh	ip6mhhti_hdr;
+	uint16_t	ip6mhhti_reserved;
+	uint32_t	ip6mhhti_cookie[2];	/* 64 bit Cookie by MN */
+	/* Followed by optional Mobility Options */
+} __attribute__ ((packed));
+
+struct ip6_mh_careof_test_init {
+	struct ip6_mh	ip6mhcti_hdr;
+	uint16_t	ip6mhcti_reserved;
+	uint32_t	ip6mhcti_cookie[2];	/* 64 bit Cookie by MN */
+	/* Followed by optional Mobility Options */
+} __attribute__ ((packed));
+
+struct ip6_mh_home_test {
+	struct ip6_mh	ip6mhht_hdr;
+	uint16_t	ip6mhht_nonce_index;
+	uint32_t	ip6mhht_cookie[2];	/* Cookie from HOTI msg */
+	uint32_t	ip6mhht_keygen[2];	/* 64 Bit Key by CN */
+	/* Followed by optional Mobility Options */
+} __attribute__ ((packed));
+
+struct ip6_mh_careof_test {
+	struct ip6_mh	ip6mhct_hdr;
+	uint16_t	ip6mhct_nonce_index;
+	uint32_t	ip6mhct_cookie[2];	/* Cookie from COTI message */
+	uint32_t	ip6mhct_keygen[2];	/* 64bit key by CN */
+	/* Followed by optional Mobility Options */
+} __attribute__ ((packed));
+
+struct ip6_mh_binding_update {
+	struct ip6_mh	ip6mhbu_hdr;
+	uint16_t	ip6mhbu_seqno;		/* Sequence Number */
+	uint16_t	ip6mhbu_flags;
+	uint16_t	ip6mhbu_lifetime;	/* Time in unit of 4 sec */
+	/* Followed by optional Mobility Options */
+} __attribute__ ((packed));
+
+/* ip6mhbu_flags */
+#if BYTE_ORDER == BIG_ENDIAN
+#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 */
+#else				/* BYTE_ORDER == LITTLE_ENDIAN */
+#define IP6_MH_BU_ACK		0x0080	/* Request a binding ack */
+#define IP6_MH_BU_HOME		0x0040	/* Home Registration */
+#define IP6_MH_BU_LLOCAL	0x0020	/* Link-local compatibility */
+#define IP6_MH_BU_KEYM		0x0010	/* Key management mobility */
+#define IP6_MH_BU_MAP		0x0008	/* HMIPv6 MAP Registration */
+#define IP6_MH_BU_MR		0x0004	/* NEMO MR Registration */
+#endif
+
+struct ip6_mh_binding_ack {
+	struct ip6_mh	ip6mhba_hdr;
+	uint8_t 	ip6mhba_status;	/* Status code */
+	uint8_t		ip6mhba_flags;
+	uint16_t	ip6mhba_seqno;
+	uint16_t	ip6mhba_lifetime;
+	/* Followed by optional Mobility Options */
+} __attribute__ ((packed));
+
+/* ip6mhba_flags */
+#define IP6_MH_BA_KEYM		0x80	/* Key management mobility */
+#define IP6_MH_BA_MR		0x40	/* NEMO MR registration */
+
+struct ip6_mh_binding_error {
+	struct ip6_mh	ip6mhbe_hdr;
+	uint8_t 	ip6mhbe_status;	/* Error Status */
+	uint8_t		ip6mhbe_reserved;
+	struct in6_addr	ip6mhbe_homeaddr;
+	/* Followed by optional Mobility Options */
+} __attribute__ ((packed));
+
+/*
+ * Mobility Option TLV data structure
+ */
+struct ip6_mh_opt {
+	uint8_t		ip6mhopt_type;	/* Option Type */
+	uint8_t		ip6mhopt_len;	/* Option Length */
+	/* Followed by variable length Option Data in bytes */
+} __attribute__ ((packed));
+
+/*
+ * Mobility Option Data Structures
+ */
+struct ip6_mh_opt_refresh_advice {
+	uint8_t		ip6mora_type;
+	uint8_t		ip6mora_len;
+	uint16_t	ip6mora_interval;	/* Refresh interval in 4 sec */
+} __attribute__ ((packed));
+
+struct ip6_mh_opt_altcoa {
+	uint8_t		ip6moa_type;
+	uint8_t		ip6moa_len;
+	struct in6_addr	ip6moa_addr;		/* Alternate Care-of Address */
+} __attribute__ ((packed));
+
+struct ip6_mh_opt_nonce_index {
+	uint8_t		ip6moni_type;
+	uint8_t		ip6moni_len;
+	uint16_t	ip6moni_home_nonce;
+	uint16_t	ip6moni_coa_nonce;
+} __attribute__ ((packed));
+
+struct ip6_mh_opt_auth_data {
+	uint8_t		ip6moad_type;
+	uint8_t 	ip6moad_len;
+	uint8_t 	ip6moad_data[12];	/* 96 bit Authenticator */
+} __attribute__ ((packed));
+
+struct ip6_mh_opt_mob_net_prefix {
+	uint8_t 	ip6mnp_type;
+	uint8_t 	ip6mnp_len;
+	uint8_t 	ip6mnp_reserved;
+	uint8_t 	ip6mnp_prefix_len;
+	struct in6_addr ip6mnp_prefix;
+} __attribute__ ((packed));
+
+/* XXX See how to move the following definitions (until IPPROTO_MH)
+ * XXX outside that file. They do not belong here and the availability
+ * XXX of most of them should be checked using autoconf.  --arno
+ */
+
+/* XXX Removed as it is now available directly in ip6.h. At least
+ * XXX under linux. Check that for other systems --arno
+ */
+/*
+struct ip6_opt {
+       uint8_t ip6o_type;
+       uint8_t ip6o_len;
+} __attribute__((__packed__));
+*/
+
+struct ip6_opt_home_address {
+       uint8_t ip6oh_type;
+       uint8_t ip6oh_len;
+       uint8_t ip6oh_addr[16];
+       /* sub options */
+} __attribute__((packed));
+
+#define IPV6_VERSION_MASK      0xf0
+#define IPV6_VERSION           0x60
+
+#ifndef IP6OPT_HOME_ADDRESS
+#define IP6OPT_HOME_ADDRESS    0xc9
+#endif
+
+#ifndef IPPROTO_MH
+#define IPPROTO_MH             135
+#endif
+
+
+/*
+ *     Mobility Header Message Types
+ */
+#define IP6_MH_TYPE_BRR		0	/* Binding Refresh Request */
+#define IP6_MH_TYPE_HOTI	1	/* HOTI Message */
+#define IP6_MH_TYPE_COTI	2	/* COTI Message */
+#define IP6_MH_TYPE_HOT		3	/* HOT Message */
+#define IP6_MH_TYPE_COT		4	/* COT Message */
+#define IP6_MH_TYPE_BU		5	/* Binding Update */
+#define IP6_MH_TYPE_BACK	6	/* Binding ACK */
+#define IP6_MH_TYPE_BERROR	7	/* Binding Error */
+
+/*
+ *     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 */
+
+/*
+ *    Status values accompanied with Mobility Binding Acknowledgement
+ */
+#define IP6_MH_BAS_ACCEPTED		0	/* BU accepted */
+#define IP6_MH_BAS_PRFX_DISCOV		1	/* Accepted, but prefix discovery
+						   required */
+#define IP6_MH_BAS_UNSPECIFIED		128	/* Reason unspecified */
+#define IP6_MH_BAS_PROHIBIT		129	/* Administratively prohibited */
+#define IP6_MH_BAS_INSUFFICIENT		130	/* Insufficient resources */
+#define IP6_MH_BAS_HA_NOT_SUPPORTED	131	/* HA registration not supported */
+#define IP6_MH_BAS_NOT_HOME_SUBNET	132	/* Not Home subnet */
+#define IP6_MH_BAS_NOT_HA		133	/* Not HA for this mobile node */
+#define IP6_MH_BAS_DAD_FAILED		134	/* DAD failed */
+#define IP6_MH_BAS_SEQNO_BAD		135	/* Sequence number out of range */
+#define IP6_MH_BAS_HOME_NI_EXPIRED	136	/* Expired Home nonce index */
+#define IP6_MH_BAS_COA_NI_EXPIRED	137	/* Expired Care-of nonce index */
+#define IP6_MH_BAS_NI_EXPIRED		138	/* Expired Nonce Indices */
+#define IP6_MH_BAS_REG_NOT_ALLOWED	139	/* Registration type change
+						   disallowed */
+#define IP6_MH_BAS_MR_OP_NOT_PERMITTED	140	/* MR Operation not permitted */
+#define IP6_MH_BAS_INVAL_PRFX		141	/* Invalid Prefix */
+#define IP6_MH_BAS_NOT_AUTH_FOR_PRFX	142	/* Not Authorized for Prefix */
+#define IP6_MH_BAS_FWDING_FAILED	143	/* Forwarding Setup failed */
+/*
+ *    Status values for the Binding Error mobility messages
+ */
+#define IP6_MH_BES_UNKNOWN_HAO	1	/* Unknown binding for HOA */
+#define IP6_MH_BES_UNKNOWN_MH	2	/* Unknown MH Type */
+
+#endif	/* netinet/ip6mh.h */
Index: ipsec-tools/src/racoon/grabmyaddr.c
===================================================================
--- ipsec-tools.orig/src/racoon/grabmyaddr.c	2007-08-21 19:11:57.844444335 +0200
+++ ipsec-tools/src/racoon/grabmyaddr.c	2007-08-21 19:12:01.268639468 +0200
@@ -316,6 +316,8 @@
 		return NULL;
 
 	for (q = db; q; q = q->next) {
+  	        if (!q->addr)
+		        continue;
 		if (p->addr->sa_family != q->addr->sa_family)
 			continue;
 		if (getnameinfo(q->addr, sysdep_sa_len(q->addr), h2, sizeof(h2),
@@ -332,7 +334,7 @@
 grab_myaddrs()
 {
 #ifdef HAVE_GETIFADDRS
-	struct myaddrs *p, *q, *old;
+	struct myaddrs *p, *q;
 	struct ifaddrs *ifa0, *ifap;
 #ifdef INET6
 	struct sockaddr_in6 *sin6;
@@ -347,7 +349,8 @@
 		/*NOTREACHED*/
 	}
 
-	old = lcconf->myaddrs;
+	lcconf->oldaddrs = lcconf->myaddrs;
+	lcconf->myaddrs = NULL;
 
 	for (ifap = ifa0; ifap; ifap = ifap->ifa_next) {
 		if (! ifap->ifa_addr)
@@ -404,16 +407,18 @@
 #endif
 		if (getnameinfo(p->addr, sysdep_sa_len(p->addr),
 				addr1, sizeof(addr1),
-				NULL, 0,
+			      	NULL, 0,
 				NI_NUMERICHOST | niflags))
-		strlcpy(addr1, "(invalid)", sizeof(addr1));
+		        strlcpy(addr1, "(invalid)", sizeof(addr1));
 		plog(LLV_DEBUG, LOCATION, NULL,
 			"my interface: %s (%s)\n",
 			addr1, ifap->ifa_name);
-		q = find_myaddr(old, p);
-		if (q)
+		q = find_myaddr(lcconf->oldaddrs, p);
+		if (q) {
 			p->sock = q->sock;
-		else
+			racoon_free(q->addr);
+			q->addr = NULL;
+		} else
 			p->sock = -1;
 		p->next = lcconf->myaddrs;
 		lcconf->myaddrs = p;
@@ -421,8 +426,6 @@
 
 	freeifaddrs(ifa0);
 
-	clear_myaddr(&old);
-
 #else /*!HAVE_GETIFADDRS*/
 	int s;
 	unsigned int maxif;
@@ -430,7 +433,7 @@
 	struct ifreq *iflist;
 	struct ifconf ifconf;
 	struct ifreq *ifr, *ifr_end;
-	struct myaddrs *p, *q, *old;
+	struct myaddrs *p, *q;
 #ifdef INET6
 #ifdef __KAME__
 	struct sockaddr_in6 *sin6;
@@ -470,7 +473,8 @@
 	}
 	close(s);
 
-	old = lcconf->myaddrs;
+	lcconf->oldaddrs = lcconf->myaddrs;
+	lcconf->myaddrs = NULL;
 
 	/* Look for this interface in the list */
 	ifr_end = (struct ifreq *) (ifconf.ifc_buf + ifconf.ifc_len);
@@ -522,14 +526,16 @@
 					addr1, sizeof(addr1),
 					NULL, 0,
 					NI_NUMERICHOST | niflags))
-			strlcpy(addr1, "(invalid)", sizeof(addr1));
+				strlcpy(addr1, "(invalid)", sizeof(addr1));
 			plog(LLV_DEBUG, LOCATION, NULL,
 				"my interface: %s (%s)\n",
 				addr1, ifr->ifr_name);
-			q = find_myaddr(old, p);
-			if (q)
+			q = find_myaddr(lcconf->oldaddrs, p);
+			if (q) {
 				p->sock = q->sock;
-			else
+				racoon_free(q->addr);
+				q->addr = NULL;
+			} else
 				p->sock = -1;
 			p->next = lcconf->myaddrs;
 			lcconf->myaddrs = p;
@@ -539,8 +545,6 @@
 		}
 	}
 
-	clear_myaddr(&old);
-
 	racoon_free(iflist);
 #endif /*HAVE_GETIFADDRS*/
 }
@@ -624,6 +628,7 @@
 #ifdef __linux__
 	char msg[BUFSIZ];
 	int len;
+	__u16 nlmsg_type;
 	struct nlmsghdr *h = (void*)msg;
 	len = read(lcconf->rtsock, msg, sizeof(msg));
 	if (len < 0)
@@ -632,8 +637,11 @@
 		return 0;
 	if (h->nlmsg_pid) /* not from kernel! */
 		return 0;
-	if (h->nlmsg_type == RTM_NEWLINK)
+
+	nlmsg_type = h->nlmsg_type;
+	if (!(nlmsg_type == RTM_NEWADDR || nlmsg_type == RTM_DELADDR))
 		return 0;
+
 	plog(LLV_DEBUG, LOCATION, NULL,
 		"netlink signals update interface address list\n");
 	return 1;
@@ -667,6 +675,9 @@
 	case RTM_DELADDR:
 	case RTM_DELETE:
 	case RTM_IFINFO:
+#ifdef RTM_IFANNOUNCE
+	case RTM_IFANNOUNCE:
+#endif
 		break;
 	case RTM_MISS:
 		/* ignore this message silently */
@@ -715,8 +726,14 @@
 	}
 #endif
 
-	for (p = lcconf->myaddrs, n = 0; p; p = p->next, n++) {
-		set_port (p->addr, p->udp_encap ? lcconf->port_isakmp_natt : lcconf->port_isakmp);
+	for (p = lcconf->myaddrs, n = 0; p; p = p->next) {
+		if (!p->addr)
+			continue;
+		n++;
+		if (p->sock > 0)
+			continue;
+		set_port (p->addr,
+		p->udp_encap ? lcconf->port_isakmp_natt : lcconf->port_isakmp);
 	}
 	plog(LLV_DEBUG, LOCATION, NULL,
 		"%d addrs are configured successfully\n", n);
Index: ipsec-tools/src/racoon/isakmp.c
===================================================================
--- ipsec-tools.orig/src/racoon/isakmp.c	2007-08-21 19:11:57.852444790 +0200
+++ ipsec-tools/src/racoon/isakmp.c	2007-08-21 19:12:01.268639468 +0200
@@ -1574,7 +1574,7 @@
 	return(0);
 
 err:
-	isakmp_close();
+	isakmp_close(&lcconf->myaddrs);
 	return(-1);
 }
 
@@ -1624,9 +1624,16 @@
 	struct myaddrs *p;
 
 	for (p = lcconf->myaddrs; p; p = p->next) {
+	        /* disabled? */
 		if (!p->addr)
 			continue;
 
+		/* already open? */
+		if (p->sock > 0) {
+		        ifnum++;
+			continue;
+		}
+
 		/* warn if wildcard address - should we forbid this? */
 		switch (p->addr->sa_family) {
 		case AF_INET:
@@ -1800,11 +1807,12 @@
 }
 
 void
-isakmp_close()
+isakmp_close(db)
+     struct myaddrs **db;
 {
 	struct myaddrs *p, *next;
 
-	for (p = lcconf->myaddrs; p; p = next) {
+	for (p = *db; p; *db = p = next) {
 		next = p->next;
 
 		if (!p->addr) {
@@ -1816,7 +1824,7 @@
 		racoon_free(p);
 	}
 
-	lcconf->myaddrs = NULL;
+	*db = NULL;
 }
 
 int
Index: ipsec-tools/src/racoon/isakmp_var.h
===================================================================
--- ipsec-tools.orig/src/racoon/isakmp_var.h	2007-08-21 19:11:57.856445018 +0200
+++ ipsec-tools/src/racoon/isakmp_var.h	2007-08-21 19:12:01.268639468 +0200
@@ -56,7 +56,7 @@
 struct ph1handle;
 struct ph2handle;
 struct remoteconf;
-struct isakmp_gen;
+struct myaddrs;
 struct ipsecdoi_pl_id;	/* XXX */
 struct isakmp_pl_ke;	/* XXX */
 struct isakmp_pl_nonce;	/* XXX */
@@ -71,7 +71,7 @@
 extern int isakmp_init __P((void));
 extern const char *isakmp_pindex __P((const isakmp_index *, const u_int32_t));
 extern int isakmp_open __P((void));
-extern void isakmp_close __P((void));
+extern void isakmp_close __P((struct myaddrs **));
 extern int isakmp_send __P((struct ph1handle *, vchar_t *));
 
 extern void isakmp_ph1resend_stub __P((void *));
Index: ipsec-tools/src/racoon/localconf.c
===================================================================
--- ipsec-tools.orig/src/racoon/localconf.c	2007-08-21 19:11:57.860445246 +0200
+++ ipsec-tools/src/racoon/localconf.c	2007-08-21 19:12:01.268639468 +0200
@@ -85,7 +85,7 @@
 	int i;
 
 	setdefault();
-	clear_myaddr(&lcconf->myaddrs);
+	clear_myaddr(&lcconf->oldaddrs);
 	for (i = 0; i < LC_PATHTYPE_MAX; i++) {
 		if (lcconf->pathinfo[i]) {
 			racoon_free(lcconf->pathinfo[i]);
Index: ipsec-tools/src/racoon/localconf.h
===================================================================
--- ipsec-tools.orig/src/racoon/localconf.h	2007-08-21 19:11:57.864445474 +0200
+++ ipsec-tools/src/racoon/localconf.h	2007-08-21 19:12:01.268639468 +0200
@@ -83,6 +83,7 @@
 
 	int autograbaddr;
 	struct myaddrs *myaddrs;
+	struct myaddrs *oldaddrs;
 
 	char *pathinfo[LC_PATHTYPE_MAX];
 	vchar_t *ident[LC_IDENTTYPE_MAX]; /* base of Identifier payload. */
Index: ipsec-tools/src/racoon/session.c
===================================================================
--- ipsec-tools.orig/src/racoon/session.c	2007-08-21 19:11:57.872445930 +0200
+++ ipsec-tools/src/racoon/session.c	2007-08-21 19:12:01.272639696 +0200
@@ -213,7 +213,7 @@
 #endif
 
 		for (p = lcconf->myaddrs; p; p = p->next) {
-			if (!p->addr)
+			if ((!p->addr) || (p->sock <= 0))
 				continue;
 			if (FD_ISSET(p->sock, &rfds))
 				isakmp_handler(p->sock);
@@ -225,8 +225,7 @@
 		if (lcconf->rtsock >= 0 && FD_ISSET(lcconf->rtsock, &rfds)) {
 			if (update_myaddrs() && lcconf->autograbaddr)
 				check_rtsock(NULL);
-			else
-				initfds();
+			initfds();
 		}
 	}
 }
@@ -250,13 +249,10 @@
 check_rtsock(unused)
 	void *unused;
 {
-	isakmp_close();
 	grab_myaddrs();
 	autoconf_myaddrsport();
+	isakmp_close(&lcconf->oldaddrs);
 	isakmp_open();
-
-	/* initialize socket list again */
-	initfds();
 }
 
 static void
@@ -301,7 +297,7 @@
 	}
 
 	for (p = lcconf->myaddrs; p; p = p->next) {
-		if (!p->addr)
+		if ((!p->addr) || (p->sock <= 0))
 			continue;
 		if (p->sock >= FD_SETSIZE) {
 			plog(LLV_ERROR, LOCATION, NULL, "fd_set overrun\n");
@@ -582,7 +578,7 @@
 static int
 close_sockets()
 {
-	isakmp_close();
+	isakmp_close(&lcconf->myaddrs);
 	pfkey_close(lcconf->sock_pfkey);
 #ifdef ENABLE_ADMINPORT
 	(void)admin_close();
Index: ipsec-tools/src/racoon/pfkey.c
===================================================================
--- ipsec-tools.orig/src/racoon/pfkey.c	2007-08-21 18:59:22.673409590 +0200
+++ ipsec-tools/src/racoon/pfkey.c	2007-08-21 19:07:21.356688195 +0200
@@ -68,6 +68,12 @@
 #include PATH_IPSEC_H
 #include <fcntl.h>
 
+#ifdef SADB_X_EXT_PACKET
+/* XXX inclusion should be done differently --arno */
+#include <netinet/ip6.h>
+#include <netinet/ip6mh.h>
+#endif
+
 #include "libpfkey.h"
 
 #include "var.h"
@@ -161,6 +167,9 @@
 };
 
 static int addnewsp __P((caddr_t *));
+#ifdef SADB_X_EXT_PACKET
+static void mip6_remap __P((struct ph2handle *, caddr_t));
+#endif
 
 /* cope with old kame headers - ugly */
 #ifndef SADB_X_AALG_MD5
@@ -848,19 +857,33 @@
 		proxy = iph2->ph1->rmconf->support_proxy;
 	} else {
 		pp = iph2->approval;
+		/* Proxy mode on responder requires a "from idtype string"
+		 * statement for the sainfo to match with ID provided in
+		 * Phase 1. It allows to have a specific Phase 2 sainfo be
+		 * selected based on id provided by peer during Phase 1.
+		 * In MIPv6 case, on the HA, this allows binding the HoA
+		 * of a MN (destination_id in sainfo statement) to its
+		 * Phase 1 credentials (e.g. from asn1dn "C=FR, ..."). */
 		if (iph2->sainfo && iph2->sainfo->id_i)
 			proxy = 1;
 	}
 
-	/* for mobile IPv6 */
-	if (proxy && iph2->src_id && iph2->dst_id &&
-	    ipsecdoi_transportmode(pp)) {
-		src = iph2->src_id;
-		dst = iph2->dst_id;
-	} else {
-		src = iph2->src;
-		dst = iph2->dst;
-	}
+        if (proxy)
+          plog(LLV_INFO, LOCATION, NULL,
+	       "PROXY: proxy mode SET in pk_sendgetspi()\n");
+        else
+          plog(LLV_INFO, LOCATION, NULL,
+	       "PROXY: proxy mode NOT SET in pk_sendgetspi()\n");
+
+        /* For mobile IPv6 */
+        if (proxy && iph2->src_id && iph2->dst_id &&
+            ipsecdoi_transportmode(pp)) {
+                src = iph2->src_id;
+                dst = iph2->dst_id;
+        } else {
+                src = iph2->src;
+                dst = iph2->dst;
+        }
 
 	for (pr = pp->head; pr != NULL; pr = pr->next) {
 
@@ -1037,7 +1060,7 @@
 	if (iph2->side == INITIATOR)
 		proxy = iph2->ph1->rmconf->support_proxy;
 	else if (iph2->sainfo && iph2->sainfo->id_i)
-		proxy = 1;
+		proxy = 1; /* See comment in pk_sendgetspi() */
 
 	/* fill in some needed for pfkey_send_update2 */
 	memset (&sa_args, 0, sizeof (sa_args));
@@ -1322,7 +1345,7 @@
 	if (iph2->side == INITIATOR)
 		proxy = iph2->ph1->rmconf->support_proxy;
 	else if (iph2->sainfo && iph2->sainfo->id_i)
-		proxy = 1;
+		proxy = 1; /* see comment in pk_sendgetspi() */
 
 	/* fill in some needed for pfkey_send_update2 */
 	memset (&sa_args, 0, sizeof (sa_args));
@@ -1722,12 +1745,41 @@
 			}
 		}
 
+#ifdef SADB_X_EXT_PACKET
+		if (!do_listen) {
+			/* Last chance : SADB_X_EXT_PACKET in ACQUIRE to direct
+                         * us to use another address AND proxy mode activated
+			 * for remote peer. _explicit_ debug message -- arno */
+			if (mhp[SADB_X_EXT_PACKET] != NULL) {
+			        struct sockaddr *dst = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_DST]);
+			        struct remoteconf * rmconf = getrmconf(dst);
+
+				if ((rmconf == NULL) ||
+				    (!rmconf->support_proxy)) {
+				        plog(LLV_DEBUG, LOCATION, NULL,
+					     "SADB_X_EXT_PACKET : not listening on source address %s,\n"
+					     "SADB_X_EXT_PACKET extension found in ACQUIRE but proxy \n"
+					     "mode not activated (or n/a) for remote peer %s. Ignoring ...",
+					     saddrwop2str(sa),
+					     saddrwop2str(dst));
+					return 0;
+				}
+			} else {
+			        plog(LLV_DEBUG, LOCATION, NULL,
+				     "SADB_X_EXT_PACKET: ignoring ACQUIRE because not listening on source\n"
+				     " address %s and no SADB_X_EXT_PACKET extension found.\n",
+				     saddrwop2str(sa));
+				return 0;
+			}
+		}
+#else /* !SADB_X_EXT_PACKET */
 		if (!do_listen) {
 			plog(LLV_DEBUG, LOCATION, NULL,
 				"ignore because do not listen on source address : %s.\n",
 				saddrwop2str(sa));
 			return 0;
 		}
+#endif
 	}
 
 	/*
@@ -1882,6 +1934,16 @@
 		delph2(iph2[n]);
 		return -1;
 	}
+
+#ifdef SADB_X_EXT_PACKET
+	/* possible remap for mobile IPv6 */
+	plog(LLV_INFO, LOCATION, NULL, "SADB_X_EXT_PACKET: test presence in ACQUIRE\n");
+	if (mhp[SADB_X_EXT_PACKET] != NULL) {
+		plog(LLV_INFO, LOCATION, NULL, "SADB_X_EXT_PACKET: found presence in ACQUIRE. Remapping ...\n");
+		mip6_remap(iph2[n], mhp[SADB_X_EXT_PACKET]);
+	}
+#endif /* SADB_X_EXT_PACKET */
+
 #ifdef HAVE_SECCTX
 	if (m_sec_ctx) {
 		set_secctx_in_proposal(iph2[n], spidx);
@@ -2008,6 +2070,7 @@
 	struct ph2handle *iph2;
 {
 	struct policyindex *spidx = (struct policyindex *)iph2->spidx_gen;
+	struct sockaddr *src = NULL, *dst = NULL;
 	struct sadb_x_policy *xpl;
 	struct sadb_x_ipsecrequest *xisr;
 	struct saproto *pr;
@@ -2016,12 +2079,31 @@
 	caddr_t policy, p;
 	int policylen;
 	int xisrlen;
+	int proxy = 0;
 	u_int satype, mode;
 	int len = 0;
 #ifdef HAVE_SECCTX
 	int ctxlen = 0;
 #endif /* HAVE_SECCTX */
 
+	/* for proxy case */
+	if (type != SADB_X_SPDDELETE) {
+	        if (iph2->side == INITIATOR)
+	                proxy = iph2->ph1->rmconf->support_proxy;
+	        else if (iph2->sainfo && iph2->sainfo->id_i)
+	                proxy = 1; /* see comment in pk_sendgetspi() */
+
+	        if (proxy && iph2->src_id && iph2->dst_id &&
+	            ipsecdoi_transportmode(iph2->approval)) {
+		        plog(LLV_INFO, LOCATION, NULL, "PROXY: using src_id and dst_id as src and dst.\n");
+	                src = iph2->src_id;
+	                dst = iph2->dst_id;
+	        } else {
+		        plog(LLV_INFO, LOCATION, NULL, "PROXY: NOT using src_id and dst_id as src and dst.\n");
+	                src = iph2->src;
+	                dst = iph2->dst;
+	        }
+	}
 
 	/* get policy buffer size */
 	policylen = sizeof(struct sadb_x_policy);
@@ -2029,8 +2111,8 @@
 		for (pr = iph2->approval->head; pr; pr = pr->next) {
 			xisrlen = sizeof(*xisr);
 			if (pr->encmode == IPSECDOI_ATTR_ENC_MODE_TUNNEL) {
-				xisrlen += (sysdep_sa_len(iph2->src)
-				          + sysdep_sa_len(iph2->dst));
+				xisrlen += (sysdep_sa_len(src)
+				          + sysdep_sa_len(dst));
 			}
 
 			policylen += PFKEY_ALIGN8(xisrlen);
@@ -2135,14 +2217,14 @@
 		if (pr->encmode == IPSECDOI_ATTR_ENC_MODE_TUNNEL) {
 			int src_len, dst_len;
 
-			src_len = sysdep_sa_len(iph2->src);
-			dst_len = sysdep_sa_len(iph2->dst);
+			src_len = sysdep_sa_len(src);
+			dst_len = sysdep_sa_len(dst);
 			xisrlen += src_len + dst_len;
 
-			memcpy(p, iph2->src, src_len);
+			memcpy(p, src, src_len);
 			p += src_len;
 
-			memcpy(p, iph2->dst, dst_len);
+			memcpy(p, dst, dst_len);
 			p += dst_len;
 		}
 
@@ -3145,3 +3227,237 @@
 
 	return buf;
 }
+
+
+#ifdef SADB_X_EXT_PACKET
+
+/* Negotiation of transport mode SA for protection of MIPv6 Home Regsitration
+ * Binding Update packet from a MN to a HA requires the use of the CoA as
+ * source of IKE traffic where the negotiated SA uses the HoA. For that to
+ * happen, a hint is provided by the inclusion in the ACQUIRE of an
+ * SADB_X_EXT_PACKET extension. This extension will contain a citation of the
+ * packet that has triggered the ACQUIRE. If this packet is a HRBU, it provides
+ * the required information to select the right source address, i.e. allow us
+ * to remap the source address to the CoA. This function is called in
+ * pk_recvacquire(). It is provided a pointer to Phase 2 handle and an
+ * SABD_X_EXT_PACKET extension. If a HRBU is found, content is used for
+ * remapping.
+ *
+ * See draft-sugimoto-mip6-pfkey-migrate-03 for details.
+ */
+
+static void
+mip6_remap(iph2, p)
+	struct ph2handle *iph2;
+	caddr_t p;
+{
+#ifdef INET6
+	struct sadb_x_packet *pkt = (struct sadb_x_packet *)p;
+	struct ip6_hdr *ip = (struct ip6_hdr *)(pkt + 1);
+	struct ip6_ext *ep = (struct ip6_ext *)(ip + 1);
+	struct ip6_mh *mh = NULL;
+	struct ip6_mh_binding_update *hrbu = NULL;
+	struct remoteconf *rmconf;
+	struct sockaddr_in6 *src6;
+	struct ip6_mh_opt * mhopt;
+	struct in6_addr *altcoa = NULL;
+	char *a;
+	int len, nxt, l;
+
+	if (!ipsecdoi_transportmode(iph2->proposal)) {
+	        plog(LLV_INFO, LOCATION, NULL,
+		     "SADB_X_EXT_PACKET: found transport mode "
+		     "proposal in mip6_remap().\n");
+		return;
+        }
+
+	plog(LLV_INFO, LOCATION, NULL,
+	     "SADB_X_EXT_PACKET: Using %s as destination to look "
+	     "for remote configuration elements.\n",
+	     saddrwop2str(iph2->dst));
+
+	rmconf = getrmconf(iph2->dst);
+	if (rmconf == NULL) {
+	        plog(LLV_INFO, LOCATION, NULL,
+		     "SADB_X_EXT_PACKET: unable to find remote conf "
+		     "for destination %s. Exiting mip6_remap().\n",
+		     saddrwop2str(iph2->dst));
+		return;
+        }
+
+	plog(LLV_INFO, LOCATION, NULL,
+	     "SADB_X_EXT_PACKET: Remote configuration found for "
+	     "destination %s.\n", saddrwop2str(iph2->dst));
+
+	if (!rmconf->support_proxy) {
+	        plog(LLV_INFO, LOCATION, NULL,
+		     "SADB_X_EXT_PACKET: proxy mode not activated "
+		     "for remote peer (%s). Exiting mip6_remap().\n",
+		     saddrwop2str(iph2->dst));
+		return;
+        }
+
+	plog(LLV_INFO, LOCATION, NULL,
+	     "SADB_X_EXT_PACKET: Great: remote configuration "
+	     "has support_proxy activated.\n");
+
+        /* sadb_x_packet_len is SADB_X_EXT_PACKET ext length in units
+	 * of 8 octets.
+	 * sadb_x_packet_copylen is the length in bytes of triggering
+	 * packet available as a citation */
+        if ((!pkt->sadb_x_packet_len)  ||
+	    (pkt->sadb_x_packet_copylen > (8 * pkt->sadb_x_packet_len -
+					   sizeof(struct sadb_x_packet)))) {
+	        plog(LLV_INFO, LOCATION, NULL,
+		     "SADB_X_EXT_PACKET: weird sadb_x_packet_len and "
+		     "sadb_x_packet_copylen. Exiting mip6_remap().\n");
+		return;
+        }
+
+#define HRBU_MIN_LEN	(40 + 12 + 2 + 18)
+        if (pkt->sadb_x_packet_copylen < HRBU_MIN_LEN) {
+	        plog(LLV_INFO, LOCATION, NULL, "SADB_X_EXT_PACKET: passed "
+		     "BU is too short. Exiting mip6_remap().\n");
+		return;
+	}
+
+        if ((ip->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) {
+	        plog(LLV_INFO, LOCATION, NULL, "SADB_X_EXT_PACKET: passed "
+		     "BU is not an IPv6 packet. Exiting mip6_remap().\n");
+		return;
+	}
+
+	/* Decode the triggering packet, chasing for AltCoA option in
+	 * Home Registration Binding Update */
+
+	len = ntohs(ip->ip6_plen) + sizeof(*ip);
+	if (len > pkt->sadb_x_packet_copylen) /* truncated packet */
+		len = pkt->sadb_x_packet_copylen;
+	len -= sizeof(*ip);
+	nxt = ip->ip6_nxt;
+	while (len > sizeof(*ep))
+		switch (nxt) {
+		case IPPROTO_HOPOPTS:
+		case IPPROTO_ROUTING:
+		case IPPROTO_FRAGMENT:
+			l = (ep->ip6e_len + 1) << 3;
+		skip:
+			nxt = ep->ip6e_nxt;
+			len -= l;
+			ep = (struct ip6_ext *)((caddr_t)ep + l);
+			break;
+
+		case IPPROTO_AH:
+			l = (ep->ip6e_len + 2) << 2;
+			goto skip;
+
+		case IPPROTO_DSTOPTS:
+			l = (ep->ip6e_len + 1) << 3;
+			goto skip;
+
+		case IPPROTO_MH:
+			l = (ep->ip6e_len + 1) << 3;
+			hrbu = (struct ip6_mh_binding_update *)ep;
+			mh = &hrbu->ip6mhbu_hdr;
+			if (l > len || l < sizeof(*hrbu))
+				return;
+			len = l > len ? len : l;
+
+#ifndef IP6_MH_BU_HOME
+#define IP6_MH_BU_HOME IP6MU_HOME
+#endif
+			if (mh->ip6mh_type != IP6_MH_TYPE_BU) {
+			        plog(LLV_ERROR, LOCATION, NULL,
+				     "SADB_X_EXT_PACKET: Expected BU in msg. "
+				     "Found MH type %d. Exiting mip6_remap()\n",
+				     mh->ip6mh_type);
+				return;
+			}
+
+			if ((hrbu->ip6mhbu_flags & IP6_MH_BU_HOME) == 0) {
+			        plog(LLV_ERROR, LOCATION, NULL,
+				     "SADB_X_EXT_PACKET: Found BU with Home "
+				     "Registration bit unset. "
+				     "Exiting mip6_remap().\n");
+				return;
+			}
+
+			/* We found our Home Registration Binding Update. Let's
+			 * now search for the AltCoA option in its options */
+			len -= sizeof(struct ip6_mh_binding_update);
+			mhopt = (struct ip6_mh_opt *)((caddr_t)ep +
+						      sizeof(*hrbu));
+
+			while ((len >= sizeof(struct ip6_mh_opt_altcoa)) &&
+			       (mhopt->ip6mhopt_type != IP6_MHOPT_ALTCOA)) {
+				l = mhopt->ip6mhopt_len + 2;
+				len -= l;
+				mhopt = (struct ip6_mh_opt *)((caddr_t)mhopt+l);
+			}
+
+			if ((len < sizeof(struct ip6_mh_opt_altcoa)) ||
+			    (mhopt->ip6mhopt_len != sizeof(struct in6_addr))) {
+				plog(LLV_ERROR, LOCATION, NULL,
+				     "SADB_X_EXT_PACKET: invalid "
+				     "AltCoA Option (bad length)\n");
+				return;
+			}
+
+			altcoa = &(((struct ip6_mh_opt_altcoa *)mhopt)->ip6moa_addr);
+
+			/* force exit */
+			len = 0;
+			break;
+
+		case IPPROTO_ESP:
+		case IPPROTO_IPCOMP:
+		case IPPROTO_NONE:
+		default:
+			return;
+		}
+
+	if (altcoa == NULL)
+		return;
+
+	/* Sanity checks */
+        if (iph2->src_id)
+	        plog(LLV_INFO, LOCATION, NULL,
+		     "SADB_X_EXT_PACKET: found already "
+		     "defined src_id in ph2. Should not happen.\n");
+
+        if (iph2->dst_id)
+	        plog(LLV_INFO, LOCATION, NULL,
+		     "SADB_X_EXT_PACKET: found already "
+		     "defined dst_id in ph2. Should not happen.\n");
+
+	iph2->src_id = dupsaddr(iph2->src);
+	iph2->dst_id = dupsaddr(iph2->dst);
+	src6 = (struct sockaddr_in6 *)iph2->src;
+	memcpy(&src6->sin6_addr, altcoa, sizeof(struct in6_addr));
+
+	plog(LLV_INFO, LOCATION, NULL,
+	     "SADB_X_EXT_PACKET: Filled phase2 src_id and dst_id:\n");
+
+	a = strdup(saddrwop2str(iph2->src_id));
+	plog(LLV_INFO, LOCATION, NULL,
+	     "SADB_X_EXT_PACKET:    iph2->src_id: %s\n", a);
+	racoon_free(a);
+
+	a = strdup(saddrwop2str(iph2->dst_id));
+	plog(LLV_INFO, LOCATION, NULL,
+	     "SADB_X_EXT_PACKET:    iph2->dst_id: %s\n", a);
+	racoon_free(a);
+
+	a = strdup(saddrwop2str(iph2->src_id));
+	plog(LLV_INFO, LOCATION, NULL,
+	     "SADB_X_EXT_PACKET:   old iph2->src: %s\n", a);
+	racoon_free(a);
+
+	a = strdup(saddrwop2str((struct sockaddr *)src6));
+	plog(LLV_INFO, LOCATION, NULL,
+	     "SADB_X_EXT_PACKET:     remapped to: %s\n", a);
+	racoon_free(a);
+
+#endif /* INET6 */
+}
+#endif /* SADB_X_EXT_PACKET */
Index: ipsec-tools/src/racoon/pfkey.c
===================================================================
--- ipsec-tools.orig/src/racoon/pfkey.c	2007-08-22 10:06:10.419490693 +0200
+++ ipsec-tools/src/racoon/pfkey.c	2007-08-23 19:13:24.860492843 +0200
@@ -133,6 +133,9 @@
 static int pk_recvspdget __P((caddr_t *));
 static int pk_recvspddump __P((caddr_t *));
 static int pk_recvspdflush __P((caddr_t *));
+#ifdef SADB_X_MIGRATE
+static int pk_recvmigrate __P((caddr_t *));
+#endif
 static struct sadb_msg *pk_recv __P((int, int *));
 
 static int (*pkrecvf[]) __P((caddr_t *)) = {
@@ -160,13 +163,21 @@
 pk_recvspdexpire,
 NULL,	/* SADB_X_SPDDELETE2 */
 NULL,	/* SADB_X_NAT_T_NEW_MAPPING */
+#ifdef SADB_X_MIGRATE
+pk_recvmigrate,
+#else
 NULL,	/* SADB_X_MIGRATE */
+#endif
 #if (SADB_MAX > 24)
 #error "SADB extra message?"
 #endif
 };
 
 static int addnewsp __P((caddr_t *));
+#ifdef SADB_X_MIGRATE
+static int  isakmp_ph1migrate __P((struct secasindex *, struct secasindex *));
+static void isakmp_ph2migrate __P((struct ph1handle *, struct ph2handle *));
+#endif
 #ifdef SADB_X_EXT_PACKET
 static void mip6_remap __P((struct ph2handle *, caddr_t));
 #endif
@@ -952,7 +963,7 @@
 	struct sadb_msg *msg;
 	struct sadb_sa *sa;
 	struct ph2handle *iph2;
-	struct sockaddr *dst;
+	struct sockaddr *src, *dst;
 	int proto_id;
 	int allspiok, notfound;
 	struct saprop *pp;
@@ -960,7 +971,8 @@
 
 	/* validity check */
 	if (mhp[SADB_EXT_SA] == NULL
-	 || mhp[SADB_EXT_ADDRESS_DST] == NULL) {
+	 || mhp[SADB_EXT_ADDRESS_DST] == NULL
+	 || mhp[SADB_EXT_ADDRESS_SRC] == NULL) {
 		plog(LLV_ERROR, LOCATION, NULL,
 			"inappropriate sadb getspi message passed.\n");
 		return -1;
@@ -968,6 +980,7 @@
 	msg = (struct sadb_msg *)mhp[0];
 	sa = (struct sadb_sa *)mhp[SADB_EXT_SA];
 	dst = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_SRC]); /* note SA dir */
+	src = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_DST]);
 
 	/* the message has to be processed or not ? */
 	if (msg->sadb_msg_pid != getpid()) {
@@ -1007,7 +1020,7 @@
 			notfound = 0;
 			plog(LLV_DEBUG, LOCATION, NULL,
 				"pfkey GETSPI succeeded: %s\n",
-				sadbsecas2str(iph2->dst, iph2->src,
+				sadbsecas2str(dst, src,
 				    msg->sadb_msg_satype,
 				    sa->sadb_sa_spi,
 				    ipsecdoi2pfkey_mode(pr->encmode)));
@@ -1019,7 +1032,7 @@
 	if (notfound) {
 		plog(LLV_ERROR, LOCATION, NULL,
 			"get spi for unknown address %s\n",
-			saddrwop2str(iph2->dst));
+			saddrwop2str(dst));
 		return -1;
 	}
 
@@ -1265,14 +1278,14 @@
 			pr->ok = 1;
 			plog(LLV_DEBUG, LOCATION, NULL,
 				"pfkey UPDATE succeeded: %s\n",
-				sadbsecas2str(iph2->dst, iph2->src,
+				sadbsecas2str(dst, src,
 				    msg->sadb_msg_satype,
 				    sa->sadb_sa_spi,
 				    sa_mode));
 
 			plog(LLV_INFO, LOCATION, NULL,
 				"IPsec-SA established: %s\n",
-				sadbsecas2str(iph2->dst, iph2->src,
+				sadbsecas2str(dst, src,
 					msg->sadb_msg_satype, sa->sadb_sa_spi,
 					sa_mode));
 		}
@@ -1311,12 +1324,6 @@
 	set_port(iph2->dst, extract_port(iph2->ph1->remote));
 #endif
 
-	/*
-	 * since we are going to reuse the phase2 handler, we need to
-	 * remain it and refresh all the references between ph1 and ph2 to use.
-	 */
-	unbindph12(iph2);
-
 	iph2->sce = sched_new(iph2->approval->lifetime,
 	    isakmp_ph2expire_stub, iph2);
 
@@ -1531,7 +1538,7 @@
 
 	plog(LLV_INFO, LOCATION, NULL,
 		"IPsec-SA established: %s\n",
-		sadbsecas2str(iph2->src, iph2->dst,
+		sadbsecas2str(src, dst,
 			msg->sadb_msg_satype, sa->sadb_sa_spi, sa_mode));
 
 	plog(LLV_DEBUG, LOCATION, NULL, "===\n");
@@ -1617,8 +1624,30 @@
 	/* INITIATOR, begin phase 2 exchange. */
 	/* allocate buffer for status management of pfkey message */
 	if (iph2->side == INITIATOR) {
+		int clear_id = 1;
+
+		/* If our id and id_p payloads have already been defined
+		 * for initial negotiation, we prevent them to be cleared.
+		 * This is required in at least two cases:
+		 * - rekeying for a transport mode SA negotiated with proxy
+		 *   mode/SADB_X_EXT_PACKET extension as we do not have the
+		 *   hint anymore for correctly setting the ID with the
+		 *   right addresses. This should be MIPv6 specific.
+		 * - rekeying for a SA for which SP has been removed. As
+		 *   ipsecdoi_setid2() will be called if those id are unset
+		 *   a SA for which associated SP has been removed will
+		 *   not be rekeyed. For MIPv6 tunnel SA on the Home Network,
+		 *   it will end up not been rekyed as the policy is removed
+		 *   to avoid traffic been encrypted. This creates an
+		 *   additionnal delay when moving again to a new foreign
+		 *   network.
+		 *                                                --arno
+		 */
+		if (iph2->id != NULL && iph2->id_p != NULL)
+			clear_id = 0;
+
+		initph2(iph2, clear_id);
 
-		initph2(iph2);
 
 		/* update status for re-use */
 		iph2->status = PHASE2ST_STATUS2;
@@ -2029,7 +2058,7 @@
 
 	plog(LLV_ERROR, LOCATION, NULL,
 		"pfkey DELETE received: %s\n",
-		sadbsecas2str(iph2->src, iph2->dst,
+		sadbsecas2str(src, dst,
 			msg->sadb_msg_satype, sa->sadb_sa_spi, IPSEC_MODE_ANY));
 
 	/* send delete information */
@@ -2794,6 +2823,112 @@
 	return 0;
 }
 
+
+#ifdef SADB_X_MIGRATE
+static int
+pk_recvmigrate(mhp)
+	caddr_t *mhp;
+{
+	struct sadb_address *saddr, *daddr;
+	struct sadb_x_policy *xpl;
+ 	struct sadb_lifetime *lt;
+	struct policyindex spidx;
+	struct secpolicy *sp;
+	struct ipsecrequest *xisr;
+	struct secasindex *oldsaidx;
+ 	u_int64_t created;
+
+	/* sanity check */
+	if (mhp[0] == NULL
+	 || mhp[SADB_EXT_ADDRESS_SRC] == NULL
+	 || mhp[SADB_EXT_ADDRESS_DST] == NULL
+	 || mhp[SADB_X_EXT_POLICY] == NULL) {
+		plog(LLV_ERROR, LOCATION, NULL,
+			"SADB_X_MIGRATE: invalid MIGRATE message received.\n");
+		return -1;
+	}
+	saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_SRC];
+	daddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_DST];
+	xpl = (struct sadb_x_policy *)mhp[SADB_X_EXT_POLICY];
+	lt = (struct sadb_lifetime*)mhp[SADB_EXT_LIFETIME_HARD];
+	if (lt != NULL)
+		created = lt->sadb_lifetime_addtime;
+	else
+		created = 0;
+
+	/* Add some logging to help debbugging */
+	if (xpl->sadb_x_policy_dir == IPSEC_DIR_OUTBOUND)
+			plog(LLV_WARNING, LOCATION, NULL,
+				"SADB_X_MIGRATE: Outbound SA being migrated.\n");
+	else
+			plog(LLV_WARNING, LOCATION, NULL,
+				"SADB_X_MIGRATE: Inbound SA being migrated.\n");
+
+#ifdef HAVE_PFKEY_POLICY_PRIORITY
+	KEY_SETSECSPIDX(xpl->sadb_x_policy_dir,
+			saddr + 1,
+			daddr + 1,
+			saddr->sadb_address_prefixlen,
+			daddr->sadb_address_prefixlen,
+			saddr->sadb_address_proto,
+			xpl->sadb_x_policy_priority,
+			created,
+			&spidx);
+#else
+	KEY_SETSECSPIDX(xpl->sadb_x_policy_dir,
+			saddr + 1,
+			daddr + 1,
+			saddr->sadb_address_prefixlen,
+			daddr->sadb_address_prefixlen,
+			saddr->sadb_address_proto,
+			created,
+			&spidx);
+#endif
+
+	sp = getsp(&spidx);
+	if (sp == NULL) {
+		plog(LLV_ERROR, LOCATION, NULL,
+			"SADB_X_MIGRATE: passed policy does not already exist: %s\n",
+			spidx2str(&spidx));
+	} else {
+		remsp(sp);
+		delsp(sp);
+	}
+
+	/* New SP is created based on the content of MIGRATE message.
+	 * All required elements are available. The only trick is that
+	 * it contains 2 ISR describing old and new tunnel parameters.
+	 * Order is kept in created SP.
+	 */
+	if (addnewsp(mhp) < 0)
+		return -1;
+
+	/* zap first ISR, which contains old tunnel parameters */
+	sp = getsp(&spidx);
+	if (sp == NULL)
+		return -1;
+	xisr = sp->req;
+	if ((xisr == NULL) || (xisr->next == NULL))
+		return -1;
+	sp->req = xisr->next;
+	if (xpl->sadb_x_policy_dir != IPSEC_DIR_OUTBOUND)
+		oldsaidx = NULL;
+	else {
+		oldsaidx = racoon_malloc(sizeof(*oldsaidx));
+		if (oldsaidx == NULL)
+			plog(LLV_ERROR, LOCATION, NULL,
+				"SADB_X_MIGRATE: old saidx copy allocation failed.\n");
+		else
+			*oldsaidx = xisr->saidx;
+	}
+
+	racoon_free(xisr); /* Free old tunnel ISR */
+	if (oldsaidx)
+		return isakmp_ph1migrate(oldsaidx, &sp->req->saidx);
+	return 0;
+}
+#endif
+
 /*
  * send error against acquire message to kenrel.
  */
@@ -3461,3 +3596,144 @@
 #endif /* INET6 */
 }
 #endif /* SADB_X_EXT_PACKET */
+
+
+#ifdef SADB_X_MIGRATE
+
+/* Migration of phase 1 handle following reception of PF_KEY MIGRATE message.
+ * It is our responsability to racoon_free oldx when leaving. */
+
+static int
+isakmp_ph1migrate(oldx, newx)
+	struct secasindex *oldx, *newx;
+{
+	struct ph1handle *iph1;
+	struct ph2handle *iph2, *next;
+	struct sockaddr *local, *remote;
+	char *a, *b;
+
+	if (oldx == NULL)
+		return 0;
+	if (newx == NULL) {
+	        plog(LLV_INFO, LOCATION, NULL, "SADB_X_MIGRATE: found NULL value for new SA index. Exiting isakmp_ph1migrate().\n");
+		racoon_free(oldx);
+		return -1;
+	}
+
+	local = (struct sockaddr *)&oldx->src;
+	remote = (struct sockaddr *)&oldx->dst;
+
+	a = strdup(saddr2str(local));
+	plog(LLV_INFO, LOCATION, NULL, "SADB_X_MIGRATE: old sa idx src: %s\n", a);
+	racoon_free(a);
+	a = strdup(saddr2str((struct sockaddr *)&newx->src));
+	plog(LLV_INFO, LOCATION, NULL, "SADB_X_MIGRATE: new sa idx src: %s\n", a);
+	racoon_free(a);
+	a = strdup(saddr2str(remote));
+	plog(LLV_INFO, LOCATION, NULL, "SADB_X_MIGRATE: old sa idx dst: %s\n", a);
+	racoon_free(a);
+	a = strdup(saddr2str((struct sockaddr *)&newx->dst));
+	plog(LLV_INFO, LOCATION, NULL, "SADB_X_MIGRATE: new sa idx src: %s\n", a);
+	racoon_free(a);
+
+	if ((memcmp(local, &newx->src, sysdep_sa_len(local)) == 0) &&
+	    (memcmp(remote, &newx->dst, sysdep_sa_len(remote)) == 0)) {
+	        plog(LLV_INFO, LOCATION, NULL, "SADB_X_MIGRATE: Found identical src/dst in old and new SA index. Exiting\n");
+		racoon_free(oldx);
+		return 0;
+	}
+
+	iph1 = getph1byaddr(local, remote);
+	if (iph1 == NULL) {
+	        a = strdup(saddr2str(local));
+	        b = strdup(saddr2str(remote));
+   	        plog(LLV_INFO, LOCATION, NULL, "SADB_X_MIGRATE: no phase 1 found for src %s and dst %s. Exiting.\n", a, b);
+	        racoon_free(a);
+	        racoon_free(b);
+
+		racoon_free(oldx);
+		return 0;
+	}
+
+	plog(LLV_INFO, LOCATION, NULL,
+		"SADB_X_MIGRATE: Phase 1 found (%p). Migrating it.\n", iph1);
+
+	local = (struct sockaddr *)&newx->src;
+	remote = (struct sockaddr *)&newx->dst;
+
+	switch (iph1->remote->sa_family) {
+	case AF_INET:
+		((struct sockaddr_in *)iph1->local)->sin_addr =
+			((struct sockaddr_in *)local)->sin_addr;
+		((struct sockaddr_in *)iph1->remote)->sin_addr =
+			((struct sockaddr_in *)remote)->sin_addr;
+		break;
+#ifdef INET6
+        case AF_INET6:
+		memcpy(&((struct sockaddr_in6 *)iph1->local)->sin6_addr,
+			&((struct sockaddr_in6 *)local)->sin6_addr,
+			sizeof(struct in6_addr));
+		memcpy(&((struct sockaddr_in6 *)iph1->remote)->sin6_addr,
+			&((struct sockaddr_in6 *)remote)->sin6_addr,
+			sizeof(struct in6_addr));
+		break;
+#endif
+	default:
+		racoon_free(oldx);
+		return -1;
+	}
+
+	racoon_free(oldx);
+
+	plog(LLV_INFO, LOCATION, NULL,
+	     "SADB_X_MIGRATE: Now starting migration of Phase 2 tree elements.\n");
+
+	/* Let's now remap addresses in associated Phase 2 SA */
+	LIST_FOREACH(iph2, &iph1->ph2tree, chain)
+		isakmp_ph2migrate(iph1, iph2);
+
+	plog(LLV_INFO, LOCATION, NULL,
+	     "SADB_X_MIGRATE: Migration of Phase 2 tree elements is over.\n");
+	return 0;
+}
+
+/* Update src and dst parameters of Phase 2 handle associated with Phase 1,
+ * following reception of a MIGRATE message. Note that we _need_ to update
+ * both the transport and tunnel mode SA information, for following reasons:
+ *
+ * - tunnel mode: as the tunnel endpoint has changed, so that we need to
+ *                update iph2->src and iph2->dst.
+ * - transport mode: we need to update iph2->src and iph2->dst as they are
+ *                   used in racoon as the local and remote addresses for the
+ *                   IKE negotiation. When proxy mode enters the game, this
+ *                   makes those addresses different from the one in the SA.
+ *                   The one in the SA are those stored in iph2->src_id and
+ *                   iph2->dst_id.
+ *
+ * Note that the update is obviously the same on responder and initiator.
+ */
+static void
+isakmp_ph2migrate(struct ph1handle *iph1, struct ph2handle *iph2)
+{
+	switch (iph1->remote->sa_family) {
+	case AF_INET:
+		((struct sockaddr_in *)iph2->src)->sin_addr =
+			((struct sockaddr_in *)iph1->local)->sin_addr;
+		((struct sockaddr_in *)iph2->dst)->sin_addr =
+			((struct sockaddr_in *)iph1->remote)->sin_addr;
+		break;
+#ifdef INET6
+        case AF_INET6:
+		memcpy(&((struct sockaddr_in6 *)iph2->src)->sin6_addr,
+			&((struct sockaddr_in6 *)iph1->local)->sin6_addr,
+			sizeof(struct in6_addr));
+		memcpy(&((struct sockaddr_in6 *)iph2->dst)->sin6_addr,
+			&((struct sockaddr_in6 *)iph1->remote)->sin6_addr,
+			sizeof(struct in6_addr));
+		break;
+#endif
+	}
+
+	plog(LLV_INFO, LOCATION, NULL, "SADB_X_MIGRATE: Phase 2 SA (%p) migrated.\n", iph2);
+}
+#endif
Index: ipsec-tools/src/racoon/isakmp.c
===================================================================
--- ipsec-tools.orig/src/racoon/isakmp.c	2007-08-22 10:06:10.387488869 +0200
+++ ipsec-tools/src/racoon/isakmp.c	2007-08-22 10:06:10.435491605 +0200
@@ -1289,8 +1289,8 @@
 #ifdef ENABLE_STATS
 	gettimeofday(&iph2->start, NULL);
 #endif
-	/* found isakmp-sa */
-	bindph12(iph1, iph2);
+	if (iph2->status != PHASE2ST_EXPIRED) /* Phase 1 is already bound (ongoing rekeying) */
+		bindph12(iph1, iph2);
 	iph2->status = PHASE2ST_STATUS2;
 
 	if ((ph2exchange[etypesw2(ISAKMP_ETYPE_QUICK)]
@@ -2215,24 +2215,29 @@
 		return 0;
 	}
 
-	/* 
-	 * Search isakmp status table by address and port 
-	 * If NAT-T is in use, consider null ports as a 
-	 * wildcard and use IKE ports instead.
-	 */
+	if (iph2->ph1 != NULL) {
+		/* We are rekeying Phase 2, no need to look for Phase 1
+		 * we can reuse our previous one */
+		iph1 = iph2->ph1;
+	} else {
+		/*
+		 * Search isakmp status table by address and port
+		 * If NAT-T is in use, consider null ports as a
+		 * wildcard and use IKE ports instead.
+		 */
 #ifdef ENABLE_NATT
-	if (!extract_port(iph2->src) && !extract_port(iph2->dst)) {
-		if ((iph1 = getph1byaddrwop(iph2->src, iph2->dst)) != NULL) {
-			set_port(iph2->src, extract_port(iph1->local));
-			set_port(iph2->dst, extract_port(iph1->remote));
+		if (!extract_port(iph2->src) && !extract_port(iph2->dst)) {
+			if ((iph1 = getph1byaddrwop(iph2->src, iph2->dst)) != NULL) {
+				set_port(iph2->src, extract_port(iph1->local));
+				set_port(iph2->dst, extract_port(iph1->remote));
+			}
+		} else {
+			iph1 = getph1byaddr(iph2->src, iph2->dst);
 		}
-	} else {
-		iph1 = getph1byaddr(iph2->src, iph2->dst);
-	}
 #else
-	iph1 = getph1byaddr(iph2->src, iph2->dst);
+		iph1 = getph1byaddr(iph2->src, iph2->dst);
 #endif
-
+	}
 	/* no ISAKMP-SA found. */
 	if (iph1 == NULL) {
 		struct sched *sc;
@@ -2349,26 +2354,33 @@
 		return;
 	}
 
-	/* 
-	 * Search isakmp status table by address and port 
-	 * If NAT-T is in use, consider null ports as a 
-	 * wildcard and use IKE ports instead.
-	 */
+
+	if (iph2->ph1 != NULL) {
+		/* We are rekeying Phase 2, no need to look for Phase 1
+		 * we can reuse our previous one */
+		iph1 = iph2->ph1;
+	} else {
+		/*
+		 * Search isakmp status table by address and port
+		 * If NAT-T is in use, consider null ports as a
+		 * wildcard and use IKE ports instead.
+		 */
 #ifdef ENABLE_NATT
-	if (!extract_port(iph2->src) && !extract_port(iph2->dst)) {
-		plog(LLV_DEBUG2, LOCATION, NULL, "CHKPH1THERE: extract_port.\n");
-		if( (iph1 = getph1byaddrwop(iph2->src, iph2->dst)) != NULL){
-			plog(LLV_DEBUG2, LOCATION, NULL, "CHKPH1THERE: found a ph1 wop.\n");
+		if (!extract_port(iph2->src) && !extract_port(iph2->dst)) {
+			plog(LLV_DEBUG2, LOCATION, NULL, "CHKPH1THERE: extract_port.\n");
+			if( (iph1 = getph1byaddrwop(iph2->src, iph2->dst)) != NULL){
+				plog(LLV_DEBUG2, LOCATION, NULL, "CHKPH1THERE: found a ph1 wop.\n");
+			}
+		} else {
+			plog(LLV_DEBUG2, LOCATION, NULL, "CHKPH1THERE: searching byaddr.\n");
+			iph1 = getph1byaddr(iph2->src, iph2->dst);
+			if(iph1 != NULL)
+				plog(LLV_DEBUG2, LOCATION, NULL, "CHKPH1THERE: found byaddr.\n");
 		}
-	} else {
-		plog(LLV_DEBUG2, LOCATION, NULL, "CHKPH1THERE: searching byaddr.\n");
-		iph1 = getph1byaddr(iph2->src, iph2->dst);
-		if(iph1 != NULL)
-			plog(LLV_DEBUG2, LOCATION, NULL, "CHKPH1THERE: found byaddr.\n");
-	}
 #else
-	iph1 = getph1byaddr(iph2->src, iph2->dst);
+		iph1 = getph1byaddr(iph2->src, iph2->dst);
 #endif
+	}
 
 	/* XXX Even if ph1 as responder is there, should we not start
 	 * phase 2 negotiation ? */
Index: ipsec-tools/src/racoon/isakmp_inf.c
===================================================================
--- ipsec-tools.orig/src/racoon/isakmp_inf.c	2007-07-18 14:07:51.000000000 +0200
+++ ipsec-tools/src/racoon/isakmp_inf.c	2007-08-22 10:06:10.435491605 +0200
@@ -636,11 +636,15 @@
 	if (iph2->status != PHASE2ST_ESTABLISHED)
 		return 0;
 
+	if (iph2->ph1 != NULL)
+		iph1 = iph2->ph1;
+	else
+		iph1 = getph1byaddr(iph2->src, iph2->dst);
+
 	/*
 	 * don't send delete information if there is no phase 1 handler.
 	 * It's nonsensical to negotiate phase 1 to send the information.
 	 */
-	iph1 = getph1byaddr(iph2->src, iph2->dst); 
 	if (iph1 == NULL){
 		plog(LLV_DEBUG2, LOCATION, NULL,
 			 "No ph1 handler found, could not send DELETE_SA\n");
Index: ipsec-tools/src/racoon/handler.c
===================================================================
--- ipsec-tools.orig/src/racoon/handler.c	2007-06-06 11:18:16.000000000 +0200
+++ ipsec-tools/src/racoon/handler.c	2007-08-22 10:06:10.435491605 +0200
@@ -584,10 +584,12 @@
  * initialize ph2handle
  * NOTE: don't initialize src/dst.
  *       SPI in the proposal is cleared.
+ *       id and id_p are not cleared if clear_id is 0 (rekeying case)
  */
 void
-initph2(iph2)
+initph2(iph2, clear_id)
 	struct ph2handle *iph2;
+	const int clear_id;
 {
 	sched_scrub_param(iph2);
 	iph2->sce = NULL;
@@ -625,8 +627,10 @@
 	VPTRINIT(iph2->dhpub);
 	VPTRINIT(iph2->dhpub_p);
 	VPTRINIT(iph2->dhgxy);
-	VPTRINIT(iph2->id);
-	VPTRINIT(iph2->id_p);
+	if (clear_id) {
+		VPTRINIT(iph2->id);
+		VPTRINIT(iph2->id_p);
+	}
 	VPTRINIT(iph2->nonce);
 	VPTRINIT(iph2->nonce_p);
 	VPTRINIT(iph2->sa);
@@ -645,7 +649,7 @@
 delph2(iph2)
 	struct ph2handle *iph2;
 {
-	initph2(iph2);
+	initph2(iph2, 1);
 
 	if (iph2->src) {
 		racoon_free(iph2->src);
Index: ipsec-tools/src/racoon/handler.h
===================================================================
--- ipsec-tools.orig/src/racoon/handler.h	2006-09-09 18:22:09.000000000 +0200
+++ ipsec-tools/src/racoon/handler.h	2007-08-22 10:06:10.435491605 +0200
@@ -453,7 +453,7 @@
 extern struct ph2handle *getph2bysaidx __P((struct sockaddr *,
 	struct sockaddr *, u_int, u_int32_t));
 extern struct ph2handle *newph2 __P((void));
-extern void initph2 __P((struct ph2handle *));
+extern void initph2 __P((struct ph2handle *, const int));
 extern void delph2 __P((struct ph2handle *));
 extern int insph2 __P((struct ph2handle *));
 extern void remph2 __P((struct ph2handle *));
Index: ipsec-tools/src/racoon/isakmp_quick.c
===================================================================
--- ipsec-tools.orig/src/racoon/isakmp_quick.c	2007-08-22 10:06:10.351486818 +0200
+++ ipsec-tools/src/racoon/isakmp_quick.c	2007-08-22 10:06:10.439491833 +0200
@@ -200,11 +200,13 @@
 		}
 	}
 
-	/* generate ID value */
-	if (ipsecdoi_setid2(iph2) < 0) {
-		plog(LLV_ERROR, LOCATION, NULL,
-			"failed to get ID.\n");
-		goto end;
+	/* Generate ID value if not already available (rekeying case) */
+	if (iph2->id == NULL && iph2->id_p == NULL) {
+		if (ipsecdoi_setid2(iph2) < 0) {
+			plog(LLV_ERROR, LOCATION, NULL,
+			     "failed to get ID.\n");
+			goto end;
+		}
 	}
 	plog(LLV_DEBUG, LOCATION, NULL, "IDci:\n");
 	plogdump(LLV_DEBUG, iph2->id->v, iph2->id->l);