ipsec-tools: Update to 0.8.0.

This change updates ipsec-tools to 0.8.0. However, a quick test reveals
a regression in IPSec PSK sessions. The server rejects the first packet
of phase 2 negotiation with INVALID-ID-INFORMATION error. After testing
files one by one, it turns out that using the old ipsec_doi.c fixes the
problem. Then the next error shows that identity check is failed. This
can be fixed by marking few lines in isakmp_quick.c just like 0.7.3.

This change adds ipsec_doi-0.7.3.c as a temporary fix. I will come back
and see if I can find the real problem. IPSec RSA sessions will be
covered in the next change.

Change-Id: I48f0026c3be07f506b3901b59202081bf88f41c9
diff --git a/Android.mk b/Android.mk
index b11ce55..078770f 100644
--- a/Android.mk
+++ b/Android.mk
@@ -21,6 +21,10 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES := \
+	src/racoon/algorithm.c \
+	src/racoon/crypto_openssl.c \
+	src/racoon/genlist.c \
+	src/racoon/handler.c \
 	src/racoon/isakmp.c \
 	src/racoon/isakmp_agg.c \
 	src/racoon/isakmp_base.c \
@@ -29,22 +33,19 @@
 	src/racoon/isakmp_inf.c \
 	src/racoon/isakmp_newg.c \
 	src/racoon/isakmp_quick.c \
-	src/racoon/handler.c \
-	src/racoon/pfkey.c \
-	src/racoon/ipsec_doi.c \
-	src/racoon/oakley.c \
-	src/racoon/vendorid.c \
-	src/racoon/policy.c \
-	src/racoon/crypto_openssl.c \
-	src/racoon/algorithm.c \
-	src/racoon/proposal.c \
-	src/racoon/strnames.c \
-	src/racoon/schedule.c \
-	src/racoon/str2val.c \
-	src/racoon/genlist.c \
-	src/racoon/vmbuf.c \
-	src/racoon/sockmisc.c \
+	src/racoon/ipsec_doi-0.7.3.c \
 	src/racoon/nattraversal.c \
+	src/racoon/oakley.c \
+	src/racoon/pfkey.c \
+	src/racoon/policy.c \
+	src/racoon/proposal.c \
+	src/racoon/remoteconf.c \
+	src/racoon/schedule.c \
+	src/racoon/sockmisc.c \
+	src/racoon/str2val.c \
+	src/racoon/strnames.c \
+	src/racoon/vendorid.c \
+	src/racoon/vmbuf.c \
 	main.c \
 	setup.c
 
diff --git a/ChangeLog b/ChangeLog
index 0bc2ef7..b071e40 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,46 +1,574 @@
-2009-08-13  tag ipsec-tools-0_7_3
+2011-03-17  Yvan Vanhullebus <vanhu@netasq.com>
+
+	* src/racoon/oakley.c: fixed a memory leak in
+	  oakley_append_rmconf_cr() while generating plist. patch by Roman
+	  Hoog Antink <rha@open.ch>
+
+	* src/racoon/oakley.c: free name later, to avoid a memory use after
+	  free in oakley_check_certid(). also give iph1->remote to some plog()
+	  calls. patch by Roman Hoog Antink <rha@open.ch>
+
+	* src/racoon/oakley.c: fixed a memory leak in
+	  oakley_check_certid(). patch by Roman Hoog Antink <rha@open.ch>
+
+2011-03-15  Yvan Vanhullebus <vanhu@netasq.com>
+
+	* src/racoon/: isakmp.c, isakmp_inf.c, pfkey.c: directly call
+	  isakmp_ph1delete() instead of scheduling isakmp_ph1delete_stub(), as
+	  it is useless an can lead to memory access after free
+
+2011-03-14  Timo Teras <timo.teras@iki.fi>
+
+	* src/racoon/: grabmyaddr.c, handler.c, isakmp.c, isakmp_inf.c,
+	  isakmp_quick.c, nattraversal.c, pfkey.c, policy.c, sockmisc.c,
+	  sockmisc.h, throttle.c: Explicitly compare return value of
+	  cmpsaddr() against a return value define to make it more obvious
+	  what is the intended action. One more return value is also added, to
+	  fix comparison of security policy descriptors. Namely, getsp()
+	  should not allow wildcard matching (as the comment says, it does
+	  exact matching) - otherwise we get problems when kernel has generic
+	  policy with no ports, and a second similar policy with ports.
+
+2011-03-14  Yvan Vanhullebus <vanhu@netasq.com>
+
+	* src/racoon/: cfparse.y, isakmp_xauth.c, isakmp_xauth.h,
+	  remoteconf.c, remoteconf.h, rsalist.c, rsalist.h: avoid some
+	  memory leaks / free memory access when reloading conf and have
+	  inherited config. patch from Roman Hoog Antink <rha@open.ch>
+
+	* src/racoon/handler.c: removed an useless comment
+
+	* src/racoon/handler.c: check if we got RMCONF_ERR_MULTIPLE from
+	  getrmconf_by_ph1() in revalidate_ph1tree_rmconf()
+
+2011-03-11  Yvan Vanhullebus <vanhu@netasq.com>
+
+	* src/racoon/: handler.c, isakmp.c: directly delete a ph1 in
+	  remove_ph1-) instead of scheduling it, to avoid (completely ?) a
+	  race condition when reloading configuration
+
+2011-03-06  Timo Teras <timo.teras@iki.fi>
+
+	* src/racoon/privsep.c: Quiet a gcc warning when strict-aliasing
+	  checks are enabled. Reported by Stephen Clark.
+
+2011-03-02  Yvan Vanhullebus <vanhu@netasq.com>
+
+	* src/racoon/session.c: flush sainfo list when closing session.
+	  patch by Roman Hoog Antink <rha@open.ch>
+
+	* src/racoon/: remoteconf.c, rsalist.c, rsalist.h: free rsa
+	  structures when deleting a struct rmconf. patch by Roman Hoog Antink
+	  <rha@open.ch>
+
+	* src/racoon/: cfparse.y, remoteconf.c, remoteconf.h: free spspec
+	  when deleting a rmconf struct. patch by Roman Hoog Antink
+	  <rha@open.ch>
+
+	* src/racoon/: remoteconf.c, session.c: fixed some memory leaks in
+	  remoteconf. patch by Roman Hoog Antink <rha@open.ch>
+
+	* src/racoon/: cfparse.y, prsa_par.y: fixed some memory leaks
+	  during configuration parsing. patch by Roman Hoog Antink
+	  <rha@open.ch>
+
+2011-03-01  Yvan Vanhullebus <vanhu@netasq.com>
+
+	* src/racoon/: isakmp.c, pfkey.c: plog text fixes, patch from M E
+	  Andersson <debian@gisladisker.se>
+
+	* src/racoon/cfparse.y: reset yyerrorcount before doing parse
+	  stuff. patch by Roman Hoog Antink <rha@open.ch>
+
+2011-02-20  Timo Teras <timo.teras@iki.fi>
+
+	* src/racoon/oakley.c: From Roman Hoog Antink <rha@open.ch>: Fix
+	  memory leak when using plain RSA key authentication.
+
+2011-02-11  Timo Teras <timo.teras@iki.fi>
+
+	* src/racoon/plainrsa-gen.c: From Mats E Andersson
+	  <debian@gisladisker.se>: Fix fprintf format specifier usage from
+	  previous patch.
+
+2011-02-10  Timo Teras <timo.teras@iki.fi>
+
+	* src/racoon/plainrsa-gen.c: From Mats Erik Andersson
+	  <debian@gisladisker.se>: Implement importing of RSA keys from PEM
+	  files.
+
+	* src/racoon/prsa_par.y: From M E Andersson
+	  <debian@gisladisker.se>: Fix parsing of restricted RSA key
+	  addresses.
+
+2011-02-02  Yvan Vanhullebus <vanhu@netasq.com>
+
+	* src/racoon/: cftoken.l, isakmp.c, remoteconf.h, sainfo.c,
+	  sainfo.h: store ph1id in an u_int32_t instead of a (signed)int.
+	  Patch from Christophe Carre
+
+2011-01-28  Timo Teras <timo.teras@iki.fi>
+
+	* src/racoon/: sainfo.c, sainfo.h, session.c: From Roman Hoog
+	  Antink <rha@open.ch>: Clean up sainfo reloading: rename the
+	  functions, and remove unneeded global variable.
+
+	* src/racoon/: remoteconf.c, remoteconf.h, session.c: From Roman
+	  Hoog Antink <rha@open.ch>: Clean up rmconf reloading: rename the
+	  functions, and remove unneeded global variable.
+
+	* src/racoon/plog.c: From Roman Hoog Antink <rha@open.ch>: Log
+	  remote IP address if available (slightly modified by tteras)
+
+2011-01-22  Timo Teras <timo.teras@iki.fi>
+
+	* src/racoon/isakmp_inf.c: From Roman Hoog Antink <rha@open.ch>:
+	  Fixes a null pointer dereference that might occur after removing
+	  peers from the config and then reloading.
+
+2011-01-20  Yvan Vanhullebus <vanhu@netasq.com>
+
+	* src/libipsec/pfkey.c: fixed a typo, it will now compile when
+	  KMADDRESS is defined. reported by Roman Hoog Antink (rha (at)
+	  open.ch)
+
+2010-12-28  Timo Teras <timo.teras@iki.fi>
+
+	* src/racoon/handler.c: From Roman Hoog Antink <rha@open.ch>: Fix
+	  config reload to not delete too many phase 2 handles, because wrong
+	  chain field is used when enumerating the handles.
+
+2010-12-16  gdt
+
+	* src/racoon/oakley.c: When encountering a certificate where "ID
+	  mismatched with ASN1 SubjectName", and verify_identifier is off,
+	  don't raise an error.  This makes the behavior match the man page.
+
+	  Patch sent for review long ago:
+	    http://mail-index.netbsd.org/tech-security/2006/03/24/0000.html
+	  with no negative feedback received to date.
+
+2010-12-14  Timo Teras <timo.teras@iki.fi>
+
+	* src/racoon/ipsec_doi.c: From Roman Hoog Antink <rha@open.ch>: Fix
+	  possible null derefence.
+
+2010-12-08  Timo Teras <timo.teras@iki.fi>
+
+	* src/racoon/admin.c: Use separate SA addresses for phase2's
+	  created by admin command. The phase2 startup overwrites src/dst with
+	  ISAKMP ports if they are zero and we don't want that to happen for
+	  the SA ports.
+
+2010-12-08  joerg
+
+	* src/libipsec/pfkey.c: ANSIfy
+
+2010-12-07  Timo Teras <timo.teras@iki.fi>
+
+	* src/racoon/isakmp_quick.c: Fix spacing and improve wording in
+	  some log messages.
+
+2010-12-03  Timo Teras <timo.teras@iki.fi>
+
+	* src/libipsec/ipsec_dump_policy.c: Recognize direction for Linux
+	  per-socket policies.
+
+	* src/: libipsec/libpfkey.h, libipsec/pfkey_dump.c, setkey/parse.y,
+	  setkey/setkey.8: Support GRE key as upper layer protocol
+	  specifier (will be supported in Linux kernel 2.6.38).
+
+	* src/racoon/grabmyaddr.c: Netlink deletion notification does not
+	  guarentee actual address deletion: it might still exist on some
+	  other interface. Make sure we do not unbind unless the address is
+	  really gone.
+
+2010-11-17  Timo Teras <timo.teras@iki.fi>
+
+	* src/racoon/: handler.c, handler.h, isakmp.c, isakmp_inf.c: Fix my
+	  previous patch to not call purge_remote() twice. Change the place
+	  where purge_remote() is called. This fixes also a possible crash
+	  from the same patch since ph1->remote can be NULL (when we are
+	  responder and config is not yet selected).
+
+2010-11-12  Timo Teras <timo.teras@iki.fi>
+
+	* src/racoon/: admin.c, isakmp.c, isakmp_var.h, pfkey.c:
+	  isakmp_post_acquire is now called from admin commands too, add a
+	  flag so admin commands can be used to establish even passive links
+	  on demand.
+
+	* src/racoon/isakmp.c: Purge all IPsec-SA's if the last main
+	  ISAKMP-SA for the node is deleted by remote request and the phase1
+	  rekeying is enabled (this will also trigger the new phase1_dead
+	  script hook).
+
+	* src/racoon/: handler.h, isakmp_inf.c: Improve DPD sequence checks
+	  to allow any reply within valid sequence window to be proof of
+	  livelyness. This can improves things if there's random packet
+	  delays, or if racoon is not getting enough CPU time.
+
+	* src/racoon/: admin.c, admin.h, kmpstat.c, racoonctl.c: Extern
+	  admin protocol to allow reply packets to exceed 64kb. E.g SA dumps
+	  with many established SAs can be easily over the limit.
+
+2010-10-22  Timo Teras <timo.teras@iki.fi>
+
+	* src/racoon/grabmyaddr.c: Change Linux Netlink address monitoring
+	  to monitor local route changes.  This works around a kernel bug, and
+	  slightly improves behaviour on some special cases.
+
+2010-10-21  Timo Teras <timo.teras@iki.fi>
+
+	* src/racoon/: admin.c, evt.c, grabmyaddr.c, isakmp.c, pfkey.c,
+	  session.c, session.h: Introduce priorities for file descriptor
+	  polling mechanism and give priority to admin port. If admin port is
+	  used by ISAKMP-SA hook scripts they should be preferred, other wise
+	  heavy traffic can delay admin port requests considerably. This in
+	  turn may cause renegotiation loop for ISAKMP-SA. This is mostly
+	  useful for OpenNHRP setup, but can benefit other setups too.
+
+	* src/racoon/: admin.c, handler.c, handler.h: Remove
+	  initial-contact entry when all ISAKMP-SA are purged via adminport.
+	  This will avoid stale security associations if some of the delete
+	  notifications happens to get lost.
+
+2010-10-20  Timo Teras <timo.teras@iki.fi>
+
+	* src/racoon/crypto_openssl.c: Use high-level openssl EVP and HMAC
+	  functions when possible: this allows openssl to perform hardware
+	  acceleration if available.
+
+	* src/racoon/: isakmp.c, isakmp_quick.c: Various improvements to
+	  error log messages and a few additional error log messages to
+	  improve diagnosing an error condition.
+
+	* src/racoon/grabmyaddr.c: Fix address comparison so we actually
+	  close sockets which were bound to IP-address that got deconfigured.
+
+2010-10-11  Yvan Vanhullebus <vanhu@netasq.com>
+
+	* src/racoon/ipsec_doi.c: report a higher encryption key length in
+	  approval for OBEY / CLAIM / STRICT modes
+
+2010-09-27  Yvan Vanhullebus <vanhu@netasq.com>
+
+	* src/racoon/isakmp_xauth.c: fixed some typos in logs (reported by
+	  fazaeli (at) sepehrs.com)
+
+2010-09-24  Yvan Vanhullebus <vanhu@netasq.com>
+
+	* src/racoon/cftoken.l: fixed a fd leak, patch by getlaser (at)
+	  gmail.com
+
+2010-09-22  Yvan Vanhullebus <vanhu@netasq.com>
+
+	* src/racoon/admin.c: get the correct length of username when
+	  processing ADMIN_LOGOUT_USER, patch by rweikusat (at) mssgmbh.com
+
+	* src/racoon/nattraversal.h: fixed a typo in macros, reported by
+	  marisp (at) mt.lv
+
+2010-09-21  Yvan Vanhullebus <vanhu@netasq.com>
+
+	* src/racoon/isakmp_cfg.c: moved from utmp.h to utmpx.h (patch
+	  provided by marcin.cieslak (at) gmail.com)
+
+2010-09-08  Yvan Vanhullebus <vanhu@netasq.com>
+
+	* src/racoon/remoteconf.c: fixed remoteconf selection when no ID
+	  specified in configuration, and added some debug to remoteconf
+	  selection
+
+2010-08-26  Yvan Vanhullebus <vanhu@netasq.com>
+
+	* src/racoon/remoteconf.c: fix by Sergio.Gelato (at) astro.su.se:
+	  duplicate some dynamic values in duprmconf()
+
+2010-08-04  Yvan Vanhullebus <vanhu@netasq.com>
+
+	* src/racoon/isakmp_cfg.c: fixed answer for IP4_SUBNET request
+
+2010-07-30  Yvan Vanhullebus <vanhu@netasq.com>
+
+	* src/racoon/doc/FAQ: updated link to NetBSD's documentation
+
+2010-06-22  Thomas Klausner <wiz@netbsd.org>
+
+	* src/racoon/racoon.conf.5: Bump date for previous.
+
+2010-06-22  Yvan Vanhullebus <vanhu@netasq.com>
+
+	* src/racoon/: cfparse.y, cftoken.l, isakmp.c, isakmp_inf.c,
+	  racoon.conf.5, remoteconf.c, remoteconf.h: added a specific
+	  script hook when a dead peer is detected
+
+2010-06-04  Thomas Klausner <wiz@netbsd.org>
+
+	* src/setkey/setkey.8: New sentence, new line. Bump date for
+	  previous.
+
+2010-06-04  Yvan Vanhullebus <vanhu@netasq.com>
+
+	* src/setkey/: parse.y, setkey.8, token.l: Added support for
+	  spdupdate command in setkey
+
+2010-04-07  Yvan Vanhullebus <vanhu@netasq.com>
+
+	* src/libipsec/ipsec_strerror.c: by Eric Preston: fixed a typo
+
+2010-04-02  Christos Zoulas <christos@netbsd.org>
+
+	* src/: libipsec/pfkey_dump.c, racoon/backupsa.c: handle ctime
+	  returning NULL.
+
+2010-03-11  Christos Zoulas <christos@netbsd.org>
+
+	* src/racoon/handler.c: PR/42363: Yasuoka Masahiko: Second part of
+	  the patch: iterate only on the phase2 handles that are bound by the
+	  given phase1 handle.
+
+2010-03-05  Timo Teras <timo.teras@iki.fi>
+
+	* src/: libipsec/ipsec_set_policy.3, racoon/privsep.c,
+	  racoon/doc/FAQ, setkey/setkey.8: From Stefan Bauer: Fix multiple
+	  typoes and manpage formatting errors.
+
+2010-03-04  Yvan Vanhullebus <vanhu@netasq.com>
+
+	* src/racoon/session.c: From Pierre POMES: fixed admin port
+	  initialization
+
+2010-02-28  snj
+
+	* src/racoon/: sockmisc.c, sockmisc.h: Fight the ever-increasing
+	  size of src checkouts by spelling "useful" without an extra l.
+
+2010-02-09  Thomas Klausner <wiz@netbsd.org>
+
+	* src/racoon/: pfkey.c, proposal.h: Fix typo in comment.
+
+2010-01-17  Thomas Klausner <wiz@netbsd.org>
+
+	* src/racoon/sainfo.c: Free strdeupped string after using it. Found
+	  by cppcheck.
+
+	* src/racoon/: eaytest.c, ipsec_doi.c: Close file handles after
+	  using them. Found by cppcheck.
+
+2010-01-15  joerg
+
+	* src/setkey/setkey.8: Use .%U instead of .%O for URLs.
+
+2009-12-11  Timo Teras <timo.teras@iki.fi>
+
+	* src/racoon/Makefile.am: From Paul Wernau: vmbuf.h was defined
+	  twice in the headers. Remove the redundant entry so new install tool
+	  does not complain about overwriting just installed file.
+
+2009-11-22  Christos Zoulas <christos@netbsd.org>
+
+	* src/racoon/handler.c: PR/42363: Yasuoka Masahiko:
+
+	  racoon uses a wrong IPsec-SA handle that is for other peer in case
+	  it receives a ISAKMP message for IPsec-SA that has the same
+	  message-id as the message-id that is received before.
+
+	  racoon uses message-id to find the handle of IPsec-SA.  The
+	  message-id is a unique number for each peer, but different peers may
+	  use the same value.
+
+	  Different Windows Vista or Windows 7 peers seem to use the same
+	  message-id.  racoon can handle the first Windows's Phase-2, but it
+	  cannot handle the second Windows.  Because racoon misunderstands the
+	  message for the second Windows as the message for the first Windows.
+
+	  >Category:       bin >Synopsis:       racoon uses a wrong IPsec-SA
+	  that is for different peer >Confidential:   no >Severity:
+	  serious >Priority:       medium >Responsible:    bin-bug-people
+	  >State:          open >Class:          sw-bug >Submitter-Id:   net
+	  >Arrival-Date:   Sun Nov 22 18:25:00 +0000 2009 >Originator:
+	  yasuoka@iij.ad.jp
+
+2009-10-29  Christos Zoulas <christos@netbsd.org>
+
+	* src/setkey/token.l: use %option noinput nounput
+
+2009-10-28  Christos Zoulas <christos@netbsd.org>
+
+	* src/setkey/token.l: no unput
+
+2009-10-14  joerg
+
+	* src/libipsec/ipsec_set_policy.3: Do not use .Xo/.Xc to workaround
+	  ancient groff limits.
+
+	* src/setkey/setkey.8: Do not use .Xo/.Xc to work around ancient
+	  groff limits.  Fix markup.
+
+	* src/racoon/racoon.conf.5: Don't use .Xo/.Xc to work around
+	  ancient groff limits.  Set only one list type.
+
+2009-09-18  Timo Teras <timo.teras@iki.fi>
+
+	* src/racoon/: isakmp_agg.c, isakmp_ident.c: From Tomas Mraz: Fix
+	  gssapi error checking.
+
+2009-09-03  Timo Teras <timo.teras@iki.fi>
+
+	* src/racoon/: admin.c, handler.c, handler.h, isakmp.c,
+	  isakmp_var.h, pfkey.c: When rekeying phase2 use phase1 used to
+	  negotiate phase2 as a hint to select the phase1 for rekeying the new
+	  phase2.
+
+2009-09-01  Timo Teras <timo.teras@iki.fi>
+
+	* src/racoon/: nattraversal.c, racoon.conf.5, vendorid.c: Check
+	  nat_traversal configuration from remote configuration candidates
+	  when acting as responder. Enable NAT-T if any of the remote
+	  candidates have NAT-T enabled.
+
+	* src/racoon/remoteconf.c: Change remote conf matching level to
+	  matching score. This way one can override anonymous certificate
+	  block config with more exact "inhereted" IP specific block.
+
+	* src/racoon/: isakmp.c, racoon.conf.5: From Maik Broemme: export
+	  ISAKMP SA identity as REMOTE_ID for phase1 up script (trac #313).
+
+2009-08-24  Yvan Vanhullebus <vanhu@netasq.com>
+
+	* src/racoon/oakley.c: fixed typo: algoriym -> algorithm
+
+2009-08-19  Yvan Vanhullebus <vanhu@netasq.com>
+
+	* src/racoon/remoteconf.c: fixed address check in
+	  rmconf_match_type(), just check address with wildcard port
+
+2009-08-19  Timo Teras <timo.teras@iki.fi>
+
+	* src/racoon/remoteconf.c: Have an enum for rmconf_match_type()
+	  return values to make the code a bit more readable.
+
+2009-08-18  Yvan Vanhullebus <vanhu@netasq.com>
+
+	* src/racoon/oakley.c: typo: algoritym -> algorithm
+
+2009-08-17  Yvan Vanhullebus <vanhu@netasq.com>
+
+	* src/libipsec/libpfkey.h: do not use SADB_X_NAT_T_NEW_MAPPING to
+	  check system support for NAT-T, as at least FreeBSD doesn't have
+	  this define anymore
+
+	* src/racoon/schedule.h: include stddef.h so we have a chance to
+	  get the system offsetof if present
+
+	* src/racoon/crypto_openssl.h: removed a self include
 
 2009-08-13  Yvan Vanhullebus <vanhu@netasq.com>
 
-	* NEWS, configure.ac: 0.7.3 release
-
 	* src/racoon/oakley.c: fixed a potential DoS in
 	  oakley_do_decrypt(), reported by Orange Labs
 
+2009-08-10  Timo Teras <timo.teras@iki.fi>
+
+	* src/racoon/pfkey.c: Don't print EAGAIN error from
+	  pfkey_handler(), it can occur normally under some code paths and is
+	  not a hard error in any case.
+
 2009-08-06  Timo Teras <timo.teras@iki.fi>
 
 	* src/setkey/setkey.c: From Paul Wenau: Check fgets return value in
 	  setkey to make gcc happy.
 
-2009-06-19  Timo Teras <timo.teras@iki.fi>
+2009-08-05  Timo Teras <timo.teras@iki.fi>
 
-	* src/racoon/ipsec_doi.c: Backport S.P.Zeidler's fix to IPv6
-	  address related stack smashing in ipsecdoi_id2str() from CVS HEAD.
+	* src/racoon/pfkey.c: From Paul Wernau: Fix transport mode per-port
+	  security associations that got broke during NAT-T fixes.
+
+2009-07-07  Timo Teras <timo.teras@iki.fi>
+
+	* src/racoon/sockmisc.c: From Arnaud Ebalard: Fix possible usage of
+	  uninitialized local variable (not sure if any code path triggers
+	  this, but this makes compiler happy).
+
+2009-07-03  Timo Teras <timo.teras@iki.fi>
+
+	* src/racoon/: admin.c, grabmyaddr.c, handler.c, handler.h,
+	  isakmp.c, isakmp_cfg.c, isakmp_inf.c, isakmp_quick.c,
+	  nattraversal.c, pfkey.c, policy.c, remoteconf.c, remoteconf.h,
+	  sockmisc.c, sockmisc.h, throttle.c: Get rid of the evil CMPSADDR
+	  macro. Trac #295.
+
+	* src/: libipsec/libpfkey.h, libipsec/pfkey.c, racoon/isakmp.c,
+	  racoon/isakmp_inf.c, racoon/pfkey.c, racoon/pfkey.h: From Yvan
+	  Vanhullebus: Use SADB_X_EXT_NAT_T_* consistently for passing the
+	  NAT-T port information. This might break compatibility with some
+	  kernels, but as discussed this is the proper way to pass NAT-T ports
+	  and the broken kernels need to be fixed.
+
+2009-06-24  Timo Teras <timo.teras@iki.fi>
+
+	* src/racoon/session.c: Fix a call to null pointer: in some cases,
+	  the unmonitor_fd can be called from another fd's callback. That
+	  could lead to still have callback pending after unmonitoring the fd
+	  resulting in a call to null pointer.  This is fixed by making
+	  unmonitor_fd now clear the pending fd_set too.  Bug was introduced
+	  by my commit in 2008-12-23.
+
+2009-05-20  Yvan Vanhullebus <vanhu@netasq.com>
+
+	* src/racoon/isakmp.h: typo
+
+2009-05-19  Timo Teras <timo.teras@iki.fi>
+
+	* src/racoon/: ipsec_doi.c, isakmp.c: From Jukka Salmi: Fix couple
+	  of typos from previous commit.
 
 2009-05-18  Timo Teras <timo.teras@iki.fi>
 
+	* src/racoon/: ipsec_doi.c, isakmp.c, sockmisc.c, sockmisc.h: From
+	  Tomas Mraz: Introduce union sockaddr_any and use it to make code
+	  more readable. Related to trac #293.
+
 	* src/racoon/isakmp_inf.c: From Tomas Mraz: Remove variable that is
 	  not really used; only referenced while uninitialized causing
 	  valgrind error.
 
 	* src/racoon/nattraversal.c: From Tomas Mraz: Fix natt_flags check.
 
+2009-05-04  Thomas Klausner <wiz@netbsd.org>
+
+	* src/racoon/racoon.conf.5: Remove superfluous spaces around
+	  parentheses.
+
 2009-04-29  Timo Teras <timo.teras@iki.fi>
 
 	* src/racoon/crypto_openssl.c: From Ross Meng: Fix a memory leak in
 	  X509 certificate validation.
 
-2009-04-22  tag ipsec-tools-0_7_2
+2009-04-28  Timo Teras <timo.teras@iki.fi>
+
+	* src/racoon/handler.c: Reset nat_oa variables too when reusing
+	  phase two handler. Otherwise phase2 rekeying might fail in some
+	  scenarios.
 
 2009-04-22  Timo Teras <timo.teras@iki.fi>
 
-	* NEWS, configure.ac: Updates for 0.7.2 release
-
 	* src/racoon/isakmp_frag.c: From Neil Kettle: Fix a possible null
 	  pointer dereference in fragmentation code.
 
+2009-04-21  Timo Teras <timo.teras@iki.fi>
+
+	* src/racoon/: grabmyaddr.c, grabmyaddr.h, session.c: Fix
+	  strict_address to work again. The lists needs to be initialized
+	  before configuration is read, which happens before my_addr_init()
+	  call.
+
 2009-04-20  Timo Teras <timo.teras@iki.fi>
 
+	* src/racoon/: isakmp.c, isakmp.h, isakmp_var.h: Fix a memory leak
+	  in certificate request generation.
+
 	* src/racoon/: isakmp_inf.c, isakmp_xauth.c, plog.c: Orignally from
 	  Bin Li: Fix possible memory corruption in binsanitize().
 
@@ -56,25 +584,257 @@
 	* src/racoon/handler.c: From Paul Moore: Phase2 message id's should
 	  be unique wrt phase1, not globally.
 
+2009-03-13  Timo Teras <timo.teras@iki.fi>
+
+	* src/racoon/: pfkey.c, remoteconf.h: From Arnaud Ebalard: Fix
+	  couple of problems with previous commit.
+
+2009-03-12  he
+
+	* src/racoon/: isakmp.c, remoteconf.c: When casting to/from a
+	  pointer to an integral type (a bad practice, if you ask me), you
+	  need to cast via intptr_t for portability.
+
+2009-03-12  Thomas Klausner <wiz@netbsd.org>
+
+	* src/racoon/racoon.conf.5: New sentence, new line. Avoid marking
+	  up punctuation.
+
+	* src/racoon/racoonctl.8: Bump date for previous. Sort options to
+	  establish-sa.  Stop using Xo/Xc.
+
+2009-03-12  Timo Teras <timo.teras@iki.fi>
+
+	* src/racoon/: admin.c, cfparse.y, cftoken.l, crypto_openssl.c,
+	  crypto_openssl.h, dnssec.c, dnssec.h, handler.c, handler.h,
+	  ipsec_doi.c, ipsec_doi.h, isakmp.c, isakmp.h, isakmp_agg.c,
+	  isakmp_base.c, isakmp_ident.c, isakmp_inf.c, isakmp_quick.c,
+	  isakmp_var.h, nattraversal.c, oakley.c, oakley.h, racoon.conf.5,
+	  racoonctl.8, racoonctl.c, remoteconf.c, remoteconf.h, sockmisc.c,
+	  vendorid.c: Support multiple anonymous remotes and decide
+	  remoteconf based on identity, received certificates and other
+	  information. General code clean up.
+
+2009-03-06  Timo Teras <timo.teras@iki.fi>
+
+	* src/setkey/: extern.h, parse.y, setkey.c: setkey: fix deleteall
+	  in Linux
+
+	  Linux requires SADB_DELETE message to have SPI. So send a
+	  SADB_DELETE message for each matching SA. Trac #284.
+
+	  From: Gabriel Somlo <somlo@cmu.edu>
+
 2009-02-16  Timo Teras <timo.teras@iki.fi>
 
 	* src/libipsec/policy_parse.y: From Paul Moore: Fix a heap
 	  corruption bug (yacc return non-null terminated buffer and sprintf
 	  writes over bounds).
 
+2009-02-11  Yvan Vanhullebus <vanhu@netasq.com>
+
+	* src/racoon/: isakmp.c, sockmisc.c, sockmisc.h: trac#301: fixed
+	  IPsec SAs flush in purge_remote() when NAT-T enabled but no NAT-T on
+	  tunnel
+
+2009-02-03  Timo Teras <timo.teras@iki.fi>
+
+	* src/racoon/isakmp.c: From: Phil Sutter. Fix script environment
+	  variables with IPv6 addresses.
+
+2009-01-26  Timo Teras <timo.teras@iki.fi>
+
+	* src/racoon/main.c: Argument parsing needs lcconf initialized.
+
+2009-01-24  Thomas Klausner <wiz@netbsd.org>
+
+	* src/racoon/racoonctl.c: Sort options in usage.
+
+	* src/racoon/racoonctl.8: Sort options. New sentence, new line.
+
+	* src/racoon/racoon.8: Sort options.
+
+2009-01-23  Timo Teras <timo.teras@iki.fi>
+
+	* src/racoon/: racoonctl.8, racoonctl.c: Update usage and manpage
+	  for racoonctl.
+
+	* src/racoon/: main.c, racoon.8: Racoon -v to print version and
+	  compilation information. Update usage message.
+
+	* NEWS: Update NEWS with major changes since 0.7 release.
+
+	* src/racoon/schedule.c: Fix monotonic scheduler change, to not
+	  refresh 'now' before exit. Otherwise we can return negative timeout
+	  after spending time handling other events.
+
+	* src/racoon/: handler.c, pfkey.c: From Arnaud Ebalard: Handle
+	  reception of MIGRATE message during Phase 1 and Phase 2 negotiation.
+	  Also corrects some debugging statements.
+
+	* src/racoon/pfkey.c: From Arnaud Ebalard: On the responder (for
+	  instance), there is a need to not only migrate local and remote
+	  addresses of Phase 1 that match previous addresses but also the
+	  local and remote addresses of a Phase 1 *associated* with a migrated
+	  Phase 2. For instance, we have that need when receiving the first
+	  MIGRATE/KMADDRESS message because the old addresses are still the
+	  HoA and the address of the HA (while the peer has contacted us using
+	  the CoA and we have negotiated this address as src attribute in
+	  Phase 2). The patch fixes that by having migrate_ph1_ike_addresses()
+	  called from migrate_ph2_ike_addresses() callback.
+
+	* src/racoon/isakmp_quick.c: From Arnaud Ebalard: Set phase2 spid
+	  when acting as responder.
+
+	* configure.ac, src/racoon/handler.c, src/racoon/handler.h,
+	  src/racoon/isakmp_inf.c, src/racoon/isakmp_xauth.c,
+	  src/racoon/schedule.c, src/racoon/schedule.h,
+	  src/racoon/throttle.c, src/racoon/throttle.h: Detect if monotonic
+	  system clock is available, and use it for relative time measurements
+	  to avoid complite hang if time jumps backwards.
+
+	* src/racoon/: cfparse.y, ipsec_doi.c, isakmp.c, isakmp_agg.c,
+	  isakmp_base.c, isakmp_cfg.c, isakmp_ident.c, isakmp_xauth.c,
+	  oakley.c, oakley.h: Fix authentication method ambiguity by
+	  internally using unique ID and setting/interpreting the wire format
+	  based on received vendor ID:s. Fixes trac #280.
+
+	* src/racoon/: handler.h, isakmp_agg.c, isakmp_base.c,
+	  isakmp_ident.c, vendorid.c, vendorid.h: Introduce vendorid
+	  bitmask that can be used otherwhere to detect peer capabilities.
+
+	* configure.ac, src/racoon/admin.c, src/racoon/evt.c,
+	  src/racoon/grabmyaddr.c, src/racoon/isakmp.c, src/racoon/pfkey.c,
+	  src/racoon/session.c, src/racoon/session.h: Remove "fastquit"
+	  configure option and make it the default behaviour. The previous
+	  normal behaviour is buggy, as after flush kernel can immediately
+	  create larval SA:s which would prevent exit.
+
 2009-01-20  Timo Teras <timo.teras@iki.fi>
 
-	* configure.ac: Fix a CPPLAGS typo to CPPFLAGS which was intended
-
-	* misc/cvs2cl.pl, misc/cvsusermap, Makefile.am: Autogenerate
+	* Makefile.am, misc/cvs2cl.pl, misc/cvsusermap: Autogenerate
 	  ChangeLog from NetBSD CVS. Put sourceforge.net changes to
 	  ChangeLog.old.
 
-	* misc/cvs2cl.pl: file cvs2cl.pl was added on branch
-	  ipsec-tools-0_7-branch on 2009-01-20 14:36:32 +0000
+2009-01-10  Thomas Klausner <wiz@netbsd.org>
 
-	* misc/cvsusermap: file cvsusermap was added on branch
-	  ipsec-tools-0_7-branch on 2009-01-20 14:36:32 +0000
+	* src/racoon/racoon.conf.5: Make ready for HTML output.  Use proper
+	  escape for backslash ('\e').
+
+2009-01-10  Timo Teras <timo.teras@iki.fi>
+
+	* src/racoon/: crypto_openssl.c, racoon.conf.5: From Cyrus Rahman:
+	  Accept RFC2253 compliant escaped special characters for asn1dn
+	  identifier.
+
+2009-01-09  Timo Teras <timo.teras@iki.fi>
+
+	* configure.ac: Fix a CPPLAGS typo to CPPFLAGS which was intended
+
+2009-01-05  Timo Teras <timo.teras@iki.fi>
+
+	* src/racoon/: cfparse.y, cftoken.l, racoon.conf.5: Remove obsolete
+	  configuration options, fix radius configuration block and add GRE as
+	  recognized protocol.
+
+	* src/racoon/session.c: Do not use counting in signal handling as
+	  it was unsafe by not using atomic functions (post increment is not
+	  necessarily atomic).  Instead reap all children on SIGCHLD as that
+	  was the only signal needing signal counting.
+
+2008-12-30  Timo Teras <timo.teras@iki.fi>
+
+	* src/racoon/session.c: schedular() call can now modify fd mask so
+	  make the working copy just before calling select(); otherwise it can
+	  contain bad file descriptors
+
+2008-12-29  Michael van Elst <mlelstv@netbsd.org>
+
+	* src/setkey/parse.y: support icmp codes. Fixes PR 39056.
+
+2008-12-24  Christos Zoulas <christos@netbsd.org>
+
+	* src/racoon/grabmyaddr.c: remove sin{6,}_len linux does not have
+	  it. From Timo Teras.
+
+	* src/racoon/grabmyaddr.c: I was wrong. addr is actually set.
+
+	* src/racoon/grabmyaddr.c:
+	  - make this compile by zeroing out the whole structure not just
+	  bogus fields.
+	  - set length field of sockets appropriately.
+	  - mark bogus no-op code (I don't understand what the author intended
+	  here).
+
+2008-12-23  Thomas Klausner <wiz@netbsd.org>
+
+	* src/racoon/racoon.conf.5: Bump date for identity configuration
+	  option removal.
+
+2008-12-23  Timo Teras <timo.teras@iki.fi>
+
+	* src/racoon/: cfparse.y, cftoken.l, ipsec_doi.c, localconf.c,
+	  localconf.h, racoon.conf.5: Remove the obsoleted global identity
+	  configuration option.
+
+	* src/racoon/: admin.c, admin_var.h, cfparse.y, debug.h, evt.c,
+	  evt.h, grabmyaddr.c, grabmyaddr.h, handler.c, isakmp.c,
+	  isakmp_inf.c, isakmp_var.h, localconf.c, localconf.h, main.c,
+	  nattraversal.c, pfkey.c, pfkey.h, privsep.c, session.c,
+	  session.h: rewrite local address detection make some functions
+	  static that arr not needed globally rework how fd_set is
+	  construction for the main loop select()
+
+2008-12-18  Timo Teras <timo.teras@iki.fi>
+
+	* src/racoon/pfkey.c: From Arnaud Ebalard: Delete larval ph2handles
+	  when expire with hard lifetime received
+
+2008-12-16  Timo Teras <timo.teras@iki.fi>
+
+	* README: Update README
+
+	* src/racoon/pfkey.c: Fix transport mode address selection in
+	  acquire handling.  Some earlier fixes got lost on 2008-12-05 commit.
+
+2008-12-11  Yvan Vanhullebus <vanhu@netasq.com>
+
+	* src/racoon/grabmyaddr.c: Fixed compilation on FreeBSD (RTM_IFINFO
+	  and RTM_OIFINFO stuff)
+
+	* src/racoon/isakmp.c: Fixed compilation when DPD support is
+	  disabled
+
+2008-12-08  Timo Teras <timo.teras@iki.fi>
+
+	* src/racoon/: pfkey.c, privsep.c, privsep.h: Do not cache pfkey
+	  sockets: it might cause to not handle some pfkey events when
+	  select() has marked pfkey socket readable, but a timer callback
+	  first calls pfkey_dump_sadb().
+
+2008-12-05  Timo Teras <timo.teras@iki.fi>
+
+	* src/: libipsec/key_debug.c, libipsec/libpfkey.h,
+	  libipsec/pfkey.c, racoon/handler.c, racoon/handler.h,
+	  racoon/ipsec_doi.c, racoon/isakmp.c, racoon/isakmp_quick.c,
+	  racoon/pfkey.c, racoon/policy.c, racoon/policy.h: From Arnaud
+	  Ebalard: Improved Mobile IPv6 support per
+	  draft-ebalard-mext-pfkey-enhanced-migrate.
+
+2008-12-04  Christoph Badura <bad@netbsd.org>
+
+	* src/racoon/privsep.c: Fix typo in previous and use SIG_IGN as I
+	  intended.
+
+2008-12-02  Timo Teras <timo.teras@iki.fi>
+
+	* src/racoon/session.c: Explicitly ignore SIGPIPE. Default action
+	  on Linux is terminate.
+
+2008-11-28  Thomas Klausner <wiz@netbsd.org>
+
+	* src/racoon/racoon.conf.5: Remove empty line. Fix typo. New
+	  sentence, new line.
 
 2008-11-27  Yvan Vanhullebus <vanhu@netasq.com>
 
@@ -83,26 +843,181 @@
 
 	* src/racoon/isakmp_cfg.c: Fixed pool resizing
 
+2008-11-27  Timo Teras <timo.teras@iki.fi>
+
+	* src/racoon/pfkey.c: From Arnaud Ebalard: Remove MAXNESTEDSA
+	  weirdness. It's probably meant for bundle support which is not done.
+	  When someone actually writes bundle support, the nested SA stuff
+	  would probably be reworked too anyway.
+
+	* src/: libipsec/libpfkey.h, libipsec/pfkey.c, racoon/cfparse.y,
+	  racoon/cftoken.l, racoon/localconf.c, racoon/localconf.h,
+	  racoon/pfkey.c, racoon/racoon.conf.5: From: Matthew Krenzer
+	  Ability to set pfkey socket buffer size via configuration file
+	  directive.  (Indentation and minor fixes by me.)
+
+2008-11-25  Christoph Badura <bad@netbsd.org>
+
+	* src/racoon/: evt.c, privsep.c, session.c: Avoid using
+	  MSG_NOSIGNAL as it is not available everywhere.  Ignore SIGPIPE
+	  instead.
+
+	* src/racoon/grabmyaddr.c: Ignore unspecified and looback
+	  addresses.  Ignoring unspecified addresses prevents racoon from
+	  trying to bind to the wildcard address and specific addresses
+	  simultaneously after e.g. dhclient has changed an interface's
+	  address to 0.0.0.0.
+
+	* src/racoon/grabmyaddr.c: RTM_DELETE and RTM_IFINFO don't carry
+	  info for added or deleted addresses.  Ignore them silently.
+
+	* src/racoon/grabmyaddr.c: Ignoring an unsuitable address is not an
+	  error.  Therefore log it as informational.  Make it clear from the
+	  log message that a route message is not interesting.
+
+	* src/racoon/grabmyaddr.c: Use insmyaddr() instead of open coding
+	  it.
+
+	* src/racoon/isakmp.c: Do not return erroneously from isakmp_open()
+	  when setting IPV6_USE_MIN_MTU fails.
+
+	* src/racoon/: grabmyaddr.c, isakmp.c: Keep myaddr.sock at -1 when
+	  no socket is opened.
+
+2008-11-08  Christoph Badura <bad@netbsd.org>
+
+	* src/racoon/samples/roadwarrior/client/: phase1-down.sh,
+	  phase1-up.sh: Preserve owner and permissions of original
+	  /etc/resolv.conf.  Ensure that new /etc/resolv.conf isn't group or
+	  world writable.
+
+	* src/racoon/samples/roadwarrior/client/: phase1-down.sh,
+	  phase1-up.sh: Print and check INTERNAL_NETMASK4.
+
+	* src/racoon/samples/roadwarrior/client/: phase1-down.sh,
+	  phase1-up.sh: Make the handling of NAT-T SPD entries automatic.
+
+	* src/racoon/samples/roadwarrior/client/: phase1-down.sh,
+	  phase1-up.sh: Ensure that the determination of the default
+	  gateway and the corresponding interface don't get confused by
+	  multiple, possibly non-IPv4  default routes.  Bring the NetBSD case
+	  of deleting the VPN routes and address in line with the Linux case
+	  and delete the address after deleting the VPN routes.
+
+2008-11-06  Yvan Vanhullebus <vanhu@netasq.com>
+
+	* src/racoon/sainfo.c: fixed delsainfo() to avoid a crash when
+	  iddst's value is SAINFO_CLIENTADDR
+
+2008-10-29  S.P.Zeidler <spz@netbsd.org>
+
+	* src/racoon/ipsec_doi.c: Changes to ipsecdoi_id2str():
+
+	  struct sockaddr -> struct sockaddr_storage fixes a stack overflow
+
+	  For non-linklocal addresses the value in 'scope' is garbage and gets
+	  set to zero instead.
+
+2008-10-27  Timo Teras <timo.teras@iki.fi>
+
+	* src/racoon/pfkey.c: From Arnaud Ebalard: Add missing return to
+	  error path
+
+	* src/racoon/grabmyaddr.c: From Francis Dupont (sent by Arnaud
+	  Ebalard): recognize RTM_IFANNOUNCE
+
+	* src/racoon/grabmyaddr.c: From Arnaud Ebalard: Fix indentation
+	  issues for readability
+
+	* src/racoon/session.c: From Arnaud Ebalard: initfds() needs to be
+	  called only if monitored file descriptor numbers have changed
+
+	* src/racoon/isakmp_var.h: From Arnaud Ebalard: Remove duplicate
+	  declaration
+
+2008-10-23  Timo Teras <timo.teras@iki.fi>
+
+	* src/racoon/: privsep.c, session.c, session.h: From Krzysztof
+	  Piotr Oledzki <olel@ans.pl>: Revert parts of 2008-08-06 commit; the
+	  problem those changes address are already handled in a sensible way
+	  by Cyrus Rahman's patch from 2008-03-06.
+
+2008-10-09  Timo Teras <timo.teras@iki.fi>
+
+	* src/racoon/isakmp_quick.c: From Arnaud Ebalard: remove
+	  unnecessary unbindph12() call which is now done in remph2()
+
 2008-09-25  Yvan Vanhullebus <vanhu@netasq.com>
 
 	* src/racoon/isakmp.c: Fixed resending mechanism to have non-ESP
 	  marker for retransmitted packets
 
+2008-09-19  Thomas Klausner <wiz@netbsd.org>
+
+	* src/racoon/racoon.conf.5: New sentence, new line.
+
+2008-09-19  Timo Teras <timo.teras@iki.fi>
+
+	* src/racoon/: admin.c, cfparse.y, cftoken.l, handler.c, handler.h,
+	  isakmp.c, isakmp_cfg.c, isakmp_inf.c, isakmp_quick.c,
+	  isakmp_var.h, isakmp_xauth.c, pfkey.c, proposal.c, racoon.conf.5,
+	  remoteconf.c, remoteconf.h: Implement ISAKMP SA rekeying
+	  configurable with rekey {on|off|force} option in remote conf.
+
+	* src/racoon/: handler.c, handler.h, isakmp.c, isakmp_inf.c,
+	  isakmp_quick.c, isakmp_var.h, isakmp_xauth.c, isakmp_xauth.h,
+	  nattraversal.c, pfkey.c, pfkey.h, schedule.c, schedule.h,
+	  session.c: Change struct sched to be allocated be the caller to
+	  avoid some memory allocations. Optimize scheduling algorithm to not
+	  scan all entries in the main loop.
+
 2008-09-17  Yvan Vanhullebus <vanhu@netasq.com>
 
 	* src/racoon/isakmp_inf.c: Fixed port match in purge_ipsec_spi()
 	  when NAT-T enabled and trying to purge non NAT-T SAs
 
+2008-09-09  Yvan Vanhullebus <vanhu@netasq.com>
+
+	* src/racoon/pfkey.c: Some calls to set_port() were not correctly
+	  updated in the previous commit
+
+2008-09-03  Yvan Vanhullebus <vanhu@netasq.com>
+
+	* src/racoon/pfkey.c: From Tomas Mraz: Duplicate addresses in
+	  pk_sendxxx functions, as they may be altered for NAT-T stuff.
+
+2008-09-03  Timo Teras <timo.teras@iki.fi>
+
+	* src/: libipsec/pfkey.c, racoon/pfkey.c, racoon/sockmisc.c:
+	  - Fix reloading of SPD (Linux satype check, handling of SPD dump
+	  responses)
+	  - Remove some spurious error log message from extract_port()
+
+2008-08-29  Gregory McGarry <gmcgarry@netbsd.org>
+
+	* src/racoon/isakmp.c: Eliminate gcc-specific feature of empty
+	  structures.
+
+	* src/racoon/evt.h: Eliminate superfluous semicolon.
+
+	* src/racoon/: admin.c, admin.h: Eliminate gcc-specific feature of
+	  unnamed structures added recently.
+
 2008-08-12  Yvan Vanhullebus <vanhu@netasq.com>
 
-	* src/racoon/isakmp.c: From Krzysztof Oledzki: Remove ph1handler if
-	  we received an invalid first exchange from initiator.
+	* src/racoon/isakmp.c: From Krzysztof Piotr Oledzki: Remove
+	  ph1handler if we received an invalid first exchange from initiator.
 
-2008-07-23  tag ipsec-tools-0_7_1
+2008-08-06  Timo Teras <timo.teras@iki.fi>
 
-2008-07-23  Yvan Vanhullebus <vanhu@netasq.com>
+	* src/racoon/: privsep.c, session.c, session.h: From Krzysztof
+	  Piotr Oledzki: Make privileged process exit if unprivileged process
+	  is terminated and some spelling fixes.
 
-	* NEWS: NEWS for 0.7.1 release
+2008-07-23  Matthew Grooms <mgrooms@shrew.net>
+
+	* src/racoon/: cfparse.y, session.c: Add some missing ifdefs
+	  required for non-radius enabled builds.
 
 2008-07-23  Timo Teras <timo.teras@iki.fi>
 
@@ -114,16 +1029,30 @@
 
 2008-07-22  Yvan Vanhullebus <vanhu@netasq.com>
 
-	* configure.ac: 0.7.1 coming !
-
 	* src/racoon/proposal.c: From Kohki Ohhira: fix some memory leaks,
 	  when malloc fails or when peer sends invalid proposal.
 
-2008-07-21  Timo Teras <timo.teras@iki.fi>
+2008-07-22  Matthew Grooms <mgrooms@shrew.net>
+
+	* src/racoon/: cfparse.y, cftoken.l, isakmp_cfg.c, isakmp_xauth.c,
+	  isakmp_xauth.h, main.c, racoon.conf.5, session.c: Add an optional
+	  radius configuration section to the racoon.conf file. This is
+	  similar to the the LDAP configuration section and overrides settings
+	  in the system radius configuration file.
+
+2008-07-21  Matthias Scheler <tron@netbsd.org>
 
 	* src/racoon/cfparse.y: Correct typo to fix the build.
 
-	* src/racoon/cfparse.y: Do not set default gss id if xauth is used.
+2008-07-21  Timo Teras <timo.teras@iki.fi>
+
+	* src/racoon/: isakmp_agg.c, isakmp_base.c, isakmp_ident.c,
+	  vendorid.c, vendorid.h: Separate generic vendor id handling to a
+	  new function and use it.
+
+	* src/racoon/cfparse.y: Do not set default gss id if xauth is used,
+	  otherwise gss-id attribute might be sent even if it was not
+	  requested.
 
 2008-07-15  Matthew Grooms <mgrooms@shrew.net>
 
@@ -134,6 +1063,17 @@
 	  racoonctl.c: Fix a conflict with the FreeBSD 8 system hexdump
 	  function.
 
+2008-07-14  Timo Teras <timo.teras@iki.fi>
+
+	* src/racoon/: handler.h, ipsec_doi.c, ipsec_doi.h, isakmp_quick.c,
+	  pfkey.c: Handle RESPONDER-LIFETIME notification in quick mode.
+
+	* src/racoon/: handler.h, isakmp.c, isakmp_agg.c, isakmp_ident.c,
+	  isakmp_inf.c, isakmp_inf.h, isakmp_quick.c, strnames.c: Clean up
+	  notification payload handling. Handle INITIAL-CONTACT notification
+	  in last main mode exchange (delayed) and during quick mode
+	  exchanges.
+
 2008-07-11  Timo Teras <timo.teras@iki.fi>
 
 	* src/racoon/: isakmp.c, isakmp_inf.c: Original patch from Atis
@@ -147,48 +1087,125 @@
 
 2008-07-02  Yvan Vanhullebus <vanhu@netasq.com>
 
-	* src/racoon/isakmp_inf.c: From Timo Teras: fixed some %d to %zu
-	  (size_t values).
+	* src/racoon/isakmp_inf.c: From Timo Teras: fix some %d to %zu
+	  (size_t values)
+
+2008-06-18  Thomas Klausner <wiz@netbsd.org>
+
+	* src/racoon/racoonctl.8: Bump date for previous.
 
 2008-06-18  Matthew Grooms <mgrooms@shrew.net>
 
-	* src/racoon/: grabmyaddr.c, admin.c, ipsec_doi.c, isakmp.c,
-	  isakmp_cfg.c, isakmp_inf.c, remoteconf.c: Use utility functions
-	  to evaluate and manipulate network port values. No functional
-	  changes. Submitted by Timo Teras.
+	* src/racoon/: admin.c, admin.h, racoonctl.8, racoonctl.c: Add an
+	  admin port command to retrieve the peer certificate. Submitted by
+	  Timo Teras.
+
+	* src/racoon/: admin.c, grabmyaddr.c, isakmp.c, misc.c, misc.h: Set
+	  sockets to be closed on exec to avoid potential file descriptor
+	  inheritance issues. Submitted by Timo Teras.
+
+	* src/racoon/: admin.c, grabmyaddr.c, ipsec_doi.c, isakmp.c,
+	  isakmp_cfg.c, isakmp_inf.c, privsep.c, remoteconf.c: Use utility
+	  functions to evaluate and manipulate network port values. No
+	  functional changes. Submitted by Timo Teras.
+
+	* src/racoon/: admin.c, racoonctl.c: Admin port code cleanup. No
+	  functional changes. Submitted by Timo Teras.
+
+	* src/racoon/pfkey.c: Correct a phase2 status event. Submitted by
+	  Timo Teras.
+
+2008-05-24  Christos Zoulas <christos@netbsd.org>
+
+	* src/racoon/privsep.c: Coverity CID 5018: Fix double frees.
+
+2008-05-08  Emmanuel Dreyfus <manu@netbsd.org>
+
+	* configure.ac: From Christian Hohnstaedt: allow out of tree
+	  building
+
+2008-04-30  Martin Husemann <martin@netbsd.org>
+
+	* netbsd-import.sh: Convert TNF licenses to new 2 clause variant
 
 2008-04-25  Yvan Vanhullebus <vanhu@netasq.com>
 
 	* src/racoon/isakmp_inf.c: From Timo Teras: extract port numbers
 	  from SADB_X_EXT_NAT_T[SD]PORT if present in purge_ipsec_spi().
 
+2008-04-13  Christos Zoulas <christos@netbsd.org>
+
+	* src/racoon/privsep.c: for symmetry set controllen the same way we
+	  set it on the receiving side.
+
+2008-04-02  Emmanuel Dreyfus <manu@netbsd.org>
+
+	* src/racoon/: Makefile.am, sockmisc.c, sockmisc.h: fix Linux build
+
+2008-03-28  Christos Zoulas <christos@netbsd.org>
+
+	* src/racoon/privsep.c: properly fix the variable stack allocation
+	  code.
+
+2008-03-28  Emmanuel Dreyfus <manu@netbsd.org>
+
+	* src/racoon/privsep.c: Still from Cyrus Rahman: fix file
+	  descriptor leak introduced by previous commit.
+
+	* src/racoon/: Makefile.am, isakmp.c, isakmp_inf.c, privsep.c,
+	  privsep.h, sockmisc.c, doc/README.privsep: From Cyrus Rahman:
+	  Allow interface reconfiguration when running in privilege separation
+	  mode, document privilege separation
+
 2008-03-06  Yvan Vanhullebus <vanhu@netasq.com>
 
 	* src/racoon/oakley.c: Generates a log if cert validation has been
 	  disabled by configuration
 
+2008-03-06  Emmanuel Dreyfus <manu@netbsd.org>
+
+	* src/racoon/: privsep.c, session.c: From Cyrus Rahman
+	  <crahman@gmail.com> privilegied instance exit when unprivilegied one
+	  terminates. Save PID in real root, not in chroot
+
+2008-03-06  Matthew Grooms <mgrooms@shrew.net>
+
+	* src/racoon/: admin.c, isakmp.c, isakmp_var.h, pfkey.c,
+	  racoonctl.8, racoonctl.c: Add the ability to initiate IPsec SA
+	  negotiations using the admin socket.  Submitted by Timo Teras.
+
+	* src/racoon/: admin.c, admin.h, evt.c, evt.h, handler.c,
+	  handler.h, isakmp.c, isakmp_agg.c, isakmp_base.c, isakmp_cfg.c,
+	  isakmp_ident.c, isakmp_inf.c, isakmp_var.h, isakmp_xauth.c,
+	  racoonctl.8, racoonctl.c, session.c: Refactor admin socket event
+	  protocol to be less error prone. Backwards compatibility is
+	  provided. Submitted by Timo Teras.
+
 2008-03-05  Matthew Grooms <mgrooms@shrew.net>
 
 	* src/racoon/cfparse.y: Properly initialize the unity network
 	  struct to prevent erroneous protocol and port info from being
 	  transmitted.
 
-	* src/racoon/pfkey.c: Provide better handling for pfkey socket read
+	* src/racoon/: pfkey.c, pfkey.h, session.c: Reload SPD on SIGHUP or
+	  adminport reload. Also provide better handling for pfkey socket read
 	  errors. Submitted by Timo Teras.
 
 2008-02-25  Emmanuel Dreyfus <manu@netbsd.org>
 
-	* src/racoon/ipsec_doi.c: From Brian Haley <brian.haley@hp.com>:
+	* src/racoon/ipsec_doi.c: From Brian Haley <brian.haley@hp.com>
 	  There's a cut/paste error in cmp_aproppair_i(), it's supposed to be
 	  checking spi_size but it's not.  I'm not sure this patch is correct,
 	  but what's there isn't either.
 
-	  Add fogotten entry in ChangeLog
-
 2008-02-22  Emmanuel Dreyfus <manu@netbsd.org>
 
-	* src/racoon/isakmp.c: Fix bad address length computation, from
-	  Brian Haley.
+	* src/racoon/isakmp.c: Fix address length, from Brian Haley
+
+2008-02-10  S.P.Zeidler <spz@netbsd.org>
+
+	* src/racoon/ipsec_doi.c: closes PR bin/37644 did not meet violent
+	  opposition ( :) ) on ipsec-tools-devel
 
 2008-01-11  Yvan Vanhullebus <vanhu@netasq.com>
 
@@ -208,12 +1225,58 @@
 	* src/racoon/: handler.c, handler.h: added an 'established' arg to
 	  getph1byaddr()
 
+2007-12-31  Matthew Grooms <mgrooms@shrew.net>
+
+	* src/racoon/: policy.c, racoonctl.8, racoonctl.c: Add GRE protocol
+	  number to racoonctl. Correct id wildcard matching for transport
+	  mode. Submitted by Timo Teras.
+
+2007-12-12  Matthew Grooms <mgrooms@shrew.net>
+
+	* NEWS, src/racoon/isakmp_quick.c: Add corrections submitted in a
+	  follow up patch for the nat-t oa support.
+
+	* src/racoon/: handler.c, handler.h, isakmp_quick.c, pfkey.c: Add
+	  support for nat-t oa payload handling. Submitted by Timo Teras.
+
+2007-12-04  Matthew Grooms <mgrooms@shrew.net>
+
+	* src/racoon/: ipsec_doi.c, ipsec_doi.h, isakmp_quick.c: Modify
+	  ipsecdoi_sockaddr2id() to obtain an id without specifying the exact
+	  prefix length. Correct a memory leak in phase2. Both submitted by
+	  Timo Teras.
+
+2007-12-01  Thomas Klausner <wiz@netbsd.org>
+
+	* src/racoon/racoon.conf.5: Fix typos. New sentence, new line.
+
 2007-11-29  Yvan Vanhullebus <vanhu@netasq.com>
 
 	* src/racoon/Makefile.am: From Natanael Copa: fixed a race
 	  condition when building yacc stuff.
 
-2007-11-06  Yvan Vanhullebus <vanhu@netasq.com>
+2007-11-09  Yvan Vanhullebus <vanhu@netasq.com>
+
+	* src/racoon/pfkey.c: From Arnaud Ebalard: Some sanity checking in
+	  pk_recv()
+
+	* src/racoon/policy.c: From Arnaud Ebalard: Better matching of SPD
+	  entries in getsp_r().
+
+	* src/racoon/isakmp_quick.c: From Arnaud Ebalard: Added some debug
+	  in get_proposal_r().
+
+2007-10-19  Emmanuel Dreyfus <manu@netbsd.org>
+
+	* src/racoon/: isakmp_cfg.c, isakmp_unity.c, isakmp_unity.h,
+	  racoon.conf.5: Add SPLITNET_{INCLUDR_LOCAL}_CIDR to hook scripts
+
+2007-10-15  Yvan Vanhullebus <vanhu@netasq.com>
+
+	* src/libipsec/pfkey.c: Try to increase the buffer size of the
+	  pfkey socket, this may help things when we have a huge SPD
+
+2007-10-02  Yvan Vanhullebus <vanhu@netasq.com>
 
 	* src/racoon/crypto_openssl.c: From Scott Lamb: include plog.h to
 	  work with the new plog macro.
@@ -223,34 +1286,53 @@
 
 	* src/racoon/: plog.c, plog.h: From Scott Lamb: new plog macro.
 
-2007-10-15  Yvan Vanhullebus <vanhu@netasq.com>
-
-	* src/libipsec/pfkey.c: Try to increase the buffer size of the
-	  pfkey socket, this may help things when we have a huge SPD
-
 2007-09-19  Matthew Grooms <mgrooms@shrew.net>
 
+	* src/racoon/isakmp.c: Set REUSE option on sockets to prevent
+	  failures associated with closing and immediately re-opening.
+	  Submitted by Gabriel Somlo.
+
+	* src/racoon/isakmp_unity.c: Prevent duplicate entries in splitnet
+	  list. Submitted by Gabriel Somlo.
+
+2007-09-13  Matthew Grooms <mgrooms@shrew.net>
+
 	* configure.ac: Fix autoconf check for selinux support. Submitted
 	  by Joy Latten.
 
+2007-09-12  Matthew Grooms <mgrooms@shrew.net>
+
+	* src/racoon/: cfparse.y, cftoken.l, handler.c, isakmp_quick.c,
+	  pfkey.c, racoon.conf.5, sainfo.c, sainfo.h: Implement clientaddr
+	  sainfo remote id option and refine the sainfo man page syntax.
+
+2007-09-05  Matthew Grooms <mgrooms@shrew.net>
+
+	* src/racoon/sainfo.c: Sort sainfo sections on insert and improve
+	  matching logic.
+
 2007-09-03  Matthew Grooms <mgrooms@shrew.net>
 
 	* src/racoon/: cftoken.l, racoon.conf.5: Correct the syntax for
 	  wins4 in the man page and add nbns4 as an alias. Pointed out by
 	  Claas Langbehn.
 
-2007-08-09  tag ipsec-tools-0_7
-
-2007-08-09  Matthew Grooms <mgrooms@shrew.net>
-
-	* NEWS, configure.ac: Prepare for 0.7 release tag.
-
 2007-08-07  Emmanuel Dreyfus <manu@netbsd.org>
 
-	* src/racoon/isakmp_xauth.c: Don't mix up RADIUS authentication and
-	  authorization ports. Allow interoperability with freeradius
+	* src/racoon/isakmp_xauth.c: src/racoon/isakmp_xauth.c: Don't mix
+	  up RADIUS authentication and authorization ports. Allow
+	  interoperability with freeradius
 
-2007-08-01  Yvan Vanhullebus <vanhu@netasq.com>
+2007-07-24  Matthew Grooms <mgrooms@shrew.net>
+
+	* NEWS: Update NEWS file with additional 0.7 improvements.
+
+2007-07-18  Matthew Grooms <mgrooms@shrew.net>
+
+	* src/racoon/racoon.conf.5: Various racoon configuration manpage
+	  updates.
+
+2007-07-18  Yvan Vanhullebus <vanhu@netasq.com>
 
 	* configure.ac, src/libipsec/ipsec_dump_policy.c,
 	  src/libipsec/ipsec_get_policylen.c,
@@ -269,58 +1351,50 @@
 	  src/setkey/token.l: use a single PATH_IPSEC_H to fix some
 	  path_to_ipsec.h issues
 
-2007-07-24  Matthew Grooms <mgrooms@shrew.net>
-
-	* NEWS: Update NEWS file with additional 0.7 improvements.
-
-2007-07-18  Matthew Grooms <mgrooms@shrew.net>
-
-	* src/racoon/racoon.conf.5: Various racoon configuration manpage
-	  updates.
-
 2007-07-16  Yvan Vanhullebus <vanhu@netasq.com>
 
 	* src/racoon/grabmyaddr.c: fixed a socket leak
 
-2007-06-12  tag ipsec-tools-0_7-RC1
-
-2007-06-12  tag ipsec-tools-0_7-rc1
-
-2007-06-12  Emmanuel Dreyfus <manu@netbsd.org>
-
-	* configure.ac: ipsec-tools used to use tags in lower case
-
-2007-06-12  Yvan Vanhullebus <vanhu@netasq.com>
-
-	* configure.ac: 0.7-RC1
+	* src/racoon/proposal.c: indentation
 
 2007-06-07  Emmanuel Dreyfus <manu@netbsd.org>
 
-	* src/racoon/: main.c, policy.h, security.c: From Joy Latten
-	  <latten@austin.ibm.com> Fix file descriptor shortage when using
-	  labeled IPsec.
-
 	* src/racoon/isakmp_cfg.c: From Paul Winder
-	  <Paul.Winder@tadpole.com> Fix ignored INTERNAL_DNS4_LIST
+	  <Paul.Winder@tadpole.com>: Fix ignored INTERNAL_DNS4_LIST
 
 2007-06-06  Yvan Vanhullebus <vanhu@netasq.com>
 
 	* src/racoon/: eaytest.c, var.h: From Rong-En Fan: fix compilation
 	  with gcc 4.2
 
-2007-06-06  Emmanuel Dreyfus <manu@netbsd.org>
-
-	* src/racoon/kmpstat.c: From Jianli Liu <jlliu@nortel.com>: Use the
-	  specified socket path instead of the default location
-
-2007-06-06  Yvan Vanhullebus <vanhu@netasq.com>
-
 	* src/racoon/session.c: From Jianli Liu: speed up interfaces update
 	  when they change.
 
 	* src/racoon/handler.c: ignore obsolete lifebyte when validating
 	  reloaded configuration
 
+2007-05-31  Emmanuel Dreyfus <manu@netbsd.org>
+
+	* src/racoon/: main.c, policy.h, security.c: From Joy Latten
+	  <latten@austin.ibm.com> Fix file descriptor shortage when using
+	  labeled IPsec.
+
+2007-05-30  Emmanuel Dreyfus <manu@netbsd.org>
+
+	* src/racoon/kmpstat.c: From Jianli Liu <jlliu@nortel.com>: In
+	  racoonctl, use the specified socket path instead of the default
+	  location
+
+2007-05-16  Christos Zoulas <christos@netbsd.org>
+
+	* src/racoon/cfparse.y: coverity CID 4168: yyerror() does not
+	  return, so we proceed to de-reference NULL. Make it return -1
+	  instead like in other places.
+
+	* src/racoon/cfparse.y: coverity CID 4170: yyerror() does not
+	  return, so we proceed to de-reference NULL. Make it return -1
+	  instead like in other places.
+
 2007-05-04  Yvan Vanhullebus <vanhu@netasq.com>
 
 	* src/racoon/handler.c: search a ph1 by address if iph2->ph1 is
@@ -345,18 +1419,17 @@
 	* src/racoon/oakley.c: dumps peer's ID and peer's certificate
 	  subject /subjectaltname if they don't match
 
-2007-03-29  tag ipsec-tools-0_7-beta3
-
-2007-03-29  Emmanuel Dreyfus <manu@netbsd.org>
-
-	* configure.ac: Bump to 0.7beta3
-
 2007-03-26  Yvan Vanhullebus <vanhu@netasq.com>
 
 	* src/racoon/isakmp_inf.c: Store the DPD main scheduler in ph1
 	  handler, to be able to cancel it when removing the handler, and some
 	  minor cleanups in DPD code
 
+2007-03-24  Christos Zoulas <christos@netbsd.org>
+
+	* src/racoon/isakmp_xauth.c: PR/36069: Huang Yushuo: racoon can't
+	  work with pam_group Set RUSER.
+
 2007-03-23  Yvan Vanhullebus <vanhu@netasq.com>
 
 	* src/racoon/: ipsec_doi.c, security.c: From Joy Latten: fix a
@@ -389,13 +1462,7 @@
 	* src/racoon/isakmp.c: Consider a negociation timeout when
 	  retry_counter is <=0 instead of < 0
 
-2007-03-06  tag ipsec-tools-0_7-beta2
-
-2007-03-06  Emmanuel Dreyfus <manu@netbsd.org>
-
-	* configure.ac: Bump to 0.7beta2
-
-2007-03-01  Matthew Grooms <mgrooms@shrew.net>
+2007-02-28  Matthew Grooms <mgrooms@shrew.net>
 
 	* src/racoon/ipsec_doi.c: Add logic to allow ip address ids to be
 	  matched to ip subnet ids when appropriate.
@@ -423,12 +1490,6 @@
 
 	* src/racoon/isakmp.c: Removed a debug printf....
 
-2007-02-16  tag ipsec-tools-0_7-beta1
-
-2007-02-16  Emmanuel Dreyfus <manu@netbsd.org>
-
-	* configure.ac: Bump to 0.7beta1
-
 2007-02-16  Yvan Vanhullebus <vanhu@netasq.com>
 
 	* src/racoon/ipsec_doi.c: From Olivier Warin: Fix a %zu in a
@@ -436,7 +1497,7 @@
 
 2007-02-15  Emmanuel Dreyfus <manu@netbsd.org>
 
-	* src/racoon/security.c: Missing file for SELinux
+	* src/racoon/security.c: Missing SELinux file
 
 	* configure.ac: Missing stuff for SELinux
 
@@ -460,6 +1521,20 @@
 	  deleted from payload instead of just deleting the ISAKMP SA used to
 	  protect the informational exchange.
 
+2006-12-26  Arnaud Lacombe <alc@netbsd.org>
+
+	* src/racoon/ipsec_doi.c: CID-4167: check for 'iph1->approval !=
+	  NULL'
+
+2006-12-23  Thomas Klausner <wiz@netbsd.org>
+
+	* src/racoon/racoon.conf.5: Use even more macros.
+
+	* src/racoon/racoon.conf.5: Use more macros.
+
+	* src/racoon/racoon.conf.5: Serial comma, and bump date for
+	  previous.
+
 2006-12-18  Yvan Vanhullebus <vanhu@netasq.com>
 
 	* src/racoon/crypto_openssl.c: From Joy Latten: fix a memory leak
diff --git a/Makefile b/Makefile
index 52d3187..06e2a39 100644
--- a/Makefile
+++ b/Makefile
@@ -3,6 +3,10 @@
 	-Isrc/racoon -Isrc/racoon/missing -DHAVE_CONFIG_H -lcrypto \
 	src/libipsec/pfkey.c \
 	src/libipsec/ipsec_strerror.c \
+	src/racoon/algorithm.c \
+	src/racoon/crypto_openssl.c \
+	src/racoon/genlist.c \
+	src/racoon/handler.c \
 	src/racoon/isakmp.c \
 	src/racoon/isakmp_agg.c \
 	src/racoon/isakmp_base.c \
@@ -11,21 +15,18 @@
 	src/racoon/isakmp_inf.c \
 	src/racoon/isakmp_newg.c \
 	src/racoon/isakmp_quick.c \
-	src/racoon/handler.c \
-	src/racoon/pfkey.c \
-	src/racoon/ipsec_doi.c \
-	src/racoon/oakley.c \
-	src/racoon/vendorid.c \
-	src/racoon/policy.c \
-	src/racoon/crypto_openssl.c \
-	src/racoon/algorithm.c \
-	src/racoon/proposal.c \
-	src/racoon/strnames.c \
-	src/racoon/schedule.c \
-	src/racoon/str2val.c \
-	src/racoon/genlist.c \
-	src/racoon/vmbuf.c \
-	src/racoon/sockmisc.c \
+	src/racoon/ipsec_doi-0.7.3.c \
 	src/racoon/nattraversal.c \
+	src/racoon/oakley.c \
+	src/racoon/pfkey.c \
+	src/racoon/policy.c \
+	src/racoon/proposal.c \
+	src/racoon/remoteconf.c \
+	src/racoon/schedule.c \
+	src/racoon/sockmisc.c \
+	src/racoon/str2val.c \
+	src/racoon/strnames.c \
+	src/racoon/vendorid.c \
+	src/racoon/vmbuf.c \
 	main.c \
 	setup.c
diff --git a/NEWS b/NEWS
index 29ce752..6193c65 100644
--- a/NEWS
+++ b/NEWS
@@ -1,36 +1,38 @@
 Version history:
 ----------------
+0.8	- 18 March 2011
+	o Fix authentication method ambiguity with kerberos and xauth
+	o RFC2253 compliant escaping of asn1dn identifiers (Cyrus Rahman)
+	o Local address code rewrite to speed things up
+	o Improved MIPv6 support (Arnaud Ebalard)
+	o ISAKMP SA (phase1) rekeying
+	o Improved scheduler (faster algorithm, support monotonic clock)
+	o Handle RESPONDER-LIFETIME in quick mode
+	o Handle INITIAL-CONTACT in from main mode too
+	o Rewritten event handling framework for admin port
+	o Ability to initiate IPsec SA through admin port
+	o NAT-T Original Address handling (transport mode NAT-T support)
+	o clean NAT-T - PFkey support
+	o support for multiple anonymous remoteconfs
+	o Remove various obsolete configuration options
+	o A lot of other bug fixes, performance improvements and clean ups
 
-0.7.3 - 23 August 2009
-	o Fix a remote crash and a memory leak
-	o Fixed a NAT-T flag check
-	o Some code cleanups/compilation fixes with recent gcc
-
-0.7.2 - 22 April 2009
-	o Fix a remote crash in fragmentation code
-	o Phase2 message identities are phase1 specific (Vista compatibility=
-	o Autogenerate ChangeLog from cvs metadata
-	o Fix mode config pool resizing
-	o NAT-T fixes related to purging of IPsec SA:s and retransmission
-	o Remove phase1 handler immediately if first exchange is bad
-	o A bunch of memory leak and possible memory corruptions (triggerable
-	  by bad configuration or startup parameters)
-
-0.7.1 - 23 July 2008
+0.7.1	- 23 July 2008
 	o Fixes a memory leak when invalid proposal received
 	o Some fixes in DPD
 	o do not set default gss id if xauth is used
 	o fixed hybrid enabled builds
 	o fixed compilation on FreeBSD8
 	o cleanup in network port value manipulation
-	o gets ports from SADB_X_EXT_NAT_T_[SD]PORT if present in purge_ipsec_spi()
-	o Generates a log if cert validation has been disabled by configuration
+	o Gets ports from SADB_X_EXT_NAT_T_[SD]PORT if present in
+	  purge_ipsec_spi()
+	o Generates a log if cert validation has been disabled by
+	  configuration
 	o better handling for pfkey socket read errors
 	o Fixes in yacc / bison stuff
 	o new plog() macro (reduced CPU usage when logging is disabled)
-	o Try to works better with huge SPD/SAD
+	o Try to work better with huge SPD/SAD
 	o Corrected modecfg option syntax
-	o Many other various fixes...
 
 0.7	- 09 August 2007
 	o Xauth with pre-shared key PSK
@@ -63,7 +65,7 @@
 	o ESP fragmentation in tunnel mode can be tunned (NetBSD only)
 	o racoon admin interface is exported (header and library) to 
 	  help building control programs for racoon (think GUI)
- 	o Fixed single DES support; single DES users MUST UPGRADE.
+	o Fixed single DES support; single DES users MUST UPGRADE.
 
 0.5	- 10 April 2005
 	o Rewritten buildsystem. Now completely autoconfed, automaked,
@@ -91,7 +93,7 @@
 	o All source files now have 3-clause BSD license.
 
 0.3	- 14 April 2004
-        o Fixed setkey to handle multiline commands again.
+	o Fixed setkey to handle multiline commands again.
 	o Added command 'exit' to setkey.
 	o Fixed racoon to only Warn if no CRL was found.
 	o Improved testsuite.
diff --git a/README b/README
index 2e4f90a..9623997 100644
--- a/README
+++ b/README
@@ -11,20 +11,27 @@
 IPsec-tools were ported to Linux from the KAME project 
 (http://www.kame.net) by Derek Atkins  <derek@ihtfp.com>.
 
-Currently the package is actively maintained and developed 
-by Michal Ludvig <mludvig@suse.cz>, Aidas Kasparas <a.kasparas@gmc.lt>
-Emmanuel Dreyfus <manu@netbsd.org>, VANHULLEBUS Yvan <vanhu@zeninc.net>,
-and Fred Senault <fred.letter@lacave.net>.
+Currently the package is actively maintained and developed by: 
+	Emmanuel Dreyfus <manu@netbsd.org>
+	VANHULLEBUS Yvan <vanhu@free.fr>
+	Matthew Grooms <mgrooms@shrew.net>
+	Timo Teräs <timo.teras@iki.fi>
 
 Sources can be found at the IPsec-Tools home page at:
 	http://ipsec-tools.sourceforge.net/
 
+And CVS repository is hosted at NetBSD tree:
+	cvs -danoncvs@anoncvs.netbsd.org:/cvsroot co ipsec-tools
+
+Bug reports and project wiki is located at:
+	https://trac.ipsec-tools.net/
+
 Please report any problems to the mailing list:
 	ipsec-tools-devel@lists.sourceforge.net
 	ipsec-tools-users@lists.sourceforge.net
 
 You can also browse the list archive:
-	http://sourceforge.net/mailarchive/forum.php?forum_id=32000
+	http://sf.net/mailarchive/forum.php?forum_name=ipsec-tools-devel
 
 Credits:
 	IHTFP Consulting, see http://www.ihtfp.com/
diff --git a/ThirdPartyProject.prop b/ThirdPartyProject.prop
index 6ec7936..9af3ed7 100644
--- a/ThirdPartyProject.prop
+++ b/ThirdPartyProject.prop
@@ -1,7 +1,7 @@
-# Copyright 2010 Google Inc. All Rights Reserved.
-#Fri Jul 16 10:03:09 PDT 2010
-currentVersion=0.7.3
-version=0.7.3 (unreleased)
+# Copyright 2011 Google Inc. All Rights Reserved.
+#Tue Jul  5 19:05:36 PDT 2011
+currentVersion=0.8.0
+version=0.8.0
 isNative=true
 name=ipsec-tools
 keywords=ipsec-tools
diff --git a/config.h b/config.h
index fd560d4..87099b5 100644
--- a/config.h
+++ b/config.h
@@ -21,4 +21,6 @@
 #define HAVE_SYS_TIME_H 1
 #define HAVE_UNISTD_H
 
+#define RETSIGTYPE void
+
 #define ANDROID_PATCHED
diff --git a/main.c b/main.c
index a123afb..c10e32b 100644
--- a/main.c
+++ b/main.c
@@ -16,56 +16,40 @@
 
 #include <stdio.h>
 #include <stdlib.h>
-#include <string.h>
 #include <stdarg.h>
 #include <signal.h>
+#include <poll.h>
+
+#ifdef ANDROID_CHANGES
 #include <unistd.h>
 #include <sys/types.h>
 #include <sys/socket.h>
-#include <sys/select.h>
-
-#ifdef ANDROID_CHANGES
-#include <sys/ioctl.h>
-#include <linux/if.h>
 #include <android/log.h>
 #include <cutils/sockets.h>
 #include <private/android_filesystem_config.h>
-#include "keystore_get.h"
 #endif
 
 #include "config.h"
-#include "libpfkey.h"
 #include "gcmalloc.h"
-#include "vmbuf.h"
-#include "crypto_openssl.h"
-#include "oakley.h"
-#include "pfkey.h"
+#include "session.h"
 #include "schedule.h"
-#include "isakmp_var.h"
-#include "nattraversal.h"
-#include "localconf.h"
-#include "sockmisc.h"
-#include "grabmyaddr.h"
 #include "plog.h"
-#include "admin.h"
-#include "privsep.h"
-#include "misc.h"
 
 #ifdef ANDROID_CHANGES
 
-static int get_control_and_arguments(int *argc, char ***argv)
+static void android_get_arguments(int *argc, char ***argv)
 {
     static char *args[32];
     int control;
     int i;
 
     if ((i = android_get_control_socket("racoon")) == -1) {
-        return -1;
+        return;
     }
     do_plog(LLV_DEBUG, "Waiting for control socket");
     if (listen(i, 1) == -1 || (control = accept(i, NULL, 0)) == -1) {
         do_plog(LLV_ERROR, "Cannot get control socket");
-        exit(-1);
+        exit(1);
     }
     close(i);
 
@@ -75,7 +59,7 @@
         if (recv(control, &bytes[0], 1, 0) != 1
             || recv(control, &bytes[1], 1, 0) != 1) {
             do_plog(LLV_ERROR, "Cannot get argument length");
-            exit(-1);
+            exit(1);
         } else {
             int length = bytes[0] << 8 | bytes[1];
             int offset = 0;
@@ -90,7 +74,7 @@
                     offset += n;
                 } else {
                     do_plog(LLV_ERROR, "Cannot get argument value");
-                    exit(-1);
+                    exit(1);
                 }
             }
             args[i][length] = 0;
@@ -100,38 +84,19 @@
 
     *argc = i;
     *argv = args;
-    return control;
-}
-
-static void bind_interface()
-{
-    struct ifreq ifreqs[64];
-    struct ifconf ifconf = {.ifc_len = sizeof(ifreqs), .ifc_req = ifreqs};
-    struct myaddrs *p = lcconf->myaddrs;
-
-    if (ioctl(p->sock, SIOCGIFCONF, &ifconf) == -1) {
-        do_plog(LLV_WARNING, "Cannot list interfaces");
-        return;
-    }
-
-    while (p) {
-        int i = ifconf.ifc_len / sizeof(struct ifreq) - 1;
-        while (i >= 0 && cmpsaddrwop(p->addr, &ifreqs[i].ifr_addr)) {
-            --i;
-        }
-        if (i < 0 || setsockopt(p->sock, SOL_SOCKET, SO_BINDTODEVICE,
-                                ifreqs[i].ifr_name, IFNAMSIZ) == -1) {
-            do_plog(LLV_WARNING, "Cannot bind socket %d to proper interface",
-                    p->sock);
-        }
-        p = p->next;
-    }
+    close(control);
 }
 
 #endif
 
 extern void setup(int argc, char **argv);
-int f_local = 0;
+
+static int monitor_count;
+static struct {
+    int (*callback)(void *ctx, int fd);
+    void *ctx;
+} monitors[10];
+static struct pollfd pollfds[10];
 
 static void terminate(int signal)
 {
@@ -145,69 +110,60 @@
 
 int main(int argc, char **argv)
 {
-    fd_set fdset;
-    int fdset_size;
-    struct myaddrs *p;
-#ifdef ANDROID_CHANGES
-    int control = get_control_and_arguments(&argc, &argv);
-#endif
+    do_plog(LLV_INFO, "ipsec-tools 0.8.0 (http://ipsec-tools.sf.net)\n");
 
     signal(SIGHUP, terminate);
     signal(SIGINT, terminate);
     signal(SIGTERM, terminate);
     signal(SIGPIPE, SIG_IGN);
-    setup(argc, argv);
-
-    do_plog(LLV_INFO, "ipsec-tools 0.7.3 (http://ipsec-tools.sf.net)\n");
     atexit(terminated);
 
-    eay_init();
-    oakley_dhinit();
-    compute_vendorids();
-    sched_init();
-
-    if (pfkey_init() < 0 || isakmp_init() < 0) {
-        exit(1);
-    }
-
-#ifdef ENABLE_NATT
-    natt_keepalive_init();
-#endif
-
 #ifdef ANDROID_CHANGES
-    bind_interface();
-    setuid(AID_VPN);
+/*    setuid(AID_VPN); */
+    android_get_arguments(&argc, &argv);
 #endif
-
-    FD_ZERO(&fdset);
-    FD_SET(lcconf->sock_pfkey, &fdset);
-    fdset_size = lcconf->sock_pfkey;
-    for (p = lcconf->myaddrs; p; p = p->next) {
-        FD_SET(p->sock, &fdset);
-        if (fdset_size < p->sock) {
-            fdset_size = p->sock;
-        }
-    }
-    ++fdset_size;
+    setup(argc, argv);
 
     while (1) {
-        fd_set readset = fdset;
-        struct timeval *timeout = schedular();
-        if (select(fdset_size, &readset, NULL, NULL, timeout) < 0) {
-            exit(1);
-        }
-        if (FD_ISSET(lcconf->sock_pfkey, &readset)) {
-            pfkey_handler();
-        }
-        for (p = lcconf->myaddrs; p; p = p->next) {
-            if (FD_ISSET(p->sock, &readset)) {
-                isakmp_handler(p->sock);
+        struct timeval *tv = schedular();
+        int timeout = tv->tv_sec * 1000 + tv->tv_usec / 1000 + 1;
+
+        if (poll(pollfds, monitor_count, timeout) > 0) {
+            int i;
+            for (i = 0; i < monitor_count; ++i) {
+                if (pollfds[i].revents & POLLHUP) {
+                    do_plog(LLV_ERROR, "fd %d is closed\n", pollfds[i].fd);
+                    exit(1);
+                }
+                if (pollfds[i].revents & POLLIN) {
+                    monitors[i].callback(monitors[i].ctx, pollfds[i].fd);
+                }
             }
         }
     }
     return 0;
 }
 
+/* session.h */
+
+void monitor_fd(int fd, int (*callback)(void *, int), void *ctx, int priority)
+{
+    if (fd < 0 || monitor_count == 10) {
+        do_plog(LLV_ERROR, "Cannot monitor fd");
+        exit(1);
+    }
+    monitors[monitor_count].callback = callback;
+    monitors[monitor_count].ctx = ctx;
+    pollfds[monitor_count].fd = fd;
+    pollfds[monitor_count].events = POLLIN;
+    ++monitor_count;
+}
+
+void unmonitor_fd(int fd)
+{
+    exit(1);
+}
+
 /* plog.h */
 
 void do_plog(int level, char *format, ...)
@@ -245,54 +201,3 @@
     }
     return output;
 }
-
-/* privsep.h */
-
-int privsep_pfkey_open()
-{
-    return pfkey_open();
-}
-
-void privsep_pfkey_close(int key)
-{
-    pfkey_close(key);
-}
-
-vchar_t *privsep_eay_get_pkcs1privkey(char *file)
-{
-    return eay_get_pkcs1privkey(file);
-}
-
-vchar_t *privsep_getpsk(const char *key, int size)
-{
-    vchar_t *p = NULL;
-    if (key && (p = vmalloc(size)) != NULL) {
-        memcpy(p->v, key, p->l);
-    }
-    return p;
-}
-
-int privsep_script_exec(char *script, int name, char * const *environ)
-{
-    return 0;
-}
-
-/* grabmyaddr.h */
-
-int getsockmyaddr(struct sockaddr *addr)
-{
-    struct myaddrs *p;
-    for (p = lcconf->myaddrs; p; p = p->next) {
-        if (cmpsaddrstrict(addr, p->addr) == 0) {
-            return p->sock;
-        }
-    }
-    return -1;
-}
-
-/* misc.h */
-
-int racoon_hexdump(void *data, size_t length)
-{
-    return 0;
-}
diff --git a/setup.c b/setup.c
index 8bbbf81..eb575ce 100644
--- a/setup.c
+++ b/setup.c
@@ -17,22 +17,29 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <unistd.h>
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <netinet/ip.h>
 #include <netdb.h>
+#include <fcntl.h>
 
 #include "config.h"
+#include "gcmalloc.h"
 #include "libpfkey.h"
 #include "var.h"
 #include "isakmp_var.h"
 #include "isakmp.h"
 #include "vmbuf.h"
+#include "crypto_openssl.h"
 #include "oakley.h"
 #include "ipsec_doi.h"
 #include "algorithm.h"
 #include "vendorid.h"
+#include "schedule.h"
+#include "pfkey.h"
+#include "nattraversal.h"
 #include "proposal.h"
 #include "sainfo.h"
 #include "localconf.h"
@@ -42,125 +49,24 @@
 #include "plog.h"
 #include "admin.h"
 #include "privsep.h"
+#include "misc.h"
 
-static struct myaddrs myaddrs[2];
-static struct etypes main_mode = { .type = ISAKMP_ETYPE_IDENT };
 static struct localconf localconf;
-static struct remoteconf remoteconf;
 static struct sainfo sainfo;
 static char *pre_shared_key;
-static struct sockaddr target;
+
+static char *interface;
+static struct sockaddr *target;
+static struct {
+    struct sockaddr *addr;
+    int fd;
+} myaddrs[2];
 
 struct localconf *lcconf = &localconf;
 char *script_names[SCRIPT_MAX + 1];
+int f_local = 0;
 
-static void set_default()
-{
-    localconf.myaddrs = &myaddrs[0];
-    localconf.port_isakmp = PORT_ISAKMP;
-    localconf.port_isakmp_natt = PORT_ISAKMP_NATT;
-    localconf.default_af = AF_INET;
-    localconf.pad_random = LC_DEFAULT_PAD_RANDOM;
-    localconf.pad_randomlen = LC_DEFAULT_PAD_RANDOM;
-    localconf.pad_strict = LC_DEFAULT_PAD_STRICT;
-    localconf.pad_excltail = LC_DEFAULT_PAD_EXCLTAIL;
-    localconf.retry_counter = 10;
-    localconf.retry_interval = 3;
-    localconf.count_persend = LC_DEFAULT_COUNT_PERSEND;
-    localconf.secret_size = LC_DEFAULT_SECRETSIZE;
-    localconf.retry_checkph1 = LC_DEFAULT_RETRY_CHECKPH1;
-    localconf.wait_ph2complete = LC_DEFAULT_WAIT_PH2COMPLETE;
-    localconf.natt_ka_interval = LC_DEFAULT_NATT_KA_INTERVAL;
-    localconf.pathinfo[LC_PATHTYPE_CERT] = "/";
-
-    remoteconf.etypes = &main_mode;
-    remoteconf.doitype = IPSEC_DOI;
-    remoteconf.sittype = IPSECDOI_SIT_IDENTITY_ONLY;
-    remoteconf.idvtype = IDTYPE_ADDRESS;
-    remoteconf.nonce_size = DEFAULT_NONCE_SIZE;
-
-    remoteconf.ike_frag = TRUE;
-    remoteconf.esp_frag = IP_MAXPACKET;
-    remoteconf.ini_contact = TRUE;
-    remoteconf.pcheck_level = PROP_CHECK_OBEY;
-    remoteconf.verify_identifier = FALSE;
-    remoteconf.verify_cert = TRUE;
-    remoteconf.getcert_method = ISAKMP_GETCERT_PAYLOAD;
-    remoteconf.certtype = ISAKMP_CERT_X509SIGN;
-    remoteconf.getcacert_method = ISAKMP_GETCERT_LOCALFILE;
-    remoteconf.cacerttype = ISAKMP_CERT_X509SIGN;
-    remoteconf.send_cert = TRUE;
-    remoteconf.send_cr = TRUE;
-    remoteconf.gen_policy = TRUE;
-    remoteconf.retry_counter = LC_DEFAULT_RETRY_COUNTER;
-    remoteconf.retry_interval = LC_DEFAULT_RETRY_INTERVAL;
-    remoteconf.nat_traversal = TRUE;
-    remoteconf.rsa_private = genlist_init();
-    remoteconf.rsa_public = genlist_init();
-    remoteconf.dpd = TRUE;
-    remoteconf.dpd_interval = 0;
-    remoteconf.dpd_retry = 5;
-    remoteconf.dpd_maxfails = 5;
-
-    sainfo.lifetime = IPSECDOI_ATTR_SA_LD_SEC_DEFAULT;
-    sainfo.lifebyte = IPSECDOI_ATTR_SA_LD_KB_MAX;
-}
-
-static void set_address(char *server, char *port)
-{
-    struct addrinfo hints = {
-        .ai_flags = AI_NUMERICSERV,
-#ifndef INET6
-        .ai_family = AF_INET,
-#else
-        .ai_family = AF_UNSPEC,
-#endif
-        .ai_socktype = SOCK_DGRAM,
-    };
-    struct addrinfo *r;
-
-    if (getaddrinfo(server, port, &hints, &r) != 0) {
-        do_plog(LLV_ERROR, "Cannot resolve server address\n");
-        exit(1);
-    }
-    if (r->ai_next) {
-        do_plog(LLV_WARNING, "Multiple server address found\n");
-    }
-    remoteconf.remote = dupsaddr(r->ai_addr);
-    freeaddrinfo(r);
-
-    myaddrs[0].addr = getlocaladdr(remoteconf.remote);
-    if (!myaddrs[0].addr) {
-        do_plog(LLV_ERROR, "Cannot get local address\n");
-        exit(1);
-    }
-}
-
-static void add_proposal(int auth, int hash, int encryption, int length)
-{
-    struct isakmpsa *p = calloc(1, sizeof(struct isakmpsa));
-    p->prop_no = 1;
-    p->lifetime = OAKLEY_ATTR_SA_LD_SEC_DEFAULT;
-    p->enctype = encryption;
-    p->encklen = length;
-    p->authmethod = auth;
-    p->hashtype = hash;
-    p->dh_group = OAKLEY_ATTR_GRP_DESC_MODP1024;
-    p->vendorid = VENDORID_UNKNOWN;
-    p->rmconf = &remoteconf;
-
-    if (!remoteconf.proposal) {
-      p->trns_no = 1;
-      remoteconf.proposal = p;
-    } else {
-        struct isakmpsa *q = remoteconf.proposal;
-        while (q->next) {
-            q = q->next;
-        }
-        p->trns_no = q->trns_no + 1;
-        q->next = p;
-    }
-}
+/*****************************************************************************/
 
 static void add_sainfo_algorithm(int class, int algorithm, int length)
 {
@@ -179,11 +85,71 @@
     }
 }
 
-static int match(struct sadb_address *address)
+static void set_globals(char *interfaze, char *server)
+{
+    struct addrinfo hints = {
+        .ai_flags = AI_NUMERICSERV,
+#ifndef INET6
+        .ai_family = AF_INET,
+#else
+        .ai_family = AF_UNSPEC,
+#endif
+        .ai_socktype = SOCK_DGRAM,
+    };
+    struct addrinfo *info;
+
+    if (getaddrinfo(server, "80", &hints, &info) != 0) {
+        do_plog(LLV_ERROR, "Cannot resolve address: %s\n", server);
+        exit(1);
+    }
+    if (info->ai_next) {
+        do_plog(LLV_WARNING, "Found multiple addresses. Use the first one.\n");
+    }
+    target = dupsaddr(info->ai_addr);
+    freeaddrinfo(info);
+
+    interface = interfaze;
+    myaddrs[0].addr = getlocaladdr(target);
+    if (!myaddrs[0].addr) {
+        do_plog(LLV_ERROR, "Cannot get local address\n");
+        exit(1);
+    }
+    set_port(target, 0);
+    set_port(myaddrs[0].addr, 0);
+    myaddrs[0].fd = -1;
+    myaddrs[1].addr = dupsaddr(myaddrs[0].addr);
+    myaddrs[1].fd = -1;
+
+    localconf.port_isakmp = PORT_ISAKMP;
+    localconf.port_isakmp_natt = PORT_ISAKMP_NATT;
+    localconf.default_af = AF_INET;
+    localconf.pad_random = LC_DEFAULT_PAD_RANDOM;
+    localconf.pad_randomlen = LC_DEFAULT_PAD_RANDOM;
+    localconf.pad_strict = LC_DEFAULT_PAD_STRICT;
+    localconf.pad_excltail = LC_DEFAULT_PAD_EXCLTAIL;
+    localconf.retry_counter = 10;
+    localconf.retry_interval = 3;
+    localconf.count_persend = LC_DEFAULT_COUNT_PERSEND;
+    localconf.secret_size = LC_DEFAULT_SECRETSIZE;
+    localconf.retry_checkph1 = LC_DEFAULT_RETRY_CHECKPH1;
+    localconf.wait_ph2complete = LC_DEFAULT_WAIT_PH2COMPLETE;
+    localconf.natt_ka_interval = LC_DEFAULT_NATT_KA_INTERVAL;
+
+    sainfo.lifetime = IPSECDOI_ATTR_SA_LD_SEC_DEFAULT;
+    sainfo.lifebyte = IPSECDOI_ATTR_SA_LD_KB_MAX;
+    add_sainfo_algorithm(algclass_ipsec_auth, IPSECDOI_ATTR_AUTH_HMAC_SHA1, 0);
+    add_sainfo_algorithm(algclass_ipsec_auth, IPSECDOI_ATTR_AUTH_HMAC_MD5, 0);
+    add_sainfo_algorithm(algclass_ipsec_enc, IPSECDOI_ESP_3DES, 0);
+    add_sainfo_algorithm(algclass_ipsec_enc, IPSECDOI_ESP_DES, 0);
+    add_sainfo_algorithm(algclass_ipsec_enc, IPSECDOI_ESP_AES, 128);
+}
+
+/*****************************************************************************/
+
+static int policy_match(struct sadb_address *address)
 {
     if (address) {
-        struct sockaddr *source = PFKEY_ADDR_SADDR(address);
-        return !cmpsaddrwop(source, &target);
+        return cmpsaddr(PFKEY_ADDR_SADDR(address), target) < CMPSADDR_MISMATCH;
     }
     return 0;
 }
@@ -213,8 +179,8 @@
         if (p->sadb_msg_errno || pfkey_align(p, q) || pfkey_check(q)) {
             continue;
         }
-        if (match((struct sadb_address *)q[SADB_EXT_ADDRESS_SRC]) ||
-            match((struct sadb_address *)q[SADB_EXT_ADDRESS_DST])) {
+        if (policy_match((struct sadb_address *)q[SADB_EXT_ADDRESS_SRC]) ||
+            policy_match((struct sadb_address *)q[SADB_EXT_ADDRESS_DST])) {
             p->sadb_msg_type = (p->sadb_msg_type == SADB_DUMP) ?
                                SADB_DELETE : SADB_X_SPDDELETE;
             p->sadb_msg_reserved = 0;
@@ -227,34 +193,68 @@
 }
 
 /* flush; spdflush;
- * spdadd local remote udp -P out ipsec esp/transport//require; */
-static void spdadd(struct sockaddr *local, struct sockaddr *remote)
+ * spdadd src dst protocol -P out ipsec esp/transport//require; OR
+ * spdadd src any protocol -P out ipsec esp/tunnel/local-remote/require; */
+static void spdadd(struct sockaddr *src, struct sockaddr *dst,
+        int protocol, struct sockaddr *local, struct sockaddr *remote)
 {
     struct __attribute__((packed)) {
         struct sadb_x_policy p;
         struct sadb_x_ipsecrequest q;
+        char addresses[sizeof(struct sockaddr_storage) * 2];
     } policy;
-    int prefix = (local->sa_family == AF_INET) ? sizeof(struct in_addr) * 8 :
-               sizeof(struct in6_addr) * 8;
-    int key = pfkey_open();
 
+    struct sockaddr_storage any = {
+#ifndef __linux__
+        .ss_len = src->sa_len,
+#endif
+        .ss_family = src->sa_family,
+    };
+
+    int src_prefix = (src->sa_family == AF_INET) ? 32 : 128;
+    int dst_prefix = src_prefix;
+    int length = 0;
+    int key;
+
+    /* Fill default values. */
     memset(&policy, 0, sizeof(policy));
-    policy.p.sadb_x_policy_len = PFKEY_UNIT64(sizeof(policy));
     policy.p.sadb_x_policy_exttype = SADB_X_EXT_POLICY;
     policy.p.sadb_x_policy_type = IPSEC_POLICY_IPSEC;
     policy.p.sadb_x_policy_dir = IPSEC_DIR_OUTBOUND;
 #ifdef HAVE_PFKEY_POLICY_PRIORITY
     policy.p.sadb_x_policy_priority = PRIORITY_DEFAULT;
 #endif
-    policy.q.sadb_x_ipsecrequest_len = sizeof(struct sadb_x_ipsecrequest);
     policy.q.sadb_x_ipsecrequest_proto = IPPROTO_ESP;
     policy.q.sadb_x_ipsecrequest_mode = IPSEC_MODE_TRANSPORT;
     policy.q.sadb_x_ipsecrequest_level = IPSEC_LEVEL_REQUIRE;
 
-    target = *remote;
+    /* Deal with tunnel mode. */
+    if (!dst) {
+        policy.q.sadb_x_ipsecrequest_mode = IPSEC_MODE_TUNNEL;
+        dst = (struct sockaddr *)&any;
+        dst_prefix = 0;
+
+        length = sysdep_sa_len(local);
+        memcpy(policy.addresses, local, length);
+        memcpy(&policy.addresses[length], remote, length);
+        length += length;
+
+        /* Use the source address to flush policies. */
+        racoon_free(target);
+        target = dupsaddr(src);
+    }
+
+    /* Fix lengths. */
+    length += sizeof(policy.q);
+    policy.q.sadb_x_ipsecrequest_len = length;
+    length += sizeof(policy.p);
+    policy.p.sadb_x_policy_len = PFKEY_UNIT64(length);
+
+    /* Always do a flush before adding the new policy. */
     flush();
-    if (pfkey_send_spdadd(key, local, prefix, remote, prefix, IPPROTO_UDP,
-                          (caddr_t)&policy, sizeof(policy), 0) <= 0) {
+    key = pfkey_open();
+    if (pfkey_send_spdadd(key, src, src_prefix, dst, dst_prefix, protocol,
+            (caddr_t)&policy, length, 0) <= 0) {
         do_plog(LLV_ERROR, "Cannot initialize SAD and SPD\n");
         exit(1);
     }
@@ -262,66 +262,135 @@
     atexit(flush);
 }
 
+/*****************************************************************************/
+
+static void add_proposal(struct remoteconf *remoteconf,
+        int auth, int hash, int encryption, int length)
+{
+    struct isakmpsa *p = racoon_calloc(1, sizeof(struct isakmpsa));
+    p->prop_no = 1;
+    p->lifetime = OAKLEY_ATTR_SA_LD_SEC_DEFAULT;
+    p->enctype = encryption;
+    p->encklen = length;
+    p->authmethod = auth;
+    p->hashtype = hash;
+    p->dh_group = OAKLEY_ATTR_GRP_DESC_MODP1024;
+    p->vendorid = VENDORID_UNKNOWN;
+
+    if (!remoteconf->proposal) {
+      p->trns_no = 1;
+      remoteconf->proposal = p;
+    } else {
+        struct isakmpsa *q = remoteconf->proposal;
+        while (q->next) {
+            q = q->next;
+        }
+        p->trns_no = q->trns_no + 1;
+        q->next = p;
+    }
+}
+
 void setup(int argc, char **argv)
 {
+    struct remoteconf *remoteconf;
     int auth;
-    if (argc != 4 && argc != 6) {
-        printf("Usage: %s server port pre-shared-key\n"
-               "       %s server port my-private-key my-cert ca-cert\n",
-               argv[0], argv[0]);
-        exit(0);
-    }
-    set_default();
 
-    /* Set local address and remote address. */
-    set_address(argv[1], argv[2]);
+    if (argc > 2) {
+        set_globals(argv[1], argv[2]);
 
-    /* Initialize SAD and SPD. */
-    spdadd(myaddrs[0].addr, remoteconf.remote);
-
-    /* Set local port and remote port. */
-    set_port(myaddrs[0].addr, localconf.port_isakmp);
-    set_port(remoteconf.remote, localconf.port_isakmp);
+        /* Initialize everything else. */
+        eay_init();
+        initrmconf();
+        oakley_dhinit();
+        compute_vendorids();
+        sched_init();
+        if (pfkey_init() < 0 || isakmp_init() < 0) {
+            exit(1);
+        }
 #ifdef ENABLE_NATT
-    myaddrs[0].next = &myaddrs[1];
-    myaddrs[1].addr = dupsaddr(myaddrs[0].addr);
-    set_port(myaddrs[1].addr, localconf.port_isakmp_natt);
-    myaddrs[1].udp_encap = 1;
+        natt_keepalive_init();
 #endif
 
-    /* Set authentication method. */
-    if (argc == 4) {
-        pre_shared_key = argv[3];
-        auth = OAKLEY_ATTR_AUTH_METHOD_PSKEY;
-    } else {
-        remoteconf.idvtype = IDTYPE_ASN1DN;
-        remoteconf.myprivfile = argv[3];
-        remoteconf.mycertfile = argv[4];
-        remoteconf.cacertfile = argv[5];
-        auth = OAKLEY_ATTR_AUTH_METHOD_RSASIG;
+        /* Create remote configuration. */
+        remoteconf = newrmconf();
+        remoteconf->etypes = racoon_calloc(1, sizeof(struct etypes));
+        remoteconf->etypes->type = ISAKMP_ETYPE_IDENT;
+        remoteconf->ike_frag = TRUE;
+        remoteconf->pcheck_level = PROP_CHECK_OBEY;
+        remoteconf->gen_policy = TRUE;
+        remoteconf->nat_traversal = TRUE;
+        remoteconf->remote = dupsaddr(target);
+        set_port(remoteconf->remote, localconf.port_isakmp);
     }
 
-    /* Create proposals. */
-    add_proposal(auth, OAKLEY_ATTR_HASH_ALG_SHA, OAKLEY_ATTR_ENC_ALG_3DES, 0);
-    add_proposal(auth, OAKLEY_ATTR_HASH_ALG_MD5, OAKLEY_ATTR_ENC_ALG_3DES, 0);
-    add_proposal(auth, OAKLEY_ATTR_HASH_ALG_SHA, OAKLEY_ATTR_ENC_ALG_DES, 0);
-    add_proposal(auth, OAKLEY_ATTR_HASH_ALG_MD5, OAKLEY_ATTR_ENC_ALG_DES, 0);
-    add_proposal(auth, OAKLEY_ATTR_HASH_ALG_SHA, OAKLEY_ATTR_ENC_ALG_AES, 128);
-    add_proposal(auth, OAKLEY_ATTR_HASH_ALG_MD5, OAKLEY_ATTR_ENC_ALG_AES, 128);
+    /* Set authentication method and credentials. */
+    if (argc == 6 && !strcmp(argv[3], "udppsk")) {
+        set_port(target, atoi(argv[4]));
+        spdadd(myaddrs[0].addr, target, IPPROTO_UDP, NULL, NULL);
+        pre_shared_key = argv[5];
+        remoteconf->idvtype = IDTYPE_ADDRESS;
+        auth = OAKLEY_ATTR_AUTH_METHOD_PSKEY;
+    } else if (argc == 8 && !strcmp(argv[3], "udprsa")) {
+        set_port(target, atoi(argv[4]));
+        spdadd(myaddrs[0].addr, target, IPPROTO_UDP, NULL, NULL);
+        remoteconf->myprivfile = argv[5];
+        remoteconf->mycertfile = argv[6];
+        remoteconf->cacertfile = argv[7];
+        remoteconf->idvtype = IDTYPE_ASN1DN;
+        auth = OAKLEY_ATTR_AUTH_METHOD_RSASIG;
+    } else {
+        printf("Usage: %s <interface> <server> [...],\n"
+               "    where [...] can be:\n"
+               "    udppsk <port> <pre-shared-key>\n"
+               "    udprsa <port> <my-private-key> <my-cert> <ca-cert>\n",
+               argv[0]);
+        exit(0);
+    }
 
-    /* Create sainfo algorithms. */
-    add_sainfo_algorithm(algclass_ipsec_auth, IPSECDOI_ATTR_AUTH_HMAC_SHA1, 0);
-    add_sainfo_algorithm(algclass_ipsec_auth, IPSECDOI_ATTR_AUTH_HMAC_MD5, 0);
-    add_sainfo_algorithm(algclass_ipsec_enc, IPSECDOI_ESP_3DES, 0);
-    add_sainfo_algorithm(algclass_ipsec_enc, IPSECDOI_ESP_DES, 0);
-    add_sainfo_algorithm(algclass_ipsec_enc, IPSECDOI_ESP_AES, 128);
+    /* Add proposals. */
+    add_proposal(remoteconf, auth,
+            OAKLEY_ATTR_HASH_ALG_SHA, OAKLEY_ATTR_ENC_ALG_3DES, 0);
+    add_proposal(remoteconf, auth,
+            OAKLEY_ATTR_HASH_ALG_MD5, OAKLEY_ATTR_ENC_ALG_3DES, 0);
+    add_proposal(remoteconf, auth,
+            OAKLEY_ATTR_HASH_ALG_SHA, OAKLEY_ATTR_ENC_ALG_DES, 0);
+    add_proposal(remoteconf, auth,
+            OAKLEY_ATTR_HASH_ALG_MD5, OAKLEY_ATTR_ENC_ALG_DES, 0);
+    add_proposal(remoteconf, auth,
+            OAKLEY_ATTR_HASH_ALG_SHA, OAKLEY_ATTR_ENC_ALG_AES, 128);
+    add_proposal(remoteconf, auth,
+            OAKLEY_ATTR_HASH_ALG_MD5, OAKLEY_ATTR_ENC_ALG_AES, 128);
+
+    /* Install remote configuration. */
+    insrmconf(remoteconf);
+
+    /* Create ISAKMP sockets. */
+    set_port(myaddrs[0].addr, localconf.port_isakmp);
+    myaddrs[0].fd = isakmp_open(myaddrs[0].addr, FALSE);
+    if (myaddrs[0].fd == -1) {
+        do_plog(LLV_ERROR, "Cannot create ISAKMP socket");
+        exit(1);
+    }
+#ifdef ENABLE_NATT
+    set_port(myaddrs[1].addr, localconf.port_isakmp_natt);
+    myaddrs[1].fd = isakmp_open(myaddrs[1].addr, TRUE);
+    if (myaddrs[1].fd == -1) {
+        do_plog(LLV_WARNING, "Cannot create ISAKMP socket for NAT-T");
+    }
+#endif
 }
 
+/*****************************************************************************/
+
 /* localconf.h */
 
 vchar_t *getpskbyaddr(struct sockaddr *addr)
 {
-    return privsep_getpsk(pre_shared_key, strlen(pre_shared_key));
+    vchar_t *p = NULL;
+    if (pre_shared_key && (p = vmalloc(strlen(pre_shared_key)))) {
+        memcpy(p->v, pre_shared_key, p->l);
+    }
+    return p;
 }
 
 vchar_t *getpskbyname(vchar_t *name)
@@ -334,56 +403,10 @@
     strncpy(path, name, length);
 }
 
-/* remoteconf.h */
-
-struct remoteconf *getrmconf(struct sockaddr *addr)
-{
-    return cmpsaddrwop(addr, remoteconf.remote) ? NULL : &remoteconf;
-}
-
-struct isakmpsa *dupisakmpsa(struct isakmpsa *sa)
-{
-    struct isakmpsa *p = NULL;
-    if (sa && (p = malloc(sizeof(struct isakmpsa)))) {
-        *p = *sa;
-        p->next = NULL;
-        if (sa->dhgrp) {
-            oakley_setdhgroup(sa->dh_group, &p->dhgrp);
-        }
-    }
-    return p;
-}
-
-void delisakmpsa(struct isakmpsa *sa)
-{
-    while (sa) {
-        struct isakmpsa *p = sa->next;
-        if (sa->dhgrp) {
-            oakley_dhgrp_free(sa->dhgrp);
-        }
-        free(sa);
-        sa = p;
-    }
-}
-
-struct etypes *check_etypeok(struct remoteconf *rmconf, uint8_t etype)
-{
-    struct etypes *p = rmconf->etypes;
-    while (p && etype != p->type) {
-        p = p->next;
-    }
-    return p;
-}
-
-struct remoteconf *foreachrmconf(rmconf_func_t function, void *data)
-{
-    return (*function)(&remoteconf, data);
-}
-
 /* sainfo.h */
 
 struct sainfo *getsainfo(const vchar_t *src, const vchar_t *dst,
-                         const vchar_t *peer, int remoteid)
+        const vchar_t *peer, const vchar_t *client, uint32_t remoteid)
 {
     return &sainfo;
 }
@@ -392,3 +415,63 @@
 {
     return "*";
 }
+
+/* privsep.h */
+
+int privsep_socket(int domain, int type, int protocol)
+{
+    int fd = socket(domain, type, protocol);
+    if ((domain == AF_INET || domain == AF_INET6) && setsockopt(
+            fd, SOL_SOCKET, SO_BINDTODEVICE, interface, strlen(interface))) {
+        do_plog(LLV_WARNING, "Cannot bind socket to %s", interface);
+    }
+    return fd;
+}
+
+int privsep_bind(int fd, const struct sockaddr *addr, socklen_t addrlen)
+{
+    return bind(fd, addr, addrlen);
+}
+
+vchar_t *privsep_eay_get_pkcs1privkey(char *file)
+{
+    return eay_get_pkcs1privkey(file);
+}
+
+int privsep_script_exec(char *script, int name, char * const *environ)
+{
+    return 0;
+}
+
+/* grabmyaddr.h */
+
+int myaddr_getsport(struct sockaddr *addr)
+{
+    return 0;
+}
+
+int myaddr_getfd(struct sockaddr *addr)
+{
+#ifdef ENABLE_NATT
+    if (myaddrs[1].fd != -1 &&
+            cmpsaddr(addr, myaddrs[1].addr) == CMPSADDR_MATCH) {
+        return myaddrs[1].fd;
+    }
+#endif
+    if (cmpsaddr(addr, myaddrs[0].addr) < CMPSADDR_MISMATCH) {
+        return myaddrs[0].fd;
+    }
+    return -1;
+}
+
+/* misc.h */
+
+int racoon_hexdump(void *data, size_t length)
+{
+    return 0;
+}
+
+void close_on_exec(int fd)
+{
+    fcntl(fd, F_SETFD, FD_CLOEXEC);
+}
diff --git a/src/include-glibc/Makefile.in b/src/include-glibc/Makefile.in
index 842728e..d92fdf6 100644
--- a/src/include-glibc/Makefile.in
+++ b/src/include-glibc/Makefile.in
@@ -1,8 +1,9 @@
-# Makefile.in generated by automake 1.10.1 from Makefile.am.
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
 # @configure_input@
 
 # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
-# 2003, 2004, 2005, 2006, 2007, 2008  Free Software Foundation, Inc.
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009  Free Software Foundation,
+# Inc.
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
 # with or without modifications, as long as this notice is preserved.
@@ -15,8 +16,9 @@
 @SET_MAKE@
 VPATH = @srcdir@
 pkgdatadir = $(datadir)/@PACKAGE@
-pkglibdir = $(libdir)/@PACKAGE@
 pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
 am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
 install_sh_DATA = $(install_sh) -c -m 644
 install_sh_PROGRAM = $(install_sh) -c
@@ -41,6 +43,7 @@
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/config.h
 CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
 SOURCES =
 DIST_SOURCES =
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
@@ -58,23 +61,18 @@
 CPP = @CPP@
 CPPFLAGS = @CPPFLAGS@
 CRYPTOBJS = @CRYPTOBJS@
-CXX = @CXX@
-CXXCPP = @CXXCPP@
-CXXDEPMODE = @CXXDEPMODE@
-CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
 DEFS = @DEFS@
 DEPDIR = @DEPDIR@
 DSYMUTIL = @DSYMUTIL@
-ECHO = @ECHO@
+DUMPBIN = @DUMPBIN@
 ECHO_C = @ECHO_C@
 ECHO_N = @ECHO_N@
 ECHO_T = @ECHO_T@
 EGREP = @EGREP@
 EXEEXT = @EXEEXT@
 EXTRA_CRYPTO = @EXTRA_CRYPTO@
-F77 = @F77@
-FFLAGS = @FFLAGS@
+FGREP = @FGREP@
 FRAG_OBJS = @FRAG_OBJS@
 GLIBC_BUGS = @GLIBC_BUGS@
 GREP = @GREP@
@@ -88,6 +86,7 @@
 INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
 KERNEL_INCLUDE = @KERNEL_INCLUDE@
 KRB5_CONFIG = @KRB5_CONFIG@
+LD = @LD@
 LDFLAGS = @LDFLAGS@
 LEX = @LEX@
 LEXLIB = @LEXLIB@
@@ -95,18 +94,24 @@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
 LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
 LN_S = @LN_S@
 LTLIBOBJS = @LTLIBOBJS@
 MAKEINFO = @MAKEINFO@
 MKDIR_P = @MKDIR_P@
 NATT_OBJS = @NATT_OBJS@
+NM = @NM@
 NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
 OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
 PACKAGE = @PACKAGE@
 PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
 PACKAGE_NAME = @PACKAGE_NAME@
 PACKAGE_STRING = @PACKAGE_STRING@
 PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
 PACKAGE_VERSION = @PACKAGE_VERSION@
 PATH_SEPARATOR = @PATH_SEPARATOR@
 RANLIB = @RANLIB@
@@ -124,8 +129,7 @@
 abs_top_builddir = @abs_top_builddir@
 abs_top_srcdir = @abs_top_srcdir@
 ac_ct_CC = @ac_ct_CC@
-ac_ct_CXX = @ac_ct_CXX@
-ac_ct_F77 = @ac_ct_F77@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
 am__include = @am__include@
 am__leading_dot = @am__leading_dot@
 am__quote = @am__quote@
@@ -157,6 +161,7 @@
 libexecdir = @libexecdir@
 localedir = @localedir@
 localstatedir = @localstatedir@
+lt_ECHO = @lt_ECHO@
 mandir = @mandir@
 mkdir_p = @mkdir_p@
 oldincludedir = @oldincludedir@
@@ -169,6 +174,7 @@
 srcdir = @srcdir@
 sysconfdir = @sysconfdir@
 target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
 EXTRA_DIST = \
@@ -185,14 +191,14 @@
 	@for dep in $?; do \
 	  case '$(am__configure_deps)' in \
 	    *$$dep*) \
-	      cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
-		&& exit 0; \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
 	      exit 1;; \
 	  esac; \
 	done; \
-	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign  src/include-glibc/Makefile'; \
-	cd $(top_srcdir) && \
-	  $(AUTOMAKE) --foreign  src/include-glibc/Makefile
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/include-glibc/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign src/include-glibc/Makefile
 .PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
@@ -210,6 +216,7 @@
 	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
 $(ACLOCAL_M4):  $(am__aclocal_m4_deps)
 	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
 
 mostlyclean-libtool:
 	-rm -f *.lo
@@ -239,13 +246,17 @@
 	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
 	  if test -d $$d/$$file; then \
 	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
-	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
-	      cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
 	    fi; \
-	    cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
 	  else \
-	    test -f $(distdir)/$$file \
-	    || cp -p $$d/$$file $(distdir)/$$file \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
 	    || exit 1; \
 	  fi; \
 	done
@@ -273,6 +284,7 @@
 
 distclean-generic:
 	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
 	-test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)
 
 maintainer-clean-generic:
@@ -292,6 +304,8 @@
 
 html: html-am
 
+html-am:
+
 info: info-am
 
 info-am:
@@ -300,18 +314,28 @@
 
 install-dvi: install-dvi-am
 
+install-dvi-am:
+
 install-exec-am:
 
 install-html: install-html-am
 
+install-html-am:
+
 install-info: install-info-am
 
+install-info-am:
+
 install-man:
 
 install-pdf: install-pdf-am
 
+install-pdf-am:
+
 install-ps: install-ps-am
 
+install-ps-am:
+
 installcheck-am:
 
 maintainer-clean: maintainer-clean-am
@@ -351,6 +375,7 @@
 	touch .includes
 
 all: .includes
+
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
 .NOEXPORT:
diff --git a/src/libipsec/Makefile.in b/src/libipsec/Makefile.in
index 748877a..cd0993b 100644
--- a/src/libipsec/Makefile.in
+++ b/src/libipsec/Makefile.in
@@ -1,8 +1,9 @@
-# Makefile.in generated by automake 1.10.1 from Makefile.am.
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
 # @configure_input@
 
 # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
-# 2003, 2004, 2005, 2006, 2007, 2008  Free Software Foundation, Inc.
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009  Free Software Foundation,
+# Inc.
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
 # with or without modifications, as long as this notice is preserved.
@@ -17,8 +18,9 @@
 
 VPATH = @srcdir@
 pkgdatadir = $(datadir)/@PACKAGE@
-pkglibdir = $(libdir)/@PACKAGE@
 pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
 am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
 install_sh_DATA = $(install_sh) -c -m 644
 install_sh_PROGRAM = $(install_sh) -c
@@ -45,15 +47,30 @@
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/config.h
 CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
 am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
 am__vpath_adj = case $$p in \
     $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
     *) f=$$p;; \
   esac;
-am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+  srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+  for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+  for p in $$list; do echo "$$p $$p"; done | \
+  sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+  $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+    if (++n[$$2] == $(am__install_max)) \
+      { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+    END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+  sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+  sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
 am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(man3dir)" \
 	"$(DESTDIR)$(libipsecdir)"
-libLTLIBRARIES_INSTALL = $(INSTALL)
 LTLIBRARIES = $(lib_LTLIBRARIES)
 am__DEPENDENCIES_1 =
 libipsec_la_DEPENDENCIES = $(am__DEPENDENCIES_1)
@@ -67,6 +84,7 @@
 DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
 depcomp = $(SHELL) $(top_srcdir)/depcomp
 am__depfiles_maybe = depfiles
+am__mv = mv -f
 COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
 	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
 LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
@@ -88,7 +106,6 @@
 man3dir = $(mandir)/man3
 NROFF = nroff
 MANS = $(man3_MANS)
-libipsecHEADERS_INSTALL = $(INSTALL_HEADER)
 HEADERS = $(libipsec_HEADERS) $(noinst_HEADERS)
 ETAGS = etags
 CTAGS = ctags
@@ -107,23 +124,18 @@
 CPP = @CPP@
 CPPFLAGS = @CPPFLAGS@
 CRYPTOBJS = @CRYPTOBJS@
-CXX = @CXX@
-CXXCPP = @CXXCPP@
-CXXDEPMODE = @CXXDEPMODE@
-CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
 DEFS = @DEFS@
 DEPDIR = @DEPDIR@
 DSYMUTIL = @DSYMUTIL@
-ECHO = @ECHO@
+DUMPBIN = @DUMPBIN@
 ECHO_C = @ECHO_C@
 ECHO_N = @ECHO_N@
 ECHO_T = @ECHO_T@
 EGREP = @EGREP@
 EXEEXT = @EXEEXT@
 EXTRA_CRYPTO = @EXTRA_CRYPTO@
-F77 = @F77@
-FFLAGS = @FFLAGS@
+FGREP = @FGREP@
 FRAG_OBJS = @FRAG_OBJS@
 GLIBC_BUGS = @GLIBC_BUGS@
 GREP = @GREP@
@@ -137,6 +149,7 @@
 INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
 KERNEL_INCLUDE = @KERNEL_INCLUDE@
 KRB5_CONFIG = @KRB5_CONFIG@
+LD = @LD@
 LDFLAGS = @LDFLAGS@
 LEX = @LEX@
 LEXLIB = @LEXLIB@
@@ -144,18 +157,24 @@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
 LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
 LN_S = @LN_S@
 LTLIBOBJS = @LTLIBOBJS@
 MAKEINFO = @MAKEINFO@
 MKDIR_P = @MKDIR_P@
 NATT_OBJS = @NATT_OBJS@
+NM = @NM@
 NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
 OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
 PACKAGE = @PACKAGE@
 PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
 PACKAGE_NAME = @PACKAGE_NAME@
 PACKAGE_STRING = @PACKAGE_STRING@
 PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
 PACKAGE_VERSION = @PACKAGE_VERSION@
 PATH_SEPARATOR = @PATH_SEPARATOR@
 RANLIB = @RANLIB@
@@ -173,8 +192,7 @@
 abs_top_builddir = @abs_top_builddir@
 abs_top_srcdir = @abs_top_srcdir@
 ac_ct_CC = @ac_ct_CC@
-ac_ct_CXX = @ac_ct_CXX@
-ac_ct_F77 = @ac_ct_F77@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
 am__include = @am__include@
 am__leading_dot = @am__leading_dot@
 am__quote = @am__quote@
@@ -206,6 +224,7 @@
 libexecdir = @libexecdir@
 localedir = @localedir@
 localstatedir = @localstatedir@
+lt_ECHO = @lt_ECHO@
 mandir = @mandir@
 mkdir_p = @mkdir_p@
 oldincludedir = @oldincludedir@
@@ -218,6 +237,7 @@
 srcdir = @srcdir@
 sysconfdir = @sysconfdir@
 target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
 
@@ -262,14 +282,14 @@
 	@for dep in $?; do \
 	  case '$(am__configure_deps)' in \
 	    *$$dep*) \
-	      cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
-		&& exit 0; \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
 	      exit 1;; \
 	  esac; \
 	done; \
-	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign  src/libipsec/Makefile'; \
-	cd $(top_srcdir) && \
-	  $(AUTOMAKE) --foreign  src/libipsec/Makefile
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/libipsec/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign src/libipsec/Makefile
 .PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
@@ -287,23 +307,28 @@
 	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
 $(ACLOCAL_M4):  $(am__aclocal_m4_deps)
 	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
 install-libLTLIBRARIES: $(lib_LTLIBRARIES)
 	@$(NORMAL_INSTALL)
 	test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)"
-	@list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+	@list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+	list2=; for p in $$list; do \
 	  if test -f $$p; then \
-	    f=$(am__strip_dir) \
-	    echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(libdir)/$$f'"; \
-	    $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(libdir)/$$f"; \
+	    list2="$$list2 $$p"; \
 	  else :; fi; \
-	done
+	done; \
+	test -z "$$list2" || { \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \
+	}
 
 uninstall-libLTLIBRARIES:
 	@$(NORMAL_UNINSTALL)
-	@list='$(lib_LTLIBRARIES)'; for p in $$list; do \
-	  p=$(am__strip_dir) \
-	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$p'"; \
-	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$p"; \
+	@list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+	for p in $$list; do \
+	  $(am__strip_dir) \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \
 	done
 
 clean-libLTLIBRARIES:
@@ -339,21 +364,21 @@
 
 .c.o:
 @am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
-@am__fastdepCC_TRUE@	mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(COMPILE) -c $<
 
 .c.obj:
 @am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
-@am__fastdepCC_TRUE@	mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(COMPILE) -c `$(CYGPATH_W) '$<'`
 
 .c.lo:
 @am__fastdepCC_TRUE@	$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
-@am__fastdepCC_TRUE@	mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(LTCOMPILE) -c -o $@ $<
@@ -369,82 +394,74 @@
 
 clean-libtool:
 	-rm -rf .libs _libs
-install-man3: $(man3_MANS) $(man_MANS)
+install-man3: $(man3_MANS)
 	@$(NORMAL_INSTALL)
 	test -z "$(man3dir)" || $(MKDIR_P) "$(DESTDIR)$(man3dir)"
-	@list='$(man3_MANS) $(dist_man3_MANS) $(nodist_man3_MANS)'; \
-	l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
-	for i in $$l2; do \
-	  case "$$i" in \
-	    *.3*) list="$$list $$i" ;; \
-	  esac; \
+	@list='$(man3_MANS)'; test -n "$(man3dir)" || exit 0; \
+	{ for i in $$list; do echo "$$i"; done; \
+	} | while read p; do \
+	  if test -f $$p; then d=; else d="$(srcdir)/"; fi; \
+	  echo "$$d$$p"; echo "$$p"; \
+	done | \
+	sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^3][0-9a-z]*$$,3,;x' \
+	      -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \
+	sed 'N;N;s,\n, ,g' | { \
+	list=; while read file base inst; do \
+	  if test "$$base" = "$$inst"; then list="$$list $$file"; else \
+	    echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man3dir)/$$inst'"; \
+	    $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man3dir)/$$inst" || exit $$?; \
+	  fi; \
 	done; \
-	for i in $$list; do \
-	  if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
-	  else file=$$i; fi; \
-	  ext=`echo $$i | sed -e 's/^.*\\.//'`; \
-	  case "$$ext" in \
-	    3*) ;; \
-	    *) ext='3' ;; \
-	  esac; \
-	  inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
-	  inst=`echo $$inst | sed -e 's/^.*\///'`; \
-	  inst=`echo $$inst | sed '$(transform)'`.$$ext; \
-	  echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man3dir)/$$inst'"; \
-	  $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man3dir)/$$inst"; \
-	done
+	for i in $$list; do echo "$$i"; done | $(am__base_list) | \
+	while read files; do \
+	  test -z "$$files" || { \
+	    echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man3dir)'"; \
+	    $(INSTALL_DATA) $$files "$(DESTDIR)$(man3dir)" || exit $$?; }; \
+	done; }
+
 uninstall-man3:
 	@$(NORMAL_UNINSTALL)
-	@list='$(man3_MANS) $(dist_man3_MANS) $(nodist_man3_MANS)'; \
-	l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
-	for i in $$l2; do \
-	  case "$$i" in \
-	    *.3*) list="$$list $$i" ;; \
-	  esac; \
-	done; \
-	for i in $$list; do \
-	  ext=`echo $$i | sed -e 's/^.*\\.//'`; \
-	  case "$$ext" in \
-	    3*) ;; \
-	    *) ext='3' ;; \
-	  esac; \
-	  inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
-	  inst=`echo $$inst | sed -e 's/^.*\///'`; \
-	  inst=`echo $$inst | sed '$(transform)'`.$$ext; \
-	  echo " rm -f '$(DESTDIR)$(man3dir)/$$inst'"; \
-	  rm -f "$(DESTDIR)$(man3dir)/$$inst"; \
-	done
+	@list='$(man3_MANS)'; test -n "$(man3dir)" || exit 0; \
+	files=`{ for i in $$list; do echo "$$i"; done; \
+	} | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^3][0-9a-z]*$$,3,;x' \
+	      -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \
+	test -z "$$files" || { \
+	  echo " ( cd '$(DESTDIR)$(man3dir)' && rm -f" $$files ")"; \
+	  cd "$(DESTDIR)$(man3dir)" && rm -f $$files; }
 install-libipsecHEADERS: $(libipsec_HEADERS)
 	@$(NORMAL_INSTALL)
 	test -z "$(libipsecdir)" || $(MKDIR_P) "$(DESTDIR)$(libipsecdir)"
-	@list='$(libipsec_HEADERS)'; for p in $$list; do \
+	@list='$(libipsec_HEADERS)'; test -n "$(libipsecdir)" || list=; \
+	for p in $$list; do \
 	  if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
-	  f=$(am__strip_dir) \
-	  echo " $(libipsecHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(libipsecdir)/$$f'"; \
-	  $(libipsecHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(libipsecdir)/$$f"; \
+	  echo "$$d$$p"; \
+	done | $(am__base_list) | \
+	while read files; do \
+	  echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(libipsecdir)'"; \
+	  $(INSTALL_HEADER) $$files "$(DESTDIR)$(libipsecdir)" || exit $$?; \
 	done
 
 uninstall-libipsecHEADERS:
 	@$(NORMAL_UNINSTALL)
-	@list='$(libipsec_HEADERS)'; for p in $$list; do \
-	  f=$(am__strip_dir) \
-	  echo " rm -f '$(DESTDIR)$(libipsecdir)/$$f'"; \
-	  rm -f "$(DESTDIR)$(libipsecdir)/$$f"; \
-	done
+	@list='$(libipsec_HEADERS)'; test -n "$(libipsecdir)" || list=; \
+	files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+	test -n "$$files" || exit 0; \
+	echo " ( cd '$(DESTDIR)$(libipsecdir)' && rm -f" $$files ")"; \
+	cd "$(DESTDIR)$(libipsecdir)" && rm -f $$files
 
 ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
 	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
 	unique=`for i in $$list; do \
 	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
 	  done | \
-	  $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
 	      END { if (nonempty) { for (i in files) print i; }; }'`; \
 	mkid -fID $$unique
 tags: TAGS
 
 TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
 		$(TAGS_FILES) $(LISP)
-	tags=; \
+	set x; \
 	here=`pwd`; \
 	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
 	unique=`for i in $$list; do \
@@ -452,34 +469,52 @@
 	  done | \
 	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
 	      END { if (nonempty) { for (i in files) print i; }; }'`; \
-	if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
 	  test -n "$$unique" || unique=$$empty_fix; \
-	  $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
-	    $$tags $$unique; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
 	fi
 ctags: CTAGS
 CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
 		$(TAGS_FILES) $(LISP)
-	tags=; \
 	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
 	unique=`for i in $$list; do \
 	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
 	  done | \
 	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
 	      END { if (nonempty) { for (i in files) print i; }; }'`; \
-	test -z "$(CTAGS_ARGS)$$tags$$unique" \
+	test -z "$(CTAGS_ARGS)$$unique" \
 	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
-	     $$tags $$unique
+	     $$unique
 
 GTAGS:
 	here=`$(am__cd) $(top_builddir) && pwd` \
-	  && cd $(top_srcdir) \
-	  && gtags -i $(GTAGS_ARGS) $$here
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
 
 distclean-tags:
 	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
 
 distdir: $(DISTFILES)
+	@list='$(MANS)'; if test -n "$$list"; then \
+	  list=`for p in $$list; do \
+	    if test -f $$p; then d=; else d="$(srcdir)/"; fi; \
+	    if test -f "$$d$$p"; then echo "$$d$$p"; else :; fi; done`; \
+	  if test -n "$$list" && \
+	    grep 'ab help2man is required to generate this page' $$list >/dev/null; then \
+	    echo "error: found man pages containing the \`missing help2man' replacement text:" >&2; \
+	    grep -l 'ab help2man is required to generate this page' $$list | sed 's/^/         /' >&2; \
+	    echo "       to fix them, install help2man, remove and regenerate the man pages;" >&2; \
+	    echo "       typically \`make maintainer-clean' will remove them" >&2; \
+	    exit 1; \
+	  else :; fi; \
+	else :; fi
 	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
 	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
 	list='$(DISTFILES)'; \
@@ -495,13 +530,17 @@
 	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
 	  if test -d $$d/$$file; then \
 	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
-	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
-	      cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
 	    fi; \
-	    cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
 	  else \
-	    test -f $(distdir)/$$file \
-	    || cp -p $$d/$$file $(distdir)/$$file \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
 	    || exit 1; \
 	  fi; \
 	done
@@ -534,6 +573,7 @@
 
 distclean-generic:
 	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
 
 maintainer-clean-generic:
 	@echo "This command is intended for maintainers to use"
@@ -559,6 +599,8 @@
 
 html: html-am
 
+html-am:
+
 info: info-am
 
 info-am:
@@ -567,18 +609,28 @@
 
 install-dvi: install-dvi-am
 
+install-dvi-am:
+
 install-exec-am: install-libLTLIBRARIES
 
 install-html: install-html-am
 
+install-html-am:
+
 install-info: install-info-am
 
+install-info-am:
+
 install-man: install-man3
 
 install-pdf: install-pdf-am
 
+install-pdf-am:
+
 install-ps: install-ps-am
 
+install-ps-am:
+
 installcheck-am:
 
 maintainer-clean: maintainer-clean-am
@@ -604,7 +656,7 @@
 
 uninstall-man: uninstall-man3
 
-.MAKE: install-am install-strip
+.MAKE: all check install install-am install-strip
 
 .PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
 	clean-libLTLIBRARIES clean-libtool ctags distclean \
@@ -622,6 +674,7 @@
 	uninstall-am uninstall-libLTLIBRARIES \
 	uninstall-libipsecHEADERS uninstall-man uninstall-man3
 
+
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
 .NOEXPORT:
diff --git a/src/libipsec/ipsec_dump_policy.c b/src/libipsec/ipsec_dump_policy.c
index bdadb47..4d0eb77 100644
--- a/src/libipsec/ipsec_dump_policy.c
+++ b/src/libipsec/ipsec_dump_policy.c
@@ -1,4 +1,4 @@
-/*	$NetBSD: ipsec_dump_policy.c,v 1.7.6.1 2007/08/01 11:52:17 vanhu Exp $	*/
+/*	$NetBSD: ipsec_dump_policy.c,v 1.9 2010/12/03 15:01:11 tteras Exp $	*/
 
 /* Id: ipsec_dump_policy.c,v 1.10 2005/06/29 09:12:37 manubsd Exp */
 
@@ -53,7 +53,10 @@
 #include "libpfkey.h"
 
 static const char *ipsp_dir_strs[] = {
-	"any", "in", "out", "fwd"
+	"any", "in", "out", "fwd",
+#ifdef __linux__
+	"in(socket)", "out(socket)"
+#endif
 };
 
 static const char *ipsp_policy_strs[] = {
@@ -165,6 +168,8 @@
 	case IPSEC_DIR_OUTBOUND:
 #ifdef HAVE_POLICY_FWD
 	case IPSEC_DIR_FWD:
+	case IPSEC_DIR_FWD + 1:
+	case IPSEC_DIR_FWD + 2:
 #endif
 		break;
 	default:
diff --git a/src/libipsec/ipsec_get_policylen.c b/src/libipsec/ipsec_get_policylen.c
index 2f4f6e9..5a49778 100644
--- a/src/libipsec/ipsec_get_policylen.c
+++ b/src/libipsec/ipsec_get_policylen.c
@@ -1,4 +1,4 @@
-/*	$NetBSD: ipsec_get_policylen.c,v 1.6.6.1 2007/08/01 11:52:17 vanhu Exp $	*/
+/*	$NetBSD: ipsec_get_policylen.c,v 1.7 2007/07/18 12:07:50 vanhu Exp $	*/
 
 /*	$KAME: ipsec_get_policylen.c,v 1.5 2000/05/07 05:25:03 itojun Exp $	*/
 
diff --git a/src/libipsec/ipsec_set_policy.3 b/src/libipsec/ipsec_set_policy.3
index 643b582..f3832b5 100644
--- a/src/libipsec/ipsec_set_policy.3
+++ b/src/libipsec/ipsec_set_policy.3
@@ -1,4 +1,4 @@
-.\"	$NetBSD: ipsec_set_policy.3,v 1.13 2006/09/09 16:22:09 manu Exp $
+.\"	$NetBSD: ipsec_set_policy.3,v 1.15 2010/03/05 06:47:58 tteras Exp $
 .\"
 .\"	$KAME: ipsec_set_policy.3,v 1.16 2003/01/06 21:59:03 sumikawa Exp $
 .\"
@@ -124,14 +124,10 @@
 support policy priorities (Linux \*[Gt]= 2.6.6).
 It takes one of the following formats:
 .Bl -tag  -width "discard"
-.It Xo
-.Ar {priority,prio} offset
-.Xc
+.It Ar {priority,prio} offset
 .Ar offset
-is an integer in the range -2147483647..214783648.
-.It Xo
-.Ar {priority,prio} base {+,-} offset
-.Xc
+is an integer in the range \-2147483647..214783648.
+.It Ar {priority,prio} base {+,-} offset
 .Ar base
 is either
 .Li low (-1073741824) ,
@@ -162,12 +158,7 @@
 means to bypass the IPsec processing.
 .Pq the packet will be transmitted in clear .
 This is for privileged sockets.
-.It Xo
-.Ar direction
-.Bq Ar priority specification
-.Li ipsec
-.Ar request ...
-.Xc
+.It Ar direction Bo Ar priority specification Bc Li ipsec Ar request ...
 .Li ipsec
 means that the matching packets are subject to IPsec processing.
 .Li ipsec
@@ -175,16 +166,7 @@
 .Ar request
 strings, which are formatted as below:
 .Bl -tag  -width "discard"
-.It Xo
-.Ar protocol
-.Li /
-.Ar mode
-.Li /
-.Ar src
-.Li -
-.Ar dst
-.Op Ar /level
-.Xc
+.It Ar protocol Li / Ar mode Li / Ar src Li - Ar dst Op Ar /level
 .Ar protocol
 is either
 .Li ah ,
diff --git a/src/libipsec/ipsec_strerror.c b/src/libipsec/ipsec_strerror.c
index ad1ab2a..ca26d0e 100644
--- a/src/libipsec/ipsec_strerror.c
+++ b/src/libipsec/ipsec_strerror.c
@@ -1,4 +1,4 @@
-/*	$NetBSD: ipsec_strerror.c,v 1.4.6.1 2007/08/01 11:52:17 vanhu Exp $	*/
+/*	$NetBSD: ipsec_strerror.c,v 1.6 2010/04/07 14:53:52 vanhu Exp $	*/
 
 /*	$KAME: ipsec_strerror.c,v 1.7 2000/07/30 00:45:12 itojun Exp $	*/
 
@@ -63,7 +63,7 @@
 "Invalid key length",				/*EIPSEC_INVAL_KEYLEN*/
 "Invalid address family",			/*EIPSEC_INVAL_FAMILY*/
 "Invalid prefix length",			/*EIPSEC_INVAL_PREFIXLEN*/
-"Invalid direciton",				/*EIPSEC_INVAL_DIR*/
+"Invalid direction",				/*EIPSEC_INVAL_DIR*/
 "SPI range violation",				/*EIPSEC_INVAL_SPI*/
 "No protocol specified",			/*EIPSEC_NO_PROTO*/
 "No algorithm specified",			/*EIPSEC_NO_ALGS*/
diff --git a/src/libipsec/key_debug.c b/src/libipsec/key_debug.c
index 60f1602..e381a98 100644
--- a/src/libipsec/key_debug.c
+++ b/src/libipsec/key_debug.c
@@ -1,4 +1,4 @@
-/*	$NetBSD: key_debug.c,v 1.7.6.1 2007/08/01 11:52:18 vanhu Exp $	*/
+/*	$NetBSD: key_debug.c,v 1.9 2008/12/05 06:02:20 tteras Exp $	*/
 
 /*	$KAME: key_debug.c,v 1.29 2001/08/16 14:25:41 itojun Exp $	*/
 
@@ -91,6 +91,10 @@
 static void kdebug_sadb_x_packet __P((struct sadb_ext *));
 #endif
 
+#ifdef SADB_X_EXT_KMADDRESS
+static void kdebug_sadb_x_kmaddress __P((struct sadb_ext *));
+#endif
+
 #ifdef _KERNEL
 static void kdebug_secreplay __P((struct secreplay *));
 #endif
@@ -194,6 +198,11 @@
 			kdebug_sadb_x_packet(ext);
 			break;
 #endif
+#ifdef SADB_X_EXT_KMADDRESS
+		case SADB_X_EXT_KMADDRESS:
+			kdebug_sadb_x_kmaddress(ext);
+			break;
+#endif
 		default:
 			printf("kdebug_sadb: invalid ext_type %u was passed.\n",
 			    ext->sadb_ext_type);
@@ -556,6 +565,48 @@
 }
 #endif
 
+#ifdef SADB_X_EXT_KMADDRESS
+static void
+kdebug_sadb_x_kmaddress(ext)
+	struct sadb_ext *ext;
+{
+	struct sadb_x_kmaddress *kma = (struct sadb_x_kmaddress *)ext;
+	struct sockaddr * sa;
+	sa_family_t family;
+	int len, sa_len;
+
+	/* sanity check */
+	if (ext == NULL)
+		panic("kdebug_sadb_x_kmaddress: NULL pointer was passed.\n");
+
+	len = (PFKEY_UNUNIT64(kma->sadb_x_kmaddress_len) - sizeof(*kma));
+
+	printf("sadb_x_kmaddress{ reserved=0x%02x%02x%02x%02x }\n",
+	       ((u_char *)(void *)&kma->sadb_x_kmaddress_reserved)[0],
+	       ((u_char *)(void *)&kma->sadb_x_kmaddress_reserved)[1],
+	       ((u_char *)(void *)&kma->sadb_x_kmaddress_reserved)[2],
+	       ((u_char *)(void *)&kma->sadb_x_kmaddress_reserved)[3]);
+
+	sa = (struct sockaddr *)(kma + 1);
+	if (len < sizeof(struct sockaddr) || (sa_len = sysdep_sa_len(sa)) > len)
+		panic("kdebug_sadb_x_kmaddress: not enough data to read"
+		      " first sockaddr.\n");
+	kdebug_sockaddr((void *)sa); /* local address */
+	family = sa->sa_family;
+
+	len -= sa_len;
+	sa = (struct sockaddr *)((char *)sa + sa_len);
+	if (len < sizeof(struct sockaddr) || sysdep_sa_len(sa) > len)
+		panic("kdebug_sadb_x_kmaddress: not enough data to read"
+		      " second sockaddr.\n");
+	kdebug_sockaddr((void *)sa); /* remote address */
+
+	if (family != sa->sa_family)
+		printf("kdebug_sadb_x_kmaddress:  !!!! Please, note the "
+		       "unexpected mismatch in address family.\n");
+}
+#endif
+
 
 #ifdef _KERNEL
 /* %%%: about SPD and SAD */
diff --git a/src/libipsec/libpfkey.h b/src/libipsec/libpfkey.h
index b312015..ff4c603 100644
--- a/src/libipsec/libpfkey.h
+++ b/src/libipsec/libpfkey.h
@@ -1,4 +1,4 @@
-/*	$NetBSD: libpfkey.h,v 1.12.4.1 2007/08/01 11:52:18 vanhu Exp $	*/
+/*	$NetBSD: libpfkey.h,v 1.18 2010/12/03 14:32:52 tteras Exp $	*/
 
 /* Id: libpfkey.h,v 1.13 2005/12/04 20:26:43 manubsd Exp */
 
@@ -121,6 +121,10 @@
 u_int pfkey_get_softrate __P((u_int));
 int pfkey_send_getspi __P((int, u_int, u_int, struct sockaddr *,
 	struct sockaddr *, u_int32_t, u_int32_t, u_int32_t, u_int32_t));
+int pfkey_send_getspi_nat __P((int, u_int, u_int,
+	struct sockaddr *, struct sockaddr *, u_int8_t, u_int16_t, u_int16_t,
+	u_int32_t, u_int32_t, u_int32_t, u_int32_t));
+
 int pfkey_send_update2 __P((struct pfkey_send_sa_args *));
 int pfkey_send_add2 __P((struct pfkey_send_sa_args *)); 
 int pfkey_send_delete __P((int, u_int, u_int,
@@ -154,12 +158,22 @@
 int pfkey_send_spdflush __P((int));
 int pfkey_send_spddump __P((int));
 #ifdef SADB_X_MIGRATE
-int pfkey_send_migrate __P((int, struct sockaddr *, u_int,
-	struct sockaddr *, u_int, u_int, caddr_t, int, u_int32_t));
+int pfkey_send_migrate __P((int, struct sockaddr *, struct sockaddr *,
+        struct sockaddr *, u_int, struct sockaddr *, u_int, u_int,
+        caddr_t, int, u_int32_t));
 #endif
 
+/* XXX should be somewhere else !!!
+ */
+#ifdef SADB_X_EXT_NAT_T_TYPE
+#define PFKEY_ADDR_X_PORT(ext) (ntohs(((struct sadb_x_nat_t_port *)ext)->sadb_x_nat_t_port_port))
+#define PFKEY_ADDR_X_NATTYPE(ext) ( ext != NULL && ((struct sadb_x_nat_t_type *)ext)->sadb_x_nat_t_type_type )
+#endif
+
+
 int pfkey_open __P((void));
 void pfkey_close __P((int));
+int pfkey_set_buffer_size __P((int, int));
 struct sadb_msg *pfkey_recv __P((int));
 int pfkey_send __P((int, struct sadb_msg *, int));
 int pfkey_align __P((struct sadb_msg *, caddr_t *));
@@ -200,6 +214,10 @@
 #define IPPROTO_IPCOMP IPPROTO_COMP
 #endif
 
+#ifndef IPPROTO_MH
+#define IPPROTO_MH		135
+#endif
+
 static __inline u_int8_t
 sysdep_sa_len (const struct sockaddr *sa)
 {
diff --git a/src/libipsec/pfkey.c b/src/libipsec/pfkey.c
index fae0415..e64cf36 100644
--- a/src/libipsec/pfkey.c
+++ b/src/libipsec/pfkey.c
@@ -1,4 +1,4 @@
-/*	$NetBSD: pfkey.c,v 1.13.4.2 2007/10/15 16:05:22 vanhu Exp $	*/
+/*	$NetBSD: pfkey.c,v 1.21 2011/01/20 16:08:35 vanhu Exp $	*/
 
 /*	$KAME: pfkey.c,v 1.47 2003/10/02 19:52:12 itojun Exp $	*/
 
@@ -71,6 +71,12 @@
 	u_int, u_int, u_int32_t));
 static caddr_t pfkey_setsadbaddr __P((caddr_t, caddr_t, u_int,
 	struct sockaddr *, u_int, u_int));
+
+#ifdef SADB_X_EXT_KMADDRESS
+static caddr_t pfkey_setsadbkmaddr __P((caddr_t, caddr_t, struct sockaddr *,
+	struct sockaddr *));
+#endif
+
 static caddr_t pfkey_setsadbkey __P((caddr_t, caddr_t, u_int, caddr_t, u_int));
 static caddr_t pfkey_setsadblifetime __P((caddr_t, caddr_t, u_int, u_int32_t,
 	u_int32_t, u_int32_t, u_int32_t));
@@ -374,11 +380,10 @@
  *	-1	: error occured, and set errno.
  */
 int
-pfkey_send_getspi(so, satype, mode, src, dst, min, max, reqid, seq)
-	int so;
-	u_int satype, mode;
-	struct sockaddr *src, *dst;
-	u_int32_t min, max, reqid, seq;
+pfkey_send_getspi_nat(int so, u_int satype, u_int mode, struct sockaddr *src,
+    struct sockaddr *dst, u_int8_t natt_type, u_int16_t sport,
+    u_int16_t dport, u_int32_t min, u_int32_t max, u_int32_t reqid,
+    u_int32_t seq)
 {
 	struct sadb_msg *newmsg;
 	caddr_t ep;
@@ -425,6 +430,14 @@
 		len += sizeof(struct sadb_spirange);
 	}
 
+#ifdef SADB_X_EXT_NAT_T_TYPE
+	if(natt_type||sport||dport){
+		len += sizeof(struct sadb_x_nat_t_type);
+		len += sizeof(struct sadb_x_nat_t_port);
+		len += sizeof(struct sadb_x_nat_t_port);
+	}
+#endif
+
 	if ((newmsg = CALLOC((size_t)len, struct sadb_msg *)) == NULL) {
 		__ipsec_set_strerror(strerror(errno));
 		return -1;
@@ -460,6 +473,32 @@
 		return -1;
 	}
 
+#ifdef SADB_X_EXT_NAT_T_TYPE
+	/* Add nat-t messages */
+	if (natt_type) {
+		p = pfkey_set_natt_type(p, ep, SADB_X_EXT_NAT_T_TYPE, 
+					natt_type);
+		if (!p) {
+			free(newmsg);
+			return -1;
+		}
+
+		p = pfkey_set_natt_port(p, ep, SADB_X_EXT_NAT_T_SPORT,
+					sport);
+		if (!p) {
+			free(newmsg);
+			return -1;
+		}
+
+		p = pfkey_set_natt_port(p, ep, SADB_X_EXT_NAT_T_DPORT,
+					dport);
+		if (!p) {
+			free(newmsg);
+			return -1;
+		}
+	}
+#endif
+
 	/* proccessing spi range */
 	if (need_spirange) {
 		struct sadb_spirange spirange;
@@ -495,6 +534,15 @@
 	return len;
 }
 
+int
+pfkey_send_getspi(int so, u_int satype, u_int mode, struct sockaddr *src,
+    struct sockaddr *dst, u_int32_t min, u_int32_t max, u_int32_t reqid,
+    u_int32_t seq)
+{
+	return pfkey_send_getspi_nat(so, satype, mode, src, dst, 0, 0, 0,
+		min, max, reqid, seq);
+}
+
 /*
  * sending SADB_UPDATE message to the kernel.
  * The length of key material is a_keylen + e_keylen.
@@ -503,12 +551,10 @@
  *	-1	: error occured, and set errno.
  */
 int
-pfkey_send_update2(sa_parms)
-	struct pfkey_send_sa_args *sa_parms;
+pfkey_send_update2(struct pfkey_send_sa_args *sa_parms)
 {
 	int len;
 
-	
 	sa_parms->type = SADB_UPDATE;
 	if ((len = pfkey_send_x1(sa_parms)) < 0)
 		return -1;
@@ -524,8 +570,7 @@
  *	-1	: error occured, and set errno.
  */
 int
-pfkey_send_add2(sa_parms)
-	struct pfkey_send_sa_args *sa_parms;
+pfkey_send_add2(struct pfkey_send_sa_args *sa_parms)
 {
 	int len;
 	
@@ -543,11 +588,8 @@
  *	-1	: error occured, and set errno.
  */
 int
-pfkey_send_delete(so, satype, mode, src, dst, spi)
-	int so;
-	u_int satype, mode;
-	struct sockaddr *src, *dst;
-	u_int32_t spi;
+pfkey_send_delete(int so, u_int satype, u_int mode, struct sockaddr *src,
+    struct sockaddr *dst, u_int32_t spi)
 {
 	int len;
 	if ((len = pfkey_send_x2(so, SADB_DELETE, satype, mode, src, dst, spi)) < 0)
@@ -567,10 +609,8 @@
  */
 /*ARGSUSED*/
 int
-pfkey_send_delete_all(so, satype, mode, src, dst)
-	int so;
-	u_int satype, mode;
-	struct sockaddr *src, *dst;
+pfkey_send_delete_all(int so, u_int satype, u_int mode, struct sockaddr *src,
+    struct sockaddr *dst)
 {
 	struct sadb_msg *newmsg;
 	int len;
@@ -649,11 +689,8 @@
  *	-1	: error occured, and set errno.
  */
 int
-pfkey_send_get(so, satype, mode, src, dst, spi)
-	int so;
-	u_int satype, mode;
-	struct sockaddr *src, *dst;
-	u_int32_t spi;
+pfkey_send_get(int so, u_int satype, u_int mode, struct sockaddr *src,
+    struct sockaddr *dst, u_int32_t spi)
 {
 	int len;
 	if ((len = pfkey_send_x2(so, SADB_GET, satype, mode, src, dst, spi)) < 0)
@@ -669,9 +706,7 @@
  *	-1	: error occured, and set errno.
  */
 int
-pfkey_send_register(so, satype)
-	int so;
-	u_int satype;
+pfkey_send_register(int so, u_int satype)
 {
 	int len, algno;
 
@@ -711,8 +746,7 @@
  *	-1: error occured, and set errno.
  */
 int
-pfkey_recv_register(so)
-	int so;
+pfkey_recv_register(int so)
 {
 	pid_t pid = getpid();
 	struct sadb_msg *newmsg;
@@ -751,9 +785,7 @@
  *	-1: error occured, and set errno.
  */
 int
-pfkey_set_supported(msg, tlen)
-	struct sadb_msg *msg;
-	int tlen;
+pfkey_set_supported(struct sadb_msg *msg, int tlen)
 {
 	struct sadb_supported *sup;
 	caddr_t p;
@@ -815,9 +847,7 @@
  *	-1	: error occured, and set errno.
  */
 int
-pfkey_send_flush(so, satype)
-	int so;
-	u_int satype;
+pfkey_send_flush(int so, u_int satype)
 {
 	int len;
 
@@ -834,9 +864,7 @@
  *	-1	: error occured, and set errno.
  */
 int
-pfkey_send_dump(so, satype)
-	int so;
-	u_int satype;
+pfkey_send_dump(int so, u_int satype)
 {
 	int len;
 
@@ -859,9 +887,7 @@
  *	        algorithms is.
  */
 int
-pfkey_send_promisc_toggle(so, flag)
-	int so;
-	int flag;
+pfkey_send_promisc_toggle(int so, int flag)
 {
 	int len;
 
@@ -879,13 +905,9 @@
  *	-1	: error occured, and set errno.
  */
 int
-pfkey_send_spdadd(so, src, prefs, dst, prefd, proto, policy, policylen, seq)
-	int so;
-	struct sockaddr *src, *dst;
-	u_int prefs, prefd, proto;
-	caddr_t policy;
-	int policylen;
-	u_int32_t seq;
+pfkey_send_spdadd(int so, struct sockaddr *src, u_int prefs,
+    struct sockaddr *dst, u_int prefd, u_int proto, caddr_t policy,
+    int policylen, u_int32_t seq)
 {
 	int len;
 
@@ -905,15 +927,9 @@
  *	-1	: error occured, and set errno.
  */
 int
-pfkey_send_spdadd2(so, src, prefs, dst, prefd, proto, ltime, vtime,
-		policy, policylen, seq)
-	int so;
-	struct sockaddr *src, *dst;
-	u_int prefs, prefd, proto;
-	u_int64_t ltime, vtime;
-	caddr_t policy;
-	int policylen;
-	u_int32_t seq;
+pfkey_send_spdadd2(int so, struct sockaddr *src, u_int prefs,
+    struct sockaddr *dst, u_int prefd, u_int proto, u_int64_t ltime,
+    u_int64_t vtime, caddr_t policy, int policylen, u_int32_t seq)
 {
 	int len;
 
@@ -933,13 +949,9 @@
  *	-1	: error occured, and set errno.
  */
 int
-pfkey_send_spdupdate(so, src, prefs, dst, prefd, proto, policy, policylen, seq)
-	int so;
-	struct sockaddr *src, *dst;
-	u_int prefs, prefd, proto;
-	caddr_t policy;
-	int policylen;
-	u_int32_t seq;
+pfkey_send_spdupdate(int so, struct sockaddr *src, u_int prefs,
+    struct sockaddr *dst, u_int prefd, u_int proto, caddr_t policy,
+    int policylen, u_int32_t seq)
 {
 	int len;
 
@@ -959,15 +971,9 @@
  *	-1	: error occured, and set errno.
  */
 int
-pfkey_send_spdupdate2(so, src, prefs, dst, prefd, proto, ltime, vtime,
-		policy, policylen, seq)
-	int so;
-	struct sockaddr *src, *dst;
-	u_int prefs, prefd, proto;
-	u_int64_t ltime, vtime;
-	caddr_t policy;
-	int policylen;
-	u_int32_t seq;
+pfkey_send_spdupdate2(int so, struct sockaddr *src, u_int prefs,
+    struct sockaddr *dst, u_int prefd, u_int proto, u_int64_t ltime,
+    u_int64_t vtime, caddr_t policy, int policylen, u_int32_t seq)
 {
 	int len;
 
@@ -987,13 +993,9 @@
  *	-1	: error occured, and set errno.
  */
 int
-pfkey_send_spddelete(so, src, prefs, dst, prefd, proto, policy, policylen, seq)
-	int so;
-	struct sockaddr *src, *dst;
-	u_int prefs, prefd, proto;
-	caddr_t policy;
-	int policylen;
-	u_int32_t seq;
+pfkey_send_spddelete(int so, struct sockaddr *src, u_int prefs,
+    struct sockaddr *dst, u_int prefd, u_int proto, caddr_t policy,
+    int policylen, u_int32_t seq)
 {
 	int len;
 
@@ -1018,9 +1020,7 @@
  *	-1	: error occured, and set errno.
  */
 int
-pfkey_send_spddelete2(so, spid)
-	int so;
-	u_int32_t spid;
+pfkey_send_spddelete2(int so, u_int32_t spid)
 {
 	int len;
 
@@ -1037,9 +1037,7 @@
  *	-1	: error occured, and set errno.
  */
 int
-pfkey_send_spdget(so, spid)
-	int so;
-	u_int32_t spid;
+pfkey_send_spdget(int so, u_int32_t spid)
 {
 	int len;
 
@@ -1056,13 +1054,9 @@
  *	-1	: error occured, and set errno.
  */
 int
-pfkey_send_spdsetidx(so, src, prefs, dst, prefd, proto, policy, policylen, seq)
-	int so;
-	struct sockaddr *src, *dst;
-	u_int prefs, prefd, proto;
-	caddr_t policy;
-	int policylen;
-	u_int32_t seq;
+pfkey_send_spdsetidx(int so, struct sockaddr *src, u_int prefs,
+    struct sockaddr *dst, u_int prefd, u_int proto, caddr_t policy,
+    int policylen, u_int32_t seq)
 {
 	int len;
 
@@ -1087,8 +1081,7 @@
  *	-1	: error occured, and set errno.
  */
 int
-pfkey_send_spdflush(so)
-	int so;
+pfkey_send_spdflush(int so)
 {
 	int len;
 
@@ -1105,8 +1098,7 @@
  *	-1	: error occured, and set errno.
  */
 int
-pfkey_send_spddump(so)
-	int so;
+pfkey_send_spddump(int so)
 {
 	int len;
 
@@ -1125,13 +1117,9 @@
  *	-1	: error occured, and set errno.
  */
 int
-pfkey_send_migrate(so, src, prefs, dst, prefd, proto, policy, policylen, seq)
-	int so;
-	struct sockaddr *src, *dst;
-	u_int prefs, prefd, proto;
-	caddr_t policy;
-	int policylen;
-	u_int32_t seq;
+pfkey_send_migrate(int so, struct sockaddr *local, struct sockaddr *remote,
+    struct sockaddr *src, u_int prefs, struct sockaddr *dst, u_int prefd,
+    u_int proto, caddr_t policy, int policylen, u_int32_t seq)
 {
 	struct sadb_msg *newmsg;
 	int len;
@@ -1149,6 +1137,17 @@
 		return -1;
 	}
 
+	if (local == NULL || remote == NULL) {
+		__ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+		return -1;
+	}
+#ifdef SADB_X_EXT_KMADDRESS
+	if (local->sa_family != remote->sa_family) {
+		__ipsec_errcode = EIPSEC_FAMILY_MISMATCH;
+		return -1;
+	}
+#endif
+
 	switch (src->sa_family) {
 	case AF_INET:
 		plen = sizeof(struct in_addr) << 3;
@@ -1167,6 +1166,10 @@
 
 	/* create new sadb_msg to reply. */
 	len = sizeof(struct sadb_msg)
+#ifdef SADB_X_EXT_KMADDRESS
+		+ sizeof(struct sadb_x_kmaddress)
+		+ PFKEY_ALIGN8(2*sysdep_sa_len(local))
+#endif
 		+ sizeof(struct sadb_address)
 		+ PFKEY_ALIGN8(sysdep_sa_len(src))
 		+ sizeof(struct sadb_address)
@@ -1185,6 +1188,13 @@
 		free(newmsg);
 		return -1;
 	}
+#ifdef SADB_X_EXT_KMADDRESS
+	p = pfkey_setsadbkmaddr(p, ep, local, remote);
+	if (!p) {
+		free(newmsg);
+		return -1;
+	}
+#endif
 	p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, prefs, proto);
 	if (!p) {
 		free(newmsg);
@@ -1212,8 +1222,7 @@
 
 /* sending SADB_ADD or SADB_UPDATE message to the kernel */
 static int
-pfkey_send_x1(sa_parms)
-	struct pfkey_send_sa_args *sa_parms;
+pfkey_send_x1(struct pfkey_send_sa_args *sa_parms)
 {
 	struct sadb_msg *newmsg;
 	int len;
@@ -1486,11 +1495,8 @@
 /* sending SADB_DELETE or SADB_GET message to the kernel */
 /*ARGSUSED*/
 static int
-pfkey_send_x2(so, type, satype, mode, src, dst, spi)
-	int so;
-	u_int type, satype, mode;
-	struct sockaddr *src, *dst;
-	u_int32_t spi;
+pfkey_send_x2(int so, u_int type, u_int satype, u_int mode,
+    struct sockaddr *src, struct sockaddr *dst, u_int32_t spi)
 {
 	struct sadb_msg *newmsg;
 	int len;
@@ -1573,9 +1579,7 @@
  * to the kernel
  */
 static int
-pfkey_send_x3(so, type, satype)
-	int so;
-	u_int type, satype;
+pfkey_send_x3(int so, u_int type, u_int satype)
 {
 	struct sadb_msg *newmsg;
 	int len;
@@ -1635,15 +1639,9 @@
 
 /* sending SADB_X_SPDADD message to the kernel */
 static int
-pfkey_send_x4(so, type, src, prefs, dst, prefd, proto,
-		ltime, vtime, policy, policylen, seq)
-	int so;
-	struct sockaddr *src, *dst;
-	u_int type, prefs, prefd, proto;
-	u_int64_t ltime, vtime;
-	char *policy;
-	int policylen;
-	u_int32_t seq;
+pfkey_send_x4(int so, u_int type, struct sockaddr *src, u_int prefs,
+    struct sockaddr *dst, u_int prefd, u_int proto, u_int64_t ltime,
+    u_int64_t vtime, char *policy, int policylen, u_int32_t seq)
 {
 	struct sadb_msg *newmsg;
 	int len;
@@ -1729,10 +1727,7 @@
 
 /* sending SADB_X_SPDGET or SADB_X_SPDDELETE message to the kernel */
 static int
-pfkey_send_x5(so, type, spid)
-	int so;
-	u_int type;
-	u_int32_t spid;
+pfkey_send_x5(int so, u_int type, u_int32_t spid)
 {
 	struct sadb_msg *newmsg;
 	struct sadb_x_policy xpl;
@@ -1785,7 +1780,7 @@
  *	others : success and return value of socket.
  */
 int
-pfkey_open()
+pfkey_open(void)
 {
 	int so;
 	int bufsiz = 128 * 1024;	/*is 128K enough?*/
@@ -1811,6 +1806,42 @@
 	return so;
 }
 
+int
+pfkey_set_buffer_size(int so, int size)
+{
+	int newsize;
+	int actual_bufsiz;
+	socklen_t sizebufsiz;
+	int desired_bufsiz;
+
+	/*
+	 * on linux you may need to allow the kernel to allocate
+	 * more buffer space by increasing:
+	 * /proc/sys/net/core/rmem_max and wmem_max
+	 */
+	if (size > 0) {
+		actual_bufsiz = 0;
+		sizebufsiz = sizeof(actual_bufsiz);
+		desired_bufsiz = size * 1024;
+		if ((getsockopt(so, SOL_SOCKET, SO_RCVBUF,
+				&actual_bufsiz, &sizebufsiz) < 0)
+		    || (actual_bufsiz < desired_bufsiz)) {
+			if (setsockopt(so, SOL_SOCKET, SO_RCVBUF,
+				       &desired_bufsiz, sizeof(desired_bufsiz)) < 0) {
+				__ipsec_set_strerror(strerror(errno));
+				return -1;
+			}
+		}
+	}
+
+	/* return actual buffer size */
+	actual_bufsiz = 0;
+	sizebufsiz = sizeof(actual_bufsiz);
+	getsockopt(so, SOL_SOCKET, SO_RCVBUF,
+		   &actual_bufsiz, &sizebufsiz);
+	return actual_bufsiz / 1024;
+}
+
 /*
  * close a socket.
  * OUT:
@@ -1818,8 +1849,7 @@
  *	-1: fail.
  */
 void
-pfkey_close(so)
-	int so;
+pfkey_close(int so)
 {
 	(void)close(so);
 
@@ -1837,8 +1867,7 @@
  * XXX should be rewritten to pass length explicitly
  */
 struct sadb_msg *
-pfkey_recv(so)
-	int so;
+pfkey_recv(int so)
 {
 	struct sadb_msg buf, *newmsg;
 	int len, reallen;
@@ -1895,10 +1924,7 @@
  *	-1     : fail.
  */
 int
-pfkey_send(so, msg, len)
-	int so;
-	struct sadb_msg *msg;
-	int len;
+pfkey_send(int so, struct sadb_msg *msg, int len)
 {
 	if ((len = send(so, (void *)msg, (socklen_t)len, 0)) < 0) {
 		__ipsec_set_strerror(strerror(errno));
@@ -1924,9 +1950,7 @@
  * XXX should be rewritten to obtain length explicitly
  */
 int
-pfkey_align(msg, mhp)
-	struct sadb_msg *msg;
-	caddr_t *mhp;
+pfkey_align(struct sadb_msg *msg, caddr_t *mhp)
 {
 	struct sadb_ext *ext;
 	int i;
@@ -2001,6 +2025,9 @@
 #ifdef SADB_X_EXT_PACKET
 		case SADB_X_EXT_PACKET:
 #endif
+#ifdef SADB_X_EXT_KMADDRESS
+		case SADB_X_EXT_KMADDRESS:
+#endif
 #ifdef SADB_X_EXT_SEC_CTX
 		case SADB_X_EXT_SEC_CTX:
 #endif
@@ -2035,8 +2062,7 @@
  *	 0: valid.
  */
 int
-pfkey_check(mhp)
-	caddr_t *mhp;
+pfkey_check(caddr_t *mhp)
 {
 	struct sadb_msg *msg;
 
@@ -2112,6 +2138,12 @@
 			break;
 		/*FALLTHROUGH*/
 	default:
+#ifdef __linux__
+		/* Linux kernel seems to be buggy and return
+		 * uninitialized satype for spd flush message */
+		if (msg->sadb_msg_type == SADB_X_SPDFLUSH)
+			break;
+#endif
 		__ipsec_errcode = EIPSEC_INVAL_SATYPE;
 		return -1;
 	}
@@ -2159,13 +2191,8 @@
  * `buf' must has been allocated sufficiently.
  */
 static caddr_t
-pfkey_setsadbmsg(buf, lim, type, tlen, satype, seq, pid)
-	caddr_t buf;
-	caddr_t lim;
-	u_int type, satype;
-	u_int tlen;
-	u_int32_t seq;
-	pid_t pid;
+pfkey_setsadbmsg(caddr_t buf, caddr_t lim, u_int type, u_int tlen,
+    u_int satype, u_int32_t seq, pid_t pid)
 {
 	struct sadb_msg *p;
 	u_int len;
@@ -2194,11 +2221,8 @@
  * `buf' must has been allocated sufficiently.
  */
 static caddr_t
-pfkey_setsadbsa(buf, lim, spi, wsize, auth, enc, flags)
-	caddr_t buf;
-	caddr_t lim;
-	u_int32_t spi, flags;
-	u_int wsize, auth, enc;
+pfkey_setsadbsa(caddr_t buf, caddr_t lim, u_int32_t spi, u_int wsize,
+    u_int auth, u_int enc, u_int32_t flags)
 {
 	struct sadb_sa *p;
 	u_int len;
@@ -2228,13 +2252,8 @@
  * prefixlen is in bits.
  */
 static caddr_t
-pfkey_setsadbaddr(buf, lim, exttype, saddr, prefixlen, ul_proto)
-	caddr_t buf;
-	caddr_t lim;
-	u_int exttype;
-	struct sockaddr *saddr;
-	u_int prefixlen;
-	u_int ul_proto;
+pfkey_setsadbaddr(caddr_t buf, caddr_t lim, u_int exttype,
+    struct sockaddr *saddr, u_int prefixlen, u_int ul_proto)
 {
 	struct sadb_address *p;
 	u_int len;
@@ -2257,16 +2276,50 @@
 	return(buf + len);
 }
 
+#ifdef SADB_X_EXT_KMADDRESS
+/*
+ * set data into sadb_x_kmaddress.
+ * `buf' must has been allocated sufficiently.
+ */
+static caddr_t
+pfkey_setsadbkmaddr(caddr_t buf, caddr_t lim, struct sockaddr *local,
+    struct sockaddr *remote)
+{
+	struct sadb_x_kmaddress *p;
+	struct sockaddr *sa;
+	u_int salen = sysdep_sa_len(local);
+	u_int len;
+
+	/* sanity check */
+	if (local->sa_family != remote->sa_family)
+		return NULL;
+
+	p = (void *)buf;
+	len = sizeof(struct sadb_x_kmaddress) + PFKEY_ALIGN8(2*salen);
+
+	if (buf + len > lim)
+		return NULL;
+
+	memset(p, 0, len);
+	p->sadb_x_kmaddress_len = PFKEY_UNIT64(len);
+	p->sadb_x_kmaddress_exttype = SADB_X_EXT_KMADDRESS;
+	p->sadb_x_kmaddress_reserved = 0;
+	sa = (struct sockaddr *)(p + 1);
+	memcpy(sa, local, salen);
+	sa = (struct sockaddr *)((char *)sa + salen);
+	memcpy(sa, remote, salen);
+
+	return(buf + len);
+}
+#endif
+
 /*
  * set sadb_key structure after clearing buffer with zero.
  * OUT: the pointer of buf + len.
  */
 static caddr_t
-pfkey_setsadbkey(buf, lim, type, key, keylen)
-	caddr_t buf;
-	caddr_t lim;
-	caddr_t key;
-	u_int type, keylen;
+pfkey_setsadbkey(caddr_t buf, caddr_t lim, u_int type, caddr_t key,
+    u_int keylen)
 {
 	struct sadb_key *p;
 	u_int len;
@@ -2293,11 +2346,8 @@
  * OUT: the pointer of buf + len.
  */
 static caddr_t
-pfkey_setsadblifetime(buf, lim, type, l_alloc, l_bytes, l_addtime, l_usetime)
-	caddr_t buf;
-	caddr_t lim;
-	u_int type;
-	u_int32_t l_alloc, l_bytes, l_addtime, l_usetime;
+pfkey_setsadblifetime(caddr_t buf, caddr_t lim, u_int type, u_int32_t l_alloc,
+    u_int32_t l_bytes, u_int32_t l_addtime, u_int32_t l_usetime)
 {
 	struct sadb_lifetime *p;
 	u_int len;
@@ -2339,11 +2389,7 @@
  * `buf' must has been allocated sufficiently.
  */
 static caddr_t
-pfkey_setsadbxsa2(buf, lim, mode0, reqid)
-	caddr_t buf;
-	caddr_t lim;
-	u_int32_t mode0;
-	u_int32_t reqid;
+pfkey_setsadbxsa2(caddr_t buf, caddr_t lim, u_int32_t mode0, u_int32_t reqid)
 {
 	struct sadb_x_sa2 *p;
 	u_int8_t mode = mode0 & 0xff;
@@ -2366,11 +2412,7 @@
 
 #ifdef SADB_X_EXT_NAT_T_TYPE
 static caddr_t
-pfkey_set_natt_type(buf, lim, type, l_natt_type)
-	caddr_t buf;
-	caddr_t lim;
-	u_int type;
-	u_int8_t l_natt_type;
+pfkey_set_natt_type(caddr_t buf, caddr_t lim, u_int type, u_int8_t l_natt_type)
 {
 	struct sadb_x_nat_t_type *p;
 	u_int len;
@@ -2390,11 +2432,7 @@
 }
 
 static caddr_t
-pfkey_set_natt_port(buf, lim, type, l_natt_port)
-	caddr_t buf;
-	caddr_t lim;
-	u_int type;
-	u_int16_t l_natt_port;
+pfkey_set_natt_port(caddr_t buf, caddr_t lim, u_int type, u_int16_t l_natt_port)
 {
 	struct sadb_x_nat_t_port *p;
 	u_int len;
@@ -2416,11 +2454,8 @@
 
 #ifdef SADB_X_EXT_NAT_T_FRAG
 static caddr_t
-pfkey_set_natt_frag(buf, lim, type, l_natt_frag)
-	caddr_t buf;
-	caddr_t lim;
-	u_int type;
-	u_int16_t l_natt_frag;
+pfkey_set_natt_frag(caddr_t buf, caddr_t lim, u_int type, 
+    u_int16_t l_natt_frag)
 {
 	struct sadb_x_nat_t_frag *p;
 	u_int len;
@@ -2442,13 +2477,8 @@
 
 #ifdef SADB_X_EXT_SEC_CTX
 static caddr_t
-pfkey_setsecctx(buf, lim, type, ctx_doi, ctx_alg, sec_ctx, sec_ctxlen)
-	caddr_t buf;
-	caddr_t lim;
-	u_int type;
-	u_int8_t ctx_doi, ctx_alg;
-	caddr_t sec_ctx;
-	u_int16_t sec_ctxlen;
+pfkey_setsecctx(caddr_t buf, caddr_t lim, u_int type, u_int8_t ctx_doi,
+    u_int8_t ctx_alg, caddr_t sec_ctx, u_int16_t sec_ctxlen)
 {
 	struct sadb_x_sec_ctx *p;
 	u_int len;
@@ -2477,18 +2507,11 @@
  * libipsec users. Please use pfkey_send_update2 and pfkey_send_add2 instead 
  */
 int
-pfkey_send_update(so, satype, mode, src, dst, spi, reqid, wsize,
-		keymat, e_type, e_keylen, a_type, a_keylen, flags,
-		l_alloc, l_bytes, l_addtime, l_usetime, seq)
-	int so;
-	u_int satype, mode, wsize;
-	struct sockaddr *src, *dst;
-	u_int32_t spi, reqid;
-	caddr_t keymat;
-	u_int e_type, e_keylen, a_type, a_keylen, flags;
-	u_int32_t l_alloc;
-	u_int64_t l_bytes, l_addtime, l_usetime;
-	u_int32_t seq;
+pfkey_send_update(int so, u_int satype, u_int mode, struct sockaddr *src,
+    struct sockaddr *dst, u_int32_t spi, u_int32_t reqid, u_int wsize,
+    caddr_t keymat, u_int e_type, u_int e_keylen, u_int a_type,
+    u_int a_keylen, u_int flags, u_int32_t l_alloc, u_int64_t l_bytes,
+    u_int64_t l_addtime, u_int64_t l_usetime, u_int32_t seq)
 {
 	struct pfkey_send_sa_args psaa;
 
@@ -2518,24 +2541,13 @@
 }
 
 int
-pfkey_send_update_nat(so, satype, mode, src, dst, spi, reqid, wsize,
-		      keymat, e_type, e_keylen, a_type, a_keylen, flags,
-		      l_alloc, l_bytes, l_addtime, l_usetime, seq,
-		      l_natt_type, l_natt_sport, l_natt_dport, l_natt_oa,
-		      l_natt_frag)
-	int so;
-	u_int satype, mode, wsize;
-	struct sockaddr *src, *dst;
-	u_int32_t spi, reqid;
-	caddr_t keymat;
-	u_int e_type, e_keylen, a_type, a_keylen, flags;
-	u_int32_t l_alloc;
-	u_int64_t l_bytes, l_addtime, l_usetime;
-	u_int32_t seq;
-	u_int8_t l_natt_type;
-	u_int16_t l_natt_sport, l_natt_dport;
-	struct sockaddr *l_natt_oa;
-	u_int16_t l_natt_frag;
+pfkey_send_update_nat(int so, u_int satype, u_int mode, struct sockaddr *src,
+    struct sockaddr *dst, u_int32_t spi, u_int32_t reqid, u_int wsize,
+    caddr_t keymat, u_int e_type, u_int e_keylen, u_int a_type,
+    u_int a_keylen, u_int flags, u_int32_t l_alloc, u_int64_t l_bytes,
+    u_int64_t l_addtime, u_int64_t l_usetime, u_int32_t seq,
+    u_int8_t l_natt_type, u_int16_t l_natt_sport, u_int16_t l_natt_dport,
+    struct sockaddr *l_natt_oa, u_int16_t l_natt_frag)
 {
 	struct pfkey_send_sa_args psaa;
 
@@ -2570,18 +2582,11 @@
 }
 
 int
-pfkey_send_add(so, satype, mode, src, dst, spi, reqid, wsize,
-		keymat, e_type, e_keylen, a_type, a_keylen, flags,
-		l_alloc, l_bytes, l_addtime, l_usetime, seq)
-	int so;
-	u_int satype, mode, wsize;
-	struct sockaddr *src, *dst;
-	u_int32_t spi, reqid;
-	caddr_t keymat;
-	u_int e_type, e_keylen, a_type, a_keylen, flags;
-	u_int32_t l_alloc;
-	u_int64_t l_bytes, l_addtime, l_usetime;
-	u_int32_t seq;
+pfkey_send_add(int so, u_int satype, u_int mode, struct sockaddr *src,
+    struct sockaddr *dst, u_int32_t spi, u_int32_t reqid, u_int wsize,
+    caddr_t keymat, u_int e_type, u_int e_keylen, u_int a_type,
+    u_int a_keylen, u_int flags, u_int32_t l_alloc, u_int64_t l_bytes,
+    u_int64_t l_addtime, u_int64_t l_usetime, u_int32_t seq)
 {
 	struct pfkey_send_sa_args psaa;
 
@@ -2611,24 +2616,13 @@
 }
 
 int
-pfkey_send_add_nat(so, satype, mode, src, dst, spi, reqid, wsize,
-		      keymat, e_type, e_keylen, a_type, a_keylen, flags,
-		      l_alloc, l_bytes, l_addtime, l_usetime, seq,
-		      l_natt_type, l_natt_sport, l_natt_dport, l_natt_oa,
-		      l_natt_frag)
-	int so;
-	u_int satype, mode, wsize;
-	struct sockaddr *src, *dst;
-	u_int32_t spi, reqid;
-	caddr_t keymat;
-	u_int e_type, e_keylen, a_type, a_keylen, flags;
-	u_int32_t l_alloc;
-	u_int64_t l_bytes, l_addtime, l_usetime;
-	u_int32_t seq;
-	u_int8_t l_natt_type;
-	u_int16_t l_natt_sport, l_natt_dport;
-	struct sockaddr *l_natt_oa;
-	u_int16_t l_natt_frag;
+pfkey_send_add_nat(int so, u_int satype, u_int mode, struct sockaddr *src,
+    struct sockaddr *dst, u_int32_t spi, u_int32_t reqid, u_int wsize,
+    caddr_t keymat, u_int e_type, u_int e_keylen, u_int a_type,
+    u_int a_keylen, u_int flags, u_int32_t l_alloc, u_int64_t l_bytes,
+    u_int64_t l_addtime, u_int64_t l_usetime, u_int32_t seq,
+    u_int8_t l_natt_type, u_int16_t l_natt_sport, u_int16_t l_natt_dport,
+    struct sockaddr *l_natt_oa, u_int16_t l_natt_frag)
 {
 	struct pfkey_send_sa_args psaa;
 
diff --git a/src/libipsec/pfkey_dump.c b/src/libipsec/pfkey_dump.c
index 8fa4084..4627ebc 100644
--- a/src/libipsec/pfkey_dump.c
+++ b/src/libipsec/pfkey_dump.c
@@ -1,4 +1,4 @@
-/*	$NetBSD: pfkey_dump.c,v 1.15.6.1 2007/08/01 11:52:18 vanhu Exp $	*/
+/*	$NetBSD: pfkey_dump.c,v 1.18 2010/12/03 14:32:52 tteras Exp $	*/
 
 /*	$KAME: pfkey_dump.c,v 1.45 2003/09/08 10:14:56 itojun Exp $	*/
 
@@ -716,13 +716,19 @@
 	else
 		snprintf(prefbuf, sizeof(prefbuf), "/%u", pref);
 
-	if (ulp == IPPROTO_ICMPV6)
+	switch (ulp) {
+	case IPPROTO_ICMP:
+	case IPPROTO_ICMPV6:
+	case IPPROTO_MH:
+	case IPPROTO_GRE:
 		memset(portbuf, 0, sizeof(portbuf));
-	else {
+		break;
+	default:
 		if (port == IPSEC_PORT_ANY)
-			snprintf(portbuf, sizeof(portbuf), "[%s]", "any");
+			strcpy(portbuf, "[any]");
 		else
 			snprintf(portbuf, sizeof(portbuf), "[%u]", port);
+		break;
 	}
 
 	snprintf(buf, sizeof(buf), "%s%s", prefbuf, portbuf);
@@ -734,29 +740,26 @@
 str_upperspec(ulp, p1, p2)
 	u_int ulp, p1, p2;
 {
-	if (ulp == IPSEC_ULPROTO_ANY)
-		printf("any");
-	else if (ulp == IPPROTO_ICMPV6) {
-		printf("icmp6");
-		if (!(p1 == IPSEC_PORT_ANY && p2 == IPSEC_PORT_ANY))
-			printf(" %u,%u", p1, p2);
-	} else {
-		struct protoent *ent;
+	struct protoent *ent;
 
-		switch (ulp) {
-		case IPPROTO_IPV4:
-			printf("ip4");
-			break;
-		default:
-			ent = getprotobynumber((int)ulp);
-			if (ent)
-				printf("%s", ent->p_name);
-			else
-				printf("%u", ulp);
+	ent = getprotobynumber((int)ulp);
+	if (ent)
+		printf("%s", ent->p_name);
+	else
+		printf("%u", ulp);
 
-			endprotoent();
-			break;
-		}
+	if (p1 == IPSEC_PORT_ANY && p2 == IPSEC_PORT_ANY)
+		return;
+
+	switch (ulp) {
+	case IPPROTO_ICMP:
+	case IPPROTO_ICMPV6:
+	case IPPROTO_MH:
+		printf(" %u,%u", p1, p2);
+		break;
+	case IPPROTO_GRE:
+		printf(" %u", (p1 << 16) + p2);
+		break;
 	}
 }
 
@@ -774,8 +777,10 @@
 		for (;i < 20;) buf[i++] = ' ';
 	} else {
 		char *t0;
-		t0 = ctime(&t);
-		memcpy(buf, t0 + 4, 20);
+		if ((t0 = ctime(&t)) == NULL)
+			memset(buf, '?', 20);
+		else
+			memcpy(buf, t0 + 4, 20);
 	}
 
 	buf[20] = '\0';
diff --git a/src/libipsec/policy_parse.h b/src/libipsec/policy_parse.h
index a4c1d0b..dc629dd 100644
--- a/src/libipsec/policy_parse.h
+++ b/src/libipsec/policy_parse.h
@@ -1,24 +1,23 @@
-/* A Bison parser, made by GNU Bison 2.3.  */
+
+/* A Bison parser, made by GNU Bison 2.4.1.  */
 
 /* Skeleton interface for Bison's Yacc-like parsers in C
-
-   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+   
+      Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
    Free Software Foundation, Inc.
-
-   This program is free software; you can redistribute it and/or modify
+   
+   This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
-   any later version.
-
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+   
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
-
+   
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301, USA.  */
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 /* As a special exception, you may create a larger work that contains
    part or all of the Bison parser skeleton and distribute that work
@@ -29,10 +28,11 @@
    special exception, which will cause the skeleton and the resulting
    Bison output files to be licensed under the GNU General Public
    License without this special exception.
-
+   
    This special exception was added by the Free Software Foundation in
    version 2.2 of Bison.  */
 
+
 /* Tokens.  */
 #ifndef YYTOKENTYPE
 # define YYTOKENTYPE
@@ -80,22 +80,28 @@
 
 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
 typedef union YYSTYPE
-#line 129 "policy_parse.y"
 {
+
+/* Line 1676 of yacc.c  */
+#line 129 "policy_parse.y"
+
 	u_int num;
 	u_int32_t num32;
 	struct _val {
 		int len;
 		char *buf;
 	} val;
-}
-/* Line 1489 of yacc.c.  */
-#line 94 "policy_parse.h"
-	YYSTYPE;
+
+
+
+/* Line 1676 of yacc.c  */
+#line 99 "policy_parse.h"
+} YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
 # define yystype YYSTYPE /* obsolescent; will be withdrawn */
 # define YYSTYPE_IS_DECLARED 1
-# define YYSTYPE_IS_TRIVIAL 1
 #endif
 
 extern YYSTYPE __libipseclval;
 
+
diff --git a/src/libipsec/policy_parse.y b/src/libipsec/policy_parse.y
index a13dc12..321f4f0 100644
--- a/src/libipsec/policy_parse.y
+++ b/src/libipsec/policy_parse.y
@@ -1,4 +1,4 @@
-/*	$NetBSD: policy_parse.y,v 1.9.6.2 2009/02/16 18:38:26 tteras Exp $	*/
+/*	$NetBSD: policy_parse.y,v 1.11 2009/02/16 18:36:21 tteras Exp $	*/
 
 /*	$KAME: policy_parse.y,v 1.21 2003/12/12 08:01:26 itojun Exp $	*/
 
diff --git a/src/libipsec/policy_token.l b/src/libipsec/policy_token.l
index 0833c20..243b678 100644
--- a/src/libipsec/policy_token.l
+++ b/src/libipsec/policy_token.l
@@ -1,4 +1,4 @@
-/*	$NetBSD: policy_token.l,v 1.6.6.1 2007/08/01 11:52:19 vanhu Exp $	*/
+/*	$NetBSD: policy_token.l,v 1.7 2007/07/18 12:07:50 vanhu Exp $	*/
 
 /* Id: policy_token.l,v 1.12 2005/05/05 12:32:18 manubsd Exp */
 
diff --git a/src/racoon/Makefile.am b/src/racoon/Makefile.am
index 202a18e..dbaded9 100644
--- a/src/racoon/Makefile.am
+++ b/src/racoon/Makefile.am
@@ -3,7 +3,7 @@
 sbin_PROGRAMS = racoon racoonctl plainrsa-gen
 noinst_PROGRAMS = eaytest
 include_racoon_HEADERS = racoonctl.h var.h vmbuf.h misc.h gcmalloc.h admin.h \
-	schedule.h sockmisc.h vmbuf.h isakmp_var.h isakmp.h isakmp_xauth.h \
+	schedule.h sockmisc.h isakmp_var.h isakmp.h isakmp_xauth.h \
 	isakmp_cfg.h isakmp_unity.h ipsec_doi.h evt.h
 lib_LTLIBRARIES = libracoon.la
 
@@ -48,6 +48,7 @@
 racoonctl_LDADD = libracoon.la ../libipsec/libipsec.la 
 
 libracoon_la_SOURCES = kmpstat.c vmbuf.c sockmisc.c misc.c
+libracoon_la_CFLAGS = -DNOUSE_PRIVSEP $(AM_CFLAGS)
 
 plainrsa_gen_SOURCES = plainrsa-gen.c plog.c \
 	crypto_openssl.c logger.c 
@@ -88,6 +89,7 @@
    ${man5_MANS} ${man8_MANS} \
    missing/crypto/rijndael/boxes-fst.dat \
    doc/FAQ doc/README.certificate doc/README.gssapi doc/README.plainrsa \
+   doc/README.privsep \
    contrib/sp.pl stats.pl \
    samples/psk.txt.sample  samples/racoon.conf.sample \
    samples/psk.txt.in samples/racoon.conf.in \
diff --git a/src/racoon/Makefile.in b/src/racoon/Makefile.in
index 47e997b..4b4e635 100644
--- a/src/racoon/Makefile.in
+++ b/src/racoon/Makefile.in
@@ -1,8 +1,9 @@
-# Makefile.in generated by automake 1.10.1 from Makefile.am.
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
 # @configure_input@
 
 # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
-# 2003, 2004, 2005, 2006, 2007, 2008  Free Software Foundation, Inc.
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009  Free Software Foundation,
+# Inc.
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
 # with or without modifications, as long as this notice is preserved.
@@ -20,8 +21,9 @@
 
 VPATH = @srcdir@
 pkgdatadir = $(datadir)/@PACKAGE@
-pkglibdir = $(libdir)/@PACKAGE@
 pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
 am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
 install_sh_DATA = $(install_sh) -c -m 644
 install_sh_PROGRAM = $(install_sh) -c
@@ -52,21 +54,40 @@
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/config.h
 CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
 am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
 am__vpath_adj = case $$p in \
     $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
     *) f=$$p;; \
   esac;
-am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+  srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+  for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+  for p in $$list; do echo "$$p $$p"; done | \
+  sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+  $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+    if (++n[$$2] == $(am__install_max)) \
+      { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+    END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+  sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+  sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
 am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(sbindir)" \
 	"$(DESTDIR)$(man5dir)" "$(DESTDIR)$(man8dir)" \
 	"$(DESTDIR)$(include_racoondir)"
-libLTLIBRARIES_INSTALL = $(INSTALL)
 LTLIBRARIES = $(lib_LTLIBRARIES)
 libracoon_la_LIBADD =
-am_libracoon_la_OBJECTS = kmpstat.lo vmbuf.lo sockmisc.lo misc.lo
+am_libracoon_la_OBJECTS = libracoon_la-kmpstat.lo \
+	libracoon_la-vmbuf.lo libracoon_la-sockmisc.lo \
+	libracoon_la-misc.lo
 libracoon_la_OBJECTS = $(am_libracoon_la_OBJECTS)
-sbinPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
+libracoon_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(libracoon_la_CFLAGS) \
+	$(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
 PROGRAMS = $(noinst_PROGRAMS) $(sbin_PROGRAMS)
 am_eaytest_OBJECTS = eaytest.$(OBJEXT) plog.$(OBJEXT) logger.$(OBJEXT)
 eaytest_OBJECTS = $(am_eaytest_OBJECTS)
@@ -96,6 +117,7 @@
 DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
 depcomp = $(SHELL) $(top_srcdir)/depcomp
 am__depfiles_maybe = depfiles
+am__mv = mv -f
 COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
 	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
 LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
@@ -124,10 +146,11 @@
 man8dir = $(mandir)/man8
 NROFF = nroff
 MANS = $(man5_MANS) $(man8_MANS)
-include_racoonHEADERS_INSTALL = $(INSTALL_HEADER)
 HEADERS = $(include_racoon_HEADERS) $(noinst_HEADERS)
 ETAGS = etags
 CTAGS = ctags
+am__tty_colors = \
+red=; grn=; lgn=; blu=; std=
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 ACLOCAL = @ACLOCAL@
 AMTAR = @AMTAR@
@@ -143,23 +166,18 @@
 CPP = @CPP@
 CPPFLAGS = @CPPFLAGS@
 CRYPTOBJS = @CRYPTOBJS@
-CXX = @CXX@
-CXXCPP = @CXXCPP@
-CXXDEPMODE = @CXXDEPMODE@
-CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
 DEFS = @DEFS@
 DEPDIR = @DEPDIR@
 DSYMUTIL = @DSYMUTIL@
-ECHO = @ECHO@
+DUMPBIN = @DUMPBIN@
 ECHO_C = @ECHO_C@
 ECHO_N = @ECHO_N@
 ECHO_T = @ECHO_T@
 EGREP = @EGREP@
 EXEEXT = @EXEEXT@
 EXTRA_CRYPTO = @EXTRA_CRYPTO@
-F77 = @F77@
-FFLAGS = @FFLAGS@
+FGREP = @FGREP@
 FRAG_OBJS = @FRAG_OBJS@
 GLIBC_BUGS = @GLIBC_BUGS@
 GREP = @GREP@
@@ -173,6 +191,7 @@
 INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
 KERNEL_INCLUDE = @KERNEL_INCLUDE@
 KRB5_CONFIG = @KRB5_CONFIG@
+LD = @LD@
 LDFLAGS = @LDFLAGS@
 LEX = @LEX@
 LEXLIB = @LEXLIB@
@@ -180,18 +199,24 @@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
 LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
 LN_S = @LN_S@
 LTLIBOBJS = @LTLIBOBJS@
 MAKEINFO = @MAKEINFO@
 MKDIR_P = @MKDIR_P@
 NATT_OBJS = @NATT_OBJS@
+NM = @NM@
 NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
 OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
 PACKAGE = @PACKAGE@
 PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
 PACKAGE_NAME = @PACKAGE_NAME@
 PACKAGE_STRING = @PACKAGE_STRING@
 PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
 PACKAGE_VERSION = @PACKAGE_VERSION@
 PATH_SEPARATOR = @PATH_SEPARATOR@
 RANLIB = @RANLIB@
@@ -209,8 +234,7 @@
 abs_top_builddir = @abs_top_builddir@
 abs_top_srcdir = @abs_top_srcdir@
 ac_ct_CC = @ac_ct_CC@
-ac_ct_CXX = @ac_ct_CXX@
-ac_ct_F77 = @ac_ct_F77@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
 am__include = @am__include@
 am__leading_dot = @am__leading_dot@
 am__quote = @am__quote@
@@ -242,6 +266,7 @@
 libexecdir = @libexecdir@
 localedir = @localedir@
 localstatedir = @localstatedir@
+lt_ECHO = @lt_ECHO@
 mandir = @mandir@
 mkdir_p = @mkdir_p@
 oldincludedir = @oldincludedir@
@@ -254,10 +279,11 @@
 srcdir = @srcdir@
 sysconfdir = @sysconfdir@
 target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
 include_racoon_HEADERS = racoonctl.h var.h vmbuf.h misc.h gcmalloc.h admin.h \
-	schedule.h sockmisc.h vmbuf.h isakmp_var.h isakmp.h isakmp_xauth.h \
+	schedule.h sockmisc.h isakmp_var.h isakmp.h isakmp_xauth.h \
 	isakmp_cfg.h isakmp_unity.h ipsec_doi.h evt.h
 
 lib_LTLIBRARIES = libracoon.la
@@ -302,6 +328,7 @@
 racoonctl_SOURCES = racoonctl.c str2val.c 
 racoonctl_LDADD = libracoon.la ../libipsec/libipsec.la 
 libracoon_la_SOURCES = kmpstat.c vmbuf.c sockmisc.c misc.c
+libracoon_la_CFLAGS = -DNOUSE_PRIVSEP $(AM_CFLAGS)
 plainrsa_gen_SOURCES = plainrsa-gen.c plog.c \
 	crypto_openssl.c logger.c 
 
@@ -341,6 +368,7 @@
    ${man5_MANS} ${man8_MANS} \
    missing/crypto/rijndael/boxes-fst.dat \
    doc/FAQ doc/README.certificate doc/README.gssapi doc/README.plainrsa \
+   doc/README.privsep \
    contrib/sp.pl stats.pl \
    samples/psk.txt.sample  samples/racoon.conf.sample \
    samples/psk.txt.in samples/racoon.conf.in \
@@ -362,14 +390,14 @@
 	@for dep in $?; do \
 	  case '$(am__configure_deps)' in \
 	    *$$dep*) \
-	      cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
-		&& exit 0; \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
 	      exit 1;; \
 	  esac; \
 	done; \
-	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign  src/racoon/Makefile'; \
-	cd $(top_srcdir) && \
-	  $(AUTOMAKE) --foreign  src/racoon/Makefile
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/racoon/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign src/racoon/Makefile
 .PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
@@ -387,23 +415,28 @@
 	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
 $(ACLOCAL_M4):  $(am__aclocal_m4_deps)
 	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
 install-libLTLIBRARIES: $(lib_LTLIBRARIES)
 	@$(NORMAL_INSTALL)
 	test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)"
-	@list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+	@list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+	list2=; for p in $$list; do \
 	  if test -f $$p; then \
-	    f=$(am__strip_dir) \
-	    echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(libdir)/$$f'"; \
-	    $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(libdir)/$$f"; \
+	    list2="$$list2 $$p"; \
 	  else :; fi; \
-	done
+	done; \
+	test -z "$$list2" || { \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \
+	}
 
 uninstall-libLTLIBRARIES:
 	@$(NORMAL_UNINSTALL)
-	@list='$(lib_LTLIBRARIES)'; for p in $$list; do \
-	  p=$(am__strip_dir) \
-	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$p'"; \
-	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$p"; \
+	@list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+	for p in $$list; do \
+	  $(am__strip_dir) \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \
 	done
 
 clean-libLTLIBRARIES:
@@ -415,42 +448,59 @@
 	  rm -f "$${dir}/so_locations"; \
 	done
 libracoon.la: $(libracoon_la_OBJECTS) $(libracoon_la_DEPENDENCIES) 
-	$(LINK) -rpath $(libdir) $(libracoon_la_OBJECTS) $(libracoon_la_LIBADD) $(LIBS)
+	$(libracoon_la_LINK) -rpath $(libdir) $(libracoon_la_OBJECTS) $(libracoon_la_LIBADD) $(LIBS)
 
 clean-noinstPROGRAMS:
-	@list='$(noinst_PROGRAMS)'; for p in $$list; do \
-	  f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
-	  echo " rm -f $$p $$f"; \
-	  rm -f $$p $$f ; \
-	done
+	@list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \
+	echo " rm -f" $$list; \
+	rm -f $$list || exit $$?; \
+	test -n "$(EXEEXT)" || exit 0; \
+	list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+	echo " rm -f" $$list; \
+	rm -f $$list
 install-sbinPROGRAMS: $(sbin_PROGRAMS)
 	@$(NORMAL_INSTALL)
 	test -z "$(sbindir)" || $(MKDIR_P) "$(DESTDIR)$(sbindir)"
-	@list='$(sbin_PROGRAMS)'; for p in $$list; do \
-	  p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
-	  if test -f $$p \
-	     || test -f $$p1 \
-	  ; then \
-	    f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
-	   echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(sbinPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(sbindir)/$$f'"; \
-	   $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(sbinPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(sbindir)/$$f" || exit 1; \
-	  else :; fi; \
-	done
+	@list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \
+	for p in $$list; do echo "$$p $$p"; done | \
+	sed 's/$(EXEEXT)$$//' | \
+	while read p p1; do if test -f $$p || test -f $$p1; \
+	  then echo "$$p"; echo "$$p"; else :; fi; \
+	done | \
+	sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \
+	    -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
+	sed 'N;N;N;s,\n, ,g' | \
+	$(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
+	  { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+	    if ($$2 == $$4) files[d] = files[d] " " $$1; \
+	    else { print "f", $$3 "/" $$4, $$1; } } \
+	  END { for (d in files) print "f", d, files[d] }' | \
+	while read type dir files; do \
+	    if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+	    test -z "$$files" || { \
+	    echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \
+	    $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \
+	    } \
+	; done
 
 uninstall-sbinPROGRAMS:
 	@$(NORMAL_UNINSTALL)
-	@list='$(sbin_PROGRAMS)'; for p in $$list; do \
-	  f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
-	  echo " rm -f '$(DESTDIR)$(sbindir)/$$f'"; \
-	  rm -f "$(DESTDIR)$(sbindir)/$$f"; \
-	done
+	@list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \
+	files=`for p in $$list; do echo "$$p"; done | \
+	  sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
+	      -e 's/$$/$(EXEEXT)/' `; \
+	test -n "$$list" || exit 0; \
+	echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \
+	cd "$(DESTDIR)$(sbindir)" && rm -f $$files
 
 clean-sbinPROGRAMS:
-	@list='$(sbin_PROGRAMS)'; for p in $$list; do \
-	  f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
-	  echo " rm -f $$p $$f"; \
-	  rm -f $$p $$f ; \
-	done
+	@list='$(sbin_PROGRAMS)'; test -n "$$list" || exit 0; \
+	echo " rm -f" $$list; \
+	rm -f $$list || exit $$?; \
+	test -n "$(EXEEXT)" || exit 0; \
+	list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+	echo " rm -f" $$list; \
+	rm -f $$list
 eaytest$(EXEEXT): $(eaytest_OBJECTS) $(eaytest_DEPENDENCIES) 
 	@rm -f eaytest$(EXEEXT)
 	$(LINK) $(eaytest_OBJECTS) $(eaytest_LDADD) $(LIBS)
@@ -506,11 +556,13 @@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isakmp_quick.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isakmp_unity.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isakmp_xauth.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kmpstat.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libracoon_la-kmpstat.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libracoon_la-misc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libracoon_la-sockmisc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libracoon_la-vmbuf.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/localconf.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/logger.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/misc.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nattraversal.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/oakley.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pfkey.Po@am__quote@
@@ -532,51 +584,77 @@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/security.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/session.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sha2.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sockmisc.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/str2val.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/strnames.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/throttle.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vendorid.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vmbuf.Plo@am__quote@
 
 .c.o:
 @am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
-@am__fastdepCC_TRUE@	mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(COMPILE) -c $<
 
 .c.obj:
 @am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
-@am__fastdepCC_TRUE@	mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(COMPILE) -c `$(CYGPATH_W) '$<'`
 
 .c.lo:
 @am__fastdepCC_TRUE@	$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
-@am__fastdepCC_TRUE@	mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(LTCOMPILE) -c -o $@ $<
 
+libracoon_la-kmpstat.lo: kmpstat.c
+@am__fastdepCC_TRUE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libracoon_la_CFLAGS) $(CFLAGS) -MT libracoon_la-kmpstat.lo -MD -MP -MF $(DEPDIR)/libracoon_la-kmpstat.Tpo -c -o libracoon_la-kmpstat.lo `test -f 'kmpstat.c' || echo '$(srcdir)/'`kmpstat.c
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/libracoon_la-kmpstat.Tpo $(DEPDIR)/libracoon_la-kmpstat.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='kmpstat.c' object='libracoon_la-kmpstat.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libracoon_la_CFLAGS) $(CFLAGS) -c -o libracoon_la-kmpstat.lo `test -f 'kmpstat.c' || echo '$(srcdir)/'`kmpstat.c
+
+libracoon_la-vmbuf.lo: vmbuf.c
+@am__fastdepCC_TRUE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libracoon_la_CFLAGS) $(CFLAGS) -MT libracoon_la-vmbuf.lo -MD -MP -MF $(DEPDIR)/libracoon_la-vmbuf.Tpo -c -o libracoon_la-vmbuf.lo `test -f 'vmbuf.c' || echo '$(srcdir)/'`vmbuf.c
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/libracoon_la-vmbuf.Tpo $(DEPDIR)/libracoon_la-vmbuf.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='vmbuf.c' object='libracoon_la-vmbuf.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libracoon_la_CFLAGS) $(CFLAGS) -c -o libracoon_la-vmbuf.lo `test -f 'vmbuf.c' || echo '$(srcdir)/'`vmbuf.c
+
+libracoon_la-sockmisc.lo: sockmisc.c
+@am__fastdepCC_TRUE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libracoon_la_CFLAGS) $(CFLAGS) -MT libracoon_la-sockmisc.lo -MD -MP -MF $(DEPDIR)/libracoon_la-sockmisc.Tpo -c -o libracoon_la-sockmisc.lo `test -f 'sockmisc.c' || echo '$(srcdir)/'`sockmisc.c
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/libracoon_la-sockmisc.Tpo $(DEPDIR)/libracoon_la-sockmisc.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='sockmisc.c' object='libracoon_la-sockmisc.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libracoon_la_CFLAGS) $(CFLAGS) -c -o libracoon_la-sockmisc.lo `test -f 'sockmisc.c' || echo '$(srcdir)/'`sockmisc.c
+
+libracoon_la-misc.lo: misc.c
+@am__fastdepCC_TRUE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libracoon_la_CFLAGS) $(CFLAGS) -MT libracoon_la-misc.lo -MD -MP -MF $(DEPDIR)/libracoon_la-misc.Tpo -c -o libracoon_la-misc.lo `test -f 'misc.c' || echo '$(srcdir)/'`misc.c
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/libracoon_la-misc.Tpo $(DEPDIR)/libracoon_la-misc.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='misc.c' object='libracoon_la-misc.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libracoon_la_CFLAGS) $(CFLAGS) -c -o libracoon_la-misc.lo `test -f 'misc.c' || echo '$(srcdir)/'`misc.c
+
 sha2.obj: missing/crypto/sha2/sha2.c
 @am__fastdepCC_TRUE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT sha2.obj -MD -MP -MF $(DEPDIR)/sha2.Tpo -c -o sha2.obj `if test -f 'missing/crypto/sha2/sha2.c'; then $(CYGPATH_W) 'missing/crypto/sha2/sha2.c'; else $(CYGPATH_W) '$(srcdir)/missing/crypto/sha2/sha2.c'; fi`
-@am__fastdepCC_TRUE@	mv -f $(DEPDIR)/sha2.Tpo $(DEPDIR)/sha2.Po
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/sha2.Tpo $(DEPDIR)/sha2.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	source='missing/crypto/sha2/sha2.c' object='sha2.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sha2.obj `if test -f 'missing/crypto/sha2/sha2.c'; then $(CYGPATH_W) 'missing/crypto/sha2/sha2.c'; else $(CYGPATH_W) '$(srcdir)/missing/crypto/sha2/sha2.c'; fi`
 
 rijndael-api-fst.obj: missing/crypto/rijndael/rijndael-api-fst.c
 @am__fastdepCC_TRUE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT rijndael-api-fst.obj -MD -MP -MF $(DEPDIR)/rijndael-api-fst.Tpo -c -o rijndael-api-fst.obj `if test -f 'missing/crypto/rijndael/rijndael-api-fst.c'; then $(CYGPATH_W) 'missing/crypto/rijndael/rijndael-api-fst.c'; else $(CYGPATH_W) '$(srcdir)/missing/crypto/rijndael/rijndael-api-fst.c'; fi`
-@am__fastdepCC_TRUE@	mv -f $(DEPDIR)/rijndael-api-fst.Tpo $(DEPDIR)/rijndael-api-fst.Po
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/rijndael-api-fst.Tpo $(DEPDIR)/rijndael-api-fst.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	source='missing/crypto/rijndael/rijndael-api-fst.c' object='rijndael-api-fst.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o rijndael-api-fst.obj `if test -f 'missing/crypto/rijndael/rijndael-api-fst.c'; then $(CYGPATH_W) 'missing/crypto/rijndael/rijndael-api-fst.c'; else $(CYGPATH_W) '$(srcdir)/missing/crypto/rijndael/rijndael-api-fst.c'; fi`
 
 rijndael-alg-fst.obj: missing/crypto/rijndael/rijndael-alg-fst.c
 @am__fastdepCC_TRUE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT rijndael-alg-fst.obj -MD -MP -MF $(DEPDIR)/rijndael-alg-fst.Tpo -c -o rijndael-alg-fst.obj `if test -f 'missing/crypto/rijndael/rijndael-alg-fst.c'; then $(CYGPATH_W) 'missing/crypto/rijndael/rijndael-alg-fst.c'; else $(CYGPATH_W) '$(srcdir)/missing/crypto/rijndael/rijndael-alg-fst.c'; fi`
-@am__fastdepCC_TRUE@	mv -f $(DEPDIR)/rijndael-alg-fst.Tpo $(DEPDIR)/rijndael-alg-fst.Po
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/rijndael-alg-fst.Tpo $(DEPDIR)/rijndael-alg-fst.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	source='missing/crypto/rijndael/rijndael-alg-fst.c' object='rijndael-alg-fst.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o rijndael-alg-fst.obj `if test -f 'missing/crypto/rijndael/rijndael-alg-fst.c'; then $(CYGPATH_W) 'missing/crypto/rijndael/rijndael-alg-fst.c'; else $(CYGPATH_W) '$(srcdir)/missing/crypto/rijndael/rijndael-alg-fst.c'; fi`
@@ -592,127 +670,108 @@
 
 clean-libtool:
 	-rm -rf .libs _libs
-install-man5: $(man5_MANS) $(man_MANS)
+install-man5: $(man5_MANS)
 	@$(NORMAL_INSTALL)
 	test -z "$(man5dir)" || $(MKDIR_P) "$(DESTDIR)$(man5dir)"
-	@list='$(man5_MANS) $(dist_man5_MANS) $(nodist_man5_MANS)'; \
-	l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
-	for i in $$l2; do \
-	  case "$$i" in \
-	    *.5*) list="$$list $$i" ;; \
-	  esac; \
+	@list='$(man5_MANS)'; test -n "$(man5dir)" || exit 0; \
+	{ for i in $$list; do echo "$$i"; done; \
+	} | while read p; do \
+	  if test -f $$p; then d=; else d="$(srcdir)/"; fi; \
+	  echo "$$d$$p"; echo "$$p"; \
+	done | \
+	sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^5][0-9a-z]*$$,5,;x' \
+	      -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \
+	sed 'N;N;s,\n, ,g' | { \
+	list=; while read file base inst; do \
+	  if test "$$base" = "$$inst"; then list="$$list $$file"; else \
+	    echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man5dir)/$$inst'"; \
+	    $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man5dir)/$$inst" || exit $$?; \
+	  fi; \
 	done; \
-	for i in $$list; do \
-	  if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
-	  else file=$$i; fi; \
-	  ext=`echo $$i | sed -e 's/^.*\\.//'`; \
-	  case "$$ext" in \
-	    5*) ;; \
-	    *) ext='5' ;; \
-	  esac; \
-	  inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
-	  inst=`echo $$inst | sed -e 's/^.*\///'`; \
-	  inst=`echo $$inst | sed '$(transform)'`.$$ext; \
-	  echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man5dir)/$$inst'"; \
-	  $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man5dir)/$$inst"; \
-	done
+	for i in $$list; do echo "$$i"; done | $(am__base_list) | \
+	while read files; do \
+	  test -z "$$files" || { \
+	    echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man5dir)'"; \
+	    $(INSTALL_DATA) $$files "$(DESTDIR)$(man5dir)" || exit $$?; }; \
+	done; }
+
 uninstall-man5:
 	@$(NORMAL_UNINSTALL)
-	@list='$(man5_MANS) $(dist_man5_MANS) $(nodist_man5_MANS)'; \
-	l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
-	for i in $$l2; do \
-	  case "$$i" in \
-	    *.5*) list="$$list $$i" ;; \
-	  esac; \
-	done; \
-	for i in $$list; do \
-	  ext=`echo $$i | sed -e 's/^.*\\.//'`; \
-	  case "$$ext" in \
-	    5*) ;; \
-	    *) ext='5' ;; \
-	  esac; \
-	  inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
-	  inst=`echo $$inst | sed -e 's/^.*\///'`; \
-	  inst=`echo $$inst | sed '$(transform)'`.$$ext; \
-	  echo " rm -f '$(DESTDIR)$(man5dir)/$$inst'"; \
-	  rm -f "$(DESTDIR)$(man5dir)/$$inst"; \
-	done
-install-man8: $(man8_MANS) $(man_MANS)
+	@list='$(man5_MANS)'; test -n "$(man5dir)" || exit 0; \
+	files=`{ for i in $$list; do echo "$$i"; done; \
+	} | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^5][0-9a-z]*$$,5,;x' \
+	      -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \
+	test -z "$$files" || { \
+	  echo " ( cd '$(DESTDIR)$(man5dir)' && rm -f" $$files ")"; \
+	  cd "$(DESTDIR)$(man5dir)" && rm -f $$files; }
+install-man8: $(man8_MANS)
 	@$(NORMAL_INSTALL)
 	test -z "$(man8dir)" || $(MKDIR_P) "$(DESTDIR)$(man8dir)"
-	@list='$(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS)'; \
-	l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
-	for i in $$l2; do \
-	  case "$$i" in \
-	    *.8*) list="$$list $$i" ;; \
-	  esac; \
+	@list='$(man8_MANS)'; test -n "$(man8dir)" || exit 0; \
+	{ for i in $$list; do echo "$$i"; done; \
+	} | while read p; do \
+	  if test -f $$p; then d=; else d="$(srcdir)/"; fi; \
+	  echo "$$d$$p"; echo "$$p"; \
+	done | \
+	sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^8][0-9a-z]*$$,8,;x' \
+	      -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \
+	sed 'N;N;s,\n, ,g' | { \
+	list=; while read file base inst; do \
+	  if test "$$base" = "$$inst"; then list="$$list $$file"; else \
+	    echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man8dir)/$$inst'"; \
+	    $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man8dir)/$$inst" || exit $$?; \
+	  fi; \
 	done; \
-	for i in $$list; do \
-	  if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
-	  else file=$$i; fi; \
-	  ext=`echo $$i | sed -e 's/^.*\\.//'`; \
-	  case "$$ext" in \
-	    8*) ;; \
-	    *) ext='8' ;; \
-	  esac; \
-	  inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
-	  inst=`echo $$inst | sed -e 's/^.*\///'`; \
-	  inst=`echo $$inst | sed '$(transform)'`.$$ext; \
-	  echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man8dir)/$$inst'"; \
-	  $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man8dir)/$$inst"; \
-	done
+	for i in $$list; do echo "$$i"; done | $(am__base_list) | \
+	while read files; do \
+	  test -z "$$files" || { \
+	    echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man8dir)'"; \
+	    $(INSTALL_DATA) $$files "$(DESTDIR)$(man8dir)" || exit $$?; }; \
+	done; }
+
 uninstall-man8:
 	@$(NORMAL_UNINSTALL)
-	@list='$(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS)'; \
-	l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
-	for i in $$l2; do \
-	  case "$$i" in \
-	    *.8*) list="$$list $$i" ;; \
-	  esac; \
-	done; \
-	for i in $$list; do \
-	  ext=`echo $$i | sed -e 's/^.*\\.//'`; \
-	  case "$$ext" in \
-	    8*) ;; \
-	    *) ext='8' ;; \
-	  esac; \
-	  inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
-	  inst=`echo $$inst | sed -e 's/^.*\///'`; \
-	  inst=`echo $$inst | sed '$(transform)'`.$$ext; \
-	  echo " rm -f '$(DESTDIR)$(man8dir)/$$inst'"; \
-	  rm -f "$(DESTDIR)$(man8dir)/$$inst"; \
-	done
+	@list='$(man8_MANS)'; test -n "$(man8dir)" || exit 0; \
+	files=`{ for i in $$list; do echo "$$i"; done; \
+	} | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^8][0-9a-z]*$$,8,;x' \
+	      -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \
+	test -z "$$files" || { \
+	  echo " ( cd '$(DESTDIR)$(man8dir)' && rm -f" $$files ")"; \
+	  cd "$(DESTDIR)$(man8dir)" && rm -f $$files; }
 install-include_racoonHEADERS: $(include_racoon_HEADERS)
 	@$(NORMAL_INSTALL)
 	test -z "$(include_racoondir)" || $(MKDIR_P) "$(DESTDIR)$(include_racoondir)"
-	@list='$(include_racoon_HEADERS)'; for p in $$list; do \
+	@list='$(include_racoon_HEADERS)'; test -n "$(include_racoondir)" || list=; \
+	for p in $$list; do \
 	  if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
-	  f=$(am__strip_dir) \
-	  echo " $(include_racoonHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(include_racoondir)/$$f'"; \
-	  $(include_racoonHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(include_racoondir)/$$f"; \
+	  echo "$$d$$p"; \
+	done | $(am__base_list) | \
+	while read files; do \
+	  echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(include_racoondir)'"; \
+	  $(INSTALL_HEADER) $$files "$(DESTDIR)$(include_racoondir)" || exit $$?; \
 	done
 
 uninstall-include_racoonHEADERS:
 	@$(NORMAL_UNINSTALL)
-	@list='$(include_racoon_HEADERS)'; for p in $$list; do \
-	  f=$(am__strip_dir) \
-	  echo " rm -f '$(DESTDIR)$(include_racoondir)/$$f'"; \
-	  rm -f "$(DESTDIR)$(include_racoondir)/$$f"; \
-	done
+	@list='$(include_racoon_HEADERS)'; test -n "$(include_racoondir)" || list=; \
+	files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+	test -n "$$files" || exit 0; \
+	echo " ( cd '$(DESTDIR)$(include_racoondir)' && rm -f" $$files ")"; \
+	cd "$(DESTDIR)$(include_racoondir)" && rm -f $$files
 
 ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
 	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
 	unique=`for i in $$list; do \
 	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
 	  done | \
-	  $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
 	      END { if (nonempty) { for (i in files) print i; }; }'`; \
 	mkid -fID $$unique
 tags: TAGS
 
 TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
 		$(TAGS_FILES) $(LISP)
-	tags=; \
+	set x; \
 	here=`pwd`; \
 	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
 	unique=`for i in $$list; do \
@@ -720,37 +779,43 @@
 	  done | \
 	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
 	      END { if (nonempty) { for (i in files) print i; }; }'`; \
-	if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
 	  test -n "$$unique" || unique=$$empty_fix; \
-	  $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
-	    $$tags $$unique; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
 	fi
 ctags: CTAGS
 CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
 		$(TAGS_FILES) $(LISP)
-	tags=; \
 	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
 	unique=`for i in $$list; do \
 	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
 	  done | \
 	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
 	      END { if (nonempty) { for (i in files) print i; }; }'`; \
-	test -z "$(CTAGS_ARGS)$$tags$$unique" \
+	test -z "$(CTAGS_ARGS)$$unique" \
 	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
-	     $$tags $$unique
+	     $$unique
 
 GTAGS:
 	here=`$(am__cd) $(top_builddir) && pwd` \
-	  && cd $(top_srcdir) \
-	  && gtags -i $(GTAGS_ARGS) $$here
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
 
 distclean-tags:
 	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
 
 check-TESTS: $(TESTS)
-	@failed=0; all=0; xfail=0; xpass=0; skip=0; ws='[	 ]'; \
+	@failed=0; all=0; xfail=0; xpass=0; skip=0; \
 	srcdir=$(srcdir); export srcdir; \
 	list=' $(TESTS) '; \
+	$(am__tty_colors); \
 	if test -n "$$list"; then \
 	  for tst in $$list; do \
 	    if test -f ./$$tst; then dir=./; \
@@ -759,49 +824,63 @@
 	    if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \
 	      all=`expr $$all + 1`; \
 	      case " $(XFAIL_TESTS) " in \
-	      *$$ws$$tst$$ws*) \
+	      *[\ \	]$$tst[\ \	]*) \
 		xpass=`expr $$xpass + 1`; \
 		failed=`expr $$failed + 1`; \
-		echo "XPASS: $$tst"; \
+		col=$$red; res=XPASS; \
 	      ;; \
 	      *) \
-		echo "PASS: $$tst"; \
+		col=$$grn; res=PASS; \
 	      ;; \
 	      esac; \
 	    elif test $$? -ne 77; then \
 	      all=`expr $$all + 1`; \
 	      case " $(XFAIL_TESTS) " in \
-	      *$$ws$$tst$$ws*) \
+	      *[\ \	]$$tst[\ \	]*) \
 		xfail=`expr $$xfail + 1`; \
-		echo "XFAIL: $$tst"; \
+		col=$$lgn; res=XFAIL; \
 	      ;; \
 	      *) \
 		failed=`expr $$failed + 1`; \
-		echo "FAIL: $$tst"; \
+		col=$$red; res=FAIL; \
 	      ;; \
 	      esac; \
 	    else \
 	      skip=`expr $$skip + 1`; \
-	      echo "SKIP: $$tst"; \
+	      col=$$blu; res=SKIP; \
 	    fi; \
+	    echo "$${col}$$res$${std}: $$tst"; \
 	  done; \
+	  if test "$$all" -eq 1; then \
+	    tests="test"; \
+	    All=""; \
+	  else \
+	    tests="tests"; \
+	    All="All "; \
+	  fi; \
 	  if test "$$failed" -eq 0; then \
 	    if test "$$xfail" -eq 0; then \
-	      banner="All $$all tests passed"; \
+	      banner="$$All$$all $$tests passed"; \
 	    else \
-	      banner="All $$all tests behaved as expected ($$xfail expected failures)"; \
+	      if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \
+	      banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \
 	    fi; \
 	  else \
 	    if test "$$xpass" -eq 0; then \
-	      banner="$$failed of $$all tests failed"; \
+	      banner="$$failed of $$all $$tests failed"; \
 	    else \
-	      banner="$$failed of $$all tests did not behave as expected ($$xpass unexpected passes)"; \
+	      if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \
+	      banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \
 	    fi; \
 	  fi; \
 	  dashes="$$banner"; \
 	  skipped=""; \
 	  if test "$$skip" -ne 0; then \
-	    skipped="($$skip tests were not run)"; \
+	    if test "$$skip" -eq 1; then \
+	      skipped="($$skip test was not run)"; \
+	    else \
+	      skipped="($$skip tests were not run)"; \
+	    fi; \
 	    test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \
 	      dashes="$$skipped"; \
 	  fi; \
@@ -812,15 +891,32 @@
 	      dashes="$$report"; \
 	  fi; \
 	  dashes=`echo "$$dashes" | sed s/./=/g`; \
-	  echo "$$dashes"; \
+	  if test "$$failed" -eq 0; then \
+	    echo "$$grn$$dashes"; \
+	  else \
+	    echo "$$red$$dashes"; \
+	  fi; \
 	  echo "$$banner"; \
 	  test -z "$$skipped" || echo "$$skipped"; \
 	  test -z "$$report" || echo "$$report"; \
-	  echo "$$dashes"; \
+	  echo "$$dashes$$std"; \
 	  test "$$failed" -eq 0; \
 	else :; fi
 
 distdir: $(DISTFILES)
+	@list='$(MANS)'; if test -n "$$list"; then \
+	  list=`for p in $$list; do \
+	    if test -f $$p; then d=; else d="$(srcdir)/"; fi; \
+	    if test -f "$$d$$p"; then echo "$$d$$p"; else :; fi; done`; \
+	  if test -n "$$list" && \
+	    grep 'ab help2man is required to generate this page' $$list >/dev/null; then \
+	    echo "error: found man pages containing the \`missing help2man' replacement text:" >&2; \
+	    grep -l 'ab help2man is required to generate this page' $$list | sed 's/^/         /' >&2; \
+	    echo "       to fix them, install help2man, remove and regenerate the man pages;" >&2; \
+	    echo "       typically \`make maintainer-clean' will remove them" >&2; \
+	    exit 1; \
+	  else :; fi; \
+	else :; fi
 	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
 	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
 	list='$(DISTFILES)'; \
@@ -836,13 +932,17 @@
 	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
 	  if test -d $$d/$$file; then \
 	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
-	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
-	      cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
 	    fi; \
-	    cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
 	  else \
-	    test -f $(distdir)/$$file \
-	    || cp -p $$d/$$file $(distdir)/$$file \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
 	    || exit 1; \
 	  fi; \
 	done
@@ -876,6 +976,7 @@
 
 distclean-generic:
 	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
 
 maintainer-clean-generic:
 	@echo "This command is intended for maintainers to use"
@@ -904,6 +1005,8 @@
 
 html: html-am
 
+html-am:
+
 info: info-am
 
 info-am:
@@ -912,19 +1015,29 @@
 
 install-dvi: install-dvi-am
 
+install-dvi-am:
+
 install-exec-am: install-exec-local install-libLTLIBRARIES \
 	install-sbinPROGRAMS
 
 install-html: install-html-am
 
+install-html-am:
+
 install-info: install-info-am
 
+install-info-am:
+
 install-man: install-man5 install-man8
 
 install-pdf: install-pdf-am
 
+install-pdf-am:
+
 install-ps: install-ps-am
 
+install-ps-am:
+
 installcheck-am:
 
 maintainer-clean: maintainer-clean-am
@@ -950,7 +1063,7 @@
 
 uninstall-man: uninstall-man5 uninstall-man8
 
-.MAKE: install-am install-strip
+.MAKE: all check check-am install install-am install-strip
 
 .PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \
 	clean-generic clean-libLTLIBRARIES clean-libtool \
@@ -995,6 +1108,7 @@
 	$(COMPILE) -c $(srcdir)/missing/crypto/rijndael/$*.c
 sha2.o: $(srcdir)/missing/crypto/sha2/sha2.c
 	$(COMPILE) -c $(srcdir)/missing/crypto/sha2/$*.c
+
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
 .NOEXPORT:
diff --git a/src/racoon/admin.c b/src/racoon/admin.c
index b56dd2c..b0aad88 100644
--- a/src/racoon/admin.c
+++ b/src/racoon/admin.c
@@ -1,11 +1,11 @@
-/*	$NetBSD: admin.c,v 1.17.6.3 2009/04/20 13:32:57 tteras Exp $	*/
+/*	$NetBSD: admin.c,v 1.38 2010/12/08 07:38:35 tteras Exp $	*/
 
 /* Id: admin.c,v 1.25 2006/04/06 14:31:04 manubsd Exp */
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
  * All rights reserved.
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
@@ -17,7 +17,7 @@
  * 3. Neither the name of the project nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
- * 
+ *
  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@@ -76,6 +76,7 @@
 #include "evt.h"
 #include "pfkey.h"
 #include "ipsec_doi.h"
+#include "policy.h"
 #include "admin.h"
 #include "admin_var.h"
 #include "isakmp_inf.h"
@@ -93,10 +94,12 @@
 
 static struct sockaddr_un sunaddr;
 static int admin_process __P((int, char *));
-static int admin_reply __P((int, struct admin_com *, vchar_t *));
+static int admin_reply __P((int, struct admin_com *, int, vchar_t *));
 
-int
-admin_handler()
+static int
+admin_handler(ctx, fd)
+	void *ctx;
+	int fd;
 {
 	int so2;
 	struct sockaddr_storage from;
@@ -112,6 +115,7 @@
 			strerror(errno));
 		return -1;
 	}
+	close_on_exec(so2);
 
 	/* get buffer length */
 	while ((len = recv(so2, (char *)&com, sizeof(com), MSG_PEEK)) < 0) {
@@ -147,22 +151,30 @@
 		goto end;
 	}
 
-	if (com.ac_cmd == ADMIN_RELOAD_CONF) {
-		/* reload does not work at all! */
-		signal_handler(SIGHUP);
-		goto end;
-	}
-
 	error = admin_process(so2, combuf);
 
-    end:
-	(void)close(so2);
+end:
+	if (error == -2) {
+		plog(LLV_DEBUG, LOCATION, NULL,
+			"[%d] admin connection established\n", so2);
+	} else {
+		(void)close(so2);
+	}
+
 	if (combuf)
 		racoon_free(combuf);
 
 	return error;
 }
 
+static int admin_ph1_delete_sa(struct ph1handle *iph1, void *arg)
+{
+	if (iph1->status >= PHASE1ST_ESTABLISHED)
+		isakmp_info_send_d1(iph1);
+	purge_remote(iph1);
+	return 0;
+}
+
 /*
  * main child's process.
  */
@@ -176,131 +188,140 @@
 	vchar_t *id = NULL;
 	vchar_t *key = NULL;
 	int idtype = 0;
-	int error = -1;
+	int error = 0, l_ac_errno = 0;
+	struct evt_listener_list *event_list = NULL;
 
-	com->ac_errno = 0;
+	if (com->ac_cmd & ADMIN_FLAG_VERSION)
+		com->ac_cmd &= ~ADMIN_FLAG_VERSION;
+	else
+		com->ac_version = 0;
 
 	switch (com->ac_cmd) {
 	case ADMIN_RELOAD_CONF:
-		/* don't entered because of proccessing it in other place. */
-		plog(LLV_ERROR, LOCATION, NULL, "should never reach here\n");
-		goto out;
+		signal_handler(SIGHUP);
+		break;
 
-	case ADMIN_SHOW_SCHED:
-	{
+	case ADMIN_SHOW_SCHED: {
 		caddr_t p = NULL;
 		int len;
 
-		com->ac_errno = -1;
-
-		if (sched_dump(&p, &len) == -1)
-			goto out2;
-
-		if ((buf = vmalloc(len)) == NULL)
-			goto out2;
-
-		memcpy(buf->v, p, len);
-
-		com->ac_errno = 0;
-out2:
-		racoon_free(p);
+		if (sched_dump(&p, &len) != -1) {
+			buf = vmalloc(len);
+			if (buf != NULL)
+				memcpy(buf->v, p, len);
+			else
+				l_ac_errno = ENOMEM;
+			racoon_free(p);
+		} else
+			l_ac_errno = ENOMEM;
 		break;
 	}
 
 	case ADMIN_SHOW_EVT:
-		/* It's not really an error, don't force racoonctl to quit */
-		if ((buf = evt_dump()) == NULL)
-			com->ac_errno = 0; 
+		if (com->ac_version == 0) {
+			buf = evt_dump();
+			l_ac_errno = 0;
+		}
 		break;
 
 	case ADMIN_SHOW_SA:
-	case ADMIN_FLUSH_SA:
-	    {
 		switch (com->ac_proto) {
 		case ADMIN_PROTO_ISAKMP:
-			switch (com->ac_cmd) {
-			case ADMIN_SHOW_SA:
-				buf = dumpph1();
+			buf = dumpph1();
+			if (buf == NULL)
+				l_ac_errno = ENOMEM;
+			break;
+		case ADMIN_PROTO_IPSEC:
+		case ADMIN_PROTO_AH:
+		case ADMIN_PROTO_ESP: {
+			u_int p;
+			p = admin2pfkey_proto(com->ac_proto);
+			if (p != -1) {
+				buf = pfkey_dump_sadb(p);
 				if (buf == NULL)
-					com->ac_errno = -1;
-				break;
-			case ADMIN_FLUSH_SA:
-				flushph1();
-				break;
-			}
+					l_ac_errno = ENOMEM;
+			} else
+				l_ac_errno = EINVAL;
+			break;
+		}
+		case ADMIN_PROTO_INTERNAL:
+		default:
+			l_ac_errno = ENOTSUP;
+			break;
+		}
+		break;
+
+	case ADMIN_GET_SA_CERT: {
+		struct admin_com_indexes *ndx;
+		struct sockaddr *src, *dst;
+		struct ph1handle *iph1;
+
+		ndx = (struct admin_com_indexes *) ((caddr_t)com + sizeof(*com));
+		src = (struct sockaddr *) &ndx->src;
+		dst = (struct sockaddr *) &ndx->dst;
+
+		if (com->ac_proto != ADMIN_PROTO_ISAKMP) {
+			l_ac_errno = ENOTSUP;
+			break;
+		}
+
+		iph1 = getph1byaddr(src, dst, 0);
+		if (iph1 == NULL) {
+			l_ac_errno = ENOENT;
+			break;
+		}
+
+		if (iph1->cert_p != NULL) {
+			vchar_t tmp;
+			tmp.v = iph1->cert_p->v + 1;
+			tmp.l = iph1->cert_p->l - 1;
+			buf = vdup(&tmp);
+		}
+		break;
+	}
+
+	case ADMIN_FLUSH_SA:
+		switch (com->ac_proto) {
+		case ADMIN_PROTO_ISAKMP:
+			flushph1();
 			break;
 		case ADMIN_PROTO_IPSEC:
 		case ADMIN_PROTO_AH:
 		case ADMIN_PROTO_ESP:
-			switch (com->ac_cmd) {
-			case ADMIN_SHOW_SA:
-			    {
-				u_int p;
-				p = admin2pfkey_proto(com->ac_proto);
-				if (p == -1)
-					goto out;
-				buf = pfkey_dump_sadb(p);
-				if (buf == NULL)
-					com->ac_errno = -1;
-			    }
-				break;
-			case ADMIN_FLUSH_SA:
-				pfkey_flush_sadb(com->ac_proto);
-				break;
-			}
+			pfkey_flush_sadb(com->ac_proto);
 			break;
-
 		case ADMIN_PROTO_INTERNAL:
-			switch (com->ac_cmd) {
-			case ADMIN_SHOW_SA:
-				buf = NULL; /*XXX dumpph2(&error);*/
-				if (buf == NULL)
-					com->ac_errno = error;
-				break;
-			case ADMIN_FLUSH_SA:
-				/*XXX flushph2();*/
-				com->ac_errno = 0;
-				break;
-			}
-			break;
-
+			/*XXX flushph2();*/
 		default:
-			/* ignore */
-			com->ac_errno = -1;
+			l_ac_errno = ENOTSUP;
+			break;
 		}
-	    }
 		break;
 
 	case ADMIN_DELETE_SA: {
-		struct ph1handle *iph1;
-		struct sockaddr *dst;
-		struct sockaddr *src;
 		char *loc, *rem;
+		struct ph1selector sel;
 
-		src = (struct sockaddr *)
+		memset(&sel, 0, sizeof(sel));
+		sel.local = (struct sockaddr *)
 			&((struct admin_com_indexes *)
 			    ((caddr_t)com + sizeof(*com)))->src;
-		dst = (struct sockaddr *)
+		sel.remote = (struct sockaddr *)
 			&((struct admin_com_indexes *)
 			    ((caddr_t)com + sizeof(*com)))->dst;
 
-		loc = racoon_strdup(saddrwop2str(src));
-		rem = racoon_strdup(saddrwop2str(dst));
+		loc = racoon_strdup(saddr2str(sel.local));
+		rem = racoon_strdup(saddr2str(sel.remote));
 		STRDUP_FATAL(loc);
 		STRDUP_FATAL(rem);
 
-		if ((iph1 = getph1byaddrwop(src, dst)) == NULL) {
-			plog(LLV_ERROR, LOCATION, NULL, 
-			    "phase 1 for %s -> %s not found\n", loc, rem);
-		} else {
-			if (iph1->status == PHASE1ST_ESTABLISHED)
-				isakmp_info_send_d1(iph1);
-			purge_remote(iph1);
-		}
+		plog(LLV_INFO, LOCATION, NULL,
+		     "admin delete-sa %s %s\n", loc, rem);
+		enumph1(&sel, admin_ph1_delete_sa, NULL);
+		remcontacted(sel.remote);
 
 		racoon_free(loc);
 		racoon_free(rem);
-
 		break;
 	}
 
@@ -308,7 +329,7 @@
 	case ADMIN_LOGOUT_USER: {
 		struct ph1handle *iph1;
 		char user[LOGINLEN+1];
-		int found = 0, len = com->ac_len - sizeof(com);
+		int found = 0, len = com->ac_len - sizeof(*com);
 
 		if (len > LOGINLEN) {
 			plog(LLV_ERROR, LOCATION, NULL,
@@ -320,7 +341,7 @@
 		user[len] = 0;
 
 		found = purgeph1bylogin(user);
-		plog(LLV_INFO, LOCATION, NULL, 
+		plog(LLV_INFO, LOCATION, NULL,
 		    "deleted %d SA for user \"%s\"\n", found, user);
 
 		break;
@@ -339,22 +360,21 @@
 		rem = racoon_strdup(saddrwop2str(dst));
 		STRDUP_FATAL(rem);
 
-		plog(LLV_INFO, LOCATION, NULL, 
+		plog(LLV_INFO, LOCATION, NULL,
 		    "Flushing all SAs for peer %s\n", rem);
 
-		while ((iph1 = getph1bydstaddrwop(dst)) != NULL) {
+		while ((iph1 = getph1bydstaddr(dst)) != NULL) {
 			loc = racoon_strdup(saddrwop2str(iph1->local));
 			STRDUP_FATAL(loc);
 
-			if (iph1->status == PHASE1ST_ESTABLISHED)
+			if (iph1->status >= PHASE1ST_ESTABLISHED)
 				isakmp_info_send_d1(iph1);
 			purge_remote(iph1);
 
 			racoon_free(loc);
 		}
-		
-		racoon_free(rem);
 
+		racoon_free(rem);
 		break;
 	}
 
@@ -362,17 +382,15 @@
 		struct admin_com_psk *acp;
 		char *data;
 
-		com->ac_cmd = ADMIN_ESTABLISH_SA;
-
 		acp = (struct admin_com_psk *)
-		    ((char *)com + sizeof(*com) + 
+		    ((char *)com + sizeof(*com) +
 		    sizeof(struct admin_com_indexes));
 
 		idtype = acp->id_type;
 
 		if ((id = vmalloc(acp->id_len)) == NULL) {
 			plog(LLV_ERROR, LOCATION, NULL,
-			    "cannot allocate memory: %s\n", 
+			    "cannot allocate memory: %s\n",
 			    strerror(errno));
 			break;
 		}
@@ -381,7 +399,7 @@
 
 		if ((key = vmalloc(acp->key_len)) == NULL) {
 			plog(LLV_ERROR, LOCATION, NULL,
-			    "cannot allocate memory: %s\n", 
+			    "cannot allocate memory: %s\n",
 			    strerror(errno));
 			vfree(id);
 			id = NULL;
@@ -391,56 +409,57 @@
 		memcpy(key->v, data, key->l);
 	}
 	/* FALLTHROUGH */
-	case ADMIN_ESTABLISH_SA:
-	    {
+	case ADMIN_ESTABLISH_SA: {
+		struct admin_com_indexes *ndx;
 		struct sockaddr *dst;
 		struct sockaddr *src;
-		src = (struct sockaddr *)
-			&((struct admin_com_indexes *)
-			    ((caddr_t)com + sizeof(*com)))->src;
-		dst = (struct sockaddr *)
-			&((struct admin_com_indexes *)
-			    ((caddr_t)com + sizeof(*com)))->dst;
+		char *name = NULL;
+
+		ndx = (struct admin_com_indexes *) ((caddr_t)com + sizeof(*com));
+		src = (struct sockaddr *) &ndx->src;
+		dst = (struct sockaddr *) &ndx->dst;
+
+		if (com->ac_cmd == ADMIN_ESTABLISH_SA &&
+		    com->ac_len > sizeof(*com) + sizeof(*ndx))
+			name = (char *) ((caddr_t) ndx + sizeof(*ndx));
 
 		switch (com->ac_proto) {
 		case ADMIN_PROTO_ISAKMP: {
+			struct ph1handle *ph1;
 			struct remoteconf *rmconf;
-			struct sockaddr *remote = NULL;
-			struct sockaddr *local = NULL;
 			u_int16_t port;
 
-			com->ac_errno = -1;
+			l_ac_errno = -1;
+
+			/* connected already? */
+			ph1 = getph1byaddr(src, dst, 0);
+			if (ph1 != NULL) {
+				event_list = &ph1->evt_listeners;
+				if (ph1->status == PHASE1ST_ESTABLISHED)
+					l_ac_errno = EEXIST;
+				else
+					l_ac_errno = 0;
+				break;
+			}
 
 			/* search appropreate configuration */
-			rmconf = getrmconf(dst);
+			if (name == NULL)
+				rmconf = getrmconf(dst, 0);
+			else
+				rmconf = getrmconf_by_name(name);
 			if (rmconf == NULL) {
 				plog(LLV_ERROR, LOCATION, NULL,
 					"no configuration found "
 					"for %s\n", saddrwop2str(dst));
-				goto out1;
+				break;
 			}
 
-			/* get remote IP address and port number. */
-			if ((remote = dupsaddr(dst)) == NULL)
-				goto out1;
-
-			port = extract_port(rmconf->remote);
-			if (set_port(remote, port) == NULL)
-				goto out1;
-
-			/* get local address */
-			if ((local = dupsaddr(src)) == NULL)
-				goto out1;
-
-			port = getmyaddrsport(local);
-			if (set_port(local, port) == NULL)
-				goto out1;
-
 #ifdef ENABLE_HYBRID
+			/* XXX This overwrites rmconf information globally. */
 			/* Set the id and key */
 			if (id && key) {
 				if (xauth_rmconf_used(&rmconf->xauth) == -1)
-					goto out1;
+					break;
 
 				if (rmconf->xauth->login != NULL) {
 					vfree(rmconf->xauth->login);
@@ -455,43 +474,145 @@
 				rmconf->xauth->pass = key;
 			}
 #endif
- 
+
 			plog(LLV_INFO, LOCATION, NULL,
 				"accept a request to establish IKE-SA: "
-				"%s\n", saddrwop2str(remote));
+				"%s\n", saddrwop2str(dst));
 
 			/* begin ident mode */
-			if (isakmp_ph1begin_i(rmconf, remote, local) < 0)
-				goto out1;
+			ph1 = isakmp_ph1begin_i(rmconf, dst, src);
+			if (ph1 == NULL)
+				break;
 
-			com->ac_errno = 0;
-out1:
-			if (local != NULL)
-				racoon_free(local);
-			if (remote != NULL)
-				racoon_free(remote);
+			event_list = &ph1->evt_listeners;
+			l_ac_errno = 0;
 			break;
 		}
 		case ADMIN_PROTO_AH:
-		case ADMIN_PROTO_ESP:
+		case ADMIN_PROTO_ESP: {
+			struct ph2handle *iph2;
+			struct secpolicy *sp_out = NULL, *sp_in = NULL;
+			struct policyindex spidx;
+
+			l_ac_errno = -1;
+
+			/* got outbound policy */
+			memset(&spidx, 0, sizeof(spidx));
+			spidx.dir = IPSEC_DIR_OUTBOUND;
+			memcpy(&spidx.src, src, sizeof(spidx.src));
+			memcpy(&spidx.dst, dst, sizeof(spidx.dst));
+			spidx.prefs = ndx->prefs;
+			spidx.prefd = ndx->prefd;
+			spidx.ul_proto = ndx->ul_proto;
+
+			sp_out = getsp_r(&spidx);
+			if (sp_out) {
+				plog(LLV_DEBUG, LOCATION, NULL,
+					"suitable outbound SP found: %s.\n",
+					spidx2str(&sp_out->spidx));
+			} else {
+				l_ac_errno = ENOENT;
+				plog(LLV_NOTIFY, LOCATION, NULL,
+					"no outbound policy found: %s\n",
+					spidx2str(&spidx));
+				break;
+			}
+
+			iph2 = getph2byid(src, dst, sp_out->id);
+			if (iph2 != NULL) {
+				event_list = &iph2->evt_listeners;
+				if (iph2->status == PHASE2ST_ESTABLISHED)
+					l_ac_errno = EEXIST;
+				else
+					l_ac_errno = 0;
+				break;
+			}
+
+			/* get inbound policy */
+			memset(&spidx, 0, sizeof(spidx));
+			spidx.dir = IPSEC_DIR_INBOUND;
+			memcpy(&spidx.src, dst, sizeof(spidx.src));
+			memcpy(&spidx.dst, src, sizeof(spidx.dst));
+			spidx.prefs = ndx->prefd;
+			spidx.prefd = ndx->prefs;
+			spidx.ul_proto = ndx->ul_proto;
+
+			sp_in = getsp_r(&spidx);
+			if (sp_in) {
+				plog(LLV_DEBUG, LOCATION, NULL,
+					"suitable inbound SP found: %s.\n",
+					spidx2str(&sp_in->spidx));
+			} else {
+				l_ac_errno = ENOENT;
+				plog(LLV_NOTIFY, LOCATION, NULL,
+					"no inbound policy found: %s\n",
+				spidx2str(&spidx));
+				break;
+			}
+
+			/* allocate a phase 2 */
+			iph2 = newph2();
+			if (iph2 == NULL) {
+				plog(LLV_ERROR, LOCATION, NULL,
+					"failed to allocate phase2 entry.\n");
+				break;
+			}
+			iph2->side = INITIATOR;
+			iph2->satype = admin2pfkey_proto(com->ac_proto);
+			iph2->spid = sp_out->id;
+			iph2->seq = pk_getseq();
+			iph2->status = PHASE2ST_STATUS2;
+
+			/* set end addresses of SA */
+			iph2->sa_dst = dupsaddr(dst);
+			iph2->sa_src = dupsaddr(src);
+			iph2->dst = dupsaddr(dst);
+			iph2->src = dupsaddr(src);
+			if (iph2->sa_src == NULL || iph2->sa_dst == NULL ||
+			    iph2->dst == NULL || iph2->src == NULL) {
+				delph2(iph2);
+				break;
+			}
+			set_port(iph2->dst, 0);
+			set_port(iph2->src, 0);
+
+			if (isakmp_get_sainfo(iph2, sp_out, sp_in) < 0) {
+				delph2(iph2);
+				break;
+			}
+
+			insph2(iph2);
+			if (isakmp_post_acquire(iph2, NULL, FALSE) < 0) {
+				remph2(iph2);
+				delph2(iph2);
+				break;
+			}
+
+			event_list = &iph2->evt_listeners;
+			l_ac_errno = 0;
 			break;
+		}
 		default:
 			/* ignore */
-			com->ac_errno = -1;
+			l_ac_errno = ENOTSUP;
 		}
-	    }
 		break;
+	}
 
 	default:
 		plog(LLV_ERROR, LOCATION, NULL,
 			"invalid command: %d\n", com->ac_cmd);
-		com->ac_errno = -1;
+		l_ac_errno = ENOTSUP;
 	}
 
-	if ((error = admin_reply(so2, com, buf)) != 0)
+	if ((error = admin_reply(so2, com, l_ac_errno, buf)) != 0)
 		goto out;
 
-	error = 0;
+	/* start pushing events if so requested */
+	if ((l_ac_errno == 0) &&
+	    (com->ac_version >= 1) &&
+	    (com->ac_cmd == ADMIN_SHOW_EVT || event_list != NULL))
+		error = evt_subscribe(event_list, so2);
 out:
 	if (buf != NULL)
 		vfree(buf);
@@ -500,12 +621,13 @@
 }
 
 static int
-admin_reply(so, combuf, buf)
-	int so;
-	struct admin_com *combuf;
+admin_reply(so, req, l_ac_errno, buf)
+	int so, l_ac_errno;
+	struct admin_com *req;
 	vchar_t *buf;
 {
 	int tlen;
+	struct admin_com *combuf;
 	char *retbuf = NULL;
 
 	if (buf != NULL)
@@ -520,8 +642,17 @@
 		return -1;
 	}
 
-	memcpy(retbuf, combuf, sizeof(*combuf));
-	((struct admin_com *)retbuf)->ac_len = tlen;
+	combuf = (struct admin_com *) retbuf;
+	combuf->ac_len = (u_int16_t) tlen;
+	combuf->ac_cmd = req->ac_cmd & ~ADMIN_FLAG_VERSION;
+	if (tlen != (u_int32_t) combuf->ac_len &&
+	    l_ac_errno == 0) {
+		combuf->ac_len_high = tlen >> 16;
+		combuf->ac_cmd |= ADMIN_FLAG_LONG_REPLY;
+	} else {
+		combuf->ac_errno = l_ac_errno;
+	}
+	combuf->ac_proto = req->ac_proto;
 
 	if (buf != NULL)
 		memcpy(retbuf + sizeof(*combuf), buf->v, buf->l);
@@ -577,6 +708,7 @@
 			"socket: %s\n", strerror(errno));
 		return -1;
 	}
+	close_on_exec(lcconf->sock_admin);
 
 	unlink(sunaddr.sun_path);
 	if (bind(lcconf->sock_admin, (struct sockaddr *)&sunaddr,
@@ -589,17 +721,17 @@
 	}
 
 	if (chown(sunaddr.sun_path, adminsock_owner, adminsock_group) != 0) {
-		plog(LLV_ERROR, LOCATION, NULL, 
-		    "chown(%s, %d, %d): %s\n", 
-		    sunaddr.sun_path, adminsock_owner, 
+		plog(LLV_ERROR, LOCATION, NULL,
+		    "chown(%s, %d, %d): %s\n",
+		    sunaddr.sun_path, adminsock_owner,
 		    adminsock_group, strerror(errno));
 		(void)close(lcconf->sock_admin);
 		return -1;
 	}
 
 	if (chmod(sunaddr.sun_path, adminsock_mode) != 0) {
-		plog(LLV_ERROR, LOCATION, NULL, 
-		    "chmod(%s, 0%03o): %s\n", 
+		plog(LLV_ERROR, LOCATION, NULL,
+		    "chmod(%s, 0%03o): %s\n",
 		    sunaddr.sun_path, adminsock_mode, strerror(errno));
 		(void)close(lcconf->sock_admin);
 		return -1;
@@ -612,8 +744,10 @@
 		(void)close(lcconf->sock_admin);
 		return -1;
 	}
+
+	monitor_fd(lcconf->sock_admin, admin_handler, NULL, 0);
 	plog(LLV_DEBUG, LOCATION, NULL,
-		"open %s as racoon management.\n", sunaddr.sun_path);
+	     "open %s as racoon management.\n", sunaddr.sun_path);
 
 	return 0;
 }
@@ -621,8 +755,9 @@
 int
 admin_close()
 {
+	unmonitor_fd(lcconf->sock_admin);
 	close(lcconf->sock_admin);
 	return 0;
 }
-#endif
 
+#endif
diff --git a/src/racoon/admin.h b/src/racoon/admin.h
index cbc19e8..8cb9382 100644
--- a/src/racoon/admin.h
+++ b/src/racoon/admin.h
@@ -1,4 +1,4 @@
-/*	$NetBSD: admin.h,v 1.4 2006/09/09 16:22:09 manu Exp $	*/
+/*	$NetBSD: admin.h,v 1.8 2010/11/12 09:08:26 tteras Exp $	*/
 
 /* Id: admin.h,v 1.11 2005/06/19 22:37:47 manubsd Exp */
 
@@ -46,9 +46,22 @@
 struct admin_com {
 	u_int16_t ac_len;	/* total packet length including data */
 	u_int16_t ac_cmd;
-	int16_t ac_errno;
+	union {
+		int16_t ac_un_errno;
+		uint16_t ac_un_version;
+		uint16_t ac_un_len_high;
+	} u;
 	u_int16_t ac_proto;
 };
+#define ac_errno u.ac_un_errno
+#define ac_version u.ac_un_version
+#define ac_len_high u.ac_un_len_high
+
+/*
+ * Version field in request is valid.
+ */
+#define ADMIN_FLAG_VERSION	0x8000
+#define ADMIN_FLAG_LONG_REPLY	0x8000
 
 /*
  * No data follows as the data.
@@ -72,6 +85,8 @@
 #define ADMIN_ESTABLISH_SA	0x0202
 #define ADMIN_DELETE_ALL_SA_DST	0x0204	/* All SA for a given peer */
 
+#define ADMIN_GET_SA_CERT	0x0206
+
 /*
  * The admin_com_indexes and admin_com_psk follow, see below.
  */
diff --git a/src/racoon/admin_var.h b/src/racoon/admin_var.h
index 6d7ba81..f4471a3 100644
--- a/src/racoon/admin_var.h
+++ b/src/racoon/admin_var.h
@@ -1,4 +1,4 @@
-/*	$NetBSD: admin_var.h,v 1.4 2006/09/09 16:22:09 manu Exp $	*/
+/*	$NetBSD: admin_var.h,v 1.5 2008/12/23 14:03:12 tteras Exp $	*/
 
 /* Id: admin_var.h,v 1.7 2004/12/30 00:08:30 manubsd Exp */
 
@@ -34,7 +34,6 @@
 #ifndef _ADMIN_VAR_H
 #define _ADMIN_VAR_H
 
-extern int admin_handler __P((void));
 extern int admin_init __P((void));
 extern int admin_close __P((void));
 
diff --git a/src/racoon/backupsa.c b/src/racoon/backupsa.c
index 9496000..82d74ca 100644
--- a/src/racoon/backupsa.c
+++ b/src/racoon/backupsa.c
@@ -1,4 +1,4 @@
-/*	$NetBSD: backupsa.c,v 1.8.4.1 2007/08/01 11:52:19 vanhu Exp $	*/
+/*	$NetBSD: backupsa.c,v 1.10 2010/04/02 15:15:00 christos Exp $	*/
 
 /*	$KAME: backupsa.c,v 1.16 2001/12/31 20:13:40 thorpej Exp $	*/
 
@@ -452,7 +452,7 @@
 	struct tm tm;
 	time_t t;
 	char *buf = "Nov 24 18:22:48 1986 ";
-	char *p;
+	const char *p;
 
 	memset(&tm, 0, sizeof(tm));
 	p = str2tmx(buf, &tm);
@@ -460,7 +460,8 @@
 	t = mktime(&tm);
 	if (t == -1)
 		printf("mktime failed.");
-	p = ctime(&t);
+	if ((p = ctime(&t)) == NULL)
+		p = "?";
 	printf("[%s]\n", p);
 
 	exit(0);
diff --git a/src/racoon/cfparse.h b/src/racoon/cfparse.h
index 2946b3e..bbf678a 100644
--- a/src/racoon/cfparse.h
+++ b/src/racoon/cfparse.h
@@ -1,24 +1,23 @@
-/* A Bison parser, made by GNU Bison 2.3.  */
+
+/* A Bison parser, made by GNU Bison 2.4.1.  */
 
 /* Skeleton interface for Bison's Yacc-like parsers in C
-
-   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+   
+      Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
    Free Software Foundation, Inc.
-
-   This program is free software; you can redistribute it and/or modify
+   
+   This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
-   any later version.
-
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+   
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
-
+   
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301, USA.  */
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 /* As a special exception, you may create a larger work that contains
    part or all of the Bison parser skeleton and distribute that work
@@ -29,10 +28,11 @@
    special exception, which will cause the skeleton and the resulting
    Bison output files to be licensed under the GNU General Public
    License without this special exception.
-
+   
    This special exception was added by the Free Software Foundation in
    version 2.2 of Bison.  */
 
+
 /* Tokens.  */
 #ifndef YYTOKENTYPE
 # define YYTOKENTYPE
@@ -46,161 +46,170 @@
      PATH = 262,
      PATHTYPE = 263,
      INCLUDE = 264,
-     IDENTIFIER = 265,
-     VENDORID = 266,
-     LOGGING = 267,
-     LOGLEV = 268,
-     PADDING = 269,
-     PAD_RANDOMIZE = 270,
-     PAD_RANDOMIZELEN = 271,
-     PAD_MAXLEN = 272,
-     PAD_STRICT = 273,
-     PAD_EXCLTAIL = 274,
-     LISTEN = 275,
-     X_ISAKMP = 276,
-     X_ISAKMP_NATT = 277,
-     X_ADMIN = 278,
-     STRICT_ADDRESS = 279,
-     ADMINSOCK = 280,
-     DISABLED = 281,
-     LDAPCFG = 282,
-     LDAP_HOST = 283,
-     LDAP_PORT = 284,
-     LDAP_PVER = 285,
-     LDAP_BASE = 286,
-     LDAP_BIND_DN = 287,
-     LDAP_BIND_PW = 288,
-     LDAP_SUBTREE = 289,
-     LDAP_ATTR_USER = 290,
-     LDAP_ATTR_ADDR = 291,
-     LDAP_ATTR_MASK = 292,
-     LDAP_ATTR_GROUP = 293,
-     LDAP_ATTR_MEMBER = 294,
-     MODECFG = 295,
-     CFG_NET4 = 296,
-     CFG_MASK4 = 297,
-     CFG_DNS4 = 298,
-     CFG_NBNS4 = 299,
-     CFG_DEFAULT_DOMAIN = 300,
-     CFG_AUTH_SOURCE = 301,
-     CFG_AUTH_GROUPS = 302,
-     CFG_SYSTEM = 303,
-     CFG_RADIUS = 304,
-     CFG_PAM = 305,
-     CFG_LDAP = 306,
-     CFG_LOCAL = 307,
-     CFG_NONE = 308,
-     CFG_GROUP_SOURCE = 309,
-     CFG_ACCOUNTING = 310,
-     CFG_CONF_SOURCE = 311,
-     CFG_MOTD = 312,
-     CFG_POOL_SIZE = 313,
-     CFG_AUTH_THROTTLE = 314,
-     CFG_SPLIT_NETWORK = 315,
-     CFG_SPLIT_LOCAL = 316,
-     CFG_SPLIT_INCLUDE = 317,
-     CFG_SPLIT_DNS = 318,
-     CFG_PFS_GROUP = 319,
-     CFG_SAVE_PASSWD = 320,
-     RETRY = 321,
-     RETRY_COUNTER = 322,
-     RETRY_INTERVAL = 323,
-     RETRY_PERSEND = 324,
-     RETRY_PHASE1 = 325,
-     RETRY_PHASE2 = 326,
-     NATT_KA = 327,
-     ALGORITHM_CLASS = 328,
-     ALGORITHMTYPE = 329,
-     STRENGTHTYPE = 330,
-     SAINFO = 331,
-     FROM = 332,
-     REMOTE = 333,
-     ANONYMOUS = 334,
-     INHERIT = 335,
-     EXCHANGE_MODE = 336,
-     EXCHANGETYPE = 337,
-     DOI = 338,
-     DOITYPE = 339,
-     SITUATION = 340,
-     SITUATIONTYPE = 341,
-     CERTIFICATE_TYPE = 342,
-     CERTTYPE = 343,
-     PEERS_CERTFILE = 344,
-     CA_TYPE = 345,
-     VERIFY_CERT = 346,
-     SEND_CERT = 347,
-     SEND_CR = 348,
-     IDENTIFIERTYPE = 349,
-     IDENTIFIERQUAL = 350,
-     MY_IDENTIFIER = 351,
-     PEERS_IDENTIFIER = 352,
-     VERIFY_IDENTIFIER = 353,
-     DNSSEC = 354,
-     CERT_X509 = 355,
-     CERT_PLAINRSA = 356,
-     NONCE_SIZE = 357,
-     DH_GROUP = 358,
-     KEEPALIVE = 359,
-     PASSIVE = 360,
-     INITIAL_CONTACT = 361,
-     NAT_TRAVERSAL = 362,
-     REMOTE_FORCE_LEVEL = 363,
-     PROPOSAL_CHECK = 364,
-     PROPOSAL_CHECK_LEVEL = 365,
-     GENERATE_POLICY = 366,
-     GENERATE_LEVEL = 367,
-     SUPPORT_PROXY = 368,
-     PROPOSAL = 369,
-     EXEC_PATH = 370,
-     EXEC_COMMAND = 371,
-     EXEC_SUCCESS = 372,
-     EXEC_FAILURE = 373,
-     GSS_ID = 374,
-     GSS_ID_ENC = 375,
-     GSS_ID_ENCTYPE = 376,
-     COMPLEX_BUNDLE = 377,
-     DPD = 378,
-     DPD_DELAY = 379,
-     DPD_RETRY = 380,
-     DPD_MAXFAIL = 381,
-     PH1ID = 382,
-     XAUTH_LOGIN = 383,
-     WEAK_PHASE1_CHECK = 384,
-     PREFIX = 385,
-     PORT = 386,
-     PORTANY = 387,
-     UL_PROTO = 388,
-     ANY = 389,
-     IKE_FRAG = 390,
-     ESP_FRAG = 391,
-     MODE_CFG = 392,
-     PFS_GROUP = 393,
-     LIFETIME = 394,
-     LIFETYPE_TIME = 395,
-     LIFETYPE_BYTE = 396,
-     STRENGTH = 397,
-     REMOTEID = 398,
-     SCRIPT = 399,
-     PHASE1_UP = 400,
-     PHASE1_DOWN = 401,
-     NUMBER = 402,
-     SWITCH = 403,
-     BOOLEAN = 404,
-     HEXSTRING = 405,
-     QUOTEDSTRING = 406,
-     ADDRSTRING = 407,
-     ADDRRANGE = 408,
-     UNITTYPE_BYTE = 409,
-     UNITTYPE_KBYTES = 410,
-     UNITTYPE_MBYTES = 411,
-     UNITTYPE_TBYTES = 412,
-     UNITTYPE_SEC = 413,
-     UNITTYPE_MIN = 414,
-     UNITTYPE_HOUR = 415,
-     EOS = 416,
-     BOC = 417,
-     EOC = 418,
-     COMMA = 419
+     PFKEY_BUFFER = 265,
+     LOGGING = 266,
+     LOGLEV = 267,
+     PADDING = 268,
+     PAD_RANDOMIZE = 269,
+     PAD_RANDOMIZELEN = 270,
+     PAD_MAXLEN = 271,
+     PAD_STRICT = 272,
+     PAD_EXCLTAIL = 273,
+     LISTEN = 274,
+     X_ISAKMP = 275,
+     X_ISAKMP_NATT = 276,
+     X_ADMIN = 277,
+     STRICT_ADDRESS = 278,
+     ADMINSOCK = 279,
+     DISABLED = 280,
+     LDAPCFG = 281,
+     LDAP_HOST = 282,
+     LDAP_PORT = 283,
+     LDAP_PVER = 284,
+     LDAP_BASE = 285,
+     LDAP_BIND_DN = 286,
+     LDAP_BIND_PW = 287,
+     LDAP_SUBTREE = 288,
+     LDAP_ATTR_USER = 289,
+     LDAP_ATTR_ADDR = 290,
+     LDAP_ATTR_MASK = 291,
+     LDAP_ATTR_GROUP = 292,
+     LDAP_ATTR_MEMBER = 293,
+     RADCFG = 294,
+     RAD_AUTH = 295,
+     RAD_ACCT = 296,
+     RAD_TIMEOUT = 297,
+     RAD_RETRIES = 298,
+     MODECFG = 299,
+     CFG_NET4 = 300,
+     CFG_MASK4 = 301,
+     CFG_DNS4 = 302,
+     CFG_NBNS4 = 303,
+     CFG_DEFAULT_DOMAIN = 304,
+     CFG_AUTH_SOURCE = 305,
+     CFG_AUTH_GROUPS = 306,
+     CFG_SYSTEM = 307,
+     CFG_RADIUS = 308,
+     CFG_PAM = 309,
+     CFG_LDAP = 310,
+     CFG_LOCAL = 311,
+     CFG_NONE = 312,
+     CFG_GROUP_SOURCE = 313,
+     CFG_ACCOUNTING = 314,
+     CFG_CONF_SOURCE = 315,
+     CFG_MOTD = 316,
+     CFG_POOL_SIZE = 317,
+     CFG_AUTH_THROTTLE = 318,
+     CFG_SPLIT_NETWORK = 319,
+     CFG_SPLIT_LOCAL = 320,
+     CFG_SPLIT_INCLUDE = 321,
+     CFG_SPLIT_DNS = 322,
+     CFG_PFS_GROUP = 323,
+     CFG_SAVE_PASSWD = 324,
+     RETRY = 325,
+     RETRY_COUNTER = 326,
+     RETRY_INTERVAL = 327,
+     RETRY_PERSEND = 328,
+     RETRY_PHASE1 = 329,
+     RETRY_PHASE2 = 330,
+     NATT_KA = 331,
+     ALGORITHM_CLASS = 332,
+     ALGORITHMTYPE = 333,
+     STRENGTHTYPE = 334,
+     SAINFO = 335,
+     FROM = 336,
+     REMOTE = 337,
+     ANONYMOUS = 338,
+     CLIENTADDR = 339,
+     INHERIT = 340,
+     REMOTE_ADDRESS = 341,
+     EXCHANGE_MODE = 342,
+     EXCHANGETYPE = 343,
+     DOI = 344,
+     DOITYPE = 345,
+     SITUATION = 346,
+     SITUATIONTYPE = 347,
+     CERTIFICATE_TYPE = 348,
+     CERTTYPE = 349,
+     PEERS_CERTFILE = 350,
+     CA_TYPE = 351,
+     VERIFY_CERT = 352,
+     SEND_CERT = 353,
+     SEND_CR = 354,
+     MATCH_EMPTY_CR = 355,
+     IDENTIFIERTYPE = 356,
+     IDENTIFIERQUAL = 357,
+     MY_IDENTIFIER = 358,
+     PEERS_IDENTIFIER = 359,
+     VERIFY_IDENTIFIER = 360,
+     DNSSEC = 361,
+     CERT_X509 = 362,
+     CERT_PLAINRSA = 363,
+     NONCE_SIZE = 364,
+     DH_GROUP = 365,
+     KEEPALIVE = 366,
+     PASSIVE = 367,
+     INITIAL_CONTACT = 368,
+     NAT_TRAVERSAL = 369,
+     REMOTE_FORCE_LEVEL = 370,
+     PROPOSAL_CHECK = 371,
+     PROPOSAL_CHECK_LEVEL = 372,
+     GENERATE_POLICY = 373,
+     GENERATE_LEVEL = 374,
+     SUPPORT_PROXY = 375,
+     PROPOSAL = 376,
+     EXEC_PATH = 377,
+     EXEC_COMMAND = 378,
+     EXEC_SUCCESS = 379,
+     EXEC_FAILURE = 380,
+     GSS_ID = 381,
+     GSS_ID_ENC = 382,
+     GSS_ID_ENCTYPE = 383,
+     COMPLEX_BUNDLE = 384,
+     DPD = 385,
+     DPD_DELAY = 386,
+     DPD_RETRY = 387,
+     DPD_MAXFAIL = 388,
+     PH1ID = 389,
+     XAUTH_LOGIN = 390,
+     WEAK_PHASE1_CHECK = 391,
+     REKEY = 392,
+     PREFIX = 393,
+     PORT = 394,
+     PORTANY = 395,
+     UL_PROTO = 396,
+     ANY = 397,
+     IKE_FRAG = 398,
+     ESP_FRAG = 399,
+     MODE_CFG = 400,
+     PFS_GROUP = 401,
+     LIFETIME = 402,
+     LIFETYPE_TIME = 403,
+     LIFETYPE_BYTE = 404,
+     STRENGTH = 405,
+     REMOTEID = 406,
+     SCRIPT = 407,
+     PHASE1_UP = 408,
+     PHASE1_DOWN = 409,
+     PHASE1_DEAD = 410,
+     NUMBER = 411,
+     SWITCH = 412,
+     BOOLEAN = 413,
+     HEXSTRING = 414,
+     QUOTEDSTRING = 415,
+     ADDRSTRING = 416,
+     ADDRRANGE = 417,
+     UNITTYPE_BYTE = 418,
+     UNITTYPE_KBYTES = 419,
+     UNITTYPE_MBYTES = 420,
+     UNITTYPE_TBYTES = 421,
+     UNITTYPE_SEC = 422,
+     UNITTYPE_MIN = 423,
+     UNITTYPE_HOUR = 424,
+     EOS = 425,
+     BOC = 426,
+     EOC = 427,
+     COMMA = 428
    };
 #endif
 /* Tokens.  */
@@ -211,182 +220,197 @@
 #define PATH 262
 #define PATHTYPE 263
 #define INCLUDE 264
-#define IDENTIFIER 265
-#define VENDORID 266
-#define LOGGING 267
-#define LOGLEV 268
-#define PADDING 269
-#define PAD_RANDOMIZE 270
-#define PAD_RANDOMIZELEN 271
-#define PAD_MAXLEN 272
-#define PAD_STRICT 273
-#define PAD_EXCLTAIL 274
-#define LISTEN 275
-#define X_ISAKMP 276
-#define X_ISAKMP_NATT 277
-#define X_ADMIN 278
-#define STRICT_ADDRESS 279
-#define ADMINSOCK 280
-#define DISABLED 281
-#define LDAPCFG 282
-#define LDAP_HOST 283
-#define LDAP_PORT 284
-#define LDAP_PVER 285
-#define LDAP_BASE 286
-#define LDAP_BIND_DN 287
-#define LDAP_BIND_PW 288
-#define LDAP_SUBTREE 289
-#define LDAP_ATTR_USER 290
-#define LDAP_ATTR_ADDR 291
-#define LDAP_ATTR_MASK 292
-#define LDAP_ATTR_GROUP 293
-#define LDAP_ATTR_MEMBER 294
-#define MODECFG 295
-#define CFG_NET4 296
-#define CFG_MASK4 297
-#define CFG_DNS4 298
-#define CFG_NBNS4 299
-#define CFG_DEFAULT_DOMAIN 300
-#define CFG_AUTH_SOURCE 301
-#define CFG_AUTH_GROUPS 302
-#define CFG_SYSTEM 303
-#define CFG_RADIUS 304
-#define CFG_PAM 305
-#define CFG_LDAP 306
-#define CFG_LOCAL 307
-#define CFG_NONE 308
-#define CFG_GROUP_SOURCE 309
-#define CFG_ACCOUNTING 310
-#define CFG_CONF_SOURCE 311
-#define CFG_MOTD 312
-#define CFG_POOL_SIZE 313
-#define CFG_AUTH_THROTTLE 314
-#define CFG_SPLIT_NETWORK 315
-#define CFG_SPLIT_LOCAL 316
-#define CFG_SPLIT_INCLUDE 317
-#define CFG_SPLIT_DNS 318
-#define CFG_PFS_GROUP 319
-#define CFG_SAVE_PASSWD 320
-#define RETRY 321
-#define RETRY_COUNTER 322
-#define RETRY_INTERVAL 323
-#define RETRY_PERSEND 324
-#define RETRY_PHASE1 325
-#define RETRY_PHASE2 326
-#define NATT_KA 327
-#define ALGORITHM_CLASS 328
-#define ALGORITHMTYPE 329
-#define STRENGTHTYPE 330
-#define SAINFO 331
-#define FROM 332
-#define REMOTE 333
-#define ANONYMOUS 334
-#define INHERIT 335
-#define EXCHANGE_MODE 336
-#define EXCHANGETYPE 337
-#define DOI 338
-#define DOITYPE 339
-#define SITUATION 340
-#define SITUATIONTYPE 341
-#define CERTIFICATE_TYPE 342
-#define CERTTYPE 343
-#define PEERS_CERTFILE 344
-#define CA_TYPE 345
-#define VERIFY_CERT 346
-#define SEND_CERT 347
-#define SEND_CR 348
-#define IDENTIFIERTYPE 349
-#define IDENTIFIERQUAL 350
-#define MY_IDENTIFIER 351
-#define PEERS_IDENTIFIER 352
-#define VERIFY_IDENTIFIER 353
-#define DNSSEC 354
-#define CERT_X509 355
-#define CERT_PLAINRSA 356
-#define NONCE_SIZE 357
-#define DH_GROUP 358
-#define KEEPALIVE 359
-#define PASSIVE 360
-#define INITIAL_CONTACT 361
-#define NAT_TRAVERSAL 362
-#define REMOTE_FORCE_LEVEL 363
-#define PROPOSAL_CHECK 364
-#define PROPOSAL_CHECK_LEVEL 365
-#define GENERATE_POLICY 366
-#define GENERATE_LEVEL 367
-#define SUPPORT_PROXY 368
-#define PROPOSAL 369
-#define EXEC_PATH 370
-#define EXEC_COMMAND 371
-#define EXEC_SUCCESS 372
-#define EXEC_FAILURE 373
-#define GSS_ID 374
-#define GSS_ID_ENC 375
-#define GSS_ID_ENCTYPE 376
-#define COMPLEX_BUNDLE 377
-#define DPD 378
-#define DPD_DELAY 379
-#define DPD_RETRY 380
-#define DPD_MAXFAIL 381
-#define PH1ID 382
-#define XAUTH_LOGIN 383
-#define WEAK_PHASE1_CHECK 384
-#define PREFIX 385
-#define PORT 386
-#define PORTANY 387
-#define UL_PROTO 388
-#define ANY 389
-#define IKE_FRAG 390
-#define ESP_FRAG 391
-#define MODE_CFG 392
-#define PFS_GROUP 393
-#define LIFETIME 394
-#define LIFETYPE_TIME 395
-#define LIFETYPE_BYTE 396
-#define STRENGTH 397
-#define REMOTEID 398
-#define SCRIPT 399
-#define PHASE1_UP 400
-#define PHASE1_DOWN 401
-#define NUMBER 402
-#define SWITCH 403
-#define BOOLEAN 404
-#define HEXSTRING 405
-#define QUOTEDSTRING 406
-#define ADDRSTRING 407
-#define ADDRRANGE 408
-#define UNITTYPE_BYTE 409
-#define UNITTYPE_KBYTES 410
-#define UNITTYPE_MBYTES 411
-#define UNITTYPE_TBYTES 412
-#define UNITTYPE_SEC 413
-#define UNITTYPE_MIN 414
-#define UNITTYPE_HOUR 415
-#define EOS 416
-#define BOC 417
-#define EOC 418
-#define COMMA 419
+#define PFKEY_BUFFER 265
+#define LOGGING 266
+#define LOGLEV 267
+#define PADDING 268
+#define PAD_RANDOMIZE 269
+#define PAD_RANDOMIZELEN 270
+#define PAD_MAXLEN 271
+#define PAD_STRICT 272
+#define PAD_EXCLTAIL 273
+#define LISTEN 274
+#define X_ISAKMP 275
+#define X_ISAKMP_NATT 276
+#define X_ADMIN 277
+#define STRICT_ADDRESS 278
+#define ADMINSOCK 279
+#define DISABLED 280
+#define LDAPCFG 281
+#define LDAP_HOST 282
+#define LDAP_PORT 283
+#define LDAP_PVER 284
+#define LDAP_BASE 285
+#define LDAP_BIND_DN 286
+#define LDAP_BIND_PW 287
+#define LDAP_SUBTREE 288
+#define LDAP_ATTR_USER 289
+#define LDAP_ATTR_ADDR 290
+#define LDAP_ATTR_MASK 291
+#define LDAP_ATTR_GROUP 292
+#define LDAP_ATTR_MEMBER 293
+#define RADCFG 294
+#define RAD_AUTH 295
+#define RAD_ACCT 296
+#define RAD_TIMEOUT 297
+#define RAD_RETRIES 298
+#define MODECFG 299
+#define CFG_NET4 300
+#define CFG_MASK4 301
+#define CFG_DNS4 302
+#define CFG_NBNS4 303
+#define CFG_DEFAULT_DOMAIN 304
+#define CFG_AUTH_SOURCE 305
+#define CFG_AUTH_GROUPS 306
+#define CFG_SYSTEM 307
+#define CFG_RADIUS 308
+#define CFG_PAM 309
+#define CFG_LDAP 310
+#define CFG_LOCAL 311
+#define CFG_NONE 312
+#define CFG_GROUP_SOURCE 313
+#define CFG_ACCOUNTING 314
+#define CFG_CONF_SOURCE 315
+#define CFG_MOTD 316
+#define CFG_POOL_SIZE 317
+#define CFG_AUTH_THROTTLE 318
+#define CFG_SPLIT_NETWORK 319
+#define CFG_SPLIT_LOCAL 320
+#define CFG_SPLIT_INCLUDE 321
+#define CFG_SPLIT_DNS 322
+#define CFG_PFS_GROUP 323
+#define CFG_SAVE_PASSWD 324
+#define RETRY 325
+#define RETRY_COUNTER 326
+#define RETRY_INTERVAL 327
+#define RETRY_PERSEND 328
+#define RETRY_PHASE1 329
+#define RETRY_PHASE2 330
+#define NATT_KA 331
+#define ALGORITHM_CLASS 332
+#define ALGORITHMTYPE 333
+#define STRENGTHTYPE 334
+#define SAINFO 335
+#define FROM 336
+#define REMOTE 337
+#define ANONYMOUS 338
+#define CLIENTADDR 339
+#define INHERIT 340
+#define REMOTE_ADDRESS 341
+#define EXCHANGE_MODE 342
+#define EXCHANGETYPE 343
+#define DOI 344
+#define DOITYPE 345
+#define SITUATION 346
+#define SITUATIONTYPE 347
+#define CERTIFICATE_TYPE 348
+#define CERTTYPE 349
+#define PEERS_CERTFILE 350
+#define CA_TYPE 351
+#define VERIFY_CERT 352
+#define SEND_CERT 353
+#define SEND_CR 354
+#define MATCH_EMPTY_CR 355
+#define IDENTIFIERTYPE 356
+#define IDENTIFIERQUAL 357
+#define MY_IDENTIFIER 358
+#define PEERS_IDENTIFIER 359
+#define VERIFY_IDENTIFIER 360
+#define DNSSEC 361
+#define CERT_X509 362
+#define CERT_PLAINRSA 363
+#define NONCE_SIZE 364
+#define DH_GROUP 365
+#define KEEPALIVE 366
+#define PASSIVE 367
+#define INITIAL_CONTACT 368
+#define NAT_TRAVERSAL 369
+#define REMOTE_FORCE_LEVEL 370
+#define PROPOSAL_CHECK 371
+#define PROPOSAL_CHECK_LEVEL 372
+#define GENERATE_POLICY 373
+#define GENERATE_LEVEL 374
+#define SUPPORT_PROXY 375
+#define PROPOSAL 376
+#define EXEC_PATH 377
+#define EXEC_COMMAND 378
+#define EXEC_SUCCESS 379
+#define EXEC_FAILURE 380
+#define GSS_ID 381
+#define GSS_ID_ENC 382
+#define GSS_ID_ENCTYPE 383
+#define COMPLEX_BUNDLE 384
+#define DPD 385
+#define DPD_DELAY 386
+#define DPD_RETRY 387
+#define DPD_MAXFAIL 388
+#define PH1ID 389
+#define XAUTH_LOGIN 390
+#define WEAK_PHASE1_CHECK 391
+#define REKEY 392
+#define PREFIX 393
+#define PORT 394
+#define PORTANY 395
+#define UL_PROTO 396
+#define ANY 397
+#define IKE_FRAG 398
+#define ESP_FRAG 399
+#define MODE_CFG 400
+#define PFS_GROUP 401
+#define LIFETIME 402
+#define LIFETYPE_TIME 403
+#define LIFETYPE_BYTE 404
+#define STRENGTH 405
+#define REMOTEID 406
+#define SCRIPT 407
+#define PHASE1_UP 408
+#define PHASE1_DOWN 409
+#define PHASE1_DEAD 410
+#define NUMBER 411
+#define SWITCH 412
+#define BOOLEAN 413
+#define HEXSTRING 414
+#define QUOTEDSTRING 415
+#define ADDRSTRING 416
+#define ADDRRANGE 417
+#define UNITTYPE_BYTE 418
+#define UNITTYPE_KBYTES 419
+#define UNITTYPE_MBYTES 420
+#define UNITTYPE_TBYTES 421
+#define UNITTYPE_SEC 422
+#define UNITTYPE_MIN 423
+#define UNITTYPE_HOUR 424
+#define EOS 425
+#define BOC 426
+#define EOC 427
+#define COMMA 428
 
 
 
 
 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
 typedef union YYSTYPE
-#line 174 "cfparse.y"
 {
+
+/* Line 1676 of yacc.c  */
+#line 177 "cfparse.y"
+
 	unsigned long num;
 	vchar_t *val;
 	struct remoteconf *rmconf;
 	struct sockaddr *saddr;
 	struct sainfoalg *alg;
-}
-/* Line 1489 of yacc.c.  */
-#line 385 "cfparse.h"
-	YYSTYPE;
+
+
+
+/* Line 1676 of yacc.c  */
+#line 408 "cfparse.h"
+} YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
 # define yystype YYSTYPE /* obsolescent; will be withdrawn */
 # define YYSTYPE_IS_DECLARED 1
-# define YYSTYPE_IS_TRIVIAL 1
 #endif
 
 extern YYSTYPE yylval;
 
+
diff --git a/src/racoon/cfparse.y b/src/racoon/cfparse.y
index 540c400..12920d8 100644
--- a/src/racoon/cfparse.y
+++ b/src/racoon/cfparse.y
@@ -1,4 +1,4 @@
-/*	$NetBSD: cfparse.y,v 1.18.4.7 2008/07/21 20:45:32 tteras Exp $	*/
+/*	$NetBSD: cfparse.y,v 1.42 2011/03/14 15:50:36 vanhu Exp $	*/
 
 /* Id: cfparse.y,v 1.66 2006/08/22 18:17:17 manubsd Exp */
 
@@ -94,14 +94,7 @@
 #endif
 #include "vendorid.h"
 #include "rsalist.h"
-
-struct proposalspec {
-	time_t lifetime;		/* for isakmp/ipsec */
-	int lifebyte;			/* for isakmp/ipsec */
-	struct secprotospec *spspec;	/* the head is always current spec. */
-	struct proposalspec *next;	/* the tail is the most prefered. */
-	struct proposalspec *prev;
-};
+#include "crypto_openssl.h"
 
 struct secprotospec {
 	int prop_no;
@@ -120,7 +113,6 @@
 
 	struct secprotospec *next;	/* the tail is the most prefiered. */
 	struct secprotospec *prev;
-	struct proposalspec *back;
 };
 
 static int num2dhgroup[] = {
@@ -151,24 +143,35 @@
 static int cur_algclass;
 static int oldloglevel = LLV_BASE;
 
-static struct proposalspec *newprspec __P((void));
-static void insprspec __P((struct proposalspec *, struct proposalspec **));
 static struct secprotospec *newspspec __P((void));
-static void insspspec __P((struct secprotospec *, struct proposalspec **));
+static void insspspec __P((struct remoteconf *, struct secprotospec *));
+void dupspspec_list __P((struct remoteconf *dst, struct remoteconf *src));
+void flushspspec __P((struct remoteconf *));
 static void adminsock_conf __P((vchar_t *, vchar_t *, vchar_t *, int));
 
-static int set_isakmp_proposal
-	__P((struct remoteconf *, struct proposalspec *));
+static int set_isakmp_proposal __P((struct remoteconf *));
 static void clean_tmpalgtype __P((void));
 static int expand_isakmpspec __P((int, int, int *,
 	int, int, time_t, int, int, int, char *, struct remoteconf *));
-static int listen_addr __P((struct sockaddr *addr, int udp_encap));
 
 void freeetypes (struct etypes **etypes);
 
-#if 0
-static int fix_lifebyte __P((u_long));
-#endif
+static int load_x509(const char *file, char **filenameptr,
+		     vchar_t **certptr)
+{
+	char path[PATH_MAX];
+
+	getpathname(path, sizeof(path), LC_PATHTYPE_CERT, file);
+	*certptr = eay_get_x509cert(path);
+	if (*certptr == NULL)
+		return -1;
+
+	*filenameptr = racoon_strdup(file);
+	STRDUP_FATAL(*filenameptr);
+
+	return 0;
+}
+
 %}
 
 %union {
@@ -185,8 +188,8 @@
 %token PATH PATHTYPE
 	/* include */
 %token INCLUDE
-	/* self information */
-%token IDENTIFIER VENDORID
+	/* PFKEY_BUFFER */
+%token PFKEY_BUFFER
 	/* logging */
 %token LOGGING LOGLEV
 	/* padding */
@@ -196,6 +199,8 @@
 	/* ldap config */
 %token LDAPCFG LDAP_HOST LDAP_PORT LDAP_PVER LDAP_BASE LDAP_BIND_DN LDAP_BIND_PW LDAP_SUBTREE
 %token LDAP_ATTR_USER LDAP_ATTR_ADDR LDAP_ATTR_MASK LDAP_ATTR_GROUP LDAP_ATTR_MEMBER
+	/* radius config */
+%token RADCFG RAD_AUTH RAD_ACCT RAD_TIMEOUT RAD_RETRIES
 	/* modecfg */
 %token MODECFG CFG_NET4 CFG_MASK4 CFG_DNS4 CFG_NBNS4 CFG_DEFAULT_DOMAIN
 %token CFG_AUTH_SOURCE CFG_AUTH_GROUPS CFG_SYSTEM CFG_RADIUS CFG_PAM CFG_LDAP CFG_LOCAL CFG_NONE
@@ -211,10 +216,10 @@
 	/* sainfo */
 %token SAINFO FROM
 	/* remote */
-%token REMOTE ANONYMOUS INHERIT
+%token REMOTE ANONYMOUS CLIENTADDR INHERIT REMOTE_ADDRESS
 %token EXCHANGE_MODE EXCHANGETYPE DOI DOITYPE SITUATION SITUATIONTYPE
 %token CERTIFICATE_TYPE CERTTYPE PEERS_CERTFILE CA_TYPE
-%token VERIFY_CERT SEND_CERT SEND_CR
+%token VERIFY_CERT SEND_CERT SEND_CR MATCH_EMPTY_CR
 %token IDENTIFIERTYPE IDENTIFIERQUAL MY_IDENTIFIER 
 %token PEERS_IDENTIFIER VERIFY_IDENTIFIER
 %token DNSSEC CERT_X509 CERT_PLAINRSA
@@ -229,11 +234,12 @@
 %token DPD DPD_DELAY DPD_RETRY DPD_MAXFAIL
 %token PH1ID
 %token XAUTH_LOGIN WEAK_PHASE1_CHECK
+%token REKEY
 
 %token PREFIX PORT PORTANY UL_PROTO ANY IKE_FRAG ESP_FRAG MODE_CFG
 %token PFS_GROUP LIFETIME LIFETYPE_TIME LIFETYPE_BYTE STRENGTH REMOTEID
 
-%token SCRIPT PHASE1_UP PHASE1_DOWN
+%token SCRIPT PHASE1_UP PHASE1_DOWN PHASE1_DEAD
 
 %token NUMBER SWITCH BOOLEAN
 %token HEXSTRING QUOTEDSTRING ADDRSTRING ADDRRANGE
@@ -265,12 +271,13 @@
 	:	privsep_statement
 	|	path_statement
 	|	include_statement
+	|	pfkey_statement
 	|	gssenc_statement
-	|	identifier_statement
 	|	logging_statement
 	|	padding_statement
 	|	listen_statement
 	|	ldapcfg_statement
+	|	radcfg_statement
 	|	modecfg_statement
 	|	timer_statement
 	|	sainfo_statement
@@ -354,6 +361,13 @@
 		}
 	;
 
+    /* pfkey_buffer */
+pfkey_statement
+    :   PFKEY_BUFFER NUMBER EOS
+        {
+			lcconf->pfkey_buffer_size = $2;
+        }
+    ;
 	/* gss_id_enc */
 gssenc_statement
 	:	GSS_ID_ENC GSS_ID_ENCTYPE EOS
@@ -366,45 +380,12 @@
 		}
 	;
 
-	/* self information */
-identifier_statement
-	:	IDENTIFIER identifier_stmt
-	;
-identifier_stmt
-	:	VENDORID
-		{
-			/*XXX to be deleted */
-		}
-		QUOTEDSTRING EOS
-	|	IDENTIFIERTYPE QUOTEDSTRING
-		{
-			/*XXX to be deleted */
-			$2->l--;	/* nuke '\0' */
-			lcconf->ident[$1] = $2;
-			if (lcconf->ident[$1] == NULL) {
-				yyerror("failed to set my ident: %s",
-					strerror(errno));
-				return -1;
-			}
-		}
-		EOS
-	;
-
 	/* logging */
 logging_statement
 	:	LOGGING log_level EOS
 	;
 log_level
-	:	HEXSTRING
-		{
-			/*
-			 * XXX ignore it because this specification
-			 * will be obsoleted.
-			 */
-			yywarn("see racoon.conf(5), such a log specification will be obsoleted.");
-			vfree($1);
-		}
-	|	LOGLEV
+	:	LOGLEV
 		{
 			/*
 			 * set the loglevel to the value specified
@@ -443,23 +424,21 @@
 listen_stmt
 	:	X_ISAKMP ike_addrinfo_port
 		{
-			listen_addr ($2, 0);
+			myaddr_listen($2, FALSE);
+			racoon_free($2);
 		}
 		EOS
 	|	X_ISAKMP_NATT ike_addrinfo_port
 		{
 #ifdef ENABLE_NATT
-			listen_addr ($2, 1);
+			myaddr_listen($2, TRUE);
+			racoon_free($2);
 #else
+			racoon_free($2);
 			yyerror("NAT-T support not compiled in.");
 #endif
 		}
 		EOS
-	|	X_ADMIN
-		{
-			yyerror("admin directive is obsoleted.");
-		}
-		PORT EOS
 	|	ADMINSOCK QUOTEDSTRING QUOTEDSTRING QUOTEDSTRING NUMBER 
 		{
 #ifdef ENABLE_ADMINPORT
@@ -506,6 +485,122 @@
 	|	PORT		{ $$ = $1; }
 	;
 
+	/* radius configuration */
+radcfg_statement
+	:	RADCFG {
+#ifndef ENABLE_HYBRID
+			yyerror("racoon not configured with --enable-hybrid");
+			return -1;
+#endif
+#ifndef HAVE_LIBRADIUS
+			yyerror("racoon not configured with --with-libradius");
+			return -1;
+#endif
+#ifdef ENABLE_HYBRID
+#ifdef HAVE_LIBRADIUS
+			xauth_rad_config.timeout = 3;
+			xauth_rad_config.retries = 3;
+#endif
+#endif
+		} BOC radcfg_stmts EOC
+	;
+radcfg_stmts
+	:	/* nothing */
+	|	radcfg_stmts radcfg_stmt
+	;
+radcfg_stmt
+	:	RAD_AUTH QUOTEDSTRING QUOTEDSTRING
+		{
+#ifdef ENABLE_HYBRID
+#ifdef HAVE_LIBRADIUS
+			int i = xauth_rad_config.auth_server_count;
+			if (i == RADIUS_MAX_SERVERS) {
+				yyerror("maximum radius auth servers exceeded");
+				return -1;
+			}
+
+			xauth_rad_config.auth_server_list[i].host = vdup($2);
+			xauth_rad_config.auth_server_list[i].secret = vdup($3);
+			xauth_rad_config.auth_server_list[i].port = 0; // default port
+			xauth_rad_config.auth_server_count++;
+#endif
+#endif
+		}
+		EOS
+	|	RAD_AUTH QUOTEDSTRING NUMBER QUOTEDSTRING
+		{
+#ifdef ENABLE_HYBRID
+#ifdef HAVE_LIBRADIUS
+			int i = xauth_rad_config.auth_server_count;
+			if (i == RADIUS_MAX_SERVERS) {
+				yyerror("maximum radius auth servers exceeded");
+				return -1;
+			}
+
+			xauth_rad_config.auth_server_list[i].host = vdup($2);
+			xauth_rad_config.auth_server_list[i].secret = vdup($4);
+			xauth_rad_config.auth_server_list[i].port = $3;
+			xauth_rad_config.auth_server_count++;
+#endif
+#endif
+		}
+		EOS
+	|	RAD_ACCT QUOTEDSTRING QUOTEDSTRING
+		{
+#ifdef ENABLE_HYBRID
+#ifdef HAVE_LIBRADIUS
+			int i = xauth_rad_config.acct_server_count;
+			if (i == RADIUS_MAX_SERVERS) {
+				yyerror("maximum radius account servers exceeded");
+				return -1;
+			}
+
+			xauth_rad_config.acct_server_list[i].host = vdup($2);
+			xauth_rad_config.acct_server_list[i].secret = vdup($3);
+			xauth_rad_config.acct_server_list[i].port = 0; // default port
+			xauth_rad_config.acct_server_count++;
+#endif
+#endif
+		}
+		EOS
+	|	RAD_ACCT QUOTEDSTRING NUMBER QUOTEDSTRING
+		{
+#ifdef ENABLE_HYBRID
+#ifdef HAVE_LIBRADIUS
+			int i = xauth_rad_config.acct_server_count;
+			if (i == RADIUS_MAX_SERVERS) {
+				yyerror("maximum radius account servers exceeded");
+				return -1;
+			}
+
+			xauth_rad_config.acct_server_list[i].host = vdup($2);
+			xauth_rad_config.acct_server_list[i].secret = vdup($4);
+			xauth_rad_config.acct_server_list[i].port = $3;
+			xauth_rad_config.acct_server_count++;
+#endif
+#endif
+		}
+		EOS
+	|	RAD_TIMEOUT NUMBER
+		{
+#ifdef ENABLE_HYBRID
+#ifdef HAVE_LIBRADIUS
+			xauth_rad_config.timeout = $2;
+#endif
+#endif
+		}
+		EOS
+	|	RAD_RETRIES NUMBER
+		{
+#ifdef ENABLE_HYBRID
+#ifdef HAVE_LIBRADIUS
+			xauth_rad_config.retries = $2;
+#endif
+#endif
+		}
+		EOS
+	;
+
 	/* ldap configuration */
 ldapcfg_statement
 	:	LDAPCFG {
@@ -1015,12 +1110,16 @@
 
 			grouplist = racoon_realloc(icc->grouplist,
 					sizeof(char**)*(icc->groupcount+1));
-			if (grouplist == NULL)
+			if (grouplist == NULL) {
 				yyerror("unable to allocate auth group list");
+				return -1;
+			}
 
 			groupname = racoon_malloc($1->l+1);
-			if (groupname == NULL)
+			if (groupname == NULL) {
 				yyerror("unable to allocate auth group name");
+				return -1;
+			}
 
 			memcpy(groupname,$1->v,$1->l);
 			groupname[$1->l]=0;
@@ -1048,8 +1147,10 @@
 			if (!icc->splitdns_len)
 			{
 				icc->splitdns_list = racoon_malloc($1->l);
-				if(icc->splitdns_list == NULL)
+				if(icc->splitdns_list == NULL) {
 					yyerror("error allocating splitdns list buffer");
+					return -1;
+				}
 				memcpy(icc->splitdns_list,$1->v,$1->l);
 				icc->splitdns_len = $1->l;
 			}
@@ -1057,8 +1158,10 @@
 			{
 				int len = icc->splitdns_len + $1->l + 1;
 				icc->splitdns_list = racoon_realloc(icc->splitdns_list,len);
-				if(icc->splitdns_list == NULL)
+				if(icc->splitdns_list == NULL) {
 					yyerror("error allocating splitdns list buffer");
+					return -1;
+				}
 				icc->splitdns_list[icc->splitdns_len] = ',';
 				memcpy(icc->splitdns_list + icc->splitdns_len + 1, $1->v, $1->l);
 				icc->splitdns_len = len;
@@ -1154,12 +1257,16 @@
 			check = getsainfo(cur_sainfo->idsrc,
 					  cur_sainfo->iddst,
 					  cur_sainfo->id_i,
+					  NULL,
 					  cur_sainfo->remoteid);
-			if (check && (!check->idsrc && !cur_sainfo->idsrc)) {
+
+			if (check && ((check->idsrc != SAINFO_ANONYMOUS) &&
+				      (cur_sainfo->idsrc != SAINFO_ANONYMOUS))) {
 				yyerror("duplicated sainfo: %s",
 					sainfo2str(cur_sainfo));
 				return -1;
 			}
+
 			inssainfo(cur_sainfo);
 		}
 		EOC
@@ -1167,18 +1274,28 @@
 sainfo_name
 	:	ANONYMOUS
 		{
-			cur_sainfo->idsrc = NULL;
-			cur_sainfo->iddst = NULL;
+			cur_sainfo->idsrc = SAINFO_ANONYMOUS;
+			cur_sainfo->iddst = SAINFO_ANONYMOUS;
+		}
+	|	ANONYMOUS CLIENTADDR
+		{
+			cur_sainfo->idsrc = SAINFO_ANONYMOUS;
+			cur_sainfo->iddst = SAINFO_CLIENTADDR;
 		}
 	|	ANONYMOUS sainfo_id
 		{
-			cur_sainfo->idsrc = NULL;
+			cur_sainfo->idsrc = SAINFO_ANONYMOUS;
 			cur_sainfo->iddst = $2;
 		}
 	|	sainfo_id ANONYMOUS
 		{
 			cur_sainfo->idsrc = $1;
-			cur_sainfo->iddst = NULL;
+			cur_sainfo->iddst = SAINFO_ANONYMOUS;
+		}
+	|	sainfo_id CLIENTADDR
+		{
+			cur_sainfo->idsrc = $1;
+			cur_sainfo->iddst = SAINFO_CLIENTADDR;
 		}
 	|	sainfo_id sainfo_id
 		{
@@ -1407,16 +1524,6 @@
 			cur_algclass = $1;
 		}
 		algorithms EOS
-	|	IDENTIFIER IDENTIFIERTYPE
-		{
-			yyerror("it's deprecated to specify a identifier in phase 2");
-		}
-		EOS
-	|	MY_IDENTIFIER IDENTIFIERTYPE QUOTEDSTRING
-		{
-			yyerror("it's deprecated to specify a identifier in phase 2");
-		}
-		EOS
 	;
 
 algorithms
@@ -1507,36 +1614,82 @@
 
 	/* remote */
 remote_statement
-	:	REMOTE remote_index INHERIT remote_index
+	: REMOTE QUOTEDSTRING INHERIT QUOTEDSTRING
 		{
-			struct remoteconf *new;
-			struct proposalspec *prspec;
+			struct remoteconf *from, *new;
 
-			new = copyrmconf($4);
-			if (new == NULL) {
-				yyerror("failed to get remoteconf for %s.", saddr2str ($4));
+			if (getrmconf_by_name($2->v) != NULL) {
+				yyerror("named remoteconf \"%s\" already exists.");
 				return -1;
 			}
 
-			new->remote = $2;
-			new->inherited_from = getrmconf_strict($4, 1);
-			new->proposal = NULL;
-			new->prhead = NULL;
+			from = getrmconf_by_name($4->v);
+			if (from == NULL) {
+				yyerror("named parent remoteconf \"%s\" does not exist.",
+					$4->v);
+				return -1;
+			}
+
+			new = duprmconf_shallow(from);
+			if (new == NULL) {
+				yyerror("failed to duplicate remoteconf from \"%s\".",
+					$4->v);
+				return -1;
+			}
+
+			new->name = racoon_strdup($2->v);
 			cur_rmconf = new;
 
-			prspec = newprspec();
-			if (prspec == NULL || !cur_rmconf->inherited_from 
-				|| !cur_rmconf->inherited_from->proposal)
+			vfree($2);
+			vfree($4);
+		}
+		remote_specs_block
+	| REMOTE QUOTEDSTRING
+		{
+			struct remoteconf *new;
+
+			if (getrmconf_by_name($2->v) != NULL) {
+				yyerror("Named remoteconf \"%s\" already exists.");
 				return -1;
-			prspec->lifetime = cur_rmconf->inherited_from->proposal->lifetime;
-			prspec->lifebyte = cur_rmconf->inherited_from->proposal->lifebyte;
-			insprspec(prspec, &cur_rmconf->prhead);
+			}
+
+			new = newrmconf();
+			if (new == NULL) {
+				yyerror("failed to get new remoteconf.");
+				return -1;
+			}
+			new->name = racoon_strdup($2->v);
+			cur_rmconf = new;
+
+			vfree($2);
+		}
+		remote_specs_block
+	| REMOTE remote_index INHERIT remote_index
+		{
+			struct remoteconf *from, *new;
+
+			from = getrmconf($4, GETRMCONF_F_NO_ANONYMOUS);
+			if (from == NULL) {
+				yyerror("failed to get remoteconf for %s.",
+					saddr2str($4));
+				return -1;
+			}
+
+			new = duprmconf_shallow(from);
+			if (new == NULL) {
+				yyerror("failed to duplicate remoteconf from %s.",
+					saddr2str($4));
+				return -1;
+			}
+
+			racoon_free($4);
+			new->remote = $2;
+			cur_rmconf = new;
 		}
 		remote_specs_block
 	|	REMOTE remote_index
 		{
 			struct remoteconf *new;
-			struct proposalspec *prspec;
 
 			new = newrmconf();
 			if (new == NULL) {
@@ -1546,12 +1699,6 @@
 
 			new->remote = $2;
 			cur_rmconf = new;
-
-			prspec = newprspec();
-			if (prspec == NULL)
-				return -1;
-			prspec->lifetime = oakley_get_defaultlifetime();
-			insprspec(prspec, &cur_rmconf->prhead);
 		}
 		remote_specs_block
 	;
@@ -1568,7 +1715,6 @@
 			if (cur_rmconf->idvtype == IDTYPE_UNDEFINED)
 				cur_rmconf->idvtype = IDTYPE_ADDRESS;
 
-
 			if (cur_rmconf->idvtype == IDTYPE_ASN1DN) {
 				if (cur_rmconf->mycertfile) {
 					if (cur_rmconf->idv)
@@ -1583,17 +1729,24 @@
 					return -1;
 				}
 			}
-			
-			if (cur_rmconf->prhead->spspec == NULL
-				&& cur_rmconf->inherited_from
-				&& cur_rmconf->inherited_from->prhead) {
-				cur_rmconf->prhead->spspec = cur_rmconf->inherited_from->prhead->spspec;
+
+			if (duprmconf_finish(cur_rmconf))
+				return -1;
+
+#if 0
+			/* this pointer copy will never happen, because duprmconf_shallow
+			 * already copied all pointers.
+			 */
+			if (cur_rmconf->spspec == NULL &&
+			    cur_rmconf->inherited_from != NULL) {
+				cur_rmconf->spspec = cur_rmconf->inherited_from->spspec;
 			}
-			if (set_isakmp_proposal(cur_rmconf, cur_rmconf->prhead) != 0)
+#endif
+			if (set_isakmp_proposal(cur_rmconf) != 0)
 				return -1;
 
 			/* DH group settting if aggressive mode is there. */
-			if (check_etypeok(cur_rmconf, ISAKMP_ETYPE_AGG) != NULL) {
+			if (check_etypeok(cur_rmconf, (void*) ISAKMP_ETYPE_AGG)) {
 				struct isakmpsa *p;
 				int b = 0;
 
@@ -1648,7 +1801,16 @@
 	|	remote_specs remote_spec
 	;
 remote_spec
-	:	EXCHANGE_MODE
+	:	REMOTE_ADDRESS ike_addrinfo_port
+		{
+			if (cur_rmconf->remote != NULL) {
+				yyerror("remote_address already specified");
+				return -1;
+			}
+			cur_rmconf->remote = $2;
+		}
+		EOS
+	|	EXCHANGE_MODE
 		{
 			cur_rmconf->etypes = NULL;
 		}
@@ -1660,33 +1822,36 @@
 		{
 			yywarn("This directive without certtype will be removed!\n");
 			yywarn("Please use 'peers_certfile x509 \"%s\";' instead\n", $2->v);
-			cur_rmconf->getcert_method = ISAKMP_GETCERT_LOCALFILE;
 
-			if (cur_rmconf->peerscertfile != NULL)
-				racoon_free(cur_rmconf->peerscertfile);
-			cur_rmconf->peerscertfile = racoon_strdup($2->v);
-			STRDUP_FATAL(cur_rmconf->peerscertfile);
+			if (cur_rmconf->peerscert != NULL) {
+				yyerror("peers_certfile already defined\n");
+				return -1;
+			}
+
+			if (load_x509($2->v, &cur_rmconf->peerscertfile,
+				      &cur_rmconf->peerscert)) {
+				yyerror("failed to load certificate \"%s\"\n",
+					$2->v);
+				return -1;
+			}
+
 			vfree($2);
 		}
 		EOS
-	|	CA_TYPE CERT_X509 QUOTEDSTRING
-		{
-			cur_rmconf->cacerttype = $2;
-			cur_rmconf->getcacert_method = ISAKMP_GETCERT_LOCALFILE;
-			if (cur_rmconf->cacertfile != NULL)
-				racoon_free(cur_rmconf->cacertfile);
-			cur_rmconf->cacertfile = racoon_strdup($3->v);
-			STRDUP_FATAL(cur_rmconf->cacertfile);
-			vfree($3);
-		}
-		EOS
 	|	PEERS_CERTFILE CERT_X509 QUOTEDSTRING
 		{
-			cur_rmconf->getcert_method = ISAKMP_GETCERT_LOCALFILE;
-			if (cur_rmconf->peerscertfile != NULL)
-				racoon_free(cur_rmconf->peerscertfile);
-			cur_rmconf->peerscertfile = racoon_strdup($3->v);
-			STRDUP_FATAL(cur_rmconf->peerscertfile);
+			if (cur_rmconf->peerscert != NULL) {
+				yyerror("peers_certfile already defined\n");
+				return -1;
+			}
+
+			if (load_x509($3->v, &cur_rmconf->peerscertfile,
+				      &cur_rmconf->peerscert)) {
+				yyerror("failed to load certificate \"%s\"\n",
+					$3->v);
+				return -1;
+			}
+
 			vfree($3);
 		}
 		EOS
@@ -1695,37 +1860,66 @@
 			char path[MAXPATHLEN];
 			int ret = 0;
 
-			getpathname(path, sizeof(path),
-				LC_PATHTYPE_CERT, $3->v);
-			vfree($3);
-
-			if (cur_rmconf->getcert_method == ISAKMP_GETCERT_DNS) {
-				yyerror("Different peers_certfile method "
-					"already defined: %d!\n",
-					cur_rmconf->getcert_method);
+			if (cur_rmconf->peerscert != NULL) {
+				yyerror("peers_certfile already defined\n");
 				return -1;
 			}
-			cur_rmconf->getcert_method = ISAKMP_GETCERT_LOCALFILE;
-			if (rsa_parse_file(cur_rmconf->rsa_public, path, RSA_TYPE_PUBLIC)) {
+
+			cur_rmconf->peerscert = vmalloc(1);
+			if (cur_rmconf->peerscert == NULL) {
+				yyerror("failed to allocate peerscert");
+				return -1;
+			}
+			cur_rmconf->peerscert->v[0] = ISAKMP_CERT_PLAINRSA;
+
+			getpathname(path, sizeof(path),
+				    LC_PATHTYPE_CERT, $3->v);
+			if (rsa_parse_file(cur_rmconf->rsa_public, path,
+					   RSA_TYPE_PUBLIC)) {
 				yyerror("Couldn't parse keyfile.\n", path);
 				return -1;
 			}
-			plog(LLV_DEBUG, LOCATION, NULL, "Public PlainRSA keyfile parsed: %s\n", path);
+			plog(LLV_DEBUG, LOCATION, NULL,
+			     "Public PlainRSA keyfile parsed: %s\n", path);
+
+			vfree($3);
 		}
 		EOS
 	|	PEERS_CERTFILE DNSSEC
 		{
-			if (cur_rmconf->getcert_method) {
-				yyerror("Different peers_certfile method already defined!\n");
+			if (cur_rmconf->peerscert != NULL) {
+				yyerror("peers_certfile already defined\n");
 				return -1;
 			}
-			cur_rmconf->getcert_method = ISAKMP_GETCERT_DNS;
-			cur_rmconf->peerscertfile = NULL;
+			cur_rmconf->peerscert = vmalloc(1);
+			if (cur_rmconf->peerscert == NULL) {
+				yyerror("failed to allocate peerscert");
+				return -1;
+			}
+			cur_rmconf->peerscert->v[0] = ISAKMP_CERT_DNS;
+		}
+		EOS
+	|	CA_TYPE CERT_X509 QUOTEDSTRING
+		{
+			if (cur_rmconf->cacert != NULL) {
+				yyerror("ca_type already defined\n");
+				return -1;
+			}
+
+			if (load_x509($3->v, &cur_rmconf->cacertfile,
+				      &cur_rmconf->cacert)) {
+				yyerror("failed to load certificate \"%s\"\n",
+					$3->v);
+				return -1;
+			}
+
+			vfree($3);
 		}
 		EOS
 	|	VERIFY_CERT SWITCH { cur_rmconf->verify_cert = $2; } EOS
 	|	SEND_CERT SWITCH { cur_rmconf->send_cert = $2; } EOS
 	|	SEND_CR SWITCH { cur_rmconf->send_cr = $2; } EOS
+	|	MATCH_EMPTY_CR SWITCH { cur_rmconf->match_empty_cr = $2; } EOS
 	|	MY_IDENTIFIER IDENTIFIERTYPE identifierstring
 		{
 			if (set_identifier(&cur_rmconf->idv, $2, $3) != 0) {
@@ -1830,6 +2024,13 @@
 			cur_rmconf->script[SCRIPT_PHASE1_DOWN] = 
 			    script_path_add(vdup($2));
 		} EOS
+	|	SCRIPT QUOTEDSTRING PHASE1_DEAD { 
+			if (cur_rmconf->script[SCRIPT_PHASE1_DEAD] != NULL)
+				vfree(cur_rmconf->script[SCRIPT_PHASE1_DEAD]);
+
+			cur_rmconf->script[SCRIPT_PHASE1_DEAD] = 
+			    script_path_add(vdup($2));
+		} EOS
 	|	MODE_CFG SWITCH { cur_rmconf->mode_cfg = $2; } EOS
 	|	WEAK_PHASE1_CHECK SWITCH {
 			cur_rmconf->weak_phase1_check = $2;
@@ -1895,6 +2096,8 @@
 #endif
 		}
 		EOS
+	|	REKEY SWITCH { cur_rmconf->rekey = $2; } EOS
+	|	REKEY REMOTE_FORCE_LEVEL { cur_rmconf->rekey = REKEY_FORCE; } EOS
 	|	PH1ID NUMBER
 		{
 			cur_rmconf->ph1id = $2;
@@ -1902,7 +2105,7 @@
 		EOS
 	|	LIFETIME LIFETYPE_TIME NUMBER unittype_time
 		{
-			cur_rmconf->prhead->lifetime = $3 * $4;
+			cur_rmconf->lifetime = $3 * $4;
 		}
 		EOS
 	|	PROPOSAL_CHECK PROPOSAL_CHECK_LEVEL { cur_rmconf->pcheck_level = $2; } EOS
@@ -1914,8 +2117,8 @@
 #else
 			yywarn("the lifetime of bytes in phase 1 "
 				"will be ignored at the moment.");
-			cur_rmconf->prhead->lifebyte = fix_lifebyte($3 * $4);
-			if (cur_rmconf->prhead->lifebyte == 0)
+			cur_rmconf->lifebyte = fix_lifebyte($3 * $4);
+			if (cur_rmconf->lifebyte == 0)
 				return -1;
 #endif
 		}
@@ -1927,7 +2130,7 @@
 			spspec = newspspec();
 			if (spspec == NULL)
 				return -1;
-			insspspec(spspec, &cur_rmconf->prhead);
+			insspspec(cur_rmconf, spspec);
 		}
 		BOC isakmpproposal_specs EOC
 	;
@@ -1958,16 +2161,22 @@
 cert_spec
 	:	CERT_X509 QUOTEDSTRING QUOTEDSTRING
 		{
-			cur_rmconf->certtype = $1;
-			if (cur_rmconf->mycertfile != NULL)
-				racoon_free(cur_rmconf->mycertfile);
-			cur_rmconf->mycertfile = racoon_strdup($2->v);
-			STRDUP_FATAL(cur_rmconf->mycertfile);
-			vfree($2);
-			if (cur_rmconf->myprivfile != NULL)
-				racoon_free(cur_rmconf->myprivfile);
+			if (cur_rmconf->mycert != NULL) {
+				yyerror("certificate_type already defined\n");
+				return -1;
+			}
+
+			if (load_x509($2->v, &cur_rmconf->mycertfile,
+				      &cur_rmconf->mycert)) {
+				yyerror("failed to load certificate \"%s\"\n",
+					$2->v);
+				return -1;
+			}
+
 			cur_rmconf->myprivfile = racoon_strdup($3->v);
 			STRDUP_FATAL(cur_rmconf->myprivfile);
+
+			vfree($2);
 			vfree($3);
 		}
 		EOS
@@ -1976,19 +2185,31 @@
 			char path[MAXPATHLEN];
 			int ret = 0;
 
-			getpathname(path, sizeof(path),
-				LC_PATHTYPE_CERT, $2->v);
-			vfree($2);
+			if (cur_rmconf->mycert != NULL) {
+				yyerror("certificate_type already defined\n");
+				return -1;
+			}
 
-			cur_rmconf->certtype = $1;
+			cur_rmconf->mycert = vmalloc(1);
+			if (cur_rmconf->mycert == NULL) {
+				yyerror("failed to allocate mycert");
+				return -1;
+			}
+			cur_rmconf->mycert->v[0] = ISAKMP_CERT_PLAINRSA;
+
+			getpathname(path, sizeof(path),
+				    LC_PATHTYPE_CERT, $2->v);
 			cur_rmconf->send_cr = FALSE;
 			cur_rmconf->send_cert = FALSE;
 			cur_rmconf->verify_cert = FALSE;
-			if (rsa_parse_file(cur_rmconf->rsa_private, path, RSA_TYPE_PRIVATE)) {
+			if (rsa_parse_file(cur_rmconf->rsa_private, path,
+					   RSA_TYPE_PRIVATE)) {
 				yyerror("Couldn't parse keyfile.\n", path);
 				return -1;
 			}
-			plog(LLV_DEBUG, LOCATION, NULL, "Private PlainRSA keyfile parsed: %s\n", path);
+			plog(LLV_DEBUG, LOCATION, NULL,
+			     "Private PlainRSA keyfile parsed: %s\n", path);
+			vfree($2);
 		}
 		EOS
 	;
@@ -2022,13 +2243,9 @@
 	|	isakmpproposal_specs isakmpproposal_spec
 	;
 isakmpproposal_spec
-	:	STRENGTH
+	:	LIFETIME LIFETYPE_TIME NUMBER unittype_time
 		{
-			yyerror("strength directive is obsoleted.");
-		} STRENGTHTYPE EOS
-	|	LIFETIME LIFETYPE_TIME NUMBER unittype_time
-		{
-			cur_rmconf->prhead->spspec->lifetime = $3 * $4;
+			cur_rmconf->spspec->lifetime = $3 * $4;
 		}
 		EOS
 	|	LIFETIME LIFETYPE_BYTE NUMBER unittype_byte
@@ -2037,28 +2254,28 @@
 			yyerror("byte lifetime support is deprecated");
 			return -1;
 #else
-			cur_rmconf->prhead->spspec->lifebyte = fix_lifebyte($3 * $4);
-			if (cur_rmconf->prhead->spspec->lifebyte == 0)
+			cur_rmconf->spspec->lifebyte = fix_lifebyte($3 * $4);
+			if (cur_rmconf->spspec->lifebyte == 0)
 				return -1;
 #endif
 		}
 		EOS
 	|	DH_GROUP dh_group_num
 		{
-			cur_rmconf->prhead->spspec->algclass[algclass_isakmp_dh] = $2;
+			cur_rmconf->spspec->algclass[algclass_isakmp_dh] = $2;
 		}
 		EOS
 	|	GSS_ID QUOTEDSTRING
 		{
-			if (cur_rmconf->prhead->spspec->vendorid != VENDORID_GSSAPI) {
+			if (cur_rmconf->spspec->vendorid != VENDORID_GSSAPI) {
 				yyerror("wrong Vendor ID for gssapi_id");
 				return -1;
 			}
-			if (cur_rmconf->prhead->spspec->gssid != NULL)
-				racoon_free(cur_rmconf->prhead->spspec->gssid);
-			cur_rmconf->prhead->spspec->gssid = 
+			if (cur_rmconf->spspec->gssid != NULL)
+				racoon_free(cur_rmconf->spspec->gssid);
+			cur_rmconf->spspec->gssid =
 			    racoon_strdup($2->v);
-			STRDUP_FATAL(cur_rmconf->prhead->spspec->gssid);
+			STRDUP_FATAL(cur_rmconf->spspec->gssid);
 		}
 		EOS
 	|	ALGORITHM_CLASS ALGORITHMTYPE keylength
@@ -2090,7 +2307,7 @@
 				}
 #endif
 
-				cur_rmconf->prhead->spspec->algclass[algclass_isakmp_enc] = doi;
+				cur_rmconf->spspec->algclass[algclass_isakmp_enc] = doi;
 				defklen = default_keylen($1, $2);
 				if (defklen == 0) {
 					if ($3) {
@@ -2104,22 +2321,22 @@
 					}
 				}
 				if ($3)
-					cur_rmconf->prhead->spspec->encklen = $3;
+					cur_rmconf->spspec->encklen = $3;
 				else
-					cur_rmconf->prhead->spspec->encklen = defklen;
+					cur_rmconf->spspec->encklen = defklen;
 				break;
 			case algclass_isakmp_hash:
-				cur_rmconf->prhead->spspec->algclass[algclass_isakmp_hash] = doi;
+				cur_rmconf->spspec->algclass[algclass_isakmp_hash] = doi;
 				break;
 			case algclass_isakmp_ameth:
-				cur_rmconf->prhead->spspec->algclass[algclass_isakmp_ameth] = doi;
+				cur_rmconf->spspec->algclass[algclass_isakmp_ameth] = doi;
 				/*
 				 * We may have to set the Vendor ID for the
 				 * authentication method we're using.
 				 */
 				switch ($2) {
 				case algtype_gssapikrb:
-					if (cur_rmconf->prhead->spspec->vendorid !=
+					if (cur_rmconf->spspec->vendorid !=
 					    VENDORID_UNKNOWN) {
 						yyerror("Vendor ID mismatch "
 						    "for auth method");
@@ -2129,19 +2346,19 @@
 					 * For interoperability with Win2k,
 					 * we set the Vendor ID to "GSSAPI".
 					 */
-					cur_rmconf->prhead->spspec->vendorid =
+					cur_rmconf->spspec->vendorid =
 					    VENDORID_GSSAPI;
 					break;
 				case algtype_rsasig:
-					if (cur_rmconf->certtype == ISAKMP_CERT_PLAINRSA) {
+					if (oakley_get_certtype(cur_rmconf->peerscert) == ISAKMP_CERT_PLAINRSA) {
 						if (rsa_list_count(cur_rmconf->rsa_private) == 0) {
 							yyerror ("Private PlainRSA key not set. "
-								"Use directive 'certificate_type plainrsa ...'\n");
+								 "Use directive 'certificate_type plainrsa ...'\n");
 							return -1;
 						}
 						if (rsa_list_count(cur_rmconf->rsa_public) == 0) {
 							yyerror ("Public PlainRSA keys not set. "
-								"Use directive 'peers_certfile plainrsa ...'\n");
+								 "Use directive 'peers_certfile plainrsa ...'\n");
 							return -1;
 						}
 					}
@@ -2171,32 +2388,6 @@
 	;
 %%
 
-static struct proposalspec *
-newprspec()
-{
-	struct proposalspec *new;
-
-	new = racoon_calloc(1, sizeof(*new));
-	if (new == NULL)
-		yyerror("failed to allocate proposal");
-
-	return new;
-}
-
-/*
- * insert into head of list.
- */
-static void
-insprspec(prspec, head)
-	struct proposalspec *prspec;
-	struct proposalspec **head;
-{
-	if (*head != NULL)
-		(*head)->prev = prspec;
-	prspec->next = *head;
-	*head = prspec;
-}
-
 static struct secprotospec *
 newspspec()
 {
@@ -2224,44 +2415,113 @@
  * insert into head of list.
  */
 static void
-insspspec(spspec, head)
+insspspec(rmconf, spspec)
+	struct remoteconf *rmconf;
 	struct secprotospec *spspec;
-	struct proposalspec **head;
 {
-	spspec->back = *head;
+	if (rmconf->spspec != NULL)
+		rmconf->spspec->prev = spspec;
+	spspec->next = rmconf->spspec;
+	rmconf->spspec = spspec;
+}
 
-	if ((*head)->spspec != NULL)
-		(*head)->spspec->prev = spspec;
-	spspec->next = (*head)->spspec;
-	(*head)->spspec = spspec;
+static struct secprotospec *
+dupspspec(spspec)
+	struct secprotospec *spspec;
+{
+	struct secprotospec *new;
+
+	new = newspspec();
+	if (new == NULL) {
+		plog(LLV_ERROR, LOCATION, NULL, 
+		    "dupspspec: malloc failed\n");
+		return NULL;
+	}
+	memcpy(new, spspec, sizeof(*new));
+
+	if (spspec->gssid) {
+		new->gssid = racoon_strdup(spspec->gssid);
+		STRDUP_FATAL(new->gssid);
+	}
+	if (spspec->remote) {
+		new->remote = racoon_malloc(sizeof(*new->remote));
+		if (new->remote == NULL) {
+			plog(LLV_ERROR, LOCATION, NULL, 
+			    "dupspspec: malloc failed (remote)\n");
+			return NULL;
+		}
+		memcpy(new->remote, spspec->remote, sizeof(*new->remote));
+	}
+
+	return new;
+}
+
+/*
+ * copy the whole list
+ */
+void
+dupspspec_list(dst, src)
+	struct remoteconf *dst, *src;
+{
+	struct secprotospec *p, *new, *last;
+
+	for(p = src->spspec, last = NULL; p; p = p->next, last = new) {
+		new = dupspspec(p);
+		if (new == NULL)
+			exit(1);
+
+		new->prev = last;
+		new->next = NULL; /* not necessary but clean */
+
+		if (last)
+			last->next = new;
+		else /* first element */
+			dst->spspec = new;
+
+	}
+}
+
+/*
+ * delete the whole list
+ */
+void
+flushspspec(rmconf)
+	struct remoteconf *rmconf;
+{
+	struct secprotospec *p;
+
+	while(rmconf->spspec != NULL) {
+		p = rmconf->spspec;
+		rmconf->spspec = p->next;
+		if (p->next != NULL)
+			p->next->prev = NULL; /* not necessary but clean */
+
+		if (p->gssid)
+			racoon_free(p->gssid);
+		if (p->remote)
+			racoon_free(p->remote);
+		racoon_free(p);
+	}
+	rmconf->spspec = NULL;
 }
 
 /* set final acceptable proposal */
 static int
-set_isakmp_proposal(rmconf, prspec)
+set_isakmp_proposal(rmconf)
 	struct remoteconf *rmconf;
-	struct proposalspec *prspec;
 {
-	struct proposalspec *p;
 	struct secprotospec *s;
 	int prop_no = 1; 
 	int trns_no = 1;
 	int32_t types[MAXALGCLASS];
 
-	p = prspec;
-	if (p->next != 0) {
-		plog(LLV_ERROR, LOCATION, NULL,
-			"multiple proposal definition.\n");
-		return -1;
-	}
-
 	/* mandatory check */
-	if (p->spspec == NULL) {
+	if (rmconf->spspec == NULL) {
 		yyerror("no remote specification found: %s.\n",
 			saddr2str(rmconf->remote));
 		return -1;
 	}
-	for (s = p->spspec; s != NULL; s = s->next) {
+	for (s = rmconf->spspec; s != NULL; s = s->next) {
 		/* XXX need more to check */
 		if (s->algclass[algclass_isakmp_enc] == 0) {
 			yyerror("encryption algorithm required.");
@@ -2282,16 +2542,16 @@
 	}
 
 	/* skip to last part */
-	for (s = p->spspec; s->next != NULL; s = s->next)
+	for (s = rmconf->spspec; s->next != NULL; s = s->next)
 		;
 
 	while (s != NULL) {
 		plog(LLV_DEBUG2, LOCATION, NULL,
 			"lifetime = %ld\n", (long)
-			(s->lifetime ? s->lifetime : p->lifetime));
+			(s->lifetime ? s->lifetime : rmconf->lifetime));
 		plog(LLV_DEBUG2, LOCATION, NULL,
 			"lifebyte = %d\n",
-			s->lifebyte ? s->lifebyte : p->lifebyte);
+			s->lifebyte ? s->lifebyte : rmconf->lifebyte);
 		plog(LLV_DEBUG2, LOCATION, NULL,
 			"encklen=%d\n", s->encklen);
 
@@ -2306,8 +2566,8 @@
 		clean_tmpalgtype();
 		trns_no = expand_isakmpspec(prop_no, trns_no, types,
 				algclass_isakmp_enc, algclass_isakmp_ameth + 1,
-				s->lifetime ? s->lifetime : p->lifetime,
-				s->lifebyte ? s->lifebyte : p->lifebyte,
+				s->lifetime ? s->lifetime : rmconf->lifetime,
+				s->lifebyte ? s->lifebyte : rmconf->lifebyte,
 				s->encklen, s->vendorid, s->gssid,
 				rmconf);
 		if (trns_no == -1) {
@@ -2412,11 +2672,7 @@
 			}
 			memcpy(new->gssid->v, gssid, new->gssid->l);
 			racoon_free(gssid);
-#ifdef ENABLE_HYBRID
-		} else if (rmconf->xauth == NULL) {
-#else
 		} else {
-#endif
 			/*
 			 * Allocate the default ID so that it gets put
 			 * into a GSS ID attribute during the Phase 1
@@ -2431,30 +2687,6 @@
 	return trns_no;
 }
 
-static int
-listen_addr (struct sockaddr *addr, int udp_encap)
-{
-	struct myaddrs *p;
-
-	p = newmyaddr();
-	if (p == NULL) {
-		yyerror("failed to allocate myaddrs");
-		return -1;
-	}
-	p->addr = addr;
-	if (p->addr == NULL) {
-		yyerror("failed to copy sockaddr ");
-		delmyaddr(p);
-		return -1;
-	}
-	p->udp_encap = udp_encap;
-
-	insmyaddr(p, &lcconf->myaddrs);
-
-	lcconf->autograbaddr = 0;
-	return 0;
-}
-
 #if 0
 /*
  * fix lifebyte.
@@ -2479,6 +2711,7 @@
 {
 	int error;
 
+	yyerrorcount = 0;
 	yycf_init_buffer();
 
 	if (yycf_switch_buffer(lcconf->racoon_conf) != 0) {
diff --git a/src/racoon/cftoken.l b/src/racoon/cftoken.l
index 9950d49..3042796 100644
--- a/src/racoon/cftoken.l
+++ b/src/racoon/cftoken.l
@@ -1,4 +1,4 @@
-/*	$NetBSD: cftoken.l,v 1.11.4.2 2007/09/03 18:07:29 mgrooms Exp $	*/
+/*	$NetBSD: cftoken.l,v 1.23 2011/02/02 15:21:34 vanhu Exp $	*/
 
 /* Id: cftoken.l,v 1.53 2006/08/22 18:17:17 manubsd Exp */
 
@@ -132,7 +132,7 @@
 decstring	{digit}+
 hexstring	0x{hexdigit}+
 
-%s S_INI S_PRIV S_PTH S_INF S_LOG S_PAD S_LST S_RTRY S_CFG S_LDAP
+%s S_INI S_PRIV S_PTH S_LOG S_PAD S_LST S_RTRY S_CFG S_LDAP S_RAD
 %s S_ALGST S_ALGCL
 %s S_SAINF S_SAINFS
 %s S_RMT S_RMTS S_RMTP
@@ -174,9 +174,8 @@
 	/* include */
 <S_INI>include		{ YYDB; return(INCLUDE); }
 
-	/* self information */
-<S_INI>identifier	{ BEGIN S_INF; YYDB; yywarn("it is obsoleted.  use \"my_identifier\" in each remote directives."); return(IDENTIFIER); }
-<S_INF>{semi}		{ BEGIN S_INI; return(EOS); }
+    /* pfkey_buffer */
+<S_INI>pfkey_buffer { YYDB; return(PFKEY_BUFFER); }
 
 	/* special */
 <S_INI>complex_bundle	{ YYDB; return(COMPLEX_BUNDLE); }
@@ -189,8 +188,6 @@
 <S_LOG>info		{ YYD; yylval.num = LLV_INFO; return(LOGLEV); }
 <S_LOG>debug		{ YYD; yylval.num = LLV_DEBUG; return(LOGLEV); }
 <S_LOG>debug2		{ YYD; yylval.num = LLV_DEBUG2; return(LOGLEV); }
-<S_LOG>debug3		{ YYD; yywarn("it is obsoleted.  use \"debug2\""); yylval.num = LLV_DEBUG2; return(LOGLEV); }
-<S_LOG>debug4		{ YYD; yywarn("it is obsoleted.  use \"debug2\""); yylval.num = LLV_DEBUG2; return(LOGLEV); }
 <S_LOG>{semi}		{ BEGIN S_INI; return(EOS); }
 
 	/* padding */
@@ -214,6 +211,15 @@
 <S_LST>strict_address	{ YYD; return(STRICT_ADDRESS); }
 <S_LST>{ecl}		{ BEGIN S_INI; return(EOC); }
 
+	/* radius config */
+<S_INI>radiuscfg	{ BEGIN S_RAD; YYDB; return(RADCFG); }
+<S_RAD>{bcl}		{ return(BOC); }
+<S_RAD>auth		{ YYD; return(RAD_AUTH); }
+<S_RAD>acct		{ YYD; return(RAD_ACCT); }
+<S_RAD>timeout		{ YYD; return(RAD_TIMEOUT); }
+<S_RAD>retries		{ YYD; return(RAD_RETRIES); }
+<S_RAD>{ecl}		{ BEGIN S_INI; return(EOC); }
+
 	/* ldap config */
 <S_INI>ldapcfg		{ BEGIN S_LDAP; YYDB; return(LDAPCFG); }
 <S_LDAP>{bcl}		{ return(BOC); }
@@ -277,6 +283,7 @@
 	/* sainfo */
 <S_INI>sainfo		{ BEGIN S_SAINF; YYDB; return(SAINFO); }
 <S_SAINF>anonymous	{ YYD; return(ANONYMOUS); }
+<S_SAINF>clientaddr	{ YYD; return(CLIENTADDR); }
 <S_SAINF>{blcl}any{elcl}	{ YYD; return(PORTANY); }
 <S_SAINF>any		{ YYD; return(ANY); }
 <S_SAINF>from		{ YYD; return(FROM); }
@@ -287,7 +294,6 @@
 <S_SAINFS>{ecl}		{ BEGIN S_INI; return(EOC); }
 <S_SAINFS>pfs_group	{ YYD; return(PFS_GROUP); }
 <S_SAINFS>remoteid	{ YYD; return(REMOTEID); }
-<S_SAINFS>identifier	{ YYD; yywarn("it is obsoleted.  use \"my_identifier\"."); return(IDENTIFIER); }
 <S_SAINFS>my_identifier	{ YYD; return(MY_IDENTIFIER); }
 <S_SAINFS>lifetime	{ YYD; return(LIFETIME); }
 <S_SAINFS>time		{ YYD; return(LIFETYPE_TIME); }
@@ -304,6 +310,7 @@
 	/* remote spec */
 <S_RMT>{bcl}		{ BEGIN S_RMTS; return(BOC); }
 <S_RMTS>{ecl}		{ BEGIN S_INI; return(EOC); }
+<S_RMTS>remote_address	{ YYD; return(REMOTE_ADDRESS); }
 <S_RMTS>exchange_mode	{ YYD; return(EXCHANGE_MODE); }
 <S_RMTS>{comma}		{ YYD; /* XXX ignored, but to be handled. */ ; }
 <S_RMTS>base		{ YYD; yylval.num = ISAKMP_ETYPE_BASE; return(EXCHANGETYPE); }
@@ -315,7 +322,6 @@
 <S_RMTS>identity_only	{ YYD; yylval.num = IPSECDOI_SIT_IDENTITY_ONLY; return(SITUATIONTYPE); }
 <S_RMTS>secrecy		{ YYD; yylval.num = IPSECDOI_SIT_SECRECY; return(SITUATIONTYPE); }
 <S_RMTS>integrity	{ YYD; yylval.num = IPSECDOI_SIT_INTEGRITY; return(SITUATIONTYPE); }
-<S_RMTS>identifier	{ YYD; yywarn("it is obsoleted.  use \"my_identifier\"."); return(IDENTIFIER); }
 <S_RMTS>my_identifier	{ YYD; return(MY_IDENTIFIER); }
 <S_RMTS>xauth_login	{ YYD; return(XAUTH_LOGIN); /* formerly identifier type login */ }
 <S_RMTS>peers_identifier	{ YYD; return(PEERS_IDENTIFIER); }
@@ -329,12 +335,12 @@
 <S_RMTS>verify_cert	{ YYD; return(VERIFY_CERT); }
 <S_RMTS>send_cert	{ YYD; return(SEND_CERT); }
 <S_RMTS>send_cr		{ YYD; return(SEND_CR); }
+<S_RMTS>match_empty_cr	{ YYD; return(MATCH_EMPTY_CR); }
 <S_RMTS>dh_group	{ YYD; return(DH_GROUP); }
 <S_RMTS>nonce_size	{ YYD; return(NONCE_SIZE); }
 <S_RMTS>generate_policy	{ YYD; return(GENERATE_POLICY); }
 <S_RMTS>unique		{ YYD; yylval.num = GENERATE_POLICY_UNIQUE; return(GENERATE_LEVEL); }
 <S_RMTS>require		{ YYD; yylval.num = GENERATE_POLICY_REQUIRE; return(GENERATE_LEVEL); }
-<S_RMTS>support_mip6	{ YYD; yywarn("it is obsoleted.  use \"support_proxy\"."); return(SUPPORT_PROXY); }
 <S_RMTS>support_proxy	{ YYD; return(SUPPORT_PROXY); }
 <S_RMTS>initial_contact	{ YYD; return(INITIAL_CONTACT); }
 <S_RMTS>nat_traversal	{ YYD; return(NAT_TRAVERSAL); }
@@ -359,8 +365,10 @@
 <S_RMTS>script		{ YYD; return(SCRIPT); }
 <S_RMTS>phase1_up	{ YYD; return(PHASE1_UP); }
 <S_RMTS>phase1_down	{ YYD; return(PHASE1_DOWN); }
+<S_RMTS>phase1_dead	{ YYD; return(PHASE1_DEAD); }
 <S_RMTS>mode_cfg	{ YYD; return(MODE_CFG); }
 <S_RMTS>weak_phase1_check { YYD; return(WEAK_PHASE1_CHECK); }
+<S_RMTS>rekey		{ YYD; return(REKEY); }
 	/* remote proposal */
 <S_RMTS>proposal	{ BEGIN S_RMTP; YYDB; return(PROPOSAL); }
 <S_RMTP>{bcl}		{ return(BOC); }
@@ -427,6 +435,7 @@
 icmp6		{ YYD; yylval.num = IPPROTO_ICMPV6; return(UL_PROTO); }
 tcp		{ YYD; yylval.num = IPPROTO_TCP; return(UL_PROTO); }
 udp		{ YYD; yylval.num = IPPROTO_UDP; return(UL_PROTO); }
+gre		{ YYD; yylval.num = IPPROTO_GRE; return(UL_PROTO); }
 
 	/* algorithm type */
 des_iv64	{ YYD; yylval.num = algtype_des_iv64;	return(ALGORITHMTYPE); }
@@ -543,14 +552,12 @@
 
 
 	/* identifier type */
-vendor_id	{ YYD; yywarn("it is obsoleted."); return(VENDORID); }
 user_fqdn	{ YYD; yylval.num = IDTYPE_USERFQDN; return(IDENTIFIERTYPE); }
 fqdn		{ YYD; yylval.num = IDTYPE_FQDN; return(IDENTIFIERTYPE); }
 keyid		{ YYD; yylval.num = IDTYPE_KEYID; return(IDENTIFIERTYPE); }
 address		{ YYD; yylval.num = IDTYPE_ADDRESS; return(IDENTIFIERTYPE); }
 subnet		{ YYD; yylval.num = IDTYPE_SUBNET; return(IDENTIFIERTYPE); }
 asn1dn		{ YYD; yylval.num = IDTYPE_ASN1DN; return(IDENTIFIERTYPE); }
-certname	{ YYD; yywarn("certname will be obsoleted in near future."); yylval.num = IDTYPE_ASN1DN; return(IDENTIFIERTYPE); }
 
 	/* identifier qualifier */
 tag		{ YYD; yylval.num = IDQUAL_TAG;  return(IDENTIFIERQUAL); }
@@ -573,7 +580,7 @@
 			char *bp;
 
 			YYD;
-			yylval.num = strtol(yytext, &bp, 10);
+			yylval.num = strtoul(yytext, &bp, 10);
 			return(NUMBER);
 		}
 
@@ -631,6 +638,10 @@
 
 <<EOF>>		{
 			yy_delete_buffer(YY_CURRENT_BUFFER);
+			fclose (incstack[incstackp].fp);
+			incstack[incstackp].fp = NULL;
+			racoon_free(incstack[incstackp].path);
+			incstack[incstackp].path = NULL;
 			incstackp--;
     nextfile:
 			if (incstack[incstackp].matchon <
diff --git a/src/racoon/crypto_openssl.c b/src/racoon/crypto_openssl.c
index b6e4c0d..f8a4db9 100644
--- a/src/racoon/crypto_openssl.c
+++ b/src/racoon/crypto_openssl.c
@@ -1,4 +1,4 @@
-/*	$NetBSD: crypto_openssl.c,v 1.11.6.6 2009/04/29 10:50:25 tteras Exp $	*/
+/*	$NetBSD: crypto_openssl.c,v 1.20 2010/10/20 13:40:02 tteras Exp $	*/
 
 /* Id: crypto_openssl.c,v 1.47 2006/05/06 20:42:09 manubsd Exp */
 
@@ -113,6 +113,7 @@
 #include "crypto_openssl.h"
 #include "debug.h"
 #include "gcmalloc.h"
+#include "isakmp.h"
 
 /*
  * I hate to cast every parameter to des_xx into void *, but it is
@@ -136,9 +137,9 @@
 	int len;
 {
 	X509_NAME *name;
-	char *buf;
+	char *buf, *dst;
 	char *field, *value;
-	int i, j;
+	int i;
 	vchar_t *ret = NULL;
 	caddr_t p;
 
@@ -154,15 +155,38 @@
 
 	name = X509_NAME_new();
 
-	field = &buf[0];
+	dst = field = &buf[0];
 	value = NULL;
 	for (i = 0; i < len; i++) {
+		if (buf[i] == '\\') {
+			/* Escape characters specified in RFC 2253 */
+			if (i < len - 1 &&
+			    strchr("\\,=+<>#;", buf[i+1]) != NULL) {
+				*dst++ = buf[++i];
+				continue;
+			} else if (i < len - 2) {
+				/* RFC 2253 hexpair character escape */
+				long u;
+				char esc_str[3];
+				char *endptr;
+
+				esc_str[0] = buf[++i];
+				esc_str[1] = buf[++i];
+				esc_str[2] = '\0';
+				u = strtol(esc_str, &endptr, 16);
+				if (*endptr != '\0' || u < 0 || u > 255)
+					goto err;
+				*dst++ = u;
+				continue;
+			} else
+				goto err;
+		}
 		if (!value && buf[i] == '=') {
-			buf[i] = '\0';
-			value = &buf[i + 1];
+			*dst = '\0';
+			dst = value = &buf[i + 1];
 			continue;
 		} else if (buf[i] == ',' || buf[i] == '/') {
-			buf[i] = '\0';
+			*dst = '\0';
 
 			plog(LLV_DEBUG, LOCATION, NULL, "DN: %s=%s\n",
 			     field, value);
@@ -179,16 +203,16 @@
 				     "%s\n", eay_strerror());
 				goto err;
 			}
-			for (j = i + 1; j < len; j++) {
-				if (buf[j] != ' ')
-					break;
-			}
-			field = &buf[j];
+
+			while (i + 1 < len && buf[i + 1] == ' ') i++;
+			dst = field = &buf[i + 1];
 			value = NULL;
 			continue;
+		} else {
+			*dst++  = buf[i];
 		}
 	}
-	buf[len] = '\0';
+	*dst = '\0';
 
 	plog(LLV_DEBUG, LOCATION, NULL, "DN: %s=%s\n",
 	     field, value);
@@ -638,7 +662,7 @@
 }
 
 /*
- * get a subjectAltName from X509 certificate.
+ * get a subjectName from X509 certificate.
  */
 vchar_t *
 eay_get_x509asn1subjectname(cert)
@@ -649,8 +673,6 @@
 	vchar_t *name = NULL;
 	int len;
 
-	bp = (unsigned char *) cert->v;
-
 	x509 = mem2x509(cert);
 	if (x509 == NULL)
 		goto error;
@@ -784,6 +806,46 @@
 	return error;
 }
 
+/*
+ * get a issuerName from X509 certificate.
+ */
+vchar_t *
+eay_get_x509asn1issuername(cert)
+	vchar_t *cert;
+{
+	X509 *x509 = NULL;
+	u_char *bp;
+	vchar_t *name = NULL;
+	int len;
+
+	x509 = mem2x509(cert);
+	if (x509 == NULL)
+		goto error;
+
+	/* get the length of the name */
+	len = i2d_X509_NAME(x509->cert_info->issuer, NULL);
+	name = vmalloc(len);
+	if (name == NULL)
+		goto error;
+
+	/* get the name */
+	bp = (unsigned char *) name->v;
+	len = i2d_X509_NAME(x509->cert_info->issuer, &bp);
+
+	X509_free(x509);
+
+	return name;
+
+error:
+	plog(LLV_ERROR, LOCATION, NULL, "%s\n", eay_strerror());
+
+	if (name != NULL)
+		vfree(name);
+	if (x509 != NULL)
+		X509_free(x509);
+
+	return NULL;
+}
 
 /*
  * decode a X509 certificate and make a readable text terminated '\n'.
@@ -850,9 +912,9 @@
     {
 	u_char *bp;
 
-	bp = (unsigned char *) cert->v;
+	bp = (unsigned char *) cert->v + 1;
 
-	x509 = d2i_X509(NULL, (void *)&bp, cert->l);
+	x509 = d2i_X509(NULL, (void *)&bp, cert->l - 1);
     }
 #else
     {
@@ -862,7 +924,7 @@
 	bio = BIO_new(BIO_s_mem());
 	if (bio == NULL)
 		return NULL;
-	len = BIO_write(bio, cert->v, cert->l);
+	len = BIO_write(bio, cert->v + 1, cert->l - 1);
 	if (len == -1)
 		return NULL;
 	x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
@@ -912,12 +974,13 @@
 		return NULL;
 
 	len = i2d_X509(x509, NULL);
-	cert = vmalloc(len);
+	cert = vmalloc(len + 1);
 	if (cert == NULL) {
 		X509_free(x509);
 		return NULL;
 	}
-	bp = (unsigned char *) cert->v;
+	cert->v[0] = ISAKMP_CERT_X509SIGN;
+	bp = (unsigned char *) &cert->v[1];
 	error = i2d_X509(x509, &bp);
 	X509_free(x509);
 
@@ -943,17 +1006,12 @@
 	vchar_t *cert;
 {
 	X509 *x509;
-	u_char *bp;
 	EVP_PKEY *evp;
 	int res;
 
-	bp = (unsigned char *) cert->v;
-
-	x509 = d2i_X509(NULL, (void *)&bp, cert->l);
-	if (x509 == NULL) {
-		plog(LLV_ERROR, LOCATION, NULL, "d2i_X509(): %s\n", eay_strerror());
+	x509 = mem2x509(cert);
+	if (x509 == NULL)
 		return -1;
-	}
 
 	evp = X509_get_pubkey(x509);
 	if (! evp) {
@@ -1807,6 +1865,42 @@
 	return (caddr_t)c;
 }
 
+static vchar_t *eay_hmac_one(key, data, type)
+	vchar_t *key, *data;
+	const EVP_MD *type;
+{
+	vchar_t *res;
+
+	if ((res = vmalloc(EVP_MD_size(type))) == 0)
+		return NULL;
+
+	if (!HMAC(type, (void *) key->v, key->l,
+		  (void *) data->v, data->l, (void *) res->v, NULL)) {
+		vfree(res);
+		return NULL;
+	}
+
+	return res;
+}
+
+static vchar_t *eay_digest_one(data, type)
+	vchar_t *data;
+	const EVP_MD *type;
+{
+	vchar_t *res;
+
+	if ((res = vmalloc(EVP_MD_size(type))) == 0)
+		return NULL;
+
+	if (!EVP_Digest((void *) data->v, data->l,
+			(void *) res->v, NULL, type, NULL)) {
+		vfree(res);
+		return NULL;
+	}
+
+	return res;
+}
+
 #ifdef WITH_SHA2
 /*
  * HMAC SHA2-512
@@ -1815,14 +1909,7 @@
 eay_hmacsha2_512_one(key, data)
 	vchar_t *key, *data;
 {
-	vchar_t *res;
-	caddr_t ctx;
-
-	ctx = eay_hmacsha2_512_init(key);
-	eay_hmacsha2_512_update(ctx, data);
-	res = eay_hmacsha2_512_final(ctx);
-
-	return(res);
+	return eay_hmac_one(key, data, EVP_sha2_512());
 }
 
 caddr_t
@@ -1872,14 +1959,7 @@
 eay_hmacsha2_384_one(key, data)
 	vchar_t *key, *data;
 {
-	vchar_t *res;
-	caddr_t ctx;
-
-	ctx = eay_hmacsha2_384_init(key);
-	eay_hmacsha2_384_update(ctx, data);
-	res = eay_hmacsha2_384_final(ctx);
-
-	return(res);
+	return eay_hmac_one(key, data, EVP_sha2_384());
 }
 
 caddr_t
@@ -1929,14 +2009,7 @@
 eay_hmacsha2_256_one(key, data)
 	vchar_t *key, *data;
 {
-	vchar_t *res;
-	caddr_t ctx;
-
-	ctx = eay_hmacsha2_256_init(key);
-	eay_hmacsha2_256_update(ctx, data);
-	res = eay_hmacsha2_256_final(ctx);
-
-	return(res);
+	return eay_hmac_one(key, data, EVP_sha2_256());
 }
 
 caddr_t
@@ -1987,14 +2060,7 @@
 eay_hmacsha1_one(key, data)
 	vchar_t *key, *data;
 {
-	vchar_t *res;
-	caddr_t ctx;
-
-	ctx = eay_hmacsha1_init(key);
-	eay_hmacsha1_update(ctx, data);
-	res = eay_hmacsha1_final(ctx);
-
-	return(res);
+	return eay_hmac_one(key, data, EVP_sha1());
 }
 
 caddr_t
@@ -2044,14 +2110,7 @@
 eay_hmacmd5_one(key, data)
 	vchar_t *key, *data;
 {
-	vchar_t *res;
-	caddr_t ctx;
-
-	ctx = eay_hmacmd5_init(key);
-	eay_hmacmd5_update(ctx, data);
-	res = eay_hmacmd5_final(ctx);
-
-	return(res);
+	return eay_hmac_one(key, data, EVP_md5());
 }
 
 caddr_t
@@ -2137,14 +2196,7 @@
 eay_sha2_512_one(data)
 	vchar_t *data;
 {
-	caddr_t ctx;
-	vchar_t *res;
-
-	ctx = eay_sha2_512_init();
-	eay_sha2_512_update(ctx, data);
-	res = eay_sha2_512_final(ctx);
-
-	return(res);
+	return eay_digest_one(data, EVP_sha512());
 }
 
 int
@@ -2197,14 +2249,7 @@
 eay_sha2_384_one(data)
 	vchar_t *data;
 {
-	caddr_t ctx;
-	vchar_t *res;
-
-	ctx = eay_sha2_384_init();
-	eay_sha2_384_update(ctx, data);
-	res = eay_sha2_384_final(ctx);
-
-	return(res);
+	return eay_digest_one(data, EVP_sha2_384());
 }
 
 int
@@ -2257,14 +2302,7 @@
 eay_sha2_256_one(data)
 	vchar_t *data;
 {
-	caddr_t ctx;
-	vchar_t *res;
-
-	ctx = eay_sha2_256_init();
-	eay_sha2_256_update(ctx, data);
-	res = eay_sha2_256_final(ctx);
-
-	return(res);
+	return eay_digest_one(data, EVP_sha2_256());
 }
 
 int
@@ -2316,14 +2354,7 @@
 eay_sha1_one(data)
 	vchar_t *data;
 {
-	caddr_t ctx;
-	vchar_t *res;
-
-	ctx = eay_sha1_init();
-	eay_sha1_update(ctx, data);
-	res = eay_sha1_final(ctx);
-
-	return(res);
+	return eay_digest_one(data, EVP_sha1());
 }
 
 int
@@ -2374,14 +2405,7 @@
 eay_md5_one(data)
 	vchar_t *data;
 {
-	caddr_t ctx;
-	vchar_t *res;
-
-	ctx = eay_md5_init();
-	eay_md5_update(ctx, data);
-	res = eay_md5_final(ctx);
-
-	return(res);
+	return eay_digest_one(data, EVP_md5());
 }
 
 int
diff --git a/src/racoon/crypto_openssl.h b/src/racoon/crypto_openssl.h
index 9a17de8..66fac73 100644
--- a/src/racoon/crypto_openssl.h
+++ b/src/racoon/crypto_openssl.h
@@ -1,4 +1,4 @@
-/*	$NetBSD: crypto_openssl.h,v 1.5 2006/10/06 12:02:27 manu Exp $	*/
+/*	$NetBSD: crypto_openssl.h,v 1.7 2009/08/17 11:59:10 vanhu Exp $	*/
 
 /* Id: crypto_openssl.h,v 1.11 2004/11/13 11:28:01 manubsd Exp */
 
@@ -34,8 +34,6 @@
 #ifndef _CRYPTO_OPENSSL_H
 #define _CRYPTO_OPENSSL_H
 
-#include "crypto_openssl.h"
-
 #include <openssl/x509v3.h>
 #include <openssl/rsa.h>
 
@@ -55,6 +53,7 @@
 extern int eay_check_x509cert __P((vchar_t *, char *, char *, int));
 extern vchar_t *eay_get_x509asn1subjectname __P((vchar_t *));
 extern int eay_get_x509subjectaltname __P((vchar_t *, char **, int *, int));
+extern vchar_t * eay_get_x509asn1issuername __P((vchar_t *));
 extern char *eay_get_x509text __P((vchar_t *));
 extern vchar_t *eay_get_x509cert __P((char *));
 extern vchar_t *eay_get_x509sign __P((vchar_t *, vchar_t *));
diff --git a/src/racoon/debug.h b/src/racoon/debug.h
index 47c2641..4270b6a 100644
--- a/src/racoon/debug.h
+++ b/src/racoon/debug.h
@@ -1,4 +1,4 @@
-/*	$NetBSD: debug.h,v 1.4 2006/09/09 16:22:09 manu Exp $	*/
+/*	$NetBSD: debug.h,v 1.5 2008/12/23 14:03:12 tteras Exp $	*/
 
 /* Id: debug.h,v 1.3 2004/06/11 16:00:16 ludvigm Exp */
 
@@ -37,5 +37,6 @@
 /* define by main.c */
 extern int f_local;
 extern int vflag;
+extern int dump_config;
 
 #endif /* _DEBUG_H */
diff --git a/src/racoon/dnssec.c b/src/racoon/dnssec.c
index 1fc0bd1..d52a243 100644
--- a/src/racoon/dnssec.c
+++ b/src/racoon/dnssec.c
@@ -1,4 +1,4 @@
-/*	$NetBSD: dnssec.c,v 1.4 2006/09/09 16:22:09 manu Exp $	*/
+/*	$NetBSD: dnssec.c,v 1.5 2009/03/12 10:57:26 tteras Exp $	*/
 
 /*	$KAME: dnssec.c,v 1.2 2001/08/05 18:46:07 itojun Exp $	*/
 
@@ -55,11 +55,11 @@
 
 extern int h_errno;
 
-cert_t *
+vchar_t *
 dnssec_getcert(id)
 	vchar_t *id;
 {
-	cert_t *cert = NULL;
+	vchar_t *cert = NULL;
 	struct certinfo *res = NULL;
 	struct ipsecdoi_id_b *id_b;
 	int type;
@@ -116,39 +116,22 @@
 	}
 
 	/* create cert holder */
-	cert = oakley_newcert();
+	cert = vmalloc(res->ci_certlen + 1);
 	if (cert == NULL) {
 		plog(LLV_ERROR, LOCATION, NULL,
 			"failed to get cert buffer.\n");
 		goto err;
 	}
-	cert->pl = vmalloc(res->ci_certlen + 1);
-	if (cert->pl == NULL) {
-		plog(LLV_ERROR, LOCATION, NULL,
-			"failed to get cert buffer.\n");
-		goto err;
-	}
-	memcpy(cert->pl->v + 1, res->ci_cert, res->ci_certlen);
-	cert->pl->v[0] = type;
-	cert->cert.v = cert->pl->v + 1;
-	cert->cert.l = cert->pl->l - 1;
+	cert->v[0] = type;
+	memcpy(&cert->v[1], res->ci_cert, res->ci_certlen);
 
 	plog(LLV_DEBUG, LOCATION, NULL, "created CERT payload:\n");
-	plogdump(LLV_DEBUG, cert->pl->v, cert->pl->l);
-
-end:
-	if (res)
-		freecertinfo(res);
-
-	return cert;
+	plogdump(LLV_DEBUG, cert->v, cert->l);
 
 err:
 	if (name)
 		racoon_free(name);
-	if (cert) {
-		oakley_delcert(cert);
-		cert = NULL;
-	}
-
-	goto end;
+	if (res)
+		freecertinfo(res);
+	return cert;
 }
diff --git a/src/racoon/dnssec.h b/src/racoon/dnssec.h
index fb1c931..1a03d77 100644
--- a/src/racoon/dnssec.h
+++ b/src/racoon/dnssec.h
@@ -1,4 +1,4 @@
-/*	$NetBSD: dnssec.h,v 1.4 2006/09/09 16:22:09 manu Exp $	*/
+/*	$NetBSD: dnssec.h,v 1.5 2009/03/12 10:57:26 tteras Exp $	*/
 
 /* Id: dnssec.h,v 1.3 2004/06/11 16:00:16 ludvigm Exp */
 
@@ -34,6 +34,6 @@
 #ifndef _DNSSEC_H
 #define _DNSSEC_H
 
-extern cert_t *dnssec_getcert __P((vchar_t *));
+extern vchar_t *dnssec_getcert __P((vchar_t *));
 
 #endif /* _DNSSEC_H */
diff --git a/src/racoon/doc/FAQ b/src/racoon/doc/FAQ
index 0ab49f0..cf9c394 100644
--- a/src/racoon/doc/FAQ
+++ b/src/racoon/doc/FAQ
@@ -18,7 +18,7 @@
 
 A:
 	Configure both ends exactly the same.  With just a tiny little
-	differnce, you will be in trouble.
+	difference, you will be in trouble.
 
 Q: How to build racoon on my platform?
 
@@ -109,6 +109,6 @@
 Q: Other documents to look at?
 
 A:
-	http://www.netbsd.org/Documentation/network/ipsec/
+	http://www.NetBSD.org/docs/network/ipsec/
 	http://www.kame.net/
 	http://www.kame.net/newsletter/
diff --git a/src/racoon/doc/README.privsep b/src/racoon/doc/README.privsep
new file mode 100644
index 0000000..e01c820
--- /dev/null
+++ b/src/racoon/doc/README.privsep
@@ -0,0 +1,152 @@
+		Using Racoon with Privilege Separation
+		     Tue Mar 25 16:37:09 MDT 2008
+
+
+Racoon can run in a chroot'd environment.  When so instructed, it runs as two
+processes, one of which handles a small number of simple requests and runs as
+root in the full native filesystem, and another which runs as a less
+privileged user in a chroot'd environment and which handles all the other and
+very complex business of racoon.
+
+Because racoon does many complex things there are many opportunities for
+coding errors to lead to compromises and so this separation is important.  If
+someone breaks into your system using racoon and you have enabled privilege
+separation, they will find themselves in a very limited environment and unable
+to do much damage.  They may be able to alter the host's security associations
+or obtain the private keys stored on that system using file descriptors
+available to the unprivileged instance of racoon, and from there they will be
+able to alter security associations on other hosts in disruptive or dangerous
+ways if you have generate_policy enabled on those hosts.  But that's because
+in its current form generate_policy is itself dangerous and requires that you
+trust anyone with the credentials to use it.
+
+They will also be able to execute any scripts you have placed in the scripts
+directory, although racoon will prevent them from mis-using the traditional
+environment variables PATH, LD_LIBRARY_PATH, and IFS.  But if you have
+introduced vulnerabilities into your scripts you may want to re-visit them.
+The thing to watch for is blindly trusting the environment variables passed
+in by racoon - assume they could be set to anything by a malicious entity and
+check them for suitability before using them.
+
+All these possibilities are present when privilege separation is not enabled,
+and they are greatly reduced when it is enabled because the resources
+available to the attacker are less.
+
+*****
+
+The basic concept with racoon's privilege separation is that a minimal
+environment containing all the files racoon needs to operate - with the
+exception of private keys, scripts, and system-wide authentication services -
+is placed in a stripped-down copy of the original environment.  The private
+keys and scripts are left in the original environment where only the
+privileged instance of racoon will have access to them.
+
+Here are basic instructions for setting up racoon to run with privilege
+separation:
+
+
+First, create a user/group for racoon to run under.  For example, user:group
+ike:ike.  The account should not have a usable password or real home
+directory, so copy the general format of another system-services type account
+such as 'daemon'.
+
+You already have files in, e.g. /usr/local/etc/racoon - perhaps racoon.conf, a
+certs directory containing certificates, a scripts directory, and other
+miscellaneous files such as welcome messages.  Perform the following steps:
+
+cd /usr/local/etc/racoon
+mkdir root
+mv certs root
+mkdir certs
+mv root/certs/*.key certs
+
+If you want to be able to switch back and forth between using and not using
+privsep, do this too:
+
+cd /usr/local/etc/racoon/certs
+for i in ../root/certs/*
+do
+	ln -s $i .
+done
+
+Now root/certs contains certificates and certs contains the keys.  The idea is
+that the public certificates are in the chroot'd area
+(/usr/local/etc/racoon/root) and the keys are available only to the privileged
+instance of racoon.
+
+Move any other racoon configuration data into /usr/local/etc/racoon/root,
+with the exception of the scripts directory and racoon.conf.
+
+All the files in /usr/local/etc/racoon/root should be owned by root and the
+ike:ike user you created should not have write access to any directories or
+files (unless you are using something like 'path backupsa', but you get the
+idea).
+
+Create the device nodes:
+
+mkdir root/dev
+
+Do whatever your OS requires to populate the new dev directory with a
+minimal set of devices, e.g. mknod, MAKEDEV, or mount devfs...  In freebsd
+this is done by adding a line to /etc/fstab:
+
+devfs	/usr/local/etc/racoon/root/dev	devfs	rw		0	0
+
+and then adding a line like this to /etc/rc.conf:
+
+devfs_set_rulesets="/usr/local/etc/racoon/root/dev=devfsrules_basic"
+
+and then adding the following lines to /etc/devfs.rules:
+
+[devfsrules_basic=10]
+add include $devfsrules_hide_all
+add include $devfsrules_unhide_basic
+
+and then either rebooting or entering "mount -a && /etc/rc.d/devfs start".
+
+When done with that:
+
+mkdir -p root/usr/local/etc
+ln -s ../../../ root/usr/local/etc/racoon
+
+This dummy hierarchy keeps the config file consistent between both copies of
+racoon. Of course, you could actually put the certs directory and any other
+configuration data down in the hierarchy but I prefer to leave it at the root
+and link to it as shown.  You may end up with something like this:
+
+root# ls -FC /usr/local/etc/racoon/root
+certs/	dev/	usr/
+
+root# ls -l /usr/local/etc/racoon/root/usr/local/etc
+lrwxr-xr-x  1 root  wheel  9 Mar  7 22:13 racoon -> ../../../
+
+root# ls -FC /usr/local/etc/racoon/root/usr/local/etc/racoon/
+certs/	dev/	usr/
+
+Presumably your racoon.conf already contains something like:
+
+path certificate "/usr/local/etc/racoon/certs";
+path script "/usr/local/etc/racoon/scripts";
+
+If so, great. If not, add them. Then, finally, add the privsep section:
+
+privsep {
+	user "ike";
+	group "ike";
+	chroot "/usr/local/etc/racoon/root";
+}
+
+Apply the patches posted to the list and rebuild racoon (the patches will be
+incorporated into the release subsequent to the date of this memo, so if you
+use that or a later release you can skip this step).
+
+Restart racoon and hopefully things will work.  As of the date of this memo,
+re-loading the configuration file with racoonctl will not work with privsep
+enabled.  However, the problem is not insurmountable and if you figure it out
+let us know.
+
+I have not tested privsep with many of racoon's features such as XAUTH or
+scripts, so if you have trouble with them and work anything out please reply
+to the list so that your discoveries may be incorporated into this document.
+
+Last modified: $Date: 2008/03/28 04:18:52 $
diff --git a/src/racoon/eaytest.c b/src/racoon/eaytest.c
index 323ecef..1474bdc 100644
--- a/src/racoon/eaytest.c
+++ b/src/racoon/eaytest.c
@@ -1,4 +1,4 @@
-/*	$NetBSD: eaytest.c,v 1.7.6.2 2008/07/15 00:55:48 mgrooms Exp $	*/
+/*	$NetBSD: eaytest.c,v 1.10 2010/01/17 23:02:48 wiz Exp $	*/
 
 /* Id: eaytest.c,v 1.22 2005/06/19 18:02:54 manubsd Exp */
 
@@ -572,6 +572,7 @@
 
 		n++;
 	}
+	closedir(dirp);
 
 	p = (char **)realloc(certs, (n + 1) * sizeof(certs));
 	if (p == NULL)
diff --git a/src/racoon/evt.c b/src/racoon/evt.c
index fc65b20..11d9695 100644
--- a/src/racoon/evt.c
+++ b/src/racoon/evt.c
@@ -1,9 +1,10 @@
-/*	$NetBSD: evt.c,v 1.5 2006/09/09 16:22:09 manu Exp $	*/
+/*	$NetBSD: evt.c,v 1.10 2010/10/21 06:15:28 tteras Exp $	*/
 
 /* Id: evt.c,v 1.5 2006/06/22 20:11:35 manubsd Exp */
 
 /*
  * Copyright (C) 2004 Emmanuel Dreyfus
+ * Copyright (C) 2008 Timo Teras
  * All rights reserved.
  * 
  * Redistribution and use in source and binary forms, with or without
@@ -46,14 +47,55 @@
 #include "plog.h"
 #include "misc.h"
 #include "admin.h"
+#include "handler.h"
+#include "session.h"
 #include "gcmalloc.h"
 #include "evt.h"
+#include "var.h"
 
 #ifdef ENABLE_ADMINPORT
-struct evtlist evtlist = TAILQ_HEAD_INITIALIZER(evtlist);
-int evtlist_len = 0;
 
-void
+static EVT_LISTENER_LIST(evt_listeners);
+
+struct evt_message {
+	struct admin_com adm;
+	struct evt_async evt;
+};
+
+struct evt {
+	struct evtdump *dump;
+	TAILQ_ENTRY(evt) next;
+};
+
+TAILQ_HEAD(evtlist, evt);
+
+#define EVTLIST_MAX	32
+
+static struct evtlist evtlist = TAILQ_HEAD_INITIALIZER(evtlist);
+static int evtlist_len = 0;
+static int evtlist_inuse = 0;
+
+static struct {
+	int newtype, oldtype;
+} evttype_map[] = {
+	{ EVT_RACOON_QUIT,		EVTT_RACOON_QUIT },
+	{ EVT_PHASE1_UP,		EVTT_PHASE1_UP },
+	{ EVT_PHASE1_DOWN,		EVTT_PHASE1_DOWN },
+	{ EVT_PHASE1_NO_RESPONSE,	EVTT_PEER_NO_RESPONSE },
+	{ EVT_PHASE1_NO_PROPOSAL,	EVTT_PEERPH1_NOPROP },
+	{ EVT_PHASE1_AUTH_FAILED,	EVTT_PEERPH1AUTH_FAILED },
+	{ EVT_PHASE1_DPD_TIMEOUT,	EVTT_DPD_TIMEOUT },
+	{ EVT_PHASE1_PEER_DELETED,	EVTT_PEER_DELETE },
+	{ EVT_PHASE1_MODE_CFG,		EVTT_ISAKMP_CFG_DONE },
+	{ EVT_PHASE1_XAUTH_SUCCESS,	EVTT_XAUTH_SUCCESS },
+	{ EVT_PHASE1_XAUTH_FAILED,	EVTT_XAUTH_FAILED },
+	{ EVT_PHASE2_NO_PHASE1,		-1 },
+	{ EVT_PHASE2_UP,		EVTT_PHASE2_UP },
+	{ EVT_PHASE2_DOWN,		EVTT_PHASE2_DOWN },
+	{ EVT_PHASE2_NO_RESPONSE,	EVTT_PEER_NO_RESPONSE },
+};
+
+static void
 evt_push(src, dst, type, optdata)
 	struct sockaddr *src;
 	struct sockaddr *dst;
@@ -63,9 +105,21 @@
 	struct evtdump *evtdump;
 	struct evt *evt;
 	size_t len;
+	int i;
 
 	/* If admin socket is disabled, silently discard anything */
-	if (adminsock_path == NULL)
+	if (adminsock_path == NULL || !evtlist_inuse)
+		return;
+
+	/* Map the event type to old */
+	for (i = 0; i < sizeof(evttype_map) / sizeof(evttype_map[0]); i++)
+		if (evttype_map[i].newtype == type)
+			break;
+	if (i >= sizeof(evttype_map) / sizeof(evttype_map[0]))
+		return;
+
+	type = evttype_map[i].oldtype;
+	if (type < 0)
 		return;
 
 	/* If we are above the limit, don't record anything */
@@ -121,7 +175,7 @@
 	return;
 }
 
-struct evtdump *
+static struct evtdump *
 evt_pop(void) {
 	struct evtdump *evtdump;
 	struct evt *evt;
@@ -142,6 +196,12 @@
 	struct evtdump *evtdump;
 	vchar_t *buf = NULL;
 
+	if (!evtlist_inuse) {
+		evtlist_inuse = 1;
+		plog(LLV_ERROR, LOCATION, NULL,
+		     "evt_dump: deprecated event polling used\n");
+	}
+
 	if ((evtdump = evt_pop()) != NULL) {
 		if ((buf = vmalloc(evtdump->len)) == NULL) {
 			plog(LLV_ERROR, LOCATION, NULL, 
@@ -155,4 +215,185 @@
 	return buf;
 }
 
+static struct evt_message *
+evtmsg_create(type, optdata)
+	int type;
+	vchar_t *optdata;
+{
+	struct evt_message *e;
+	size_t len;
+
+	len = sizeof(struct evt_message);
+	if (optdata != NULL)
+		len += optdata->l;
+
+	if ((e = racoon_malloc(len)) == NULL) {
+		plog(LLV_ERROR, LOCATION, NULL, "Cannot allocate event: %s\n",
+		     strerror(errno));
+		return NULL;
+	}
+
+	memset(e, 0, sizeof(struct evt_message));
+	e->adm.ac_len = len;
+	e->adm.ac_cmd = ADMIN_SHOW_EVT;
+	e->adm.ac_errno = 0;
+	e->adm.ac_proto = 0;
+	e->evt.ec_type = type;
+	time(&e->evt.ec_timestamp);
+	if (optdata != NULL)
+		memcpy(e + 1, optdata->v, optdata->l);
+
+	return e;
+}
+
+static void
+evt_unsubscribe(l)
+	struct evt_listener *l;
+{
+	plog(LLV_DEBUG, LOCATION, NULL,
+	     "[%d] admin connection released\n", l->fd);
+
+	LIST_REMOVE(l, ll_chain);
+	unmonitor_fd(l->fd);
+	close(l->fd);
+	racoon_free(l);
+}
+
+static int
+evt_unsubscribe_cb(ctx, fd)
+	void *ctx;
+	int fd;
+{
+	evt_unsubscribe((struct evt_listener *) ctx);
+	return 0;
+}
+
+static void
+evtmsg_broadcast(ll, e)
+	const struct evt_listener_list *ll;
+	struct evt_message *e;
+{
+	struct evt_listener *l, *nl;
+
+	for (l = LIST_FIRST(ll); l != NULL; l = nl) {
+		nl = LIST_NEXT(l, ll_chain);
+
+		if (send(l->fd, e, e->adm.ac_len, MSG_DONTWAIT) < 0) {
+			plog(LLV_DEBUG, LOCATION, NULL, "Cannot send event to fd: %s\n",
+				strerror(errno));
+			evt_unsubscribe(l);
+		}
+	}
+}
+
+void
+evt_generic(type, optdata)
+	int type;
+	vchar_t *optdata;
+{
+	struct evt_message *e;
+
+	if ((e = evtmsg_create(type, optdata)) == NULL)
+		return;
+
+	evtmsg_broadcast(&evt_listeners, e);
+	evt_push(&e->evt.ec_ph1src, &e->evt.ec_ph1dst, type, optdata);
+
+	racoon_free(e);
+}
+
+void
+evt_phase1(ph1, type, optdata)
+	const struct ph1handle *ph1;
+	int type;
+	vchar_t *optdata;
+{
+	struct evt_message *e;
+
+	if ((e = evtmsg_create(type, optdata)) == NULL)
+		return;
+
+	if (ph1->local)
+		memcpy(&e->evt.ec_ph1src, ph1->local, sysdep_sa_len(ph1->local));
+	if (ph1->remote)
+		memcpy(&e->evt.ec_ph1dst, ph1->remote, sysdep_sa_len(ph1->remote));
+
+	evtmsg_broadcast(&ph1->evt_listeners, e);
+	evtmsg_broadcast(&evt_listeners, e);
+	evt_push(&e->evt.ec_ph1src, &e->evt.ec_ph1dst, type, optdata);
+
+	racoon_free(e);
+}
+
+void
+evt_phase2(ph2, type, optdata)
+	const struct ph2handle *ph2;
+	int type;
+	vchar_t *optdata;
+{
+	struct evt_message *e;
+	struct ph1handle *ph1 = ph2->ph1;
+
+	if ((e = evtmsg_create(type, optdata)) == NULL)
+		return;
+
+	if (ph1) {
+		if (ph1->local)
+			memcpy(&e->evt.ec_ph1src, ph1->local, sysdep_sa_len(ph1->local));
+		if (ph1->remote)
+			memcpy(&e->evt.ec_ph1dst, ph1->remote, sysdep_sa_len(ph1->remote));
+	}
+	e->evt.ec_ph2msgid = ph2->msgid;
+
+	evtmsg_broadcast(&ph2->evt_listeners, e);
+	if (ph1)
+		evtmsg_broadcast(&ph1->evt_listeners, e);
+	evtmsg_broadcast(&evt_listeners, e);
+	evt_push(&e->evt.ec_ph1src, &e->evt.ec_ph1dst, type, optdata);
+
+	racoon_free(e);
+}
+
+int
+evt_subscribe(list, fd)
+	struct evt_listener_list *list;
+	int fd;
+{
+	struct evt_listener *l;
+
+	if ((l = racoon_malloc(sizeof(*l))) == NULL) {
+		plog(LLV_ERROR, LOCATION, NULL,
+		     "Cannot allocate event listener: %s\n",
+		     strerror(errno));
+		return errno;
+	}
+
+	if (list == NULL)
+		list = &evt_listeners;
+
+	LIST_INSERT_HEAD(list, l, ll_chain);
+	l->fd = fd;
+	monitor_fd(l->fd, evt_unsubscribe_cb, l, 0);
+
+	plog(LLV_DEBUG, LOCATION, NULL,
+	     "[%d] admin connection is polling events\n", fd);
+
+	return -2;
+}
+
+void
+evt_list_init(list)
+	struct evt_listener_list *list;
+{
+	LIST_INIT(list);
+}
+
+void
+evt_list_cleanup(list)
+	struct evt_listener_list *list;
+{
+	while (!LIST_EMPTY(list))
+		evt_unsubscribe(LIST_FIRST(list));
+}
+
 #endif /* ENABLE_ADMINPORT */
diff --git a/src/racoon/evt.h b/src/racoon/evt.h
index 88ee366..42e14d7 100644
--- a/src/racoon/evt.h
+++ b/src/racoon/evt.h
@@ -1,9 +1,10 @@
-/*	$NetBSD: evt.h,v 1.4 2006/09/09 16:22:09 manu Exp $	*/
+/*	$NetBSD: evt.h,v 1.7 2008/12/23 14:03:12 tteras Exp $	*/
 
 /* Id: evt.h,v 1.5 2006/01/19 10:24:09 fredsen Exp */
 
 /*
  * Copyright (C) 2004 Emmanuel Dreyfus
+ * Copyright (C) 2008 Timo Teras
  * All rights reserved.
  * 
  * Redistribution and use in source and binary forms, with or without
@@ -34,6 +35,10 @@
 #ifndef _EVT_H
 #define _EVT_H
 
+/*
+ * Old style (deprecated) events which are polled.
+ */
+
 struct evtdump {
 	size_t len;	
 	struct sockaddr_storage src;
@@ -64,25 +69,78 @@
 #define EVTT_PEERPH1_NOPROP	14	/* NO_PROPOSAL_CHOSEN & friends */
 #define EVTT_NO_ISAKMP_CFG	15	/* no need to wait for mode_cfg */
 
-struct evt {
-	struct evtdump *dump;
-	TAILQ_ENTRY(evt) next;
+/*
+ * New style, asynchronous events.
+ */
+
+struct evt_async {
+	uint32_t ec_type;
+	time_t ec_timestamp;
+
+	struct sockaddr_storage ec_ph1src;
+	struct sockaddr_storage ec_ph1dst;
+	u_int32_t ec_ph2msgid;
+
+	/*
+	 * Optionnal list of struct isakmp_data
+	 * for type EVTT_ISAKMP_CFG_DONE
+	 */
 };
 
-TAILQ_HEAD(evtlist, evt);
+/* type */
+#define EVT_RACOON_QUIT			0x0001
 
-#define EVTLIST_MAX	32
+#define EVT_PHASE1_UP			0x0100
+#define EVT_PHASE1_DOWN			0x0101
+#define EVT_PHASE1_NO_RESPONSE		0x0102
+#define EVT_PHASE1_NO_PROPOSAL		0x0103
+#define EVT_PHASE1_AUTH_FAILED		0x0104
+#define EVT_PHASE1_DPD_TIMEOUT		0x0105
+#define EVT_PHASE1_PEER_DELETED		0x0106
+#define EVT_PHASE1_MODE_CFG		0x0107
+#define EVT_PHASE1_XAUTH_SUCCESS	0x0108
+#define EVT_PHASE1_XAUTH_FAILED		0x0109
+
+#define EVT_PHASE2_NO_PHASE1		0x0200
+#define EVT_PHASE2_UP			0x0201
+#define EVT_PHASE2_DOWN			0x0202
+#define EVT_PHASE2_NO_RESPONSE		0x0203
 
 #ifdef ENABLE_ADMINPORT
-struct evtdump *evt_pop(void);
-vchar_t *evt_dump(void);
-void evt_push(struct sockaddr *, struct sockaddr *, int, vchar_t *);
-#endif
 
-#ifdef ENABLE_ADMINPORT
-#define EVT_PUSH(src, dst, type, optdata) evt_push(src, dst, type, optdata);
+struct ph1handle;
+struct ph2handle;
+
+struct evt_listener {
+	LIST_ENTRY(evt_listener) ll_chain;
+	int fd;
+};
+LIST_HEAD(evt_listener_list, evt_listener);
+#define EVT_LISTENER_LIST(x) struct evt_listener_list x
+
+void evt_generic __P((int type, vchar_t *optdata));
+void evt_phase1 __P((const struct ph1handle *ph1, int type, vchar_t *optdata));
+void evt_phase2 __P((const struct ph2handle *ph2, int type, vchar_t *optdata));
+vchar_t *evt_dump __P((void));
+
+int  evt_subscribe __P((struct evt_listener_list *list, int fd));
+void evt_list_init __P((struct evt_listener_list *list));
+void evt_list_cleanup __P((struct evt_listener_list *list));
+
 #else
-#define EVT_PUSH(src, dst, type, optdata) ;
-#endif
+
+#define EVT_LISTENER_LIST(x)
+
+#define evt_generic(type, optdata) ;
+#define evt_phase1(ph1, type, optdata) ;
+#define evt_phase2(ph2, type, optdata) ;
+
+#define evt_subscribe(eventlist, fd) ;
+#define evt_list_init(eventlist) ;
+#define evt_list_cleanup(eventlist) ;
+#define evt_get_fdmask(nfds, fdset) nfds
+#define evt_handle_fdmask(fdset) ;
+
+#endif /* ENABLE_ADMINPORT */
 
 #endif /* _EVT_H */
diff --git a/src/racoon/grabmyaddr.c b/src/racoon/grabmyaddr.c
index 8155001..29b913c 100644
--- a/src/racoon/grabmyaddr.c
+++ b/src/racoon/grabmyaddr.c
@@ -1,9 +1,7 @@
-/*	$NetBSD: grabmyaddr.c,v 1.4.6.3 2008/06/18 07:30:18 mgrooms Exp $	*/
-
-/* Id: grabmyaddr.c,v 1.27 2006/04/06 16:27:05 manubsd Exp */
-
+/*	$NetBSD: grabmyaddr.c,v 1.28 2011/03/14 17:18:12 tteras Exp $	*/
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * Copyright (C) 2008 Timo Teras <timo.teras@iki.fi>.
  * All rights reserved.
  * 
  * Redistribution and use in source and binary forms, with or without
@@ -33,40 +31,32 @@
 
 #include "config.h"
 
-#include <sys/types.h>
-#include <sys/param.h>
-#include <sys/socket.h>
-#include <sys/ioctl.h>
-
-#include <net/if.h>
-#if defined(__FreeBSD__) && __FreeBSD__ >= 3
-#include <net/if_var.h>
-#endif
-#if defined(__NetBSD__) || defined(__FreeBSD__) ||	\
-  (defined(__APPLE__) && defined(__MACH__))
-#include <netinet/in.h>
-#include <netinet6/in6_var.h>
-#endif
-#include <net/route.h>
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
 #include <errno.h>
-#ifdef HAVE_UNISTD_H
+#include <fcntl.h>
 #include <unistd.h>
-#endif
-#include <netdb.h>
-#ifdef HAVE_GETIFADDRS
-#include <ifaddrs.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+
+#ifdef __linux__
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#define USE_NETLINK
+#else
+#include <net/route.h>
 #include <net/if.h>
-#endif 
+#include <net/if_dl.h>
+#include <sys/sysctl.h>
+#define USE_ROUTE
+#endif
 
 #include "var.h"
 #include "misc.h"
 #include "vmbuf.h"
 #include "plog.h"
 #include "sockmisc.h"
+#include "session.h"
 #include "debug.h"
 
 #include "localconf.h"
@@ -77,841 +67,803 @@
 #include "gcmalloc.h"
 #include "nattraversal.h"
 
-#ifdef __linux__
-#include <linux/types.h>
-#include <linux/rtnetlink.h>
-#ifndef HAVE_GETIFADDRS
-#define HAVE_GETIFADDRS
-#define NEED_LINUX_GETIFADDRS
-#endif
-#endif
+static int kernel_receive __P((void *ctx, int fd));
+static int kernel_open_socket __P((void));
+static void kernel_sync __P((void));
 
-#ifndef HAVE_GETIFADDRS
-static unsigned int if_maxindex __P((void));
-#endif
-static struct myaddrs *find_myaddr __P((struct myaddrs *, struct myaddrs *));
-static int suitable_ifaddr __P((const char *, const struct sockaddr *));
-#ifdef INET6
-static int suitable_ifaddr6 __P((const char *, const struct sockaddr *));
-#endif
-
-#ifdef NEED_LINUX_GETIFADDRS
-
-/* We could do this _much_ better. kame racoon in its current form
- * will esentially die at frequent changes of address configuration.
- */
-
-struct ifaddrs
-{
-	struct ifaddrs *ifa_next;
-	char		ifa_name[16];
-	int		ifa_ifindex;
-	struct sockaddr *ifa_addr;
-	struct sockaddr_storage ifa_addrbuf;
+struct myaddr {
+	LIST_ENTRY(myaddr) chain;
+	struct sockaddr_storage addr;
+	int fd;
+	int udp_encap;
 };
 
-static int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
+static LIST_HEAD(_myaddr_list_, myaddr) configured, opened;
+
+static void
+myaddr_delete(my)
+	struct myaddr *my;
 {
+	if (my->fd != -1)
+		isakmp_close(my->fd);
+	LIST_REMOVE(my, chain);
+	racoon_free(my);
+}
+
+static int
+myaddr_configured(addr)
+	struct sockaddr *addr;
+{
+	struct myaddr *cfg;
+
+	if (LIST_EMPTY(&configured))
+		return TRUE;
+
+	LIST_FOREACH(cfg, &configured, chain) {
+		if (cmpsaddr(addr, (struct sockaddr *) &cfg->addr) <= CMPSADDR_WILDPORT_MATCH)
+			return TRUE;
+	}
+
+	return FALSE;
+}
+
+static int
+myaddr_open(addr, udp_encap)
+	struct sockaddr *addr;
+	int udp_encap;
+{
+	struct myaddr *my;
+
+	/* Already open? */
+	LIST_FOREACH(my, &opened, chain) {
+		if (cmpsaddr(addr, (struct sockaddr *) &my->addr) <= CMPSADDR_WILDPORT_MATCH)
+			return TRUE;
+	}
+
+	my = racoon_calloc(1, sizeof(struct myaddr));
+	if (my == NULL)
+		return FALSE;
+
+	memcpy(&my->addr, addr, sysdep_sa_len(addr));
+	my->fd = isakmp_open(addr, udp_encap);
+	if (my->fd < 0) {
+		racoon_free(my);
+		return FALSE;
+	}
+	my->udp_encap = udp_encap;
+	LIST_INSERT_HEAD(&opened, my, chain);
+	return TRUE;
+}
+
+static int
+myaddr_open_all_configured(addr)
+	struct sockaddr *addr;
+{
+	/* create all configured, not already opened addresses */
+	struct myaddr *cfg, *my;
+
+	if (addr != NULL) {
+		switch (addr->sa_family) {
+		case AF_INET:
+#ifdef INET6
+		case AF_INET6:
+#endif
+			break;
+		default:
+			return FALSE;
+		}
+	}
+
+	LIST_FOREACH(cfg, &configured, chain) {
+		if (addr != NULL &&
+		    cmpsaddr(addr, (struct sockaddr *) &cfg->addr) > CMPSADDR_WILDPORT_MATCH)
+			continue;
+		if (!myaddr_open((struct sockaddr *) &cfg->addr, cfg->udp_encap))
+			return FALSE;
+	}
+	if (LIST_EMPTY(&configured)) {
+#ifdef ENABLE_HYBRID
+		/* Exclude any address we got through ISAKMP mode config */
+		if (exclude_cfg_addr(addr) == 0)
+			return FALSE;
+#endif
+		set_port(addr, lcconf->port_isakmp);
+		myaddr_open(addr, FALSE);
+#ifdef ENABLE_NATT
+		set_port(addr, lcconf->port_isakmp_natt);
+		myaddr_open(addr, TRUE);
+#endif
+	}
+	return TRUE;
+}
+
+static void
+myaddr_close_all_open(addr)
+	struct sockaddr *addr;
+{
+	/* delete all matching open sockets */
+	struct myaddr *my, *next;
+
+	for (my = LIST_FIRST(&opened); my; my = next) {
+		next = LIST_NEXT(my, chain);
+
+		if (cmpsaddr((struct sockaddr *) addr,
+			     (struct sockaddr *) &my->addr)
+		    <= CMPSADDR_WOP_MATCH)
+			myaddr_delete(my);
+	}
+}
+
+static void
+myaddr_flush_list(list)
+	struct _myaddr_list_ *list;
+{
+	struct myaddr *my, *next;
+
+	for (my = LIST_FIRST(list); my; my = next) {
+		next = LIST_NEXT(my, chain);
+		myaddr_delete(my);
+	}
+}
+
+void
+myaddr_flush()
+{
+	myaddr_flush_list(&configured);
+}
+
+int
+myaddr_listen(addr, udp_encap)
+	struct sockaddr *addr;
+	int udp_encap;
+{
+	struct myaddr *my;
+
+	if (sysdep_sa_len(addr) > sizeof(my->addr)) {
+		plog(LLV_ERROR, LOCATION, NULL,
+		     "sockaddr size larger than sockaddr_storage\n");
+		return -1;
+	}
+
+	my = racoon_calloc(1, sizeof(struct myaddr));
+	if (my == NULL)
+		return -1;
+
+	memcpy(&my->addr, addr, sysdep_sa_len(addr));
+	my->udp_encap = udp_encap;
+	my->fd = -1;
+	LIST_INSERT_HEAD(&configured, my, chain);
+
+	return 0;
+}
+
+void
+myaddr_sync()
+{
+	struct myaddr *my, *next;
+
+	if (!lcconf->strict_address) {
+		kernel_sync();
+
+		/* delete all existing listeners which are not configured */
+		for (my = LIST_FIRST(&opened); my; my = next) {
+			next = LIST_NEXT(my, chain);
+
+			if (!myaddr_configured((struct sockaddr *) &my->addr))
+				myaddr_delete(my);
+		}
+	}
+}
+
+int
+myaddr_getfd(addr)
+        struct sockaddr *addr;
+{
+	struct myaddr *my;
+
+	LIST_FOREACH(my, &opened, chain) {
+		if (cmpsaddr((struct sockaddr *) &my->addr, addr) <= CMPSADDR_WILDPORT_MATCH)
+			return my->fd;
+	}
+
+	return -1;
+}
+
+int
+myaddr_getsport(addr)
+	struct sockaddr *addr;
+{
+	struct myaddr *my;
+
+	LIST_FOREACH(my, &opened, chain) {
+		if (cmpsaddr((struct sockaddr *) &my->addr, addr) <= CMPSADDR_WILDPORT_MATCH)
+			return extract_port((struct sockaddr *) &my->addr);
+	}
+
+	return PORT_ISAKMP;
+}
+
+void
+myaddr_init_lists()
+{
+	LIST_INIT(&configured);
+	LIST_INIT(&opened);
+}
+
+int
+myaddr_init()
+{
+        if (!lcconf->strict_address) {
+		lcconf->rtsock = kernel_open_socket();
+		if (lcconf->rtsock < 0)
+			return -1;
+		monitor_fd(lcconf->rtsock, kernel_receive, NULL, 0);
+	} else {
+		lcconf->rtsock = -1;
+		if (!myaddr_open_all_configured(NULL))
+			return -1;
+	}
+	return 0;
+}
+
+void
+myaddr_close()
+{
+	myaddr_flush_list(&configured);
+	myaddr_flush_list(&opened);
+	if (lcconf->rtsock != -1) {
+		unmonitor_fd(lcconf->rtsock);
+		close(lcconf->rtsock);
+	}
+}
+
+#if defined(USE_NETLINK)
+
+static int netlink_fd = -1;
+
+#define NLMSG_TAIL(nmsg) \
+	((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
+
+static void
+parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
+{
+	memset(tb, 0, sizeof(struct rtattr *) * (max + 1));
 	while (RTA_OK(rta, len)) {
 		if (rta->rta_type <= max)
 			tb[rta->rta_type] = rta;
 		rta = RTA_NEXT(rta,len);
 	}
-	return 0;
 }
 
-static void recvaddrs(int fd, struct ifaddrs **ifa, __u32 seq)
+static int
+netlink_add_rtattr_l(struct nlmsghdr *n, int maxlen, int type,
+		     const void *data, int alen)
 {
-	char	buf[8192];
-	struct sockaddr_nl nladdr;
-	struct iovec iov = { buf, sizeof(buf) };
-	struct ifaddrmsg *m;
-	struct rtattr * rta_tb[IFA_MAX+1];
-	struct ifaddrs *I;
+	int len = RTA_LENGTH(alen);
+	struct rtattr *rta;
 
-	while (1) {
-		int status;
-		struct nlmsghdr *h;
+	if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen)
+		return FALSE;
 
-		struct msghdr msg = {
-			(void*)&nladdr, sizeof(nladdr),
-			&iov,	1,
-			NULL,	0,
-			0
-		};
-
-		status = recvmsg(fd, &msg, 0);
-
-		if (status < 0)
-			continue;
-
-		if (status == 0)
-			return;
-
-		if (nladdr.nl_pid) /* Message not from kernel */
-			continue;
-
-		h = (struct nlmsghdr*)buf;
-		while (NLMSG_OK(h, status)) {
-			if (h->nlmsg_seq != seq)
-				goto skip_it;
-
-			if (h->nlmsg_type == NLMSG_DONE)
-				return;
-
-			if (h->nlmsg_type == NLMSG_ERROR)
-				return;
-
-			if (h->nlmsg_type != RTM_NEWADDR)
-				goto skip_it;
-
-			m = NLMSG_DATA(h);
-
-			if (m->ifa_family != AF_INET &&
-			    m->ifa_family != AF_INET6)
-				goto skip_it;
-
-			if (m->ifa_flags&IFA_F_TENTATIVE)
-				goto skip_it;
-
-			memset(rta_tb, 0, sizeof(rta_tb));
-			parse_rtattr(rta_tb, IFA_MAX, IFA_RTA(m), h->nlmsg_len - NLMSG_LENGTH(sizeof(*m)));
-
-			if (rta_tb[IFA_LOCAL] == NULL)
-				rta_tb[IFA_LOCAL] = rta_tb[IFA_ADDRESS];
-			if (rta_tb[IFA_LOCAL] == NULL)
-				goto skip_it;
-			
-			I = malloc(sizeof(struct ifaddrs));
-			if (!I)
-				return;
-			memset(I, 0, sizeof(*I));
-
-			I->ifa_ifindex = m->ifa_index;
-			I->ifa_addr = (struct sockaddr*)&I->ifa_addrbuf;
-			I->ifa_addr->sa_family = m->ifa_family;
-			if (m->ifa_family == AF_INET) {
-				struct sockaddr_in *sin = (void*)I->ifa_addr;
-				memcpy(&sin->sin_addr, RTA_DATA(rta_tb[IFA_LOCAL]), 4);
-			} else {
-				struct sockaddr_in6 *sin = (void*)I->ifa_addr;
-				memcpy(&sin->sin6_addr, RTA_DATA(rta_tb[IFA_LOCAL]), 16);
-				if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr))
-					sin->sin6_scope_id = I->ifa_ifindex;
-			}
-			I->ifa_next = *ifa;
-			*ifa = I;
-
-skip_it:
-			h = NLMSG_NEXT(h, status);
-		}
-		if (msg.msg_flags & MSG_TRUNC)
-			continue;
-	}
-	return;
+	rta = NLMSG_TAIL(n);
+	rta->rta_type = type;
+	rta->rta_len = len;
+	memcpy(RTA_DATA(rta), data, alen);
+	n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len);
+	return TRUE;
 }
 
-static int getifaddrs(struct ifaddrs **ifa0)
+static int
+netlink_enumerate(fd, family, type)
+	int fd;
+	int family;
+	int type;
 {
 	struct {
 		struct nlmsghdr nlh;
 		struct rtgenmsg g;
 	} req;
-	struct sockaddr_nl nladdr;
-	static __u32 seq;
-	struct ifaddrs *i;
-	int fd;
+	struct sockaddr_nl addr;
+	static __u32 seq = 0;
 
-	fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
-	if (fd < 0)
-		return -1;
+	memset(&addr, 0, sizeof(addr));
+	addr.nl_family = AF_NETLINK;
+
+	memset(&req, 0, sizeof(req));
+	req.nlh.nlmsg_len = sizeof(req);
+	req.nlh.nlmsg_type = type;
+	req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
+	req.nlh.nlmsg_pid = 0;
+	req.nlh.nlmsg_seq = ++seq;
+	req.g.rtgen_family = family;
+
+	return sendto(fd, (void *) &req, sizeof(req), 0,
+		      (struct sockaddr *) &addr, sizeof(addr)) >= 0;
+}
+
+static void
+netlink_add_del_address(int add, struct sockaddr *saddr)
+{
+	plog(LLV_DEBUG, LOCATION, NULL,
+	     "Netlink: address %s %s\n",
+	     saddrwop2str((struct sockaddr *) saddr),
+	     add ? "added" : "deleted");
+
+	if (add)
+		myaddr_open_all_configured(saddr);
+	else
+		myaddr_close_all_open(saddr);
+}
+
+#ifdef INET6
+static int
+netlink_process_addr(struct nlmsghdr *h)
+{
+	struct sockaddr_storage addr;
+	struct ifaddrmsg *ifa;
+	struct rtattr *rta[IFA_MAX+1];
+	struct sockaddr_in6 *sin6;
+
+	ifa = NLMSG_DATA(h);
+	parse_rtattr(rta, IFA_MAX, IFA_RTA(ifa), IFA_PAYLOAD(h));
+
+	if (ifa->ifa_family != AF_INET6)
+		return 0;
+	if (ifa->ifa_flags & IFA_F_TENTATIVE)
+		return 0;
+	if (rta[IFA_LOCAL] == NULL)
+		rta[IFA_LOCAL] = rta[IFA_ADDRESS];
+	if (rta[IFA_LOCAL] == NULL)
+		return 0;
+
+	memset(&addr, 0, sizeof(addr));
+	addr.ss_family = ifa->ifa_family;
+	sin6 = (struct sockaddr_in6 *) &addr;
+	memcpy(&sin6->sin6_addr, RTA_DATA(rta[IFA_LOCAL]),
+		sizeof(sin6->sin6_addr));
+	if (!IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
+		return 0;
+	sin6->sin6_scope_id = ifa->ifa_index;
+
+	netlink_add_del_address(h->nlmsg_type == RTM_NEWADDR,
+				(struct sockaddr *) &addr);
+
+	return 0;
+}
+#endif
+
+static int
+netlink_route_is_local(int family, const unsigned char *addr, size_t addr_len)
+{
+	struct {
+		struct nlmsghdr n;
+		struct rtmsg    r;
+		char            buf[1024];
+	} req;
+	struct rtmsg *r = NLMSG_DATA(&req.n);
+	struct rtattr *rta[RTA_MAX+1];
+	struct sockaddr_nl nladdr;
+	ssize_t rlen;
+
+	memset(&req, 0, sizeof(req));
+	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
+	req.n.nlmsg_flags = NLM_F_REQUEST;
+	req.n.nlmsg_type = RTM_GETROUTE;
+	req.r.rtm_family = family;
+	netlink_add_rtattr_l(&req.n, sizeof(req), RTA_DST,
+			     addr, addr_len);
+	req.r.rtm_dst_len = addr_len * 8;
 
 	memset(&nladdr, 0, sizeof(nladdr));
 	nladdr.nl_family = AF_NETLINK;
 
-	req.nlh.nlmsg_len = sizeof(req);
-	req.nlh.nlmsg_type = RTM_GETADDR;
-	req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
-	req.nlh.nlmsg_pid = 0;
-	req.nlh.nlmsg_seq = ++seq;
-	req.g.rtgen_family = AF_UNSPEC;
+	if (sendto(netlink_fd, &req, sizeof(req), 0,
+		   (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0)
+		return 0;
+	rlen = recv(netlink_fd, &req, sizeof(req), 0);
+	if (rlen < 0)
+		return 0;
 
-	if (sendto(fd, (void*)&req, sizeof(req), 0, (struct sockaddr*)&nladdr, sizeof(nladdr)) < 0) {
+	return  req.n.nlmsg_type == RTM_NEWROUTE &&
+		req.r.rtm_type == RTN_LOCAL;
+}
+
+static int
+netlink_process_route(struct nlmsghdr *h)
+{
+	struct sockaddr_storage addr;
+	struct rtmsg *rtm;
+	struct rtattr *rta[RTA_MAX+1];
+	struct sockaddr_in *sin;
+#ifdef INET6
+	struct sockaddr_in6 *sin6;
+#endif
+
+	rtm = NLMSG_DATA(h);
+
+	/* local IP addresses get local route in the local table */
+	if (rtm->rtm_type != RTN_LOCAL ||
+	    rtm->rtm_table != RT_TABLE_LOCAL)
+		return 0;
+
+	parse_rtattr(rta, IFA_MAX, RTM_RTA(rtm), IFA_PAYLOAD(h));
+	if (rta[RTA_DST] == NULL)
+ 		return 0;
+
+	/* setup the socket address */
+	memset(&addr, 0, sizeof(addr));
+	addr.ss_family = rtm->rtm_family;
+	switch (rtm->rtm_family) {
+	case AF_INET:
+		sin = (struct sockaddr_in *) &addr;
+		memcpy(&sin->sin_addr, RTA_DATA(rta[RTA_DST]),
+			sizeof(sin->sin_addr));
+		break;
+#ifdef INET6
+	case AF_INET6:
+		sin6 = (struct sockaddr_in6 *) &addr;
+		memcpy(&sin6->sin6_addr, RTA_DATA(rta[RTA_DST]),
+			sizeof(sin6->sin6_addr));
+		/* Link-local addresses are handled with RTM_NEWADDR
+		 * notifications */
+		if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
+			return 0;
+		break;
+#endif
+	default:
+		return 0;
+	}
+
+	/* If local route was deleted, check if there is still local
+	 * route for the same IP on another interface */
+	if (h->nlmsg_type == RTM_DELROUTE &&
+	    netlink_route_is_local(rtm->rtm_family,
+				   RTA_DATA(rta[RTA_DST]),
+				   RTA_PAYLOAD(rta[RTA_DST]))) {
+		plog(LLV_DEBUG, LOCATION, NULL,
+			"Netlink: not deleting %s yet, it exists still\n",
+			saddrwop2str((struct sockaddr *) &addr));
+		return 0;
+	}
+
+	netlink_add_del_address(h->nlmsg_type == RTM_NEWROUTE,
+				(struct sockaddr *) &addr);
+	return 0;
+}
+
+static int
+netlink_process(struct nlmsghdr *h)
+{
+	switch (h->nlmsg_type) {
+#ifdef INET6
+	case RTM_NEWADDR:
+	case RTM_DELADDR:
+		return netlink_process_addr(h);
+#endif
+	case RTM_NEWROUTE:
+	case RTM_DELROUTE:
+		return netlink_process_route(h);
+	}
+	return 0;
+}
+
+static int
+kernel_receive(ctx, fd)
+	void *ctx;
+	int fd;
+{
+	struct sockaddr_nl nladdr;
+	struct iovec iov;
+	struct msghdr msg = {
+		.msg_name = &nladdr,
+		.msg_namelen = sizeof(nladdr),
+		.msg_iov = &iov,
+		.msg_iovlen = 1,
+	};
+	struct nlmsghdr *h;
+	int len, status;
+	char buf[16*1024];
+
+	iov.iov_base = buf;
+	while (1) {
+		iov.iov_len = sizeof(buf);
+		status = recvmsg(fd, &msg, MSG_DONTWAIT);
+		if (status < 0) {
+			if (errno == EINTR)
+				continue;
+			if (errno == EAGAIN)
+				return FALSE;
+			continue;
+		}
+		if (status == 0)
+			return FALSE;
+
+		h = (struct nlmsghdr *) buf;
+		while (NLMSG_OK(h, status)) {
+			netlink_process(h);
+			h = NLMSG_NEXT(h, status);
+		}
+	}
+
+	return TRUE;
+}
+
+static int
+netlink_open_socket()
+{
+	int fd;
+
+	fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+	if (fd < 0) {
+		plog(LLV_ERROR, LOCATION, NULL,
+			"socket(PF_NETLINK) failed: %s",
+			strerror(errno));
+		return -1;
+	}
+	close_on_exec(fd);
+	if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1)
+		plog(LLV_WARNING, LOCATION, NULL,
+		     "failed to put socket in non-blocking mode\n");
+
+	return fd;
+}
+
+static int
+kernel_open_socket()
+{
+	struct sockaddr_nl nl;
+	int fd;
+
+	if (netlink_fd < 0) {
+		netlink_fd = netlink_open_socket();
+		if (netlink_fd < 0)
+			return -1;
+	}
+
+	fd = netlink_open_socket();
+	if (fd < 0)
+		return fd;
+
+	/* We monitor IPv4 addresses using RTMGRP_IPV4_ROUTE group
+	 * the get the RTN_LOCAL routes which are automatically added
+	 * by kernel. This is because:
+	 *  - Linux kernel has a bug that calling bind() immediately
+	 *    after IPv4 RTM_NEWADDR event can fail
+	 *  - if IP is configured in multiple interfaces, we get
+	 *    RTM_DELADDR for each of them. RTN_LOCAL gets deleted only
+	 *    after the last IP address is deconfigured.
+	 * The latter reason is also why I chose to use route
+	 * notifications for IPv6. However, we do need to use RTM_NEWADDR
+	 * for the link-local IPv6 addresses to get the interface index
+	 * that is needed in bind().
+	 */
+	memset(&nl, 0, sizeof(nl));
+	nl.nl_family = AF_NETLINK;
+	nl.nl_groups = RTMGRP_IPV4_ROUTE 
+#ifdef INET6
+			| RTMGRP_IPV6_IFADDR | RTMGRP_IPV6_ROUTE
+#endif
+			;
+	if (bind(fd, (struct sockaddr*) &nl, sizeof(nl)) < 0) {
+		plog(LLV_ERROR, LOCATION, NULL,
+		     "bind(PF_NETLINK) failed: %s\n",
+		     strerror(errno));
 		close(fd);
 		return -1;
 	}
-
-	*ifa0 = NULL;
-
-	recvaddrs(fd, ifa0, seq);
-
-	close(fd);
-
-	fd = socket(AF_INET, SOCK_DGRAM, 0);
-
-	for (i=*ifa0; i; i = i->ifa_next) {
-		struct ifreq ifr;
-		ifr.ifr_ifindex = i->ifa_ifindex;
-		ioctl(fd, SIOCGIFNAME, (void*)&ifr);
-		memcpy(i->ifa_name, ifr.ifr_name, 16);
-	}
-	close(fd);
-
-	return 0;
+	return fd;
 }
 
-static void freeifaddrs(struct ifaddrs *ifa0)
+static void
+kernel_sync()
 {
-        struct ifaddrs *i;
+	int fd = lcconf->rtsock;
 
-        while (ifa0) {
-                i = ifa0;
-                ifa0 = i->ifa_next;
-                free(i);
-        }
-}
-
-#endif
-
-#ifndef HAVE_GETIFADDRS
-static unsigned int
-if_maxindex()
-{
-	struct if_nameindex *p, *p0;
-	unsigned int max = 0;
-
-	p0 = if_nameindex();
-	for (p = p0; p && p->if_index && p->if_name; p++) {
-		if (max < p->if_index)
-			max = p->if_index;
-	}
-	if_freenameindex(p0);
-	return max;
-}
-#endif
-
-void
-clear_myaddr(db)
-	struct myaddrs **db;
-{
-	struct myaddrs *p;
-
-	while (*db) {
-		p = (*db)->next;
-		delmyaddr(*db);
-		*db = p;
-	}
-}
-  
-static struct myaddrs *
-find_myaddr(db, p)
-	struct myaddrs *db;
-	struct myaddrs *p;
-{
-	struct myaddrs *q;
-	char h1[NI_MAXHOST], h2[NI_MAXHOST];
-
-	if (getnameinfo(p->addr, sysdep_sa_len(p->addr), h1, sizeof(h1), NULL, 0,
-	    NI_NUMERICHOST | niflags) != 0)
-		return NULL;
-
-	for (q = db; q; q = q->next) {
-		if (p->addr->sa_family != q->addr->sa_family)
-			continue;
-		if (getnameinfo(q->addr, sysdep_sa_len(q->addr), h2, sizeof(h2),
-		    NULL, 0, NI_NUMERICHOST | niflags) != 0)
-			return NULL;
-		if (strcmp(h1, h2) == 0)
-			return q;
-	}
-
-	return NULL;
-}
-
-void
-grab_myaddrs()
-{
-#ifdef HAVE_GETIFADDRS
-	struct myaddrs *p, *q, *old;
-	struct ifaddrs *ifa0, *ifap;
-#ifdef INET6
-	struct sockaddr_in6 *sin6;
-#endif
-
-	char addr1[NI_MAXHOST];
-
-	if (getifaddrs(&ifa0)) {
+	/* refresh addresses */
+	if (!netlink_enumerate(fd, PF_UNSPEC, RTM_GETROUTE)) {
 		plog(LLV_ERROR, LOCATION, NULL,
-			"getifaddrs failed: %s\n", strerror(errno));
-		exit(1);
-		/*NOTREACHED*/
+		     "unable to enumerate addresses: %s\n",
+		     strerror(errno));
 	}
+	while (kernel_receive(NULL, fd) == TRUE);
 
-	old = lcconf->myaddrs;
-
-	for (ifap = ifa0; ifap; ifap = ifap->ifa_next) {
-		if (! ifap->ifa_addr)
-			continue;
-
-		if (ifap->ifa_addr->sa_family != AF_INET
 #ifdef INET6
-		 && ifap->ifa_addr->sa_family != AF_INET6
-#endif
-		)
-			continue;
-
-		if (!suitable_ifaddr(ifap->ifa_name, ifap->ifa_addr)) {
-			plog(LLV_ERROR, LOCATION, NULL,
-				"unsuitable address: %s %s\n",
-				ifap->ifa_name,
-				saddrwop2str(ifap->ifa_addr));
-			continue;
-		}
-
-		p = newmyaddr();
-		if (p == NULL) {
-			exit(1);
-			/*NOTREACHED*/
-		}
-		p->addr = dupsaddr(ifap->ifa_addr);
-		if (p->addr == NULL) {
-			exit(1);
-			/*NOTREACHED*/
-		}
-#ifdef INET6
-#ifdef __KAME__
-		if (ifap->ifa_addr->sa_family == AF_INET6) {
-			sin6 = (struct sockaddr_in6 *)p->addr;
-			if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)
-			 || IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr)) {
-				sin6->sin6_scope_id =
-					ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]);
-				sin6->sin6_addr.s6_addr[2] = 0;
-				sin6->sin6_addr.s6_addr[3] = 0;
-			}
-		}
-#else /* !__KAME__ */
-		if (ifap->ifa_addr->sa_family == AF_INET6) {
-			sin6 = (struct sockaddr_in6 *)p->addr;
-			if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)
-			 || IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr)) {
-				sin6->sin6_scope_id =
-					if_nametoindex(ifap->ifa_name);
-			}
-		}
-				
-#endif
-#endif
-		if (getnameinfo(p->addr, sysdep_sa_len(p->addr),
-				addr1, sizeof(addr1),
-				NULL, 0,
-				NI_NUMERICHOST | niflags))
-		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)
-			p->sock = q->sock;
-		else
-			p->sock = -1;
-		p->next = lcconf->myaddrs;
-		lcconf->myaddrs = p;
+	if (!netlink_enumerate(fd, PF_INET6, RTM_GETADDR)) {
+		plog(LLV_ERROR, LOCATION, NULL,
+		     "unable to enumerate addresses: %s\n",
+		     strerror(errno));
 	}
+	while (kernel_receive(NULL, fd) == TRUE);
+#endif
+}
 
-	freeifaddrs(ifa0);
+#elif defined(USE_ROUTE)
 
-	clear_myaddr(&old);
+#define ROUNDUP(a) \
+  ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
 
-#else /*!HAVE_GETIFADDRS*/
-	int s;
-	unsigned int maxif;
+#define SAROUNDUP(X)   ROUNDUP(((struct sockaddr *)(X))->sa_len)
+
+static size_t
+parse_address(start, end, dest)
+	caddr_t start;
+	caddr_t end;
+	struct sockaddr_storage *dest;
+{
 	int len;
-	struct ifreq *iflist;
-	struct ifconf ifconf;
-	struct ifreq *ifr, *ifr_end;
-	struct myaddrs *p, *q, *old;
-#ifdef INET6
-#ifdef __KAME__
-	struct sockaddr_in6 *sin6;
-#endif
-#endif
 
-	char addr1[NI_MAXHOST];
+	if (start >= end)
+		return 0;
 
-	maxif = if_maxindex() + 1;
-	len = maxif * sizeof(struct sockaddr_storage) * 4; /* guess guess */
+	len = SAROUNDUP(start);
+	if (start + len > end)
+		return end - start;
 
-	iflist = (struct ifreq *)racoon_malloc(len);
-	if (!iflist) {
-		plog(LLV_ERROR, LOCATION, NULL,
-			"failed to allocate buffer\n");
-		exit(1);
-		/*NOTREACHED*/
-	}
+	if (dest != NULL && len <= sizeof(struct sockaddr_storage))
+		memcpy(dest, start, len);
 
-	if ((s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
-		plog(LLV_ERROR, LOCATION, NULL,
-			"socket(SOCK_DGRAM) failed: %s\n",
-			strerror(errno));
-		exit(1);
-		/*NOTREACHED*/
-	}
-	memset(&ifconf, 0, sizeof(ifconf));
-	ifconf.ifc_req = iflist;
-	ifconf.ifc_len = len;
-	if (ioctl(s, SIOCGIFCONF, &ifconf) < 0) {
-		close(s);
-		plog(LLV_ERROR, LOCATION, NULL,
-			"ioctl(SIOCGIFCONF) failed: %s\n",
-			strerror(errno));
-		exit(1);
-		/*NOTREACHED*/
-	}
-	close(s);
-
-	old = lcconf->myaddrs;
-
-	/* Look for this interface in the list */
-	ifr_end = (struct ifreq *) (ifconf.ifc_buf + ifconf.ifc_len);
-
-#define _IFREQ_LEN(p) \
-  (sizeof((p)->ifr_name) + sysdep_sa_len(&(p)->ifr_addr) > sizeof(struct ifreq) \
-    ? sizeof((p)->ifr_name) + sysdep_sa_len(&(p)->ifr_addr) : sizeof(struct ifreq))
-
-	for (ifr = ifconf.ifc_req;
-	     ifr < ifr_end;
-	     ifr = (struct ifreq *)((caddr_t)ifr + _IFREQ_LEN(ifr))) {
-
-		switch (ifr->ifr_addr.sa_family) {
-		case AF_INET:
-#ifdef INET6
-		case AF_INET6:
-#endif
-			if (!suitable_ifaddr(ifr->ifr_name, &ifr->ifr_addr)) {
-				plog(LLV_ERROR, LOCATION, NULL,
-					"unsuitable address: %s %s\n",
-					ifr->ifr_name,
-					saddrwop2str(&ifr->ifr_addr));
-				continue;
-			}
-
-			p = newmyaddr();
-			if (p == NULL) {
-				exit(1);
-				/*NOTREACHED*/
-			}
-			p->addr = dupsaddr(&ifr->ifr_addr);
-			if (p->addr == NULL) {
-				exit(1);
-				/*NOTREACHED*/
-			}
-#ifdef INET6
-#ifdef __KAME__
-			sin6 = (struct sockaddr_in6 *)p->addr;
-			if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)
-			 || IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr)) {
-				sin6->sin6_scope_id =
-					ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]);
-				sin6->sin6_addr.s6_addr[2] = 0;
-				sin6->sin6_addr.s6_addr[3] = 0;
-			}
-#endif
-#endif
-			if (getnameinfo(p->addr, sysdep_sa_len(p->addr),
-					addr1, sizeof(addr1),
-					NULL, 0,
-					NI_NUMERICHOST | niflags))
-			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)
-				p->sock = q->sock;
-			else
-				p->sock = -1;
-			p->next = lcconf->myaddrs;
-			lcconf->myaddrs = p;
-			break;
-		default:
-			break;
-		}
-	}
-
-	clear_myaddr(&old);
-
-	racoon_free(iflist);
-#endif /*HAVE_GETIFADDRS*/
+	return len;
 }
 
-/*
- * check the interface is suitable or not
- */
-static int
-suitable_ifaddr(ifname, ifaddr)
-	const char *ifname;
-	const struct sockaddr *ifaddr;
+static void
+parse_addresses(start, end, flags, addr)
+	caddr_t start;
+	caddr_t end;
+	int flags;
+	struct sockaddr_storage *addr;
 {
-#ifdef ENABLE_HYBRID
-	/* Exclude any address we got through ISAKMP mode config */
-	if (exclude_cfg_addr(ifaddr) == 0)
-		return 0;
-#endif
-	switch(ifaddr->sa_family) {
-	case AF_INET:
-		return 1;
-#ifdef INET6
-	case AF_INET6:
-		return suitable_ifaddr6(ifname, ifaddr);
-#endif
-	default:
-		return 0;
-	}
-	/*NOTREACHED*/
+	memset(addr, 0, sizeof(*addr));
+	if (flags & RTA_DST)
+		start += parse_address(start, end, NULL);
+	if (flags & RTA_GATEWAY)
+		start += parse_address(start, end, NULL);
+	if (flags & RTA_NETMASK)
+		start += parse_address(start, end, NULL);
+	if (flags & RTA_GENMASK)
+		start += parse_address(start, end, NULL);
+	if (flags & RTA_IFP)
+		start += parse_address(start, end, NULL);
+	if (flags & RTA_IFA)
+		start += parse_address(start, end, addr);
+	if (flags & RTA_AUTHOR)
+		start += parse_address(start, end, NULL);
+	if (flags & RTA_BRD)
+		start += parse_address(start, end, NULL);
 }
 
-#ifdef INET6
-static int
-suitable_ifaddr6(ifname, ifaddr)
-	const char *ifname;
-	const struct sockaddr *ifaddr;
+static void
+kernel_handle_message(msg)
+	caddr_t msg;
 {
-#ifndef __linux__
-	struct in6_ifreq ifr6;
-	int s;
-#endif
+	struct rt_msghdr *rtm = (struct rt_msghdr *) msg;
+	struct ifa_msghdr *ifa = (struct ifa_msghdr *) msg;
+	struct sockaddr_storage addr;
 
-	if (ifaddr->sa_family != AF_INET6)
-		return 0;
-
-#ifndef __linux__
-	s = socket(PF_INET6, SOCK_DGRAM, 0);
-	if (s == -1) {
-		plog(LLV_ERROR, LOCATION, NULL,
-			"socket(SOCK_DGRAM) failed:%s\n", strerror(errno));
-		return 0;
-	}
-
-	memset(&ifr6, 0, sizeof(ifr6));
-	strncpy(ifr6.ifr_name, ifname, strlen(ifname));
-
-	ifr6.ifr_addr = *(const struct sockaddr_in6 *)ifaddr;
-
-	if (ioctl(s, SIOCGIFAFLAG_IN6, &ifr6) < 0) {
-		plog(LLV_ERROR, LOCATION, NULL,
-			"ioctl(SIOCGIFAFLAG_IN6) failed:%s\n", strerror(errno));
-		close(s);
-		return 0;
-	}
-
-	close(s);
-
-	if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DUPLICATED
-	 || ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DETACHED
-	 || ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_ANYCAST)
-		return 0;
-#endif
-
-	/* suitable */
-	return 1;
-}
-#endif
-
-int
-update_myaddrs()
-{
-#ifdef __linux__
-	char msg[BUFSIZ];
-	int len;
-	struct nlmsghdr *h = (void*)msg;
-	len = read(lcconf->rtsock, msg, sizeof(msg));
-	if (len < 0)
-		return errno == ENOBUFS;
-	if (len < sizeof(*h))
-		return 0;
-	if (h->nlmsg_pid) /* not from kernel! */
-		return 0;
-	if (h->nlmsg_type == RTM_NEWLINK)
-		return 0;
-	plog(LLV_DEBUG, LOCATION, NULL,
-		"netlink signals update interface address list\n");
-	return 1;
-#else
-	char msg[BUFSIZ];
-	int len;
-	struct rt_msghdr *rtm;
-
-	len = read(lcconf->rtsock, msg, sizeof(msg));
-	if (len < 0) {
-		plog(LLV_ERROR, LOCATION, NULL,
-			"read(PF_ROUTE) failed: %s\n",
-			strerror(errno));
-		return 0;
-	}
-	rtm = (struct rt_msghdr *)msg;
-	if (len < rtm->rtm_msglen) {
-		plog(LLV_ERROR, LOCATION, NULL,
-			"read(PF_ROUTE) short read\n");
-		return 0;
-	}
-	if (rtm->rtm_version != RTM_VERSION) {
-		plog(LLV_ERROR, LOCATION, NULL,
-			"routing socket version mismatch\n");
-		close(lcconf->rtsock);
-		lcconf->rtsock = -1;
-		return 0;
-	}
 	switch (rtm->rtm_type) {
 	case RTM_NEWADDR:
-	case RTM_DELADDR:
-	case RTM_DELETE:
-	case RTM_IFINFO:
+		parse_addresses(ifa + 1, msg + ifa->ifam_msglen,
+				ifa->ifam_addrs, &addr);
+		myaddr_open_all_configured((struct sockaddr *) &addr);
 		break;
+	case RTM_DELADDR:
+		parse_addresses(ifa + 1, msg + ifa->ifam_msglen,
+				ifa->ifam_addrs, &addr);
+		myaddr_close_all_open((struct sockaddr *) &addr);
+		break;
+	case RTM_ADD:
+	case RTM_DELETE:
+	case RTM_CHANGE:
 	case RTM_MISS:
-		/* ignore this message silently */
-		return 0;
-	default:
-		plog(LLV_DEBUG, LOCATION, NULL,
-			"msg %d not interesting\n", rtm->rtm_type);
-		return 0;
-	}
-	/* XXX more filters here? */
-
-	plog(LLV_DEBUG, LOCATION, NULL,
-		"caught rtm:%d, need update interface address list\n",
-		rtm->rtm_type);
-	return 1;
-#endif /* __linux__ */
-}
-
-/*
- * initialize default port for ISAKMP to send, if no "listen"
- * directive is specified in config file.
- *
- * DO NOT listen to wildcard addresses.  if you receive packets to
- * wildcard address, you'll be in trouble (DoS attack possible by
- * broadcast storm).
- */
-int
-autoconf_myaddrsport()
-{
-	struct myaddrs *p;
-	int n;
-
-	plog(LLV_DEBUG, LOCATION, NULL,
-		"configuring default isakmp port.\n");
-
-#ifdef ENABLE_NATT
-	if (natt_enabled_in_rmconf ()) {
-		plog(LLV_NOTIFY, LOCATION, NULL, "NAT-T is enabled, autoconfiguring ports\n");
-		for (p = lcconf->myaddrs; p; p = p->next) {
-			struct myaddrs *new;
-			if (! p->udp_encap) {
-				new = dupmyaddr(p);
-				new->udp_encap = 1;
-			}
-		}
-	}
+	case RTM_IFINFO:
+#ifdef RTM_OIFINFO
+	case RTM_OIFINFO:
 #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);
+#ifdef RTM_NEWMADDR
+	case RTM_NEWMADDR:
+	case RTM_DELMADDR:
+#endif
+#ifdef RTM_IFANNOUNCE
+	case RTM_IFANNOUNCE:
+#endif
+		break;
+	default:
+		plog(LLV_WARNING, LOCATION, NULL,
+		     "unrecognized route message with rtm_type: %d",
+		     rtm->rtm_type);
+		break;
 	}
-	plog(LLV_DEBUG, LOCATION, NULL,
-		"%d addrs are configured successfully\n", n);
-
-	return 0;
 }
 
-/*
- * get a port number to which racoon binded.
- */
-u_short
-getmyaddrsport(local)
-	struct sockaddr *local;
+static int
+kernel_receive(ctx, fd)
+	void *ctx;
+	int fd;
 {
-	struct myaddrs *p, *bestmatch = NULL;
-	u_short bestmatch_port = PORT_ISAKMP;
+	char buf[16*1024];
+	struct rt_msghdr *rtm = (struct rt_msghdr *) buf;
+	int len;
 
-	/* get a relative port */
-	for (p = lcconf->myaddrs; p; p = p->next) {
-		if (!p->addr)
-			continue;
-		if (cmpsaddrwop(local, p->addr))
-			continue;
-
-		/* use first matching address regardless of port */
-		if (!bestmatch) {
-			bestmatch = p;
-			continue;
-		}
-
-		/* matching address with port PORT_ISAKMP */
-		if (extract_port(p->addr) == PORT_ISAKMP) {
-			bestmatch = p;
-			bestmatch_port = PORT_ISAKMP;
-		}
+	len = read(fd, &buf, sizeof(buf));
+	if (len <= 0) {
+		if (len < 0 && errno != EWOULDBLOCK && errno != EAGAIN)
+			plog(LLV_WARNING, LOCATION, NULL,
+			     "routing socket error: %s", strerror(errno));
+		return FALSE;
 	}
 
-	return bestmatch_port;
-}
-
-struct myaddrs *
-newmyaddr()
-{
-	struct myaddrs *new;
-
-	new = racoon_calloc(1, sizeof(*new));
-	if (new == NULL) {
-		plog(LLV_ERROR, LOCATION, NULL,
-			"failed to allocate buffer for myaddrs.\n");
-		return NULL;
+	if (rtm->rtm_msglen != len) {
+		plog(LLV_WARNING, LOCATION, NULL,
+		     "kernel_receive: rtm->rtm_msglen %d, len %d, type %d\n",
+		     rtm->rtm_msglen, len, rtm->rtm_type);
+		return FALSE;
 	}
 
-	new->next = NULL;
-	new->addr = NULL;
-
-	return new;
+	kernel_handle_message(buf);
+	return TRUE;
 }
 
-struct myaddrs *
-dupmyaddr(struct myaddrs *old)
+static int
+kernel_open_socket()
 {
-	struct myaddrs *new;
+	int fd;
 
-	new = racoon_calloc(1, sizeof(*new));
-	if (new == NULL) {
-		plog(LLV_ERROR, LOCATION, NULL,
-			"failed to allocate buffer for myaddrs.\n");
-		return NULL;
-	}
-
-	/* Copy the whole structure and set the differences.  */
-	memcpy (new, old, sizeof (*new));
-	new->addr = dupsaddr (old->addr);
-	if (new->addr == NULL) {
-		plog(LLV_ERROR, LOCATION, NULL,
-			"failed to allocate buffer for myaddrs.\n");
-		racoon_free(new);
-		return NULL;
-	}
-	new->next = old->next;
-	old->next = new;
-
-	return new;
-}
-
-void
-insmyaddr(new, head)
-	struct myaddrs *new;
-	struct myaddrs **head;
-{
-	new->next = *head;
-	*head = new;
-}
-
-void
-delmyaddr(myaddr)
-	struct myaddrs *myaddr;
-{
-	if (myaddr->addr)
-		racoon_free(myaddr->addr);
-	racoon_free(myaddr);
-}
-
-int
-initmyaddr()
-{
-	/* initialize routing socket */
-	lcconf->rtsock = socket(PF_ROUTE, SOCK_RAW, PF_UNSPEC);
-	if (lcconf->rtsock < 0) {
+	fd = socket(PF_ROUTE, SOCK_RAW, 0);
+	if (fd < 0) {
 		plog(LLV_ERROR, LOCATION, NULL,
 			"socket(PF_ROUTE) failed: %s",
 			strerror(errno));
 		return -1;
 	}
+	close_on_exec(fd);
+	if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1)
+		plog(LLV_WARNING, LOCATION, NULL,
+		     "failed to put socket in non-blocking mode\n");
 
-#ifdef __linux__
-   {
-	struct sockaddr_nl nl;
-	u_int addr_len;
-
-	memset(&nl, 0, sizeof(nl));
-	nl.nl_family = AF_NETLINK;
-	nl.nl_groups = RTMGRP_IPV4_IFADDR|RTMGRP_LINK|RTMGRP_IPV6_IFADDR;
-
-	if (bind(lcconf->rtsock, (struct sockaddr*)&nl, sizeof(nl)) < 0) {
-		plog(LLV_ERROR, LOCATION, NULL,
-		     "bind(PF_NETLINK) failed: %s\n",
-		     strerror(errno));
-		return -1;
-	}
-	addr_len = sizeof(nl);
-	if (getsockname(lcconf->rtsock, (struct sockaddr*)&nl, &addr_len) < 0) {
-		plog(LLV_ERROR, LOCATION, NULL,
-		     "getsockname(PF_NETLINK) failed: %s\n",
-		     strerror(errno));
-		return -1;
-	}
-   }
-#endif
-
-	if (lcconf->myaddrs == NULL && lcconf->autograbaddr == 1) {
-		grab_myaddrs();
-
-		if (autoconf_myaddrsport() < 0)
-			return -1;
-	}
-
-	return 0;
+	return fd;
 }
 
-/* select the socket to be sent */
-/* should implement other method. */
-int
-getsockmyaddr(my)
-	struct sockaddr *my;
+static void
+kernel_sync()
 {
-	struct myaddrs *p, *lastresort = NULL;
-#if defined(INET6) && defined(__linux__)
-	struct myaddrs *match_wo_scope_id = NULL;
-	int check_wo_scope_id = (my->sa_family == AF_INET6) && 
-		IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *)my)->sin6_addr);
-#endif
+	caddr_t ref, buf, end;
+	size_t bufsiz;
+	struct if_msghdr *ifm;
+	struct interface *ifp;
 
-	for (p = lcconf->myaddrs; p; p = p->next) {
-		if (p->addr == NULL)
-			continue;
-		if (my->sa_family == p->addr->sa_family) {
-			lastresort = p;
-		} else continue;
-		if (sysdep_sa_len(my) == sysdep_sa_len(p->addr)
-		 && memcmp(my, p->addr, sysdep_sa_len(my)) == 0) {
-			break;
-		}
-#if defined(INET6) && defined(__linux__)
-		if (check_wo_scope_id && IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *)p->addr)->sin6_addr) &&
-			/* XXX: this depends on sin6_scope_id to be last
-			 * item in struct sockaddr_in6 */
-			memcmp(my, p->addr, 
-				sysdep_sa_len(my) - sizeof(uint32_t)) == 0) {
-			match_wo_scope_id = p;
-		}
-#endif
-	}
-#if defined(INET6) && defined(__linux__)
-	if (!p)
-		p = match_wo_scope_id;
-#endif
-	if (!p)
-		p = lastresort;
-	if (!p) {
-		plog(LLV_ERROR, LOCATION, NULL,
-			"no socket matches address family %d\n",
-			my->sa_family);
-		return -1;
+#define MIBSIZ 6
+	int mib[MIBSIZ] = {
+		CTL_NET,
+		PF_ROUTE,
+		0,
+		0, /*  AF_INET & AF_INET6 */
+		NET_RT_IFLIST,
+		0
+	};
+
+	if (sysctl(mib, MIBSIZ, NULL, &bufsiz, NULL, 0) < 0) {
+		plog(LLV_WARNING, LOCATION, NULL,
+		     "sysctl() error: %s", strerror(errno));
+		return;
 	}
 
-	return p->sock;
+	ref = buf = racoon_malloc(bufsiz);
+
+	if (sysctl(mib, MIBSIZ, buf, &bufsiz, NULL, 0) >= 0) {
+		/* Parse both interfaces and addresses. */
+		for (end = buf + bufsiz; buf < end; buf += ifm->ifm_msglen) {
+			ifm = (struct if_msghdr *) buf;
+			kernel_handle_message(buf);
+		}
+	} else {
+		plog(LLV_WARNING, LOCATION, NULL,
+		     "sysctl() error: %s", strerror(errno));
+	}
+
+	racoon_free(ref);
 }
+
+#else
+
+#error No supported interface to monitor local addresses.
+
+#endif
diff --git a/src/racoon/grabmyaddr.h b/src/racoon/grabmyaddr.h
index ac74b46..a105d8f 100644
--- a/src/racoon/grabmyaddr.h
+++ b/src/racoon/grabmyaddr.h
@@ -1,4 +1,4 @@
-/*	$NetBSD: grabmyaddr.h,v 1.4 2006/09/09 16:22:09 manu Exp $	*/
+/*	$NetBSD: grabmyaddr.h,v 1.6 2009/04/21 18:38:32 tteras Exp $	*/
 
 /* Id: grabmyaddr.h,v 1.5 2004/06/11 16:00:16 ludvigm Exp */
 
@@ -34,23 +34,15 @@
 #ifndef _GRABMYADDR_H
 #define _GRABMYADDR_H
 
-struct myaddrs {
-	struct myaddrs *next;
-	struct sockaddr *addr;
-	int sock;
-	int udp_encap;
-};
+extern void myaddr_init_lists __P((void));
+extern int myaddr_init __P((void));
+extern void myaddr_close __P((void));
 
-extern void clear_myaddr __P((struct myaddrs **));
-extern void grab_myaddrs __P((void));
-extern int update_myaddrs __P((void));
-extern int autoconf_myaddrsport __P((void));
-extern u_short getmyaddrsport __P((struct sockaddr *));
-extern struct myaddrs *newmyaddr __P((void));
-extern struct myaddrs *dupmyaddr __P((struct myaddrs *));
-extern void insmyaddr __P((struct myaddrs *, struct myaddrs **));
-extern void delmyaddr __P((struct myaddrs *));
-extern int initmyaddr __P((void));
-extern int getsockmyaddr __P((struct sockaddr *));
+extern void myaddr_flush __P((void));
+extern int myaddr_listen __P((struct sockaddr *, int));
+extern void myaddr_sync __P((void));
+
+extern int myaddr_getfd __P((struct sockaddr *));
+extern int myaddr_getsport __P((struct sockaddr *));
 
 #endif /* _GRABMYADDR_H */
diff --git a/src/racoon/handler.c b/src/racoon/handler.c
index b643256..a795ee6 100644
--- a/src/racoon/handler.c
+++ b/src/racoon/handler.c
@@ -1,11 +1,11 @@
-/*	$NetBSD: handler.c,v 1.9.6.8 2009/04/20 13:25:27 tteras Exp $	*/
+/*	$NetBSD: handler.c,v 1.39 2011/03/14 17:18:12 tteras Exp $	*/
 
 /* Id: handler.c,v 1.28 2006/05/26 12:17:29 manubsd Exp */
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
  * All rights reserved.
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
@@ -17,7 +17,7 @@
  * 3. Neither the name of the project nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
- * 
+ *
  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@@ -64,7 +64,7 @@
 #include "evt.h"
 #include "isakmp.h"
 #ifdef ENABLE_HYBRID
-#include "isakmp_xauth.h"  
+#include "isakmp_xauth.h"
 #include "isakmp_cfg.h"
 #endif
 #include "isakmp_inf.h"
@@ -85,10 +85,10 @@
 static LIST_HEAD(_ph2tree_, ph2handle) ph2tree;
 static LIST_HEAD(_ctdtree_, contacted) ctdtree;
 static LIST_HEAD(_rcptree_, recvdpkt) rcptree;
+static struct sched sc_sweep = SCHED_INITIALIZER();
 
 static void del_recvdpkt __P((struct recvdpkt *));
 static void rem_recvdpkt __P((struct recvdpkt *));
-static void sweep_recvdpkt __P((void *));
 
 /*
  * functions about management of the isakmp status table
@@ -100,6 +100,41 @@
 
 extern caddr_t val2str(const char *, size_t);
 
+/*
+ * Enumerate the Phase 1 tree.
+ * If enum_func() internally return a non-zero value,  this specific
+ * error value is returned. 0 is returned if everything went right.
+ *
+ * Note that it is ok for enum_func() to call insph1(). Those inserted
+ * Phase 1 will not interfere with current enumeration process.
+ */
+int
+enumph1(sel, enum_func, enum_arg)
+	struct ph1selector *sel;
+	int (* enum_func)(struct ph1handle *iph1, void *arg);
+	void *enum_arg;
+{
+	struct ph1handle *p;
+	int ret;
+
+	LIST_FOREACH(p, &ph1tree, chain) {
+		if (sel != NULL) {
+			if (sel->local != NULL &&
+			    cmpsaddr(sel->local, p->local) > CMPSADDR_WILDPORT_MATCH)
+				continue;
+
+			if (sel->remote != NULL &&
+			    cmpsaddr(sel->remote, p->remote) > CMPSADDR_WILDPORT_MATCH)
+				continue;
+		}
+
+		if ((ret = enum_func(p, enum_arg)) != 0)
+			return ret;
+	}
+
+	return 0;
+}
+
 struct ph1handle *
 getph1byindex(index)
 	isakmp_index *index;
@@ -107,7 +142,7 @@
 	struct ph1handle *p;
 
 	LIST_FOREACH(p, &ph1tree, chain) {
-		if (p->status == PHASE1ST_EXPIRED)
+		if (p->status >= PHASE1ST_EXPIRED)
 			continue;
 		if (memcmp(&p->index, index, sizeof(*index)) == 0)
 			return p;
@@ -127,7 +162,7 @@
 	struct ph1handle *p;
 
 	LIST_FOREACH(p, &ph1tree, chain) {
-		if (p->status == PHASE1ST_EXPIRED)
+		if (p->status >= PHASE1ST_EXPIRED)
 			continue;
 		if (memcmp(&p->index, index, sizeof(cookie_t)) == 0)
 			return p;
@@ -142,31 +177,57 @@
  * with phase 2's destinaion.
  */
 struct ph1handle *
-getph1byaddr(local, remote, established)
+getph1(ph1hint, local, remote, flags)
+	struct ph1handle *ph1hint;
 	struct sockaddr *local, *remote;
-	int established;
+	int flags;
 {
 	struct ph1handle *p;
 
-	plog(LLV_DEBUG2, LOCATION, NULL, "getph1byaddr: start\n");
+	plog(LLV_DEBUG2, LOCATION, NULL, "getph1: start\n");
 	plog(LLV_DEBUG2, LOCATION, NULL, "local: %s\n", saddr2str(local));
 	plog(LLV_DEBUG2, LOCATION, NULL, "remote: %s\n", saddr2str(remote));
 
 	LIST_FOREACH(p, &ph1tree, chain) {
-		if (p->status == PHASE1ST_EXPIRED)
+		if (p->status >= PHASE1ST_DYING)
 			continue;
+
 		plog(LLV_DEBUG2, LOCATION, NULL, "p->local: %s\n", saddr2str(p->local));
 		plog(LLV_DEBUG2, LOCATION, NULL, "p->remote: %s\n", saddr2str(p->remote));
 
-		if(established && p->status != PHASE1ST_ESTABLISHED){
-			plog(LLV_DEBUG2, LOCATION, NULL, "status %d, skipping\n", p->status);
+		if ((flags & GETPH1_F_ESTABLISHED) &&
+		    (p->status != PHASE1ST_ESTABLISHED)) {
+			plog(LLV_DEBUG2, LOCATION, NULL,
+			     "status %d, skipping\n", p->status);
 			continue;
 		}
-		if (CMPSADDR(local, p->local) == 0
-			&& CMPSADDR(remote, p->remote) == 0){
-			plog(LLV_DEBUG2, LOCATION, NULL, "matched\n");
-			return p;
+
+		if (local != NULL && cmpsaddr(local, p->local) == CMPSADDR_MISMATCH)
+			continue;
+
+		if (remote != NULL && cmpsaddr(remote, p->remote) == CMPSADDR_MISMATCH)
+			continue;
+
+		if (ph1hint != NULL) {
+			if (ph1hint->id && ph1hint->id->l && p->id && p->id->l &&
+			    (ph1hint->id->l != p->id->l ||
+			     memcmp(ph1hint->id->v, p->id->v, p->id->l) != 0)) {
+				plog(LLV_DEBUG2, LOCATION, NULL,
+				     "local identity does match hint\n");
+				continue;
+			}
+			if (ph1hint->id_p && ph1hint->id_p->l &&
+			    p->id_p && p->id_p->l &&
+			    (ph1hint->id_p->l != p->id_p->l ||
+			     memcmp(ph1hint->id_p->v, p->id_p->v, p->id_p->l) != 0)) {
+				plog(LLV_DEBUG2, LOCATION, NULL,
+				     "remote identity does match hint\n");
+				continue;
+			}
 		}
+
+		plog(LLV_DEBUG2, LOCATION, NULL, "matched\n");
+		return p;
 	}
 
 	plog(LLV_DEBUG2, LOCATION, NULL, "no match\n");
@@ -174,44 +235,78 @@
 	return NULL;
 }
 
-struct ph1handle *
-getph1byaddrwop(local, remote)
-	struct sockaddr *local, *remote;
+int
+resolveph1rmconf(iph1)
+	struct ph1handle *iph1;
 {
-	struct ph1handle *p;
+	struct remoteconf *rmconf;
 
-	LIST_FOREACH(p, &ph1tree, chain) {
-		if (p->status == PHASE1ST_EXPIRED)
-			continue;
-		if (cmpsaddrwop(local, p->local) == 0
-		 && cmpsaddrwop(remote, p->remote) == 0)
-			return p;
+	/* INITIATOR is always expected to know the exact rmconf. */
+	if (iph1->side == INITIATOR)
+		return 0;
+
+	rmconf = getrmconf_by_ph1(iph1);
+	if (rmconf == NULL)
+		return -1;
+	if (rmconf == RMCONF_ERR_MULTIPLE)
+		return 1;
+
+	if (iph1->rmconf != NULL) {
+		if (rmconf != iph1->rmconf) {
+			plog(LLV_ERROR, LOCATION, NULL,
+			     "unexpected rmconf switch; killing ph1\n");
+			return -1;
+		}
+	} else {
+		iph1->rmconf = rmconf;
 	}
 
-	return NULL;
+	return 0;
+}
+
+
+/*
+ * move phase2s from old_iph1 to new_iph1
+ */
+void
+migrate_ph12(old_iph1, new_iph1)
+	struct ph1handle *old_iph1, *new_iph1;
+{
+	struct ph2handle *p, *next;
+
+	/* Relocate phase2s to better phase1s or request a new phase1. */
+	for (p = LIST_FIRST(&old_iph1->ph2tree); p; p = next) {
+		next = LIST_NEXT(p, ph1bind);
+
+		if (p->status != PHASE2ST_ESTABLISHED)
+			continue;
+
+		unbindph12(p);
+		bindph12(new_iph1, p);
+	}
 }
 
 /*
- * search for isakmpsa handler by remote address.
- * don't use port number to search because this function search
- * with phase 2's destinaion.
+ * the iph1 is new, migrate all phase2s that belong to a dying or dead ph1
  */
-struct ph1handle *
-getph1bydstaddrwop(remote)
-	struct sockaddr *remote;
+void migrate_dying_ph12(iph1)
+	struct ph1handle *iph1;
 {
 	struct ph1handle *p;
 
 	LIST_FOREACH(p, &ph1tree, chain) {
-		if (p->status == PHASE1ST_EXPIRED)
+		if (p == iph1)
 			continue;
-		if (cmpsaddrwop(remote, p->remote) == 0)
-			return p;
-	}
+		if (p->status < PHASE1ST_DYING)
+			continue;
 
-	return NULL;
+		if (cmpsaddr(iph1->local, p->local) == CMPSADDR_MATCH
+		 && cmpsaddr(iph1->remote, p->remote) == CMPSADDR_MATCH)
+			migrate_ph12(p, iph1);
+	}
 }
 
+
 /*
  * dump isakmp-sa
  */
@@ -268,11 +363,10 @@
 
 #ifdef ENABLE_DPD
 	iph1->dpd_support = 0;
-	iph1->dpd_lastack = 0;
 	iph1->dpd_seq = 0;
 	iph1->dpd_fails = 0;
-	iph1->dpd_r_u = NULL;
 #endif
+	evt_list_init(&iph1->evt_listeners);
 
 	return iph1;
 }
@@ -289,8 +383,7 @@
 
 	/* SA down shell script hook */
 	script_hook(iph1, SCRIPT_PHASE1_DOWN);
-
-	EVT_PUSH(iph1->local, iph1->remote, EVTT_PHASE1_DOWN, NULL);
+	evt_list_cleanup(&iph1->evt_listeners);
 
 #ifdef ENABLE_NATT
 	if (iph1->natt_flags & NAT_KA_QUEUED)
@@ -308,8 +401,10 @@
 #endif
 
 #ifdef ENABLE_DPD
-	SCHED_KILL(iph1->dpd_r_u);
+	sched_cancel(&iph1->dpd_r_u);
 #endif
+	sched_cancel(&iph1->sce);
+	sched_cancel(&iph1->scr);
 
 	if (iph1->remote) {
 		racoon_free(iph1->remote);
@@ -325,13 +420,7 @@
 	}
 
 	VPTRINIT(iph1->authstr);
-
-	sched_scrub_param(iph1);
-	iph1->sce = NULL;
-	iph1->scr = NULL;
-
 	VPTRINIT(iph1->sendbuf);
-
 	VPTRINIT(iph1->dhpriv);
 	VPTRINIT(iph1->dhpub);
 	VPTRINIT(iph1->dhpub_p);
@@ -346,14 +435,10 @@
 	VPTRINIT(iph1->hash);
 	VPTRINIT(iph1->sig);
 	VPTRINIT(iph1->sig_p);
-	oakley_delcert(iph1->cert);
-	iph1->cert = NULL;
-	oakley_delcert(iph1->cert_p);
-	iph1->cert_p = NULL;
-	oakley_delcert(iph1->crl_p);
-	iph1->crl_p = NULL;
-	oakley_delcert(iph1->cr_p);
-	iph1->cr_p = NULL;
+	VPTRINIT(iph1->cert);
+	VPTRINIT(iph1->cert_p);
+	VPTRINIT(iph1->crl_p);
+	VPTRINIT(iph1->cr_p);
 	VPTRINIT(iph1->id);
 	VPTRINIT(iph1->id_p);
 
@@ -415,7 +500,7 @@
 		next = LIST_NEXT(p, chain);
 
 		/* send delete information */
-		if (p->status == PHASE1ST_ESTABLISHED) 
+		if (p->status >= PHASE1ST_ESTABLISHED)
 			isakmp_info_send_d1(p);
 
 		remph1(p);
@@ -429,26 +514,52 @@
 	LIST_INIT(&ph1tree);
 }
 
+int
+ph1_rekey_enabled(iph1)
+	struct ph1handle *iph1;
+{
+	if (iph1->rmconf == NULL)
+		return 0;
+	if (iph1->rmconf->rekey == REKEY_FORCE)
+		return 1;
+#ifdef ENABLE_DPD
+	if (iph1->rmconf->rekey == REKEY_ON && iph1->dpd_support &&
+	    iph1->rmconf->dpd_interval)
+		return 1;
+#endif
+	return 0;
+}
+
 /* %%% management phase 2 handler */
-/*
- * search ph2handle with policy id.
- */
-struct ph2handle *
-getph2byspid(spid)
-      u_int32_t spid;
+
+int
+enumph2(sel, enum_func, enum_arg)
+	struct ph2selector *sel;
+	int (*enum_func)(struct ph2handle *ph2, void *arg);
+	void *enum_arg;
 {
 	struct ph2handle *p;
+	int ret;
 
 	LIST_FOREACH(p, &ph2tree, chain) {
-		/*
-		 * there are ph2handle independent on policy
-		 * such like informational exchange.
-		 */
-		if (p->spid == spid)
-			return p;
+		if (sel != NULL) {
+			if (sel->spid != 0 && sel->spid != p->spid)
+				continue;
+
+			if (sel->src != NULL &&
+			    cmpsaddr(sel->src, p->src) != CMPSADDR_MATCH)
+				continue;
+
+			if (sel->dst != NULL &&
+			    cmpsaddr(sel->dst, p->dst) != CMPSADDR_MATCH)
+				continue;
+		}
+
+		if ((ret = enum_func(p, enum_arg)) != 0)
+			return ret;
 	}
 
-	return NULL;
+	return 0;
 }
 
 /*
@@ -478,7 +589,7 @@
 {
 	struct ph2handle *p;
 
-	LIST_FOREACH(p, &ph2tree, chain) {
+	LIST_FOREACH(p, &iph1->ph2tree, ph1bind) {
 		if (p->msgid == msgid && p->ph1 == iph1)
 			return p;
 	}
@@ -486,6 +597,15 @@
 	return NULL;
 }
 
+/* Note that src and dst are not the selectors of the SP
+ * but the source and destination addresses used for
+ * for SA negotiation (best example is tunnel mode SA
+ * where src and dst are the endpoints). There is at most
+ * a unique match because racoon does not support bundles
+ * which makes that there is at most a single established
+ * SA for a given spid. One could say that src and dst
+ * are in fact useless ...
+ */
 struct ph2handle *
 getph2byid(src, dst, spid)
 	struct sockaddr *src, *dst;
@@ -495,8 +615,8 @@
 
 	LIST_FOREACH(p, &ph2tree, chain) {
 		if (spid == p->spid &&
-		    CMPSADDR(src, p->src) == 0 &&
-		    CMPSADDR(dst, p->dst) == 0){
+		    cmpsaddr(src, p->src) <= CMPSADDR_WILDPORT_MATCH &&
+		    cmpsaddr(dst, p->dst) <= CMPSADDR_WILDPORT_MATCH){
 			/* Sanity check to detect zombie handlers
 			 * XXX Sould be done "somewhere" more interesting,
 			 * because we have lots of getph2byxxxx(), but this one
@@ -504,7 +624,7 @@
 			 */
 			if(p->status < PHASE2ST_ESTABLISHED &&
 			   p->retry_counter == 0
-			   && p->sce == NULL && p->scr == NULL){
+			   && p->sce.func == NULL && p->scr.func == NULL) {
 				plog(LLV_DEBUG, LOCATION, NULL,
 					 "Zombie ph2 found, expiring it\n");
 				isakmp_ph2expire(p);
@@ -523,8 +643,8 @@
 	struct ph2handle *p;
 
 	LIST_FOREACH(p, &ph2tree, chain) {
-		if (cmpsaddrstrict(src, p->src) == 0 &&
-		    cmpsaddrstrict(dst, p->dst) == 0)
+		if (cmpsaddr(src, p->src) <= CMPSADDR_WILDPORT_MATCH &&
+		    cmpsaddr(dst, p->dst) <= CMPSADDR_WILDPORT_MATCH)
 			return p;
 	}
 
@@ -582,6 +702,7 @@
 		return NULL;
 
 	iph2->status = PHASE1ST_SPAWN;
+	evt_list_init(&iph2->evt_listeners);
 
 	return iph2;
 }
@@ -595,9 +716,11 @@
 initph2(iph2)
 	struct ph2handle *iph2;
 {
-	sched_scrub_param(iph2);
-	iph2->sce = NULL;
-	iph2->scr = NULL;
+	evt_list_cleanup(&iph2->evt_listeners);
+	unbindph12(iph2);
+
+	sched_cancel(&iph2->sce);
+	sched_cancel(&iph2->scr);
 
 	VPTRINIT(iph2->sendbuf);
 	VPTRINIT(iph2->msg1);
@@ -642,6 +765,17 @@
 		oakley_delivm(iph2->ivm);
 		iph2->ivm = NULL;
 	}
+
+#ifdef ENABLE_NATT
+	if (iph2->natoa_src) {
+		racoon_free(iph2->natoa_src);
+		iph2->natoa_src = NULL;
+	}
+	if (iph2->natoa_dst) {
+		racoon_free(iph2->natoa_dst);
+		iph2->natoa_dst = NULL;
+	}
+#endif
 }
 
 /*
@@ -661,14 +795,24 @@
 		racoon_free(iph2->dst);
 		iph2->dst = NULL;
 	}
-	if (iph2->src_id) {
-	      racoon_free(iph2->src_id);
-	      iph2->src_id = NULL;
+	if (iph2->sa_src) {
+		racoon_free(iph2->sa_src);
+		iph2->sa_src = NULL;
 	}
-	if (iph2->dst_id) {
-	      racoon_free(iph2->dst_id);
-	      iph2->dst_id = NULL;
+	if (iph2->sa_dst) {
+		racoon_free(iph2->sa_dst);
+		iph2->sa_dst = NULL;
 	}
+#ifdef ENABLE_NATT
+	if (iph2->natoa_src) {
+		racoon_free(iph2->natoa_src);
+		iph2->natoa_src = NULL;
+	}
+	if (iph2->natoa_dst) {
+		racoon_free(iph2->natoa_dst);
+		iph2->natoa_dst = NULL;
+	}
+#endif
 
 	if (iph2->proposal) {
 		flushsaprop(iph2->proposal);
@@ -694,6 +838,7 @@
 remph2(iph2)
 	struct ph2handle *iph2;
 {
+	unbindph12(iph2);
 	LIST_REMOVE(iph2, chain);
 }
 
@@ -725,7 +870,6 @@
 		}
 
 		delete_spd(p, 0);
-		unbindph12(p);
 		remph2(p);
 		delph2(p);
 	}
@@ -763,7 +907,6 @@
 		}
 		continue;
  zap_it:
-		unbindph12(iph2);
 		remph2(iph2);
 		delph2(iph2);
 	}
@@ -775,7 +918,10 @@
 	struct ph1handle *iph1;
 	struct ph2handle *iph2;
 {
+	unbindph12(iph2);
+
 	iph2->ph1 = iph1;
+	iph1->ph2cnt++;
 	LIST_INSERT_HEAD(&iph1->ph2tree, iph2, ph1bind);
 }
 
@@ -784,8 +930,9 @@
 	struct ph2handle *iph2;
 {
 	if (iph2->ph1 != NULL) {
-		iph2->ph1 = NULL;
 		LIST_REMOVE(iph2, ph1bind);
+		iph2->ph1->ph2cnt--;
+		iph2->ph1 = NULL;
 	}
 }
 
@@ -800,7 +947,7 @@
 	struct contacted *p;
 
 	LIST_FOREACH(p, &ctdtree, chain) {
-		if (cmpsaddrstrict(remote, p->remote) == 0)
+		if (cmpsaddr(remote, p->remote) <= CMPSADDR_WILDPORT_MATCH)
 			return p;
 	}
 
@@ -835,6 +982,22 @@
 }
 
 void
+remcontacted(remote)
+	struct sockaddr *remote;
+{
+	struct contacted *p;
+
+	LIST_FOREACH(p, &ctdtree, chain) {
+		if (cmpsaddr(remote, p->remote) <= CMPSADDR_WILDPORT_MATCH) {
+			LIST_REMOVE(p, chain);
+			racoon_free(p->remote);
+			racoon_free(p);
+			break;
+		}
+	}	
+}
+
+void
 initctdtree()
 {
 	LIST_INIT(&ctdtree);
@@ -856,12 +1019,9 @@
 {
 	vchar_t *hash;
 	struct recvdpkt *r;
-	time_t t;
+	struct timeval now, diff;
 	int len, s;
 
-	/* set current time */
-	t = time(NULL);
-
 	hash = eay_md5_one(rbuf);
 	if (!hash) {
 		plog(LLV_ERROR, LOCATION, NULL,
@@ -882,7 +1042,7 @@
 	/*
 	 * the packet was processed before, but the remote address mismatches.
 	 */
-	if (cmpsaddrstrict(remote, r->remote) != 0)
+	if (cmpsaddr(remote, r->remote) != CMPSADDR_MATCH)
 		return 2;
 
 	/*
@@ -891,7 +1051,9 @@
 	 */
 
 	/* check the previous time to send */
-	if (t - r->time_send < 1) {
+	sched_get_monotonic_time(&now);
+	timersub(&now, &r->time_send, &diff);
+	if (diff.tv_sec == 0) {
 		plog(LLV_WARNING, LOCATION, NULL,
 			"the packet retransmitted in a short time from %s\n",
 			saddr2str(remote));
@@ -899,7 +1061,7 @@
 	}
 
 	/* select the socket to be sent */
-	s = getsockmyaddr(r->local);
+	s = myaddr_getfd(r->local);
 	if (s == -1)
 		return -1;
 
@@ -920,7 +1082,7 @@
 			"deleted the retransmission packet to %s.\n",
 			saddr2str(remote));
 	} else
-		r->time_send = t;
+		r->time_send = now;
 
 	return 1;
 }
@@ -977,8 +1139,7 @@
 	}
 
 	new->retry_counter = lcconf->retry_counter;
-	new->time_send = 0;
-	new->created = time(NULL);
+	sched_get_monotonic_time(&new->time_send);
 
 	LIST_INSERT_HEAD(&rcptree, new, chain);
 
@@ -1007,29 +1168,30 @@
 	LIST_REMOVE(r, chain);
 }
 
-void
+static void
 sweep_recvdpkt(dummy)
-	void *dummy;
+	struct sched *dummy;
 {
 	struct recvdpkt *r, *next;
-	time_t t, lt;
+	struct timeval now, diff, sweep;
 
-	/* set current time */
-	t = time(NULL);
+	sched_get_monotonic_time(&now);
 
-	/* set the lifetime of the retransmission */
-	lt = lcconf->retry_counter * lcconf->retry_interval;
+	/* calculate sweep time; delete entries older than this */
+	diff.tv_sec = lcconf->retry_counter * lcconf->retry_interval;
+	diff.tv_usec = 0;
+	timersub(&now, &diff, &sweep);
 
 	for (r = LIST_FIRST(&rcptree); r; r = next) {
 		next = LIST_NEXT(r, chain);
 
-		if (t - r->created > lt) {
+		if (timercmp(&r->time_send, &sweep, <)) {
 			rem_recvdpkt(r);
 			del_recvdpkt(r);
 		}
 	}
 
-	sched_new(lt, sweep_recvdpkt, NULL);
+	sched_schedule(&sc_sweep, diff.tv_sec, sweep_recvdpkt);
 }
 
 void
@@ -1039,11 +1201,11 @@
 
 	LIST_INIT(&rcptree);
 
-	sched_new(lt, sweep_recvdpkt, NULL);
+	sched_schedule(&sc_sweep, lt, sweep_recvdpkt);
 }
 
 #ifdef ENABLE_HYBRID
-/* 
+/*
  * Retruns 0 if the address was obtained by ISAKMP mode config, 1 otherwise
  * This should be in isakmp_cfg.c but ph1tree being private, it must be there
  */
@@ -1070,7 +1232,7 @@
 
 
 
-/* 
+/*
  * Reload conf code
  */
 static int revalidate_ph2(struct ph2handle *iph2){
@@ -1080,19 +1242,19 @@
 	struct saprop *approval;
 	struct ph1handle *iph1;
 
-	/* 
+	/*
 	 * Get the new sainfo using values of the old one
 	 */
 	if (iph2->sainfo != NULL) {
-		iph2->sainfo = getsainfo(iph2->sainfo->idsrc, 
+		iph2->sainfo = getsainfo(iph2->sainfo->idsrc,
 					  iph2->sainfo->iddst, iph2->sainfo->id_i,
-					  iph2->sainfo->remoteid);
+					  NULL, iph2->sainfo->remoteid);
 	}
 	approval = iph2->approval;
 	sainfo = iph2->sainfo;
 
 	if (sainfo == NULL) {
-		/* 
+		/*
 		 * Sainfo has been removed
 		 */
 		plog(LLV_DEBUG, LOCATION, NULL,
@@ -1107,7 +1269,7 @@
 		plog(LLV_DEBUG, LOCATION, NULL,
 			 "No approval found !\n");
 		return 0;
-	}	
+	}
 
 	/*
 	 * Don't care about proposals, should we do something ?
@@ -1206,7 +1368,7 @@
 	}
 
 	found = 0;
-	for (alg = sainfo->algs[algclass_ipsec_enc]; 
+	for (alg = sainfo->algs[algclass_ipsec_enc];
 	    (found == 0 && alg != NULL); alg = alg->next) {
 		plog(LLV_DEBUG, LOCATION, NULL,
 			 "Reload: next ph2 enc alg...\n");
@@ -1239,7 +1401,7 @@
 			break;
 
 		default:
-			plog(LLV_ERROR, LOCATION, NULL, 
+			plog(LLV_ERROR, LOCATION, NULL,
 			    "unexpected check_level\n");
 			continue;
 			break;
@@ -1263,7 +1425,7 @@
 }
 
 
-static void 
+static void
 remove_ph2(struct ph2handle *iph2)
 {
 	u_int32_t spis[2];
@@ -1289,7 +1451,6 @@
 		purge_ipsec_spi(iph2->dst, iph2->approval->head->proto_id,
 						spis, 2);
 	}else{
-		unbindph12(iph2);
 		remph2(iph2);
 		delph2(iph2);
 	}
@@ -1304,197 +1465,41 @@
 	plog(LLV_DEBUG, LOCATION, NULL,
 		 "Removing PH1...\n");
 
-	if (iph1->status == PHASE1ST_ESTABLISHED){
+	if (iph1->status == PHASE1ST_ESTABLISHED ||
+	    iph1->status == PHASE1ST_DYING) {
 		for (iph2 = LIST_FIRST(&iph1->ph2tree); iph2; iph2 = iph2_next) {
-			iph2_next = LIST_NEXT(iph2, chain);
+			iph2_next = LIST_NEXT(iph2, ph1bind);
 			remove_ph2(iph2);
 		}
 		isakmp_info_send_d1(iph1);
 	}
 	iph1->status = PHASE1ST_EXPIRED;
-	iph1->sce = sched_new(1, isakmp_ph1delete_stub, iph1);
+	/* directly call isakmp_ph1delete to avoid as possible a race
+	 * condition where we'll try to access iph1->rmconf after it has
+	 * freed
+	 */
+	isakmp_ph1delete(iph1);
 }
 
 
-static int revalidate_ph1tree_rmconf(void){
+static int revalidate_ph1tree_rmconf(void)
+{
 	struct ph1handle *p, *next;
-	struct remoteconf *newrmconf;
+	struct remoteconf *rmconf;
 
 	for (p = LIST_FIRST(&ph1tree); p; p = next) {
 		next = LIST_NEXT(p, chain);
 
-		if (p->status == PHASE1ST_EXPIRED)
+		if (p->status >= PHASE1ST_EXPIRED)
+			continue;
+		if (p->rmconf == NULL)
 			continue;
 
-		newrmconf=getrmconf(p->remote);
-		if(newrmconf == NULL){
-			p->rmconf = NULL;
+		rmconf = getrmconf_by_ph1(p);
+		if (rmconf == NULL || rmconf == RMCONF_ERR_MULTIPLE)
 			remove_ph1(p);
-		}else{
-			/* Do not free old rmconf, it is just a pointer to an entry in rmtree
-			 */
-			p->rmconf=newrmconf;
-			if(p->approval != NULL){
-				struct isakmpsa *tmpsa;
-
-				tmpsa=dupisakmpsa(p->approval);
-				if(tmpsa != NULL){
-					delisakmpsa(p->approval);
-					p->approval=tmpsa;
-					p->approval->rmconf=newrmconf;
-				}
-			}
-		}
-	}
-
-	return 1;
-}
-
-
-/* rmconf is already updated here
- */
-static int revalidate_ph1(struct ph1handle *iph1){
-	struct isakmpsa *p, *approval;
-	struct etypes *e;
-
-	if(iph1 == NULL ||
-	   iph1->approval == NULL ||
-		iph1->rmconf == NULL)
-		return 0;
-
-	approval=iph1->approval;
-
-	for (e = iph1->rmconf->etypes; e != NULL; e = e->next){
-		if (iph1->etype == e->type)
-			break;
-	}
-
-	if (e == NULL){
-		plog(LLV_DEBUG, LOCATION, NULL,
-			 "Reload: Exchange type mismatch\n");
-		return 0;
-	}
-
-	if (iph1->etype == ISAKMP_ETYPE_AGG &&
-	   approval->dh_group != iph1->rmconf->dh_group){
-		plog(LLV_DEBUG, LOCATION, NULL,
-			 "Reload: DH mismatch\n");
-		return 0;
-	}
-
-	for (p=iph1->rmconf->proposal; p != NULL; p=p->next){
-		plog(LLV_DEBUG, LOCATION, NULL,
-			 "Reload: Trying next proposal...\n");
-
-		if(approval->authmethod != p->authmethod){
-			plog(LLV_DEBUG, LOCATION, NULL,
-				 "Reload: Authmethod mismatch\n");
-			continue;
-		}
-
-		if(approval->enctype != p->enctype){
-			plog(LLV_DEBUG, LOCATION, NULL,
-				 "Reload: enctype mismatch\n");
-			continue;
-		}
-
-		switch (iph1->rmconf->pcheck_level) {
-		case PROP_CHECK_OBEY:
-			plog(LLV_DEBUG, LOCATION, NULL,
-				 "Reload: OBEY pcheck level, ok...\n");
-			return 1;
-			break;
-
-		case PROP_CHECK_CLAIM:
-			/* FALLTHROUGH */
-		case PROP_CHECK_STRICT:
-			if (approval->encklen < p->encklen) {
-				plog(LLV_DEBUG, LOCATION, NULL,
-					 "Reload: encklen mismatch\n");
-				continue;
-			}
-
-			if (approval->lifetime > p->lifetime) {
-				plog(LLV_DEBUG, LOCATION, NULL,
-					 "Reload: lifetime mismatch\n");
-				continue;
-			}
-
-#if 0
-			/* Lifebyte is deprecated, just ignore it
-			 */
-			if (approval->lifebyte > p->lifebyte) {
-				plog(LLV_DEBUG, LOCATION, NULL,
-					 "Reload: lifebyte mismatch\n");
-				continue;
-			}
-#endif
-			break;
-
-		case PROP_CHECK_EXACT:
-			if (approval->encklen != p->encklen) {
-				plog(LLV_DEBUG, LOCATION, NULL,
-					 "Reload: encklen mismatch\n");
-				continue;
-			}
-
-			if (approval->lifetime != p->lifetime) {
-				plog(LLV_DEBUG, LOCATION, NULL,
-					 "Reload: lifetime mismatch\n");
-				continue;
-			}
-
-#if 0
-			/* Lifebyte is deprecated, just ignore it
-			 */
-			if (approval->lifebyte != p->lifebyte) {
-				plog(LLV_DEBUG, LOCATION, NULL,
-					 "Reload: lifebyte mismatch\n");
-				continue;
-			}
-#endif
-			break;
-
-		default:
-			plog(LLV_ERROR, LOCATION, NULL, 
-			    "unexpected check_level\n");
-			continue;
-			break;
-		}
-
-		if (approval->hashtype != p->hashtype) {
-			plog(LLV_DEBUG, LOCATION, NULL,
-				 "Reload: hashtype mismatch\n");
-			continue;
-		}
-
-		if (iph1->etype != ISAKMP_ETYPE_AGG &&
-		    approval->dh_group != p->dh_group) {
-			plog(LLV_DEBUG, LOCATION, NULL,
-				 "Reload: dhgroup mismatch\n");
-			continue;
-		}
-
-		plog(LLV_DEBUG, LOCATION, NULL, "Reload: Conf ok\n");
-		return 1;
-	}
-
-	plog(LLV_DEBUG, LOCATION, NULL, "Reload: No valid conf found\n");
-	return 0;
-}
-
-
-static int revalidate_ph1tree(void){
-	struct ph1handle *p, *next;
-
-	for (p = LIST_FIRST(&ph1tree); p; p = next) {
-		next = LIST_NEXT(p, chain);
-
-		if (p->status == PHASE1ST_EXPIRED)
-			continue;
-
-		if(!revalidate_ph1(p))
-			remove_ph1(p);
+		else
+			p->rmconf = rmconf;
 	}
 
 	return 1;
@@ -1519,14 +1524,12 @@
 	return 1;
 }
 
-int 
+int
 revalidate_ph12(void)
 {
 
 	revalidate_ph1tree_rmconf();
-
 	revalidate_ph2tree();
-	revalidate_ph1tree();
 
 	return 1;
 }
@@ -1559,7 +1562,10 @@
 		if (p->mode_cfg == NULL)
 			continue;
 		if (strncmp(p->mode_cfg->login, login, LOGINLEN) == 0) {
-			if (p->status == PHASE1ST_ESTABLISHED)
+			if (p->status >= PHASE1ST_EXPIRED)
+				continue;
+
+			if (p->status >= PHASE1ST_ESTABLISHED)
 				isakmp_info_send_d1(p);
 			purge_remote(p);
 			found++;
diff --git a/src/racoon/handler.h b/src/racoon/handler.h
index a52dc6c..45d596e 100644
--- a/src/racoon/handler.h
+++ b/src/racoon/handler.h
@@ -1,11 +1,11 @@
-/*	$NetBSD: handler.h,v 1.9.6.1 2008/01/11 14:12:01 vanhu Exp $	*/
+/*	$NetBSD: handler.h,v 1.25 2010/11/17 10:40:41 tteras Exp $	*/
 
 /* Id: handler.h,v 1.19 2006/02/25 08:25:12 manubsd Exp */
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
  * All rights reserved.
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
@@ -17,7 +17,7 @@
  * 3. Neither the name of the project nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
- * 
+ *
  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@@ -41,6 +41,8 @@
 
 #include "isakmp_var.h"
 #include "oakley.h"
+#include "schedule.h"
+#include "evt.h"
 
 /* Phase 1 handler */
 /*
@@ -93,8 +95,9 @@
 #define PHASE1ST_MSG3SENT		7
 #define PHASE1ST_MSG4RECEIVED		8
 #define PHASE1ST_ESTABLISHED		9
-#define PHASE1ST_EXPIRED		10
-#define PHASE1ST_MAX			11
+#define PHASE1ST_DYING			10
+#define PHASE1ST_EXPIRED		11
+#define PHASE1ST_MAX			12
 
 /* About address semantics in each case.
  *			initiator(addr=I)	responder(addr=R)
@@ -131,6 +134,7 @@
 	u_int8_t flags;			/* Flags */
 	u_int32_t msgid;		/* message id */
 
+	u_int32_t vendorid_mask;	/* bitmask of received supported vendor ids*/
 #ifdef ENABLE_NATT
 	struct ph1natt_options *natt_options;	/* Selected NAT-T IKE version */
 	u_int32_t natt_flags;		/* NAT-T related flags */
@@ -140,9 +144,9 @@
 	struct isakmp_frag_item *frag_chain;	/* Received fragments */
 #endif
 
-	struct sched *sce;		/* schedule for expire */
+	struct sched sce;		/* schedule for expire */
 
-	struct sched *scr;		/* schedule for resend */
+	struct sched scr;		/* schedule for resend */
 	int retry_counter;		/* for resend. */
 	vchar_t *sendbuf;		/* buffer for re-sending */
 
@@ -160,10 +164,10 @@
 	vchar_t *hash;			/* HASH minus general header */
 	vchar_t *sig;			/* SIG minus general header */
 	vchar_t *sig_p;			/* peer's SIG minus general header */
-	cert_t *cert;			/* CERT minus general header */
-	cert_t *cert_p;			/* peer's CERT minus general header */
-	cert_t *crl_p;			/* peer's CRL minus general header */
-	cert_t *cr_p;			/* peer's CR not including general */
+	vchar_t *cert;			/* CERT minus general header */
+	vchar_t *cert_p;		/* peer's CERT minus general header */
+	vchar_t *crl_p;			/* peer's CRL minus general header */
+	vchar_t *cr_p;			/* peer's CR not including general */
 	RSA *rsa;			/* my RSA key */
 	RSA *rsa_p;			/* peer's RSA key */
 	struct genlist *rsa_candidates;	/* possible candidates for peer's RSA key */
@@ -190,6 +194,7 @@
 	struct isakmp_pl_hash *pl_hash;	/* pointer to hash payload */
 
 	time_t created;			/* timestamp for establish */
+	int initial_contact_received;	/* set if initial contact received */
 #ifdef ENABLE_STATS
 	struct timeval start;
 	struct timeval end;
@@ -197,10 +202,10 @@
 
 #ifdef ENABLE_DPD
 	int		dpd_support;	/* Does remote supports DPD ? */
-	time_t		dpd_lastack;	/* Last ack received */
-	u_int16_t	dpd_seq;		/* DPD seq number to receive */
+	u_int32_t	dpd_last_ack;
+	u_int32_t	dpd_seq;		/* DPD seq number to receive */
 	u_int8_t	dpd_fails;		/* number of failures */
-	struct sched	*dpd_r_u;
+	struct sched	dpd_r_u;
 #endif
 
 	u_int32_t msgid2;		/* msgid counter for Phase 2 */
@@ -210,8 +215,14 @@
 	LIST_ENTRY(ph1handle) chain;
 #ifdef ENABLE_HYBRID
 	struct isakmp_cfg_state *mode_cfg;	/* ISAKMP mode config state */
-#endif       
+#endif
+	EVT_LISTENER_LIST(evt_listeners);
+};
 
+/* For limiting enumeration of ph1 tree */
+struct ph1selector {
+	struct sockaddr *local;
+	struct sockaddr *remote;
 };
 
 /* Phase 2 handler */
@@ -244,23 +255,44 @@
 #define PHASE2ST_MAX		11
 
 struct ph2handle {
-	struct sockaddr *src;		/* my address of SA. */
-	struct sockaddr *dst;		/* peer's address of SA. */
+	/* source and destination addresses used for IKE exchange. Might
+	 * differ from source and destination of SA. On the initiator,
+	 * they are tweaked if a hint is available in the SPD (set by
+	 * MIGRATE for instance). Otherwise they are the source and
+	 * destination of SA for transport mode and the tunnel endpoints
+	 * for tunnel mode */
+	struct sockaddr *src;
+	struct sockaddr *dst;
 
-		/*
-		 * copy ip address from ID payloads when ID type is ip address.
-		 * In other case, they must be null.
-		 */
-	struct sockaddr *src_id;
-	struct sockaddr *dst_id;
+	/* source and destination addresses of the SA in the case addresses
+	 * used for IKE exchanges (src and dst) do differ. On the initiator,
+	 * they are set (if needed) in pk_recvacquire(). On the responder,
+	 * they are _derived_ from the local and remote parameters of the
+	 * SP, if available. */
+	struct sockaddr *sa_src;
+	struct sockaddr *sa_dst;
+
+	/* Store our Phase 2 ID and the peer ID (ID minus general header).
+	 * On the initiator, they are set during ACQUIRE processing.
+	 * On the responder, they are set from the content of ID payload
+	 * in quick_r1recv(). Then, if they are of type address or
+	 * tunnel, they are compared to sainfo selectors.
+	 */
+	vchar_t *id;			/* ID minus gen header */
+	vchar_t *id_p;			/* peer's ID minus general header */
+
+#ifdef ENABLE_NATT
+	struct sockaddr *natoa_src;	/* peer's view of my address */
+	struct sockaddr *natoa_dst;	/* peer's view of his address */
+#endif
 
 	u_int32_t spid;			/* policy id by kernel */
 
 	int status;			/* ipsec sa status */
 	u_int8_t side;			/* INITIATOR or RESPONDER */
 
-	struct sched *sce;		/* schedule for expire */
-	struct sched *scr;		/* schedule for resend */
+	struct sched sce;		/* schedule for expire */
+	struct sched scr;		/* schedule for resend */
 	int retry_counter;		/* for resend. */
 	vchar_t *sendbuf;		/* buffer for re-sending */
 	vchar_t *msg1;			/* buffer for re-sending */
@@ -288,6 +320,8 @@
 	struct sainfo *sainfo;		/* place holder of sainfo */
 	struct saprop *proposal;	/* SA(s) proposal. */
 	struct saprop *approval;	/* SA(s) approved. */
+	u_int32_t lifetime_secs;	/* responder lifetime (seconds) */
+	u_int32_t lifetime_kb;		/* responder lifetime (kbytes) */
 	caddr_t spidx_gen;		/* policy from peer's proposal */
 
 	struct dhgroup *pfsgrp;		/* DH; prime number */
@@ -295,8 +329,6 @@
 	vchar_t *dhpub;			/* DH; public value */
 	vchar_t *dhpub_p;		/* DH; partner's public value */
 	vchar_t *dhgxy;			/* DH; shared secret */
-	vchar_t *id;			/* ID minus gen header */
-	vchar_t *id_p;			/* peer's ID minus general header */
 	vchar_t *nonce;			/* nonce value in phase 2 */
 	vchar_t *nonce_p;		/* partner's nonce value in phase 2 */
 
@@ -320,6 +352,14 @@
 
 	LIST_ENTRY(ph2handle) chain;
 	LIST_ENTRY(ph2handle) ph1bind;	/* chain to ph1handle */
+	EVT_LISTENER_LIST(evt_listeners);
+};
+
+/* For limiting enumeration of ph2 tree */
+struct ph2selector {
+	u_int32_t spid;
+	struct sockaddr *src;
+	struct sockaddr *dst;
 };
 
 /*
@@ -339,10 +379,7 @@
 	vchar_t *hash;			/* hash of the received packet */
 	vchar_t *sendbuf;		/* buffer for the response */
 	int retry_counter;		/* how many times to send */
-	time_t time_send;		/* timestamp to send a packet */
-	time_t created;			/* timestamp to create a queue */
-
-	struct sched *scr;		/* schedule for resend, may not used */
+	struct timeval time_send;	/* timestamp of previous send */
 
 	LIST_ENTRY(recvdpkt) chain;
 };
@@ -413,7 +450,7 @@
 	struct sockaddr_storage remote;
 	struct sockaddr_storage local;
 	u_int8_t version;
-	u_int8_t etype;	
+	u_int8_t etype;
 	time_t created;
 	int ph2cnt;
 };
@@ -425,25 +462,42 @@
 
 extern struct ph1handle *getph1byindex __P((isakmp_index *));
 extern struct ph1handle *getph1byindex0 __P((isakmp_index *));
-extern struct ph1handle *getph1byaddr __P((struct sockaddr *,
-										   struct sockaddr *, int));
-extern struct ph1handle *getph1byaddrwop __P((struct sockaddr *,
-	struct sockaddr *));
-extern struct ph1handle *getph1bydstaddrwop __P((struct sockaddr *));
+
+extern int enumph1 __P((struct ph1selector *ph1sel,
+			int (* enum_func)(struct ph1handle *iph1, void *arg),
+			void *enum_arg));
+
+#define GETPH1_F_ESTABLISHED		0x0001
+
+extern struct ph1handle *getph1 __P((struct ph1handle *ph1hint,
+				     struct sockaddr *local,
+				     struct sockaddr *remote,
+				     int flags));
+
+#define getph1byaddr(local, remote, est) \
+	getph1(NULL, local, remote, est ? GETPH1_F_ESTABLISHED : 0)
+#define getph1bydstaddr(remote) \
+	getph1(NULL, NULL, remote, 0)
+
 #ifdef ENABLE_HYBRID
 struct ph1handle *getph1bylogin __P((char *));
 int purgeph1bylogin __P((char *));
 #endif
+extern void migrate_ph12 __P((struct ph1handle *old_iph1, struct ph1handle *new_iph1));
+extern void migrate_dying_ph12 __P((struct ph1handle *iph1));
 extern vchar_t *dumpph1 __P((void));
 extern struct ph1handle *newph1 __P((void));
 extern void delph1 __P((struct ph1handle *));
 extern int insph1 __P((struct ph1handle *));
 extern void remph1 __P((struct ph1handle *));
+extern int resolveph1rmconf __P((struct ph1handle *));
 extern void flushph1 __P((void));
 extern void initph1tree __P((void));
+extern int ph1_rekey_enabled __P((struct ph1handle *));
 
-extern struct ph2handle *getph2byspidx __P((struct policyindex *));
-extern struct ph2handle *getph2byspid __P((u_int32_t));
+extern int enumph2 __P((struct ph2selector *ph2sel,
+			int (* enum_func)(struct ph2handle *iph2, void *arg),
+			void *enum_arg));
 extern struct ph2handle *getph2byseq __P((u_int32_t));
 extern struct ph2handle *getph2bysaddr __P((struct sockaddr *,
 	struct sockaddr *));
@@ -466,6 +520,7 @@
 
 extern struct contacted *getcontacted __P((struct sockaddr *));
 extern int inscontacted __P((struct sockaddr *));
+extern void remcontacted __P((struct sockaddr *));
 extern void initctdtree __P((void));
 
 extern int check_recvdpkt __P((struct sockaddr *,
diff --git a/src/racoon/ipsec_doi-0.7.3.c b/src/racoon/ipsec_doi-0.7.3.c
new file mode 100644
index 0000000..7ae9f67
--- /dev/null
+++ b/src/racoon/ipsec_doi-0.7.3.c
@@ -0,0 +1,5022 @@
+/*	$NetBSD: ipsec_doi.c,v 1.23.4.10 2009/06/19 07:32:52 tteras Exp $	*/
+
+/* Id: ipsec_doi.c,v 1.55 2006/08/17 09:20:41 vanhu Exp */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+
+#include PATH_IPSEC_H
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <netdb.h>
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+#  include <sys/time.h>
+# else
+#  include <time.h>
+# endif
+#endif
+
+#include "var.h"
+#include "vmbuf.h"
+#include "misc.h"
+#include "plog.h"
+#include "debug.h"
+
+#include "cfparse_proto.h"
+#include "isakmp_var.h"
+#include "isakmp.h"
+#include "ipsec_doi.h"
+#include "oakley.h"
+#include "remoteconf.h"
+#include "localconf.h"
+#include "sockmisc.h"
+#include "handler.h"
+#include "policy.h"
+#include "algorithm.h"
+#include "sainfo.h"
+#include "proposal.h"
+#include "crypto_openssl.h"
+#include "strnames.h"
+#include "gcmalloc.h"
+
+#ifdef ENABLE_NATT
+#include "nattraversal.h"
+#endif
+#ifdef ENABLE_HYBRID
+static int switch_authmethod(int);
+#endif
+
+#ifdef HAVE_GSSAPI
+#include <iconv.h>
+#include "gssapi.h"
+#ifdef HAVE_ICONV_2ND_CONST
+#define __iconv_const const
+#else
+#define __iconv_const
+#endif
+#endif
+
+int verbose_proposal_check = 1;
+
+static vchar_t *get_ph1approval __P((struct ph1handle *, struct prop_pair **));
+static struct isakmpsa *get_ph1approvalx __P((struct prop_pair *,
+	struct isakmpsa *, struct isakmpsa *, int));
+static void print_ph1mismatched __P((struct prop_pair *, struct isakmpsa *));
+static int t2isakmpsa __P((struct isakmp_pl_t *, struct isakmpsa *));
+static int cmp_aproppair_i __P((struct prop_pair *, struct prop_pair *));
+static struct prop_pair *get_ph2approval __P((struct ph2handle *,
+	struct prop_pair **));
+static struct prop_pair *get_ph2approvalx __P((struct ph2handle *,
+	struct prop_pair *));
+static void free_proppair0 __P((struct prop_pair *));
+
+static int get_transform
+	__P((struct isakmp_pl_p *, struct prop_pair **, int *));
+static u_int32_t ipsecdoi_set_ld __P((vchar_t *));
+
+static int check_doi __P((u_int32_t));
+static int check_situation __P((u_int32_t));
+
+static int check_prot_main __P((int));
+static int check_prot_quick __P((int));
+static int (*check_protocol[]) __P((int)) = {
+	check_prot_main,	/* IPSECDOI_TYPE_PH1 */
+	check_prot_quick,	/* IPSECDOI_TYPE_PH2 */
+};
+
+static int check_spi_size __P((int, int));
+
+static int check_trns_isakmp __P((int));
+static int check_trns_ah __P((int));
+static int check_trns_esp __P((int));
+static int check_trns_ipcomp __P((int));
+static int (*check_transform[]) __P((int)) = {
+	0,
+	check_trns_isakmp,	/* IPSECDOI_PROTO_ISAKMP */
+	check_trns_ah,		/* IPSECDOI_PROTO_IPSEC_AH */
+	check_trns_esp,		/* IPSECDOI_PROTO_IPSEC_ESP */
+	check_trns_ipcomp,	/* IPSECDOI_PROTO_IPCOMP */
+};
+
+static int check_attr_isakmp __P((struct isakmp_pl_t *));
+static int check_attr_ah __P((struct isakmp_pl_t *));
+static int check_attr_esp __P((struct isakmp_pl_t *));
+static int check_attr_ipsec __P((int, struct isakmp_pl_t *));
+static int check_attr_ipcomp __P((struct isakmp_pl_t *));
+static int (*check_attributes[]) __P((struct isakmp_pl_t *)) = {
+	0,
+	check_attr_isakmp,	/* IPSECDOI_PROTO_ISAKMP */
+	check_attr_ah,		/* IPSECDOI_PROTO_IPSEC_AH */
+	check_attr_esp,		/* IPSECDOI_PROTO_IPSEC_ESP */
+	check_attr_ipcomp,	/* IPSECDOI_PROTO_IPCOMP */
+};
+
+static int setph1prop __P((struct isakmpsa *, caddr_t));
+static int setph1trns __P((struct isakmpsa *, caddr_t));
+static int setph1attr __P((struct isakmpsa *, caddr_t));
+static vchar_t *setph2proposal0 __P((const struct ph2handle *,
+	const struct saprop *, const struct saproto *));
+
+static vchar_t *getidval __P((int, vchar_t *));
+
+#ifdef HAVE_GSSAPI
+static struct isakmpsa *fixup_initiator_sa __P((struct isakmpsa *,
+	struct isakmpsa *));
+#endif
+
+/*%%%*/
+/*
+ * check phase 1 SA payload.
+ * make new SA payload to be replyed not including general header.
+ * the pointer to one of isakmpsa in proposal is set into iph1->approval.
+ * OUT:
+ *	positive: the pointer to new buffer of SA payload.
+ *		  network byte order.
+ *	NULL	: error occurd.
+ */
+int
+ipsecdoi_checkph1proposal(sa, iph1)
+	vchar_t *sa;
+	struct ph1handle *iph1;
+{
+	vchar_t *newsa;		/* new SA payload approved. */
+	struct prop_pair **pair;
+
+	/* get proposal pair */
+	pair = get_proppair(sa, IPSECDOI_TYPE_PH1);
+	if (pair == NULL)
+		return -1;
+
+	/* check and get one SA for use */
+	newsa = get_ph1approval(iph1, pair);
+	
+	free_proppair(pair);
+
+	if (newsa == NULL)
+		return -1;
+
+	iph1->sa_ret = newsa;
+
+	return 0;
+}
+
+/*
+ * acceptable check for remote configuration.
+ * return a new SA payload to be reply to peer.
+ */
+static vchar_t *
+get_ph1approval(iph1, pair)
+	struct ph1handle *iph1;
+	struct prop_pair **pair;
+{
+	vchar_t *newsa;
+	struct isakmpsa *sa, tsa;
+	struct prop_pair *s, *p;
+	int prophlen;
+	int i;
+
+	if (iph1->approval) {
+		delisakmpsa(iph1->approval);
+		iph1->approval = NULL;
+	}
+
+	for (i = 0; i < MAXPROPPAIRLEN; i++) {
+		if (pair[i] == NULL)
+			continue;
+		for (s = pair[i]; s; s = s->next) {
+			prophlen = 
+			    sizeof(struct isakmp_pl_p) + s->prop->spi_size;
+
+			/* compare proposal and select one */
+			for (p = s; p; p = p->tnext) {
+				if ((sa = get_ph1approvalx(p, 
+				    iph1->rmconf->proposal, &tsa, 
+				    iph1->rmconf->pcheck_level)) != NULL)
+					goto found;
+			}
+		}
+	}
+
+	/*
+	 * if there is no suitable proposal, racoon complains about all of
+	 * mismatched items in those proposal.
+	 */
+	if (verbose_proposal_check) {
+		for (i = 0; i < MAXPROPPAIRLEN; i++) {
+			if (pair[i] == NULL)
+				continue;
+			for (s = pair[i]; s; s = s->next) {
+				prophlen = sizeof(struct isakmp_pl_p)
+						+ s->prop->spi_size;
+				for (p = s; p; p = p->tnext) {
+					print_ph1mismatched(p,
+						iph1->rmconf->proposal);
+				}
+			}
+		}
+	}
+	plog(LLV_ERROR, LOCATION, NULL, "no suitable proposal found.\n");
+
+	return NULL;
+
+found:
+	plog(LLV_DEBUG, LOCATION, NULL, "an acceptable proposal found.\n");
+
+	/* check DH group settings */
+	if (sa->dhgrp) {
+		if (sa->dhgrp->prime && sa->dhgrp->gen1) {
+			/* it's ok */
+			goto saok;
+		}
+		plog(LLV_WARNING, LOCATION, NULL,
+			"invalid DH parameter found, use default.\n");
+		oakley_dhgrp_free(sa->dhgrp);
+		sa->dhgrp=NULL;
+	}
+
+	if (oakley_setdhgroup(sa->dh_group, &sa->dhgrp) == -1) {
+		sa->dhgrp = NULL;
+		racoon_free(sa);
+		return NULL;
+	}
+
+saok:
+#ifdef HAVE_GSSAPI
+	if (sa->gssid != NULL)
+		plog(LLV_DEBUG, LOCATION, NULL, "gss id in new sa '%.*s'\n",
+		    (int)sa->gssid->l, sa->gssid->v);
+	if (iph1-> side == INITIATOR) {
+		if (iph1->rmconf->proposal->gssid != NULL)
+			iph1->gi_i = vdup(iph1->rmconf->proposal->gssid);
+		if (tsa.gssid != NULL)
+			iph1->gi_r = vdup(tsa.gssid);
+		iph1->approval = fixup_initiator_sa(sa, &tsa);
+	} else {
+		if (tsa.gssid != NULL) {
+			iph1->gi_r = vdup(tsa.gssid);
+			iph1->gi_i = gssapi_get_id(iph1);
+			if (sa->gssid == NULL && iph1->gi_i != NULL)
+				sa->gssid = vdup(iph1->gi_i);
+		}
+		iph1->approval = sa;
+	}
+	if (iph1->gi_i != NULL)
+		plog(LLV_DEBUG, LOCATION, NULL, "GIi is %.*s\n",
+		    (int)iph1->gi_i->l, iph1->gi_i->v);
+	if (iph1->gi_r != NULL)
+		plog(LLV_DEBUG, LOCATION, NULL, "GIr is %.*s\n",
+		    (int)iph1->gi_r->l, iph1->gi_r->v);
+#else
+	iph1->approval = sa;
+#endif
+	if(iph1->approval) {
+		plog(LLV_DEBUG, LOCATION, NULL, "agreed on %s auth.\n",
+		    s_oakley_attr_method(iph1->approval->authmethod));
+	}
+
+	newsa = get_sabyproppair(p, iph1);
+	if (newsa == NULL){
+		delisakmpsa(iph1->approval);
+		iph1->approval = NULL;
+	}
+
+	return newsa;
+}
+
+/*
+ * compare peer's single proposal and all of my proposal.
+ * and select one if suiatable.
+ * p       : one of peer's proposal.
+ * proposal: my proposals.
+ */
+static struct isakmpsa *
+get_ph1approvalx(p, proposal, sap, check_level)
+	struct prop_pair *p;
+	struct isakmpsa *proposal, *sap;
+	int check_level;
+{
+	struct isakmp_pl_p *prop = p->prop;
+	struct isakmp_pl_t *trns = p->trns;
+	struct isakmpsa sa, *s, *tsap;
+	int authmethod;
+
+	plog(LLV_DEBUG, LOCATION, NULL,
+       		"prop#=%d, prot-id=%s, spi-size=%d, #trns=%d\n",
+		prop->p_no, s_ipsecdoi_proto(prop->proto_id),
+		prop->spi_size, prop->num_t);
+
+	plog(LLV_DEBUG, LOCATION, NULL,
+		"trns#=%d, trns-id=%s\n",
+		trns->t_no,
+		s_ipsecdoi_trns(prop->proto_id, trns->t_id));
+
+	tsap = sap != NULL ? sap : &sa;
+
+	memset(tsap, 0, sizeof(*tsap));
+	if (t2isakmpsa(trns, tsap) < 0)
+		return NULL;
+	for (s = proposal; s != NULL; s = s->next) {
+#ifdef ENABLE_HYBRID
+		authmethod = switch_authmethod(s->authmethod);
+#else
+		authmethod = s->authmethod;
+#endif
+		plog(LLV_DEBUG, LOCATION, NULL, "Compared: DB:Peer\n");
+		plog(LLV_DEBUG, LOCATION, NULL, "(lifetime = %ld:%ld)\n",
+			(long)s->lifetime, (long)tsap->lifetime);
+		plog(LLV_DEBUG, LOCATION, NULL, "(lifebyte = %zu:%zu)\n",
+			s->lifebyte, tsap->lifebyte);
+		plog(LLV_DEBUG, LOCATION, NULL, "enctype = %s:%s\n",
+			s_oakley_attr_v(OAKLEY_ATTR_ENC_ALG,
+					s->enctype),
+			s_oakley_attr_v(OAKLEY_ATTR_ENC_ALG,
+					tsap->enctype));
+		plog(LLV_DEBUG, LOCATION, NULL, "(encklen = %d:%d)\n",
+			s->encklen, tsap->encklen);
+		plog(LLV_DEBUG, LOCATION, NULL, "hashtype = %s:%s\n",
+			s_oakley_attr_v(OAKLEY_ATTR_HASH_ALG,
+					s->hashtype),
+			s_oakley_attr_v(OAKLEY_ATTR_HASH_ALG,
+					tsap->hashtype));
+		plog(LLV_DEBUG, LOCATION, NULL, "authmethod = %s:%s\n",
+			s_oakley_attr_v(OAKLEY_ATTR_AUTH_METHOD,
+					s->authmethod),
+			s_oakley_attr_v(OAKLEY_ATTR_AUTH_METHOD,
+					tsap->authmethod));
+		plog(LLV_DEBUG, LOCATION, NULL, "dh_group = %s:%s\n",
+			s_oakley_attr_v(OAKLEY_ATTR_GRP_DESC,
+					s->dh_group),
+			s_oakley_attr_v(OAKLEY_ATTR_GRP_DESC,
+					tsap->dh_group));
+#if 0
+		/* XXX to be considered ? */
+		if (tsap->lifebyte > s->lifebyte) ;
+#endif
+		/*
+		 * if responder side and peer's key length in proposal
+		 * is bigger than mine, it might be accepted.
+		 */
+		if(tsap->enctype == s->enctype &&
+		    tsap->authmethod == authmethod &&
+		    tsap->hashtype == s->hashtype &&
+		    tsap->dh_group == s->dh_group &&
+		    tsap->encklen == s->encklen) {
+			switch(check_level) {
+			case PROP_CHECK_OBEY:
+				goto found;
+				break;
+
+			case PROP_CHECK_STRICT:
+				if ((tsap->lifetime > s->lifetime) ||
+				    (tsap->lifebyte > s->lifebyte))
+					continue;
+				goto found;
+				break;
+
+			case PROP_CHECK_CLAIM:
+				if (tsap->lifetime < s->lifetime)
+					s->lifetime = tsap->lifetime;
+				if (tsap->lifebyte < s->lifebyte)
+					s->lifebyte = tsap->lifebyte;
+				goto found;
+				break;
+
+			case PROP_CHECK_EXACT:
+				if ((tsap->lifetime != s->lifetime) ||
+				    (tsap->lifebyte != s->lifebyte))
+					continue;
+				goto found;
+				break;
+
+			default:
+				plog(LLV_ERROR, LOCATION, NULL, 
+				    "Unexpected proposal_check value\n");
+				continue;
+				break;
+			}
+		}
+	}
+
+found:
+	if (tsap->dhgrp != NULL){
+		oakley_dhgrp_free(tsap->dhgrp);
+		tsap->dhgrp = NULL;
+	}
+
+	if ((s = dupisakmpsa(s)) != NULL) {
+		switch(check_level) {
+		case PROP_CHECK_OBEY:
+			s->lifetime = tsap->lifetime;
+			s->lifebyte = tsap->lifebyte;
+			break;
+
+		case PROP_CHECK_STRICT:
+			s->lifetime = tsap->lifetime;
+			s->lifebyte = tsap->lifebyte;
+			break;
+
+		case PROP_CHECK_CLAIM:
+			if (tsap->lifetime < s->lifetime)
+				s->lifetime = tsap->lifetime;
+			if (tsap->lifebyte < s->lifebyte)
+				s->lifebyte = tsap->lifebyte;
+			break;
+
+		default:
+			break;
+		}
+	}
+	return s;
+}
+
+/*
+ * print all of items in peer's proposal which are mismatched to my proposal.
+ * p       : one of peer's proposal.
+ * proposal: my proposals.
+ */
+static void
+print_ph1mismatched(p, proposal)
+	struct prop_pair *p;
+	struct isakmpsa *proposal;
+{
+	struct isakmpsa sa, *s;
+
+	memset(&sa, 0, sizeof(sa));
+	if (t2isakmpsa(p->trns, &sa) < 0)
+		return;
+	for (s = proposal; s ; s = s->next) {
+		if (sa.enctype != s->enctype) {
+			plog(LLV_ERROR, LOCATION, NULL,
+				"rejected enctype: "
+				"DB(prop#%d:trns#%d):Peer(prop#%d:trns#%d) = "
+				"%s:%s\n",
+				s->prop_no, s->trns_no,
+				p->prop->p_no, p->trns->t_no,
+				s_oakley_attr_v(OAKLEY_ATTR_ENC_ALG,
+					s->enctype),
+				s_oakley_attr_v(OAKLEY_ATTR_ENC_ALG,
+					sa.enctype));
+		}
+		if (sa.authmethod != s->authmethod) {
+			plog(LLV_ERROR, LOCATION, NULL,
+				"rejected authmethod: "
+				"DB(prop#%d:trns#%d):Peer(prop#%d:trns#%d) = "
+				"%s:%s\n",
+				s->prop_no, s->trns_no,
+				p->prop->p_no, p->trns->t_no,
+				s_oakley_attr_v(OAKLEY_ATTR_AUTH_METHOD,
+					s->authmethod),
+				s_oakley_attr_v(OAKLEY_ATTR_AUTH_METHOD,
+					sa.authmethod));
+		}
+		if (sa.hashtype != s->hashtype) {
+			plog(LLV_ERROR, LOCATION, NULL,
+				"rejected hashtype: "
+				"DB(prop#%d:trns#%d):Peer(prop#%d:trns#%d) = "
+				"%s:%s\n",
+				s->prop_no, s->trns_no,
+				p->prop->p_no, p->trns->t_no,
+				s_oakley_attr_v(OAKLEY_ATTR_HASH_ALG,
+					s->hashtype),
+				s_oakley_attr_v(OAKLEY_ATTR_HASH_ALG,
+					sa.hashtype));
+		}
+		if (sa.dh_group != s->dh_group) {
+			plog(LLV_ERROR, LOCATION, NULL,
+				"rejected dh_group: "
+				"DB(prop#%d:trns#%d):Peer(prop#%d:trns#%d) = "
+				"%s:%s\n",
+				s->prop_no, s->trns_no,
+				p->prop->p_no, p->trns->t_no,
+				s_oakley_attr_v(OAKLEY_ATTR_GRP_DESC,
+					s->dh_group),
+				s_oakley_attr_v(OAKLEY_ATTR_GRP_DESC,
+					sa.dh_group));
+		}
+	}
+
+	if (sa.dhgrp != NULL){
+		oakley_dhgrp_free(sa.dhgrp);
+		sa.dhgrp=NULL;
+	}
+}
+
+/*
+ * get ISAKMP data attributes
+ */
+static int
+t2isakmpsa(trns, sa)
+	struct isakmp_pl_t *trns;
+	struct isakmpsa *sa;
+{
+	struct isakmp_data *d, *prev;
+	int flag, type;
+	int error = -1;
+	int life_t;
+	int keylen = 0;
+	vchar_t *val = NULL;
+	int len, tlen;
+	u_char *p;
+
+	tlen = ntohs(trns->h.len) - sizeof(*trns);
+	prev = (struct isakmp_data *)NULL;
+	d = (struct isakmp_data *)(trns + 1);
+
+	/* default */
+	life_t = OAKLEY_ATTR_SA_LD_TYPE_DEFAULT;
+	sa->lifetime = OAKLEY_ATTR_SA_LD_SEC_DEFAULT;
+	sa->lifebyte = 0;
+	sa->dhgrp = racoon_calloc(1, sizeof(struct dhgroup));
+	if (!sa->dhgrp)
+		goto err;
+
+	while (tlen > 0) {
+
+		type = ntohs(d->type) & ~ISAKMP_GEN_MASK;
+		flag = ntohs(d->type) & ISAKMP_GEN_MASK;
+
+		plog(LLV_DEBUG, LOCATION, NULL,
+			"type=%s, flag=0x%04x, lorv=%s\n",
+			s_oakley_attr(type), flag,
+			s_oakley_attr_v(type, ntohs(d->lorv)));
+
+		/* get variable-sized item */
+		switch (type) {
+		case OAKLEY_ATTR_GRP_PI:
+		case OAKLEY_ATTR_GRP_GEN_ONE:
+		case OAKLEY_ATTR_GRP_GEN_TWO:
+		case OAKLEY_ATTR_GRP_CURVE_A:
+		case OAKLEY_ATTR_GRP_CURVE_B:
+		case OAKLEY_ATTR_SA_LD:
+		case OAKLEY_ATTR_GRP_ORDER:
+			if (flag) {	/*TV*/
+				len = 2;
+				p = (u_char *)&d->lorv;
+			} else {	/*TLV*/
+				len = ntohs(d->lorv);
+				p = (u_char *)(d + 1);
+			}
+			val = vmalloc(len);
+			if (!val)
+				return -1;
+			memcpy(val->v, p, len);
+			break;
+
+		default:
+			break;
+		}
+
+		switch (type) {
+		case OAKLEY_ATTR_ENC_ALG:
+			sa->enctype = (u_int16_t)ntohs(d->lorv);
+			break;
+
+		case OAKLEY_ATTR_HASH_ALG:
+			sa->hashtype = (u_int16_t)ntohs(d->lorv);
+			break;
+
+		case OAKLEY_ATTR_AUTH_METHOD:
+			sa->authmethod = ntohs(d->lorv);
+			break;
+
+		case OAKLEY_ATTR_GRP_DESC:
+			sa->dh_group = (u_int16_t)ntohs(d->lorv);
+			break;
+
+		case OAKLEY_ATTR_GRP_TYPE:
+		{
+			int type = (int)ntohs(d->lorv);
+			if (type == OAKLEY_ATTR_GRP_TYPE_MODP)
+				sa->dhgrp->type = type;
+			else
+				return -1;
+			break;
+		}
+		case OAKLEY_ATTR_GRP_PI:
+			sa->dhgrp->prime = val;
+			break;
+
+		case OAKLEY_ATTR_GRP_GEN_ONE:
+			vfree(val);
+			if (!flag)
+				sa->dhgrp->gen1 = ntohs(d->lorv);
+			else {
+				int len = ntohs(d->lorv);
+				sa->dhgrp->gen1 = 0;
+				if (len > 4)
+					return -1;
+				memcpy(&sa->dhgrp->gen1, d + 1, len);
+				sa->dhgrp->gen1 = ntohl(sa->dhgrp->gen1);
+			}
+			break;
+
+		case OAKLEY_ATTR_GRP_GEN_TWO:
+			vfree(val);
+			if (!flag)
+				sa->dhgrp->gen2 = ntohs(d->lorv);
+			else {
+				int len = ntohs(d->lorv);
+				sa->dhgrp->gen2 = 0;
+				if (len > 4)
+					return -1;
+				memcpy(&sa->dhgrp->gen2, d + 1, len);
+				sa->dhgrp->gen2 = ntohl(sa->dhgrp->gen2);
+			}
+			break;
+
+		case OAKLEY_ATTR_GRP_CURVE_A:
+			sa->dhgrp->curve_a = val;
+			break;
+
+		case OAKLEY_ATTR_GRP_CURVE_B:
+			sa->dhgrp->curve_b = val;
+			break;
+
+		case OAKLEY_ATTR_SA_LD_TYPE:
+		{
+			int type = (int)ntohs(d->lorv);
+			switch (type) {
+			case OAKLEY_ATTR_SA_LD_TYPE_SEC:
+			case OAKLEY_ATTR_SA_LD_TYPE_KB:
+				life_t = type;
+				break;
+			default:
+				life_t = OAKLEY_ATTR_SA_LD_TYPE_DEFAULT;
+				break;
+			}
+			break;
+		}
+		case OAKLEY_ATTR_SA_LD:
+			if (!prev
+			 || (ntohs(prev->type) & ~ISAKMP_GEN_MASK) !=
+					OAKLEY_ATTR_SA_LD_TYPE) {
+				plog(LLV_ERROR, LOCATION, NULL,
+				    "life duration must follow ltype\n");
+				break;
+			}
+
+			switch (life_t) {
+			case IPSECDOI_ATTR_SA_LD_TYPE_SEC:
+				sa->lifetime = ipsecdoi_set_ld(val);
+				vfree(val);
+				if (sa->lifetime == 0) {
+					plog(LLV_ERROR, LOCATION, NULL,
+						"invalid life duration.\n");
+					goto err;
+				}
+				break;
+			case IPSECDOI_ATTR_SA_LD_TYPE_KB:
+				sa->lifebyte = ipsecdoi_set_ld(val);
+				vfree(val);
+				if (sa->lifebyte == 0) {
+					plog(LLV_ERROR, LOCATION, NULL,
+						"invalid life duration.\n");
+					goto err;
+				}
+				break;
+			default:
+				vfree(val);
+				plog(LLV_ERROR, LOCATION, NULL,
+					"invalid life type: %d\n", life_t);
+				goto err;
+			}
+			break;
+
+		case OAKLEY_ATTR_KEY_LEN:
+		{
+			int len = ntohs(d->lorv);
+			if (len % 8 != 0) {
+				plog(LLV_ERROR, LOCATION, NULL,
+					"keylen %d: not multiple of 8\n",
+					len);
+				goto err;
+			}
+			sa->encklen = (u_int16_t)len;
+			keylen++;
+			break;
+		}
+		case OAKLEY_ATTR_PRF:
+		case OAKLEY_ATTR_FIELD_SIZE:
+			/* unsupported */
+			break;
+
+		case OAKLEY_ATTR_GRP_ORDER:
+			sa->dhgrp->order = val;
+			break;
+#ifdef HAVE_GSSAPI
+		case OAKLEY_ATTR_GSS_ID:
+		{
+			int error = -1;
+			iconv_t cd = (iconv_t) -1;
+			size_t srcleft, dstleft, rv;
+			__iconv_const char *src;
+			char *dst;
+			int len = ntohs(d->lorv);
+
+			/*
+			 * Older verions of racoon just placed the
+			 * ISO-Latin-1 string on the wire directly.
+			 * Check to see if we are configured to be
+			 * compatible with this behavior.
+			 */
+			if (lcconf->gss_id_enc == LC_GSSENC_LATIN1) {
+				if ((sa->gssid = vmalloc(len)) == NULL) {
+					plog(LLV_ERROR, LOCATION, NULL,
+					    "failed to allocate memory\n");
+					goto out;
+				}
+				memcpy(sa->gssid->v, d + 1, len);
+				plog(LLV_DEBUG, LOCATION, NULL,
+				    "received old-style gss "
+				    "id '%.*s' (len %zu)\n",
+				    (int)sa->gssid->l, sa->gssid->v, 
+				    sa->gssid->l);
+				error = 0;
+				goto out;
+			}
+
+			/*
+			 * For Windows 2000 compatibility, we expect
+			 * the GSS ID attribute on the wire to be
+			 * encoded in UTF-16LE.  Internally, we work
+			 * in ISO-Latin-1.  Therefore, we should need
+			 * 1/2 the specified length, which should always
+			 * be a multiple of 2 octets.
+			 */
+			cd = iconv_open("latin1", "utf-16le");
+			if (cd == (iconv_t) -1) {
+				plog(LLV_ERROR, LOCATION, NULL,
+				    "unable to initialize utf-16le -> latin1 "
+				    "conversion descriptor: %s\n",
+				    strerror(errno));
+				goto out;
+			}
+
+			if ((sa->gssid = vmalloc(len / 2)) == NULL) {
+				plog(LLV_ERROR, LOCATION, NULL,
+				    "failed to allocate memory\n");
+				goto out;
+			}
+
+			src = (__iconv_const char *)(d + 1);
+			srcleft = len;
+
+			dst = sa->gssid->v;
+			dstleft = len / 2;
+
+			rv = iconv(cd, (__iconv_const char **)&src, &srcleft, 
+				   &dst, &dstleft);
+			if (rv != 0) {
+				if (rv == -1) {
+					plog(LLV_ERROR, LOCATION, NULL,
+					    "unable to convert GSS ID from "
+					    "utf-16le -> latin1: %s\n",
+					    strerror(errno));
+				} else {
+					plog(LLV_ERROR, LOCATION, NULL,
+					    "%zd character%s in GSS ID cannot "
+					    "be represented in latin1\n",
+					    rv, rv == 1 ? "" : "s");
+				}
+				goto out;
+			}
+
+			/* XXX dstleft should always be 0; assert it? */
+			sa->gssid->l = (len / 2) - dstleft;
+
+			plog(LLV_DEBUG, LOCATION, NULL,
+			    "received gss id '%.*s' (len %zu)\n",
+			    (int)sa->gssid->l, sa->gssid->v, sa->gssid->l);
+
+			error = 0;
+out:
+			if (cd != (iconv_t)-1)
+				(void)iconv_close(cd);
+
+			if ((error != 0) && (sa->gssid != NULL)) {
+				vfree(sa->gssid);
+				sa->gssid = NULL;
+			}
+			break;
+		}
+#endif /* HAVE_GSSAPI */
+
+		default:
+			break;
+		}
+
+		prev = d;
+		if (flag) {
+			tlen -= sizeof(*d);
+			d = (struct isakmp_data *)((char *)d + sizeof(*d));
+		} else {
+			tlen -= (sizeof(*d) + ntohs(d->lorv));
+			d = (struct isakmp_data *)((char *)d + sizeof(*d) + ntohs(d->lorv));
+		}
+	}
+
+	/* key length must not be specified on some algorithms */
+	if (keylen) {
+		if (sa->enctype == OAKLEY_ATTR_ENC_ALG_DES
+#ifdef HAVE_OPENSSL_IDEA_H
+		 || sa->enctype == OAKLEY_ATTR_ENC_ALG_IDEA
+#endif
+		 || sa->enctype == OAKLEY_ATTR_ENC_ALG_3DES) {
+			plog(LLV_ERROR, LOCATION, NULL,
+				"keylen must not be specified "
+				"for encryption algorithm %d\n",
+				sa->enctype);
+			return -1;
+		}
+	}
+
+	return 0;
+err:
+	return error;
+}
+
+/*%%%*/
+/*
+ * check phase 2 SA payload and select single proposal.
+ * make new SA payload to be replyed not including general header.
+ * This function is called by responder only.
+ * OUT:
+ *	0: succeed.
+ *	-1: error occured.
+ */
+int
+ipsecdoi_selectph2proposal(iph2)
+	struct ph2handle *iph2;
+{
+	struct prop_pair **pair;
+	struct prop_pair *ret;
+
+	/* get proposal pair */
+	pair = get_proppair(iph2->sa, IPSECDOI_TYPE_PH2);
+	if (pair == NULL)
+		return -1;
+
+	/* check and select a proposal. */
+	ret = get_ph2approval(iph2, pair);
+	free_proppair(pair);
+	if (ret == NULL)
+		return -1;
+
+	/* make a SA to be replayed. */
+	/* SPI must be updated later. */
+	iph2->sa_ret = get_sabyproppair(ret, iph2->ph1);
+	free_proppair0(ret);
+	if (iph2->sa_ret == NULL)
+		return -1;
+
+	return 0;
+}
+
+/*
+ * check phase 2 SA payload returned from responder.
+ * This function is called by initiator only.
+ * OUT:
+ *	0: valid.
+ *	-1: invalid.
+ */
+int
+ipsecdoi_checkph2proposal(iph2)
+	struct ph2handle *iph2;
+{
+	struct prop_pair **rpair = NULL, **spair = NULL;
+	struct prop_pair *p;
+	int i, n, num;
+	int error = -1;
+	vchar_t *sa_ret = NULL;
+
+	/* get proposal pair of SA sent. */
+	spair = get_proppair(iph2->sa, IPSECDOI_TYPE_PH2);
+	if (spair == NULL) {
+		plog(LLV_ERROR, LOCATION, NULL,
+			"failed to get prop pair.\n");
+		goto end;
+	}
+
+	/* XXX should check the number of transform */
+
+	/* get proposal pair of SA replayed */
+	rpair = get_proppair(iph2->sa_ret, IPSECDOI_TYPE_PH2);
+	if (rpair == NULL) {
+		plog(LLV_ERROR, LOCATION, NULL,
+			"failed to get prop pair.\n");
+		goto end;
+	}
+
+	/* check proposal is only one ? */
+	n = 0;
+	num = 0;
+	for (i = 0; i < MAXPROPPAIRLEN; i++) {
+		if (rpair[i]) {
+			n = i;
+			num++;
+		}
+	}
+	if (num == 0) {
+		plog(LLV_ERROR, LOCATION, NULL,
+			"no proposal received.\n");
+		goto end;
+	}
+	if (num != 1) {
+		plog(LLV_ERROR, LOCATION, NULL,
+			"some proposals received.\n");
+		goto end;
+	}
+
+	if (spair[n] == NULL) {
+		plog(LLV_WARNING, LOCATION, NULL,
+			"invalid proposal number:%d received.\n", i);
+	}
+	
+
+	if (rpair[n]->tnext != NULL) {
+		plog(LLV_ERROR, LOCATION, NULL,
+			"multi transforms replyed.\n");
+		goto end;
+	}
+
+	if (cmp_aproppair_i(rpair[n], spair[n])) {
+		plog(LLV_ERROR, LOCATION, NULL,
+			"proposal mismathed.\n");
+		goto end;
+	}
+
+	/*
+	 * check and select a proposal.
+	 * ensure that there is no modification of the proposal by
+	 * cmp_aproppair_i()
+	 */
+	p = get_ph2approval(iph2, rpair);
+	if (p == NULL)
+		goto end;
+
+	/* make a SA to be replayed. */
+	sa_ret = iph2->sa_ret;
+	iph2->sa_ret = get_sabyproppair(p, iph2->ph1);
+	free_proppair0(p);
+	if (iph2->sa_ret == NULL)
+		goto end;
+
+	error = 0;
+
+end:
+	if (rpair)
+		free_proppair(rpair);
+	if (spair)
+		free_proppair(spair);
+	if (sa_ret)
+		vfree(sa_ret);
+
+	return error;
+}
+
+/*
+ * compare two prop_pair which is assumed to have same proposal number.
+ * the case of bundle or single SA, NOT multi transforms.
+ * a: a proposal that is multi protocols and single transform, usually replyed.
+ * b: a proposal that is multi protocols and multi transform, usually sent.
+ * NOTE: this function is for initiator.
+ * OUT
+ *	0: equal
+ *	1: not equal
+ * XXX cannot understand the comment!
+ */
+static int
+cmp_aproppair_i(a, b)
+	struct prop_pair *a, *b;
+{
+	struct prop_pair *p, *q, *r;
+	int len;
+
+	for (p = a, q = b; p && q; p = p->next, q = q->next) {
+		for (r = q; r; r = r->tnext) {
+			/* compare trns */
+			if (p->trns->t_no == r->trns->t_no)
+				break;
+		}
+		if (!r) {
+			/* no suitable transform found */
+			plog(LLV_ERROR, LOCATION, NULL,
+				"no suitable transform found.\n");
+			return -1;
+		}
+
+		/* compare prop */
+		if (p->prop->p_no != r->prop->p_no) {
+			plog(LLV_WARNING, LOCATION, NULL,
+				"proposal #%d mismatched, "
+				"expected #%d.\n",
+				r->prop->p_no, p->prop->p_no);
+			/*FALLTHROUGH*/
+		}
+
+		if (p->prop->proto_id != r->prop->proto_id) {
+			plog(LLV_ERROR, LOCATION, NULL,
+				"proto_id mismathed: my:%d peer:%d\n",
+				r->prop->proto_id, p->prop->proto_id);
+			return -1;
+		}
+
+		if (p->prop->spi_size != r->prop->spi_size) {
+			plog(LLV_ERROR, LOCATION, NULL,
+				"invalid spi size: %d.\n",
+				p->prop->spi_size);
+			return -1;
+		}
+
+		/* check #of transforms */
+		if (p->prop->num_t != 1) {
+			plog(LLV_WARNING, LOCATION, NULL,
+				"#of transform is %d, "
+				"but expected 1.\n", p->prop->num_t);
+			/*FALLTHROUGH*/
+		}
+
+		if (p->trns->t_id != r->trns->t_id) {
+			plog(LLV_WARNING, LOCATION, NULL,
+				"transform number has been modified.\n");
+			/*FALLTHROUGH*/
+		}
+		if (p->trns->reserved != r->trns->reserved) {
+			plog(LLV_WARNING, LOCATION, NULL,
+				"reserved field should be zero.\n");
+			/*FALLTHROUGH*/
+		}
+
+		/* compare attribute */
+		len = ntohs(r->trns->h.len) - sizeof(*p->trns);
+		if (memcmp(p->trns + 1, r->trns + 1, len) != 0) {
+			plog(LLV_WARNING, LOCATION, NULL,
+				"attribute has been modified.\n");
+			/*FALLTHROUGH*/
+		}
+	}
+	if ((p && !q) || (!p && q)) {
+		/* # of protocols mismatched */
+		plog(LLV_ERROR, LOCATION, NULL,
+			"#of protocols mismatched.\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+ * acceptable check for policy configuration.
+ * return a new SA payload to be reply to peer.
+ */
+static struct prop_pair *
+get_ph2approval(iph2, pair)
+	struct ph2handle *iph2;
+	struct prop_pair **pair;
+{
+	struct prop_pair *ret;
+	int i;
+
+	iph2->approval = NULL;
+
+	plog(LLV_DEBUG, LOCATION, NULL,
+		"begin compare proposals.\n");
+
+	for (i = 0; i < MAXPROPPAIRLEN; i++) {
+		if (pair[i] == NULL)
+			continue;
+		plog(LLV_DEBUG, LOCATION, NULL,
+			"pair[%d]: %p\n", i, pair[i]);
+		print_proppair(LLV_DEBUG, pair[i]);;
+
+		/* compare proposal and select one */
+		ret = get_ph2approvalx(iph2, pair[i]);
+		if (ret != NULL) {
+			/* found */
+			return ret;
+		}
+	}
+
+	plog(LLV_ERROR, LOCATION, NULL, "no suitable policy found.\n");
+
+	return NULL;
+}
+
+/*
+ * compare my proposal and peers just one proposal.
+ * set a approval.
+ */
+static struct prop_pair *
+get_ph2approvalx(iph2, pp)
+	struct ph2handle *iph2;
+	struct prop_pair *pp;
+{
+	struct prop_pair *ret = NULL;
+	struct saprop *pr0, *pr = NULL;
+	struct saprop *q1, *q2;
+
+	pr0 = aproppair2saprop(pp);
+	if (pr0 == NULL)
+		return NULL;
+
+	for (q1 = pr0; q1; q1 = q1->next) {
+		for (q2 = iph2->proposal; q2; q2 = q2->next) {
+			plog(LLV_DEBUG, LOCATION, NULL,
+				"peer's single bundle:\n");
+			printsaprop0(LLV_DEBUG, q1);
+			plog(LLV_DEBUG, LOCATION, NULL,
+				"my single bundle:\n");
+			printsaprop0(LLV_DEBUG, q2);
+
+			pr = cmpsaprop_alloc(iph2->ph1, q1, q2, iph2->side);
+			if (pr != NULL)
+				goto found;
+
+			plog(LLV_ERROR, LOCATION, NULL,
+				"not matched\n");
+		}
+	}
+	/* no proposal matching */
+err:
+	flushsaprop(pr0);
+	return NULL;
+
+found:
+	flushsaprop(pr0);
+	plog(LLV_DEBUG, LOCATION, NULL, "matched\n");
+	iph2->approval = pr;
+
+    {
+	struct saproto *sp;
+	struct prop_pair *p, *x;
+	struct prop_pair *n = NULL;
+
+	ret = NULL;
+
+	for (p = pp; p; p = p->next) {
+		/*
+		 * find a proposal with matching proto_id.
+		 * we have analyzed validity already, in cmpsaprop_alloc().
+		 */
+		for (sp = pr->head; sp; sp = sp->next) {
+			if (sp->proto_id == p->prop->proto_id)
+				break;
+		}
+		if (!sp)
+			goto err;
+		if (sp->head->next)
+			goto err;	/* XXX */
+
+		for (x = p; x; x = x->tnext)
+			if (sp->head->trns_no == x->trns->t_no)
+				break;
+		if (!x)
+			goto err;	/* XXX */
+
+		n = racoon_calloc(1, sizeof(struct prop_pair));
+		if (n == NULL) {
+			plog(LLV_ERROR, LOCATION, NULL,
+				"failed to get buffer.\n");
+			goto err;
+		}
+
+		n->prop = x->prop;
+		n->trns = x->trns;
+
+		/* need to preserve the order */
+		for (x = ret; x && x->next; x = x->next)
+			;
+		if (x && x->prop == n->prop) {
+			for (/*nothing*/; x && x->tnext; x = x->tnext)
+				;
+			x->tnext = n;
+		} else {
+			if (x)
+				x->next = n;
+			else {
+				ret = n;
+			}
+		}
+
+		/* #of transforms should be updated ? */
+	}
+    }
+
+	return ret;
+}
+
+void
+free_proppair(pair)
+	struct prop_pair **pair;
+{
+	int i;
+
+	for (i = 0; i < MAXPROPPAIRLEN; i++) {
+		free_proppair0(pair[i]);
+		pair[i] = NULL;
+	}
+	racoon_free(pair);
+}
+
+static void
+free_proppair0(pair)
+	struct prop_pair *pair;
+{
+	struct prop_pair *p, *q, *r, *s;
+
+	p = pair;
+	while (p) {
+		q = p->next;
+		r = p;
+		while (r) {
+			s = r->tnext;
+			racoon_free(r);
+			r = s;
+		}
+		p = q;
+	}
+}
+
+/*
+ * get proposal pairs from SA payload.
+ * tiny check for proposal payload.
+ */
+struct prop_pair **
+get_proppair(sa, mode)
+	vchar_t *sa;
+	int mode;
+{
+	struct prop_pair **pair = NULL;
+	int num_p = 0;			/* number of proposal for use */
+	int tlen;
+	caddr_t bp;
+	int i;
+	struct ipsecdoi_sa_b *sab = (struct ipsecdoi_sa_b *)sa->v;
+
+	plog(LLV_DEBUG, LOCATION, NULL, "total SA len=%zu\n", sa->l);
+	plogdump(LLV_DEBUG, sa->v, sa->l);
+
+	/* check SA payload size */
+	if (sa->l < sizeof(*sab)) {
+		plog(LLV_ERROR, LOCATION, NULL,
+			"Invalid SA length = %zu.\n", sa->l);
+		goto bad;
+	}
+
+	/* check DOI */
+	if (check_doi(ntohl(sab->doi)) < 0)
+		goto bad;
+
+	/* check SITUATION */
+	if (check_situation(ntohl(sab->sit)) < 0)
+		goto bad;
+
+	pair = racoon_calloc(1, MAXPROPPAIRLEN * sizeof(*pair));
+	if (pair == NULL) {
+		plog(LLV_ERROR, LOCATION, NULL,
+			"failed to get buffer.\n");
+		goto bad;
+	}
+	memset(pair, 0, sizeof(pair));
+
+	bp = (caddr_t)(sab + 1);
+	tlen = sa->l - sizeof(*sab);
+
+    {
+	struct isakmp_pl_p *prop;
+	int proplen;
+	vchar_t *pbuf = NULL;
+	struct isakmp_parse_t *pa;
+
+	pbuf = isakmp_parsewoh(ISAKMP_NPTYPE_P, (struct isakmp_gen *)bp, tlen);
+	if (pbuf == NULL)
+		goto bad;
+
+	for (pa = (struct isakmp_parse_t *)pbuf->v;
+	     pa->type != ISAKMP_NPTYPE_NONE;
+	     pa++) {
+		/* check the value of next payload */
+		if (pa->type != ISAKMP_NPTYPE_P) {
+			plog(LLV_ERROR, LOCATION, NULL,
+				"Invalid payload type=%u\n", pa->type);
+			vfree(pbuf);
+			goto bad;
+		}
+
+		prop = (struct isakmp_pl_p *)pa->ptr;
+		proplen = pa->len;
+
+		plog(LLV_DEBUG, LOCATION, NULL,
+			"proposal #%u len=%d\n", prop->p_no, proplen);
+
+		if (proplen == 0) {
+			plog(LLV_ERROR, LOCATION, NULL,
+				"invalid proposal with length %d\n", proplen);
+			vfree(pbuf);
+			goto bad;
+		}
+
+		/* check Protocol ID */
+		if (!check_protocol[mode]) {
+			plog(LLV_ERROR, LOCATION, NULL,
+				"unsupported mode %d\n", mode);
+			continue;
+		}
+
+		if (check_protocol[mode](prop->proto_id) < 0)
+			continue;
+
+		/* check SPI length when IKE. */
+		if (check_spi_size(prop->proto_id, prop->spi_size) < 0)
+			continue;
+
+		/* get transform */
+		if (get_transform(prop, pair, &num_p) < 0) {
+			vfree(pbuf);
+			goto bad;
+		}
+	}
+	vfree(pbuf);
+	pbuf = NULL;
+    }
+
+    {
+	int notrans, nprop;
+	struct prop_pair *p, *q;
+
+	/* check for proposals with no transforms */
+	for (i = 0; i < MAXPROPPAIRLEN; i++) {
+		if (!pair[i])
+			continue;
+
+		plog(LLV_DEBUG, LOCATION, NULL, "pair %d:\n", i);
+		print_proppair(LLV_DEBUG, pair[i]);
+
+		notrans = nprop = 0;
+		for (p = pair[i]; p; p = p->next) {
+			if (p->trns == NULL) {
+				notrans++;
+				break;
+			}
+			for (q = p; q; q = q->tnext)
+				nprop++;
+		}
+
+#if 0
+		/*
+		 * XXX at this moment, we cannot accept proposal group
+		 * with multiple proposals.  this should be fixed.
+		 */
+		if (pair[i]->next) {
+			plog(LLV_WARNING, LOCATION, NULL,
+				"proposal #%u ignored "
+				"(multiple proposal not supported)\n",
+				pair[i]->prop->p_no);
+			notrans++;
+		}
+#endif
+
+		if (notrans) {
+			for (p = pair[i]; p; p = q) {
+				q = p->next;
+				racoon_free(p);
+			}
+			pair[i] = NULL;
+			num_p--;
+		} else {
+			plog(LLV_DEBUG, LOCATION, NULL,
+				"proposal #%u: %d transform\n",
+				pair[i]->prop->p_no, nprop);
+		}
+	}
+    }
+
+	/* bark if no proposal is found. */
+	if (num_p <= 0) {
+		plog(LLV_ERROR, LOCATION, NULL,
+			"no Proposal found.\n");
+		goto bad;
+	}
+
+	return pair;
+bad:
+	if (pair != NULL)
+		racoon_free(pair);
+	return NULL;
+}
+
+/*
+ * check transform payload.
+ * OUT:
+ *	positive: return the pointer to the payload of valid transform.
+ *	0	: No valid transform found.
+ */
+static int
+get_transform(prop, pair, num_p)
+	struct isakmp_pl_p *prop;
+	struct prop_pair **pair;
+	int *num_p;
+{
+	int tlen; /* total length of all transform in a proposal */
+	caddr_t bp;
+	struct isakmp_pl_t *trns;
+	int trnslen;
+	vchar_t *pbuf = NULL;
+	struct isakmp_parse_t *pa;
+	struct prop_pair *p = NULL, *q;
+	int num_t;
+
+	bp = (caddr_t)prop + sizeof(struct isakmp_pl_p) + prop->spi_size;
+	tlen = ntohs(prop->h.len)
+		- (sizeof(struct isakmp_pl_p) + prop->spi_size);
+	pbuf = isakmp_parsewoh(ISAKMP_NPTYPE_T, (struct isakmp_gen *)bp, tlen);
+	if (pbuf == NULL)
+		return -1;
+
+	/* check and get transform for use */
+	num_t = 0;
+	for (pa = (struct isakmp_parse_t *)pbuf->v;
+	     pa->type != ISAKMP_NPTYPE_NONE;
+	     pa++) {
+
+		num_t++;
+
+		/* check the value of next payload */
+		if (pa->type != ISAKMP_NPTYPE_T) {
+			plog(LLV_ERROR, LOCATION, NULL,
+				"Invalid payload type=%u\n", pa->type);
+			break;
+		}
+
+		trns = (struct isakmp_pl_t *)pa->ptr;
+		trnslen = pa->len;
+
+		plog(LLV_DEBUG, LOCATION, NULL,
+			"transform #%u len=%u\n", trns->t_no, trnslen);
+
+		/* check transform ID */
+		if (prop->proto_id >= ARRAYLEN(check_transform)) {
+			plog(LLV_WARNING, LOCATION, NULL,
+				"unsupported proto_id %u\n",
+				prop->proto_id);
+			continue;
+		}
+		if (prop->proto_id >= ARRAYLEN(check_attributes)) {
+			plog(LLV_WARNING, LOCATION, NULL,
+				"unsupported proto_id %u\n",
+				prop->proto_id);
+			continue;
+		}
+
+		if (!check_transform[prop->proto_id]
+		 || !check_attributes[prop->proto_id]) {
+			plog(LLV_WARNING, LOCATION, NULL,
+				"unsupported proto_id %u\n",
+				prop->proto_id);
+			continue;
+		}
+		if (check_transform[prop->proto_id](trns->t_id) < 0)
+			continue;
+
+		/* check data attributes */
+		if (check_attributes[prop->proto_id](trns) != 0)
+			continue;
+
+		p = racoon_calloc(1, sizeof(*p));
+		if (p == NULL) {
+			plog(LLV_ERROR, LOCATION, NULL,
+				"failed to get buffer.\n");
+			vfree(pbuf);
+			return -1;
+		}
+		p->prop = prop;
+		p->trns = trns;
+
+		/* need to preserve the order */
+		for (q = pair[prop->p_no]; q && q->next; q = q->next)
+			;
+		if (q && q->prop == p->prop) {
+			for (/*nothing*/; q && q->tnext; q = q->tnext)
+				;
+			q->tnext = p;
+		} else {
+			if (q)
+				q->next = p;
+			else {
+				pair[prop->p_no] = p;
+				(*num_p)++;
+			}
+		}
+	}
+
+	vfree(pbuf);
+
+	return 0;
+}
+
+/*
+ * make a new SA payload from prop_pair.
+ * NOTE: this function make spi value clear.
+ */
+vchar_t *
+get_sabyproppair(pair, iph1)
+	struct prop_pair *pair;
+	struct ph1handle *iph1;
+{
+	vchar_t *newsa;
+	int newtlen;
+	u_int8_t *np_p = NULL;
+	struct prop_pair *p;
+	int prophlen, trnslen;
+	caddr_t bp;
+
+	newtlen = sizeof(struct ipsecdoi_sa_b);
+	for (p = pair; p; p = p->next) {
+		newtlen += sizeof(struct isakmp_pl_p);
+		newtlen += p->prop->spi_size;
+		newtlen += ntohs(p->trns->h.len);
+	}
+
+	newsa = vmalloc(newtlen);
+	if (newsa == NULL) {
+		plog(LLV_ERROR, LOCATION, NULL, "failed to get newsa.\n");
+		return NULL;
+	}
+	bp = newsa->v;
+
+	((struct isakmp_gen *)bp)->len = htons(newtlen);
+
+	/* update some of values in SA header */
+	((struct ipsecdoi_sa_b *)bp)->doi = htonl(iph1->rmconf->doitype);
+	((struct ipsecdoi_sa_b *)bp)->sit = htonl(iph1->rmconf->sittype);
+	bp += sizeof(struct ipsecdoi_sa_b);
+
+	/* create proposal payloads */
+	for (p = pair; p; p = p->next) {
+		prophlen = sizeof(struct isakmp_pl_p)
+				+ p->prop->spi_size;
+		trnslen = ntohs(p->trns->h.len);
+
+		if (np_p)
+			*np_p = ISAKMP_NPTYPE_P;
+
+		/* create proposal */
+
+		memcpy(bp, p->prop, prophlen);
+		((struct isakmp_pl_p *)bp)->h.np = ISAKMP_NPTYPE_NONE;
+		((struct isakmp_pl_p *)bp)->h.len = htons(prophlen + trnslen);
+		((struct isakmp_pl_p *)bp)->num_t = 1;
+		np_p = &((struct isakmp_pl_p *)bp)->h.np;
+		memset(bp + sizeof(struct isakmp_pl_p), 0, p->prop->spi_size);
+		bp += prophlen;
+
+		/* create transform */
+		memcpy(bp, p->trns, trnslen);
+		((struct isakmp_pl_t *)bp)->h.np = ISAKMP_NPTYPE_NONE;
+		((struct isakmp_pl_t *)bp)->h.len = htons(trnslen);
+		bp += trnslen;
+	}
+
+	return newsa;
+}
+
+/*
+ * update responder's spi
+ */
+int
+ipsecdoi_updatespi(iph2)
+	struct ph2handle *iph2;
+{
+	struct prop_pair **pair, *p;
+	struct saprop *pp;
+	struct saproto *pr;
+	int i;
+	int error = -1;
+	u_int8_t *spi;
+
+	pair = get_proppair(iph2->sa_ret, IPSECDOI_TYPE_PH2);
+	if (pair == NULL)
+		return -1;
+	for (i = 0; i < MAXPROPPAIRLEN; i++) {
+		if (pair[i])
+			break;
+	}
+	if (i == MAXPROPPAIRLEN || pair[i]->tnext) {
+		/* multiple transform must be filtered by selectph2proposal.*/
+		goto end;
+	}
+
+	pp = iph2->approval;
+
+	/* create proposal payloads */
+	for (p = pair[i]; p; p = p->next) {
+		/*
+		 * find a proposal/transform with matching proto_id/t_id.
+		 * we have analyzed validity already, in cmpsaprop_alloc().
+		 */
+		for (pr = pp->head; pr; pr = pr->next) {
+			if (p->prop->proto_id == pr->proto_id &&
+			    p->trns->t_id == pr->head->trns_id) {
+				break;
+			}
+		}
+		if (!pr)
+			goto end;
+
+		/*
+		 * XXX SPI bits are left-filled, for use with IPComp.
+		 * we should be switching to variable-length spi field...
+		 */
+		spi = (u_int8_t *)&pr->spi;
+		spi += sizeof(pr->spi);
+		spi -= pr->spisize;
+		memcpy((caddr_t)p->prop + sizeof(*p->prop), spi, pr->spisize);
+	}
+
+	error = 0;
+end:
+	free_proppair(pair);
+	return error;
+}
+
+/*
+ * make a new SA payload from prop_pair.
+ */
+vchar_t *
+get_sabysaprop(pp0, sa0)
+	struct saprop *pp0;
+	vchar_t *sa0;
+{
+	struct prop_pair **pair = NULL;
+	vchar_t *newsa = NULL;
+	int newtlen;
+	u_int8_t *np_p = NULL;
+	struct prop_pair *p = NULL;
+	struct saprop *pp;
+	struct saproto *pr;
+	struct satrns *tr;
+	int prophlen, trnslen;
+	caddr_t bp;
+	int error = -1;
+
+	/* get proposal pair */
+	pair = get_proppair(sa0, IPSECDOI_TYPE_PH2);
+	if (pair == NULL)
+		goto out;
+
+	newtlen = sizeof(struct ipsecdoi_sa_b);
+	for (pp = pp0; pp; pp = pp->next) {
+
+		if (pair[pp->prop_no] == NULL)
+			goto out;
+
+		for (pr = pp->head; pr; pr = pr->next) {
+			newtlen += (sizeof(struct isakmp_pl_p)
+				+ pr->spisize);
+
+			for (tr = pr->head; tr; tr = tr->next) {
+				for (p = pair[pp->prop_no]; p; p = p->tnext) {
+					if (tr->trns_no == p->trns->t_no)
+						break;
+				}
+				if (p == NULL)
+					goto out;
+
+				newtlen += ntohs(p->trns->h.len);
+			}
+		}
+	}
+
+	newsa = vmalloc(newtlen);
+	if (newsa == NULL) {
+		plog(LLV_ERROR, LOCATION, NULL, "failed to get newsa.\n");
+		goto out;
+	}
+	bp = newsa->v;
+
+	/* some of values of SA must be updated in the out of this function */
+	((struct isakmp_gen *)bp)->len = htons(newtlen);
+	bp += sizeof(struct ipsecdoi_sa_b);
+
+	/* create proposal payloads */
+	for (pp = pp0; pp; pp = pp->next) {
+
+		for (pr = pp->head; pr; pr = pr->next) {
+			prophlen = sizeof(struct isakmp_pl_p)
+					+ p->prop->spi_size;
+
+			for (tr = pr->head; tr; tr = tr->next) {
+				for (p = pair[pp->prop_no]; p; p = p->tnext) {
+					if (tr->trns_no == p->trns->t_no)
+						break;
+				}
+				if (p == NULL)
+					goto out;
+
+				trnslen = ntohs(p->trns->h.len);
+
+				if (np_p)
+					*np_p = ISAKMP_NPTYPE_P;
+
+				/* create proposal */
+
+				memcpy(bp, p->prop, prophlen);
+				((struct isakmp_pl_p *)bp)->h.np = ISAKMP_NPTYPE_NONE;
+				((struct isakmp_pl_p *)bp)->h.len = htons(prophlen + trnslen);
+				((struct isakmp_pl_p *)bp)->num_t = 1;
+				np_p = &((struct isakmp_pl_p *)bp)->h.np;
+				bp += prophlen;
+
+				/* create transform */
+				memcpy(bp, p->trns, trnslen);
+				((struct isakmp_pl_t *)bp)->h.np = ISAKMP_NPTYPE_NONE;
+				((struct isakmp_pl_t *)bp)->h.len = htons(trnslen);
+				bp += trnslen;
+			}
+		}
+	}
+
+	error = 0;
+out:
+	if (pair != NULL)
+		racoon_free(pair);
+
+	if (error != 0) {
+		if (newsa != NULL) {
+			vfree(newsa);
+			newsa = NULL;
+		}
+	}
+
+	return newsa;
+}
+
+/*
+ * If some error happens then return 0.  Although 0 means that lifetime is zero,
+ * such a value should not be accepted.
+ * Also 0 of lifebyte should not be included in a packet although 0 means not
+ * to care of it.
+ */
+static u_int32_t
+ipsecdoi_set_ld(buf)
+	vchar_t *buf;
+{
+	u_int32_t ld;
+
+	if (buf == 0)
+		return 0;
+
+	switch (buf->l) {
+	case 2:
+		ld = ntohs(*(u_int16_t *)buf->v);
+		break;
+	case 4:
+		ld = ntohl(*(u_int32_t *)buf->v);
+		break;
+	default:
+		plog(LLV_ERROR, LOCATION, NULL,
+			"length %zu of life duration "
+			"isn't supported.\n", buf->l);
+		return 0;
+	}
+
+	return ld;
+}
+
+/*%%%*/
+/*
+ * check DOI
+ */
+static int
+check_doi(doi)
+	u_int32_t doi;
+{
+	switch (doi) {
+	case IPSEC_DOI:
+		return 0;
+	default:
+		plog(LLV_ERROR, LOCATION, NULL,
+			"invalid value of DOI 0x%08x.\n", doi);
+		return -1;
+	}
+	/* NOT REACHED */
+}
+
+/*
+ * check situation
+ */
+static int
+check_situation(sit)
+	u_int32_t sit;
+{
+	switch (sit) {
+	case IPSECDOI_SIT_IDENTITY_ONLY:
+		return 0;
+
+	case IPSECDOI_SIT_SECRECY:
+	case IPSECDOI_SIT_INTEGRITY:
+		plog(LLV_ERROR, LOCATION, NULL,
+			"situation 0x%08x unsupported yet.\n", sit);
+		return -1;
+
+	default:
+		plog(LLV_ERROR, LOCATION, NULL,
+			"invalid situation 0x%08x.\n", sit);
+		return -1;
+	}
+	/* NOT REACHED */
+}
+
+/*
+ * check protocol id in main mode
+ */
+static int
+check_prot_main(proto_id)
+	int proto_id;
+{
+	switch (proto_id) {
+	case IPSECDOI_PROTO_ISAKMP:
+		return 0;
+
+	default:
+		plog(LLV_ERROR, LOCATION, NULL,
+			"Illegal protocol id=%u.\n", proto_id);
+		return -1;
+	}
+	/* NOT REACHED */
+}
+
+/*
+ * check protocol id in quick mode
+ */
+static int
+check_prot_quick(proto_id)
+	int proto_id;
+{
+	switch (proto_id) {
+	case IPSECDOI_PROTO_IPSEC_AH:
+	case IPSECDOI_PROTO_IPSEC_ESP:
+		return 0;
+
+	case IPSECDOI_PROTO_IPCOMP:
+		return 0;
+
+	default:
+		plog(LLV_ERROR, LOCATION, NULL,
+			"invalid protocol id %d.\n", proto_id);
+		return -1;
+	}
+	/* NOT REACHED */
+}
+
+static int
+check_spi_size(proto_id, size)
+	int proto_id, size;
+{
+	switch (proto_id) {
+	case IPSECDOI_PROTO_ISAKMP:
+		if (size != 0) {
+			/* WARNING */
+			plog(LLV_WARNING, LOCATION, NULL,
+				"SPI size isn't zero, but IKE proposal.\n");
+		}
+		return 0;
+
+	case IPSECDOI_PROTO_IPSEC_AH:
+	case IPSECDOI_PROTO_IPSEC_ESP:
+		if (size != 4) {
+			plog(LLV_ERROR, LOCATION, NULL,
+				"invalid SPI size=%d for IPSEC proposal.\n",
+				size);
+			return -1;
+		}
+		return 0;
+
+	case IPSECDOI_PROTO_IPCOMP:
+		if (size != 2 && size != 4) {
+			plog(LLV_ERROR, LOCATION, NULL,
+				"invalid SPI size=%d for IPCOMP proposal.\n",
+				size);
+			return -1;
+		}
+		return 0;
+
+	default:
+		/* ??? */
+		return -1;
+	}
+	/* NOT REACHED */
+}
+
+/*
+ * check transform ID in ISAKMP.
+ */
+static int
+check_trns_isakmp(t_id)
+	int t_id;
+{
+	switch (t_id) {
+	case IPSECDOI_KEY_IKE:
+		return 0;
+	default:
+		plog(LLV_ERROR, LOCATION, NULL,
+			"invalid transform-id=%u in proto_id=%u.\n",
+			t_id, IPSECDOI_KEY_IKE);
+		return -1;
+	}
+	/* NOT REACHED */
+}
+
+/*
+ * check transform ID in AH.
+ */
+static int
+check_trns_ah(t_id)
+	int t_id;
+{
+	switch (t_id) {
+	case IPSECDOI_AH_MD5:
+	case IPSECDOI_AH_SHA:
+	case IPSECDOI_AH_SHA256:
+	case IPSECDOI_AH_SHA384:
+	case IPSECDOI_AH_SHA512:
+		return 0;
+	case IPSECDOI_AH_DES:
+		plog(LLV_ERROR, LOCATION, NULL,
+			"not support transform-id=%u in AH.\n", t_id);
+		return -1;
+	default:
+		plog(LLV_ERROR, LOCATION, NULL,
+			"invalid transform-id=%u in AH.\n", t_id);
+		return -1;
+	}
+	/* NOT REACHED */
+}
+
+/*
+ * check transform ID in ESP.
+ */
+static int
+check_trns_esp(t_id)
+	int t_id;
+{
+	switch (t_id) {
+	case IPSECDOI_ESP_DES:
+	case IPSECDOI_ESP_3DES:
+	case IPSECDOI_ESP_NULL:
+	case IPSECDOI_ESP_RC5:
+	case IPSECDOI_ESP_CAST:
+	case IPSECDOI_ESP_BLOWFISH:
+	case IPSECDOI_ESP_AES:
+	case IPSECDOI_ESP_TWOFISH:
+	case IPSECDOI_ESP_CAMELLIA:
+		return 0;
+	case IPSECDOI_ESP_DES_IV32:
+	case IPSECDOI_ESP_DES_IV64:
+	case IPSECDOI_ESP_IDEA:
+	case IPSECDOI_ESP_3IDEA:
+	case IPSECDOI_ESP_RC4:
+		plog(LLV_ERROR, LOCATION, NULL,
+			"not support transform-id=%u in ESP.\n", t_id);
+		return -1;
+	default:
+		plog(LLV_ERROR, LOCATION, NULL,
+			"invalid transform-id=%u in ESP.\n", t_id);
+		return -1;
+	}
+	/* NOT REACHED */
+}
+
+/*
+ * check transform ID in IPCOMP.
+ */
+static int
+check_trns_ipcomp(t_id)
+	int t_id;
+{
+	switch (t_id) {
+	case IPSECDOI_IPCOMP_OUI:
+	case IPSECDOI_IPCOMP_DEFLATE:
+	case IPSECDOI_IPCOMP_LZS:
+		return 0;
+	default:
+		plog(LLV_ERROR, LOCATION, NULL,
+			"invalid transform-id=%u in IPCOMP.\n", t_id);
+		return -1;
+	}
+	/* NOT REACHED */
+}
+
+/*
+ * check data attributes in IKE.
+ */
+static int
+check_attr_isakmp(trns)
+	struct isakmp_pl_t *trns;
+{
+	struct isakmp_data *d;
+	int tlen;
+	int flag, type;
+	u_int16_t lorv;
+
+	tlen = ntohs(trns->h.len) - sizeof(struct isakmp_pl_t);
+	d = (struct isakmp_data *)((caddr_t)trns + sizeof(struct isakmp_pl_t));
+
+	while (tlen > 0) {
+		type = ntohs(d->type) & ~ISAKMP_GEN_MASK;
+		flag = ntohs(d->type) & ISAKMP_GEN_MASK;
+		lorv = ntohs(d->lorv);
+
+		plog(LLV_DEBUG, LOCATION, NULL,
+			"type=%s, flag=0x%04x, lorv=%s\n",
+			s_oakley_attr(type), flag,
+			s_oakley_attr_v(type, lorv));
+
+		/*
+		 * some of the attributes must be encoded in TV.
+		 * see RFC2409 Appendix A "Attribute Classes".
+		 */
+		switch (type) {
+		case OAKLEY_ATTR_ENC_ALG:
+		case OAKLEY_ATTR_HASH_ALG:
+		case OAKLEY_ATTR_AUTH_METHOD:
+		case OAKLEY_ATTR_GRP_DESC:
+		case OAKLEY_ATTR_GRP_TYPE:
+		case OAKLEY_ATTR_SA_LD_TYPE:
+		case OAKLEY_ATTR_PRF:
+		case OAKLEY_ATTR_KEY_LEN:
+		case OAKLEY_ATTR_FIELD_SIZE:
+			if (!flag) {	/* TLV*/
+				plog(LLV_ERROR, LOCATION, NULL,
+					"oakley attribute %d must be TV.\n",
+					type);
+				return -1;
+			}
+			break;
+		}
+
+		/* sanity check for TLV.  length must be specified. */
+		if (!flag && lorv == 0) {	/*TLV*/
+			plog(LLV_ERROR, LOCATION, NULL,
+				"invalid length %d for TLV attribute %d.\n",
+				lorv, type);
+			return -1;
+		}
+
+		switch (type) {
+		case OAKLEY_ATTR_ENC_ALG:
+			if (!alg_oakley_encdef_ok(lorv)) {
+				plog(LLV_ERROR, LOCATION, NULL,
+					"invalied encryption algorithm=%d.\n",
+					lorv);
+				return -1;
+			}
+			break;
+
+		case OAKLEY_ATTR_HASH_ALG:
+			if (!alg_oakley_hashdef_ok(lorv)) {
+				plog(LLV_ERROR, LOCATION, NULL,
+					"invalied hash algorithm=%d.\n",
+					lorv);
+				return -1;
+			}
+			break;
+
+		case OAKLEY_ATTR_AUTH_METHOD:
+			switch (lorv) {
+			case OAKLEY_ATTR_AUTH_METHOD_PSKEY:
+			case OAKLEY_ATTR_AUTH_METHOD_RSASIG:
+#ifdef ENABLE_HYBRID
+			case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I:
+			case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_I:
+#if 0 /* Clashes with OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB */
+			case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_I:
+#endif
+#endif
+			case OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB:
+				break;
+			case OAKLEY_ATTR_AUTH_METHOD_DSSSIG:
+#ifdef ENABLE_HYBRID
+			case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_R:
+			case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_R:
+			case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_R:
+			case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_I:
+			case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_R:
+			case OAKLEY_ATTR_AUTH_METHOD_XAUTH_DSSSIG_I:
+			case OAKLEY_ATTR_AUTH_METHOD_XAUTH_DSSSIG_R:
+			case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAENC_I:
+			case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAENC_R:
+			case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAREV_I:
+			case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAREV_R:
+#endif
+			case OAKLEY_ATTR_AUTH_METHOD_RSAENC:
+			case OAKLEY_ATTR_AUTH_METHOD_RSAREV:
+				plog(LLV_ERROR, LOCATION, NULL,
+					"auth method %s isn't supported.\n",
+					s_oakley_attr_method(lorv));
+				return -1;
+			default:
+				plog(LLV_ERROR, LOCATION, NULL,
+					"invalid auth method %d.\n",
+					lorv);
+				return -1;
+			}
+			break;
+
+		case OAKLEY_ATTR_GRP_DESC:
+			if (!alg_oakley_dhdef_ok(lorv)) {
+				plog(LLV_ERROR, LOCATION, NULL,
+					"invalid DH group %d.\n",
+					lorv);
+				return -1;
+			}
+			break;
+
+		case OAKLEY_ATTR_GRP_TYPE:
+			switch (lorv) {
+			case OAKLEY_ATTR_GRP_TYPE_MODP:
+				break;
+			default:
+				plog(LLV_ERROR, LOCATION, NULL,
+					"unsupported DH group type %d.\n",
+					lorv);
+				return -1;
+			}
+			break;
+
+		case OAKLEY_ATTR_GRP_PI:
+		case OAKLEY_ATTR_GRP_GEN_ONE:
+			/* sanity checks? */
+			break;
+
+		case OAKLEY_ATTR_GRP_GEN_TWO:
+		case OAKLEY_ATTR_GRP_CURVE_A:
+		case OAKLEY_ATTR_GRP_CURVE_B:
+			plog(LLV_ERROR, LOCATION, NULL,
+				"attr type=%u isn't supported.\n", type);
+			return -1;
+
+		case OAKLEY_ATTR_SA_LD_TYPE:
+			switch (lorv) {
+			case OAKLEY_ATTR_SA_LD_TYPE_SEC:
+			case OAKLEY_ATTR_SA_LD_TYPE_KB:
+				break;
+			default:
+				plog(LLV_ERROR, LOCATION, NULL,
+					"invalid life type %d.\n", lorv);
+				return -1;
+			}
+			break;
+
+		case OAKLEY_ATTR_SA_LD:
+			/* should check the value */
+			break;
+
+		case OAKLEY_ATTR_PRF:
+		case OAKLEY_ATTR_KEY_LEN:
+			break;
+
+		case OAKLEY_ATTR_FIELD_SIZE:
+			plog(LLV_ERROR, LOCATION, NULL,
+				"attr type=%u isn't supported.\n", type);
+			return -1;
+
+		case OAKLEY_ATTR_GRP_ORDER:
+			break;
+
+		case OAKLEY_ATTR_GSS_ID:
+			break;
+
+		default:
+			plog(LLV_ERROR, LOCATION, NULL,
+				"invalid attribute type %d.\n", type);
+			return -1;
+		}
+
+		if (flag) {
+			tlen -= sizeof(*d);
+			d = (struct isakmp_data *)((char *)d
+				+ sizeof(*d));
+		} else {
+			tlen -= (sizeof(*d) + lorv);
+			d = (struct isakmp_data *)((char *)d
+				+ sizeof(*d) + lorv);
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * check data attributes in IPSEC AH/ESP.
+ */
+static int
+check_attr_ah(trns)
+	struct isakmp_pl_t *trns;
+{
+	return check_attr_ipsec(IPSECDOI_PROTO_IPSEC_AH, trns);
+}
+
+static int
+check_attr_esp(trns)
+	struct isakmp_pl_t *trns;
+{
+	return check_attr_ipsec(IPSECDOI_PROTO_IPSEC_ESP, trns);
+}
+
+static int
+check_attr_ipsec(proto_id, trns)
+	int proto_id;
+	struct isakmp_pl_t *trns;
+{
+	struct isakmp_data *d;
+	int tlen;
+	int flag, type = 0;
+	u_int16_t lorv;
+	int attrseen[16];	/* XXX magic number */
+
+	tlen = ntohs(trns->h.len) - sizeof(struct isakmp_pl_t);
+	d = (struct isakmp_data *)((caddr_t)trns + sizeof(struct isakmp_pl_t));
+	memset(attrseen, 0, sizeof(attrseen));
+
+	while (tlen > 0) {
+		type = ntohs(d->type) & ~ISAKMP_GEN_MASK;
+		flag = ntohs(d->type) & ISAKMP_GEN_MASK;
+		lorv = ntohs(d->lorv);
+
+		plog(LLV_DEBUG, LOCATION, NULL,
+			"type=%s, flag=0x%04x, lorv=%s\n",
+			s_ipsecdoi_attr(type), flag,
+			s_ipsecdoi_attr_v(type, lorv));
+
+		if (type < sizeof(attrseen)/sizeof(attrseen[0]))
+			attrseen[type]++;
+
+		switch (type) {
+		case IPSECDOI_ATTR_ENC_MODE:
+			if (! flag) {
+				plog(LLV_ERROR, LOCATION, NULL,
+					"must be TV when ENC_MODE.\n");
+				return -1;
+			}
+
+			switch (lorv) {
+			case IPSECDOI_ATTR_ENC_MODE_TUNNEL:
+			case IPSECDOI_ATTR_ENC_MODE_TRNS:
+				break;
+#ifdef ENABLE_NATT
+			case IPSECDOI_ATTR_ENC_MODE_UDPTUNNEL_RFC:
+			case IPSECDOI_ATTR_ENC_MODE_UDPTRNS_RFC:
+			case IPSECDOI_ATTR_ENC_MODE_UDPTUNNEL_DRAFT:
+			case IPSECDOI_ATTR_ENC_MODE_UDPTRNS_DRAFT:
+				plog(LLV_DEBUG, LOCATION, NULL,
+				     "UDP encapsulation requested\n");
+				break;
+#endif
+			default:
+				plog(LLV_ERROR, LOCATION, NULL,
+					"invalid encryption mode=%u.\n",
+					lorv);
+				return -1;
+			}
+			break;
+
+		case IPSECDOI_ATTR_AUTH:
+			if (! flag) {
+				plog(LLV_ERROR, LOCATION, NULL,
+					"must be TV when AUTH.\n");
+				return -1;
+			}
+
+			switch (lorv) {
+			case IPSECDOI_ATTR_AUTH_HMAC_MD5:
+				if (proto_id == IPSECDOI_PROTO_IPSEC_AH &&
+				    trns->t_id != IPSECDOI_AH_MD5) {
+ahmismatch:
+					plog(LLV_ERROR, LOCATION, NULL,
+						"auth algorithm %u conflicts "
+						"with transform %u.\n",
+						lorv, trns->t_id);
+					return -1;
+				}
+				break;
+			case IPSECDOI_ATTR_AUTH_HMAC_SHA1:
+				if (proto_id == IPSECDOI_PROTO_IPSEC_AH) {
+					if (trns->t_id != IPSECDOI_AH_SHA)
+						goto ahmismatch;
+				}
+				break;
+ 			case IPSECDOI_ATTR_AUTH_HMAC_SHA2_256:
+ 				if (proto_id == IPSECDOI_PROTO_IPSEC_AH) {
+ 					if (trns->t_id != IPSECDOI_AH_SHA256)
+ 						goto ahmismatch;
+ 				}	
+ 				break;
+ 			case IPSECDOI_ATTR_AUTH_HMAC_SHA2_384:
+ 				if (proto_id == IPSECDOI_PROTO_IPSEC_AH) {
+ 					if (trns->t_id != IPSECDOI_AH_SHA384)
+ 						goto ahmismatch;
+ 				}
+ 				break;
+ 			case IPSECDOI_ATTR_AUTH_HMAC_SHA2_512:
+ 				if (proto_id == IPSECDOI_PROTO_IPSEC_AH) {
+ 					if (trns->t_id != IPSECDOI_AH_SHA512)
+ 					goto ahmismatch;
+ 				}
+ 				break;
+			case IPSECDOI_ATTR_AUTH_DES_MAC:
+			case IPSECDOI_ATTR_AUTH_KPDK:
+				plog(LLV_ERROR, LOCATION, NULL,
+					"auth algorithm %u isn't supported.\n",
+					lorv);
+				return -1;
+			default:
+				plog(LLV_ERROR, LOCATION, NULL,
+					"invalid auth algorithm=%u.\n",
+					lorv);
+				return -1;
+			}
+			break;
+
+		case IPSECDOI_ATTR_SA_LD_TYPE:
+			if (! flag) {
+				plog(LLV_ERROR, LOCATION, NULL,
+					"must be TV when LD_TYPE.\n");
+				return -1;
+			}
+
+			switch (lorv) {
+			case IPSECDOI_ATTR_SA_LD_TYPE_SEC:
+			case IPSECDOI_ATTR_SA_LD_TYPE_KB:
+				break;
+			default:
+				plog(LLV_ERROR, LOCATION, NULL,
+					"invalid life type %d.\n", lorv);
+				return -1;
+			}
+			break;
+
+		case IPSECDOI_ATTR_SA_LD:
+			if (flag) {
+				/* i.e. ISAKMP_GEN_TV */
+				plog(LLV_DEBUG, LOCATION, NULL,
+					"life duration was in TLV.\n");
+			} else {
+				/* i.e. ISAKMP_GEN_TLV */
+				if (lorv == 0) {
+					plog(LLV_ERROR, LOCATION, NULL,
+						"invalid length of LD\n");
+					return -1;
+				}
+			}
+			break;
+
+		case IPSECDOI_ATTR_GRP_DESC:
+			if (! flag) {
+				plog(LLV_ERROR, LOCATION, NULL,
+					"must be TV when GRP_DESC.\n");
+				return -1;
+			}
+
+			if (!alg_oakley_dhdef_ok(lorv)) {
+				plog(LLV_ERROR, LOCATION, NULL,
+					"invalid group description=%u.\n",
+					lorv);
+				return -1;
+			}
+			break;
+
+		case IPSECDOI_ATTR_KEY_LENGTH:
+			if (! flag) {
+				plog(LLV_ERROR, LOCATION, NULL,
+					"must be TV when KEY_LENGTH.\n");
+				return -1;
+			}
+			break;
+
+#ifdef HAVE_SECCTX
+		case IPSECDOI_ATTR_SECCTX:
+			if (flag) {
+				plog(LLV_ERROR, LOCATION, NULL,
+					"SECCTX must be in TLV.\n");
+				return -1;
+			}
+		break;
+#endif
+
+		case IPSECDOI_ATTR_KEY_ROUNDS:
+		case IPSECDOI_ATTR_COMP_DICT_SIZE:
+		case IPSECDOI_ATTR_COMP_PRIVALG:
+			plog(LLV_ERROR, LOCATION, NULL,
+				"attr type=%u isn't supported.\n", type);
+			return -1;
+
+		default:
+			plog(LLV_ERROR, LOCATION, NULL,
+				"invalid attribute type %d.\n", type);
+			return -1;
+		}
+
+		if (flag) {
+			tlen -= sizeof(*d);
+			d = (struct isakmp_data *)((char *)d
+				+ sizeof(*d));
+		} else {
+			tlen -= (sizeof(*d) + lorv);
+			d = (struct isakmp_data *)((caddr_t)d
+				+ sizeof(*d) + lorv);
+		}
+	}
+
+	if (proto_id == IPSECDOI_PROTO_IPSEC_AH &&
+	    !attrseen[IPSECDOI_ATTR_AUTH]) {
+		plog(LLV_ERROR, LOCATION, NULL,
+			"attr AUTH must be present for AH.\n");
+		return -1;
+	}
+
+	if (proto_id == IPSECDOI_PROTO_IPSEC_ESP &&
+	    trns->t_id == IPSECDOI_ESP_NULL &&
+	    !attrseen[IPSECDOI_ATTR_AUTH]) {
+		plog(LLV_ERROR, LOCATION, NULL,
+		    "attr AUTH must be present for ESP NULL encryption.\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int
+check_attr_ipcomp(trns)
+	struct isakmp_pl_t *trns;
+{
+	struct isakmp_data *d;
+	int tlen;
+	int flag, type = 0;
+	u_int16_t lorv;
+	int attrseen[16];	/* XXX magic number */
+
+	tlen = ntohs(trns->h.len) - sizeof(struct isakmp_pl_t);
+	d = (struct isakmp_data *)((caddr_t)trns + sizeof(struct isakmp_pl_t));
+	memset(attrseen, 0, sizeof(attrseen));
+
+	while (tlen > 0) {
+		type = ntohs(d->type) & ~ISAKMP_GEN_MASK;
+		flag = ntohs(d->type) & ISAKMP_GEN_MASK;
+		lorv = ntohs(d->lorv);
+
+		plog(LLV_DEBUG, LOCATION, NULL,
+			"type=%d, flag=0x%04x, lorv=0x%04x\n",
+			type, flag, lorv);
+
+		if (type < sizeof(attrseen)/sizeof(attrseen[0]))
+			attrseen[type]++;
+
+		switch (type) {
+		case IPSECDOI_ATTR_ENC_MODE:
+			if (! flag) {
+				plog(LLV_ERROR, LOCATION, NULL,
+					"must be TV when ENC_MODE.\n");
+				return -1;
+			}
+
+			switch (lorv) {
+			case IPSECDOI_ATTR_ENC_MODE_TUNNEL:
+			case IPSECDOI_ATTR_ENC_MODE_TRNS:
+				break;
+#ifdef ENABLE_NATT
+			case IPSECDOI_ATTR_ENC_MODE_UDPTUNNEL_RFC:
+			case IPSECDOI_ATTR_ENC_MODE_UDPTRNS_RFC:
+			case IPSECDOI_ATTR_ENC_MODE_UDPTUNNEL_DRAFT:
+			case IPSECDOI_ATTR_ENC_MODE_UDPTRNS_DRAFT:
+				plog(LLV_DEBUG, LOCATION, NULL,
+				     "UDP encapsulation requested\n");
+				break;
+#endif
+			default:
+				plog(LLV_ERROR, LOCATION, NULL,
+					"invalid encryption mode=%u.\n",
+					lorv);
+				return -1;
+			}
+			break;
+
+		case IPSECDOI_ATTR_SA_LD_TYPE:
+			if (! flag) {
+				plog(LLV_ERROR, LOCATION, NULL,
+					"must be TV when LD_TYPE.\n");
+				return -1;
+			}
+
+			switch (lorv) {
+			case IPSECDOI_ATTR_SA_LD_TYPE_SEC:
+			case IPSECDOI_ATTR_SA_LD_TYPE_KB:
+				break;
+			default:
+				plog(LLV_ERROR, LOCATION, NULL,
+					"invalid life type %d.\n", lorv);
+				return -1;
+			}
+			break;
+
+		case IPSECDOI_ATTR_SA_LD:
+			if (flag) {
+				/* i.e. ISAKMP_GEN_TV */
+				plog(LLV_DEBUG, LOCATION, NULL,
+					"life duration was in TLV.\n");
+			} else {
+				/* i.e. ISAKMP_GEN_TLV */
+				if (lorv == 0) {
+					plog(LLV_ERROR, LOCATION, NULL,
+						"invalid length of LD\n");
+					return -1;
+				}
+			}
+			break;
+
+		case IPSECDOI_ATTR_GRP_DESC:
+			if (! flag) {
+				plog(LLV_ERROR, LOCATION, NULL,
+					"must be TV when GRP_DESC.\n");
+				return -1;
+			}
+
+			if (!alg_oakley_dhdef_ok(lorv)) {
+				plog(LLV_ERROR, LOCATION, NULL,
+					"invalid group description=%u.\n",
+					lorv);
+				return -1;
+			}
+			break;
+
+		case IPSECDOI_ATTR_AUTH:
+			plog(LLV_ERROR, LOCATION, NULL,
+				"invalid attr type=%u.\n", type);
+			return -1;
+
+		case IPSECDOI_ATTR_KEY_LENGTH:
+		case IPSECDOI_ATTR_KEY_ROUNDS:
+		case IPSECDOI_ATTR_COMP_DICT_SIZE:
+		case IPSECDOI_ATTR_COMP_PRIVALG:
+			plog(LLV_ERROR, LOCATION, NULL,
+				"attr type=%u isn't supported.\n", type);
+			return -1;
+
+		default:
+			plog(LLV_ERROR, LOCATION, NULL,
+				"invalid attribute type %d.\n", type);
+			return -1;
+		}
+
+		if (flag) {
+			tlen -= sizeof(*d);
+			d = (struct isakmp_data *)((char *)d
+				+ sizeof(*d));
+		} else {
+			tlen -= (sizeof(*d) + lorv);
+			d = (struct isakmp_data *)((caddr_t)d
+				+ sizeof(*d) + lorv);
+		}
+	}
+
+#if 0
+	if (proto_id == IPSECDOI_PROTO_IPCOMP &&
+	    !attrseen[IPSECDOI_ATTR_AUTH]) {
+		plog(LLV_ERROR, LOCATION, NULL,
+			"attr AUTH must be present for AH.\n", type);
+		return -1;
+	}
+#endif
+
+	return 0;
+}
+
+/* %%% */
+/*
+ * create phase1 proposal from remote configuration.
+ * NOT INCLUDING isakmp general header of SA payload
+ */
+vchar_t *
+ipsecdoi_setph1proposal(rmconf, props)
+	struct remoteconf *rmconf;
+	struct isakmpsa *props;
+{
+	vchar_t *mysa;
+	int sablen;
+
+	/* count total size of SA minus isakmp general header */
+	/* not including isakmp general header of SA payload */
+	sablen = sizeof(struct ipsecdoi_sa_b);
+	sablen += setph1prop(props, NULL);
+
+	mysa = vmalloc(sablen);
+	if (mysa == NULL) {
+		plog(LLV_ERROR, LOCATION, NULL,
+			"failed to allocate my sa buffer\n");
+		return NULL;
+	}
+
+	/* create SA payload */
+	/* not including isakmp general header */
+	((struct ipsecdoi_sa_b *)mysa->v)->doi = htonl(rmconf->doitype);
+	((struct ipsecdoi_sa_b *)mysa->v)->sit = htonl(rmconf->sittype);
+
+	(void)setph1prop(props, mysa->v + sizeof(struct ipsecdoi_sa_b));
+
+	return mysa;
+}
+
+static int
+setph1prop(props, buf)
+	struct isakmpsa *props;
+	caddr_t buf;
+{
+	struct isakmp_pl_p *prop = NULL;
+	struct isakmpsa *s = NULL;
+	int proplen, trnslen;
+	u_int8_t *np_t; /* pointer next trns type in previous header */
+	int trns_num;
+	caddr_t p = buf;
+
+	proplen = sizeof(*prop);
+	if (buf) {
+		/* create proposal */
+		prop = (struct isakmp_pl_p *)p;
+		prop->h.np = ISAKMP_NPTYPE_NONE;
+		prop->p_no = props->prop_no;
+		prop->proto_id = IPSECDOI_PROTO_ISAKMP;
+		prop->spi_size = 0;
+		p += sizeof(*prop);
+	}
+
+	np_t = NULL;
+	trns_num = 0;
+
+	for (s = props; s != NULL; s = s->next) {
+		if (np_t)
+			*np_t = ISAKMP_NPTYPE_T;
+
+		trnslen = setph1trns(s, p);
+		proplen += trnslen;
+		if (buf) {
+			/* save buffer to pre-next payload */
+			np_t = &((struct isakmp_pl_t *)p)->h.np;
+			p += trnslen;
+
+			/* count up transform length */
+			trns_num++;
+		}
+	}
+
+	/* update proposal length */
+	if (buf) {
+		prop->h.len = htons(proplen);
+		prop->num_t = trns_num;
+	}
+
+	return proplen;
+}
+
+static int
+setph1trns(sa, buf)
+	struct isakmpsa *sa;
+	caddr_t buf;
+{
+	struct isakmp_pl_t *trns = NULL;
+	int trnslen, attrlen;
+	caddr_t p = buf;
+
+	trnslen = sizeof(*trns);
+	if (buf) {
+		/* create transform */
+		trns = (struct isakmp_pl_t *)p;
+		trns->h.np  = ISAKMP_NPTYPE_NONE;
+		trns->t_no  = sa->trns_no;
+		trns->t_id  = IPSECDOI_KEY_IKE;
+		p += sizeof(*trns);
+	}
+
+	attrlen = setph1attr(sa, p);
+	trnslen += attrlen;
+	if (buf)
+		p += attrlen;
+
+	if (buf)
+		trns->h.len = htons(trnslen);
+
+	return trnslen;
+}
+
+static int
+setph1attr(sa, buf)
+	struct isakmpsa *sa;
+	caddr_t buf;
+{
+	caddr_t p = buf;
+	int attrlen = 0;
+
+	if (sa->lifetime) {
+		u_int32_t lifetime = htonl((u_int32_t)sa->lifetime);
+
+		attrlen += sizeof(struct isakmp_data)
+			+ sizeof(struct isakmp_data);
+		if (sa->lifetime > 0xffff)
+			attrlen += sizeof(lifetime);
+		if (buf) {
+			p = isakmp_set_attr_l(p, OAKLEY_ATTR_SA_LD_TYPE,
+						OAKLEY_ATTR_SA_LD_TYPE_SEC);
+			if (sa->lifetime > 0xffff) {
+				p = isakmp_set_attr_v(p, OAKLEY_ATTR_SA_LD,
+						(caddr_t)&lifetime, 
+						sizeof(lifetime));
+			} else {
+				p = isakmp_set_attr_l(p, OAKLEY_ATTR_SA_LD,
+							sa->lifetime);
+			}
+		}
+	}
+
+	if (sa->lifebyte) {
+		u_int32_t lifebyte = htonl((u_int32_t)sa->lifebyte);
+		
+		attrlen += sizeof(struct isakmp_data)
+			+ sizeof(struct isakmp_data);
+		if (sa->lifebyte > 0xffff)
+			attrlen += sizeof(lifebyte);
+		if (buf) {
+			p = isakmp_set_attr_l(p, OAKLEY_ATTR_SA_LD_TYPE,
+						OAKLEY_ATTR_SA_LD_TYPE_KB);
+			if (sa->lifebyte > 0xffff) {
+				p = isakmp_set_attr_v(p, OAKLEY_ATTR_SA_LD,
+							(caddr_t)&lifebyte,
+							sizeof(lifebyte));
+			} else {
+				p = isakmp_set_attr_l(p, OAKLEY_ATTR_SA_LD,
+							sa->lifebyte);
+			}
+		}
+	}
+
+	if (sa->enctype) {
+		attrlen += sizeof(struct isakmp_data);
+		if (buf)
+			p = isakmp_set_attr_l(p, OAKLEY_ATTR_ENC_ALG, sa->enctype);
+	}
+	if (sa->encklen) {
+		attrlen += sizeof(struct isakmp_data);
+		if (buf)
+			p = isakmp_set_attr_l(p, OAKLEY_ATTR_KEY_LEN, sa->encklen);
+	}
+	if (sa->authmethod) {
+		int authmethod;
+
+#ifdef ENABLE_HYBRID
+		authmethod = switch_authmethod(sa->authmethod);
+#else
+		authmethod = sa->authmethod;
+#endif
+		attrlen += sizeof(struct isakmp_data);
+		if (buf)
+			p = isakmp_set_attr_l(p, OAKLEY_ATTR_AUTH_METHOD, authmethod);
+	}
+	if (sa->hashtype) {
+		attrlen += sizeof(struct isakmp_data);
+		if (buf)
+			p = isakmp_set_attr_l(p, OAKLEY_ATTR_HASH_ALG, sa->hashtype);
+	}
+	switch (sa->dh_group) {
+	case OAKLEY_ATTR_GRP_DESC_MODP768:
+	case OAKLEY_ATTR_GRP_DESC_MODP1024:
+	case OAKLEY_ATTR_GRP_DESC_MODP1536:
+	case OAKLEY_ATTR_GRP_DESC_MODP2048:
+	case OAKLEY_ATTR_GRP_DESC_MODP3072:
+	case OAKLEY_ATTR_GRP_DESC_MODP4096:
+	case OAKLEY_ATTR_GRP_DESC_MODP6144:
+	case OAKLEY_ATTR_GRP_DESC_MODP8192:
+		/* don't attach group type for known groups */
+		attrlen += sizeof(struct isakmp_data);
+		if (buf) {
+			p = isakmp_set_attr_l(p, OAKLEY_ATTR_GRP_DESC,
+				sa->dh_group);
+		}
+		break;
+	case OAKLEY_ATTR_GRP_DESC_EC2N155:
+	case OAKLEY_ATTR_GRP_DESC_EC2N185:
+		/* don't attach group type for known groups */
+		attrlen += sizeof(struct isakmp_data);
+		if (buf) {
+			p = isakmp_set_attr_l(p, OAKLEY_ATTR_GRP_TYPE,
+				OAKLEY_ATTR_GRP_TYPE_EC2N);
+		}
+		break;
+	case 0:
+	default:
+		break;
+	}
+
+#ifdef HAVE_GSSAPI
+	if (sa->authmethod == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB &&
+	    sa->gssid != NULL) {
+		attrlen += sizeof(struct isakmp_data);
+		/*
+		 * Older versions of racoon just placed the ISO-Latin-1
+		 * string on the wire directly.  Check to see if we are
+		 * configured to be compatible with this behavior.  Otherwise,
+		 * we encode the GSS ID as UTF-16LE for Windows 2000
+		 * compatibility, which requires twice the number of octets.
+		 */
+		if (lcconf->gss_id_enc == LC_GSSENC_LATIN1)
+			attrlen += sa->gssid->l;
+		else
+			attrlen += sa->gssid->l * 2;
+		if (buf) {
+			plog(LLV_DEBUG, LOCATION, NULL, "gss id attr: len %zu, "
+			    "val '%.*s'\n", sa->gssid->l, (int)sa->gssid->l,
+			    sa->gssid->v);
+			if (lcconf->gss_id_enc == LC_GSSENC_LATIN1) {
+				p = isakmp_set_attr_v(p, OAKLEY_ATTR_GSS_ID,
+					(caddr_t)sa->gssid->v,
+					sa->gssid->l);
+			} else {
+				size_t dstleft = sa->gssid->l * 2;
+				size_t srcleft = sa->gssid->l;
+				const char *src = (const char *)sa->gssid->v;
+				char *odst, *dst = racoon_malloc(dstleft);
+				iconv_t cd;
+				size_t rv;
+
+				cd = iconv_open("utf-16le", "latin1");
+				if (cd == (iconv_t) -1) {
+					plog(LLV_ERROR, LOCATION, NULL,
+					    "unable to initialize "
+					    "latin1 -> utf-16le "
+					    "converstion descriptor: %s\n",
+					    strerror(errno));
+					attrlen -= sa->gssid->l * 2;
+					goto gssid_done;
+				}
+				odst = dst;
+				rv = iconv(cd, (__iconv_const char **)&src, 
+				    &srcleft, &dst, &dstleft);
+				if (rv != 0) {
+					if (rv == -1) {
+						plog(LLV_ERROR, LOCATION, NULL,
+						    "unable to convert GSS ID "
+						    "from latin1 -> utf-16le: "
+						    "%s\n", strerror(errno));
+					} else {
+						/* should never happen */
+						plog(LLV_ERROR, LOCATION, NULL,
+						    "%zd character%s in GSS ID "
+						    "cannot be represented "
+						    "in utf-16le\n",
+						    rv, rv == 1 ? "" : "s");
+					}
+					(void) iconv_close(cd);
+					attrlen -= sa->gssid->l * 2;
+					goto gssid_done;
+				}
+				(void) iconv_close(cd);
+
+				/* XXX Check srcleft and dstleft? */
+
+				p = isakmp_set_attr_v(p, OAKLEY_ATTR_GSS_ID,
+					odst, sa->gssid->l * 2);
+
+				racoon_free(odst);
+			}
+		}
+	}
+ gssid_done:
+#endif /* HAVE_GSSAPI */
+
+	return attrlen;
+}
+
+static vchar_t *
+setph2proposal0(iph2, pp, pr)
+	const struct ph2handle *iph2;
+	const struct saprop *pp;
+	const struct saproto *pr;
+{
+	vchar_t *p;
+	struct isakmp_pl_p *prop;
+	struct isakmp_pl_t *trns;
+	struct satrns *tr;
+	int attrlen;
+	size_t trnsoff;
+	caddr_t x0, x;
+	u_int8_t *np_t; /* pointer next trns type in previous header */
+	const u_int8_t *spi;
+#ifdef HAVE_SECCTX
+	int truectxlen = 0;
+#endif
+
+	p = vmalloc(sizeof(*prop) + sizeof(pr->spi));
+	if (p == NULL)
+		return NULL;
+
+	/* create proposal */
+	prop = (struct isakmp_pl_p *)p->v;
+	prop->h.np = ISAKMP_NPTYPE_NONE;
+	prop->p_no = pp->prop_no;
+	prop->proto_id = pr->proto_id;
+	prop->num_t = 1;
+
+	spi = (const u_int8_t *)&pr->spi;
+	switch (pr->proto_id) {
+	case IPSECDOI_PROTO_IPCOMP:
+		/*
+		 * draft-shacham-ippcp-rfc2393bis-05.txt:
+		 * construct 16bit SPI (CPI).
+		 * XXX we may need to provide a configuration option to
+		 * generate 32bit SPI.  otherwise we cannot interoeprate
+		 * with nodes that uses 32bit SPI, in case we are initiator.
+		 */
+		prop->spi_size = sizeof(u_int16_t);
+		spi += sizeof(pr->spi) - sizeof(u_int16_t);
+		p->l -= sizeof(pr->spi);
+		p->l += sizeof(u_int16_t);
+		break;
+	default:
+		prop->spi_size = sizeof(pr->spi);
+		break;
+	}
+	memcpy(prop + 1, spi, prop->spi_size);
+
+	/* create transform */
+	trnsoff = sizeof(*prop) + prop->spi_size;
+	np_t = NULL;
+
+	for (tr = pr->head; tr; tr = tr->next) {
+	
+		switch (pr->proto_id) {
+		case IPSECDOI_PROTO_IPSEC_ESP:
+			/*
+			 * don't build a null encryption
+			 * with no authentication transform.
+			 */
+			if (tr->trns_id == IPSECDOI_ESP_NULL &&
+			    tr->authtype == IPSECDOI_ATTR_AUTH_NONE)
+				continue;
+			break;
+		}
+
+		if (np_t) {
+			*np_t = ISAKMP_NPTYPE_T;
+			prop->num_t++;
+		}
+
+		/* get attribute length */
+		attrlen = 0;
+		if (pp->lifetime) {
+			attrlen += sizeof(struct isakmp_data)
+				+ sizeof(struct isakmp_data);
+			if (pp->lifetime > 0xffff)
+				attrlen += sizeof(u_int32_t);
+		}
+		if (pp->lifebyte && pp->lifebyte != IPSECDOI_ATTR_SA_LD_KB_MAX) {
+			attrlen += sizeof(struct isakmp_data)
+				+ sizeof(struct isakmp_data);
+			if (pp->lifebyte > 0xffff)
+				attrlen += sizeof(u_int32_t);
+		}
+		attrlen += sizeof(struct isakmp_data);	/* enc mode */
+		if (tr->encklen)
+			attrlen += sizeof(struct isakmp_data);
+
+		switch (pr->proto_id) {
+		case IPSECDOI_PROTO_IPSEC_ESP:
+			/* non authentication mode ? */
+			if (tr->authtype != IPSECDOI_ATTR_AUTH_NONE)
+				attrlen += sizeof(struct isakmp_data);
+			break;
+		case IPSECDOI_PROTO_IPSEC_AH:
+			if (tr->authtype == IPSECDOI_ATTR_AUTH_NONE) {
+				plog(LLV_ERROR, LOCATION, NULL,
+					"no authentication algorithm found "
+					"but protocol is AH.\n");
+				vfree(p);
+				return NULL;
+			}
+			attrlen += sizeof(struct isakmp_data);
+			break;
+		case IPSECDOI_PROTO_IPCOMP:
+			break;
+		default:
+			plog(LLV_ERROR, LOCATION, NULL,
+				"invalid protocol: %d\n", pr->proto_id);
+			vfree(p);
+			return NULL;
+		}
+
+		if (alg_oakley_dhdef_ok(iph2->sainfo->pfs_group))
+			attrlen += sizeof(struct isakmp_data);
+
+#ifdef HAVE_SECCTX
+		/* ctx_str is defined as char ctx_str[MAX_CTXSTR_SIZ].
+		 * The string may be smaller than MAX_CTXSTR_SIZ.
+		 */
+		if (*pp->sctx.ctx_str) {
+			truectxlen = sizeof(struct security_ctx) -
+				     (MAX_CTXSTR_SIZE - pp->sctx.ctx_strlen);
+			attrlen += sizeof(struct isakmp_data) + truectxlen;
+		}
+#endif /* HAVE_SECCTX */
+
+		p = vrealloc(p, p->l + sizeof(*trns) + attrlen);
+		if (p == NULL)
+			return NULL;
+		prop = (struct isakmp_pl_p *)p->v;
+
+		/* set transform's values */
+		trns = (struct isakmp_pl_t *)(p->v + trnsoff);
+		trns->h.np  = ISAKMP_NPTYPE_NONE;
+		trns->t_no  = tr->trns_no;
+		trns->t_id  = tr->trns_id;
+
+		/* set attributes */
+		x = x0 = p->v + trnsoff + sizeof(*trns);
+
+		if (pp->lifetime) {
+			x = isakmp_set_attr_l(x, IPSECDOI_ATTR_SA_LD_TYPE,
+						IPSECDOI_ATTR_SA_LD_TYPE_SEC);
+			if (pp->lifetime > 0xffff) {
+				u_int32_t v = htonl((u_int32_t)pp->lifetime);
+				x = isakmp_set_attr_v(x, IPSECDOI_ATTR_SA_LD,
+							(caddr_t)&v, sizeof(v));
+			} else {
+				x = isakmp_set_attr_l(x, IPSECDOI_ATTR_SA_LD,
+							pp->lifetime);
+			}
+		}
+
+		if (pp->lifebyte && pp->lifebyte != IPSECDOI_ATTR_SA_LD_KB_MAX) {
+			x = isakmp_set_attr_l(x, IPSECDOI_ATTR_SA_LD_TYPE,
+						IPSECDOI_ATTR_SA_LD_TYPE_KB);
+			if (pp->lifebyte > 0xffff) {
+				u_int32_t v = htonl((u_int32_t)pp->lifebyte);
+				x = isakmp_set_attr_v(x, IPSECDOI_ATTR_SA_LD,
+							(caddr_t)&v, sizeof(v));
+			} else {
+				x = isakmp_set_attr_l(x, IPSECDOI_ATTR_SA_LD,
+							pp->lifebyte);
+			}
+		}
+
+		x = isakmp_set_attr_l(x, IPSECDOI_ATTR_ENC_MODE, pr->encmode);
+
+		if (tr->encklen)
+			x = isakmp_set_attr_l(x, IPSECDOI_ATTR_KEY_LENGTH, tr->encklen);
+
+		/* mandatory check has done above. */
+		if ((pr->proto_id == IPSECDOI_PROTO_IPSEC_ESP && tr->authtype != IPSECDOI_ATTR_AUTH_NONE)
+		 || pr->proto_id == IPSECDOI_PROTO_IPSEC_AH)
+			x = isakmp_set_attr_l(x, IPSECDOI_ATTR_AUTH, tr->authtype);
+
+		if (alg_oakley_dhdef_ok(iph2->sainfo->pfs_group))
+			x = isakmp_set_attr_l(x, IPSECDOI_ATTR_GRP_DESC,
+				iph2->sainfo->pfs_group);
+
+#ifdef HAVE_SECCTX
+		if (*pp->sctx.ctx_str) {
+			struct security_ctx secctx;
+			secctx = pp->sctx;
+			secctx.ctx_strlen = htons(pp->sctx.ctx_strlen);
+			x = isakmp_set_attr_v(x, IPSECDOI_ATTR_SECCTX,
+					     (caddr_t)&secctx, truectxlen);
+		}
+#endif
+		/* update length of this transform. */
+		trns = (struct isakmp_pl_t *)(p->v + trnsoff);
+		trns->h.len = htons(sizeof(*trns) + attrlen);
+
+		/* save buffer to pre-next payload */
+		np_t = &trns->h.np;
+
+		trnsoff += (sizeof(*trns) + attrlen);
+	}
+
+	if (np_t == NULL) {
+		plog(LLV_ERROR, LOCATION, NULL,
+			"no suitable proposal was created.\n");
+		return NULL;
+	}
+
+	/* update length of this protocol. */
+	prop->h.len = htons(p->l);
+
+	return p;
+}
+
+/*
+ * create phase2 proposal from policy configuration.
+ * NOT INCLUDING isakmp general header of SA payload.
+ * This function is called by initiator only.
+ */
+int
+ipsecdoi_setph2proposal(iph2)
+	struct ph2handle *iph2;
+{
+	struct saprop *proposal, *a;
+	struct saproto *b = NULL;
+	vchar_t *q;
+	struct ipsecdoi_sa_b *sab;
+	struct isakmp_pl_p *prop;
+	size_t propoff;	/* for previous field of type of next payload. */
+
+	proposal = iph2->proposal;
+
+	iph2->sa = vmalloc(sizeof(*sab));
+	if (iph2->sa == NULL) {
+		plog(LLV_ERROR, LOCATION, NULL,
+			"failed to allocate my sa buffer\n");
+		return -1;
+	}
+
+	/* create SA payload */
+	sab = (struct ipsecdoi_sa_b *)iph2->sa->v;
+	sab->doi = htonl(IPSEC_DOI);
+	sab->sit = htonl(IPSECDOI_SIT_IDENTITY_ONLY);	/* XXX configurable ? */
+
+	prop = NULL;
+	propoff = 0;
+	for (a = proposal; a; a = a->next) {
+		for (b = a->head; b; b = b->next) {
+#ifdef ENABLE_NATT
+			if (iph2->ph1->natt_flags & NAT_DETECTED) {
+			  int udp_diff = iph2->ph1->natt_options->mode_udp_diff;
+			  plog (LLV_INFO, LOCATION, NULL,
+				"NAT detected -> UDP encapsulation "
+				"(ENC_MODE %d->%d).\n",
+				b->encmode,
+				b->encmode+udp_diff);
+			  /* Tunnel -> UDP-Tunnel, Transport -> UDP_Transport */
+			  b->encmode += udp_diff;
+			  b->udp_encap = 1;
+			}
+#endif
+
+			q = setph2proposal0(iph2, a, b);
+			if (q == NULL) {
+				VPTRINIT(iph2->sa);
+				return -1;
+			}
+
+			iph2->sa = vrealloc(iph2->sa, iph2->sa->l + q->l);
+			if (iph2->sa == NULL) {
+				plog(LLV_ERROR, LOCATION, NULL,
+					"failed to allocate my sa buffer\n");
+				if (q)
+					vfree(q);
+				return -1;
+			}
+			memcpy(iph2->sa->v + iph2->sa->l - q->l, q->v, q->l);
+			if (propoff != 0) {
+				prop = (struct isakmp_pl_p *)(iph2->sa->v +
+					propoff);
+				prop->h.np = ISAKMP_NPTYPE_P;
+			}
+			propoff = iph2->sa->l - q->l;
+
+			vfree(q);
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * return 1 if all of the given protocols are transport mode.
+ */
+int
+ipsecdoi_transportmode(pp)
+	struct saprop *pp;
+{
+	struct saproto *pr = NULL;
+
+	for (; pp; pp = pp->next) {
+		for (pr = pp->head; pr; pr = pr->next) {
+			if (pr->encmode != IPSECDOI_ATTR_ENC_MODE_TRNS)
+				return 0;
+		}
+	}
+
+	return 1;
+}
+
+int
+ipsecdoi_get_defaultlifetime()
+{
+	return IPSECDOI_ATTR_SA_LD_SEC_DEFAULT;
+}
+
+int
+ipsecdoi_checkalgtypes(proto_id, enc, auth, comp)
+	int proto_id, enc, auth, comp;
+{
+#define TMPALGTYPE2STR(n) s_algtype(algclass_ipsec_##n, n)
+	switch (proto_id) {
+	case IPSECDOI_PROTO_IPSEC_ESP:
+		if (enc == 0 || comp != 0) {
+			plog(LLV_ERROR, LOCATION, NULL,
+				"illegal algorithm defined "
+				"ESP enc=%s auth=%s comp=%s.\n",
+				TMPALGTYPE2STR(enc),
+				TMPALGTYPE2STR(auth),
+				TMPALGTYPE2STR(comp));
+			return -1;
+		}
+		break;
+	case IPSECDOI_PROTO_IPSEC_AH:
+		if (enc != 0 || auth == 0 || comp != 0) {
+			plog(LLV_ERROR, LOCATION, NULL,
+				"illegal algorithm defined "
+				"AH enc=%s auth=%s comp=%s.\n",
+				TMPALGTYPE2STR(enc),
+				TMPALGTYPE2STR(auth),
+				TMPALGTYPE2STR(comp));
+			return -1;
+		}
+		break;
+	case IPSECDOI_PROTO_IPCOMP:
+		if (enc != 0 || auth != 0 || comp == 0) {
+			plog(LLV_ERROR, LOCATION, NULL,
+				"illegal algorithm defined "
+				"IPcomp enc=%s auth=%s comp=%s.\n",
+				TMPALGTYPE2STR(enc),
+				TMPALGTYPE2STR(auth),
+				TMPALGTYPE2STR(comp));
+			return -1;
+		}
+		break;
+	default:
+		plog(LLV_ERROR, LOCATION, NULL,
+			"invalid ipsec protocol %d\n", proto_id);
+		return -1;
+	}
+#undef TMPALGTYPE2STR
+	return 0;
+}
+
+int
+ipproto2doi(proto)
+	int proto;
+{
+	switch (proto) {
+	case IPPROTO_AH:
+		return IPSECDOI_PROTO_IPSEC_AH;
+	case IPPROTO_ESP:
+		return IPSECDOI_PROTO_IPSEC_ESP;
+	case IPPROTO_IPCOMP:
+		return IPSECDOI_PROTO_IPCOMP;
+	}
+	return -1;	/* XXX */
+}
+
+int
+doi2ipproto(proto)
+	int proto;
+{
+	switch (proto) {
+	case IPSECDOI_PROTO_IPSEC_AH:
+		return IPPROTO_AH;
+	case IPSECDOI_PROTO_IPSEC_ESP:
+		return IPPROTO_ESP;
+	case IPSECDOI_PROTO_IPCOMP:
+		return IPPROTO_IPCOMP;
+	}
+	return -1;	/* XXX */
+}
+
+/*
+ * Check if a subnet id is valid for comparison
+ * with an address id ( address length mask )
+ * and compare them
+ * Return value
+ * =  0 for match
+ * =  1 for mismatch
+ */
+
+int
+ipsecdoi_subnetisaddr_v4( subnet, address )
+	const vchar_t *subnet;
+	const vchar_t *address;
+{
+	struct in_addr *mask;
+
+	if (address->l != sizeof(struct in_addr))
+		return 1;
+
+	if (subnet->l != (sizeof(struct in_addr)*2))
+		return 1;
+
+	mask = (struct in_addr*)(subnet->v + sizeof(struct in_addr));
+
+	if (mask->s_addr!=0xffffffff)
+		return 1;
+
+	return memcmp(subnet->v,address->v,address->l);
+}
+
+#ifdef INET6
+
+int
+ipsecdoi_subnetisaddr_v6( subnet, address )
+	const vchar_t *subnet;
+	const vchar_t *address;
+{
+	struct in6_addr *mask;
+	int i;
+
+	if (address->l != sizeof(struct in6_addr))
+		return 1;
+
+	if (subnet->l != (sizeof(struct in6_addr)*2))
+		return 1;
+
+	mask = (struct in6_addr*)(subnet->v + sizeof(struct in6_addr));
+
+	for (i=0; i<16; i++)
+		if(mask->s6_addr[i]!=0xff)
+			return 1;
+
+	return memcmp(subnet->v,address->v,address->l);
+}
+
+#endif
+
+/*
+ * Check and Compare two IDs
+ * - specify 0 for exact if wildcards are allowed
+ * Return value
+ * =  0 for match
+ * =  1 for misatch
+ * = -1 for integrity error
+ */
+
+int
+ipsecdoi_chkcmpids( idt, ids, exact )
+	const vchar_t *idt; /* id cmp target */
+	const vchar_t *ids; /* id cmp source */
+	int exact;
+{
+	struct ipsecdoi_id_b *id_bt;
+	struct ipsecdoi_id_b *id_bs;
+	vchar_t ident_t;
+	vchar_t ident_s;
+	int result;
+
+	/* handle wildcard IDs */
+
+	if (idt == NULL || ids == NULL)
+	{
+		if( !exact )
+		{
+			plog(LLV_DEBUG, LOCATION, NULL,
+				"check and compare ids : values matched (ANONYMOUS)\n" );
+			return 0;
+		}
+		else
+		{
+			plog(LLV_DEBUG, LOCATION, NULL,
+				"check and compare ids : value mismatch (ANONYMOUS)\n" );
+			return -1;
+		}
+	}
+
+	/* make sure the ids are of the same type */
+
+	id_bt = (struct ipsecdoi_id_b *) idt->v;
+	id_bs = (struct ipsecdoi_id_b *) ids->v;
+
+	ident_t.v = idt->v + sizeof(*id_bt);
+	ident_t.l = idt->l - sizeof(*id_bt);
+	ident_s.v = ids->v + sizeof(*id_bs);
+	ident_s.l = ids->l - sizeof(*id_bs);
+
+	if (id_bs->type != id_bt->type)
+	{
+		/*
+		 * special exception for comparing
+                 * address to subnet id types when
+                 * the netmask is address length
+                 */
+
+		if ((id_bs->type == IPSECDOI_ID_IPV4_ADDR)&&
+		    (id_bt->type == IPSECDOI_ID_IPV4_ADDR_SUBNET)) {
+			result = ipsecdoi_subnetisaddr_v4(&ident_t,&ident_s);
+			goto cmpid_result;
+		}
+
+		if ((id_bs->type == IPSECDOI_ID_IPV4_ADDR_SUBNET)&&
+		    (id_bt->type == IPSECDOI_ID_IPV4_ADDR)) {
+			result = ipsecdoi_subnetisaddr_v4(&ident_s,&ident_t);
+			goto cmpid_result;
+		}
+
+#ifdef INET6
+		if ((id_bs->type == IPSECDOI_ID_IPV6_ADDR)&&
+		    (id_bt->type == IPSECDOI_ID_IPV6_ADDR_SUBNET)) {
+			result = ipsecdoi_subnetisaddr_v6(&ident_t,&ident_s);
+			goto cmpid_result;
+		}
+
+		if ((id_bs->type == IPSECDOI_ID_IPV6_ADDR_SUBNET)&&
+		    (id_bt->type == IPSECDOI_ID_IPV6_ADDR)) {
+			result = ipsecdoi_subnetisaddr_v6(&ident_s,&ident_t);
+			goto cmpid_result;
+		}
+#endif
+		plog(LLV_DEBUG, LOCATION, NULL,
+			"check and compare ids : id type mismatch %s != %s\n",
+			s_ipsecdoi_ident(id_bs->type),
+			s_ipsecdoi_ident(id_bt->type));
+
+		return 1;
+	}
+
+	if(id_bs->proto_id != id_bt->proto_id){
+		plog(LLV_DEBUG, LOCATION, NULL,
+			"check and compare ids : proto_id mismatch %d != %d\n",
+			id_bs->proto_id, id_bt->proto_id);
+
+		return 1;
+	}
+
+	/* compare the ID data. */
+
+	switch (id_bt->type) {
+	        case IPSECDOI_ID_DER_ASN1_DN:
+        	case IPSECDOI_ID_DER_ASN1_GN:
+			/* compare asn1 ids */
+			result = eay_cmp_asn1dn(&ident_t, &ident_s);
+			goto cmpid_result;
+
+		case IPSECDOI_ID_IPV4_ADDR:
+			/* validate lengths */
+			if ((ident_t.l != sizeof(struct in_addr))||
+			    (ident_s.l != sizeof(struct in_addr)))
+				goto cmpid_invalid;
+			break;
+
+		case IPSECDOI_ID_IPV4_ADDR_SUBNET:
+		case IPSECDOI_ID_IPV4_ADDR_RANGE:
+			/* validate lengths */
+			if ((ident_t.l != (sizeof(struct in_addr)*2))||
+			    (ident_s.l != (sizeof(struct in_addr)*2)))
+				goto cmpid_invalid;
+			break;
+
+#ifdef INET6
+		case IPSECDOI_ID_IPV6_ADDR:
+			/* validate lengths */
+			if ((ident_t.l != sizeof(struct in6_addr))||
+			    (ident_s.l != sizeof(struct in6_addr)))
+				goto cmpid_invalid;
+			break;
+
+		case IPSECDOI_ID_IPV6_ADDR_SUBNET:
+		case IPSECDOI_ID_IPV6_ADDR_RANGE:
+			/* validate lengths */
+			if ((ident_t.l != (sizeof(struct in6_addr)*2))||
+			    (ident_s.l != (sizeof(struct in6_addr)*2)))
+				goto cmpid_invalid;
+			break;
+#endif
+		case IPSECDOI_ID_FQDN:
+		case IPSECDOI_ID_USER_FQDN:
+		case IPSECDOI_ID_KEY_ID:
+			break;
+
+		default:
+			plog(LLV_ERROR, LOCATION, NULL,
+				"Unhandled id type %i specified for comparison\n",
+				id_bt->type);
+			return -1;
+	}
+
+	/* validate matching data and length */
+	if (ident_t.l == ident_s.l)
+		result = memcmp(ident_t.v,ident_s.v,ident_t.l);
+	else
+		result = 1;
+
+cmpid_result:
+
+	/* debug level output */
+	if(loglevel >= LLV_DEBUG) {
+		char *idstrt = ipsecdoi_id2str(idt);
+		char *idstrs = ipsecdoi_id2str(ids);
+
+		if (!result)
+	 		plog(LLV_DEBUG, LOCATION, NULL,
+				"check and compare ids : values matched (%s)\n",
+				 s_ipsecdoi_ident(id_bs->type) );
+		else
+ 			plog(LLV_DEBUG, LOCATION, NULL,
+				"check and compare ids : value mismatch (%s)\n",
+				 s_ipsecdoi_ident(id_bs->type));
+
+		plog(LLV_DEBUG, LOCATION, NULL, "cmpid target: \'%s\'\n", idstrt );
+		plog(LLV_DEBUG, LOCATION, NULL, "cmpid source: \'%s\'\n", idstrs );
+
+		racoon_free(idstrs);
+		racoon_free(idstrt);
+	}
+
+	/* return result */
+	if( !result )
+		return 0;
+	else
+		return 1;
+
+cmpid_invalid:
+
+	/* id integrity error */
+	plog(LLV_DEBUG, LOCATION, NULL, "check and compare ids : %s integrity error\n",
+		s_ipsecdoi_ident(id_bs->type));
+	plog(LLV_DEBUG, LOCATION, NULL, "cmpid target: length = \'%zu\'\n", ident_t.l );
+	plog(LLV_DEBUG, LOCATION, NULL, "cmpid source: length = \'%zu\'\n", ident_s.l );
+
+	return -1;
+}
+
+/*
+ * check the following:
+ * - In main mode with pre-shared key, only address type can be used.
+ * - if proper type for phase 1 ?
+ * - if phase 1 ID payload conformed RFC2407 4.6.2.
+ *   (proto, port) must be (0, 0), (udp, 500) or (udp, [specified]).
+ * - if ID payload sent from peer is equal to the ID expected by me.
+ *
+ * both of "id" and "id_p" should be ID payload without general header,
+ */
+int
+ipsecdoi_checkid1(iph1)
+	struct ph1handle *iph1;
+{
+	struct ipsecdoi_id_b *id_b;
+	struct sockaddr *sa;
+	caddr_t sa1, sa2;
+
+	if (iph1->id_p == NULL) {
+		plog(LLV_ERROR, LOCATION, NULL,
+			"invalid iph1 passed id_p == NULL\n");
+		return ISAKMP_INTERNAL_ERROR;
+	}
+	if (iph1->id_p->l < sizeof(*id_b)) {
+		plog(LLV_ERROR, LOCATION, NULL,
+			"invalid value passed as \"ident\" (len=%lu)\n",
+			(u_long)iph1->id_p->l);
+		return ISAKMP_NTYPE_INVALID_ID_INFORMATION;
+	}
+
+	id_b = (struct ipsecdoi_id_b *)iph1->id_p->v;
+
+	/* In main mode with pre-shared key, only address type can be used. */
+	if (iph1->etype == ISAKMP_ETYPE_IDENT &&
+	    iph1->approval->authmethod == OAKLEY_ATTR_AUTH_METHOD_PSKEY) {
+		 if (id_b->type != IPSECDOI_ID_IPV4_ADDR
+		  && id_b->type != IPSECDOI_ID_IPV6_ADDR) {
+			plog(LLV_ERROR, LOCATION, NULL,
+				"Expecting IP address type in main mode, "
+				"but %s.\n", s_ipsecdoi_ident(id_b->type));
+			return ISAKMP_NTYPE_INVALID_ID_INFORMATION;
+		}
+	}
+
+	/* if proper type for phase 1 ? */
+	switch (id_b->type) {
+	case IPSECDOI_ID_IPV4_ADDR_SUBNET:
+	case IPSECDOI_ID_IPV6_ADDR_SUBNET:
+	case IPSECDOI_ID_IPV4_ADDR_RANGE:
+	case IPSECDOI_ID_IPV6_ADDR_RANGE:
+		plog(LLV_WARNING, LOCATION, NULL,
+			"such ID type %s is not proper.\n",
+			s_ipsecdoi_ident(id_b->type));
+		/*FALLTHROUGH*/
+	}
+
+	/* if phase 1 ID payload conformed RFC2407 4.6.2. */
+	if (id_b->type == IPSECDOI_ID_IPV4_ADDR ||
+	    id_b->type == IPSECDOI_ID_IPV6_ADDR) {
+
+		if (id_b->proto_id == 0 && ntohs(id_b->port) != 0) {
+			plog(LLV_WARNING, LOCATION, NULL,
+				"protocol ID and Port mismatched. "
+				"proto_id:%d port:%d\n",
+				id_b->proto_id, ntohs(id_b->port));
+			/*FALLTHROUGH*/
+
+		} else if (id_b->proto_id == IPPROTO_UDP) {
+			/*
+			 * copmaring with expecting port.
+			 * always permit if port is equal to PORT_ISAKMP
+			 */
+			if (ntohs(id_b->port) != PORT_ISAKMP) {
+				u_int16_t port;
+
+				port = extract_port(iph1->remote);
+				if (ntohs(id_b->port) != port) {
+					plog(LLV_WARNING, LOCATION, NULL,
+						"port %d expected, but %d\n",
+						port, ntohs(id_b->port));
+					/*FALLTHROUGH*/
+				}
+			}
+		}
+	}
+
+	/* compare with the ID if specified. */
+	if (genlist_next(iph1->rmconf->idvl_p, 0)) {
+		vchar_t *ident0 = NULL;
+		vchar_t ident;
+		struct idspec *id;
+		struct genlist_entry *gpb;
+
+		for (id = genlist_next (iph1->rmconf->idvl_p, &gpb); id; id = genlist_next (0, &gpb)) {
+			/* check the type of both IDs */
+			if (id->idtype != doi2idtype(id_b->type))
+				continue;  /* ID type mismatch */
+			if (id->id == 0)
+				goto matched;
+
+			/* compare defined ID with the ID sent by peer. */
+			if (ident0 != NULL)
+				vfree(ident0);
+			ident0 = getidval(id->idtype, id->id);
+
+			switch (id->idtype) {
+			case IDTYPE_ASN1DN:
+				ident.v = iph1->id_p->v + sizeof(*id_b);
+				ident.l = iph1->id_p->l - sizeof(*id_b);
+				if (eay_cmp_asn1dn(ident0, &ident) == 0)
+					goto matched;
+				break;
+			case IDTYPE_ADDRESS:
+				sa = (struct sockaddr *)ident0->v;
+				sa2 = (caddr_t)(id_b + 1);
+				switch (sa->sa_family) {
+				case AF_INET:
+					if (iph1->id_p->l - sizeof(*id_b) != sizeof(struct in_addr))
+						continue;  /* ID value mismatch */
+					sa1 = (caddr_t)&((struct sockaddr_in *)sa)->sin_addr;
+					if (memcmp(sa1, sa2, sizeof(struct in_addr)) == 0)
+						goto matched;
+					break;
+#ifdef INET6
+				case AF_INET6:
+					if (iph1->id_p->l - sizeof(*id_b) != sizeof(struct in6_addr))
+						continue;  /* ID value mismatch */
+					sa1 = (caddr_t)&((struct sockaddr_in6 *)sa)->sin6_addr;
+					if (memcmp(sa1, sa2, sizeof(struct in6_addr)) == 0)
+						goto matched;
+					break;
+#endif
+				default:
+					break;
+				}
+				break;
+			default:
+				if (memcmp(ident0->v, id_b + 1, ident0->l) == 0)
+					goto matched;
+				break;
+			}
+		}
+		if (ident0 != NULL) {
+			vfree(ident0);
+			ident0 = NULL;
+		}
+		plog(LLV_WARNING, LOCATION, NULL, "No ID match.\n");
+		if (iph1->rmconf->verify_identifier)
+			return ISAKMP_NTYPE_INVALID_ID_INFORMATION;
+matched: /* ID value match */
+		if (ident0 != NULL)
+			vfree(ident0);
+	}
+
+	return 0;
+}
+
+/*
+ * create ID payload for phase 1 and set into iph1->id.
+ * NOT INCLUDING isakmp general header.
+ * see, RFC2407 4.6.2.1
+ */
+int
+ipsecdoi_setid1(iph1)
+	struct ph1handle *iph1;
+{
+	vchar_t *ret = NULL;
+	struct ipsecdoi_id_b id_b;
+	vchar_t *ident = NULL;
+	struct sockaddr *ipid = NULL;
+
+	/* init */
+	id_b.proto_id = 0;
+	id_b.port = 0;
+	ident = NULL;
+
+	switch (iph1->rmconf->idvtype) {
+	case IDTYPE_FQDN:
+		id_b.type = IPSECDOI_ID_FQDN;
+		ident = getidval(iph1->rmconf->idvtype, iph1->rmconf->idv);
+		break;
+	case IDTYPE_USERFQDN:
+		id_b.type = IPSECDOI_ID_USER_FQDN;
+		ident = getidval(iph1->rmconf->idvtype, iph1->rmconf->idv);
+		break;
+	case IDTYPE_KEYID:
+		id_b.type = IPSECDOI_ID_KEY_ID;
+		ident = getidval(iph1->rmconf->idvtype, iph1->rmconf->idv);
+		break;
+	case IDTYPE_ASN1DN:
+		id_b.type = IPSECDOI_ID_DER_ASN1_DN;
+		if (iph1->rmconf->idv) {
+			/* XXX it must be encoded to asn1dn. */
+			ident = vdup(iph1->rmconf->idv);
+		} else {
+			if (oakley_getmycert(iph1) < 0) {
+				plog(LLV_ERROR, LOCATION, NULL,
+					"failed to get own CERT.\n");
+				goto err;
+			}
+			ident = eay_get_x509asn1subjectname(iph1->cert);
+		}
+		break;
+	case IDTYPE_ADDRESS:
+		/*
+		 * if the value of the id type was set by the configuration
+		 * file, then use it.  otherwise the value is get from local
+		 * ip address by using ike negotiation.
+		 */
+		if (iph1->rmconf->idv)
+			ipid = (struct sockaddr *)iph1->rmconf->idv->v;
+		/*FALLTHROUGH*/
+	default:
+	    {
+		int l;
+		caddr_t p;
+
+		if (ipid == NULL)
+			ipid = iph1->local;
+
+		/* use IP address */
+		switch (ipid->sa_family) {
+		case AF_INET:
+			id_b.type = IPSECDOI_ID_IPV4_ADDR;
+			l = sizeof(struct in_addr);
+			p = (caddr_t)&((struct sockaddr_in *)ipid)->sin_addr;
+			break;
+#ifdef INET6
+		case AF_INET6:
+			id_b.type = IPSECDOI_ID_IPV6_ADDR;
+			l = sizeof(struct in6_addr);
+			p = (caddr_t)&((struct sockaddr_in6 *)ipid)->sin6_addr;
+			break;
+#endif
+		default:
+			plog(LLV_ERROR, LOCATION, NULL,
+				"invalid address family.\n");
+			goto err;
+		}
+		id_b.proto_id = IPPROTO_UDP;
+		id_b.port = htons(PORT_ISAKMP);
+		ident = vmalloc(l);
+		if (!ident) {
+			plog(LLV_ERROR, LOCATION, NULL,
+				"failed to get ID buffer.\n");
+			return 0;
+		}
+		memcpy(ident->v, p, ident->l);
+	    }
+	}
+	if (!ident) {
+		plog(LLV_ERROR, LOCATION, NULL,
+			"failed to get ID buffer.\n");
+		return 0;
+	}
+
+	ret = vmalloc(sizeof(id_b) + ident->l);
+	if (ret == NULL) {
+		plog(LLV_ERROR, LOCATION, NULL,
+			"failed to get ID buffer.\n");
+		goto err;
+	}
+
+	memcpy(ret->v, &id_b, sizeof(id_b));
+	memcpy(ret->v + sizeof(id_b), ident->v, ident->l);
+
+	iph1->id = ret;
+
+	plog(LLV_DEBUG, LOCATION, NULL,
+		"use ID type of %s\n", s_ipsecdoi_ident(id_b.type));
+	if (ident)
+		vfree(ident);
+	return 0;
+
+err:
+	if (ident)
+		vfree(ident);
+	plog(LLV_ERROR, LOCATION, NULL, "failed get my ID\n");
+	return -1;
+}
+
+static vchar_t *
+getidval(type, val)
+	int type;
+	vchar_t *val;
+{
+	vchar_t *new = NULL;
+
+	if (val)
+		new = vdup(val);
+	return new;
+}
+
+/* it's only called by cfparse.y. */
+int
+set_identifier(vpp, type, value)
+	vchar_t **vpp, *value;
+	int type;
+{
+	return set_identifier_qual(vpp, type, value, IDQUAL_UNSPEC);
+}
+
+int
+set_identifier_qual(vpp, type, value, qual)
+	vchar_t **vpp, *value;
+	int type;
+	int qual;
+{
+	vchar_t *new = NULL;
+
+	/* simply return if value is null. */
+	if (!value){
+		if( type == IDTYPE_FQDN || type == IDTYPE_USERFQDN){
+			plog(LLV_ERROR, LOCATION, NULL,
+				 "No %s\n", type == IDTYPE_FQDN ? "fqdn":"user fqdn");
+			return -1;
+		}
+		return 0;
+	}
+
+	switch (type) {
+	case IDTYPE_FQDN:
+	case IDTYPE_USERFQDN:
+		if(value->l <= 1){
+			plog(LLV_ERROR, LOCATION, NULL,
+				 "Empty %s\n", type == IDTYPE_FQDN ? "fqdn":"user fqdn");
+			return -1;
+		}
+		/* length is adjusted since QUOTEDSTRING teminates NULL. */
+		new = vmalloc(value->l - 1);
+		if (new == NULL)
+			return -1;
+		memcpy(new->v, value->v, new->l);
+		break;
+	case IDTYPE_KEYID:
+		/* 
+		 * If no qualifier is specified: IDQUAL_UNSPEC. It means
+		 * to use a file for backward compatibility sake. 
+		 */
+		switch(qual) {
+		case IDQUAL_FILE:
+		case IDQUAL_UNSPEC: {
+			FILE *fp;
+			char b[512];
+			int tlen, len;
+
+			fp = fopen(value->v, "r");
+			if (fp == NULL) {
+				plog(LLV_ERROR, LOCATION, NULL,
+					"can not open %s\n", value->v);
+				return -1;
+			}
+			tlen = 0;
+			while ((len = fread(b, 1, sizeof(b), fp)) != 0) {
+				new = vrealloc(new, tlen + len);
+				if (!new) {
+					fclose(fp);
+					return -1;
+				}
+				memcpy(new->v + tlen, b, len);
+				tlen += len;
+			}
+			fclose(fp);
+			break;
+		}
+
+		case IDQUAL_TAG:
+			new = vmalloc(value->l - 1);
+			if (new == NULL) {
+				plog(LLV_ERROR, LOCATION, NULL,
+					"can not allocate memory");
+				return -1;
+			}
+			memcpy(new->v, value->v, new->l);
+			break;
+
+		default:
+			plog(LLV_ERROR, LOCATION, NULL,
+				"unknown qualifier");
+			return -1;
+		}
+		break;
+	
+	case IDTYPE_ADDRESS: {
+		struct sockaddr *sa;
+
+		/* length is adjusted since QUOTEDSTRING teminates NULL. */
+		if (value->l == 0)
+			break;
+
+		sa = str2saddr(value->v, NULL);
+		if (sa == NULL) {
+			plog(LLV_ERROR, LOCATION, NULL,
+				"invalid ip address %s\n", value->v);
+			return -1;
+		}
+
+		new = vmalloc(sysdep_sa_len(sa));
+		if (new == NULL) {
+			racoon_free(sa);
+			return -1;
+		}
+		memcpy(new->v, sa, new->l);
+		racoon_free(sa);
+		break;
+	}
+	case IDTYPE_ASN1DN:
+		if (value->v[0] == '~')
+			/* Hex-encoded ASN1 strings */
+			new = eay_hex2asn1dn(value->v + 1, - 1);
+		else
+			/* DN encoded strings */
+			new = eay_str2asn1dn(value->v, value->l - 1);
+
+		if (new == NULL)
+			return -1;
+
+		if (loglevel >= LLV_DEBUG) {
+			X509_NAME *xn;
+			BIO *bio;
+			unsigned char *ptr = (unsigned char *) new->v, *buf;
+			size_t len;
+			char save;
+
+			xn = d2i_X509_NAME(NULL, (void *)&ptr, new->l);
+			bio = BIO_new(BIO_s_mem());
+			
+			X509_NAME_print_ex(bio, xn, 0, 0);
+			len = BIO_get_mem_data(bio, &ptr);
+			save = ptr[len];
+			ptr[len] = 0;
+			plog(LLV_DEBUG, LOCATION, NULL, "Parsed DN: %s\n", ptr);
+			ptr[len] = save;
+			X509_NAME_free(xn);
+			BIO_free(bio);
+		}
+
+		break;
+	}
+
+	*vpp = new;
+
+	return 0;
+}
+
+/*
+ * create ID payload for phase 2, and set into iph2->id and id_p.  There are
+ * NOT INCLUDING isakmp general header.
+ * this function is for initiator.  responder will get to copy from payload.
+ * responder ID type is always address type.
+ * see, RFC2407 4.6.2.1
+ */
+int
+ipsecdoi_setid2(iph2)
+	struct ph2handle *iph2;
+{
+	struct secpolicy *sp;
+
+	/* check there is phase 2 handler ? */
+	sp = getspbyspid(iph2->spid);
+	if (sp == NULL) {
+		plog(LLV_ERROR, LOCATION, NULL,
+			"no policy found for spid:%u.\n", iph2->spid);
+		return -1;
+	}
+
+	iph2->id = ipsecdoi_sockaddr2id((struct sockaddr *)&sp->spidx.src,
+					sp->spidx.prefs, sp->spidx.ul_proto);
+	if (iph2->id == NULL) {
+		plog(LLV_ERROR, LOCATION, NULL,
+			"failed to get ID for %s\n",
+			spidx2str(&sp->spidx));
+		return -1;
+	}
+	plog(LLV_DEBUG, LOCATION, NULL, "use local ID type %s\n",
+		s_ipsecdoi_ident(((struct ipsecdoi_id_b *)iph2->id->v)->type));
+
+	/* remote side */
+	iph2->id_p = ipsecdoi_sockaddr2id((struct sockaddr *)&sp->spidx.dst,
+				sp->spidx.prefd, sp->spidx.ul_proto);
+	if (iph2->id_p == NULL) {
+		plog(LLV_ERROR, LOCATION, NULL,
+			"failed to get ID for %s\n",
+			spidx2str(&sp->spidx));
+		VPTRINIT(iph2->id);
+		return -1;
+	}
+	plog(LLV_DEBUG, LOCATION, NULL,
+		"use remote ID type %s\n",
+		s_ipsecdoi_ident(((struct ipsecdoi_id_b *)iph2->id_p->v)->type));
+
+	return 0;
+}
+
+/*
+ * set address type of ID.
+ * NOT INCLUDING general header.
+ */
+vchar_t *
+ipsecdoi_sockaddr2id(saddr, prefixlen, ul_proto)
+	struct sockaddr *saddr;
+	u_int prefixlen;
+	u_int ul_proto;
+{
+	vchar_t *new;
+	int type, len1, len2;
+	caddr_t sa;
+	u_short port;
+
+	/*
+	 * Q. When type is SUBNET, is it allowed to be ::1/128.
+	 * A. Yes. (consensus at bake-off)
+	 */
+	switch (saddr->sa_family) {
+	case AF_INET:
+		len1 = sizeof(struct in_addr);
+		if (prefixlen == (sizeof(struct in_addr) << 3)) {
+			type = IPSECDOI_ID_IPV4_ADDR;
+			len2 = 0;
+		} else {
+			type = IPSECDOI_ID_IPV4_ADDR_SUBNET;
+			len2 = sizeof(struct in_addr);
+		}
+		sa = (caddr_t)&((struct sockaddr_in *)(saddr))->sin_addr;
+		port = ((struct sockaddr_in *)(saddr))->sin_port;
+		break;
+#ifdef INET6
+	case AF_INET6:
+		len1 = sizeof(struct in6_addr);
+		if (prefixlen == (sizeof(struct in6_addr) << 3)) {
+			type = IPSECDOI_ID_IPV6_ADDR;
+			len2 = 0;
+		} else {
+			type = IPSECDOI_ID_IPV6_ADDR_SUBNET;
+			len2 = sizeof(struct in6_addr);
+		}
+		sa = (caddr_t)&((struct sockaddr_in6 *)(saddr))->sin6_addr;
+		port = ((struct sockaddr_in6 *)(saddr))->sin6_port;
+		break;
+#endif
+	default:
+		plog(LLV_ERROR, LOCATION, NULL,
+			"invalid family: %d.\n", saddr->sa_family);
+		return NULL;
+	}
+
+	/* get ID buffer */
+	new = vmalloc(sizeof(struct ipsecdoi_id_b) + len1 + len2);
+	if (new == NULL) {
+		plog(LLV_ERROR, LOCATION, NULL,
+			"failed to get ID buffer.\n");
+		return NULL;
+	}
+
+	memset(new->v, 0, new->l);
+
+	/* set the part of header. */
+	((struct ipsecdoi_id_b *)new->v)->type = type;
+
+	/* set ul_proto and port */
+	/*
+	 * NOTE: we use both IPSEC_ULPROTO_ANY and IPSEC_PORT_ANY as wild card
+	 * because 0 means port number of 0.  Instead of 0, we use IPSEC_*_ANY.
+	 */
+	((struct ipsecdoi_id_b *)new->v)->proto_id =
+		ul_proto == IPSEC_ULPROTO_ANY ? 0 : ul_proto;
+	((struct ipsecdoi_id_b *)new->v)->port =
+		port == IPSEC_PORT_ANY ? 0 : port;
+	memcpy(new->v + sizeof(struct ipsecdoi_id_b), sa, len1);
+
+	/* set address */
+
+	/* set prefix */
+	if (len2) {
+		u_char *p = (unsigned char *) new->v + 
+			sizeof(struct ipsecdoi_id_b) + len1;
+		u_int bits = prefixlen;
+
+		while (bits >= 8) {
+			*p++ = 0xff;
+			bits -= 8;
+		}
+
+		if (bits > 0)
+			*p = ~((1 << (8 - bits)) - 1);
+	}
+
+	return new;
+}
+
+vchar_t *
+ipsecdoi_sockrange2id(laddr, haddr, ul_proto)
+	struct sockaddr *laddr, *haddr;
+	u_int ul_proto;
+{
+	vchar_t *new;
+	int type, len1, len2;
+	u_short port;
+
+	if (laddr->sa_family != haddr->sa_family) {
+	    plog(LLV_ERROR, LOCATION, NULL, "Address family mismatch\n");
+	    return NULL;
+	}
+
+	switch (laddr->sa_family) {
+	case AF_INET:
+	    type = IPSECDOI_ID_IPV4_ADDR_RANGE;
+	    len1 = sizeof(struct in_addr);
+	    len2 = sizeof(struct in_addr);
+	    break;
+#ifdef INET6
+	case AF_INET6:
+		type = IPSECDOI_ID_IPV6_ADDR_RANGE;
+		len1 = sizeof(struct in6_addr);
+		len2 = sizeof(struct in6_addr);
+		break;
+#endif
+	default:
+		plog(LLV_ERROR, LOCATION, NULL,
+			"invalid family: %d.\n", laddr->sa_family);
+		return NULL;
+	}
+
+	/* get ID buffer */
+	new = vmalloc(sizeof(struct ipsecdoi_id_b) + len1 + len2);
+	if (new == NULL) {
+		plog(LLV_ERROR, LOCATION, NULL,
+			"failed to get ID buffer.\n");
+		return NULL;
+	}
+
+	memset(new->v, 0, new->l);
+	/* set the part of header. */
+	((struct ipsecdoi_id_b *)new->v)->type = type;
+
+	/* set ul_proto and port */
+	/*
+	 * NOTE: we use both IPSEC_ULPROTO_ANY and IPSEC_PORT_ANY as wild card
+	 * because 0 means port number of 0.  Instead of 0, we use IPSEC_*_ANY.
+	 */
+	((struct ipsecdoi_id_b *)new->v)->proto_id =
+		ul_proto == IPSEC_ULPROTO_ANY ? 0 : ul_proto;
+	port = ((struct sockaddr_in *)(laddr))->sin_port;
+	((struct ipsecdoi_id_b *)new->v)->port =
+		port == IPSEC_PORT_ANY ? 0 : port;
+	memcpy(new->v + sizeof(struct ipsecdoi_id_b), 
+	       (caddr_t)&((struct sockaddr_in *)(laddr))->sin_addr, 
+	       len1);
+	memcpy(new->v + sizeof(struct ipsecdoi_id_b) + len1, 
+	       (caddr_t)&((struct sockaddr_in *)haddr)->sin_addr,
+	       len2);
+	return new;
+}
+
+
+/*
+ * create sockaddr structure from ID payload (buf).
+ * buffers (saddr, prefixlen, ul_proto) must be allocated.
+ * see, RFC2407 4.6.2.1
+ */
+int
+ipsecdoi_id2sockaddr(buf, saddr, prefixlen, ul_proto)
+	vchar_t *buf;
+	struct sockaddr *saddr;
+	u_int8_t *prefixlen;
+	u_int16_t *ul_proto;
+{
+	struct ipsecdoi_id_b *id_b = (struct ipsecdoi_id_b *)buf->v;
+	u_int plen = 0;
+
+	/*
+	 * When a ID payload of subnet type with a IP address of full bit
+	 * masked, it has to be processed as host address.
+	 * e.g. below 2 type are same.
+	 *      type = ipv6 subnet, data = 2001::1/128
+	 *      type = ipv6 address, data = 2001::1
+	 */
+	switch (id_b->type) {
+	case IPSECDOI_ID_IPV4_ADDR:
+	case IPSECDOI_ID_IPV4_ADDR_SUBNET:
+#ifndef __linux__
+		saddr->sa_len = sizeof(struct sockaddr_in);
+#endif
+		saddr->sa_family = AF_INET;
+		((struct sockaddr_in *)saddr)->sin_port =
+			(id_b->port == 0
+				? IPSEC_PORT_ANY
+				: id_b->port);		/* see sockaddr2id() */
+		memcpy(&((struct sockaddr_in *)saddr)->sin_addr,
+			buf->v + sizeof(*id_b), sizeof(struct in_addr));
+		break;
+#ifdef INET6
+	case IPSECDOI_ID_IPV6_ADDR:
+	case IPSECDOI_ID_IPV6_ADDR_SUBNET:
+#ifndef __linux__
+		saddr->sa_len = sizeof(struct sockaddr_in6);
+#endif
+		saddr->sa_family = AF_INET6;
+		((struct sockaddr_in6 *)saddr)->sin6_port =
+			(id_b->port == 0
+				? IPSEC_PORT_ANY
+				: id_b->port);		/* see sockaddr2id() */
+		memcpy(&((struct sockaddr_in6 *)saddr)->sin6_addr,
+			buf->v + sizeof(*id_b), sizeof(struct in6_addr));
+		break;
+#endif
+	default:
+		do_plog(LLV_INFO, "XXXXXXXXXXXXXXXXXXXXXX error\n");
+		plog(LLV_ERROR, LOCATION, NULL,
+			"unsupported ID type %d\n", id_b->type);
+		return ISAKMP_NTYPE_INVALID_ID_INFORMATION;
+	}
+
+	/* get prefix length */
+	switch (id_b->type) {
+	case IPSECDOI_ID_IPV4_ADDR:
+		plen = sizeof(struct in_addr) << 3;
+		break;
+#ifdef INET6
+	case IPSECDOI_ID_IPV6_ADDR:
+		plen = sizeof(struct in6_addr) << 3;
+		break;
+#endif
+	case IPSECDOI_ID_IPV4_ADDR_SUBNET:
+#ifdef INET6
+	case IPSECDOI_ID_IPV6_ADDR_SUBNET:
+#endif
+	    {
+		u_char *p;
+		u_int max;
+		int alen = sizeof(struct in_addr);
+
+		switch (id_b->type) {
+		case IPSECDOI_ID_IPV4_ADDR_SUBNET:
+			alen = sizeof(struct in_addr);
+			break;
+#ifdef INET6
+		case IPSECDOI_ID_IPV6_ADDR_SUBNET:
+			alen = sizeof(struct in6_addr);
+			break;
+#endif
+		}
+
+		/* sanity check */
+		if (buf->l < alen)
+			return ISAKMP_INTERNAL_ERROR;
+
+		/* get subnet mask length */
+		plen = 0;
+		max = alen <<3;
+
+		p = (unsigned char *) buf->v
+			+ sizeof(struct ipsecdoi_id_b)
+			+ alen;
+
+		for (; *p == 0xff; p++) {
+			plen += 8;
+			if (plen >= max)
+				break;
+		}
+
+		if (plen < max) {
+			u_int l = 0;
+			u_char b = ~(*p);
+
+			while (b) {
+				b >>= 1;
+				l++;
+			}
+
+			l = 8 - l;
+			plen += l;
+		}
+	    }
+		break;
+	}
+
+	*prefixlen = plen;
+	*ul_proto = id_b->proto_id == 0
+				? IPSEC_ULPROTO_ANY
+				: id_b->proto_id;	/* see sockaddr2id() */
+
+	return 0;
+}
+
+/*
+ * make printable string from ID payload except of general header.
+ */
+char *
+ipsecdoi_id2str(id)
+	const vchar_t *id;
+{
+#define BUFLEN 512
+	char * ret = NULL;
+	int len = 0;
+	char *dat;
+	static char buf[BUFLEN];
+	struct ipsecdoi_id_b *id_b = (struct ipsecdoi_id_b *)id->v;
+	struct sockaddr_storage saddr_storage;
+	struct sockaddr        *saddr;
+	struct sockaddr_in     *saddr_in;
+	struct sockaddr_in6    *saddr_in6;
+	u_int plen = 0;
+
+	saddr     = (struct sockaddr *)&saddr_storage;
+	saddr_in  = (struct sockaddr_in *)&saddr_storage;
+	saddr_in6 = (struct sockaddr_in6 *)&saddr_storage;
+
+	
+	switch (id_b->type) {
+	case IPSECDOI_ID_IPV4_ADDR:
+	case IPSECDOI_ID_IPV4_ADDR_SUBNET:
+	case IPSECDOI_ID_IPV4_ADDR_RANGE:
+
+#ifndef __linux__
+		saddr->sa_len = sizeof(struct sockaddr_in);
+#endif
+		saddr->sa_family = AF_INET;
+
+		saddr_in->sin_port = IPSEC_PORT_ANY;
+		memcpy(&saddr_in->sin_addr,
+			id->v + sizeof(*id_b), sizeof(struct in_addr));
+		break;
+#ifdef INET6
+	case IPSECDOI_ID_IPV6_ADDR:
+	case IPSECDOI_ID_IPV6_ADDR_SUBNET:
+	case IPSECDOI_ID_IPV6_ADDR_RANGE:
+
+#ifndef __linux__
+		saddr->sa_len = sizeof(struct sockaddr_in6);
+#endif
+		saddr->sa_family = AF_INET6;
+
+		saddr_in6->sin6_port = IPSEC_PORT_ANY;
+		memcpy(&saddr_in6->sin6_addr,
+			id->v + sizeof(*id_b), sizeof(struct in6_addr));
+		saddr_in6->sin6_scope_id =
+			(IN6_IS_ADDR_LINKLOCAL(&saddr_in6->sin6_addr)
+				? ((struct sockaddr_in6 *)id_b)->sin6_scope_id
+				: 0);
+		break;
+#endif
+	}
+
+	switch (id_b->type) {
+	case IPSECDOI_ID_IPV4_ADDR:
+#ifdef INET6
+	case IPSECDOI_ID_IPV6_ADDR:
+#endif
+		len = snprintf( buf, BUFLEN, "%s", saddrwop2str(saddr));
+		break;
+
+	case IPSECDOI_ID_IPV4_ADDR_SUBNET:
+#ifdef INET6
+	case IPSECDOI_ID_IPV6_ADDR_SUBNET:
+#endif
+	    {
+		u_char *p;
+		u_int max;
+		int alen = sizeof(struct in_addr);
+
+		switch (id_b->type) {
+		case IPSECDOI_ID_IPV4_ADDR_SUBNET:
+			alen = sizeof(struct in_addr);
+			break;
+#ifdef INET6
+		case IPSECDOI_ID_IPV6_ADDR_SUBNET:
+			alen = sizeof(struct in6_addr);
+			break;
+#endif
+		}
+
+		/* sanity check */
+		if (id->l < alen) {
+			len = 0;
+			break;
+		}
+
+		/* get subnet mask length */
+		plen = 0;
+		max = alen <<3;
+
+		p = (unsigned char *) id->v
+			+ sizeof(struct ipsecdoi_id_b)
+			+ alen;
+
+		for (; *p == 0xff; p++) {
+			plen += 8;
+			if (plen >= max)
+				break;
+		}
+
+		if (plen < max) {
+			u_int l = 0;
+			u_char b = ~(*p);
+
+			while (b) {
+				b >>= 1;
+				l++;
+			}
+
+			l = 8 - l;
+			plen += l;
+		}
+
+		len = snprintf( buf, BUFLEN, "%s/%i", saddrwop2str(saddr), plen);
+	    }
+		break;
+
+	case IPSECDOI_ID_IPV4_ADDR_RANGE:
+
+		len = snprintf( buf, BUFLEN, "%s-", saddrwop2str(saddr));
+
+#ifndef __linux__
+		saddr->sa_len = sizeof(struct sockaddr_in);
+#endif
+		saddr->sa_family = AF_INET;
+		saddr_in->sin_port = IPSEC_PORT_ANY;
+		memcpy(&saddr_in->sin_addr,
+			id->v + sizeof(*id_b) + sizeof(struct in_addr),
+			sizeof(struct in_addr));
+
+		len += snprintf( buf + len, BUFLEN - len, "%s", saddrwop2str(saddr));
+
+		break;
+
+#ifdef INET6
+	case IPSECDOI_ID_IPV6_ADDR_RANGE:
+
+		len = snprintf( buf, BUFLEN, "%s-", saddrwop2str(saddr));
+
+#ifndef __linux__
+		saddr->sa_len = sizeof(struct sockaddr_in6);
+#endif
+		saddr->sa_family = AF_INET6;
+		saddr_in6->sin6_port = IPSEC_PORT_ANY;
+		memcpy(&saddr_in6->sin6_addr,
+			id->v + sizeof(*id_b) + sizeof(struct in6_addr),
+			sizeof(struct in6_addr));
+		saddr_in6->sin6_scope_id =
+			(IN6_IS_ADDR_LINKLOCAL(&saddr_in6->sin6_addr)
+				? ((struct sockaddr_in6 *)id_b)->sin6_scope_id
+				: 0);
+
+		len += snprintf( buf + len, BUFLEN - len, "%s", saddrwop2str(saddr));
+
+		break;
+#endif
+
+	case IPSECDOI_ID_FQDN:
+	case IPSECDOI_ID_USER_FQDN:
+		len = id->l - sizeof(*id_b);
+		if (len > BUFLEN)
+			len = BUFLEN;
+		memcpy(buf, id->v + sizeof(*id_b), len);
+		break;
+
+	case IPSECDOI_ID_DER_ASN1_DN:
+	case IPSECDOI_ID_DER_ASN1_GN:
+	{
+		X509_NAME *xn = NULL;
+
+		dat = id->v + sizeof(*id_b);
+		len = id->l - sizeof(*id_b);
+
+		if (d2i_X509_NAME(&xn, (void*) &dat, len) != NULL) {
+			BIO *bio = BIO_new(BIO_s_mem());
+			X509_NAME_print_ex(bio, xn, 0, 0);
+			len = BIO_get_mem_data(bio, &dat);
+			if (len > BUFLEN)
+				len = BUFLEN;
+			memcpy(buf,dat,len);
+			BIO_free(bio);
+			X509_NAME_free(xn);
+		} else {
+			plog(LLV_ERROR, LOCATION, NULL,
+				"unable to extract asn1dn from id\n");
+
+			len = sprintf(buf, "<ASN1-DN>");
+		}
+
+		break;
+	}
+
+	/* currently unhandled id types */
+	case IPSECDOI_ID_KEY_ID:
+		len = sprintf( buf, "<KEY-ID>");
+		break;
+
+	default:
+		plog(LLV_ERROR, LOCATION, NULL,
+			"unknown ID type %d\n", id_b->type);
+	}
+
+	if (!len)
+		len = sprintf( buf, "<?>");
+
+	ret = racoon_malloc(len+1);
+	if (ret != NULL) {
+		memcpy(ret,buf,len);
+		ret[len]=0;
+	}
+
+	return ret;
+}
+
+/*
+ * set IPsec data attributes into a proposal.
+ * NOTE: MUST called per a transform.
+ */
+int
+ipsecdoi_t2satrns(t, pp, pr, tr)
+	struct isakmp_pl_t *t;
+	struct saprop *pp;
+	struct saproto *pr;
+	struct satrns *tr;
+{
+	struct isakmp_data *d, *prev;
+	int flag, type;
+	int error = -1;
+	int life_t;
+	int tlen;
+
+	tr->trns_no = t->t_no;
+	tr->trns_id = t->t_id;
+
+	tlen = ntohs(t->h.len) - sizeof(*t);
+	prev = (struct isakmp_data *)NULL;
+	d = (struct isakmp_data *)(t + 1);
+
+	/* default */
+	life_t = IPSECDOI_ATTR_SA_LD_TYPE_DEFAULT;
+	pp->lifetime = IPSECDOI_ATTR_SA_LD_SEC_DEFAULT;
+	pp->lifebyte = 0;
+	tr->authtype = IPSECDOI_ATTR_AUTH_NONE;
+
+	while (tlen > 0) {
+
+		type = ntohs(d->type) & ~ISAKMP_GEN_MASK;
+		flag = ntohs(d->type) & ISAKMP_GEN_MASK;
+
+		plog(LLV_DEBUG, LOCATION, NULL,
+			"type=%s, flag=0x%04x, lorv=%s\n",
+			s_ipsecdoi_attr(type), flag,
+			s_ipsecdoi_attr_v(type, ntohs(d->lorv)));
+
+		switch (type) {
+		case IPSECDOI_ATTR_SA_LD_TYPE:
+		{
+			int type = ntohs(d->lorv);
+			switch (type) {
+			case IPSECDOI_ATTR_SA_LD_TYPE_SEC:
+			case IPSECDOI_ATTR_SA_LD_TYPE_KB:
+				life_t = type;
+				break;
+			default:
+				plog(LLV_WARNING, LOCATION, NULL,
+					"invalid life duration type. "
+					"use default\n");
+				life_t = IPSECDOI_ATTR_SA_LD_TYPE_DEFAULT;
+				break;
+			}
+			break;
+		}
+		case IPSECDOI_ATTR_SA_LD:
+			if (prev == NULL
+			 || (ntohs(prev->type) & ~ISAKMP_GEN_MASK) !=
+					IPSECDOI_ATTR_SA_LD_TYPE) {
+				plog(LLV_ERROR, LOCATION, NULL,
+				    "life duration must follow ltype\n");
+				break;
+			}
+
+		    {
+			u_int32_t t;
+			vchar_t *ld_buf = NULL;
+
+			if (flag) {
+				/* i.e. ISAKMP_GEN_TV */
+				ld_buf = vmalloc(sizeof(d->lorv));
+				if (ld_buf == NULL) {
+					plog(LLV_ERROR, LOCATION, NULL,
+					    "failed to get LD buffer.\n");
+					goto end;
+				}
+				memcpy(ld_buf->v, &d->lorv, sizeof(d->lorv));
+			} else {
+				int len = ntohs(d->lorv);
+				/* i.e. ISAKMP_GEN_TLV */
+				ld_buf = vmalloc(len);
+				if (ld_buf == NULL) {
+					plog(LLV_ERROR, LOCATION, NULL,
+					    "failed to get LD buffer.\n");
+					goto end;
+				}
+				memcpy(ld_buf->v, d + 1, len);
+			}
+			switch (life_t) {
+			case IPSECDOI_ATTR_SA_LD_TYPE_SEC:
+				t = ipsecdoi_set_ld(ld_buf);
+				vfree(ld_buf);
+				if (t == 0) {
+					plog(LLV_ERROR, LOCATION, NULL,
+						"invalid life duration.\n");
+					goto end;
+				}
+				/* lifetime must be equal in a proposal. */
+				if (pp->lifetime == IPSECDOI_ATTR_SA_LD_SEC_DEFAULT)
+					pp->lifetime = t;
+				else if (pp->lifetime != t) {
+					plog(LLV_ERROR, LOCATION, NULL,
+						"lifetime mismatched "
+						"in a proposal, "
+						"prev:%ld curr:%u.\n",
+						(long)pp->lifetime, t);
+					goto end;
+				}
+				break;
+			case IPSECDOI_ATTR_SA_LD_TYPE_KB:
+				t = ipsecdoi_set_ld(ld_buf);
+				vfree(ld_buf);
+				if (t == 0) {
+					plog(LLV_ERROR, LOCATION, NULL,
+						"invalid life duration.\n");
+					goto end;
+				}
+				/* lifebyte must be equal in a proposal. */
+				if (pp->lifebyte == 0)
+					pp->lifebyte = t;
+				else if (pp->lifebyte != t) {
+					plog(LLV_ERROR, LOCATION, NULL,
+						"lifebyte mismatched "
+						"in a proposal, "
+						"prev:%d curr:%u.\n",
+						pp->lifebyte, t);
+					goto end;
+				}
+				break;
+			default:
+				vfree(ld_buf);
+				plog(LLV_ERROR, LOCATION, NULL,
+					"invalid life type: %d\n", life_t);
+				goto end;
+			}
+		    }
+			break;
+
+		case IPSECDOI_ATTR_GRP_DESC:
+			/*
+			 * RFC2407: 4.5 IPSEC Security Association Attributes
+			 *   Specifies the Oakley Group to be used in a PFS QM
+			 *   negotiation.  For a list of supported values, see
+			 *   Appendix A of [IKE].
+			 */
+			if (pp->pfs_group == 0)
+				pp->pfs_group = (u_int16_t)ntohs(d->lorv);
+			else if (pp->pfs_group != (u_int16_t)ntohs(d->lorv)) {
+				plog(LLV_ERROR, LOCATION, NULL,
+					"pfs_group mismatched "
+					"in a proposal.\n");
+				goto end;
+			}
+			break;
+
+		case IPSECDOI_ATTR_ENC_MODE:
+			if (pr->encmode &&
+			    pr->encmode != (u_int16_t)ntohs(d->lorv)) {
+				plog(LLV_ERROR, LOCATION, NULL,
+					"multiple encmode exist "
+					"in a transform.\n");
+				goto end;
+			}
+			pr->encmode = (u_int16_t)ntohs(d->lorv);
+			break;
+
+		case IPSECDOI_ATTR_AUTH:
+			if (tr->authtype != IPSECDOI_ATTR_AUTH_NONE) {
+				plog(LLV_ERROR, LOCATION, NULL,
+					"multiple authtype exist "
+					"in a transform.\n");
+				goto end;
+			}
+			tr->authtype = (u_int16_t)ntohs(d->lorv);
+			break;
+
+		case IPSECDOI_ATTR_KEY_LENGTH:
+			if (pr->proto_id != IPSECDOI_PROTO_IPSEC_ESP) {
+				plog(LLV_ERROR, LOCATION, NULL,
+					"key length defined but not ESP");
+				goto end;
+			}
+			tr->encklen = ntohs(d->lorv);
+			break;
+#ifdef HAVE_SECCTX
+		case IPSECDOI_ATTR_SECCTX:
+		{
+			int len = ntohs(d->lorv);
+			memcpy(&pp->sctx, d + 1, len);
+			pp->sctx.ctx_strlen = ntohs(pp->sctx.ctx_strlen);
+			break;
+		}
+#endif /* HAVE_SECCTX */
+		case IPSECDOI_ATTR_KEY_ROUNDS:
+		case IPSECDOI_ATTR_COMP_DICT_SIZE:
+		case IPSECDOI_ATTR_COMP_PRIVALG:
+		default:
+			break;
+		}
+
+		prev = d;
+		if (flag) {
+			tlen -= sizeof(*d);
+			d = (struct isakmp_data *)((char *)d + sizeof(*d));
+		} else {
+			tlen -= (sizeof(*d) + ntohs(d->lorv));
+			d = (struct isakmp_data *)((caddr_t)d + sizeof(*d) + ntohs(d->lorv));
+		}
+	}
+
+	error = 0;
+end:
+	return error;
+}
+
+int
+ipsecdoi_authalg2trnsid(alg)
+	int alg;
+{
+	switch (alg) {
+        case IPSECDOI_ATTR_AUTH_HMAC_MD5:
+		return IPSECDOI_AH_MD5;
+        case IPSECDOI_ATTR_AUTH_HMAC_SHA1:
+		return IPSECDOI_AH_SHA;
+	case IPSECDOI_ATTR_AUTH_HMAC_SHA2_256:
+		return IPSECDOI_AH_SHA256;
+	case IPSECDOI_ATTR_AUTH_HMAC_SHA2_384:
+		return IPSECDOI_AH_SHA384;
+	case IPSECDOI_ATTR_AUTH_HMAC_SHA2_512:
+		return IPSECDOI_AH_SHA512;
+        case IPSECDOI_ATTR_AUTH_DES_MAC:
+		return IPSECDOI_AH_DES;
+	case IPSECDOI_ATTR_AUTH_KPDK:
+		return IPSECDOI_AH_MD5;	/* XXX */
+	default:
+		plog(LLV_ERROR, LOCATION, NULL,
+			"invalid authentication algorithm:%d\n", alg);
+	}
+	return -1;
+}
+
+#ifdef HAVE_GSSAPI
+struct isakmpsa *
+fixup_initiator_sa(match, received)
+	struct isakmpsa *match, *received;
+{
+	if (received->gssid != NULL)
+		match->gssid = vdup(received->gssid);
+
+	return match;
+}
+#endif
+
+static int rm_idtype2doi[] = {
+	255,				/* IDTYPE_UNDEFINED, 0 */
+	IPSECDOI_ID_FQDN,		/* IDTYPE_FQDN, 1 */
+	IPSECDOI_ID_USER_FQDN,		/* IDTYPE_USERFQDN, 2 */
+	IPSECDOI_ID_KEY_ID,		/* IDTYPE_KEYID, 3 */
+	255,    /*			   IDTYPE_ADDRESS, 4 
+		 * it expands into 4 types by another function. */
+	IPSECDOI_ID_DER_ASN1_DN,	/* IDTYPE_ASN1DN, 5 */
+};
+
+/*
+ * convert idtype to DOI value.
+ * OUT	255  : NG
+ *	other: converted.
+ */
+int
+idtype2doi(idtype)
+	int idtype;
+{
+	if (ARRAYLEN(rm_idtype2doi) > idtype)
+		return rm_idtype2doi[idtype];
+	return 255;
+}
+
+int
+doi2idtype(doi)
+	int doi;
+{
+	switch(doi) {
+	case IPSECDOI_ID_FQDN:
+		return(IDTYPE_FQDN);
+	case IPSECDOI_ID_USER_FQDN:
+		return(IDTYPE_USERFQDN);
+	case IPSECDOI_ID_KEY_ID:
+		return(IDTYPE_KEYID);
+	case IPSECDOI_ID_DER_ASN1_DN:
+		return(IDTYPE_ASN1DN);
+	case IPSECDOI_ID_IPV4_ADDR:
+	case IPSECDOI_ID_IPV4_ADDR_SUBNET:
+	case IPSECDOI_ID_IPV6_ADDR:
+	case IPSECDOI_ID_IPV6_ADDR_SUBNET:
+		return(IDTYPE_ADDRESS);
+	default:
+		plog(LLV_WARNING, LOCATION, NULL,
+			"Inproper idtype:%s in this function.\n",
+			s_ipsecdoi_ident(doi));
+		return(IDTYPE_ADDRESS);	/* XXX */
+	}
+	/*NOTREACHED*/
+}
+
+#ifdef ENABLE_HYBRID
+static int
+switch_authmethod(authmethod)
+	int authmethod;
+{
+	switch(authmethod) {
+	case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_R:
+		authmethod = OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I;
+		break;
+	case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_R:
+		authmethod = OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_I;
+		break;
+	case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_R:
+		authmethod = OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_I;
+		break;
+	case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_R:
+		authmethod = OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_I;
+		break;
+	/* Those are not implemented */
+	case OAKLEY_ATTR_AUTH_METHOD_XAUTH_DSSSIG_R:
+		authmethod = OAKLEY_ATTR_AUTH_METHOD_XAUTH_DSSSIG_I;
+		break;
+	case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAENC_R:
+		authmethod = OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAENC_I;
+		break;
+	case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAREV_R:
+		authmethod = OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAREV_I;
+		break;
+	default:
+		break;
+	}
+
+	return authmethod;
+}
+#endif
+
+/*
+ * parse responder-lifetime attributes from payload
+ */
+int
+ipsecdoi_parse_responder_lifetime(notify, lifetime_sec, lifetime_kb)
+	struct isakmp_pl_n *notify;
+	u_int32_t *lifetime_sec;
+	u_int32_t *lifetime_kb;
+{
+	struct isakmp_data *d;
+	int flag, type, tlen, ld_type = -1;
+	u_int16_t lorv;
+	u_int32_t value;
+
+	tlen = ntohs(notify->h.len) - sizeof(*notify) - notify->spi_size;
+        d = (struct isakmp_data *)((char *)(notify + 1) +
+		notify->spi_size);
+
+	while (tlen >= sizeof(struct isakmp_data)) {
+		type = ntohs(d->type) & ~ISAKMP_GEN_MASK;
+		flag = ntohs(d->type) & ISAKMP_GEN_MASK;
+		lorv = ntohs(d->lorv);
+
+		plog(LLV_DEBUG, LOCATION, NULL,
+			"type=%s, flag=0x%04x, lorv=%s\n",
+			s_ipsecdoi_attr(type), flag,
+			s_ipsecdoi_attr_v(type, lorv));
+
+		switch (type) {
+		case IPSECDOI_ATTR_SA_LD_TYPE:
+			if (! flag) {
+				plog(LLV_ERROR, LOCATION, NULL,
+					"must be TV when LD_TYPE.\n");
+				return -1;
+			}
+			ld_type = lorv;
+			break;
+		case IPSECDOI_ATTR_SA_LD:
+			if (flag)
+				value = lorv;
+			else if (lorv == 2)
+				value = ntohs(*(u_int16_t *)(d + 1));
+			else if (lorv == 4)
+				value = ntohl(*(u_int32_t *)(d + 1));
+			else {
+				plog(LLV_ERROR, LOCATION, NULL,
+					"payload length %d for lifetime "
+					"data length is unsupported.\n", lorv);
+				return -1;
+			}
+
+			switch (ld_type) {
+			case IPSECDOI_ATTR_SA_LD_TYPE_SEC:
+				if (lifetime_sec != NULL)
+					*lifetime_sec = value;
+				plog(LLV_INFO, LOCATION, NULL,
+					"received RESPONDER-LIFETIME: %d "
+					"seconds\n", value);
+				break;
+			case IPSECDOI_ATTR_SA_LD_TYPE_KB:
+				if (lifetime_kb != NULL)
+					*lifetime_kb = value;
+				plog(LLV_INFO, LOCATION, NULL,
+					"received RESPONDER-LIFETIME: %d "
+					"kbytes\n", value);
+				break;
+			default:
+				plog(LLV_ERROR, LOCATION, NULL,
+					"lifetime data received without "
+					"lifetime data type.\n");
+				return -1;
+			}
+			break;
+		}
+
+		if (flag) {
+			tlen -= sizeof(*d);
+			d = (struct isakmp_data *)((char *)d
+				+ sizeof(*d));
+		} else {
+			tlen -= (sizeof(*d) + lorv);
+			d = (struct isakmp_data *)((char *)d
+				+ sizeof(*d) + lorv);
+		}
+	}
+
+	return 0;
+}
diff --git a/src/racoon/ipsec_doi.c b/src/racoon/ipsec_doi.c
index d0d289b..5890314 100644
--- a/src/racoon/ipsec_doi.c
+++ b/src/racoon/ipsec_doi.c
@@ -1,11 +1,11 @@
-/*	$NetBSD: ipsec_doi.c,v 1.23.4.10 2009/06/19 07:32:52 tteras Exp $	*/
+/*	$NetBSD: ipsec_doi.c,v 1.46 2010/12/14 17:57:31 tteras Exp $	*/
 
 /* Id: ipsec_doi.c,v 1.55 2006/08/17 09:20:41 vanhu Exp */
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
  * All rights reserved.
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
@@ -17,7 +17,7 @@
  * 3. Neither the name of the project nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
- * 
+ *
  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@@ -83,9 +83,6 @@
 #ifdef ENABLE_NATT
 #include "nattraversal.h"
 #endif
-#ifdef ENABLE_HYBRID
-static int switch_authmethod(int);
-#endif
 
 #ifdef HAVE_GSSAPI
 #include <iconv.h>
@@ -97,19 +94,19 @@
 #endif
 #endif
 
-int verbose_proposal_check = 1;
+static vchar_t *get_ph1approval __P((struct ph1handle *, u_int32_t, u_int32_t,
+				     struct prop_pair **));
+static int get_ph1approvalx __P((struct remoteconf *, void *));
 
-static vchar_t *get_ph1approval __P((struct ph1handle *, struct prop_pair **));
-static struct isakmpsa *get_ph1approvalx __P((struct prop_pair *,
-	struct isakmpsa *, struct isakmpsa *, int));
-static void print_ph1mismatched __P((struct prop_pair *, struct isakmpsa *));
-static int t2isakmpsa __P((struct isakmp_pl_t *, struct isakmpsa *));
+static int t2isakmpsa __P((struct isakmp_pl_t *, struct isakmpsa *, u_int32_t));
 static int cmp_aproppair_i __P((struct prop_pair *, struct prop_pair *));
 static struct prop_pair *get_ph2approval __P((struct ph2handle *,
 	struct prop_pair **));
 static struct prop_pair *get_ph2approvalx __P((struct ph2handle *,
 	struct prop_pair *));
 static void free_proppair0 __P((struct prop_pair *));
+static struct prop_pair ** get_proppair_and_doi_sit __P((vchar_t *, int,
+							 u_int32_t *, u_int32_t *));
 
 static int get_transform
 	__P((struct isakmp_pl_p *, struct prop_pair **, int *));
@@ -158,12 +155,10 @@
 static vchar_t *setph2proposal0 __P((const struct ph2handle *,
 	const struct saprop *, const struct saproto *));
 
-static vchar_t *getidval __P((int, vchar_t *));
-
-#ifdef HAVE_GSSAPI
-static struct isakmpsa *fixup_initiator_sa __P((struct isakmpsa *,
-	struct isakmpsa *));
-#endif
+struct ph1approvalx_ctx {
+	struct prop_pair *p;
+	struct isakmpsa *sa;
+};
 
 /*%%%*/
 /*
@@ -182,40 +177,82 @@
 {
 	vchar_t *newsa;		/* new SA payload approved. */
 	struct prop_pair **pair;
+	u_int32_t doitype, sittype;
 
 	/* get proposal pair */
-	pair = get_proppair(sa, IPSECDOI_TYPE_PH1);
+	pair = get_proppair_and_doi_sit(sa, IPSECDOI_TYPE_PH1,
+					&doitype, &sittype);
 	if (pair == NULL)
 		return -1;
 
 	/* check and get one SA for use */
-	newsa = get_ph1approval(iph1, pair);
-	
+	newsa = get_ph1approval(iph1, doitype, sittype, pair);
 	free_proppair(pair);
 
 	if (newsa == NULL)
 		return -1;
 
 	iph1->sa_ret = newsa;
-
 	return 0;
 }
 
+static void
+print_ph1proposal(pair, s)
+	struct prop_pair *pair;
+	struct isakmpsa *s;
+{
+	struct isakmp_pl_p *prop = pair->prop;
+	struct isakmp_pl_t *trns = pair->trns;
+
+	plog(LLV_DEBUG, LOCATION, NULL,
+	     "prop#=%d, prot-id=%s, spi-size=%d, #trns=%d\n",
+	     prop->p_no, s_ipsecdoi_proto(prop->proto_id),
+	     prop->spi_size, prop->num_t);
+	plog(LLV_DEBUG, LOCATION, NULL,
+	     "trns#=%d, trns-id=%s\n",
+	     trns->t_no, s_ipsecdoi_trns(prop->proto_id, trns->t_id));
+	plog(LLV_DEBUG, LOCATION, NULL,
+	     "  lifetime = %ld\n", (long) s->lifetime);
+	plog(LLV_DEBUG, LOCATION, NULL,
+	     "  lifebyte = %zu\n", s->lifebyte);
+	plog(LLV_DEBUG, LOCATION, NULL,
+	     "  enctype = %s\n",
+	     s_oakley_attr_v(OAKLEY_ATTR_ENC_ALG, s->enctype));
+	plog(LLV_DEBUG, LOCATION, NULL,
+	     "  encklen = %d\n", s->encklen);
+	plog(LLV_DEBUG, LOCATION, NULL,
+	     "  hashtype = %s\n",
+	     s_oakley_attr_v(OAKLEY_ATTR_HASH_ALG, s->hashtype));
+	plog(LLV_DEBUG, LOCATION, NULL,
+	     "  authmethod = %s\n",
+	     s_oakley_attr_v(OAKLEY_ATTR_AUTH_METHOD, s->authmethod));
+	plog(LLV_DEBUG, LOCATION, NULL,
+	     "  dh_group = %s\n",
+	     s_oakley_attr_v(OAKLEY_ATTR_GRP_DESC, s->dh_group));
+}
+
+
 /*
  * acceptable check for remote configuration.
  * return a new SA payload to be reply to peer.
  */
+
 static vchar_t *
-get_ph1approval(iph1, pair)
+get_ph1approval(iph1, doitype, sittype, pair)
 	struct ph1handle *iph1;
+	u_int32_t doitype, sittype;
 	struct prop_pair **pair;
 {
 	vchar_t *newsa;
-	struct isakmpsa *sa, tsa;
+	struct ph1approvalx_ctx ctx;
 	struct prop_pair *s, *p;
-	int prophlen;
+	struct rmconfselector rmsel;
+	struct isakmpsa *sa;
 	int i;
 
+	memset(&rmsel, 0, sizeof(rmsel));
+	rmsel.remote = iph1->remote;
+
 	if (iph1->approval) {
 		delisakmpsa(iph1->approval);
 		iph1->approval = NULL;
@@ -225,42 +262,35 @@
 		if (pair[i] == NULL)
 			continue;
 		for (s = pair[i]; s; s = s->next) {
-			prophlen = 
-			    sizeof(struct isakmp_pl_p) + s->prop->spi_size;
-
 			/* compare proposal and select one */
 			for (p = s; p; p = p->tnext) {
-				if ((sa = get_ph1approvalx(p, 
-				    iph1->rmconf->proposal, &tsa, 
-				    iph1->rmconf->pcheck_level)) != NULL)
-					goto found;
+				struct isakmp_pl_p *prop = p->prop;
+
+				sa = newisakmpsa();
+				ctx.p = p;
+				ctx.sa = sa;
+				if (t2isakmpsa(p->trns, sa,
+					       iph1->vendorid_mask) < 0)
+					continue;
+				print_ph1proposal(p, sa);
+				if (iph1->rmconf != NULL) {
+					if (get_ph1approvalx(iph1->rmconf, &ctx))
+						goto found;
+				} else {
+					if (enumrmconf(&rmsel, get_ph1approvalx, &ctx))
+						goto found;
+				}
+				delisakmpsa(sa);
 			}
 		}
 	}
 
-	/*
-	 * if there is no suitable proposal, racoon complains about all of
-	 * mismatched items in those proposal.
-	 */
-	if (verbose_proposal_check) {
-		for (i = 0; i < MAXPROPPAIRLEN; i++) {
-			if (pair[i] == NULL)
-				continue;
-			for (s = pair[i]; s; s = s->next) {
-				prophlen = sizeof(struct isakmp_pl_p)
-						+ s->prop->spi_size;
-				for (p = s; p; p = p->tnext) {
-					print_ph1mismatched(p,
-						iph1->rmconf->proposal);
-				}
-			}
-		}
-	}
 	plog(LLV_ERROR, LOCATION, NULL, "no suitable proposal found.\n");
 
 	return NULL;
 
 found:
+	sa = ctx.sa;
 	plog(LLV_DEBUG, LOCATION, NULL, "an acceptable proposal found.\n");
 
 	/* check DH group settings */
@@ -277,7 +307,7 @@
 
 	if (oakley_setdhgroup(sa->dh_group, &sa->dhgrp) == -1) {
 		sa->dhgrp = NULL;
-		racoon_free(sa);
+		delisakmpsa(sa);
 		return NULL;
 	}
 
@@ -286,20 +316,16 @@
 	if (sa->gssid != NULL)
 		plog(LLV_DEBUG, LOCATION, NULL, "gss id in new sa '%.*s'\n",
 		    (int)sa->gssid->l, sa->gssid->v);
-	if (iph1-> side == INITIATOR) {
+	if (iph1->side == INITIATOR) {
 		if (iph1->rmconf->proposal->gssid != NULL)
 			iph1->gi_i = vdup(iph1->rmconf->proposal->gssid);
-		if (tsa.gssid != NULL)
-			iph1->gi_r = vdup(tsa.gssid);
-		iph1->approval = fixup_initiator_sa(sa, &tsa);
+		if (sa->gssid != NULL)
+			iph1->gi_r = vdup(sa->gssid);
 	} else {
-		if (tsa.gssid != NULL) {
-			iph1->gi_r = vdup(tsa.gssid);
+		if (sa->gssid != NULL) {
+			iph1->gi_r = vdup(sa->gssid);
 			iph1->gi_i = gssapi_get_id(iph1);
-			if (sa->gssid == NULL && iph1->gi_i != NULL)
-				sa->gssid = vdup(iph1->gi_i);
 		}
-		iph1->approval = sa;
 	}
 	if (iph1->gi_i != NULL)
 		plog(LLV_DEBUG, LOCATION, NULL, "GIi is %.*s\n",
@@ -307,19 +333,15 @@
 	if (iph1->gi_r != NULL)
 		plog(LLV_DEBUG, LOCATION, NULL, "GIr is %.*s\n",
 		    (int)iph1->gi_r->l, iph1->gi_r->v);
-#else
-	iph1->approval = sa;
 #endif
-	if(iph1->approval) {
-		plog(LLV_DEBUG, LOCATION, NULL, "agreed on %s auth.\n",
-		    s_oakley_attr_method(iph1->approval->authmethod));
-	}
+	plog(LLV_DEBUG, LOCATION, NULL, "agreed on %s auth.\n",
+	     s_oakley_attr_method(sa->authmethod));
 
-	newsa = get_sabyproppair(p, iph1);
-	if (newsa == NULL){
-		delisakmpsa(iph1->approval);
-		iph1->approval = NULL;
-	}
+	newsa = get_sabyproppair(doitype, sittype, p);
+	if (newsa == NULL)
+		delisakmpsa(sa);
+	else
+		iph1->approval = sa;
 
 	return newsa;
 }
@@ -327,228 +349,57 @@
 /*
  * compare peer's single proposal and all of my proposal.
  * and select one if suiatable.
- * p       : one of peer's proposal.
- * proposal: my proposals.
  */
-static struct isakmpsa *
-get_ph1approvalx(p, proposal, sap, check_level)
-	struct prop_pair *p;
-	struct isakmpsa *proposal, *sap;
-	int check_level;
+static int
+get_ph1approvalx(rmconf, ctx)
+	struct remoteconf *rmconf;
+	void *ctx;
 {
-	struct isakmp_pl_p *prop = p->prop;
-	struct isakmp_pl_t *trns = p->trns;
-	struct isakmpsa sa, *s, *tsap;
-	int authmethod;
+	struct ph1approvalx_ctx *pctx = (struct ph1approvalx_ctx *) ctx;
+	struct isakmpsa *sa;
 
-	plog(LLV_DEBUG, LOCATION, NULL,
-       		"prop#=%d, prot-id=%s, spi-size=%d, #trns=%d\n",
-		prop->p_no, s_ipsecdoi_proto(prop->proto_id),
-		prop->spi_size, prop->num_t);
+	/* do the hard work */
+	sa = checkisakmpsa(rmconf->pcheck_level, pctx->sa, rmconf->proposal);
+	if (sa == NULL)
+		return 0;
 
-	plog(LLV_DEBUG, LOCATION, NULL,
-		"trns#=%d, trns-id=%s\n",
-		trns->t_no,
-		s_ipsecdoi_trns(prop->proto_id, trns->t_id));
+	/* duplicate and modify the found SA to match proposal */
+	sa = dupisakmpsa(sa);
 
-	tsap = sap != NULL ? sap : &sa;
-
-	memset(tsap, 0, sizeof(*tsap));
-	if (t2isakmpsa(trns, tsap) < 0)
-		return NULL;
-	for (s = proposal; s != NULL; s = s->next) {
-#ifdef ENABLE_HYBRID
-		authmethod = switch_authmethod(s->authmethod);
-#else
-		authmethod = s->authmethod;
-#endif
-		plog(LLV_DEBUG, LOCATION, NULL, "Compared: DB:Peer\n");
-		plog(LLV_DEBUG, LOCATION, NULL, "(lifetime = %ld:%ld)\n",
-			(long)s->lifetime, (long)tsap->lifetime);
-		plog(LLV_DEBUG, LOCATION, NULL, "(lifebyte = %zu:%zu)\n",
-			s->lifebyte, tsap->lifebyte);
-		plog(LLV_DEBUG, LOCATION, NULL, "enctype = %s:%s\n",
-			s_oakley_attr_v(OAKLEY_ATTR_ENC_ALG,
-					s->enctype),
-			s_oakley_attr_v(OAKLEY_ATTR_ENC_ALG,
-					tsap->enctype));
-		plog(LLV_DEBUG, LOCATION, NULL, "(encklen = %d:%d)\n",
-			s->encklen, tsap->encklen);
-		plog(LLV_DEBUG, LOCATION, NULL, "hashtype = %s:%s\n",
-			s_oakley_attr_v(OAKLEY_ATTR_HASH_ALG,
-					s->hashtype),
-			s_oakley_attr_v(OAKLEY_ATTR_HASH_ALG,
-					tsap->hashtype));
-		plog(LLV_DEBUG, LOCATION, NULL, "authmethod = %s:%s\n",
-			s_oakley_attr_v(OAKLEY_ATTR_AUTH_METHOD,
-					s->authmethod),
-			s_oakley_attr_v(OAKLEY_ATTR_AUTH_METHOD,
-					tsap->authmethod));
-		plog(LLV_DEBUG, LOCATION, NULL, "dh_group = %s:%s\n",
-			s_oakley_attr_v(OAKLEY_ATTR_GRP_DESC,
-					s->dh_group),
-			s_oakley_attr_v(OAKLEY_ATTR_GRP_DESC,
-					tsap->dh_group));
-#if 0
-		/* XXX to be considered ? */
-		if (tsap->lifebyte > s->lifebyte) ;
-#endif
-		/*
-		 * if responder side and peer's key length in proposal
-		 * is bigger than mine, it might be accepted.
-		 */
-		if(tsap->enctype == s->enctype &&
-		    tsap->authmethod == authmethod &&
-		    tsap->hashtype == s->hashtype &&
-		    tsap->dh_group == s->dh_group &&
-		    tsap->encklen == s->encklen) {
-			switch(check_level) {
-			case PROP_CHECK_OBEY:
-				goto found;
-				break;
-
-			case PROP_CHECK_STRICT:
-				if ((tsap->lifetime > s->lifetime) ||
-				    (tsap->lifebyte > s->lifebyte))
-					continue;
-				goto found;
-				break;
-
-			case PROP_CHECK_CLAIM:
-				if (tsap->lifetime < s->lifetime)
-					s->lifetime = tsap->lifetime;
-				if (tsap->lifebyte < s->lifebyte)
-					s->lifebyte = tsap->lifebyte;
-				goto found;
-				break;
-
-			case PROP_CHECK_EXACT:
-				if ((tsap->lifetime != s->lifetime) ||
-				    (tsap->lifebyte != s->lifebyte))
-					continue;
-				goto found;
-				break;
-
-			default:
-				plog(LLV_ERROR, LOCATION, NULL, 
-				    "Unexpected proposal_check value\n");
-				continue;
-				break;
-			}
-		}
+	switch (rmconf->pcheck_level) {
+	case PROP_CHECK_OBEY:
+		sa->lifetime = pctx->sa->lifetime;
+		sa->lifebyte = pctx->sa->lifebyte;
+		sa->encklen = pctx->sa->encklen;
+		break;
+	case PROP_CHECK_CLAIM:
+	case PROP_CHECK_STRICT:
+		if (pctx->sa->lifetime < sa->lifetime)
+			sa->lifetime = pctx->sa->lifetime;
+		if (pctx->sa->lifebyte < sa->lifebyte)
+			sa->lifebyte = pctx->sa->lifebyte;
+		if (pctx->sa->encklen > sa->encklen)
+			sa->encklen = pctx->sa->encklen;
+		break;
+	default:
+		break;
 	}
 
-found:
-	if (tsap->dhgrp != NULL){
-		oakley_dhgrp_free(tsap->dhgrp);
-		tsap->dhgrp = NULL;
-	}
+	/* replace the proposal with our approval sa */
+	delisakmpsa(pctx->sa);
+	pctx->sa = sa;
 
-	if ((s = dupisakmpsa(s)) != NULL) {
-		switch(check_level) {
-		case PROP_CHECK_OBEY:
-			s->lifetime = tsap->lifetime;
-			s->lifebyte = tsap->lifebyte;
-			break;
-
-		case PROP_CHECK_STRICT:
-			s->lifetime = tsap->lifetime;
-			s->lifebyte = tsap->lifebyte;
-			break;
-
-		case PROP_CHECK_CLAIM:
-			if (tsap->lifetime < s->lifetime)
-				s->lifetime = tsap->lifetime;
-			if (tsap->lifebyte < s->lifebyte)
-				s->lifebyte = tsap->lifebyte;
-			break;
-
-		default:
-			break;
-		}
-	}
-	return s;
-}
-
-/*
- * print all of items in peer's proposal which are mismatched to my proposal.
- * p       : one of peer's proposal.
- * proposal: my proposals.
- */
-static void
-print_ph1mismatched(p, proposal)
-	struct prop_pair *p;
-	struct isakmpsa *proposal;
-{
-	struct isakmpsa sa, *s;
-
-	memset(&sa, 0, sizeof(sa));
-	if (t2isakmpsa(p->trns, &sa) < 0)
-		return;
-	for (s = proposal; s ; s = s->next) {
-		if (sa.enctype != s->enctype) {
-			plog(LLV_ERROR, LOCATION, NULL,
-				"rejected enctype: "
-				"DB(prop#%d:trns#%d):Peer(prop#%d:trns#%d) = "
-				"%s:%s\n",
-				s->prop_no, s->trns_no,
-				p->prop->p_no, p->trns->t_no,
-				s_oakley_attr_v(OAKLEY_ATTR_ENC_ALG,
-					s->enctype),
-				s_oakley_attr_v(OAKLEY_ATTR_ENC_ALG,
-					sa.enctype));
-		}
-		if (sa.authmethod != s->authmethod) {
-			plog(LLV_ERROR, LOCATION, NULL,
-				"rejected authmethod: "
-				"DB(prop#%d:trns#%d):Peer(prop#%d:trns#%d) = "
-				"%s:%s\n",
-				s->prop_no, s->trns_no,
-				p->prop->p_no, p->trns->t_no,
-				s_oakley_attr_v(OAKLEY_ATTR_AUTH_METHOD,
-					s->authmethod),
-				s_oakley_attr_v(OAKLEY_ATTR_AUTH_METHOD,
-					sa.authmethod));
-		}
-		if (sa.hashtype != s->hashtype) {
-			plog(LLV_ERROR, LOCATION, NULL,
-				"rejected hashtype: "
-				"DB(prop#%d:trns#%d):Peer(prop#%d:trns#%d) = "
-				"%s:%s\n",
-				s->prop_no, s->trns_no,
-				p->prop->p_no, p->trns->t_no,
-				s_oakley_attr_v(OAKLEY_ATTR_HASH_ALG,
-					s->hashtype),
-				s_oakley_attr_v(OAKLEY_ATTR_HASH_ALG,
-					sa.hashtype));
-		}
-		if (sa.dh_group != s->dh_group) {
-			plog(LLV_ERROR, LOCATION, NULL,
-				"rejected dh_group: "
-				"DB(prop#%d:trns#%d):Peer(prop#%d:trns#%d) = "
-				"%s:%s\n",
-				s->prop_no, s->trns_no,
-				p->prop->p_no, p->trns->t_no,
-				s_oakley_attr_v(OAKLEY_ATTR_GRP_DESC,
-					s->dh_group),
-				s_oakley_attr_v(OAKLEY_ATTR_GRP_DESC,
-					sa.dh_group));
-		}
-	}
-
-	if (sa.dhgrp != NULL){
-		oakley_dhgrp_free(sa.dhgrp);
-		sa.dhgrp=NULL;
-	}
+	return 1;
 }
 
 /*
  * get ISAKMP data attributes
  */
 static int
-t2isakmpsa(trns, sa)
+t2isakmpsa(trns, sa, vendorid_mask)
 	struct isakmp_pl_t *trns;
 	struct isakmpsa *sa;
+	u_int32_t vendorid_mask;
 {
 	struct isakmp_data *d, *prev;
 	int flag, type;
@@ -618,6 +469,11 @@
 
 		case OAKLEY_ATTR_AUTH_METHOD:
 			sa->authmethod = ntohs(d->lorv);
+#ifdef HAVE_GSSAPI
+			if (sa->authmethod == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB_REAL &&
+			    (vendorid_mask & VENDORID_GSSAPI_MASK))
+				sa->authmethod = OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB;
+#endif
 			break;
 
 		case OAKLEY_ATTR_GRP_DESC:
@@ -770,7 +626,7 @@
 				plog(LLV_DEBUG, LOCATION, NULL,
 				    "received old-style gss "
 				    "id '%.*s' (len %zu)\n",
-				    (int)sa->gssid->l, sa->gssid->v, 
+				    (int)sa->gssid->l, sa->gssid->v,
 				    sa->gssid->l);
 				error = 0;
 				goto out;
@@ -805,7 +661,7 @@
 			dst = sa->gssid->v;
 			dstleft = len / 2;
 
-			rv = iconv(cd, (__iconv_const char **)&src, &srcleft, 
+			rv = iconv(cd, (__iconv_const char **)&src, &srcleft,
 				   &dst, &dstleft);
 			if (rv != 0) {
 				if (rv == -1) {
@@ -891,9 +747,11 @@
 {
 	struct prop_pair **pair;
 	struct prop_pair *ret;
+	u_int32_t doitype, sittype;
 
 	/* get proposal pair */
-	pair = get_proppair(iph2->sa, IPSECDOI_TYPE_PH2);
+	pair = get_proppair_and_doi_sit(iph2->sa, IPSECDOI_TYPE_PH2,
+					&doitype, &sittype);
 	if (pair == NULL)
 		return -1;
 
@@ -905,7 +763,7 @@
 
 	/* make a SA to be replayed. */
 	/* SPI must be updated later. */
-	iph2->sa_ret = get_sabyproppair(ret, iph2->ph1);
+	iph2->sa_ret = get_sabyproppair(doitype, sittype, ret);
 	free_proppair0(ret);
 	if (iph2->sa_ret == NULL)
 		return -1;
@@ -929,9 +787,11 @@
 	int i, n, num;
 	int error = -1;
 	vchar_t *sa_ret = NULL;
+	u_int32_t doitype, sittype;
 
 	/* get proposal pair of SA sent. */
-	spair = get_proppair(iph2->sa, IPSECDOI_TYPE_PH2);
+	spair = get_proppair_and_doi_sit(iph2->sa, IPSECDOI_TYPE_PH2,
+					 &doitype, &sittype);
 	if (spair == NULL) {
 		plog(LLV_ERROR, LOCATION, NULL,
 			"failed to get prop pair.\n");
@@ -972,7 +832,7 @@
 		plog(LLV_WARNING, LOCATION, NULL,
 			"invalid proposal number:%d received.\n", i);
 	}
-	
+
 
 	if (rpair[n]->tnext != NULL) {
 		plog(LLV_ERROR, LOCATION, NULL,
@@ -997,7 +857,7 @@
 
 	/* make a SA to be replayed. */
 	sa_ret = iph2->sa_ret;
-	iph2->sa_ret = get_sabyproppair(p, iph2->ph1);
+	iph2->sa_ret = get_sabyproppair(doitype, sittype, p);
 	free_proppair0(p);
 	if (iph2->sa_ret == NULL)
 		goto end;
@@ -1282,10 +1142,11 @@
  * get proposal pairs from SA payload.
  * tiny check for proposal payload.
  */
-struct prop_pair **
-get_proppair(sa, mode)
+static struct prop_pair **
+get_proppair_and_doi_sit(sa, mode, doitype, sittype)
 	vchar_t *sa;
 	int mode;
+	u_int32_t *doitype, *sittype;
 {
 	struct prop_pair **pair = NULL;
 	int num_p = 0;			/* number of proposal for use */
@@ -1307,10 +1168,14 @@
 	/* check DOI */
 	if (check_doi(ntohl(sab->doi)) < 0)
 		goto bad;
+	if (doitype != NULL)
+		*doitype = ntohl(sab->doi);
 
 	/* check SITUATION */
 	if (check_situation(ntohl(sab->sit)) < 0)
 		goto bad;
+	if (sittype != NULL)
+		*sittype = ntohl(sab->sit);
 
 	pair = racoon_calloc(1, MAXPROPPAIRLEN * sizeof(*pair));
 	if (pair == NULL) {
@@ -1446,6 +1311,15 @@
 	return NULL;
 }
 
+struct prop_pair **
+get_proppair(sa, mode)
+	vchar_t *sa;
+	int mode;
+{
+	return get_proppair_and_doi_sit(sa, mode, NULL, NULL);
+}
+
+
 /*
  * check transform payload.
  * OUT:
@@ -1560,9 +1434,9 @@
  * NOTE: this function make spi value clear.
  */
 vchar_t *
-get_sabyproppair(pair, iph1)
+get_sabyproppair(doitype, sittype, pair)
+	u_int32_t doitype, sittype;
 	struct prop_pair *pair;
-	struct ph1handle *iph1;
 {
 	vchar_t *newsa;
 	int newtlen;
@@ -1588,8 +1462,8 @@
 	((struct isakmp_gen *)bp)->len = htons(newtlen);
 
 	/* update some of values in SA header */
-	((struct ipsecdoi_sa_b *)bp)->doi = htonl(iph1->rmconf->doitype);
-	((struct ipsecdoi_sa_b *)bp)->sit = htonl(iph1->rmconf->sittype);
+	((struct ipsecdoi_sa_b *)bp)->doi = htonl(doitype);
+	((struct ipsecdoi_sa_b *)bp)->sit = htonl(sittype);
 	bp += sizeof(struct ipsecdoi_sa_b);
 
 	/* create proposal payloads */
@@ -1824,6 +1698,96 @@
 	return ld;
 }
 
+/*
+ * parse responder-lifetime attributes from payload
+ */
+int
+ipsecdoi_parse_responder_lifetime(notify, lifetime_sec, lifetime_kb)
+	struct isakmp_pl_n *notify;
+	u_int32_t *lifetime_sec;
+	u_int32_t *lifetime_kb;
+{
+	struct isakmp_data *d;
+	int flag, type, tlen, ld_type = -1;
+	u_int16_t lorv;
+	u_int32_t value;
+
+	tlen = ntohs(notify->h.len) - sizeof(*notify) - notify->spi_size;
+        d = (struct isakmp_data *)((char *)(notify + 1) +
+		notify->spi_size);
+
+	while (tlen >= sizeof(struct isakmp_data)) {
+		type = ntohs(d->type) & ~ISAKMP_GEN_MASK;
+		flag = ntohs(d->type) & ISAKMP_GEN_MASK;
+		lorv = ntohs(d->lorv);
+
+		plog(LLV_DEBUG, LOCATION, NULL,
+			"type=%s, flag=0x%04x, lorv=%s\n",
+			s_ipsecdoi_attr(type), flag,
+			s_ipsecdoi_attr_v(type, lorv));
+
+		switch (type) {
+		case IPSECDOI_ATTR_SA_LD_TYPE:
+			if (! flag) {
+				plog(LLV_ERROR, LOCATION, NULL,
+					"must be TV when LD_TYPE.\n");
+				return -1;
+			}
+			ld_type = lorv;
+			break;
+		case IPSECDOI_ATTR_SA_LD:
+			if (flag)
+				value = lorv;
+			else if (lorv == 2)
+				value = ntohs(*(u_int16_t *)(d + 1));
+			else if (lorv == 4)
+				value = ntohl(*(u_int32_t *)(d + 1));
+			else {
+				plog(LLV_ERROR, LOCATION, NULL,
+					"payload length %d for lifetime "
+					"data length is unsupported.\n", lorv);
+				return -1;
+			}
+
+			switch (ld_type) {
+			case IPSECDOI_ATTR_SA_LD_TYPE_SEC:
+				if (lifetime_sec != NULL)
+					*lifetime_sec = value;
+				plog(LLV_INFO, LOCATION, NULL,
+					"received RESPONDER-LIFETIME: %d "
+					"seconds\n", value);
+				break;
+			case IPSECDOI_ATTR_SA_LD_TYPE_KB:
+				if (lifetime_kb != NULL)
+					*lifetime_kb = value;
+				plog(LLV_INFO, LOCATION, NULL,
+					"received RESPONDER-LIFETIME: %d "
+					"kbytes\n", value);
+				break;
+			default:
+				plog(LLV_ERROR, LOCATION, NULL,
+					"lifetime data received without "
+					"lifetime data type.\n");
+				return -1;
+			}
+			break;
+		}
+
+		if (flag) {
+			tlen -= sizeof(*d);
+			d = (struct isakmp_data *)((char *)d
+				+ sizeof(*d));
+		} else {
+			tlen -= (sizeof(*d) + lorv);
+			d = (struct isakmp_data *)((char *)d
+				+ sizeof(*d) + lorv);
+		}
+	}
+
+	return 0;
+}
+
+
 /*%%%*/
 /*
  * check DOI
@@ -2130,11 +2094,12 @@
 #ifdef ENABLE_HYBRID
 			case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I:
 			case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_I:
-#if 0 /* Clashes with OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB */
+#endif
+#if defined(ENABLE_HYBRID) || defined(HAVE_GSSAPI)
+				/* These two authentication method IDs overlap. */
 			case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_I:
+			/*case OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB:*/
 #endif
-#endif
-			case OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB:
 				break;
 			case OAKLEY_ATTR_AUTH_METHOD_DSSSIG:
 #ifdef ENABLE_HYBRID
@@ -2351,7 +2316,7 @@
  				if (proto_id == IPSECDOI_PROTO_IPSEC_AH) {
  					if (trns->t_id != IPSECDOI_AH_SHA256)
  						goto ahmismatch;
- 				}	
+ 				}
  				break;
  			case IPSECDOI_ATTR_AUTH_HMAC_SHA2_384:
  				if (proto_id == IPSECDOI_PROTO_IPSEC_AH) {
@@ -2638,7 +2603,8 @@
  * NOT INCLUDING isakmp general header of SA payload
  */
 vchar_t *
-ipsecdoi_setph1proposal(props)
+ipsecdoi_setph1proposal(rmconf, props)
+	struct remoteconf *rmconf;
 	struct isakmpsa *props;
 {
 	vchar_t *mysa;
@@ -2658,8 +2624,8 @@
 
 	/* create SA payload */
 	/* not including isakmp general header */
-	((struct ipsecdoi_sa_b *)mysa->v)->doi = htonl(props->rmconf->doitype);
-	((struct ipsecdoi_sa_b *)mysa->v)->sit = htonl(props->rmconf->sittype);
+	((struct ipsecdoi_sa_b *)mysa->v)->doi = htonl(rmconf->doitype);
+	((struct ipsecdoi_sa_b *)mysa->v)->sit = htonl(rmconf->sittype);
 
 	(void)setph1prop(props, mysa->v + sizeof(struct ipsecdoi_sa_b));
 
@@ -2767,7 +2733,7 @@
 						OAKLEY_ATTR_SA_LD_TYPE_SEC);
 			if (sa->lifetime > 0xffff) {
 				p = isakmp_set_attr_v(p, OAKLEY_ATTR_SA_LD,
-						(caddr_t)&lifetime, 
+						(caddr_t)&lifetime,
 						sizeof(lifetime));
 			} else {
 				p = isakmp_set_attr_l(p, OAKLEY_ATTR_SA_LD,
@@ -2778,7 +2744,7 @@
 
 	if (sa->lifebyte) {
 		u_int32_t lifebyte = htonl((u_int32_t)sa->lifebyte);
-		
+
 		attrlen += sizeof(struct isakmp_data)
 			+ sizeof(struct isakmp_data);
 		if (sa->lifebyte > 0xffff)
@@ -2810,11 +2776,8 @@
 	if (sa->authmethod) {
 		int authmethod;
 
-#ifdef ENABLE_HYBRID
-		authmethod = switch_authmethod(sa->authmethod);
-#else
-		authmethod = sa->authmethod;
-#endif
+		authmethod = isakmpsa_switch_authmethod(sa->authmethod);
+		authmethod &= 0xffff;
 		attrlen += sizeof(struct isakmp_data);
 		if (buf)
 			p = isakmp_set_attr_l(p, OAKLEY_ATTR_AUTH_METHOD, authmethod);
@@ -2896,7 +2859,7 @@
 					goto gssid_done;
 				}
 				odst = dst;
-				rv = iconv(cd, (__iconv_const char **)&src, 
+				rv = iconv(cd, (__iconv_const char **)&src,
 				    &srcleft, &dst, &dstleft);
 				if (rv != 0) {
 					if (rv == -1) {
@@ -2989,7 +2952,7 @@
 	np_t = NULL;
 
 	for (tr = pr->head; tr; tr = tr->next) {
-	
+
 		switch (pr->proto_id) {
 		case IPSECDOI_PROTO_IPSEC_ESP:
 			/*
@@ -3237,7 +3200,9 @@
 
 	for (; pp; pp = pp->next) {
 		for (pr = pp->head; pr; pr = pr->next) {
-			if (pr->encmode != IPSECDOI_ATTR_ENC_MODE_TRNS)
+			if (pr->encmode != IPSECDOI_ATTR_ENC_MODE_TRNS &&
+			    pr->encmode != IPSECDOI_ATTR_ENC_MODE_UDPTRNS_RFC &&
+			    pr->encmode != IPSECDOI_ATTR_ENC_MODE_UDPTRNS_DRAFT)
 				return 0;
 		}
 	}
@@ -3597,8 +3562,6 @@
 	struct ph1handle *iph1;
 {
 	struct ipsecdoi_id_b *id_b;
-	struct sockaddr *sa;
-	caddr_t sa1, sa2;
 
 	if (iph1->id_p == NULL) {
 		plog(LLV_ERROR, LOCATION, NULL,
@@ -3614,7 +3577,6 @@
 
 	id_b = (struct ipsecdoi_id_b *)iph1->id_p->v;
 
-#ifndef ANDROID_PATCHED
 	/* In main mode with pre-shared key, only address type can be used. */
 	if (iph1->etype == ISAKMP_ETYPE_IDENT &&
 	    iph1->approval->authmethod == OAKLEY_ATTR_AUTH_METHOD_PSKEY) {
@@ -3626,7 +3588,6 @@
 			return ISAKMP_NTYPE_INVALID_ID_INFORMATION;
 		}
 	}
-#endif
 
 	/* if proper type for phase 1 ? */
 	switch (id_b->type) {
@@ -3670,73 +3631,12 @@
 		}
 	}
 
-	/* compare with the ID if specified. */
-	if (genlist_next(iph1->rmconf->idvl_p, 0)) {
-		vchar_t *ident0 = NULL;
-		vchar_t ident;
-		struct idspec *id;
-		struct genlist_entry *gpb;
+	/* resolve remote configuration if not done yet */
+	if (resolveph1rmconf(iph1) < 0)
+		return ISAKMP_NTYPE_INVALID_ID_INFORMATION;
 
-		for (id = genlist_next (iph1->rmconf->idvl_p, &gpb); id; id = genlist_next (0, &gpb)) {
-			/* check the type of both IDs */
-			if (id->idtype != doi2idtype(id_b->type))
-				continue;  /* ID type mismatch */
-			if (id->id == 0)
-				goto matched;
-
-			/* compare defined ID with the ID sent by peer. */
-			if (ident0 != NULL)
-				vfree(ident0);
-			ident0 = getidval(id->idtype, id->id);
-
-			switch (id->idtype) {
-			case IDTYPE_ASN1DN:
-				ident.v = iph1->id_p->v + sizeof(*id_b);
-				ident.l = iph1->id_p->l - sizeof(*id_b);
-				if (eay_cmp_asn1dn(ident0, &ident) == 0)
-					goto matched;
-				break;
-			case IDTYPE_ADDRESS:
-				sa = (struct sockaddr *)ident0->v;
-				sa2 = (caddr_t)(id_b + 1);
-				switch (sa->sa_family) {
-				case AF_INET:
-					if (iph1->id_p->l - sizeof(*id_b) != sizeof(struct in_addr))
-						continue;  /* ID value mismatch */
-					sa1 = (caddr_t)&((struct sockaddr_in *)sa)->sin_addr;
-					if (memcmp(sa1, sa2, sizeof(struct in_addr)) == 0)
-						goto matched;
-					break;
-#ifdef INET6
-				case AF_INET6:
-					if (iph1->id_p->l - sizeof(*id_b) != sizeof(struct in6_addr))
-						continue;  /* ID value mismatch */
-					sa1 = (caddr_t)&((struct sockaddr_in6 *)sa)->sin6_addr;
-					if (memcmp(sa1, sa2, sizeof(struct in6_addr)) == 0)
-						goto matched;
-					break;
-#endif
-				default:
-					break;
-				}
-				break;
-			default:
-				if (memcmp(ident0->v, id_b + 1, ident0->l) == 0)
-					goto matched;
-				break;
-			}
-		}
-		if (ident0 != NULL) {
-			vfree(ident0);
-			ident0 = NULL;
-		}
-		plog(LLV_WARNING, LOCATION, NULL, "No ID match.\n");
-		if (iph1->rmconf->verify_identifier)
-			return ISAKMP_NTYPE_INVALID_ID_INFORMATION;
-matched: /* ID value match */
-		if (ident0 != NULL)
-			vfree(ident0);
-	}
+	if (iph1->rmconf == NULL)
+		return ISAKMP_NTYPE_INVALID_ID_INFORMATION;
 
 	return 0;
 }
@@ -3763,15 +3663,15 @@
 	switch (iph1->rmconf->idvtype) {
 	case IDTYPE_FQDN:
 		id_b.type = IPSECDOI_ID_FQDN;
-		ident = getidval(iph1->rmconf->idvtype, iph1->rmconf->idv);
+		ident = vdup(iph1->rmconf->idv);
 		break;
 	case IDTYPE_USERFQDN:
 		id_b.type = IPSECDOI_ID_USER_FQDN;
-		ident = getidval(iph1->rmconf->idvtype, iph1->rmconf->idv);
+		ident = vdup(iph1->rmconf->idv);
 		break;
 	case IDTYPE_KEYID:
 		id_b.type = IPSECDOI_ID_KEY_ID;
-		ident = getidval(iph1->rmconf->idvtype, iph1->rmconf->idv);
+		ident = vdup(iph1->rmconf->idv);
 		break;
 	case IDTYPE_ASN1DN:
 		id_b.type = IPSECDOI_ID_DER_ASN1_DN;
@@ -3784,7 +3684,7 @@
 					"failed to get own CERT.\n");
 				goto err;
 			}
-			ident = eay_get_x509asn1subjectname(&iph1->cert->cert);
+			ident = eay_get_x509asn1subjectname(iph1->cert);
 		}
 		break;
 	case IDTYPE_ADDRESS:
@@ -3829,7 +3729,7 @@
 		if (!ident) {
 			plog(LLV_ERROR, LOCATION, NULL,
 				"failed to get ID buffer.\n");
-			return 0;
+			return -1;
 		}
 		memcpy(ident->v, p, ident->l);
 	    }
@@ -3837,7 +3737,7 @@
 	if (!ident) {
 		plog(LLV_ERROR, LOCATION, NULL,
 			"failed to get ID buffer.\n");
-		return 0;
+		return -1;
 	}
 
 	ret = vmalloc(sizeof(id_b) + ident->l);
@@ -3865,21 +3765,6 @@
 	return -1;
 }
 
-static vchar_t *
-getidval(type, val)
-	int type;
-	vchar_t *val;
-{
-	vchar_t *new = NULL;
-
-	if (val)
-		new = vdup(val);
-	else if (lcconf->ident[type])
-		new = vdup(lcconf->ident[type]);
-
-	return new;
-}
-
 /* it's only called by cfparse.y. */
 int
 set_identifier(vpp, type, value)
@@ -3922,9 +3807,9 @@
 		memcpy(new->v, value->v, new->l);
 		break;
 	case IDTYPE_KEYID:
-		/* 
+		/*
 		 * If no qualifier is specified: IDQUAL_UNSPEC. It means
-		 * to use a file for backward compatibility sake. 
+		 * to use a file for backward compatibility sake.
 		 */
 		switch(qual) {
 		case IDQUAL_FILE:
@@ -3969,7 +3854,7 @@
 			return -1;
 		}
 		break;
-	
+
 	case IDTYPE_ADDRESS: {
 		struct sockaddr *sa;
 
@@ -4013,7 +3898,7 @@
 
 			xn = d2i_X509_NAME(NULL, (void *)&ptr, new->l);
 			bio = BIO_new(BIO_s_mem());
-			
+
 			X509_NAME_print_ex(bio, xn, 0, 0);
 			len = BIO_get_mem_data(bio, &ptr);
 			save = ptr[len];
@@ -4053,8 +3938,25 @@
 		return -1;
 	}
 
-	iph2->id = ipsecdoi_sockaddr2id((struct sockaddr *)&sp->spidx.src,
-					sp->spidx.prefs, sp->spidx.ul_proto);
+	if (!ipsecdoi_transportmode(iph2->proposal))
+		iph2->id = ipsecdoi_sockaddr2id((struct sockaddr *)&sp->spidx.src,
+				sp->spidx.prefs, sp->spidx.ul_proto);
+	else if (iph2->sa_src != NULL) {
+		/* He have a specific hint indicating that the transport
+		 * mode SA will be negotiated using addresses that differ
+		 * with the one from the SA. We need to indicate that to
+		 * our peer by setting the SA address as ID.
+		 * This is typically the case for the bootstrapping of the
+		 * transport mode SA protecting BU/BA for MIPv6 traffic
+		 *
+		 * --arno*/
+		iph2->id = ipsecdoi_sockaddr2id(iph2->sa_src,
+						IPSECDOI_PREFIX_HOST,
+						sp->spidx.ul_proto);
+	} else
+		iph2->id = ipsecdoi_sockaddr2id(iph2->src, IPSECDOI_PREFIX_HOST,
+						sp->spidx.ul_proto);
+
 	if (iph2->id == NULL) {
 		plog(LLV_ERROR, LOCATION, NULL,
 			"failed to get ID for %s\n",
@@ -4065,8 +3967,18 @@
 		s_ipsecdoi_ident(((struct ipsecdoi_id_b *)iph2->id->v)->type));
 
 	/* remote side */
-	iph2->id_p = ipsecdoi_sockaddr2id((struct sockaddr *)&sp->spidx.dst,
+	if (!ipsecdoi_transportmode(iph2->proposal))
+		iph2->id_p = ipsecdoi_sockaddr2id((struct sockaddr *)&sp->spidx.dst,
 				sp->spidx.prefd, sp->spidx.ul_proto);
+	else if (iph2->sa_dst != NULL) {
+		/* See comment above for local side. */
+		iph2->id_p = ipsecdoi_sockaddr2id(iph2->sa_dst,
+						  IPSECDOI_PREFIX_HOST,
+						  sp->spidx.ul_proto);
+	} else
+		iph2->id_p = ipsecdoi_sockaddr2id(iph2->dst, IPSECDOI_PREFIX_HOST,
+			sp->spidx.ul_proto);
+
 	if (iph2->id_p == NULL) {
 		plog(LLV_ERROR, LOCATION, NULL,
 			"failed to get ID for %s\n",
@@ -4103,7 +4015,7 @@
 	switch (saddr->sa_family) {
 	case AF_INET:
 		len1 = sizeof(struct in_addr);
-		if (prefixlen == (sizeof(struct in_addr) << 3)) {
+		if (prefixlen >= (sizeof(struct in_addr) << 3)) {
 			type = IPSECDOI_ID_IPV4_ADDR;
 			len2 = 0;
 		} else {
@@ -4116,7 +4028,7 @@
 #ifdef INET6
 	case AF_INET6:
 		len1 = sizeof(struct in6_addr);
-		if (prefixlen == (sizeof(struct in6_addr) << 3)) {
+		if (prefixlen >= (sizeof(struct in6_addr) << 3)) {
 			type = IPSECDOI_ID_IPV6_ADDR;
 			len2 = 0;
 		} else {
@@ -4161,7 +4073,7 @@
 
 	/* set prefix */
 	if (len2) {
-		u_char *p = (unsigned char *) new->v + 
+		u_char *p = (unsigned char *) new->v +
 			sizeof(struct ipsecdoi_id_b) + len1;
 		u_int bits = prefixlen;
 
@@ -4232,10 +4144,10 @@
 	port = ((struct sockaddr_in *)(laddr))->sin_port;
 	((struct ipsecdoi_id_b *)new->v)->port =
 		port == IPSEC_PORT_ANY ? 0 : port;
-	memcpy(new->v + sizeof(struct ipsecdoi_id_b), 
-	       (caddr_t)&((struct sockaddr_in *)(laddr))->sin_addr, 
+	memcpy(new->v + sizeof(struct ipsecdoi_id_b),
+	       (caddr_t)&((struct sockaddr_in *)(laddr))->sin_addr,
 	       len1);
-	memcpy(new->v + sizeof(struct ipsecdoi_id_b) + len1, 
+	memcpy(new->v + sizeof(struct ipsecdoi_id_b) + len1,
 	       (caddr_t)&((struct sockaddr_in *)haddr)->sin_addr,
 	       len2);
 	return new;
@@ -4254,9 +4166,14 @@
 	u_int8_t *prefixlen;
 	u_int16_t *ul_proto;
 {
-	struct ipsecdoi_id_b *id_b = (struct ipsecdoi_id_b *)buf->v;
+	struct ipsecdoi_id_b *id_b = NULL;
 	u_int plen = 0;
 
+	if (buf == NULL)
+		return ISAKMP_INTERNAL_ERROR;
+
+	id_b = (struct ipsecdoi_id_b *)buf->v;
+
 	/*
 	 * When a ID payload of subnet type with a IP address of full bit
 	 * masked, it has to be processed as host address.
@@ -4291,6 +4208,11 @@
 				: id_b->port);		/* see sockaddr2id() */
 		memcpy(&((struct sockaddr_in6 *)saddr)->sin6_addr,
 			buf->v + sizeof(*id_b), sizeof(struct in6_addr));
+		((struct sockaddr_in6 *)saddr)->sin6_scope_id =
+			(IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *)saddr)->sin6_addr)
+				? ((struct sockaddr_in6 *)id_b)->sin6_scope_id
+				: 0);
+
 		break;
 #endif
 	default:
@@ -4384,29 +4306,20 @@
 	char *dat;
 	static char buf[BUFLEN];
 	struct ipsecdoi_id_b *id_b = (struct ipsecdoi_id_b *)id->v;
-	struct sockaddr_storage saddr_storage;
-	struct sockaddr        *saddr;
-	struct sockaddr_in     *saddr_in;
-	struct sockaddr_in6    *saddr_in6;
+	union sockaddr_any saddr;
 	u_int plen = 0;
 
-	saddr     = (struct sockaddr *)&saddr_storage;
-	saddr_in  = (struct sockaddr_in *)&saddr_storage;
-	saddr_in6 = (struct sockaddr_in6 *)&saddr_storage;
-
-	
 	switch (id_b->type) {
 	case IPSECDOI_ID_IPV4_ADDR:
 	case IPSECDOI_ID_IPV4_ADDR_SUBNET:
 	case IPSECDOI_ID_IPV4_ADDR_RANGE:
 
 #ifndef __linux__
-		saddr->sa_len = sizeof(struct sockaddr_in);
+		saddr.sa.sa_len = sizeof(struct sockaddr_in);
 #endif
-		saddr->sa_family = AF_INET;
-
-		saddr_in->sin_port = IPSEC_PORT_ANY;
-		memcpy(&saddr_in->sin_addr,
+		saddr.sa.sa_family = AF_INET;
+		saddr.sin.sin_port = IPSEC_PORT_ANY;
+		memcpy(&saddr.sin.sin_addr,
 			id->v + sizeof(*id_b), sizeof(struct in_addr));
 		break;
 #ifdef INET6
@@ -4415,15 +4328,14 @@
 	case IPSECDOI_ID_IPV6_ADDR_RANGE:
 
 #ifndef __linux__
-		saddr->sa_len = sizeof(struct sockaddr_in6);
+		saddr.sa.sa_len = sizeof(struct sockaddr_in6);
 #endif
-		saddr->sa_family = AF_INET6;
-
-		saddr_in6->sin6_port = IPSEC_PORT_ANY;
-		memcpy(&saddr_in6->sin6_addr,
+		saddr.sa.sa_family = AF_INET6;
+		saddr.sin6.sin6_port = IPSEC_PORT_ANY;
+		memcpy(&saddr.sin6.sin6_addr,
 			id->v + sizeof(*id_b), sizeof(struct in6_addr));
-		saddr_in6->sin6_scope_id =
-			(IN6_IS_ADDR_LINKLOCAL(&saddr_in6->sin6_addr)
+		saddr.sin6.sin6_scope_id =
+			(IN6_IS_ADDR_LINKLOCAL(&saddr.sin6.sin6_addr)
 				? ((struct sockaddr_in6 *)id_b)->sin6_scope_id
 				: 0);
 		break;
@@ -4435,7 +4347,7 @@
 #ifdef INET6
 	case IPSECDOI_ID_IPV6_ADDR:
 #endif
-		len = snprintf( buf, BUFLEN, "%s", saddrwop2str(saddr));
+		len = snprintf( buf, BUFLEN, "%s", saddrwop2str(&saddr.sa));
 		break;
 
 	case IPSECDOI_ID_IPV4_ADDR_SUBNET:
@@ -4491,47 +4403,44 @@
 			plen += l;
 		}
 
-		len = snprintf( buf, BUFLEN, "%s/%i", saddrwop2str(saddr), plen);
+		len = snprintf( buf, BUFLEN, "%s/%i", saddrwop2str(&saddr.sa), plen);
 	    }
 		break;
 
 	case IPSECDOI_ID_IPV4_ADDR_RANGE:
 
-		len = snprintf( buf, BUFLEN, "%s-", saddrwop2str(saddr));
+		len = snprintf( buf, BUFLEN, "%s-", saddrwop2str(&saddr.sa));
 
 #ifndef __linux__
-		saddr->sa_len = sizeof(struct sockaddr_in);
+		saddr.sa.sa_len = sizeof(struct sockaddr_in);
 #endif
-		saddr->sa_family = AF_INET;
-		saddr_in->sin_port = IPSEC_PORT_ANY;
-		memcpy(&saddr_in->sin_addr,
+		saddr.sa.sa_family = AF_INET;
+		saddr.sin.sin_port = IPSEC_PORT_ANY;
+		memcpy(&saddr.sin.sin_addr,
 			id->v + sizeof(*id_b) + sizeof(struct in_addr),
 			sizeof(struct in_addr));
 
-		len += snprintf( buf + len, BUFLEN - len, "%s", saddrwop2str(saddr));
-
+		len += snprintf(buf + len, BUFLEN - len, "%s", saddrwop2str(&saddr.sa));
 		break;
 
 #ifdef INET6
 	case IPSECDOI_ID_IPV6_ADDR_RANGE:
-
-		len = snprintf( buf, BUFLEN, "%s-", saddrwop2str(saddr));
+		len = snprintf( buf, BUFLEN, "%s-", saddrwop2str(&saddr.sa));
 
 #ifndef __linux__
-		saddr->sa_len = sizeof(struct sockaddr_in6);
+		saddr.sa.sa_len = sizeof(struct sockaddr_in6);
 #endif
-		saddr->sa_family = AF_INET6;
-		saddr_in6->sin6_port = IPSEC_PORT_ANY;
-		memcpy(&saddr_in6->sin6_addr,
+		saddr.sa.sa_family = AF_INET6;
+		saddr.sin6.sin6_port = IPSEC_PORT_ANY;
+		memcpy(&saddr.sin6.sin6_addr,
 			id->v + sizeof(*id_b) + sizeof(struct in6_addr),
 			sizeof(struct in6_addr));
-		saddr_in6->sin6_scope_id =
-			(IN6_IS_ADDR_LINKLOCAL(&saddr_in6->sin6_addr)
+		saddr.sin6.sin6_scope_id =
+			(IN6_IS_ADDR_LINKLOCAL(&saddr.sin6.sin6_addr)
 				? ((struct sockaddr_in6 *)id_b)->sin6_scope_id
 				: 0);
 
-		len += snprintf( buf + len, BUFLEN - len, "%s", saddrwop2str(saddr));
-
+		len += snprintf(buf + len, BUFLEN - len, "%s", saddrwop2str(&saddr.sa));
 		break;
 #endif
 
@@ -4836,24 +4745,12 @@
 	return -1;
 }
 
-#ifdef HAVE_GSSAPI
-struct isakmpsa *
-fixup_initiator_sa(match, received)
-	struct isakmpsa *match, *received;
-{
-	if (received->gssid != NULL)
-		match->gssid = vdup(received->gssid);
-
-	return match;
-}
-#endif
-
 static int rm_idtype2doi[] = {
 	255,				/* IDTYPE_UNDEFINED, 0 */
 	IPSECDOI_ID_FQDN,		/* IDTYPE_FQDN, 1 */
 	IPSECDOI_ID_USER_FQDN,		/* IDTYPE_USERFQDN, 2 */
 	IPSECDOI_ID_KEY_ID,		/* IDTYPE_KEYID, 3 */
-	255,    /*			   IDTYPE_ADDRESS, 4 
+	255,    /*			   IDTYPE_ADDRESS, 4
 		 * it expands into 4 types by another function. */
 	IPSECDOI_ID_DER_ASN1_DN,	/* IDTYPE_ASN1DN, 5 */
 };
@@ -4898,39 +4795,3 @@
 	}
 	/*NOTREACHED*/
 }
-
-#ifdef ENABLE_HYBRID
-static int
-switch_authmethod(authmethod)
-	int authmethod;
-{
-	switch(authmethod) {
-	case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_R:
-		authmethod = OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I;
-		break;
-	case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_R:
-		authmethod = OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_I;
-		break;
-	case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_R:
-		authmethod = OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_I;
-		break;
-	case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_R:
-		authmethod = OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_I;
-		break;
-	/* Those are not implemented */
-	case OAKLEY_ATTR_AUTH_METHOD_XAUTH_DSSSIG_R:
-		authmethod = OAKLEY_ATTR_AUTH_METHOD_XAUTH_DSSSIG_I;
-		break;
-	case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAENC_R:
-		authmethod = OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAENC_I;
-		break;
-	case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAREV_R:
-		authmethod = OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAREV_I;
-		break;
-	default:
-		break;
-	}
-
-	return authmethod;
-}
-#endif
diff --git a/src/racoon/ipsec_doi.h b/src/racoon/ipsec_doi.h
index 21dd93d..19a861a 100644
--- a/src/racoon/ipsec_doi.h
+++ b/src/racoon/ipsec_doi.h
@@ -1,4 +1,4 @@
-/*	$NetBSD: ipsec_doi.h,v 1.9 2006/12/09 05:52:57 manu Exp $	*/
+/*	$NetBSD: ipsec_doi.h,v 1.12 2009/03/12 10:57:26 tteras Exp $	*/
 
 /* Id: ipsec_doi.h,v 1.15 2006/08/11 16:06:30 vanhu Exp */
 
@@ -34,6 +34,8 @@
 #ifndef _IPSEC_DOI_H
 #define _IPSEC_DOI_H
 
+#include "isakmp.h"
+
 /* refered to RFC2407 */
 
 #define IPSEC_DOI 1
@@ -197,6 +199,12 @@
 #define IPSECDOI_TYPE_PH1	0
 #define IPSECDOI_TYPE_PH2	1
 
+/*
+ * Prefix that will make ipsecdoi_sockaddr2id() generate address type
+ * identities without knowning the exact length of address.
+ */
+#define IPSECDOI_PREFIX_HOST	0xff
+
 struct isakmpsa;
 struct ipsecdoi_pl_sa;
 struct saprop;
@@ -209,7 +217,11 @@
 extern int ipsecdoi_checkph2proposal __P((struct ph2handle *));
 
 extern struct prop_pair **get_proppair __P((vchar_t *, int));
+#ifdef ANDROID_PATCHED
 extern vchar_t *get_sabyproppair __P((struct prop_pair *, struct ph1handle *));
+#else
+extern vchar_t *get_sabyproppair __P((u_int32_t, u_int32_t, struct prop_pair *));
+#endif
 extern int ipsecdoi_updatespi __P((struct ph2handle *iph2));
 extern vchar_t *get_sabysaprop __P((struct saprop *, vchar_t *));
 extern int ipsecdoi_chkcmpids( const vchar_t *, const vchar_t *, int );
@@ -225,7 +237,8 @@
 extern vchar_t *ipsecdoi_sockrange2id __P((	struct sockaddr *,
 	struct sockaddr *, u_int));
 
-extern vchar_t *ipsecdoi_setph1proposal __P((struct isakmpsa *));
+extern vchar_t *ipsecdoi_setph1proposal __P((struct remoteconf *,
+					     struct isakmpsa *));
 extern int ipsecdoi_setph2proposal __P((struct ph2handle *));
 extern int ipsecdoi_transportmode __P((struct saprop *));
 extern int ipsecdoi_get_defaultlifetime __P((void));
@@ -239,5 +252,8 @@
 extern int idtype2doi __P((int));
 extern int doi2idtype __P((int));
 
+extern int ipsecdoi_parse_responder_lifetime __P((struct isakmp_pl_n *notify,
+	u_int32_t *lifetime_sec, u_int32_t *liftime_kb));
+
 
 #endif /* _IPSEC_DOI_H */
diff --git a/src/racoon/isakmp.c b/src/racoon/isakmp.c
index 12eb5a0..048ca71 100644
--- a/src/racoon/isakmp.c
+++ b/src/racoon/isakmp.c
@@ -1,11 +1,11 @@
-/*	$NetBSD: isakmp.c,v 1.20.6.13 2008/09/25 09:34:39 vanhu Exp $	*/
+/*	$NetBSD: isakmp.c,v 1.71 2011/03/15 13:20:14 vanhu Exp $	*/
 
 /* Id: isakmp.c,v 1.74 2006/05/07 21:32:59 manubsd Exp */
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
  * All rights reserved.
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
@@ -17,7 +17,7 @@
  * 3. Neither the name of the project nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
- * 
+ *
  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@@ -72,6 +72,7 @@
 #include "plog.h"
 #include "sockmisc.h"
 #include "schedule.h"
+#include "session.h"
 #include "debug.h"
 
 #include "remoteconf.h"
@@ -88,6 +89,9 @@
 #include "pfkey.h"
 #include "crypto_openssl.h"
 #include "policy.h"
+#include "algorithm.h"
+#include "proposal.h"
+#include "sainfo.h"
 #include "isakmp_ident.h"
 #include "isakmp_agg.h"
 #include "isakmp_base.h"
@@ -116,9 +120,6 @@
 #  ifndef SOL_UDP
 #   define SOL_UDP 17
 #  endif
-#ifdef ANDROID_CHANGES
-#define __linux
-#endif
 # endif /* __linux__ */
 # if defined(__NetBSD__) || defined(__FreeBSD__) ||	\
   (defined(__APPLE__) && defined(__MACH__))
@@ -137,34 +138,34 @@
 static int (*ph1exchange[][2][PHASE1ST_MAX])
 	__P((struct ph1handle *, vchar_t *)) = {
  /* error */
- { {}, {}, },
+ { { 0 }, { 0 }, },
  /* Identity Protection exchange */
  {
   { nostate1, ident_i1send, nostate1, ident_i2recv, ident_i2send,
-    ident_i3recv, ident_i3send, ident_i4recv, ident_i4send, nostate1, },
+    ident_i3recv, ident_i3send, ident_i4recv, ident_i4send, nostate1, nostate1,},
   { nostate1, ident_r1recv, ident_r1send, ident_r2recv, ident_r2send,
-    ident_r3recv, ident_r3send, nostate1, nostate1, nostate1, },
+    ident_r3recv, ident_r3send, nostate1, nostate1, nostate1, nostate1, },
  },
  /* Aggressive exchange */
  {
   { nostate1, agg_i1send, nostate1, agg_i2recv, agg_i2send,
-    nostate1, nostate1, nostate1, nostate1, nostate1, },
+    nostate1, nostate1, nostate1, nostate1, nostate1, nostate1, },
   { nostate1, agg_r1recv, agg_r1send, agg_r2recv, agg_r2send,
-    nostate1, nostate1, nostate1, nostate1, nostate1, },
+    nostate1, nostate1, nostate1, nostate1, nostate1, nostate1, },
  },
  /* Base exchange */
  {
   { nostate1, base_i1send, nostate1, base_i2recv, base_i2send,
-    base_i3recv, base_i3send, nostate1, nostate1, nostate1, },
+    base_i3recv, base_i3send, nostate1, nostate1, nostate1, nostate1, },
   { nostate1, base_r1recv, base_r1send, base_r2recv, base_r2send,
-    nostate1, nostate1, nostate1, nostate1, nostate1, },
+    nostate1, nostate1, nostate1, nostate1, nostate1, nostate1, },
  },
 };
 
 static int (*ph2exchange[][2][PHASE2ST_MAX])
 	__P((struct ph2handle *, vchar_t *)) = {
  /* error */
- { {}, {}, },
+ { { 0 }, { 0 }, },
  /* Quick mode for IKE */
  {
   { nostate2, nostate2, quick_i1prep, nostate2, quick_i1send,
@@ -175,7 +176,7 @@
 };
 
 static u_char r_ck0[] = { 0,0,0,0,0,0,0,0 }; /* used to verify the r_ck. */
- 
+
 static int isakmp_main __P((vchar_t *, struct sockaddr *, struct sockaddr *));
 static int ph1_main __P((struct ph1handle *, vchar_t *));
 static int quick_main __P((struct ph2handle *, vchar_t *));
@@ -185,29 +186,35 @@
 static int isakmp_ph2begin_r __P((struct ph1handle *, vchar_t *));
 static int etypesw1 __P((int));
 static int etypesw2 __P((int));
+static int isakmp_ph1resend __P((struct ph1handle *));
+static int isakmp_ph2resend __P((struct ph2handle *));
+
 #ifdef ENABLE_FRAG
-static int frag_handler(struct ph1handle *, 
+static int frag_handler(struct ph1handle *,
     vchar_t *, struct sockaddr *, struct sockaddr *);
 #endif
 
 /*
  * isakmp packet handler
  */
-int
-isakmp_handler(so_isakmp)
+static int
+isakmp_handler(ctx, so_isakmp)
+        void *ctx;
 	int so_isakmp;
 {
 	struct isakmp isakmp;
 	union {
 		char		buf[sizeof (isakmp) + 4];
 		u_int32_t	non_esp[2];
-		char		lbuf[sizeof(struct udphdr) + 
+		struct		{
+				     struct udphdr udp;
 #ifdef __linux
-				     sizeof(struct iphdr) + 
+				     struct iphdr ip;
 #else
-				     sizeof(struct ip) + 
+				     struct ip ip;
 #endif
-				     sizeof(isakmp) + 4];
+				     char buf[sizeof(isakmp) + 4];
+				} lbuf;
 	} x;
 	struct sockaddr_storage remote;
 	struct sockaddr_storage local;
@@ -243,34 +250,25 @@
 
 	/* Lucent IKE in UDP encapsulation */
 	{
-		struct udphdr *udp;
 #ifdef __linux__
-		struct iphdr *ip;
-
-		udp = (struct udphdr *)&x.lbuf[0];
-		if (ntohs(udp->dest) == 501) {
-			ip = (struct iphdr *)(x.lbuf + sizeof(*udp));
-			extralen += sizeof(*udp) + ip->ihl;
+		if (ntohs(x.lbuf.udp.dest) == 501) {
+			extralen += sizeof(x.lbuf.udp) + x.lbuf.ip.ihl;
 		}
 #else
-		struct ip *ip;
-
-		udp = (struct udphdr *)&x.lbuf[0];
-		if (ntohs(udp->uh_dport) == 501) {
-			ip = (struct ip *)(x.lbuf + sizeof(*udp));
-			extralen += sizeof(*udp) + ip->ip_hl;
+		if (ntohs(x.lbuf.udp.uh_dport) == 501) {
+			extralen += sizeof(x.lbuf.udp) + x.lbuf.ip.ip_hl;
 		}
 #endif
-	}	
+	}
 
 #ifdef ENABLE_NATT
-	/* we don't know about portchange yet, 
+	/* we don't know about portchange yet,
 	   look for non-esp marker instead */
 	if (x.non_esp[0] == 0 && x.non_esp[1] != 0)
 		extralen = NON_ESP_MARKER_LEN;
 #endif
 
-	/* now we know if there is an extra non-esp 
+	/* now we know if there is an extra non-esp
 	   marker at the beginning or not */
 	memcpy ((char *)&isakmp, x.buf + extralen, sizeof (isakmp));
 
@@ -311,7 +309,7 @@
 		if ((len = recvfrom(so_isakmp, (char *)&isakmp, sizeof(isakmp),
 			    0, (struct sockaddr *)&remote, &remote_len)) < 0) {
 			plog(LLV_ERROR, LOCATION, NULL,
-				"failed to receive isakmp packet: %s\n", 
+				"failed to receive isakmp packet: %s\n",
 				strerror (errno));
 		}
 		goto end;
@@ -334,11 +332,11 @@
 			(len - extralen));
 		goto end;
 	}
-	
+
 	memcpy (buf->v, tmpbuf->v + extralen, buf->l);
 
 	len -= extralen;
-	
+
 	if (len != buf->l) {
 		plog(LLV_ERROR, LOCATION, (struct sockaddr *)&remote,
 			"received invalid length (%d != %zu), why ?\n",
@@ -349,7 +347,7 @@
 	plog(LLV_DEBUG, LOCATION, NULL, "===\n");
 	plog(LLV_DEBUG, LOCATION, NULL,
 		"%d bytes message received %s\n",
-		len, saddr2str_fromto("from %s to %s", 
+		len, saddr2str_fromto("from %s to %s",
 			(struct sockaddr *)&remote,
 			(struct sockaddr *)&local));
 	plogdump(LLV_DEBUG, buf->v, buf->l);
@@ -386,8 +384,7 @@
 		vfree(tmpbuf);
 	if (buf != NULL)
 		vfree(buf);
-
-	return(error);
+	return error;
 }
 
 /*
@@ -471,8 +468,8 @@
 		/* Floating ports for NAT-T */
 		if (NATT_AVAILABLE(iph1) &&
 		    ! (iph1->natt_flags & NAT_PORTS_CHANGED) &&
-		    ((cmpsaddrstrict(iph1->remote, remote) != 0) ||
-		    (cmpsaddrstrict(iph1->local, local) != 0)))
+		    ((cmpsaddr(iph1->remote, remote) != CMPSADDR_MATCH) ||
+		     (cmpsaddr(iph1->local, local) != CMPSADDR_MATCH)))
 		{
 			/* prevent memory leak */
 			racoon_free(iph1->remote);
@@ -499,12 +496,12 @@
 			}
 
 			/* set the flag to prevent further port floating
-			   (FIXME: should we allow it? E.g. when the NAT gw 
+			   (FIXME: should we allow it? E.g. when the NAT gw
 			    is rebooted?) */
 			iph1->natt_flags |= NAT_PORTS_CHANGED | NAT_ADD_NON_ESP_MARKER;
-			
+
 			/* print some neat info */
-			plog (LLV_INFO, LOCATION, NULL, 
+			plog (LLV_INFO, LOCATION, NULL,
 			      "NAT-T: ports changed to: %s\n",
 			      saddr2str_fromto ("%s<->%s", iph1->remote, iph1->local));
 
@@ -513,7 +510,7 @@
 #endif
 
 		/* must be same addresses in one stream of a phase at least. */
-		if (cmpsaddrstrict(iph1->remote, remote) != 0) {
+		if (cmpsaddr(iph1->remote, remote) != CMPSADDR_MATCH) {
 			char *saddr_db, *saddr_act;
 
 			saddr_db = racoon_strdup(saddr2str(iph1->remote));
@@ -639,7 +636,7 @@
 					"exchange received.\n");
 				return -1;
 			}
-			if (cmpsaddrstrict(iph1->remote, remote) != 0) {
+			if (cmpsaddr(iph1->remote, remote) != CMPSADDR_MATCH) {
 				plog(LLV_WARNING, LOCATION, remote,
 					"remote address mismatched. "
 					"db=%s\n",
@@ -671,7 +668,7 @@
 			return -1;
 		}
 #ifdef ENABLE_HYBRID
-		/* Reinit the IVM if it's still there */		
+		/* Reinit the IVM if it's still there */
 		if (iph1->mode_cfg && iph1->mode_cfg->ivm) {
 			oakley_delivm(iph1->mode_cfg->ivm);
 			iph1->mode_cfg->ivm = NULL;
@@ -683,7 +680,8 @@
 #endif
 
 		/* check status of phase 1 whether negotiated or not. */
-		if (iph1->status != PHASE1ST_ESTABLISHED) {
+		if (iph1->status != PHASE1ST_ESTABLISHED &&
+		    iph1->status != PHASE1ST_DYING) {
 			plog(LLV_ERROR, LOCATION, remote,
 				"can't start the quick mode, "
 				"there is no valid ISAKMP-SA, %s\n",
@@ -715,7 +713,6 @@
 		if (quick_main(iph2, msg) < 0) {
 			plog(LLV_ERROR, LOCATION, iph1->remote,
 				"phase2 negotiation failed.\n");
-			unbindph12(iph2);
 			remph2(iph2);
 			delph2(iph2);
 			return -1;
@@ -756,7 +753,7 @@
 
 		isakmp_cfg_r(iph1, msg);
 		break;
-#endif	 
+#endif
 
 	case ISAKMP_ETYPE_NONE:
 	default:
@@ -783,7 +780,7 @@
 #endif
 
 	/* ignore a packet */
-	if (iph1->status == PHASE1ST_ESTABLISHED)
+	if (iph1->status >= PHASE1ST_ESTABLISHED)
 		return 0;
 
 #ifdef ENABLE_STATS
@@ -813,7 +810,8 @@
 
 		if (iph1->side == RESPONDER && iph1->status == PHASE1ST_START) {
 			plog(LLV_ERROR, LOCATION, iph1->remote,
-				"failed to pre-process packet.\n");
+				"failed to pre-process ph1 packet (side: %d, status %d).\n",
+				iph1->side, iph1->status);
 			return -1;
 		} else {
 			/* ignore the error and keep phase 1 handler */
@@ -825,7 +823,7 @@
 	/* free resend buffer */
 	if (iph1->sendbuf == NULL) {
 		plog(LLV_ERROR, LOCATION, NULL,
-			"no buffer found as sendbuf\n"); 
+			"no buffer found as sendbuf\n");
 		return -1;
 	}
 #endif
@@ -833,7 +831,7 @@
 	VPTRINIT(iph1->sendbuf);
 
 	/* turn off schedule */
-	SCHED_KILL(iph1->scr);
+	sched_cancel(&iph1->scr);
 
 	/* send */
 	plog(LLV_DEBUG, LOCATION, NULL, "===\n");
@@ -841,7 +839,8 @@
 			[iph1->side]
 			[iph1->status])(iph1, msg) != 0) {
 		plog(LLV_ERROR, LOCATION, iph1->remote,
-			"failed to process packet.\n");
+			"failed to process ph1 packet (side: %d, status: %d).\n",
+			iph1->side, iph1->status);
 		return -1;
 	}
 
@@ -863,12 +862,23 @@
 		/* save created date. */
 		(void)time(&iph1->created);
 
+		/* migrate ph2s from dying ph1s */
+		migrate_dying_ph12(iph1);
+
 		/* add to the schedule to expire, and seve back pointer. */
-		iph1->sce = sched_new(iph1->approval->lifetime,
-		    isakmp_ph1expire_stub, iph1);
+		if (ph1_rekey_enabled(iph1)) {
+			sched_schedule(&iph1->sce,
+				       iph1->approval->lifetime *
+				       PFKEY_SOFT_LIFETIME_RATE / 100,
+				       isakmp_ph1dying_stub);
+		} else {
+			sched_schedule(&iph1->sce, iph1->approval->lifetime,
+				       isakmp_ph1expire_stub);
+		}
+
 #ifdef ENABLE_HYBRID
 		if (iph1->mode_cfg->flags & ISAKMP_CFG_VENDORID_XAUTH) {
-			switch(AUTHMETHOD(iph1)) {
+			switch (iph1->approval->authmethod) {
 			case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_R:
 			case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_R:
 			case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_R:
@@ -905,18 +915,20 @@
 				/* ignore */
 			}
 		}
+		if (iph1->initial_contact_received)
+			isakmp_info_recv_initialcontact(iph1, NULL);
 
 		log_ph1established(iph1);
 		plog(LLV_DEBUG, LOCATION, NULL, "===\n");
 
-		/* 
+		/*
 		 * SA up shell script hook: do it now,except if
 		 * ISAKMP mode config was requested. In the later
 		 * case it is done when we receive the configuration.
 		 */
 		if ((iph1->status == PHASE1ST_ESTABLISHED) &&
-		    !iph1->rmconf->mode_cfg) { 
-			switch (AUTHMETHOD(iph1)) {
+		    !iph1->rmconf->mode_cfg) {
+			switch (iph1->approval->authmethod) {
 #ifdef ENABLE_HYBRID
 			case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_R:
 			case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_R:
@@ -974,7 +986,8 @@
 			    [iph2->status])(iph2, msg);
 	if (error != 0) {
 		plog(LLV_ERROR, LOCATION, iph2->ph1->remote,
-			"failed to pre-process packet.\n");
+			"failed to pre-process ph2 packet (side: %d, status %d).\n",
+			iph2->side, iph2->status);
 		if (error == ISAKMP_INTERNAL_ERROR)
 			return 0;
 		isakmp_info_send_n1(iph2->ph1, error, NULL);
@@ -988,13 +1001,13 @@
 	/* free resend buffer */
 	if (iph2->sendbuf == NULL) {
 		plog(LLV_ERROR, LOCATION, NULL,
-			"no buffer found as sendbuf\n"); 
+			"no buffer found as sendbuf\n");
 		return -1;
 	}
 	VPTRINIT(iph2->sendbuf);
 
 	/* turn off schedule */
-	SCHED_KILL(iph2->scr);
+	sched_cancel(&iph2->scr);
 
 	/* send */
 	plog(LLV_DEBUG, LOCATION, NULL, "===\n");
@@ -1002,7 +1015,8 @@
 			[iph2->side]
 			[iph2->status])(iph2, msg) != 0) {
 		plog(LLV_ERROR, LOCATION, iph2->ph1->remote,
-			"failed to process packet.\n");
+			"failed to process ph2 packet (side: %d, status: %d).\n",
+			iph2->side, iph2->status);
 		return -1;
 	}
 
@@ -1018,7 +1032,7 @@
 }
 
 /* new negotiation of phase 1 for initiator */
-int
+struct ph1handle *
 isakmp_ph1begin_i(rmconf, remote, local)
 	struct remoteconf *rmconf;
 	struct sockaddr *remote, *local;
@@ -1031,7 +1045,7 @@
 	/* get new entry to isakmp status table. */
 	iph1 = newph1();
 	if (iph1 == NULL)
-		return -1;
+		return NULL;
 
 	iph1->status = PHASE1ST_START;
 	iph1->rmconf = rmconf;
@@ -1046,7 +1060,7 @@
 #ifdef ENABLE_HYBRID
 	if ((iph1->mode_cfg = isakmp_cfg_mkstate()) == NULL) {
 		delph1(iph1);
-		return -1;
+		return NULL;
 	}
 #endif
 #ifdef ENABLE_FRAG
@@ -1062,7 +1076,7 @@
 	/* XXX copy remote address */
 	if (copy_ph1addresses(iph1, rmconf, remote, local) < 0) {
 		delph1(iph1);
-		return -1;
+		return NULL;
 	}
 
 	(void)insph1(iph1);
@@ -1098,7 +1112,7 @@
 		remph1(iph1);
 		delph1(iph1);
 
-		return -1;
+		return NULL;
 	}
 
 #ifdef ENABLE_STATS
@@ -1109,7 +1123,7 @@
 		timedelta(&start, &end));
 #endif
 
-	return 0;
+	return iph1;
 }
 
 /* new negotiation of phase 1 for responder */
@@ -1120,27 +1134,19 @@
 	u_int8_t etype;
 {
 	struct isakmp *isakmp = (struct isakmp *)msg->v;
-	struct remoteconf *rmconf;
 	struct ph1handle *iph1;
-	struct etypes *etypeok;
+	struct rmconfselector rmsel;
 #ifdef ENABLE_STATS
 	struct timeval start, end;
 #endif
 
-	/* look for my configuration */
-	rmconf = getrmconf(remote);
-	if (rmconf == NULL) {
+	/* check if this etype is allowed */
+	memset(&rmsel, 0, sizeof(rmsel));
+	rmsel.remote = remote;
+	if (enumrmconf(&rmsel, check_etypeok, (void *) (intptr_t) etype) == 0) {
 		plog(LLV_ERROR, LOCATION, remote,
-			"couldn't find "
-			"configuration.\n");
-		return -1;
-	}
-
-	/* check to be acceptable exchange type */
-	etypeok = check_etypeok(rmconf, etype);
-	if (etypeok == NULL) {
-		plog(LLV_ERROR, LOCATION, remote,
-			"not acceptable %s mode\n", s_isakmp_etype(etype));
+		     "exchange %s not allowed in any applicable rmconf.\n",
+		     s_isakmp_etype(etype));
 		return -1;
 	}
 
@@ -1151,10 +1157,9 @@
 
 	memcpy(&iph1->index.i_ck, &isakmp->i_ck, sizeof(iph1->index.i_ck));
 	iph1->status = PHASE1ST_START;
-	iph1->rmconf = rmconf;
 	iph1->flags = 0;
 	iph1->side = RESPONDER;
-	iph1->etype = etypeok->type;
+	iph1->etype = etype;
 	iph1->version = isakmp->v;
 	iph1->msgid = 0;
 #ifdef HAVE_GSSAPI
@@ -1181,8 +1186,9 @@
 		iph1->natt_flags |= (NAT_PORTS_CHANGED);
 #endif
 
-	/* copy remote address */
-	if (copy_ph1addresses(iph1, rmconf, remote, local) < 0) {
+	/* copy remote address; remote and local always contain
+	 * port numbers so rmconf is not needed */
+	if (copy_ph1addresses(iph1, NULL, remote, local) < 0) {
 		delph1(iph1);
 		return -1;
 	}
@@ -1218,7 +1224,8 @@
 			[iph1->side]
 			[iph1->status])(iph1, msg) < 0) {
 		plog(LLV_ERROR, LOCATION, remote,
-			"failed to process packet.\n");
+			"failed to process ph1 packet (side: %d, status: %d).\n",
+			iph1->side, iph1->status);
 		remph1(iph1);
 		delph1(iph1);
 		return -1;
@@ -1260,6 +1267,12 @@
 	}
 #endif
 
+	/* fixup ph2 ports for this ph1 */
+	if (extract_port(iph2->src) == 0)
+		set_port(iph2->src, extract_port(iph1->local));
+	if (extract_port(iph2->dst) == 0)
+		set_port(iph2->dst, extract_port(iph1->remote));
+
 	/* found ISAKMP-SA. */
 	plog(LLV_DEBUG, LOCATION, NULL, "===\n");
 	plog(LLV_DEBUG, LOCATION, NULL, "begin QUICK mode.\n");
@@ -1277,14 +1290,13 @@
 #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)]
 			 [iph2->side]
 			 [iph2->status])(iph2, NULL) < 0) {
-		unbindph12(iph2);
 		/* release ipsecsa handler due to internal error. */
 		remph2(iph2);
 		return -1;
@@ -1319,7 +1331,6 @@
 		return -1;
 	}
 
-	iph2->ph1 = iph1;
 	iph2->side = RESPONDER;
 	iph2->status = PHASE2ST_START;
 	iph2->flags = isakmp->flags;
@@ -1340,15 +1351,6 @@
 		delph2(iph2);
 		return -1;
 	}
-#if (!defined(ENABLE_NATT)) || (defined(BROKEN_NATT))
-	if (set_port(iph2->dst, 0) == NULL ||
-	    set_port(iph2->src, 0) == NULL) {
-		plog(LLV_ERROR, LOCATION, NULL,
-		     "invalid family: %d\n", iph2->dst->sa_family);
-		delph2(iph2);
-		return -1;
-	}
-#endif
 
 	/* add new entry to isakmp status table */
 	insph2(iph2);
@@ -1376,14 +1378,14 @@
 	                   [iph2->status])(iph2, msg);
 	if (error != 0) {
 		plog(LLV_ERROR, LOCATION, iph1->remote,
-			"failed to pre-process packet.\n");
+			"failed to pre-process ph2 packet (side: %d, status: %d).\n",
+			iph2->side, iph2->status);
 		if (error != ISAKMP_INTERNAL_ERROR)
 			isakmp_info_send_n1(iph2->ph1, error, NULL);
 		/*
 		 * release handler because it's wrong that ph2handle is kept
 		 * after failed to check message for responder's.
 		 */
-		unbindph12(iph2);
 		remph2(iph2);
 		delph2(iph2);
 		return -1;
@@ -1395,7 +1397,8 @@
 			[iph2->side]
 			[iph2->status])(iph2, msg) < 0) {
 		plog(LLV_ERROR, LOCATION, iph2->ph1->remote,
-			"failed to process packet.\n");
+			"failed to process ph2 packet (side: %d, status: %d).\n",
+			iph2->side, iph2->status);
 		/* don't release handler */
 		return -1;
 	}
@@ -1526,14 +1529,7 @@
 	initctdtree();
 	init_recvdpkt();
 
-	if (isakmp_open() < 0)
-		goto err;
-
-	return(0);
-
-err:
-	isakmp_close();
-	return(-1);
+	return 0;
 }
 
 /*
@@ -1572,211 +1568,172 @@
 
 /* open ISAKMP sockets. */
 int
-isakmp_open()
+isakmp_open(struct sockaddr *addr, int udp_encap)
 {
 	const int yes = 1;
-	int ifnum = 0, encap_ifnum = 0;
+	int ifnum = 0, encap_ifnum = 0, fd;
+	struct sockaddr_in *sin = (struct sockaddr_in *) addr;
 #ifdef INET6
+	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) addr;
 	int pktinfo;
 #endif
-	struct myaddrs *p;
-
-	for (p = lcconf->myaddrs; p; p = p->next) {
-		if (!p->addr)
-			continue;
-
-		/* warn if wildcard address - should we forbid this? */
-		switch (p->addr->sa_family) {
-		case AF_INET:
-			if (((struct sockaddr_in *)p->addr)->sin_addr.s_addr == 0)
-				plog(LLV_WARNING, LOCATION, NULL,
-					"listening to wildcard address,"
-					"broadcast IKE packet may kill you\n");
-			break;
-#ifdef INET6
-		case AF_INET6:
-			if (IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)p->addr)->sin6_addr))
-				plog(LLV_WARNING, LOCATION, NULL,
-					"listening to wildcard address, "
-					"broadcast IKE packet may kill you\n");
-			break;
-#endif
-		default:
-			plog(LLV_ERROR, LOCATION, NULL,
-				"unsupported address family %d\n",
-				lcconf->default_af);
-			goto err_and_next;
-		}
-
-#ifdef INET6
-		if (p->addr->sa_family == AF_INET6 &&
-		    IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6 *)
-					    p->addr)->sin6_addr))
-		{
-			plog(LLV_DEBUG, LOCATION, NULL, 
-				"Ignoring multicast address %s\n",
-				saddr2str(p->addr));
-				racoon_free(p->addr);
-				p->addr = NULL;
-			continue;
-		}
-#endif
-
-		if ((p->sock = socket(p->addr->sa_family, SOCK_DGRAM, 0)) < 0) {
-			plog(LLV_ERROR, LOCATION, NULL,
-				"socket (%s)\n", strerror(errno));
-			goto err_and_next;
-		}
-
-		if (fcntl(p->sock, F_SETFL, O_NONBLOCK) == -1)
-			plog(LLV_WARNING, LOCATION, NULL,
-				"failed to put socket in non-blocking mode\n");
-
-		/* receive my interface address on inbound packets. */
-		switch (p->addr->sa_family) {
-		case AF_INET:
-			if (setsockopt(p->sock, IPPROTO_IP,
-#ifdef __linux__
-				       IP_PKTINFO,
-#else
-				       IP_RECVDSTADDR,
-#endif
-					(const void *)&yes, sizeof(yes)) < 0) {
-				plog(LLV_ERROR, LOCATION, NULL,
-					"setsockopt IP_RECVDSTADDR (%s)\n", 
-					strerror(errno));
-				goto err_and_next;
-			}
-			break;
-#ifdef INET6
-		case AF_INET6:
-#ifdef INET6_ADVAPI
-#ifdef IPV6_RECVPKTINFO
-			pktinfo = IPV6_RECVPKTINFO;
-#else  /* old adv. API */
-			pktinfo = IPV6_PKTINFO;
-#endif /* IPV6_RECVPKTINFO */
-#else
-			pktinfo = IPV6_RECVDSTADDR;
-#endif
-			if (setsockopt(p->sock, IPPROTO_IPV6, pktinfo,
-					(const void *)&yes, sizeof(yes)) < 0)
-			{
-				plog(LLV_ERROR, LOCATION, NULL,
-					"setsockopt IPV6_RECVDSTADDR (%d):%s\n",
-					pktinfo, strerror(errno));
-				goto err_and_next;
-			}
-			break;
-#endif
-		}
-
-#ifdef IPV6_USE_MIN_MTU
-		if (p->addr->sa_family == AF_INET6 &&
-		    setsockopt(p->sock, IPPROTO_IPV6, IPV6_USE_MIN_MTU,
-		    (void *)&yes, sizeof(yes)) < 0) {
-			plog(LLV_ERROR, LOCATION, NULL,
-			    "setsockopt IPV6_USE_MIN_MTU (%s)\n", 
-			    strerror(errno));
-			return -1;
-		}
-#endif
-
-		if (setsockopt_bypass(p->sock, p->addr->sa_family) < 0)
-			goto err_and_next;
-
-		if (bind(p->sock, p->addr, sysdep_sa_len(p->addr)) < 0) {
-			plog(LLV_ERROR, LOCATION, p->addr,
-				"failed to bind to address %s (%s).\n",
-				saddr2str(p->addr), strerror(errno));
-			close(p->sock);
-			goto err_and_next;
-		}
-
-		ifnum++;
-
-		plog(LLV_INFO, LOCATION, NULL,
-			"%s used as isakmp port (fd=%d)\n",
-			saddr2str(p->addr), p->sock);
-
 #ifdef ENABLE_NATT
-		if (p->addr->sa_family == AF_INET) {
-			int option = -1;
-
-
-			if(p->udp_encap)
-				option = UDP_ENCAP_ESPINUDP;
-#if defined(ENABLE_NATT_00) || defined(ENABLE_NATT_01)
-			else
-				option = UDP_ENCAP_ESPINUDP_NON_IKE;
+	int option = -1;
 #endif
-			if(option != -1){
-				if (setsockopt (p->sock, SOL_UDP, 
-				    UDP_ENCAP, &option, sizeof (option)) < 0) {
-					plog(LLV_WARNING, LOCATION, NULL,
-					    "setsockopt(%s): UDP_ENCAP %s\n",
-					    option == UDP_ENCAP_ESPINUDP ? "UDP_ENCAP_ESPINUDP" : "UDP_ENCAP_ESPINUDP_NON_IKE",
-						 strerror(errno));
-					goto skip_encap;
-				}
-				else {
-					plog(LLV_INFO, LOCATION, NULL,
-						 "%s used for NAT-T\n",
-						 saddr2str(p->addr));
-					encap_ifnum++;
-				}
-			}
-		}
-skip_encap:
-#endif
-		continue;
 
-	err_and_next:
-		racoon_free(p->addr);
-		p->addr = NULL;
-		if (! lcconf->autograbaddr && lcconf->strict_address)
+	/* warn if wildcard address - should we forbid this? */
+	switch (addr->sa_family) {
+	case AF_INET:
+		if (sin->sin_addr.s_addr == 0)
+			plog(LLV_WARNING, LOCATION, NULL,
+			     "listening to wildcard address,"
+			     "broadcast IKE packet may kill you\n");
+		break;
+#ifdef INET6
+	case AF_INET6:
+		if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) {
+			plog(LLV_DEBUG, LOCATION, NULL,
+			     "ignoring multicast address %s\n",
+			     saddr2str(addr));
 			return -1;
-		continue;
-	}
+		}
 
-	if (!ifnum) {
+		if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr))
+			plog(LLV_WARNING, LOCATION, NULL,
+			     "listening to wildcard address, "
+			     "broadcast IKE packet may kill you\n");
+		break;
+#endif
+	default:
 		plog(LLV_ERROR, LOCATION, NULL,
-			"no address could be bound.\n");
+		     "unsupported address family %d\n",
+		     addr->sa_family);
 		return -1;
 	}
 
-#ifdef ENABLE_NATT
-	if (natt_enabled_in_rmconf() && !encap_ifnum) {
-		plog(LLV_WARNING, LOCATION, NULL, 
-			"NAT-T is enabled in at least one remote{} section,\n");
-		plog(LLV_WARNING, LOCATION, NULL, 
-			"but no 'isakmp_natt' address was specified!\n");
+	if ((fd = privsep_socket(addr->sa_family, SOCK_DGRAM, 0)) < 0) {
+		plog(LLV_ERROR, LOCATION, NULL,
+		     "socket(%s)\n", strerror(errno));
+		return -1;
 	}
-#endif
+	close_on_exec(fd);
+	if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1)
+		plog(LLV_WARNING, LOCATION, NULL,
+		     "failed to put socket in non-blocking mode\n");
 
-	return 0;
+	/* receive my interface address on inbound packets. */
+	switch (addr->sa_family) {
+	case AF_INET:
+		if (setsockopt(fd, IPPROTO_IP,
+#ifdef __linux__
+			       IP_PKTINFO,
+#else
+			       IP_RECVDSTADDR,
+#endif
+			       (const void *) &yes, sizeof(yes)) < 0) {
+			plog(LLV_ERROR, LOCATION, NULL,
+			     "setsockopt IP_RECVDSTADDR (%s)\n",
+			     strerror(errno));
+			goto err;
+		}
+
+#ifdef ENABLE_NATT
+		if (udp_encap)
+			option = UDP_ENCAP_ESPINUDP;
+#if defined(ENABLE_NATT_00) || defined(ENABLE_NATT_01)
+		else
+			option = UDP_ENCAP_ESPINUDP_NON_IKE;
+#endif
+		if (option == -1)
+			break;
+
+		if (setsockopt(fd, SOL_UDP,
+			       UDP_ENCAP, &option,
+			       sizeof(option)) < 0) {
+			plog(LLV_WARNING, LOCATION, NULL,
+			     "setsockopt(%s): UDP_ENCAP %s\n",
+			     option == UDP_ENCAP_ESPINUDP ? "UDP_ENCAP_ESPINUDP" : "UDP_ENCAP_ESPINUDP_NON_IKE",
+			     strerror(errno));
+		} else {
+			plog(LLV_INFO, LOCATION, NULL,
+			     "%s used for NAT-T\n",
+			     saddr2str(addr));
+		}
+#endif
+		break;
+
+#ifdef INET6
+	case AF_INET6:
+#if defined(INET6_ADVAPI)
+#ifdef IPV6_RECVPKTINFO
+		pktinfo = IPV6_RECVPKTINFO;
+#else  /* old adv. API */
+		pktinfo = IPV6_PKTINFO;
+#endif /* IPV6_RECVPKTINFO */
+#else
+		pktinfo = IPV6_RECVDSTADDR;
+#endif
+		if (setsockopt(fd, IPPROTO_IPV6, pktinfo,
+			       (const void *) &yes, sizeof(yes)) < 0) {
+			plog(LLV_ERROR, LOCATION, NULL,
+			     "setsockopt IPV6_RECVDSTADDR (%d):%s\n",
+			     pktinfo, strerror(errno));
+			goto err;
+		}
+
+#ifdef IPV6_USE_MIN_MTU
+		if (setsockopt(fd, IPPROTO_IPV6, IPV6_USE_MIN_MTU,
+			       (void *) &yes, sizeof(yes)) < 0) {
+			plog(LLV_ERROR, LOCATION, NULL,
+			     "setsockopt IPV6_USE_MIN_MTU (%s)\n",
+			     strerror(errno));
+			goto err;
+		}
+#endif
+		break;
+#endif
+	}
+
+	if (setsockopt(fd, SOL_SOCKET,
+#ifdef __linux__
+		       SO_REUSEADDR,
+#else
+		       SO_REUSEPORT,
+#endif
+		       (void *) &yes, sizeof(yes)) < 0) {
+		plog(LLV_ERROR, LOCATION, NULL,
+		     "failed to set REUSE flag on %s (%s).\n",
+		     saddr2str(addr), strerror(errno));
+		goto err;
+	}
+
+	if (setsockopt_bypass(fd, addr->sa_family) < 0)
+		goto err;
+
+	if (privsep_bind(fd, addr, sysdep_sa_len(addr)) < 0) {
+		plog(LLV_ERROR, LOCATION, addr,
+		     "failed to bind to address %s (%s).\n",
+		     saddr2str(addr), strerror(errno));
+		goto err;
+	}
+
+	plog(LLV_INFO, LOCATION, NULL,
+	     "%s used as isakmp port (fd=%d)\n",
+	     saddr2str(addr), fd);
+
+	monitor_fd(fd, isakmp_handler, NULL, 1);
+	return fd;
+
+err:
+	close(fd);
+	return -1;
 }
 
 void
-isakmp_close()
+isakmp_close(int fd)
 {
-#ifndef ANDROID_PATCHED
-	struct myaddrs *p, *next;
-
-	for (p = lcconf->myaddrs; p; p = next) {
-		next = p->next;
-
-		if (!p->addr) {
-			racoon_free(p);
-			continue;
-		}
-		close(p->sock);
-		racoon_free(p->addr);
-		racoon_free(p);
-	}
-
-	lcconf->myaddrs = NULL;
-#endif
+	unmonitor_fd(fd);
+	close(fd);
 }
 
 int
@@ -1798,23 +1755,23 @@
 		extralen = 0;
 
 #ifdef ENABLE_FRAG
-	/* 
+	/*
 	 * Do not add the non ESP marker for a packet that will
-	 * be fragmented. The non ESP marker should appear in 
+	 * be fragmented. The non ESP marker should appear in
 	 * all fragment's packets, but not in the fragmented packet
 	 */
-	if (iph1->frag && sbuf->l > ISAKMP_FRAG_MAXLEN) 
+	if (iph1->frag && sbuf->l > ISAKMP_FRAG_MAXLEN)
 		extralen = 0;
 #endif
 	if (extralen)
 		plog (LLV_DEBUG, LOCATION, NULL, "Adding NON-ESP marker\n");
 
-	/* If NAT-T port floating is in use, 4 zero bytes (non-ESP marker) 
-	   must added just before the packet itself. For this we must 
+	/* If NAT-T port floating is in use, 4 zero bytes (non-ESP marker)
+	   must added just before the packet itself. For this we must
 	   allocate a new buffer and release it at the end. */
 	if (extralen) {
 		if ((vbuf = vmalloc (sbuf->l + extralen)) == NULL) {
-			plog(LLV_ERROR, LOCATION, NULL, 
+			plog(LLV_ERROR, LOCATION, NULL,
 			    "vbuf allocation failed\n");
 			return -1;
 		}
@@ -1831,22 +1788,21 @@
 #endif
 
 	/* select the socket to be sent */
-	s = getsockmyaddr(iph1->local);
-	if (s == -1){
+	s = myaddr_getfd(iph1->local);
+	if (s == -1)
 		return -1;
-	}
 
-	plog (LLV_DEBUG, LOCATION, NULL, "%zu bytes %s\n", sbuf->l, 
+	plog (LLV_DEBUG, LOCATION, NULL, "%zu bytes %s\n", sbuf->l,
 	      saddr2str_fromto("from %s to %s", iph1->local, iph1->remote));
 
 #ifdef ENABLE_FRAG
 	if (iph1->frag && sbuf->l > ISAKMP_FRAG_MAXLEN) {
 		if (isakmp_sendfrags(iph1, sbuf) == -1) {
-			plog(LLV_ERROR, LOCATION, NULL, 
+			plog(LLV_ERROR, LOCATION, NULL,
 			    "isakmp_sendfrags failed\n");
 			return -1;
 		}
-	} else 
+	} else
 #endif
 	{
 		len = sendfromto(s, sbuf->v, sbuf->l,
@@ -1857,32 +1813,24 @@
 			return -1;
 		}
 	}
-	
+
 	return 0;
 }
 
 /* called from scheduler */
-void
+static void
 isakmp_ph1resend_stub(p)
-	void *p;
+	struct sched *p;
 {
-	struct ph1handle *iph1;
+	struct ph1handle *iph1 = container_of(p, struct ph1handle, scr);
 
-	iph1=(struct ph1handle *)p;
-	if(isakmp_ph1resend(iph1) < 0){
-		if(iph1->scr != NULL){
-			/* Should not happen...
-			 */
-			sched_kill(iph1->scr);
-			iph1->scr=NULL;
-		}
-
+	if (isakmp_ph1resend(iph1) < 0) {
 		remph1(iph1);
 		delph1(iph1);
 	}
 }
 
-int
+static int
 isakmp_ph1resend(iph1)
 	struct ph1handle *iph1;
 {
@@ -1892,8 +1840,9 @@
 		plog(LLV_ERROR, LOCATION, NULL,
 			"phase1 negotiation failed due to time up. %s\n",
 			isakmp_pindex(&iph1->index, iph1->msgid));
-		EVT_PUSH(iph1->local, iph1->remote, 
-		    EVTT_PEER_NO_RESPONSE, NULL);
+		/* XXX is the peer really "dead" here ??? */
+		script_hook(iph1, SCRIPT_PHASE1_DEAD);
+		evt_phase1(iph1, EVT_PHASE1_NO_RESPONSE, NULL);
 
 		return -1;
 	}
@@ -1902,8 +1851,7 @@
 		plog(LLV_ERROR, LOCATION, NULL,
 			 "phase1 negotiation failed due to send error. %s\n",
 			 isakmp_pindex(&iph1->index, iph1->msgid));
-		EVT_PUSH(iph1->local, iph1->remote, 
-				 EVTT_PEER_NO_RESPONSE, NULL);
+		evt_phase1(iph1, EVT_PHASE1_NO_RESPONSE, NULL);
 		return -1;
 	}
 
@@ -1913,35 +1861,40 @@
 
 	iph1->retry_counter--;
 
-	iph1->scr = sched_new(iph1->rmconf->retry_interval,
-		isakmp_ph1resend_stub, iph1);
+	sched_schedule(&iph1->scr, lcconf->retry_interval,
+		       isakmp_ph1resend_stub);
 
 	return 0;
 }
 
-/* called from scheduler */
-void
-isakmp_ph2resend_stub(p)
-	void *p;
+int
+isakmp_ph1send(iph1)
+	struct ph1handle *iph1;
 {
-	struct ph2handle *iph2;
+	iph1->retry_counter = lcconf->retry_counter;
+	return isakmp_ph1resend(iph1);
+}
 
-	iph2=(struct ph2handle *)p;
+/* called from scheduler */
+static void
+isakmp_ph2resend_stub(p)
+	struct sched *p;
+{
+	struct ph2handle *iph2 = container_of(p, struct ph2handle, scr);
 
-	if(isakmp_ph2resend(iph2) < 0){
-		unbindph12(iph2);
+	if (isakmp_ph2resend(iph2) < 0) {
 		remph2(iph2);
 		delph2(iph2);
 	}
 }
 
-int
+static int
 isakmp_ph2resend(iph2)
 	struct ph2handle *iph2;
 {
 	/* Note: NEVER do the unbind/rem/del here, it will be done by the caller or by the _stub function
 	 */
-	if (iph2->ph1->status == PHASE1ST_EXPIRED){
+	if (iph2->ph1->status >= PHASE1ST_EXPIRED) {
 		plog(LLV_ERROR, LOCATION, NULL,
 			"phase2 negotiation failed due to phase1 expired. %s\n",
 				isakmp_pindex(&iph2->ph1->index, iph2->msgid));
@@ -1952,7 +1905,7 @@
 		plog(LLV_ERROR, LOCATION, NULL,
 			"phase2 negotiation failed due to time up. %s\n",
 				isakmp_pindex(&iph2->ph1->index, iph2->msgid));
-		EVT_PUSH(iph2->src, iph2->dst, EVTT_PEER_NO_RESPONSE, NULL);
+		evt_phase2(iph2, EVT_PHASE2_NO_RESPONSE, NULL);
 		unbindph12(iph2);
 		return -1;
 	}
@@ -1961,8 +1914,7 @@
 		plog(LLV_ERROR, LOCATION, NULL,
 			"phase2 negotiation failed due to send error. %s\n",
 				isakmp_pindex(&iph2->ph1->index, iph2->msgid));
-		EVT_PUSH(iph2->src, iph2->dst, EVTT_PEER_NO_RESPONSE, NULL);
-
+		evt_phase2(iph2, EVT_PHASE2_NO_RESPONSE, NULL);
 		return -1;
 	}
 
@@ -1972,19 +1924,77 @@
 
 	iph2->retry_counter--;
 
-	iph2->scr = sched_new(iph2->ph1->rmconf->retry_interval,
-		isakmp_ph2resend_stub, iph2);
+	sched_schedule(&iph2->scr, lcconf->retry_interval,
+		       isakmp_ph2resend_stub);
 
 	return 0;
 }
 
+int
+isakmp_ph2send(iph2)
+	struct ph2handle *iph2;
+{
+	iph2->retry_counter = lcconf->retry_counter;
+	return isakmp_ph2resend(iph2);
+}
+
+/* called from scheduler */
+void
+isakmp_ph1dying_stub(p)
+	struct sched *p;
+{
+
+	isakmp_ph1dying(container_of(p, struct ph1handle, sce));
+}
+
+void
+isakmp_ph1dying(iph1)
+	struct ph1handle *iph1;
+{
+	struct ph1handle *new_iph1;
+	struct ph2handle *p;
+	struct remoteconf *rmconf;
+
+	if (iph1->status >= PHASE1ST_DYING)
+		return;
+
+	/* Going away in after a while... */
+	iph1->status = PHASE1ST_DYING;
+
+	/* Any fresh phase1s? */
+	new_iph1 = getph1(iph1, iph1->local, iph1->remote, 1);
+	if (new_iph1 == NULL) {
+		LIST_FOREACH(p, &iph1->ph2tree, ph1bind) {
+			if (p->status != PHASE2ST_ESTABLISHED)
+				continue;
+
+			plog(LLV_INFO, LOCATION, NULL,
+			     "renegotiating phase1 to %s due to "
+			     "active phase2\n",
+			     saddrwop2str(iph1->remote));
+
+			if (iph1->side == INITIATOR)
+				isakmp_ph1begin_i(iph1->rmconf, iph1->remote,
+						  iph1->local);
+
+			break;
+		}
+	} else {
+		migrate_ph12(iph1, new_iph1);
+	}
+
+	/* Schedule for expiration */
+	sched_schedule(&iph1->sce, iph1->approval->lifetime *
+		       (100 - PFKEY_SOFT_LIFETIME_RATE) / 100,
+		       isakmp_ph1expire_stub);
+}
+
 /* called from scheduler */
 void
 isakmp_ph1expire_stub(p)
-	void *p;
+	struct sched *p;
 {
-
-	isakmp_ph1expire((struct ph1handle *)p);
+	isakmp_ph1expire(container_of(p, struct ph1handle, sce));
 }
 
 void
@@ -1993,9 +2003,7 @@
 {
 	char *src, *dst;
 
-	SCHED_KILL(iph1->sce);
-
-	if(iph1->status != PHASE1ST_EXPIRED){
+	if (iph1->status < PHASE1ST_EXPIRED) {
 		src = racoon_strdup(saddr2str(iph1->local));
 		dst = racoon_strdup(saddr2str(iph1->remote));
 		STRDUP_FATAL(src);
@@ -2010,41 +2018,44 @@
 		iph1->status = PHASE1ST_EXPIRED;
 	}
 
-	/*
-	 * the phase1 deletion is postponed until there is no phase2.
-	 */
-	if (LIST_FIRST(&iph1->ph2tree) != NULL) {
-		iph1->sce = sched_new(1, isakmp_ph1expire_stub, iph1);
-		return;
-	}
-
-	iph1->sce = sched_new(1, isakmp_ph1delete_stub, iph1);
+	isakmp_ph1delete(iph1);
 }
 
 /* called from scheduler */
 void
 isakmp_ph1delete_stub(p)
-	void *p;
+	struct sched *p;
 {
 
-	isakmp_ph1delete((struct ph1handle *)p);
+	isakmp_ph1delete(container_of(p, struct ph1handle, sce));
 }
 
 void
 isakmp_ph1delete(iph1)
 	struct ph1handle *iph1;
 {
+	struct ph2handle *p, *next;
+	struct ph1handle *new_iph1;
 	char *src, *dst;
 
-	SCHED_KILL(iph1->sce);
+	/* Migrate established phase2s. Any fresh phase1s? */
+	new_iph1 = getph1(iph1, iph1->local, iph1->remote, 1);
+	if (new_iph1 != NULL)
+		migrate_ph12(iph1, new_iph1);
 
-	if (LIST_FIRST(&iph1->ph2tree) != NULL) {
-		iph1->sce = sched_new(1, isakmp_ph1delete_stub, iph1);
-		return;
+	/* Discard any left phase2s */
+	for (p = LIST_FIRST(&iph1->ph2tree); p; p = next) {
+		next = LIST_NEXT(p, ph1bind);
+		if (p->status == PHASE2ST_ESTABLISHED)
+			isakmp_info_send_d2(p);
+		/* remove all ph2 handles,
+		 * as ph1handle will be expired soon
+		 */
+		delete_spd(p, 1);
+		remph2(p);
+		delph2(p);
 	}
 
-	/* don't re-negosiation when the phase 1 SA expires. */
-
 	src = racoon_strdup(saddr2str(iph1->local));
 	dst = racoon_strdup(saddr2str(iph1->remote));
 	STRDUP_FATAL(src);
@@ -2053,14 +2064,16 @@
 	plog(LLV_INFO, LOCATION, NULL,
 		"ISAKMP-SA deleted %s-%s spi:%s\n",
 		src, dst, isakmp_pindex(&iph1->index, 0));
-	EVT_PUSH(iph1->local, iph1->remote, EVTT_PHASE1_DOWN, NULL);
+
+	evt_phase1(iph1, EVT_PHASE1_DOWN, NULL);
+	if (new_iph1 == NULL && ph1_rekey_enabled(iph1))
+		script_hook(iph1, SCRIPT_PHASE1_DEAD);
+
 	racoon_free(src);
 	racoon_free(dst);
 
 	remph1(iph1);
 	delph1(iph1);
-
-	return;
 }
 
 /* called from scheduler.
@@ -2071,10 +2084,10 @@
  */
 void
 isakmp_ph2expire_stub(p)
-	void *p;
+	struct sched *p;
 {
 
-	isakmp_ph2expire((struct ph2handle *)p);
+	isakmp_ph2expire(container_of(p, struct ph2handle, sce));
 }
 
 void
@@ -2083,8 +2096,6 @@
 {
 	char *src, *dst;
 
-	SCHED_KILL(iph2->sce);
-
 	src = racoon_strdup(saddrwop2str(iph2->src));
 	dst = racoon_strdup(saddrwop2str(iph2->dst));
 	STRDUP_FATAL(src);
@@ -2096,19 +2107,16 @@
 	racoon_free(dst);
 
 	iph2->status = PHASE2ST_EXPIRED;
-
-	iph2->sce = sched_new(1, isakmp_ph2delete_stub, iph2);
-
-	return;
+	sched_schedule(&iph2->sce, 1, isakmp_ph2delete_stub);
 }
 
 /* called from scheduler */
 void
 isakmp_ph2delete_stub(p)
-	void *p;
+	struct sched *p;
 {
 
-	isakmp_ph2delete((struct ph2handle *)p);
+	isakmp_ph2delete(container_of(p, struct ph2handle, sce));
 }
 
 void
@@ -2117,8 +2125,6 @@
 {
 	char *src, *dst;
 
-	SCHED_KILL(iph2->sce);
-
 	src = racoon_strdup(saddrwop2str(iph2->src));
 	dst = racoon_strdup(saddrwop2str(iph2->dst));
 	STRDUP_FATAL(src);
@@ -2129,7 +2135,6 @@
 	racoon_free(src);
 	racoon_free(dst);
 
-	unbindph12(iph2);
 	remph2(iph2);
 	delph2(iph2);
 
@@ -2144,25 +2149,39 @@
  * if phase1 has been finished, begin phase2.
  */
 int
-isakmp_post_acquire(iph2)
+isakmp_post_acquire(iph2, iph1hint, nopassive)
 	struct ph2handle *iph2;
+	struct ph1handle *iph1hint;
+	int nopassive;
 {
 	struct remoteconf *rmconf;
 	struct ph1handle *iph1 = NULL;
-	
+
 	plog(LLV_DEBUG, LOCATION, NULL, "in post_acquire\n");
 
-	/* search appropreate configuration with masking port. */
-	rmconf = getrmconf(iph2->dst);
-	if (rmconf == NULL) {
-		plog(LLV_ERROR, LOCATION, NULL,
-			"no configuration found for %s.\n",
-			saddrwop2str(iph2->dst));
-		return -1;
+	/* Search appropriate configuration with masking port. Note that
+	 * we always use iph2->dst, and not iph2->sa_dst.
+	 *
+	 * XXX One possible need for using iph2->sa_dst if not NULL would
+	 * be for selecting a remote configuration based on a stable
+	 * address of a mobile node (not a CoA provided by MIGRATE/KMADDRESS
+	 * as iph2->dst hint). This scenario would require additional changes,
+	 * so no need to bother yet. --arno */
+
+	if (iph1hint == NULL || iph1hint->rmconf == NULL) {
+		rmconf = getrmconf(iph2->dst, nopassive ? GETRMCONF_F_NO_PASSIVE : 0);
+		if (rmconf == NULL) {
+			plog(LLV_ERROR, LOCATION, NULL,
+				"no configuration found for %s.\n",
+				saddrwop2str(iph2->dst));
+			return -1;
+		}
+	} else {
+		rmconf = iph1hint->rmconf;
 	}
 
 	/* if passive mode, ignore the acquire message */
-	if (rmconf->passive) {
+	if (nopassive && rmconf->passive) {
 		plog(LLV_DEBUG, LOCATION, NULL,
 			"because of passive mode, "
 			"ignore the acquire message for %s.\n",
@@ -2170,38 +2189,25 @@
 		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.
+	/*
+	 * XXX Searching by IP addresses + ports might fail on
+	 * some cases, we should use the ISAKMP identity to search
+	 * matching ISAKMP.
 	 */
-#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));
-		}
-	} else {
-		iph1 = getph1byaddr(iph2->src, iph2->dst, 0);
-	}
-#else
-	iph1 = getph1byaddr(iph2->src, iph2->dst, 0);
-#endif
+	iph1 = getph1(iph1hint, iph2->src, iph2->dst, 0);
 
 	/* no ISAKMP-SA found. */
 	if (iph1 == NULL) {
-		struct sched *sc;
-
 		iph2->retry_checkph1 = lcconf->retry_checkph1;
-		sc = sched_new(1, isakmp_chkph1there_stub, iph2);
+		sched_schedule(&iph2->sce, 1, isakmp_chkph1there_stub);
 		plog(LLV_INFO, LOCATION, NULL,
 			"IPsec-SA request for %s queued "
 			"due to no phase1 found.\n",
 			saddrwop2str(iph2->dst));
 
 		/* start phase 1 negotiation as a initiator. */
-		if (isakmp_ph1begin_i(rmconf, iph2->dst, iph2->src) < 0) {
-			SCHED_KILL(sc);
+		if (isakmp_ph1begin_i(rmconf, iph2->dst, iph2->src) == NULL) {
+			sched_cancel(&iph2->sce);
 			return -1;
 		}
 
@@ -2210,9 +2216,9 @@
 	}
 
 	/* found ISAKMP-SA, but on negotiation. */
-	if (iph1->status != PHASE1ST_ESTABLISHED) {
+	if (iph1->status < PHASE1ST_ESTABLISHED) {
 		iph2->retry_checkph1 = lcconf->retry_checkph1;
-		sched_new(1, isakmp_chkph1there_stub, iph2);
+		sched_schedule(&iph2->sce, 1, isakmp_chkph1there_stub);
 		plog(LLV_INFO, LOCATION, iph2->dst,
 			"request for establishing IPsec-SA was queued "
 			"due to no phase1 found.\n");
@@ -2233,6 +2239,69 @@
 	return 0;
 }
 
+int
+isakmp_get_sainfo(iph2, sp_out, sp_in)
+	struct ph2handle *iph2;
+	struct secpolicy *sp_out, *sp_in;
+{
+	struct remoteconf *conf;
+	uint32_t remoteid = 0;
+
+	plog(LLV_DEBUG, LOCATION, NULL,
+		"new acquire %s\n", spidx2str(&sp_out->spidx));
+
+	/* get sainfo */
+	{
+		vchar_t *idsrc, *iddst;
+
+		idsrc = ipsecdoi_sockaddr2id((struct sockaddr *)&sp_out->spidx.src,
+			sp_out->spidx.prefs, sp_out->spidx.ul_proto);
+		if (idsrc == NULL) {
+			plog(LLV_ERROR, LOCATION, NULL,
+				"failed to get ID for %s\n",
+				spidx2str(&sp_out->spidx));
+			return -1;
+		}
+		iddst = ipsecdoi_sockaddr2id((struct sockaddr *)&sp_out->spidx.dst,
+			sp_out->spidx.prefd, sp_out->spidx.ul_proto);
+		if (iddst == NULL) {
+			plog(LLV_ERROR, LOCATION, NULL,
+				"failed to get ID for %s\n",
+				spidx2str(&sp_out->spidx));
+			vfree(idsrc);
+			return -1;
+		}
+
+		conf = getrmconf(iph2->dst, 0);
+		if (conf != NULL)
+			remoteid = conf->ph1id;
+		else
+			plog(LLV_DEBUG, LOCATION, NULL, "Warning: no valid rmconf !\n");
+
+		iph2->sainfo = getsainfo(idsrc, iddst, NULL, NULL, remoteid);
+		vfree(idsrc);
+		vfree(iddst);
+		if (iph2->sainfo == NULL) {
+			plog(LLV_ERROR, LOCATION, NULL,
+				"failed to get sainfo.\n");
+			return -1;
+			/* XXX should use the algorithm list from register message */
+		}
+
+		plog(LLV_DEBUG, LOCATION, NULL,
+			"selected sainfo: %s\n", sainfo2str(iph2->sainfo));
+	}
+
+	if (set_proposal_from_policy(iph2, sp_out, sp_in) < 0) {
+		plog(LLV_ERROR, LOCATION, NULL,
+			"failed to create saprop.\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+
 /*
  * receive GETSPI from kernel.
  */
@@ -2245,7 +2314,7 @@
 #endif
 
 	/* don't process it because there is no suitable phase1-sa. */
-	if (iph2->ph1->status == PHASE1ST_EXPIRED) {
+	if (iph2->ph1->status >= PHASE1ST_EXPIRED) {
 		plog(LLV_ERROR, LOCATION, iph2->ph1->remote,
 			"the negotiation is stopped, "
 			"because there is no suitable ISAKMP-SA.\n");
@@ -2273,9 +2342,9 @@
 /* called by scheduler */
 void
 isakmp_chkph1there_stub(p)
-	void *p;
+	struct sched *p;
 {
-	isakmp_chkph1there((struct ph2handle *)p);
+	isakmp_chkph1there(container_of(p, struct ph2handle, sce));
 }
 
 void
@@ -2297,33 +2366,14 @@
 		/* send acquire to kernel as error */
 		pk_sendeacquire(iph2);
 
-		unbindph12(iph2);
 		remph2(iph2);
 		delph2(iph2);
 
 		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.
-	 */
-#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");
-		}
-	} else {
-		plog(LLV_DEBUG2, LOCATION, NULL, "CHKPH1THERE: searching byaddr.\n");
-		iph1 = getph1byaddr(iph2->src, iph2->dst, 0);
-		if(iph1 != NULL)
-			plog(LLV_DEBUG2, LOCATION, NULL, "CHKPH1THERE: found byaddr.\n");
-	}
-#else
+	/* Search isakmp status table by address and port */
 	iph1 = getph1byaddr(iph2->src, iph2->dst, 0);
-#endif
 
 	/* XXX Even if ph1 as responder is there, should we not start
 	 * phase 2 negotiation ? */
@@ -2351,7 +2401,7 @@
 	plog(LLV_DEBUG2, LOCATION, NULL, "CHKPH1THERE: no established ph1 handler found\n");
 
 	/* no isakmp-sa found */
-	sched_new(1, isakmp_chkph1there_stub, iph2);
+	sched_schedule(&iph2->sce, 1, isakmp_chkph1there_stub);
 
 	return;
 }
@@ -2874,7 +2924,9 @@
 	 * respect content of "remote".
 	 */
 	if (extract_port(iph1->remote) == 0) {
-		port = extract_port(rmconf->remote);
+		port = 0;
+		if (rmconf != NULL)
+			port = extract_port(rmconf->remote);
 		if (port == 0)
 			port = PORT_ISAKMP;
 		set_port(iph1->remote, port);
@@ -2887,8 +2939,12 @@
 	if (iph1->local == NULL)
 		return -1;
 
-	if (extract_port(iph1->local) == 0)
+	if (extract_port(iph1->local) == 0) {
+		port = myaddr_getsport(iph1->local);
+		if (port == 0)
+			port = PORT_ISAKMP;
 		set_port(iph1->local, PORT_ISAKMP);
+	}
 
 #ifdef ENABLE_NATT
 	if (extract_port(iph1->local) == lcconf->port_isakmp_natt) {
@@ -2935,10 +2991,10 @@
 		"ISAKMP-SA established %s-%s spi:%s\n",
 		src, dst,
 		isakmp_pindex(&iph1->index, 0));
-	
-	EVT_PUSH(iph1->local, iph1->remote, EVTT_PHASE1_UP, NULL);
+
+	evt_phase1(iph1, EVT_PHASE1_UP, NULL);
 	if(!iph1->rmconf->mode_cfg)
-		EVT_PUSH(iph1->local, iph1->remote, EVTT_NO_ISAKMP_CFG, NULL);
+		evt_phase1(iph1, EVT_PHASE1_MODE_CFG, NULL);
 
 	racoon_free(src);
 	racoon_free(dst);
@@ -2947,7 +3003,8 @@
 }
 
 struct payload_list *
-isakmp_plist_append (struct payload_list *plist, vchar_t *payload, int payload_type)
+isakmp_plist_append_full (struct payload_list *plist, vchar_t *payload,
+			  u_int8_t payload_type, u_int8_t free_payload)
 {
 	if (! plist) {
 		plist = racoon_malloc (sizeof (struct payload_list));
@@ -2962,11 +3019,12 @@
 	plist->next = NULL;
 	plist->payload = payload;
 	plist->payload_type = payload_type;
+	plist->free_payload = free_payload;
 
 	return plist;
 }
 
-vchar_t * 
+vchar_t *
 isakmp_plist_set_all (struct payload_list **plist, struct ph1handle *iph1)
 {
 	struct payload_list *ptr = *plist, *first;
@@ -2977,7 +3035,7 @@
 	/* Seek to the first item.  */
 	while (ptr->prev) ptr = ptr->prev;
 	first = ptr;
-	
+
 	/* Compute the whole length.  */
 	while (ptr) {
 		tlen += ptr->payload->l + sizeof (struct isakmp_gen);
@@ -3002,6 +3060,8 @@
 		p = set_isakmp_payload (p, ptr->payload, ptr->next ? ptr->next->payload_type : ISAKMP_NPTYPE_NONE);
 		first = ptr;
 		ptr = ptr->next;
+		if (first->free_payload)
+			vfree(first->payload);
 		racoon_free (first);
 		/* ptr->prev = NULL; first = NULL; ... omitted.  */
 		n++;
@@ -3017,7 +3077,7 @@
 }
 
 #ifdef ENABLE_FRAG
-int 
+int
 frag_handler(iph1, msg, remote, local)
 	struct ph1handle *iph1;
 	vchar_t *msg;
@@ -3028,7 +3088,7 @@
 
 	if (isakmp_frag_extract(iph1, msg) == 1) {
 		if ((newmsg = isakmp_frag_reassembly(iph1)) == NULL) {
-			plog(LLV_ERROR, LOCATION, remote, 
+			plog(LLV_ERROR, LOCATION, remote,
 			    "Packet reassembly failed\n");
 			return -1;
 		}
@@ -3050,7 +3110,6 @@
 	char portstr[PORT_MAX];
 	char **envp = NULL;
 	int envc = 1;
-	struct sockaddr_in *sin;
 	char **c;
 
 	if (iph1 == NULL ||
@@ -3063,9 +3122,7 @@
 #endif
 
 	/* local address */
-	sin = (struct sockaddr_in *)iph1->local;
-	inet_ntop(sin->sin_family, &sin->sin_addr, addrstr, IP_MAX);
-	snprintf(portstr, PORT_MAX, "%d", ntohs(sin->sin_port));
+	GETNAMEINFO(iph1->local, addrstr, portstr);
 
 	if (script_env_append(&envp, &envc, "LOCAL_ADDR", addrstr) != 0) {
 		plog(LLV_ERROR, LOCATION, NULL, "Cannot set LOCAL_ADDR\n");
@@ -3079,9 +3136,7 @@
 
 	/* Peer address */
 	if (iph1->remote != NULL) {
-		sin = (struct sockaddr_in *)iph1->remote;
-		inet_ntop(sin->sin_family, &sin->sin_addr, addrstr, IP_MAX);
-		snprintf(portstr, PORT_MAX, "%d", ntohs(sin->sin_port));
+		GETNAMEINFO(iph1->remote, addrstr, portstr);
 
 		if (script_env_append(&envp, &envc, 
 		    "REMOTE_ADDR", addrstr) != 0) {
@@ -3098,6 +3153,16 @@
 		}
 	}
 
+	/* Peer identity. */
+	if (iph1->id_p != NULL) {
+		if (script_env_append(&envp, &envc, "REMOTE_ID",
+				      ipsecdoi_id2str(iph1->id_p)) != 0) {
+			plog(LLV_ERROR, LOCATION, NULL,
+			     "Cannot set REMOTE_ID\n");
+			goto out;
+		}
+	}
+
 	if (privsep_script_exec(iph1->rmconf->script[script]->v, 
 	    script, envp) != 0) 
 		plog(LLV_ERROR, LOCATION, NULL, 
@@ -3160,7 +3225,7 @@
 	argv[1] = script_names[name];
 	argv[2] = NULL;
 
-	switch (fork()) { 
+	switch (fork()) {
 	case 0:
 		execve(argv[0], argv, envp);
 		plog(LLV_ERROR, LOCATION, NULL,
@@ -3175,7 +3240,7 @@
 		break;
 	default:
 		break;
-	}	
+	}
 	return 0;
 
 }
@@ -3201,7 +3266,7 @@
 	iph1->status = PHASE1ST_EXPIRED;
 
 	/* Check if we have another, still valid, phase1 SA. */
-	new_iph1 = getph1byaddr(iph1->local, iph1->remote, 1);
+	new_iph1 = getph1(iph1, iph1->local, iph1->remote, GETPH1_F_ESTABLISHED);
 
 	/*
 	 * Delete all orphaned or binded to the deleting ph1handle phase2 SAs.
@@ -3240,6 +3305,7 @@
 			msg = next;
 			continue;
 		}
+		pk_fixup_sa_addresses(mhp);
 		src = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_SRC]);
 		dst = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_DST]);
 
@@ -3255,8 +3321,10 @@
 		 * Select only SAs where src == local and dst == remote (outgoing)
 		 * or src == remote and dst == local (incoming).
 		 */
-		if ((CMPSADDR(iph1->local, src) || CMPSADDR(iph1->remote, dst)) &&
-			(CMPSADDR(iph1->local, dst) || CMPSADDR(iph1->remote, src))) {
+		if ((cmpsaddr(iph1->local, src) != CMPSADDR_MATCH ||
+		     cmpsaddr(iph1->remote, dst) != CMPSADDR_MATCH) &&
+		    (cmpsaddr(iph1->local, dst) != CMPSADDR_MATCH ||
+		     cmpsaddr(iph1->remote, src) != CMPSADDR_MATCH)) {
 			msg = next;
 			continue;
 		}
@@ -3274,7 +3342,7 @@
 					ntohl(sa->sadb_sa_spi));
 			}else{
 
-				/* 
+				/*
 				 * If we have a new ph1, do not purge IPsec-SAs binded
 				 *  to a different ISAKMP-SA
 				 */
@@ -3286,7 +3354,7 @@
 				/* If the ph2handle is established, do not purge IPsec-SA */
 				if (iph2->status == PHASE2ST_ESTABLISHED ||
 					iph2->status == PHASE2ST_EXPIRED) {
-					
+
 					plog(LLV_INFO, LOCATION, NULL,
 						 "keeping IPsec-SA spi=%u - found valid ISAKMP-SA spi=%s.\n",
 						 ntohl(sa->sadb_sa_spi),
@@ -3297,7 +3365,7 @@
 			}
 		}
 
-		
+
 		pfkey_send_delete(lcconf->sock_pfkey,
 				  msg->sadb_msg_satype,
 				  IPSEC_MODE_ANY,
@@ -3306,7 +3374,6 @@
 		/* delete a relative phase 2 handle. */
 		if (iph2 != NULL) {
 			delete_spd(iph2, 0);
-			unbindph12(iph2);
 			remph2(iph2);
 			delph2(iph2);
 		}
@@ -3326,12 +3393,10 @@
 		 "purged ISAKMP-SA spi=%s.\n",
 		 isakmp_pindex(&(iph1->index), iph1->msgid));
 
-	SCHED_KILL(iph1->sce);
-
-	iph1->sce = sched_new(1, isakmp_ph1delete_stub, iph1);
+	isakmp_ph1delete(iph1);
 }
 
-void 
+void
 delete_spd(iph2, created)
 	struct ph2handle *iph2;
  	u_int64_t created;
@@ -3356,23 +3421,23 @@
 	dst = iph2->dst;
 
 	plog(LLV_INFO, LOCATION, NULL,
-		 "generated policy, deleting it.\n");
-		
+		 "deleting a generated policy.\n");
+
 	memset(&spidx, 0, sizeof(spidx));
 	iph2->spidx_gen = (caddr_t )&spidx;
-		
+
 	/* make inbound policy */
 	iph2->src = dst;
 	iph2->dst = src;
 	spidx.dir = IPSEC_DIR_INBOUND;
 	spidx.ul_proto = 0;
-		
-	/* 
+
+	/*
 	 * Note: code from get_proposal_r
 	 */
-		
+
 #define _XIDT(d) ((struct ipsecdoi_id_b *)(d)->v)->type
-		
+
 	/*
 	 * make destination address in spidx from either ID payload
 	 * or phase 1 address into a address in spidx.
@@ -3388,48 +3453,48 @@
 									 &spidx.prefd, &spidx.ul_proto);
 		if (error)
 			goto purge;
-			
+
 #ifdef INET6
 		/*
 		 * get scopeid from the SA address.
 		 * note that the phase 1 source address is used as
-		 * a destination address to search for a inbound 
+		 * a destination address to search for a inbound
 		 * policy entry because rcoon is responder.
 		 */
 		if (_XIDT(iph2->id) == IPSECDOI_ID_IPV6_ADDR) {
-			if ((error = 
+			if ((error =
 				 setscopeid((struct sockaddr *)&spidx.dst,
 							iph2->src)) != 0)
 				goto purge;
 		}
 #endif
-			
+
 		if (_XIDT(iph2->id) == IPSECDOI_ID_IPV4_ADDR
 			|| _XIDT(iph2->id) == IPSECDOI_ID_IPV6_ADDR)
 			idi2type = _XIDT(iph2->id);
-			
+
 	} else {
-			
+
 		plog(LLV_DEBUG, LOCATION, NULL,
 			 "get a destination address of SP index "
 			 "from phase1 address "
 			 "due to no ID payloads found "
 			 "OR because ID type is not address.\n");
-			
+
 		/*
-		 * copy the SOURCE address of IKE into the 
-		 * DESTINATION address of the key to search the 
+		 * copy the SOURCE address of IKE into the
+		 * DESTINATION address of the key to search the
 		 * SPD because the direction of policy is inbound.
 		 */
 		memcpy(&spidx.dst, iph2->src, sysdep_sa_len(iph2->src));
 		switch (spidx.dst.ss_family) {
 		case AF_INET:
-			spidx.prefd = 
+			spidx.prefd =
 				sizeof(struct in_addr) << 3;
 			break;
 #ifdef INET6
 		case AF_INET6:
-			spidx.prefd = 
+			spidx.prefd =
 				sizeof(struct in6_addr) << 3;
 			break;
 #endif
@@ -3438,8 +3503,8 @@
 			break;
 		}
 	}
-					
-	/* make source address in spidx */
+
+		/* make source address in spidx */
 	if (iph2->id_p != NULL
 		&& (_XIDT(iph2->id_p) == IPSECDOI_ID_IPV4_ADDR
 			|| _XIDT(iph2->id_p) == IPSECDOI_ID_IPV6_ADDR
@@ -3447,8 +3512,8 @@
 			|| _XIDT(iph2->id_p) == IPSECDOI_ID_IPV6_ADDR_SUBNET)) {
 		/* get a source address of inbound SA */
 		error = ipsecdoi_id2sockaddr(iph2->id_p,
-									 (struct sockaddr *)&spidx.src,
-									 &spidx.prefs, &spidx.ul_proto);
+					     (struct sockaddr *)&spidx.src,
+					     &spidx.prefs, &spidx.ul_proto);
 		if (error)
 			goto purge;
 
@@ -3458,7 +3523,7 @@
 		 * for more detail, see above of this function.
 		 */
 		if (_XIDT(iph2->id_p) == IPSECDOI_ID_IPV6_ADDR) {
-			error = 
+			error =
 				setscopeid((struct sockaddr *)&spidx.src,
 						   iph2->dst);
 			if (error)
@@ -3466,19 +3531,19 @@
 		}
 #endif
 
-		/* make id[src,dst] if both ID types are IP address and same */
+		/* make sa_[src,dst] if both ID types are IP address and same */
 		if (_XIDT(iph2->id_p) == idi2type
 			&& spidx.dst.ss_family == spidx.src.ss_family) {
-			iph2->src_id = 
+			iph2->sa_src =
 				dupsaddr((struct sockaddr *)&spidx.dst);
-			if (iph2->src_id == NULL) {
+			if (iph2->sa_src == NULL) {
 				plog(LLV_ERROR, LOCATION, NULL,
 					 "allocation failed\n");
 				goto purge;
 			}
-			iph2->dst_id = 
+			iph2->sa_dst =
 				dupsaddr((struct sockaddr *)&spidx.src);
-			if (iph2->dst_id == NULL) {
+			if (iph2->sa_dst == NULL) {
 				plog(LLV_ERROR, LOCATION, NULL,
 					 "allocation failed\n");
 				goto purge;
@@ -3496,12 +3561,12 @@
 		memcpy(&spidx.src, iph2->dst, sysdep_sa_len(iph2->dst));
 		switch (spidx.src.ss_family) {
 		case AF_INET:
-			spidx.prefs = 
+			spidx.prefs =
 				sizeof(struct in_addr) << 3;
 			break;
 #ifdef INET6
 		case AF_INET6:
-			spidx.prefs = 
+			spidx.prefs =
 				sizeof(struct in6_addr) << 3;
 			break;
 #endif
@@ -3539,7 +3604,7 @@
 	 */
 	if( created ){
 		struct secpolicy *p;
-		
+
 		p = getsp(&spidx);
 		if(p != NULL){
 			/* just do no test if p is NULL, because this probably just means
@@ -3604,7 +3669,7 @@
 	struct sockaddr *sp_addr0, *sa_addr0;
 {
 	struct sockaddr_in6 *sp_addr, *sa_addr;
-    
+
 	sp_addr = (struct sockaddr_in6 *)sp_addr0;
 	sa_addr = (struct sockaddr_in6 *)sa_addr0;
 
diff --git a/src/racoon/isakmp.h b/src/racoon/isakmp.h
index d0fd242..16986a9 100644
--- a/src/racoon/isakmp.h
+++ b/src/racoon/isakmp.h
@@ -1,4 +1,4 @@
-/*	$NetBSD: isakmp.h,v 1.4 2006/09/09 16:22:09 manu Exp $	*/
+/*	$NetBSD: isakmp.h,v 1.7 2009/05/20 07:54:50 vanhu Exp $	*/
 
 /* Id: isakmp.h,v 1.11 2005/04/25 22:19:39 manubsd Exp */
 
@@ -36,8 +36,8 @@
 
 /* refer to RFC 2408 */
 
-/* must include <netinet/in.h> first. */
-/* must include "isakmp_var.h" first. */
+#include <netinet/in.h>
+#include "isakmp_var.h"
 
 #define INITIATOR	0	/* synonym sender */
 #define RESPONDER	1	/* synonym receiver */
@@ -133,7 +133,7 @@
 /* Exchange Type */
 #define ISAKMP_ETYPE_NONE	0	/* NONE */
 #define ISAKMP_ETYPE_BASE	1	/* Base */
-#define ISAKMP_ETYPE_IDENT	2	/* Identity Proteciton */
+#define ISAKMP_ETYPE_IDENT	2	/* Identity Protection */
 #define ISAKMP_ETYPE_AUTH	3	/* Authentication Only */
 #define ISAKMP_ETYPE_AGG	4	/* Aggressive */
 #define ISAKMP_ETYPE_INFO	5	/* Informational */
@@ -270,11 +270,6 @@
 #define ISAKMP_CERT_X509ATTR	10
 #define ISAKMP_CERT_PLAINRSA	11
 
-/* the method to get peers certificate */
-#define ISAKMP_GETCERT_PAYLOAD		1
-#define ISAKMP_GETCERT_LOCALFILE	2
-#define ISAKMP_GETCERT_DNS		3
-
 /* 3.10 Certificate Request Payload */
 struct isakmp_pl_cr {
 	struct isakmp_gen h;
@@ -384,7 +379,8 @@
 struct payload_list {
 	struct payload_list	*next, *prev;
 	vchar_t			*payload;
-	int			payload_type;
+	u_int8_t		payload_type;
+	u_int8_t		free_payload;
 };
 
 
diff --git a/src/racoon/isakmp_agg.c b/src/racoon/isakmp_agg.c
index 0d43883..2e387fb 100644
--- a/src/racoon/isakmp_agg.c
+++ b/src/racoon/isakmp_agg.c
@@ -1,11 +1,11 @@
-/*	$NetBSD: isakmp_agg.c,v 1.9 2006/09/30 21:49:37 manu Exp $	*/
+/*	$NetBSD: isakmp_agg.c,v 1.16 2009/09/18 10:31:11 tteras Exp $	*/
 
 /* Id: isakmp_agg.c,v 1.28 2006/04/06 16:46:08 manubsd Exp */
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
  * All rights reserved.
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
@@ -17,7 +17,7 @@
  * 3. Neither the name of the project nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
- * 
+ *
  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@@ -113,8 +113,6 @@
 	vchar_t *msg; /* must be null */
 {
 	struct payload_list *plist = NULL;
-	int need_cr = 0;
-	vchar_t *cr = NULL; 
 	int error = -1;
 #ifdef ENABLE_NATT
 	vchar_t *vid_natt[MAX_NATT_VID_COUNT] = { NULL };
@@ -135,7 +133,6 @@
 	vchar_t *vid_dpd = NULL;
 #endif
 
-
 	/* validity check */
 	if (msg != NULL) {
 		plog(LLV_ERROR, LOCATION, NULL,
@@ -157,7 +154,7 @@
 		goto end;
 
 	/* create SA payload for my proposal */
-	iph1->sa = ipsecdoi_setph1proposal(iph1->rmconf->proposal);
+	iph1->sa = ipsecdoi_setph1proposal(iph1->rmconf, iph1->rmconf->proposal);
 	if (iph1->sa == NULL)
 		goto end;
 
@@ -180,8 +177,8 @@
 
 #ifdef ENABLE_HYBRID
 	/* Do we need Xauth VID? */
-	switch (RMAUTHMETHOD(iph1)) {
-	case FICTIVE_AUTH_METHOD_XAUTH_PSKEY_I:
+	switch (iph1->rmconf->proposal->authmethod) {
+	case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_I:
 	case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I:
 	case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_I:
 	case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_I:
@@ -189,10 +186,10 @@
 	case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAENC_I:
 	case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAREV_I:
 		if ((vid_xauth = set_vendorid(VENDORID_XAUTH)) == NULL)
-			plog(LLV_ERROR, LOCATION, NULL, 
+			plog(LLV_ERROR, LOCATION, NULL,
 			     "Xauth vendor ID generation failed\n");
 		if ((vid_unity = set_vendorid(VENDORID_UNITY)) == NULL)
-			plog(LLV_ERROR, LOCATION, NULL, 
+			plog(LLV_ERROR, LOCATION, NULL,
 			     "Unity vendor ID generation failed\n");
 		break;
 	default:
@@ -209,26 +206,13 @@
 		if (vid_frag == NULL)
 			plog(LLV_ERROR, LOCATION, NULL,
 			    "Frag vendorID construction failed\n");
-	}		
-#endif
-
-	/* create CR if need */
-	if (iph1->rmconf->send_cr
-	 && oakley_needcr(iph1->rmconf->proposal->authmethod)
-	 && iph1->rmconf->peerscertfile == NULL) {
-		need_cr = 1;
-		cr = oakley_getcr(iph1);
-		if (cr == NULL) {
-			plog(LLV_ERROR, LOCATION, NULL,
-				"failed to get cr buffer.\n");
-			goto end;
-		}
 	}
+#endif
 
 	plog(LLV_DEBUG, LOCATION, NULL, "authmethod is %s\n",
 		s_oakley_attr_method(iph1->rmconf->proposal->authmethod));
 #ifdef HAVE_GSSAPI
-	if (RMAUTHMETHOD(iph1) == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB)
+	if (iph1->rmconf->proposal->authmethod == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB)
 		gssapi_get_itoken(iph1, &len);
 #endif
 
@@ -245,33 +229,37 @@
 	plist = isakmp_plist_append(plist, iph1->id, ISAKMP_NPTYPE_ID);
 
 #ifdef HAVE_GSSAPI
-	if (RMAUTHMETHOD(iph1) == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB) {
-		gssapi_get_token_to_send(iph1, &gsstoken);
+	if (iph1->rmconf->proposal->authmethod == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB) {
+		if (gssapi_get_token_to_send(iph1, &gsstoken) < 0) {
+			plog(LLV_ERROR, LOCATION, NULL,
+			     "Failed to get gssapi token.\n");
+			goto end;
+		}
 		plist = isakmp_plist_append(plist, gsstoken, ISAKMP_NPTYPE_GSS);
 	}
 #endif
 	/* create isakmp CR payload */
-	if (need_cr)
-		plist = isakmp_plist_append(plist, cr, ISAKMP_NPTYPE_CR);
+	if (oakley_needcr(iph1->rmconf->proposal->authmethod))
+		plist = oakley_append_cr(plist, iph1);
 
 #ifdef ENABLE_FRAG
 	if (vid_frag)
 		plist = isakmp_plist_append(plist, vid_frag, ISAKMP_NPTYPE_VID);
 #endif
 #ifdef ENABLE_NATT
-	/* 
-	 * set VID payload for NAT-T if NAT-T 
-	 * support allowed in the config file 
+	/*
+	 * set VID payload for NAT-T if NAT-T
+	 * support allowed in the config file
 	 */
-	if (iph1->rmconf->nat_traversal) 
+	if (iph1->rmconf->nat_traversal)
 		plist = isakmp_plist_append_natt_vids(plist, vid_natt);
 #endif
 #ifdef ENABLE_HYBRID
 	if (vid_xauth)
-		plist = isakmp_plist_append(plist, 
+		plist = isakmp_plist_append(plist,
 		    vid_xauth, ISAKMP_NPTYPE_VID);
 	if (vid_unity)
-		plist = isakmp_plist_append(plist, 
+		plist = isakmp_plist_append(plist,
 		    vid_unity, ISAKMP_NPTYPE_VID);
 #endif
 #ifdef ENABLE_DPD
@@ -289,8 +277,7 @@
 #endif
 
 	/* send the packet, add to the schedule to resend */
-	iph1->retry_counter = iph1->rmconf->retry_counter;
-	if (isakmp_ph1resend(iph1) == -1)
+	if (isakmp_ph1send(iph1) == -1)
 		goto end;
 
 	iph1->status = PHASE1ST_MSG1SENT;
@@ -298,8 +285,6 @@
 	error = 0;
 
 end:
-	if (cr)
-		vfree(cr);
 #ifdef HAVE_GSSAPI
 	if (gsstoken)
 		vfree(gsstoken);
@@ -343,7 +328,6 @@
 	struct isakmp_parse_t *pa;
 	vchar_t *satmp = NULL;
 	int error = -1;
-	int vid_numeric;
 	int ptype;
 #ifdef ENABLE_HYBRID
 	vchar_t *unity_vid;
@@ -425,37 +409,12 @@
 				goto end;
 			break;
 		case ISAKMP_NPTYPE_VID:
-			vid_numeric = check_vendorid(pa->ptr);
-#ifdef ENABLE_NATT
-			if (iph1->rmconf->nat_traversal && 
-			    natt_vendorid(vid_numeric))
-				natt_handle_vendorid(iph1, vid_numeric);
-#endif
-#ifdef ENABLE_HYBRID
-			switch (vid_numeric) {
-			case VENDORID_XAUTH:
-				iph1->mode_cfg->flags |= 
-				    ISAKMP_CFG_VENDORID_XAUTH;
-				break;
-
-			case VENDORID_UNITY:
-				iph1->mode_cfg->flags |= 
-				    ISAKMP_CFG_VENDORID_UNITY;
-				break;
-			default:
-				break;
-			}
-#endif
-#ifdef ENABLE_DPD
-			if (vid_numeric == VENDORID_DPD && iph1->rmconf->dpd) {
-				iph1->dpd_support=1;
-				plog(LLV_DEBUG, LOCATION, NULL,
-					 "remote supports DPD\n");
-			}
-#endif
+			handle_vendorid(iph1, pa->ptr);
 			break;
 		case ISAKMP_NPTYPE_N:
-			isakmp_check_notify(pa->ptr, iph1);
+			isakmp_log_notify(iph1,
+				(struct isakmp_pl_n *) pa->ptr,
+				"aggressive exchange");
 			break;
 #ifdef HAVE_GSSAPI
 		case ISAKMP_NPTYPE_GSS:
@@ -529,7 +488,7 @@
 	if (NATT_AVAILABLE(iph1)) {
 		struct natd_payload *natd = NULL;
 		int natd_verified;
-		
+
 		plog(LLV_INFO, LOCATION, iph1->remote,
 		     "Selected NAT-T version: %s\n",
 		     vid_string_by_id(iph1->natt_options->version));
@@ -537,9 +496,9 @@
 		/* set both bits first so that we can clear them
 		   upon verifying hashes */
 		iph1->natt_flags |= NAT_DETECTED;
-                        
+
 		while ((natd = TAILQ_FIRST(&natd_tree)) != NULL) {
-			/* this function will clear appropriate bits bits 
+			/* this function will clear appropriate bits bits
 			   from iph1->natt_flags */
 			natd_verified = natt_compare_addr_hash (iph1,
 				natd->payload, natd->seq);
@@ -547,7 +506,7 @@
 			plog (LLV_INFO, LOCATION, NULL, "NAT-D payload #%d %s\n",
 				natd->seq - 1,
 				natd_verified ? "verified" : "doesn't match");
-			
+
 			vfree (natd->payload);
 
 			TAILQ_REMOVE(&natd_tree, natd, chain);
@@ -555,7 +514,7 @@
 		}
 
 		plog (LLV_INFO, LOCATION, NULL, "NAT %s %s%s\n",
-		      iph1->natt_flags & NAT_DETECTED ? 
+		      iph1->natt_flags & NAT_DETECTED ?
 		      		"detected:" : "not detected",
 		      iph1->natt_flags & NAT_DETECTED_ME ? "ME " : "",
 		      iph1->natt_flags & NAT_DETECTED_PEER ? "PEER" : "");
@@ -587,8 +546,7 @@
 			/* message printed inner oakley_validate_auth() */
 			goto end;
 		}
-		EVT_PUSH(iph1->local, iph1->remote, 
-		    EVTT_PEERPH1AUTH_FAILED, NULL);
+		evt_phase1(iph1, EVT_PHASE1_AUTH_FAILED, NULL);
 		isakmp_info_send_n1(iph1, ptype, NULL);
 		goto end;
 	}
@@ -616,13 +574,10 @@
 		VPTRINIT(iph1->dhpub_p);
 		VPTRINIT(iph1->nonce_p);
 		VPTRINIT(iph1->id_p);
-		oakley_delcert(iph1->cert_p);
-		iph1->cert_p = NULL;
-		oakley_delcert(iph1->crl_p);
-		iph1->crl_p = NULL;
+		VPTRINIT(iph1->cert_p);
+		VPTRINIT(iph1->crl_p);
 		VPTRINIT(iph1->sig_p);
-		oakley_delcert(iph1->cr_p);
-		iph1->cr_p = NULL;
+		VPTRINIT(iph1->cr_p);
 	}
 
 	return error;
@@ -669,15 +624,15 @@
 		goto end;
 	}
 
-	switch (AUTHMETHOD(iph1)) {
+	switch (iph1->approval->authmethod) {
 	case OAKLEY_ATTR_AUTH_METHOD_PSKEY:
 #ifdef ENABLE_HYBRID
-	case FICTIVE_AUTH_METHOD_XAUTH_PSKEY_I:
+	case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_I:
 	case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I:
 	case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_I:
-#endif  
+#endif
 		/* set HASH payload */
-		plist = isakmp_plist_append(plist, 
+		plist = isakmp_plist_append(plist,
 		    iph1->hash, ISAKMP_NPTYPE_HASH);
 		break;
 
@@ -700,11 +655,11 @@
 
 		/* add CERT payload if there */
 		if (need_cert)
-			plist = isakmp_plist_append(plist, 
-			    iph1->cert->pl, ISAKMP_NPTYPE_CERT);
+			plist = isakmp_plist_append(plist, iph1->cert,
+						    ISAKMP_NPTYPE_CERT);
 
 		/* add SIG payload */
-		plist = isakmp_plist_append(plist, 
+		plist = isakmp_plist_append(plist,
 		    iph1->sig, ISAKMP_NPTYPE_SIG);
 		break;
 
@@ -726,7 +681,7 @@
 			goto end;
 		}
 
-		plist = isakmp_plist_append(plist, 
+		plist = isakmp_plist_append(plist,
 		    gsshash, ISAKMP_NPTYPE_HASH);
 		break;
 #endif
@@ -737,26 +692,26 @@
 	if (NATT_AVAILABLE(iph1)) {
 		vchar_t *natd[2] = { NULL, NULL };
 
-		plog(LLV_INFO, LOCATION, 
+		plog(LLV_INFO, LOCATION,
 		    NULL, "Adding remote and local NAT-D payloads.\n");
 
 		if ((natd[0] = natt_hash_addr (iph1, iph1->remote)) == NULL) {
 			plog(LLV_ERROR, LOCATION, NULL,
-			    "NAT-D hashing failed for %s\n", 
+			    "NAT-D hashing failed for %s\n",
 			    saddr2str(iph1->remote));
 			goto end;
 		}
 
 		if ((natd[1] = natt_hash_addr (iph1, iph1->local)) == NULL) {
 			plog(LLV_ERROR, LOCATION, NULL,
-			    "NAT-D hashing failed for %s\n", 
+			    "NAT-D hashing failed for %s\n",
 			    saddr2str(iph1->local));
 			goto end;
 		}
 
-		plist = isakmp_plist_append(plist, 
+		plist = isakmp_plist_append(plist,
 		    natd[0], iph1->natt_options->payload_nat_d);
-		plist = isakmp_plist_append(plist, 
+		plist = isakmp_plist_append(plist,
 		    natd[1], iph1->natt_options->payload_nat_d);
 	}
 #endif
@@ -860,37 +815,7 @@
 				goto end;
 			break;
 		case ISAKMP_NPTYPE_VID:
-			vid_numeric = check_vendorid(pa->ptr);
-
-#ifdef ENABLE_NATT
-			if (iph1->rmconf->nat_traversal &&
-			    natt_vendorid(vid_numeric)) {
-				natt_handle_vendorid(iph1, vid_numeric);
-				break;
-			}
-#endif
-#ifdef ENABLE_HYBRID
-			switch (vid_numeric) {
-			case VENDORID_XAUTH:
-				iph1->mode_cfg->flags |= 
-				    ISAKMP_CFG_VENDORID_XAUTH;
-				break;
-
-			case VENDORID_UNITY:
-				iph1->mode_cfg->flags |= 
-				    ISAKMP_CFG_VENDORID_UNITY;
-				break;
-			default:
-				break;
-			}
-#endif
-#ifdef ENABLE_DPD
-			if (vid_numeric == VENDORID_DPD && iph1->rmconf->dpd) {
-				iph1->dpd_support=1;
-				plog(LLV_DEBUG, LOCATION, NULL,
-					 "remote supports DPD\n");
-			}
-#endif
+			vid_numeric = handle_vendorid(iph1, pa->ptr);
 #ifdef ENABLE_FRAG
 			if ((vid_numeric == VENDORID_FRAG) &&
 			    (vendorid_frag_cap(pa->ptr) & VENDORID_FRAG_AGG))
@@ -970,8 +895,7 @@
 		VPTRINIT(iph1->dhpub_p);
 		VPTRINIT(iph1->nonce_p);
 		VPTRINIT(iph1->id_p);
-		oakley_delcert(iph1->cr_p);
-		iph1->cr_p = NULL;
+		VPTRINIT(iph1->cr_p);
 	}
 
 	return error;
@@ -991,9 +915,7 @@
 	vchar_t *msg;
 {
 	struct payload_list *plist = NULL;
-	int need_cr = 0;
 	int need_cert = 0;
-	vchar_t *cr = NULL;
 	int error = -1;
 #ifdef ENABLE_HYBRID
 	vchar_t *xauth_vid = NULL;
@@ -1057,7 +979,7 @@
 		goto end;
 
 #ifdef HAVE_GSSAPI
-	if (RMAUTHMETHOD(iph1) == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB)
+	if (iph1->rmconf->proposal->authmethod == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB)
 		gssapi_get_rtoken(iph1, &gsslen);
 #endif
 
@@ -1073,19 +995,6 @@
 		goto end;
 	}
 
-	/* create CR if need */
-	if (iph1->rmconf->send_cr
-	 && oakley_needcr(iph1->approval->authmethod)
-	 && iph1->rmconf->peerscertfile == NULL) {
-		need_cr = 1;
-		cr = oakley_getcr(iph1);
-		if (cr == NULL) {
-			plog(LLV_ERROR, LOCATION, NULL,
-				"failed to get cr buffer.\n");
-			goto end;
-		}
-	}
-
 #ifdef ENABLE_NATT
 	/* Has the peer announced NAT-T? */
 	if (NATT_AVAILABLE(iph1)) {
@@ -1124,35 +1033,34 @@
 	}
 #endif
 
-	switch (AUTHMETHOD(iph1)) {
+	switch (iph1->approval->authmethod) {
 	case OAKLEY_ATTR_AUTH_METHOD_PSKEY:
 #ifdef ENABLE_HYBRID
 	case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_R:
 #endif
 		/* set SA payload to reply */
-		plist = isakmp_plist_append(plist, 
+		plist = isakmp_plist_append(plist,
 		    iph1->sa_ret, ISAKMP_NPTYPE_SA);
 
 		/* create isakmp KE payload */
-		plist = isakmp_plist_append(plist, 
+		plist = isakmp_plist_append(plist,
 		    iph1->dhpub, ISAKMP_NPTYPE_KE);
 
 		/* create isakmp NONCE payload */
-		plist = isakmp_plist_append(plist, 
+		plist = isakmp_plist_append(plist,
 		    iph1->nonce, ISAKMP_NPTYPE_NONCE);
 
 		/* create isakmp ID payload */
-		plist = isakmp_plist_append(plist, 
+		plist = isakmp_plist_append(plist,
 		    iph1->id, ISAKMP_NPTYPE_ID);
 
 		/* create isakmp HASH payload */
-		plist = isakmp_plist_append(plist, 
+		plist = isakmp_plist_append(plist,
 		    iph1->hash, ISAKMP_NPTYPE_HASH);
 
 		/* create isakmp CR payload if needed */
-		if (need_cr)
-			plist = isakmp_plist_append(plist, 
-			    cr, ISAKMP_NPTYPE_CR);
+		if (oakley_needcr(iph1->approval->authmethod))
+			plist = oakley_append_cr(plist, iph1);
 		break;
 	case OAKLEY_ATTR_AUTH_METHOD_DSSSIG:
 	case OAKLEY_ATTR_AUTH_METHOD_RSASIG:
@@ -1174,34 +1082,33 @@
 			need_cert = 1;
 
 		/* set SA payload to reply */
-		plist = isakmp_plist_append(plist, 
+		plist = isakmp_plist_append(plist,
 		    iph1->sa_ret, ISAKMP_NPTYPE_SA);
 
 		/* create isakmp KE payload */
-		plist = isakmp_plist_append(plist, 
+		plist = isakmp_plist_append(plist,
 		    iph1->dhpub, ISAKMP_NPTYPE_KE);
 
 		/* create isakmp NONCE payload */
-		plist = isakmp_plist_append(plist, 
+		plist = isakmp_plist_append(plist,
 		    iph1->nonce, ISAKMP_NPTYPE_NONCE);
 
 		/* add ID payload */
-		plist = isakmp_plist_append(plist, 
+		plist = isakmp_plist_append(plist,
 		    iph1->id, ISAKMP_NPTYPE_ID);
 
 		/* add CERT payload if there */
 		if (need_cert)
-			plist = isakmp_plist_append(plist, 
-			    iph1->cert->pl, ISAKMP_NPTYPE_CERT);
+			plist = isakmp_plist_append(plist, iph1->cert,
+						    ISAKMP_NPTYPE_CERT);
 
 		/* add SIG payload */
-		plist = isakmp_plist_append(plist, 
+		plist = isakmp_plist_append(plist,
 		    iph1->sig, ISAKMP_NPTYPE_SIG);
 
 		/* create isakmp CR payload if needed */
-		if (need_cr)
-			plist = isakmp_plist_append(plist, 
-			    cr, ISAKMP_NPTYPE_CR);
+		if (oakley_needcr(iph1->approval->authmethod))
+			plist = oakley_append_cr(plist, iph1);
 		break;
 
 	case OAKLEY_ATTR_AUTH_METHOD_RSAENC:
@@ -1219,9 +1126,9 @@
 				plog(LLV_ERROR, LOCATION, NULL,
 					"failed to wrap hash\n");
 				/*
-				 * This is probably due to the GSS 
-				 * roundtrips not being finished yet. 
-				 * Return this error in the hope that 
+				 * This is probably due to the GSS
+				 * roundtrips not being finished yet.
+				 * Return this error in the hope that
 				 * a fallback to main mode will be done.
 				 */
 				isakmp_info_send_n1(iph1,
@@ -1229,8 +1136,8 @@
 				goto end;
 			}
 			if (iph1->approval->gssid != NULL)
-				gss_sa = 
-				    ipsecdoi_setph1proposal(iph1->approval);  
+				gss_sa = ipsecdoi_setph1proposal(iph1->rmconf,
+								 iph1->approval);
 			else
 				gss_sa = iph1->sa_ret;
 
@@ -1238,28 +1145,32 @@
 				free_gss_sa = 1;
 
 			/* set SA payload to reply */
-			plist = isakmp_plist_append(plist, 
+			plist = isakmp_plist_append(plist,
 			    gss_sa, ISAKMP_NPTYPE_SA);
 
 			/* create isakmp KE payload */
-			plist = isakmp_plist_append(plist, 
+			plist = isakmp_plist_append(plist,
 			    iph1->dhpub, ISAKMP_NPTYPE_KE);
 
 			/* create isakmp NONCE payload */
-			plist = isakmp_plist_append(plist, 
+			plist = isakmp_plist_append(plist,
 			    iph1->nonce, ISAKMP_NPTYPE_NONCE);
 
 			/* create isakmp ID payload */
-			plist = isakmp_plist_append(plist, 
+			plist = isakmp_plist_append(plist,
 			    iph1->id, ISAKMP_NPTYPE_ID);
 
 			/* create GSS payload */
-			gssapi_get_token_to_send(iph1, &gsstoken);
-			plist = isakmp_plist_append(plist, 
+			if (gssapi_get_token_to_send(iph1, &gsstoken) < 0) {
+				plog(LLV_ERROR, LOCATION, NULL,
+				    "Failed to get gssapi token.\n");
+				goto end;
+			}
+			plist = isakmp_plist_append(plist,
 			    gsstoken, ISAKMP_NPTYPE_GSS);
 
 			/* create isakmp HASH payload */
-			plist = isakmp_plist_append(plist, 
+			plist = isakmp_plist_append(plist,
 			    gsshash, ISAKMP_NPTYPE_HASH);
 
 			/* append vendor id, if needed */
@@ -1275,7 +1186,7 @@
 			    "Cannot create Xauth vendor ID\n");
 			goto end;
 		}
-		plist = isakmp_plist_append(plist, 
+		plist = isakmp_plist_append(plist,
 		    xauth_vid, ISAKMP_NPTYPE_VID);
 	}
 
@@ -1285,7 +1196,7 @@
 			    "Cannot create Unity vendor ID\n");
 			goto end;
 		}
-		plist = isakmp_plist_append(plist, 
+		plist = isakmp_plist_append(plist,
 		    unity_vid, ISAKMP_NPTYPE_VID);
 	}
 #endif
@@ -1318,8 +1229,7 @@
 #endif
 
 	/* send the packet, add to the schedule to resend */
-	iph1->retry_counter = iph1->rmconf->retry_counter;
-	if (isakmp_ph1resend(iph1) == -1)
+	if (isakmp_ph1send(iph1) == -1)
 		goto end;
 
 	/* the sending message is added to the received-list. */
@@ -1334,8 +1244,6 @@
 	error = 0;
 
 end:
-	if (cr)
-		vfree(cr);
 #ifdef ENABLE_HYBRID
 	if (xauth_vid)
 		vfree(xauth_vid);
@@ -1378,9 +1286,7 @@
 	vchar_t *msg = NULL;
 	vchar_t *pbuf = NULL;
 	struct isakmp_parse_t *pa;
-	int error = -1;
-	int ptype;
-
+	int error = -1, ptype;
 #ifdef ENABLE_NATT
 	int natd_seq = 0;
 #endif
@@ -1418,7 +1324,7 @@
 			iph1->pl_hash = (struct isakmp_pl_hash *)pa->ptr;
 			break;
 		case ISAKMP_NPTYPE_VID:
-			(void)check_vendorid(pa->ptr);
+			handle_vendorid(iph1, pa->ptr);
 			break;
 		case ISAKMP_NPTYPE_CERT:
 			if (oakley_savecert(iph1, pa->ptr) < 0)
@@ -1429,7 +1335,9 @@
 				goto end;
 			break;
 		case ISAKMP_NPTYPE_N:
-			isakmp_check_notify(pa->ptr, iph1);
+			isakmp_log_notify(iph1,
+				(struct isakmp_pl_n *) pa->ptr,
+				"aggressive exchange");
 			break;
 
 #ifdef ENABLE_NATT
@@ -1440,20 +1348,20 @@
 			{
 				vchar_t *natd_received = NULL;
 				int natd_verified;
-				
+
 				if (isakmp_p2ph (&natd_received, pa->ptr) < 0)
 					goto end;
-				
+
 				if (natd_seq == 0)
 					iph1->natt_flags |= NAT_DETECTED;
-				
+
 				natd_verified = natt_compare_addr_hash (iph1,
 					natd_received, natd_seq++);
-				
+
 				plog (LLV_INFO, LOCATION, NULL, "NAT-D payload #%d %s\n",
 					natd_seq - 1,
 					natd_verified ? "verified" : "doesn't match");
-				
+
 				vfree (natd_received);
 				break;
 			}
@@ -1473,7 +1381,7 @@
 #ifdef ENABLE_NATT
 	if (NATT_AVAILABLE(iph1))
 		plog (LLV_INFO, LOCATION, NULL, "NAT %s %s%s\n",
-		      iph1->natt_flags & NAT_DETECTED ? 
+		      iph1->natt_flags & NAT_DETECTED ?
 		      		"detected:" : "not detected",
 		      iph1->natt_flags & NAT_DETECTED_ME ? "ME " : "",
 		      iph1->natt_flags & NAT_DETECTED_PEER ? "PEER" : "");
@@ -1486,8 +1394,7 @@
 			/* message printed inner oakley_validate_auth() */
 			goto end;
 		}
-		EVT_PUSH(iph1->local, iph1->remote, 
-		    EVTT_PEERPH1AUTH_FAILED, NULL);
+		evt_phase1(iph1, EVT_PHASE1_AUTH_FAILED, NULL);
 		isakmp_info_send_n1(iph1, ptype, NULL);
 		goto end;
 	}
@@ -1502,10 +1409,8 @@
 	if (msg)
 		vfree(msg);
 	if (error) {
-		oakley_delcert(iph1->cert_p);
-		iph1->cert_p = NULL;
-		oakley_delcert(iph1->crl_p);
-		iph1->crl_p = NULL;
+		VPTRINIT(iph1->cert_p);
+		VPTRINIT(iph1->crl_p);
 		VPTRINIT(iph1->sig_p);
 	}
 
diff --git a/src/racoon/isakmp_base.c b/src/racoon/isakmp_base.c
index 3ac0b72..f37d51e 100644
--- a/src/racoon/isakmp_base.c
+++ b/src/racoon/isakmp_base.c
@@ -1,4 +1,4 @@
-/*	$NetBSD: isakmp_base.c,v 1.7 2006/10/02 21:51:33 manu Exp $	*/
+/*	$NetBSD: isakmp_base.c,v 1.12 2009/03/12 10:57:26 tteras Exp $	*/
 
 /*	$KAME: isakmp_base.c,v 1.49 2003/11/13 02:30:20 sakane Exp $	*/
 
@@ -143,7 +143,8 @@
 		goto end;
 
 	/* create SA payload for my proposal */
-	iph1->sa = ipsecdoi_setph1proposal(iph1->rmconf->proposal);
+	iph1->sa = ipsecdoi_setph1proposal(iph1->rmconf,
+					   iph1->rmconf->proposal);
 	if (iph1->sa == NULL)
 		goto end;
 
@@ -154,8 +155,8 @@
 
 #ifdef ENABLE_HYBRID
         /* Do we need Xauth VID? */
-        switch (RMAUTHMETHOD(iph1)) {
-        case FICTIVE_AUTH_METHOD_XAUTH_PSKEY_I:
+        switch (iph1->rmconf->proposal->authmethod) {
+        case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_I:
         case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I:
         case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_I:
         case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_I:
@@ -250,8 +251,7 @@
 #endif
 
 	/* send the packet, add to the schedule to resend */
-	iph1->retry_counter = iph1->rmconf->retry_counter;
-	if (isakmp_ph1resend(iph1) == -1)
+	if (isakmp_ph1send(iph1) == -1)
 		goto end;
 
 	iph1->status = PHASE1ST_MSG1SENT;
@@ -297,7 +297,6 @@
 	struct isakmp_parse_t *pa;
 	vchar_t *satmp = NULL;
 	int error = -1;
-	int vid_numeric;
 #ifdef ENABLE_HYBRID
 	vchar_t *unity_vid;
 	vchar_t *xauth_vid;
@@ -342,34 +341,7 @@
 				goto end;
 			break;
 		case ISAKMP_NPTYPE_VID:
-			vid_numeric = check_vendorid(pa->ptr);
-#ifdef ENABLE_NATT
-			if (iph1->rmconf->nat_traversal && natt_vendorid(vid_numeric))
-			  natt_handle_vendorid(iph1, vid_numeric);
-#endif
-#ifdef ENABLE_HYBRID
-			switch (vid_numeric) {
-			case VENDORID_XAUTH:
-				iph1->mode_cfg->flags |=
-				    ISAKMP_CFG_VENDORID_XAUTH;
-				break;
-
-			case VENDORID_UNITY:
-				iph1->mode_cfg->flags |=
-				    ISAKMP_CFG_VENDORID_UNITY;
-				break;
-
-			default:
-				break;
-			}
-#endif
-#ifdef ENABLE_DPD
-			if (vid_numeric == VENDORID_DPD && iph1->rmconf->dpd) {
-				iph1->dpd_support=1;
-				plog(LLV_DEBUG, LOCATION, NULL,
-					 "remote supports DPD\n");
-			}
-#endif
+			handle_vendorid(iph1, pa->ptr);
 			break;
 		default:
 			/* don't send information, see ident_r1recv() */
@@ -462,7 +434,7 @@
 		goto end;
 
 	/* generate SKEYID to compute hash if not signature mode */
-	switch (AUTHMETHOD(iph1)) {
+	switch (iph1->approval->authmethod) {
 	case OAKLEY_ATTR_AUTH_METHOD_RSASIG:
 	case OAKLEY_ATTR_AUTH_METHOD_DSSSIG:
 #ifdef ENABLE_HYBRID
@@ -484,10 +456,10 @@
 	iph1->hash = oakley_ph1hash_base_i(iph1, GENERATE);
 	if (iph1->hash == NULL)
 		goto end;
-	switch (AUTHMETHOD(iph1)) {
+	switch (iph1->approval->authmethod) {
 	case OAKLEY_ATTR_AUTH_METHOD_PSKEY:
 #ifdef ENABLE_HYBRID
-	case FICTIVE_AUTH_METHOD_XAUTH_PSKEY_I:
+	case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_I:
 	case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I:
 	case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_I:
 #endif
@@ -521,16 +493,16 @@
 			need_cert = 1;
 
 		/* create isakmp KE payload */
-		plist = isakmp_plist_append(plist, 
-		    iph1->dhpub, ISAKMP_NPTYPE_KE);
+		plist = isakmp_plist_append(plist, iph1->dhpub,
+					    ISAKMP_NPTYPE_KE);
 
 		/* add CERT payload if there */
 		if (need_cert)
-			plist = isakmp_plist_append(plist, 
-			    iph1->cert->pl, ISAKMP_NPTYPE_CERT);
+			plist = isakmp_plist_append(plist,  iph1->cert,
+						    ISAKMP_NPTYPE_CERT);
 
 		/* add SIG payload */
-		plist = isakmp_plist_append(plist, 
+		plist = isakmp_plist_append(plist,
 		    iph1->sig, ISAKMP_NPTYPE_SIG);
 
 		break;
@@ -579,8 +551,7 @@
 #endif
 
 	/* send the packet, add to the schedule to resend */
-	iph1->retry_counter = iph1->rmconf->retry_counter;
-	if (isakmp_ph1resend(iph1) == -1)
+	if (isakmp_ph1send(iph1) == -1)
 		goto end;
 
 	/* the sending message is added to the received-list. */
@@ -614,8 +585,7 @@
 {
 	vchar_t *pbuf = NULL;
 	struct isakmp_parse_t *pa;
-	int error = -1;
-	int ptype;
+	int error = -1, ptype;
 #ifdef ENABLE_NATT
 	vchar_t	*natd_received;
 	int natd_seq = 0, natd_verified;
@@ -654,7 +624,7 @@
 				goto end;
 			break;
 		case ISAKMP_NPTYPE_VID:
-			(void)check_vendorid(pa->ptr);
+			handle_vendorid(iph1, pa->ptr);
 			break;
 
 #ifdef ENABLE_NATT
@@ -716,8 +686,7 @@
 			/* message printed inner oakley_validate_auth() */
 			goto end;
 		}
-		EVT_PUSH(iph1->local, iph1->remote, 
-		    EVTT_PEERPH1AUTH_FAILED, NULL);
+		evt_phase1(iph1, EVT_PHASE1_AUTH_FAILED, NULL);
 		isakmp_info_send_n1(iph1, ptype, NULL);
 		goto end;
 	}
@@ -728,7 +697,7 @@
 		goto end;
 
 	/* generate SKEYID to compute hash if signature mode */
-	switch (AUTHMETHOD(iph1)) {
+	switch (iph1->approval->authmethod) {
 	case OAKLEY_ATTR_AUTH_METHOD_RSASIG:
 	case OAKLEY_ATTR_AUTH_METHOD_DSSSIG:
 #ifdef ENABLE_HYBRID
@@ -769,10 +738,8 @@
 
 	if (error) {
 		VPTRINIT(iph1->dhpub_p);
-		oakley_delcert(iph1->cert_p);
-		iph1->cert_p = NULL;
-		oakley_delcert(iph1->crl_p);
-		iph1->crl_p = NULL;
+		VPTRINIT(iph1->cert_p);
+		VPTRINIT(iph1->crl_p);
 		VPTRINIT(iph1->sig_p);
 	}
 
@@ -829,9 +796,6 @@
 	}
 
 	/* validate the type of next payload */
-	/*
-	 * NOTE: XXX even if multiple VID, we'll silently ignore those.
-	 */
 	pbuf = isakmp_parse(msg);
 	if (pbuf == NULL)
 		goto end;
@@ -863,39 +827,12 @@
 				goto end;
 			break;
 		case ISAKMP_NPTYPE_VID:
-			vid_numeric = check_vendorid(pa->ptr);
-#ifdef ENABLE_NATT
-			if (iph1->rmconf->nat_traversal && natt_vendorid(vid_numeric))
-				natt_handle_vendorid(iph1, vid_numeric);
-#endif
+			vid_numeric = handle_vendorid(iph1, pa->ptr);
 #ifdef ENABLE_FRAG
 			if ((vid_numeric == VENDORID_FRAG) &&
 			    (vendorid_frag_cap(pa->ptr) & VENDORID_FRAG_BASE))
 				iph1->frag = 1;
 #endif
-#ifdef ENABLE_HYBRID
-			switch (vid_numeric) {
-			case VENDORID_XAUTH:
-				iph1->mode_cfg->flags |=
-				    ISAKMP_CFG_VENDORID_XAUTH;
-				break;
-
-			case VENDORID_UNITY:
-				iph1->mode_cfg->flags |=
-				    ISAKMP_CFG_VENDORID_UNITY;
-				break;
-
-			default:
-				break;
-			}
-#endif
-#ifdef ENABLE_DPD
-			if (vid_numeric == VENDORID_DPD && iph1->rmconf->dpd) {
-				iph1->dpd_support=1;
-				plog(LLV_DEBUG, LOCATION, NULL,
-					 "remote supports DPD\n");
-			}
-#endif 
 			break;
 		default:
 			/* don't send information, see ident_r1recv() */
@@ -1073,8 +1010,7 @@
 #endif
 
 	/* send the packet, add to the schedule to resend */
-	iph1->retry_counter = iph1->rmconf->retry_counter;
-	if (isakmp_ph1resend(iph1) == -1) {
+	if (isakmp_ph1send(iph1) == -1) {
 		iph1 = NULL;
 		goto end;
 	}
@@ -1130,8 +1066,7 @@
 {
 	vchar_t *pbuf = NULL;
 	struct isakmp_parse_t *pa;
-	int error = -1;
-	int ptype;
+	int error = -1, ptype;
 #ifdef ENABLE_NATT
 	int natd_seq = 0;
 #endif
@@ -1171,7 +1106,7 @@
 				goto end;
 			break;
 		case ISAKMP_NPTYPE_VID:
-			(void)check_vendorid(pa->ptr);
+			handle_vendorid(iph1, pa->ptr);
 			break;
 
 #ifdef ENABLE_NATT
@@ -1242,8 +1177,7 @@
 			/* message printed inner oakley_validate_auth() */
 			goto end;
 		}
-		EVT_PUSH(iph1->local, iph1->remote, 
-		    EVTT_PEERPH1AUTH_FAILED, NULL);
+		evt_phase1(iph1, EVT_PHASE1_AUTH_FAILED, NULL);
 		isakmp_info_send_n1(iph1, ptype, NULL);
 		goto end;
 	}
@@ -1258,10 +1192,8 @@
 
 	if (error) {
 		VPTRINIT(iph1->dhpub_p);
-		oakley_delcert(iph1->cert_p);
-		iph1->cert_p = NULL;
-		oakley_delcert(iph1->crl_p);
-		iph1->crl_p = NULL;
+		VPTRINIT(iph1->cert_p);
+		VPTRINIT(iph1->crl_p);
 		VPTRINIT(iph1->sig_p);
 	}
 
@@ -1294,7 +1226,7 @@
 
 	/* generate HASH to send */
 	plog(LLV_DEBUG, LOCATION, NULL, "generate HASH_I\n");
-	switch (AUTHMETHOD(iph1)) {
+	switch (iph1->approval->authmethod) {
 	case OAKLEY_ATTR_AUTH_METHOD_PSKEY:
 #ifdef ENABLE_HYBRID
 	case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_R:
@@ -1329,7 +1261,7 @@
 	if (iph1->hash == NULL)
 		goto end;
 
-	switch (AUTHMETHOD(iph1)) {
+	switch (iph1->approval->authmethod) {
 	case OAKLEY_ATTR_AUTH_METHOD_PSKEY:
 #ifdef ENABLE_HYBRID
 	case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_R:
@@ -1369,16 +1301,17 @@
 			need_cert = 1;
 
 		/* create isakmp KE payload */
-		plist = isakmp_plist_append(plist, 
-		    iph1->dhpub, ISAKMP_NPTYPE_KE);
+		plist = isakmp_plist_append(plist, iph1->dhpub,
+					    ISAKMP_NPTYPE_KE);
 
 		/* add CERT payload if there */
 		if (need_cert)
-			plist = isakmp_plist_append(plist, 
-			    iph1->cert->pl, ISAKMP_NPTYPE_CERT);
+			plist = isakmp_plist_append(plist, iph1->cert,
+						    ISAKMP_NPTYPE_CERT);
+
 		/* add SIG payload */
-		plist = isakmp_plist_append(plist, 
-		    iph1->sig, ISAKMP_NPTYPE_SIG);
+		plist = isakmp_plist_append(plist, iph1->sig,
+					    ISAKMP_NPTYPE_SIG);
 		break;
 #ifdef HAVE_GSSAPI
 	case OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB:
diff --git a/src/racoon/isakmp_cfg.c b/src/racoon/isakmp_cfg.c
index 52862c4..0ec30ee 100644
--- a/src/racoon/isakmp_cfg.c
+++ b/src/racoon/isakmp_cfg.c
@@ -1,4 +1,4 @@
-/*	$NetBSD: isakmp_cfg.c,v 1.12.6.4 2008/11/27 15:25:20 vanhu Exp $	*/
+/*	$NetBSD: isakmp_cfg.c,v 1.24 2010/09/21 13:14:17 vanhu Exp $	*/
 
 /* Id: isakmp_cfg.c,v 1.55 2006/08/22 18:17:17 manubsd Exp */
 
@@ -38,7 +38,7 @@
 #include <sys/socket.h>
 #include <sys/queue.h>
 
-#include <utmp.h>
+#include <utmpx.h>
 #if defined(__APPLE__) && defined(__MACH__)
 #include <util.h>
 #endif
@@ -114,6 +114,8 @@
 #endif
 static vchar_t *isakmp_cfg_addr4(struct ph1handle *, 
 				 struct isakmp_data *, in_addr_t *);
+static vchar_t *isakmp_cfg_addrnet4(struct ph1handle *, 
+				 struct isakmp_data *, in_addr_t *, in_addr_t *);
 static void isakmp_cfg_getaddr4(struct isakmp_data *, struct in_addr *);
 static vchar_t *isakmp_cfg_addr4_list(struct ph1handle *,
 				      struct isakmp_data *, in_addr_t *, int);
@@ -446,8 +448,8 @@
 	
 	if ((iph1->status == PHASE1ST_ESTABLISHED) && 
 	    iph1->rmconf->mode_cfg) {
-		switch (AUTHMETHOD(iph1)) {
-		case FICTIVE_AUTH_METHOD_XAUTH_PSKEY_I:
+		switch (iph1->approval->authmethod) {
+		case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_I:
 		case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I:
 		/* Unimplemented */
 		case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_I: 
@@ -473,8 +475,7 @@
 			    "Cannot allocate memory: %s\n", strerror(errno));
 		} else {
 			memcpy(buf->v, attrpl + 1, buf->l);
-			EVT_PUSH(iph1->local, iph1->remote, 
-			    EVTT_ISAKMP_CFG_DONE, buf);
+			evt_phase1(iph1, EVT_PHASE1_MODE_CFG, buf);
 			vfree(buf);
 		}
 	}
@@ -629,7 +630,7 @@
 	    ISAKMP_NPTYPE_ATTR, ISAKMP_FLAG_E, 0);
 
 	if (iph1->status == PHASE1ST_ESTABLISHED) {
-		switch (AUTHMETHOD(iph1)) {
+		switch (iph1->approval->authmethod) {
 		case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_R:
 		case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_R:
 		/* Unimplemented */
@@ -731,7 +732,8 @@
 	    ISAKMP_NPTYPE_ATTR, ISAKMP_FLAG_E, 0);
 
 	if (iph1->mode_cfg->flags & ISAKMP_CFG_DELETE_PH1) {
-		if (iph1->status == PHASE1ST_ESTABLISHED)
+		if (iph1->status == PHASE1ST_ESTABLISHED ||
+		    iph1->status == PHASE1ST_DYING)
 			isakmp_info_send_d1(iph1);
 		remph1(iph1);
 		delph1(iph1);
@@ -901,8 +903,15 @@
 		break;
 
 	case INTERNAL_IP4_SUBNET:
-		return isakmp_cfg_addr4(iph1, 
-		    attr, &isakmp_cfg_config.network4);
+		if(isakmp_cfg_config.splitnet_count > 0){
+			return isakmp_cfg_addrnet4(iph1, attr,
+						    &isakmp_cfg_config.splitnet_list->network.addr4.s_addr,
+						    &isakmp_cfg_config.splitnet_list->network.mask4.s_addr);
+		}else{
+			plog(LLV_INFO, LOCATION, NULL,
+			     "%s requested but no splitnet in configuration\n",
+			     s_isakmp_cfg_type(type));
+		}
 		break;
 
 	default:
@@ -1042,6 +1051,36 @@
 }
 
 static vchar_t *
+isakmp_cfg_addrnet4(iph1, attr, addr, mask)
+	struct ph1handle *iph1;
+	struct isakmp_data *attr;
+	in_addr_t *addr;
+	in_addr_t *mask;
+{
+	vchar_t *buffer;
+	struct isakmp_data *new;
+	size_t len;
+	in_addr_t netbuff[2];
+
+	len = sizeof(netbuff);
+	if ((buffer = vmalloc(sizeof(*attr) + len)) == NULL) {
+		plog(LLV_ERROR, LOCATION, NULL, "Cannot allocate memory\n");
+		return NULL;
+	}
+
+	new = (struct isakmp_data *)buffer->v;
+
+	new->type = attr->type;
+	new->lorv = htons(len);
+	netbuff[0]=*addr;
+	netbuff[1]=*mask;
+	memcpy(new + 1, netbuff, len);
+	
+	return buffer;
+}
+
+
+static vchar_t *
 isakmp_cfg_addr4_list(iph1, attr, addr, nbr)
 	struct ph1handle *iph1;
 	struct isakmp_data *attr;
@@ -1127,7 +1166,7 @@
 	struct isakmp_cfg_state *ics = iph1->mode_cfg;
 
 	/* Check if phase 1 is established */
-	if ((iph1->status != PHASE1ST_ESTABLISHED) || 
+	if ((iph1->status < PHASE1ST_ESTABLISHED) ||
 	    (iph1->local == NULL) ||
 	    (iph1->remote == NULL)) {
 		plog(LLV_ERROR, LOCATION, NULL, 
@@ -1151,16 +1190,6 @@
 		goto end;
 	}
 
-#if (!defined(ENABLE_NATT)) || (defined(BROKEN_NATT))
-	if (set_port(iph2->dst, 0) == NULL ||
-	    set_port(iph2->src, 0) == NULL) {
-		plog(LLV_ERROR, LOCATION, NULL,
-		     "invalid family: %d\n", iph1->remote->sa_family);
-		delph2(iph2);
-		goto end;
-	}
-#endif
-	iph2->ph1 = iph1;
 	iph2->side = INITIATOR;
 	iph2->status = PHASE2ST_START;
 
@@ -1179,7 +1208,7 @@
 		}
 
 		/* generate HASH(1) */
-		hash = oakley_compute_hash1(iph2->ph1, iph2->msgid, payload);
+		hash = oakley_compute_hash1(iph1, iph2->msgid, payload);
 		if (hash == NULL) {
 			delph2(iph2);
 			goto end;
@@ -1278,7 +1307,6 @@
 	if (iph2->sendbuf != NULL)
 		vfree(iph2->sendbuf);
 
-	unbindph12(iph2);
 	remph2(iph2);
 	delph2(iph2);
 end:
@@ -1492,24 +1520,6 @@
 	struct ph1handle *iph1;
 	int inout;
 {
-	/* For first time use, initialize Radius */
-	if (radius_acct_state == NULL) {
-		if ((radius_acct_state = rad_acct_open()) == NULL) {
-			plog(LLV_ERROR, LOCATION, NULL,
-			    "Cannot init librradius\n");
-			return -1;
-		}
-
-		if (rad_config(radius_acct_state, NULL) != 0) {
-			 plog(LLV_ERROR, LOCATION, NULL,
-			     "Cannot open librarius config file: %s\n",
-			     rad_strerror(radius_acct_state));
-			  rad_close(radius_acct_state);
-			  radius_acct_state = NULL;
-			  return -1;
-		}
-	}
-
 	if (rad_create_request(radius_acct_state, 
 	    RAD_ACCOUNTING_REQUEST) != 0) {
 		plog(LLV_ERROR, LOCATION, NULL,
@@ -1651,8 +1661,7 @@
 	int inout;
 {
 	int error = 0;
-	struct utmp ut;
-	char term[UT_LINESIZE];
+	struct utmpx ut;
 	char addr[NI_MAXHOST];
 	
 	if (usr == NULL || usr[0]=='\0') {
@@ -1661,36 +1670,33 @@
 		return -1;
 	}
 
-	sprintf(term, TERMSPEC, port);
+	memset(&ut, 0, sizeof ut);
+	gettimeofday((struct timeval *)&ut.ut_tv, NULL);
+	snprintf(ut.ut_id, sizeof ut.ut_id, TERMSPEC, port);
 
 	switch (inout) {
 	case ISAKMP_CFG_LOGIN:
-		strncpy(ut.ut_name, usr, UT_NAMESIZE);
-		ut.ut_name[UT_NAMESIZE - 1] = '\0';
-
-		strncpy(ut.ut_line, term, UT_LINESIZE);
-		ut.ut_line[UT_LINESIZE - 1] = '\0';
+		ut.ut_type = USER_PROCESS;
+		strncpy(ut.ut_user, usr, sizeof ut.ut_user);
 
 		GETNAMEINFO_NULL(raddr, addr);
-		strncpy(ut.ut_host, addr, UT_HOSTSIZE);
-		ut.ut_host[UT_HOSTSIZE - 1] = '\0';
+		strncpy(ut.ut_host, addr, sizeof ut.ut_host);
 
-		ut.ut_time = time(NULL);
- 
 		plog(LLV_INFO, LOCATION, NULL,
 			"Accounting : '%s' logging on '%s' from %s.\n",
-			ut.ut_name, ut.ut_line, ut.ut_host);
+			ut.ut_user, ut.ut_id, addr);
 
-		login(&ut);
+		pututxline(&ut);
 
 		break;
 	case ISAKMP_CFG_LOGOUT:	
+		ut.ut_type = DEAD_PROCESS;
 
 		plog(LLV_INFO, LOCATION, NULL,
 			"Accounting : '%s' unlogging from '%s'.\n",
-			usr, term);
+			usr, ut.ut_id);
 
-		logout(term);
+		pututxline(&ut);
 
 		break;
 	default:
@@ -1865,6 +1871,7 @@
 	char addrstr[IP_MAX];
 	char addrlist[IP_MAX * MAXNS + MAXNS];
 	char *splitlist = addrlist;
+	char *splitlist_cidr;
 	char defdom[MAXPATHLEN + 1];
 	int cidr, tmp;
 	char cidrstr[4];
@@ -2005,10 +2012,14 @@
 	}
 
 	/* Split networks */
-	if (iph1->mode_cfg->flags & ISAKMP_CFG_GOT_SPLIT_INCLUDE)
-		splitlist = splitnet_list_2str(iph1->mode_cfg->split_include);
-	else {
+	if (iph1->mode_cfg->flags & ISAKMP_CFG_GOT_SPLIT_INCLUDE) {
+		splitlist = 
+		    splitnet_list_2str(iph1->mode_cfg->split_include, NETMASK);
+		splitlist_cidr = 
+		    splitnet_list_2str(iph1->mode_cfg->split_include, CIDR);
+	} else {
 		splitlist = addrlist;
+		splitlist_cidr = addrlist;
 		addrlist[0] = '\0';
 	}
 
@@ -2016,13 +2027,25 @@
 		plog(LLV_ERROR, LOCATION, NULL, "Cannot set SPLIT_INCLUDE\n");
 		return -1;
 	}
+	if (script_env_append(envp, envc, 
+	    "SPLIT_INCLUDE_CIDR", splitlist_cidr) != 0) {
+		plog(LLV_ERROR, LOCATION, NULL,
+		     "Cannot set SPLIT_INCLUDE_CIDR\n");
+		return -1;
+	}
 	if (splitlist != addrlist)
 		racoon_free(splitlist);
+	if (splitlist_cidr != addrlist)
+		racoon_free(splitlist_cidr);
 
-	if (iph1->mode_cfg->flags & ISAKMP_CFG_GOT_SPLIT_LOCAL)
-		splitlist = splitnet_list_2str(iph1->mode_cfg->split_local);
-	else {
+	if (iph1->mode_cfg->flags & ISAKMP_CFG_GOT_SPLIT_LOCAL) {
+		splitlist =
+		    splitnet_list_2str(iph1->mode_cfg->split_local, NETMASK);
+		splitlist_cidr =
+		    splitnet_list_2str(iph1->mode_cfg->split_local, CIDR);
+	} else {
 		splitlist = addrlist;
+		splitlist_cidr = addrlist;
 		addrlist[0] = '\0';
 	}
 
@@ -2030,8 +2053,16 @@
 		plog(LLV_ERROR, LOCATION, NULL, "Cannot set SPLIT_LOCAL\n");
 		return -1;
 	}
+	if (script_env_append(envp, envc,
+	    "SPLIT_LOCAL_CIDR", splitlist_cidr) != 0) {
+		plog(LLV_ERROR, LOCATION, NULL,
+		     "Cannot set SPLIT_LOCAL_CIDR\n");
+		return -1;
+	}
 	if (splitlist != addrlist)
 		racoon_free(splitlist);
+	if (splitlist_cidr != addrlist)
+		racoon_free(splitlist_cidr);
 	
 	return 0;
 }
diff --git a/src/racoon/isakmp_frag.c b/src/racoon/isakmp_frag.c
index 6fac6a2..ebba34b 100644
--- a/src/racoon/isakmp_frag.c
+++ b/src/racoon/isakmp_frag.c
@@ -1,4 +1,4 @@
-/*	$NetBSD: isakmp_frag.c,v 1.4.6.1 2009/04/22 11:25:35 tteras Exp $	*/
+/*	$NetBSD: isakmp_frag.c,v 1.5 2009/04/22 11:24:20 tteras Exp $	*/
 
 /* Id: isakmp_frag.c,v 1.4 2004/11/13 17:31:36 manubsd Exp */
 
diff --git a/src/racoon/isakmp_ident.c b/src/racoon/isakmp_ident.c
index 1e00dc4..a9c3a01 100644
--- a/src/racoon/isakmp_ident.c
+++ b/src/racoon/isakmp_ident.c
@@ -1,11 +1,11 @@
-/*	$NetBSD: isakmp_ident.c,v 1.6 2006/10/02 21:41:59 manu Exp $	*/
+/*	$NetBSD: isakmp_ident.c,v 1.13 2009/09/18 10:31:11 tteras Exp $	*/
 
 /* Id: isakmp_ident.c,v 1.21 2006/04/06 16:46:08 manubsd Exp */
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
  * All rights reserved.
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
@@ -17,7 +17,7 @@
  * 3. Neither the name of the project nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
- * 
+ *
  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@@ -86,12 +86,13 @@
 #include "isakmp_xauth.h"
 #include "isakmp_cfg.h"
 #endif
-#ifdef ENABLE_FRAG 
+#ifdef ENABLE_FRAG
 #include "isakmp_frag.h"
 #endif
 
 static vchar_t *ident_ir2mx __P((struct ph1handle *));
 static vchar_t *ident_ir3mx __P((struct ph1handle *));
+static int ident_recv_n __P((struct ph1handle *, struct isakmp_gen *));
 
 /* %%%
  * begin Identity Protection Mode as initiator.
@@ -114,13 +115,13 @@
 	vchar_t *vid_natt[MAX_NATT_VID_COUNT] = { NULL };
 	int i;
 #endif
-#ifdef ENABLE_HYBRID  
+#ifdef ENABLE_HYBRID
 	vchar_t *vid_xauth = NULL;
 	vchar_t *vid_unity = NULL;
 #endif
-#ifdef ENABLE_FRAG 
+#ifdef ENABLE_FRAG
 	vchar_t *vid_frag = NULL;
-#endif 
+#endif
 #ifdef ENABLE_DPD
 	vchar_t *vid_dpd = NULL;
 #endif
@@ -141,7 +142,8 @@
 	isakmp_newcookie((caddr_t)&iph1->index, iph1->remote, iph1->local);
 
 	/* create SA payload for my proposal */
-	iph1->sa = ipsecdoi_setph1proposal(iph1->rmconf->proposal);
+	iph1->sa = ipsecdoi_setph1proposal(iph1->rmconf,
+					   iph1->rmconf->proposal);
 	if (iph1->sa == NULL)
 		goto end;
 
@@ -150,13 +152,13 @@
 
 #ifdef ENABLE_NATT
 	/* set VID payload for NAT-T if NAT-T support allowed in the config file */
-	if (iph1->rmconf->nat_traversal) 
+	if (iph1->rmconf->nat_traversal)
 		plist = isakmp_plist_append_natt_vids(plist, vid_natt);
 #endif
 #ifdef ENABLE_HYBRID
 	/* Do we need Xauth VID? */
-	switch (RMAUTHMETHOD(iph1)) {
-	case FICTIVE_AUTH_METHOD_XAUTH_PSKEY_I:
+	switch (iph1->rmconf->proposal->authmethod) {
+	case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_I:
 	case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I:
 	case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_I:
 	case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_I:
@@ -169,12 +171,12 @@
 		else
 			plist = isakmp_plist_append(plist,
 			    vid_xauth, ISAKMP_NPTYPE_VID);
-			
+
 		if ((vid_unity = set_vendorid(VENDORID_UNITY)) == NULL)
 			plog(LLV_ERROR, LOCATION, NULL,
 			     "Unity vendor ID generation failed\n");
 		else
-                	plist = isakmp_plist_append(plist,
+			plist = isakmp_plist_append(plist,
 			    vid_unity, ISAKMP_NPTYPE_VID);
 		break;
 	default:
@@ -189,7 +191,7 @@
 		} else {
 			vid_frag = isakmp_frag_addcap(vid_frag,
 			    VENDORID_FRAG_IDENT);
-			plist = isakmp_plist_append(plist, 
+			plist = isakmp_plist_append(plist,
 			    vid_frag, ISAKMP_NPTYPE_VID);
 		}
 	}
@@ -210,8 +212,7 @@
 #endif
 
 	/* send the packet, add to the schedule to resend */
-	iph1->retry_counter = iph1->rmconf->retry_counter;
-	if (isakmp_ph1resend(iph1) == -1)
+	if (isakmp_ph1send(iph1) == -1)
 		goto end;
 
 	iph1->status = PHASE1ST_MSG1SENT;
@@ -220,9 +221,9 @@
 
 end:
 #ifdef ENABLE_FRAG
-	if (vid_frag) 
+	if (vid_frag)
 		vfree(vid_frag);
-#endif  
+#endif
 #ifdef ENABLE_NATT
 	for (i = 0; i < MAX_NATT_VID_COUNT && vid_natt[i] != NULL; i++)
 		vfree(vid_natt[i]);
@@ -257,7 +258,6 @@
 	struct isakmp_parse_t *pa;
 	vchar_t *satmp = NULL;
 	int error = -1;
-	int vid_numeric;
 
 	/* validity check */
 	if (iph1->status != PHASE1ST_MSG1SENT) {
@@ -299,31 +299,7 @@
 
 		switch (pa->type) {
 		case ISAKMP_NPTYPE_VID:
-			vid_numeric = check_vendorid(pa->ptr);
-#ifdef ENABLE_NATT
-			if (iph1->rmconf->nat_traversal && natt_vendorid(vid_numeric))
-			  natt_handle_vendorid(iph1, vid_numeric);
-#endif
-#ifdef ENABLE_HYBRID
-			switch (vid_numeric) {
-			case VENDORID_XAUTH:
-				iph1->mode_cfg->flags |=
-				    ISAKMP_CFG_VENDORID_XAUTH;
-				break;
-	
-			case VENDORID_UNITY:
-				iph1->mode_cfg->flags |=
-				    ISAKMP_CFG_VENDORID_UNITY;
-				break;
-	
-			default:
-				break;
-			}
-#endif  
-#ifdef ENABLE_DPD
-			if (vid_numeric == VENDORID_DPD && iph1->rmconf->dpd)
-				iph1->dpd_support=1;
-#endif
+			handle_vendorid(iph1, pa->ptr);
 			break;
 		default:
 			/* don't send information, see ident_r1recv() */
@@ -401,7 +377,7 @@
 		goto end;
 
 #ifdef HAVE_GSSAPI
-	if (AUTHMETHOD(iph1) == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB &&
+	if (iph1->approval->authmethod == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB &&
 	    gssapi_get_itoken(iph1, NULL) < 0)
 		goto end;
 #endif
@@ -416,8 +392,7 @@
 #endif
 
 	/* send the packet, add to the schedule to resend */
-	iph1->retry_counter = iph1->rmconf->retry_counter;
-	if (isakmp_ph1resend(iph1) == -1)
+	if (isakmp_ph1send(iph1) == -1)
 		goto end;
 
 	/* the sending message is added to the received-list. */
@@ -485,7 +460,7 @@
 				goto end;
 			break;
 		case ISAKMP_NPTYPE_VID:
-			(void)check_vendorid(pa->ptr);
+			handle_vendorid(iph1, pa->ptr);
 			break;
 		case ISAKMP_NPTYPE_CR:
 			if (oakley_savecr(iph1, pa->ptr) < 0)
@@ -507,21 +482,21 @@
 				natd_received = NULL;
 				if (isakmp_p2ph (&natd_received, pa->ptr) < 0)
 					goto end;
-                        
+
 				/* set both bits first so that we can clear them
 				   upon verifying hashes */
 				if (natd_seq == 0)
 					iph1->natt_flags |= NAT_DETECTED;
-                        
-				/* this function will clear appropriate bits bits 
+
+				/* this function will clear appropriate bits bits
 				   from iph1->natt_flags */
 				natd_verified = natt_compare_addr_hash (iph1,
 					natd_received, natd_seq++);
-                        
+
 				plog (LLV_INFO, LOCATION, NULL, "NAT-D payload #%d %s\n",
 					natd_seq - 1,
 					natd_verified ? "verified" : "doesn't match");
-                        
+
 				vfree (natd_received);
 				break;
 			}
@@ -541,7 +516,7 @@
 #ifdef ENABLE_NATT
 	if (NATT_AVAILABLE(iph1)) {
 		plog (LLV_INFO, LOCATION, NULL, "NAT %s %s%s\n",
-		      iph1->natt_flags & NAT_DETECTED ? 
+		      iph1->natt_flags & NAT_DETECTED ?
 		      		"detected:" : "not detected",
 		      iph1->natt_flags & NAT_DETECTED_ME ? "ME " : "",
 		      iph1->natt_flags & NAT_DETECTED_PEER ? "PEER" : "");
@@ -577,8 +552,7 @@
 		VPTRINIT(iph1->dhpub_p);
 		VPTRINIT(iph1->nonce_p);
 		VPTRINIT(iph1->id_p);
-		oakley_delcert(iph1->cr_p);
-		iph1->cr_p = NULL;
+		VPTRINIT(iph1->cr_p);
 	}
 
 	return error;
@@ -630,7 +604,7 @@
 		goto end;
 
 #ifdef HAVE_GSSAPI
-	if (AUTHMETHOD(iph1) == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB &&
+	if (iph1->approval->authmethod == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB &&
 	    gssapi_more_tokens(iph1)) {
 		plog(LLV_DEBUG, LOCATION, NULL, "calling get_itoken\n");
 		if (gssapi_get_itoken(iph1, &len) < 0)
@@ -657,8 +631,7 @@
 		goto end;
 
 	/* send the packet, add to the schedule to resend */
-	iph1->retry_counter = iph1->rmconf->retry_counter;
-	if (isakmp_ph1resend(iph1) == -1)
+	if (isakmp_ph1send(iph1) == -1)
 		goto end;
 
 	/* the sending message is added to the received-list. */
@@ -754,10 +727,10 @@
 			break;
 #endif
 		case ISAKMP_NPTYPE_VID:
-			(void)check_vendorid(pa->ptr);
+			handle_vendorid(iph1, pa->ptr);
 			break;
 		case ISAKMP_NPTYPE_N:
-			isakmp_check_notify(pa->ptr, iph1);
+			ident_recv_n(iph1, pa->ptr);
 			break;
 		default:
 			/* don't send information, see ident_r1recv() */
@@ -788,8 +761,7 @@
 				/* msg printed inner oakley_validate_auth() */
 				goto end;
 			}
-			EVT_PUSH(iph1->local, iph1->remote, 
-			    EVTT_PEERPH1AUTH_FAILED, NULL);
+			evt_phase1(iph1, EVT_PHASE1_AUTH_FAILED, NULL);
 			isakmp_info_send_n1(iph1, type, NULL);
 			goto end;
 		}
@@ -812,7 +784,7 @@
 	 * If we got a GSS token, we need to this roundtrip again.
 	 */
 #ifdef HAVE_GSSAPI
-	iph1->status = gsstoken != 0 ? PHASE1ST_MSG3RECEIVED : 
+	iph1->status = gsstoken != 0 ? PHASE1ST_MSG3RECEIVED :
 	    PHASE1ST_MSG4RECEIVED;
 #else
 	iph1->status = PHASE1ST_MSG4RECEIVED;
@@ -832,10 +804,8 @@
 
 	if (error) {
 		VPTRINIT(iph1->id_p);
-		oakley_delcert(iph1->cert_p);
-		iph1->cert_p = NULL;
-		oakley_delcert(iph1->crl_p);
-		iph1->crl_p = NULL;
+		VPTRINIT(iph1->cert_p);
+		VPTRINIT(iph1->crl_p);
 		VPTRINIT(iph1->sig_p);
 	}
 
@@ -921,35 +891,11 @@
 
 		switch (pa->type) {
 		case ISAKMP_NPTYPE_VID:
-			vid_numeric = check_vendorid(pa->ptr);
-#ifdef ENABLE_NATT
-			if (iph1->rmconf->nat_traversal && natt_vendorid(vid_numeric))
-				natt_handle_vendorid(iph1, vid_numeric);
-#endif
+			vid_numeric = handle_vendorid(iph1, pa->ptr);
 #ifdef ENABLE_FRAG
 			if ((vid_numeric == VENDORID_FRAG) &&
 			    (vendorid_frag_cap(pa->ptr) & VENDORID_FRAG_IDENT))
 				iph1->frag = 1;
-#endif   
-#ifdef ENABLE_HYBRID
-			switch (vid_numeric) {
-			case VENDORID_XAUTH:
-				iph1->mode_cfg->flags |=
-				    ISAKMP_CFG_VENDORID_XAUTH;
-				break;
-		
-			case VENDORID_UNITY:
-				iph1->mode_cfg->flags |=
-				    ISAKMP_CFG_VENDORID_UNITY;
-				break;
-	
-			default:  
-				break;
-			}
-#endif
-#ifdef ENABLE_DPD
-			if (vid_numeric == VENDORID_DPD && iph1->rmconf->dpd)
-				iph1->dpd_support=1;
 #endif
 			break;
 		default:
@@ -1021,13 +967,13 @@
 #ifdef ENABLE_HYBRID
         vchar_t *vid_xauth = NULL;
         vchar_t *vid_unity = NULL;
-#endif  
+#endif
 #ifdef ENABLE_DPD
 	vchar_t *vid_dpd = NULL;
 #endif
-#ifdef ENABLE_FRAG          
+#ifdef ENABLE_FRAG
 	vchar_t *vid_frag = NULL;
-#endif 
+#endif
 
 	/* validity check */
 	if (iph1->status != PHASE1ST_MSG1RECEIVED) {
@@ -1041,10 +987,10 @@
 
 #ifdef HAVE_GSSAPI
 	if (iph1->approval->gssid != NULL) {
-		gss_sa = ipsecdoi_setph1proposal(iph1->approval);
+		gss_sa = ipsecdoi_setph1proposal(iph1->rmconf, iph1->approval);
 		if (gss_sa != iph1->sa_ret)
 			free_gss_sa = 1;
-	} else 
+	} else
 #endif
 		gss_sa = iph1->sa_ret;
 
@@ -1082,8 +1028,7 @@
 		plist = isakmp_plist_append(plist, vid_natt, ISAKMP_NPTYPE_VID);
 #endif
 #ifdef ENABLE_DPD
-	/* XXX only send DPD VID if remote sent it ? */
-	if(iph1->rmconf->dpd){
+	if (iph1->dpd_support) {
 		vid_dpd = set_vendorid(VENDORID_DPD);
 		if (vid_dpd != NULL)
 			plist = isakmp_plist_append(plist, vid_dpd, ISAKMP_NPTYPE_VID);
@@ -1099,7 +1044,7 @@
 			plog(LLV_ERROR, LOCATION, NULL,
 			    "Frag vendorID construction failed\n");
 		else
-			plist = isakmp_plist_append(plist, 
+			plist = isakmp_plist_append(plist,
 			     vid_frag, ISAKMP_NPTYPE_VID);
 	}
 #endif
@@ -1111,10 +1056,8 @@
 #endif
 
 	/* send the packet, add to the schedule to resend */
-	iph1->retry_counter = iph1->rmconf->retry_counter;
-	if (isakmp_ph1resend(iph1) == -1) {
+	if (isakmp_ph1send(iph1) == -1)
 		goto end;
-	}
 
 	/* the sending message is added to the received-list. */
 	if (add_recvdpkt(iph1->remote, iph1->local, iph1->sendbuf, msg) == -1) {
@@ -1203,7 +1146,7 @@
 				goto end;
 			break;
 		case ISAKMP_NPTYPE_VID:
-			(void)check_vendorid(pa->ptr);
+			handle_vendorid(iph1, pa->ptr);
 			break;
 		case ISAKMP_NPTYPE_CR:
 			plog(LLV_WARNING, LOCATION, iph1->remote,
@@ -1226,20 +1169,20 @@
 			{
 				vchar_t *natd_received = NULL;
 				int natd_verified;
-				
+
 				if (isakmp_p2ph (&natd_received, pa->ptr) < 0)
 					goto end;
-				
+
 				if (natd_seq == 0)
 					iph1->natt_flags |= NAT_DETECTED;
-				
+
 				natd_verified = natt_compare_addr_hash (iph1,
 					natd_received, natd_seq++);
-				
+
 				plog (LLV_INFO, LOCATION, NULL, "NAT-D payload #%d %s\n",
 					natd_seq - 1,
 					natd_verified ? "verified" : "doesn't match");
-				
+
 				vfree (natd_received);
 				break;
 			}
@@ -1259,7 +1202,7 @@
 #ifdef ENABLE_NATT
 	if (NATT_AVAILABLE(iph1))
 		plog (LLV_INFO, LOCATION, NULL, "NAT %s %s%s\n",
-		      iph1->natt_flags & NAT_DETECTED ? 
+		      iph1->natt_flags & NAT_DETECTED ?
 		      		"detected:" : "not detected",
 		      iph1->natt_flags & NAT_DETECTED_ME ? "ME " : "",
 		      iph1->natt_flags & NAT_DETECTED_PEER ? "PEER" : "");
@@ -1321,12 +1264,12 @@
 		goto end;
 
 	/* generate NONCE value */
-	iph1->nonce = eay_set_random(iph1->rmconf->nonce_size);
+	iph1->nonce = eay_set_random(RMCONF_NONCE_SIZE(iph1->rmconf));
 	if (iph1->nonce == NULL)
 		goto end;
 
 #ifdef HAVE_GSSAPI
-	if (AUTHMETHOD(iph1) == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB)
+	if (iph1->approval->authmethod == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB)
 		gssapi_get_rtoken(iph1, NULL);
 #endif
 
@@ -1340,8 +1283,7 @@
 #endif
 
 	/* send the packet, add to the schedule to resend */
-	iph1->retry_counter = iph1->rmconf->retry_counter;
-	if (isakmp_ph1resend(iph1) == -1)
+	if (isakmp_ph1send(iph1) == -1)
 		goto end;
 
 	/* the sending message is added to the received-list. */
@@ -1429,6 +1371,8 @@
 		case ISAKMP_NPTYPE_ID:
 			if (isakmp_p2ph(&iph1->id_p, pa->ptr) < 0)
 				goto end;
+			if (resolveph1rmconf(iph1) < 0)
+				goto end;
 			break;
 		case ISAKMP_NPTYPE_HASH:
 			iph1->pl_hash = (struct isakmp_pl_hash *)pa->ptr;
@@ -1453,10 +1397,10 @@
 			break;
 #endif
 		case ISAKMP_NPTYPE_VID:
-			(void)check_vendorid(pa->ptr);
+			handle_vendorid(iph1, pa->ptr);
 			break;
 		case ISAKMP_NPTYPE_N:
-			isakmp_check_notify(pa->ptr, iph1);
+			ident_recv_n(iph1, pa->ptr);
 			break;
 		default:
 			/* don't send information, see ident_r1recv() */
@@ -1473,7 +1417,7 @@
     {
 	int ng = 0;
 
-	switch (AUTHMETHOD(iph1)) {
+	switch (iph1->approval->authmethod) {
 	case OAKLEY_ATTR_AUTH_METHOD_PSKEY:
 #ifdef ENABLE_HYBRID
 	case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_R:
@@ -1537,8 +1481,7 @@
 				/* msg printed inner oakley_validate_auth() */
 				goto end;
 			}
-			EVT_PUSH(iph1->local, iph1->remote, 
-			    EVTT_PEERPH1AUTH_FAILED, NULL);
+			evt_phase1(iph1, EVT_PHASE1_AUTH_FAILED, NULL);
 			isakmp_info_send_n1(iph1, type, NULL);
 			goto end;
 		}
@@ -1583,13 +1526,10 @@
 
 	if (error) {
 		VPTRINIT(iph1->id_p);
-		oakley_delcert(iph1->cert_p);
-		iph1->cert_p = NULL;
-		oakley_delcert(iph1->crl_p);
-		iph1->crl_p = NULL;
+		VPTRINIT(iph1->cert_p);
+		VPTRINIT(iph1->crl_p);
 		VPTRINIT(iph1->sig_p);
-		oakley_delcert(iph1->cr_p);
-		iph1->cr_p = NULL;
+		VPTRINIT(iph1->cr_p);
 	}
 
 	return error;
@@ -1626,7 +1566,7 @@
 		goto end;
 
 #ifdef HAVE_GSSAPI
-	if (AUTHMETHOD(iph1) == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB &&
+	if (iph1->approval->authmethod == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB &&
 	    gssapi_more_tokens(iph1)) {
 		gssapi_get_rtoken(iph1, &len);
 		if (len != 0)
@@ -1694,8 +1634,6 @@
 {
 	vchar_t *buf = 0;
 	struct payload_list *plist = NULL;
-	int need_cr = 0;
-	vchar_t *cr = NULL;
 	vchar_t *vid = NULL;
 	int error = -1;
 #ifdef HAVE_GSSAPI
@@ -1705,23 +1643,14 @@
 	vchar_t *natd[2] = { NULL, NULL };
 #endif
 
-	/* create CR if need */
-	if (iph1->side == RESPONDER
-	 && iph1->rmconf->send_cr
-	 && oakley_needcr(iph1->approval->authmethod)
-	 && iph1->rmconf->peerscertfile == NULL) {
-		need_cr = 1;
-		cr = oakley_getcr(iph1);
-		if (cr == NULL) {
+#ifdef HAVE_GSSAPI
+	if (iph1->approval->authmethod == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB) {
+		if (gssapi_get_token_to_send(iph1, &gsstoken) < 0) {
 			plog(LLV_ERROR, LOCATION, NULL,
-				"failed to get cr buffer.\n");
+			     "Failed to get gssapi token.\n");
 			goto end;
 		}
 	}
-
-#ifdef HAVE_GSSAPI
-	if (AUTHMETHOD(iph1) == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB)
-		gssapi_get_token_to_send(iph1, &gsstoken);
 #endif
 
 	/* create isakmp KE payload */
@@ -1731,7 +1660,7 @@
 	plist = isakmp_plist_append(plist, iph1->nonce, ISAKMP_NPTYPE_NONCE);
 
 #ifdef HAVE_GSSAPI
-	if (AUTHMETHOD(iph1) == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB)
+	if (iph1->approval->authmethod == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB)
 		plist = isakmp_plist_append(plist, gsstoken, ISAKMP_NPTYPE_GSS);
 #endif
 
@@ -1739,9 +1668,10 @@
 	if (vid)
 		plist = isakmp_plist_append(plist, vid, ISAKMP_NPTYPE_VID);
 
-	/* create isakmp CR payload if needed */
-	if (need_cr)
-		plist = isakmp_plist_append(plist, cr, ISAKMP_NPTYPE_CR);
+	/* create CR if need */
+	if (iph1->side == RESPONDER &&
+	    oakley_needcr(iph1->approval->authmethod))
+		plist = oakley_append_cr(plist, iph1);
 
 #ifdef ENABLE_NATT
 	/* generate and append NAT-D payloads */
@@ -1764,9 +1694,9 @@
 		plist = isakmp_plist_append(plist, natd[1], iph1->natt_options->payload_nat_d);
 	}
 #endif
-	
+
 	buf = isakmp_plist_set_all (&plist, iph1);
-	
+
 	error = 0;
 
 end:
@@ -1774,8 +1704,6 @@
 		vfree(buf);
 		buf = NULL;
 	}
-	if (cr)
-		vfree(cr);
 #ifdef HAVE_GSSAPI
 	if (gsstoken)
 		vfree(gsstoken);
@@ -1814,9 +1742,7 @@
 {
 	struct payload_list *plist = NULL;
 	vchar_t *buf = NULL, *new = NULL;
-	int need_cr = 0;
 	int need_cert = 0;
-	vchar_t *cr = NULL;
 	int error = -1;
 #ifdef HAVE_GSSAPI
 	int nptype;
@@ -1824,10 +1750,10 @@
 	vchar_t *gsshash = NULL;
 #endif
 
-	switch (AUTHMETHOD(iph1)) {
+	switch (iph1->approval->authmethod) {
 	case OAKLEY_ATTR_AUTH_METHOD_PSKEY:
 #ifdef ENABLE_HYBRID
-	case FICTIVE_AUTH_METHOD_XAUTH_PSKEY_I:
+	case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_I:
 	case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_R:
 	case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I:
 	case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_I:
@@ -1847,27 +1773,13 @@
 	case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_R:
 	case OAKLEY_ATTR_AUTH_METHOD_XAUTH_DSSSIG_I:
 	case OAKLEY_ATTR_AUTH_METHOD_XAUTH_DSSSIG_R:
-#endif 
+#endif
 		if (oakley_getmycert(iph1) < 0)
 			goto end;
 
 		if (oakley_getsign(iph1) < 0)
 			goto end;
 
-		/* create CR if need */
-		if (iph1->side == INITIATOR
-		 && iph1->rmconf->send_cr
-	 	 && oakley_needcr(iph1->approval->authmethod)
-		 && iph1->rmconf->peerscertfile == NULL) {
-			need_cr = 1;
-			cr = oakley_getcr(iph1);
-			if (cr == NULL) {
-				plog(LLV_ERROR, LOCATION, NULL,
-					"failed to get cr buffer.\n");
-				goto end;
-			}
-		}
-
 		if (iph1->cert != NULL && iph1->rmconf->send_cert)
 			need_cert = 1;
 
@@ -1876,13 +1788,15 @@
 
 		/* add CERT payload if there */
 		if (need_cert)
-			plist = isakmp_plist_append(plist, iph1->cert->pl, ISAKMP_NPTYPE_CERT);
+			plist = isakmp_plist_append(plist, iph1->cert,
+						    ISAKMP_NPTYPE_CERT);
 		/* add SIG payload */
 		plist = isakmp_plist_append(plist, iph1->sig, ISAKMP_NPTYPE_SIG);
 
 		/* create isakmp CR payload */
-		if (need_cr)
-			plist = isakmp_plist_append(plist, cr, ISAKMP_NPTYPE_CR);
+		if (iph1->side == INITIATOR &&
+		    oakley_needcr(iph1->approval->authmethod))
+			plist = oakley_append_cr(plist, iph1);
 		break;
 #ifdef HAVE_GSSAPI
 	case OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB:
@@ -1891,7 +1805,11 @@
 			if (gsshash == NULL)
 				goto end;
 		} else {
-			gssapi_get_token_to_send(iph1, &gsstoken);
+			if (gssapi_get_token_to_send(iph1, &gsstoken) < 0) {
+				plog(LLV_ERROR, LOCATION, NULL,
+					"Failed to get gssapi token.\n");
+				goto end;
+			}
 		}
 
 		if (!gssapi_id_sent(iph1)) {
@@ -1927,7 +1845,7 @@
 	}
 
 	buf = isakmp_plist_set_all (&plist, iph1);
-	
+
 #ifdef HAVE_PRINT_ISAKMP_C
 	isakmp_printpacket(buf, iph1->local, iph1->remote, 1);
 #endif
@@ -1948,8 +1866,6 @@
 	if (gsstoken)
 		vfree(gsstoken);
 #endif
-	if (cr)
-		vfree(cr);
 	if (error && buf != NULL) {
 		vfree(buf);
 		buf = NULL;
@@ -1957,3 +1873,28 @@
 
 	return buf;
 }
+
+/*
+ * handle a notification payload inside identity exchange.
+ * called only when the packet has been verified to be encrypted.
+ */
+static int
+ident_recv_n(iph1, gen)
+	struct ph1handle *iph1;
+	struct isakmp_gen *gen;
+{
+	struct isakmp_pl_n *notify = (struct isakmp_pl_n *) gen;
+	u_int type;
+
+	type = ntohs(notify->type);
+	switch (type) {
+	case ISAKMP_NTYPE_INITIAL_CONTACT:
+		iph1->initial_contact_received = TRUE;
+		break;
+	default:
+		isakmp_log_notify(iph1, notify, "identity exchange");
+		break;
+	}
+	return 0;
+}
+
diff --git a/src/racoon/isakmp_inf.c b/src/racoon/isakmp_inf.c
index 5f487d2..9bf81c6 100644
--- a/src/racoon/isakmp_inf.c
+++ b/src/racoon/isakmp_inf.c
@@ -1,4 +1,4 @@
-/*	$NetBSD: isakmp_inf.c,v 1.14.4.17 2009/05/18 17:07:46 tteras Exp $	*/
+/*	$NetBSD: isakmp_inf.c,v 1.47 2011/03/15 13:20:14 vanhu Exp $	*/
 
 /* Id: isakmp_inf.c,v 1.44 2006/05/06 20:45:52 manubsd Exp */
 
@@ -107,11 +107,10 @@
 	struct isakmp_pl_ru *, u_int32_t));
 static int isakmp_info_recv_r_u_ack __P((struct ph1handle *,
 	struct isakmp_pl_ru *, u_int32_t));
-static void isakmp_info_send_r_u __P((void *));
+static void isakmp_info_send_r_u __P((struct sched *));
 #endif
 
 static void purge_isakmp_spi __P((int, isakmp_index *, size_t));
-static void info_recv_initialcontact __P((struct ph1handle *));
 
 /* %%%
  * Information Exchange
@@ -168,7 +167,8 @@
 	if (msg->l < sizeof(*isakmp) + sizeof(*gen)) {
 		plog(LLV_ERROR, LOCATION, NULL, 
 			"ignore information because the "
-			"message is way too short - %zu byte(s).\n", msg->l);
+			"message is way too short - %zu byte(s).\n",
+			msg->l);
 		goto end;
 	}
 
@@ -179,14 +179,15 @@
 	if (encrypted) {
 		if (isakmp->np != ISAKMP_NPTYPE_HASH) {
 			plog(LLV_ERROR, LOCATION, NULL,
-			    "ignore information because the"
+			    "ignore information because the "
 			    "message has no hash payload.\n");
 			goto end;
 		}
 
-		if (iph1->status != PHASE1ST_ESTABLISHED) {
+		if (iph1->status != PHASE1ST_ESTABLISHED &&
+		    iph1->status != PHASE1ST_DYING) {
 			plog(LLV_ERROR, LOCATION, NULL,
-			    "ignore information because ISAKMP-SA"
+			    "ignore information because ISAKMP-SA "
 			    "has not been established yet.\n");
 			goto end;
 		}
@@ -195,7 +196,8 @@
 		if (msg->l < sizeof(*isakmp) + ntohs(gen->len) + sizeof(*nd)) {
 			plog(LLV_ERROR, LOCATION, NULL, 
 				"ignore information because the "
-				"message is too short - %zu byte(s).\n", msg->l);
+				"message is too short - %zu byte(s).\n",
+				msg->l);
 			goto end;
 		}
 
@@ -323,6 +325,65 @@
 	return error;
 }
 
+
+/*
+ * log unhandled / unallowed Notification payload
+ */
+int
+isakmp_log_notify(iph1, notify, exchange)
+	struct ph1handle *iph1;
+	struct isakmp_pl_n *notify;
+	const char *exchange;
+{
+	u_int type;
+	char *nraw, *ndata, *nhex;
+	size_t l;
+
+	type = ntohs(notify->type);
+	if (ntohs(notify->h.len) < sizeof(*notify) + notify->spi_size) {
+		plog(LLV_ERROR, LOCATION, iph1->remote,
+			"invalid spi_size in %s notification in %s.\n",
+			s_isakmp_notify_msg(type), exchange);
+		return -1;
+	}
+
+	plog(LLV_ERROR, LOCATION, iph1->remote,
+		"notification %s received in %s.\n",
+		s_isakmp_notify_msg(type), exchange);
+
+	nraw = ((char*) notify) + sizeof(*notify) + notify->spi_size;
+	l = ntohs(notify->h.len) - sizeof(*notify) - notify->spi_size;
+	if (l > 0) {
+		if (type >= ISAKMP_NTYPE_MINERROR &&
+		    type <= ISAKMP_NTYPE_MAXERROR) {
+			ndata = binsanitize(nraw, l);
+			if (ndata != NULL) {
+				plog(LLV_ERROR, LOCATION, iph1->remote,
+					"error message: '%s'.\n",
+					ndata);
+				racoon_free(ndata);
+			} else {
+				plog(LLV_ERROR, LOCATION, iph1->remote,
+					"Cannot allocate memory\n");
+			}
+		} else {
+			nhex = val2str(nraw, l);
+			if (nhex != NULL) {
+				plog(LLV_ERROR, LOCATION, iph1->remote,
+					"notification payload: %s.\n",
+					nhex);
+				racoon_free(nhex);
+			} else {
+				plog(LLV_ERROR, LOCATION, iph1->remote,
+					"Cannot allocate memory\n");
+			}
+		}
+	}
+
+	return 0;
+}
+
+
 /*
  * handling of Notification payload
  */
@@ -334,13 +395,8 @@
 	int encrypted;
 {
 	u_int type;
-	vchar_t *pbuf;
-	char *nraw, *ndata;
-	size_t l;
-	char *spi;
 
 	type = ntohs(notify->type);
-
 	switch (type) {
 	case ISAKMP_NTYPE_CONNECTED:
 	case ISAKMP_NTYPE_RESPONDER_LIFETIME:
@@ -352,8 +408,7 @@
 		break;
 	case ISAKMP_NTYPE_INITIAL_CONTACT:
 		if (encrypted)
-			info_recv_initialcontact(iph1);
-			return 0;
+			return isakmp_info_recv_initialcontact(iph1, NULL);
 		break;
 #ifdef ENABLE_DPD
 	case ISAKMP_NTYPE_R_U_THERE:
@@ -367,76 +422,23 @@
 				(struct isakmp_pl_ru *)notify, msgid);
 		break;
 #endif
-	default:
-	    {
-		/* XXX there is a potential of dos attack. */
-		if(type >= ISAKMP_NTYPE_MINERROR &&
-		   type <= ISAKMP_NTYPE_MAXERROR) {
-			if (msgid == 0) {
-				/* don't think this realy deletes ph1 ? */
-				plog(LLV_ERROR, LOCATION, iph1->remote,
-					"delete phase1 handle.\n");
-				return -1;
-			} else {
-				if (getph2bymsgid(iph1, msgid) == NULL) {
-					plog(LLV_ERROR, LOCATION, iph1->remote,
-						"fatal %s notify messsage, "
-						"phase1 should be deleted.\n",
-						s_isakmp_notify_msg(type));
-				} else {
-					plog(LLV_ERROR, LOCATION, iph1->remote,
-						"fatal %s notify messsage, "
-						"phase2 should be deleted.\n",
-						s_isakmp_notify_msg(type));
-				}
-			}
-		} else {
-			plog(LLV_ERROR, LOCATION, iph1->remote,
-				"unhandled notify message %s, "
-				"no phase2 handle found.\n",
-				s_isakmp_notify_msg(type));
-		}
-	    }
-	    break;
 	}
 
-	/* get spi if specified and allocate */
-	if(notify->spi_size > 0) {
-		if (ntohs(notify->h.len) < sizeof(*notify) + notify->spi_size) {
-			plog(LLV_ERROR, LOCATION, iph1->remote,
-				"invalid spi_size in notification payload.\n");
-			return -1;
-		}
-		spi = val2str((char *)(notify + 1), notify->spi_size);
+	/* If we receive a error notification we should delete the related
+	 * phase1 / phase2 handle, and send an event to racoonctl.
+	 * However, since phase1 error notifications are not encrypted and
+	 * can not be authenticated, it would allow a DoS attack possibility
+	 * to handle them.
+	 * Phase2 error notifications should be encrypted, so we could handle
+	 * those, but it needs implementing (the old code didn't implement
+	 * that either).
+	 * So we are good to just log the messages here.
+	 */
+	if (encrypted)
+		isakmp_log_notify(iph1, notify, "informational exchange");
+	else
+		isakmp_log_notify(iph1, notify, "unencrypted informational exchange");
 
-		plog(LLV_DEBUG, LOCATION, iph1->remote,
-			"notification message %d:%s, "
-			"doi=%d proto_id=%d spi=%s(size=%d).\n",
-			type, s_isakmp_notify_msg(type),
-			ntohl(notify->doi), notify->proto_id, spi, notify->spi_size);
-
-		racoon_free(spi);
-	}
-
-	/* Send the message data to the logs */
-	if(type >= ISAKMP_NTYPE_MINERROR &&
-	   type <= ISAKMP_NTYPE_MAXERROR) {
-		l = ntohs(notify->h.len) - sizeof(*notify) - notify->spi_size;
-		if (l > 0) {
-			nraw = (char*)notify;	
-			nraw += sizeof(*notify) + notify->spi_size;
-			ndata = binsanitize(nraw, l);
-			if (ndata != NULL) {
-				plog(LLV_ERROR, LOCATION, iph1->remote,
-				    "Message: '%s'.\n", 
-				    ndata);
-				racoon_free(ndata);
-			} else {
-				plog(LLV_ERROR, LOCATION, iph1->remote,
-				    "Cannot allocate memory\n");
-			}
-		}
-	}
 	return 0;
 }
 
@@ -510,16 +512,16 @@
 		del_ph1=getph1byindex((isakmp_index *)(delete + 1));
 		if(del_ph1 != NULL){
 
-			EVT_PUSH(del_ph1->local, del_ph1->remote,
-			EVTT_PEERPH1_NOPROP, NULL);
-			if (del_ph1->scr)
-				SCHED_KILL(del_ph1->scr);
+			evt_phase1(iph1, EVT_PHASE1_PEER_DELETED, NULL);
+			sched_cancel(&del_ph1->scr);
 
 			/*
-			 * Do not delete IPsec SAs when receiving an IKE delete notification.
-			 * Just delete the IKE SA.
+			 * Delete also IPsec-SAs if rekeying is enabled.
 			 */
-			isakmp_ph1expire(del_ph1);
+			if (ph1_rekey_enabled(del_ph1))
+				purge_remote(del_ph1);
+			else
+				isakmp_ph1expire(del_ph1);
 		}
 		break;
 
@@ -532,8 +534,6 @@
 				delete->spi_size, delete->proto_id);
 			return 0;
 		}
-		EVT_PUSH(iph1->local, iph1->remote, 
-		    EVTT_PEER_DELETE, NULL);
 		purge_ipsec_spi(iph1->remote, delete->proto_id,
 		    (u_int32_t *)(delete + 1), num_spi);
 		break;
@@ -636,7 +636,7 @@
 	 * 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, 0);
+	iph1 = getph1byaddr(iph2->src, iph2->dst, 0); 
 	if (iph1 == NULL){
 		plog(LLV_DEBUG2, LOCATION, NULL,
 			 "No ph1 handler found, could not send DELETE_SA\n");
@@ -696,21 +696,12 @@
 	vchar_t *data;
 {
 	struct ph1handle *iph1 = NULL;
-	struct remoteconf *rmconf;
 	vchar_t *payload = NULL;
 	int tlen;
 	int error = -1;
 	struct isakmp_pl_n *n;
 	int spisiz = 0;		/* see below */
 
-	/* search appropreate configuration */
-	rmconf = getrmconf(remote);
-	if (rmconf == NULL) {
-		plog(LLV_ERROR, LOCATION, remote,
-			"no configuration found for peer address.\n");
-		goto end;
-	}
-
 	/* add new entry to isakmp status table. */
 	iph1 = newph1();
 	if (iph1 == NULL)
@@ -719,7 +710,6 @@
 	memcpy(&iph1->index.i_ck, &isakmp->i_ck, sizeof(cookie_t));
 	isakmp_newcookie((char *)&iph1->index.r_ck, remote, local);
 	iph1->status = PHASE1ST_START;
-	iph1->rmconf = rmconf;
 	iph1->side = INITIATOR;
 	iph1->version = isakmp->v;
 	iph1->flags = 0;
@@ -734,7 +724,7 @@
 #endif
 
 	/* copy remote address */
-	if (copy_ph1addresses(iph1, rmconf, remote, local) < 0)
+	if (copy_ph1addresses(iph1, NULL, remote, local) < 0)
 		goto end;
 
 	tlen = sizeof(*n) + spisiz;
@@ -911,16 +901,6 @@
 		delph2(iph2);
 		goto end;
 	}
-#if (!defined(ENABLE_NATT)) || (defined(BROKEN_NATT))
-	if (set_port(iph2->dst, 0) == NULL ||
-	    set_port(iph2->src, 0) == NULL) {
-		plog(LLV_ERROR, LOCATION, NULL,
-		     "invalid family: %d\n", iph1->remote->sa_family);
-		delph2(iph2);
-		goto end;
-	}
-#endif
-	iph2->ph1 = iph1;
 	iph2->side = INITIATOR;
 	iph2->status = PHASE2ST_START;
 	iph2->msgid = isakmp_newmsgid2(iph1);
@@ -934,7 +914,7 @@
 		}
 
 		/* generate HASH(1) */
-		hash = oakley_compute_hash1(iph2->ph1, iph2->msgid, payload);
+		hash = oakley_compute_hash1(iph1, iph2->msgid, payload);
 		if (hash == NULL) {
 			delph2(iph2);
 			goto end;
@@ -1035,7 +1015,6 @@
 	return error;
 
 err:
-	unbindph12(iph2);
 	remph2(iph2);
 	delph2(iph2);
 	goto end;
@@ -1114,9 +1093,8 @@
 			s_ipsecdoi_proto(proto),
 			isakmp_pindex(&spi[i], 0));
 
-		SCHED_KILL(iph1->sce);
 		iph1->status = PHASE1ST_EXPIRED;
-		iph1->sce = sched_new(1, isakmp_ph1delete_stub, iph1);
+		isakmp_ph1delete(iph1);
 	}
 }
 
@@ -1138,10 +1116,6 @@
 	u_int64_t created;
 	size_t i;
 	caddr_t mhp[SADB_EXT_MAX + 1];
-#ifdef ENABLE_NATT
-	struct sadb_x_nat_t_type *natt_type;
-	struct sadb_x_nat_t_port *natt_port;
-#endif
 
 	plog(LLV_DEBUG2, LOCATION, NULL,
 		 "purge_ipsec_spi:\n");
@@ -1181,6 +1155,7 @@
 			msg = next;
 			continue;
 		}
+		pk_fixup_sa_addresses(mhp);
 		src = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_SRC]);
 		dst = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_DST]);
 		lt = (struct sadb_lifetime*)mhp[SADB_EXT_LIFETIME_HARD];
@@ -1194,25 +1169,7 @@
 			msg = next;
 			continue;
 		}
-#ifdef ENABLE_NATT
-		natt_type = (void *)mhp[SADB_X_EXT_NAT_T_TYPE];
-		if (natt_type && natt_type->sadb_x_nat_t_type_type) {
-			/* NAT-T is enabled for this SADB entry; copy
-			 * the ports from NAT-T extensions */
-			natt_port = (void *)mhp[SADB_X_EXT_NAT_T_SPORT];
-			if (extract_port(src) == 0 && natt_port != NULL)
-				set_port(src, ntohs(natt_port->sadb_x_nat_t_port_port));
 
-			natt_port = (void *)mhp[SADB_X_EXT_NAT_T_DPORT];
-			if (extract_port(dst) == 0 && natt_port != NULL)
-				set_port(dst, ntohs(natt_port->sadb_x_nat_t_port_port));
-		}else{
-			/* Force default UDP ports, so CMPSADDR will match SAs with NO encapsulation
-			 */
-			set_port(src, PORT_ISAKMP);
-			set_port(dst, PORT_ISAKMP);
-		}
-#endif
 		plog(LLV_DEBUG2, LOCATION, NULL, "src: %s\n", saddr2str(src));
 		plog(LLV_DEBUG2, LOCATION, NULL, "dst: %s\n", saddr2str(dst));
 
@@ -1220,20 +1177,11 @@
 
 		/* don't delete inbound SAs at the moment */
 		/* XXX should we remove SAs with opposite direction as well? */
-		if (CMPSADDR(dst0, dst)) {
+		if (cmpsaddr(dst0, dst) != CMPSADDR_MATCH) {
 			msg = next;
 			continue;
 		}
 
-#ifdef ENABLE_NATT
-		if (natt_type == NULL ||
-			! natt_type->sadb_x_nat_t_type_type) {
-			/* Set back port to 0 if it was forced to default UDP port
-			 */
-			set_port(src, 0);
-			set_port(dst, 0);
-		}
-#endif
 		for (i = 0; i < n; i++) {
 			plog(LLV_DEBUG, LOCATION, NULL,
 				"check spi(packet)=%u spi(db)=%u.\n",
@@ -1254,7 +1202,6 @@
 			iph2 = getph2bysaidx(src, dst, proto, spi[i]);
 			if(iph2 != NULL){
 				delete_spd(iph2, created);
-				unbindph12(iph2);
 				remph2(iph2);
 				delph2(iph2);
 			}
@@ -1273,15 +1220,17 @@
 }
 
 /*
- * delete all phase2 sa relatived to the destination address.
+ * delete all phase2 sa relatived to the destination address
+ * (except the phase2 within which the INITIAL-CONTACT was received).
  * Don't delete Phase 1 handlers on INITIAL-CONTACT, and don't ignore
  * an INITIAL-CONTACT if we have contacted the peer.  This matches the
  * Sun IKE behavior, and makes rekeying work much better when the peer
  * restarts.
  */
-static void
-info_recv_initialcontact(iph1)
+int
+isakmp_info_recv_initialcontact(iph1, protectedph2)
 	struct ph1handle *iph1;
+	struct ph2handle *protectedph2;
 {
 	vchar_t *buf = NULL;
 	struct sadb_msg *msg, *next, *end;
@@ -1294,8 +1243,10 @@
 	char *loc, *rem;
 #endif
 
+	plog(LLV_INFO, LOCATION, iph1->remote, "received INITIAL-CONTACT\n");
+
 	if (f_local)
-		return;
+		return 0;
 
 #if 0
 	loc = racoon_strdup(saddrwop2str(iph1->local));
@@ -1344,7 +1295,7 @@
 
 	racoon_free(loc);
 	racoon_free(rem);
-	return;
+	return 0;
 
  the_hard_way:
 	racoon_free(loc);
@@ -1355,43 +1306,39 @@
 	if (buf == NULL) {
 		plog(LLV_DEBUG, LOCATION, NULL,
 			"pfkey_dump_sadb returned nothing.\n");
-		return;
+		return 0;
 	}
 
 	msg = (struct sadb_msg *)buf->v;
 	end = (struct sadb_msg *)(buf->v + buf->l);
 
-	while (msg < end) {
+	for (; msg < end; msg = next) {
 		if ((msg->sadb_msg_len << 3) < sizeof(*msg))
 			break;
+
 		next = (struct sadb_msg *)((caddr_t)msg + (msg->sadb_msg_len << 3));
-		if (msg->sadb_msg_type != SADB_DUMP) {
-			msg = next;
+		if (msg->sadb_msg_type != SADB_DUMP)
 			continue;
-		}
 
 		if (pfkey_align(msg, mhp) || pfkey_check(mhp)) {
 			plog(LLV_ERROR, LOCATION, NULL,
 				"pfkey_check (%s)\n", ipsec_strerror());
-			msg = next;
 			continue;
 		}
 
 		if (mhp[SADB_EXT_SA] == NULL
 		 || mhp[SADB_EXT_ADDRESS_SRC] == NULL
-		 || mhp[SADB_EXT_ADDRESS_DST] == NULL) {
-			msg = next;
+		 || mhp[SADB_EXT_ADDRESS_DST] == NULL)
 			continue;
-		}
+
 		sa = (struct sadb_sa *)mhp[SADB_EXT_SA];
+		pk_fixup_sa_addresses(mhp);
 		src = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_SRC]);
 		dst = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_DST]);
 
 		if (sa->sadb_sa_state != SADB_SASTATE_MATURE
-		 && sa->sadb_sa_state != SADB_SASTATE_DYING) {
-			msg = next;
+		 && sa->sadb_sa_state != SADB_SASTATE_DYING)
 			continue;
-		}
 
 		/*
 		 * RFC2407 4.6.3.3 INITIAL-CONTACT is the message that
@@ -1401,39 +1348,18 @@
 		 * racoon only deletes SA which is matched both the
 		 * source address and the destination accress.
 		 */
-#ifdef ENABLE_NATT
-		/* 
-		 * XXX RFC 3947 says that whe MUST NOT use IP+port to find old SAs
-		 * from this peer !
-		 */
-		if(iph1->natt_flags & NAT_DETECTED){
-			if (CMPSADDR(iph1->local, src) == 0 &&
-				CMPSADDR(iph1->remote, dst) == 0)
-				;
-			else if (CMPSADDR(iph1->remote, src) == 0 &&
-					 CMPSADDR(iph1->local, dst) == 0)
-				;
-			else {
-				msg = next;
-				continue;
-			}
-		} else
-#endif
-		/* If there is no NAT-T, we don't have to check addr + port...
-		 * XXX what about a configuration with a remote peers which is not
-		 * NATed, but which NATs some other peers ?
-		 * Here, the INITIAl-CONTACT would also flush all those NATed peers !!
-		 */
-		if (cmpsaddrwop(iph1->local, src) == 0 &&
-		    cmpsaddrwop(iph1->remote, dst) == 0)
-			;
-		else if (cmpsaddrwop(iph1->remote, src) == 0 &&
-		    cmpsaddrwop(iph1->local, dst) == 0)
-			;
-		else {
-			msg = next;
+
+		/*
+		 * Check that the IP and port match. But this is not optimal,
+		 * since NAT-T can make the peer have multiple different
+		 * ports. Correct thing to do is delete all entries with
+                 * same identity. -TT
+                 */
+		if ((cmpsaddr(iph1->local, src) != CMPSADDR_MATCH ||
+		     cmpsaddr(iph1->remote, dst) != CMPSADDR_MATCH) &&
+		    (cmpsaddr(iph1->local, dst) != CMPSADDR_MATCH ||
+		     cmpsaddr(iph1->remote, src) != CMPSADDR_MATCH))
 			continue;
-		}
 
 		/*
 		 * Make sure this is an SATYPE that we manage.
@@ -1445,10 +1371,8 @@
 			    msg->sadb_msg_satype)
 				break;
 		}
-		if (i == pfkey_nsatypes) {
-			msg = next;
+		if (i == pfkey_nsatypes)
 			continue;
-		}
 
 		plog(LLV_INFO, LOCATION, NULL,
 			"purging spi=%u.\n", ntohl(sa->sadb_sa_spi));
@@ -1463,54 +1387,15 @@
 		 */
 		proto_id = pfkey2ipsecdoi_proto(msg->sadb_msg_satype);
 		iph2 = getph2bysaidx(src, dst, proto_id, sa->sadb_sa_spi);
-		if (iph2) {
+		if (iph2 && iph2 != protectedph2) {
 			delete_spd(iph2, 0);
-			unbindph12(iph2);
 			remph2(iph2);
 			delph2(iph2);
 		}
-
-		msg = next;
 	}
 
 	vfree(buf);
-}
-
-void
-isakmp_check_notify(gen, iph1)
-	struct isakmp_gen *gen;		/* points to Notify payload */
-	struct ph1handle *iph1;
-{
-	struct isakmp_pl_n *notify = (struct isakmp_pl_n *)gen;
-
-	plog(LLV_DEBUG, LOCATION, iph1->remote,
-		"Notify Message received\n");
-
-	switch (ntohs(notify->type)) {
-	case ISAKMP_NTYPE_CONNECTED:
-	case ISAKMP_NTYPE_RESPONDER_LIFETIME:
-	case ISAKMP_NTYPE_REPLAY_STATUS:
-	case ISAKMP_NTYPE_HEARTBEAT:
-#ifdef ENABLE_HYBRID
-	case ISAKMP_NTYPE_UNITY_HEARTBEAT:
-#endif
-		plog(LLV_WARNING, LOCATION, iph1->remote,
-			"ignore %s notification.\n",
-			s_isakmp_notify_msg(ntohs(notify->type)));
-		break;
-	case ISAKMP_NTYPE_INITIAL_CONTACT:
-		plog(LLV_WARNING, LOCATION, iph1->remote,
-			"ignore INITIAL-CONTACT notification, "
-			"because it is only accepted after phase1.\n");
-		break;
-	default:
-		isakmp_info_send_n1(iph1, ISAKMP_NTYPE_INVALID_PAYLOAD_TYPE, NULL);
-		plog(LLV_ERROR, LOCATION, iph1->remote,
-			"received unknown notification type %s.\n",
-			s_isakmp_notify_msg(ntohs(notify->type)));
-	}
-
-	return;
+	return 0;
 }
 
 
@@ -1567,17 +1452,16 @@
 	struct isakmp_pl_ru *ru;
 	u_int32_t msgid;
 {
+	u_int32_t seq;
 
 	plog(LLV_DEBUG, LOCATION, iph1->remote,
 		 "DPD R-U-There-Ack received\n");
 
-	/* XXX Maintain window of acceptable sequence numbers ?
-	 * => ru->data <= iph2->dpd_seq &&
-	 *    ru->data >= iph2->dpd_seq - iph2->dpd_fails ? */
-	if (ntohl(ru->data) != iph1->dpd_seq-1) {
+	seq = ntohl(ru->data);
+	if (seq <= iph1->dpd_last_ack || seq > iph1->dpd_seq) {
 		plog(LLV_ERROR, LOCATION, iph1->remote,
-			 "Wrong DPD sequence number (%d, %d expected).\n", 
-			 ntohl(ru->data), iph1->dpd_seq-1);
+			 "Wrong DPD sequence number (%d; last_ack=%d, seq=%d).\n", 
+			 seq, iph1->dpd_last_ack, iph1->dpd_seq);
 		return 0;
 	}
 
@@ -1589,12 +1473,8 @@
 	}
 
 	iph1->dpd_fails = 0;
-
-	/* Useless ??? */
-	iph1->dpd_lastack = time(NULL);
-
-	SCHED_KILL(iph1->dpd_r_u);
-
+	iph1->dpd_last_ack = seq;
+	sched_cancel(&iph1->dpd_r_u);
 	isakmp_sched_r_u(iph1, 0);
 
 	plog(LLV_DEBUG, LOCATION, NULL, "received an R-U-THERE-ACK\n");
@@ -1609,10 +1489,10 @@
  * send DPD R-U-THERE payload in Informational exchange.
  */
 static void
-isakmp_info_send_r_u(arg)
-	void *arg;
+isakmp_info_send_r_u(sc)
+	struct sched *sc;
 {
-	struct ph1handle *iph1 = arg;
+	struct ph1handle *iph1 = container_of(sc, struct ph1handle, dpd_r_u);
 
 	/* create R-U-THERE payload */
 	struct isakmp_pl_ru *ru;
@@ -1622,7 +1502,14 @@
 
 	plog(LLV_DEBUG, LOCATION, iph1->remote, "DPD monitoring....\n");
 
-	iph1->dpd_r_u=NULL;
+	if (iph1->status == PHASE1ST_EXPIRED) {
+		/* This can happen after removing tunnels from the
+		 * config file and then reloading.
+		 * Such iph1 have rmconf=NULL, so return before the if
+		 * block below.
+		 */
+		return;
+	}
 
 	if (iph1->dpd_fails >= iph1->rmconf->dpd_maxfails) {
 
@@ -1630,7 +1517,8 @@
 			"DPD: remote (ISAKMP-SA spi=%s) seems to be dead.\n",
 			isakmp_pindex(&iph1->index, 0));
 
-		EVT_PUSH(iph1->local, iph1->remote, EVTT_DPD_TIMEOUT, NULL);
+		script_hook(iph1, SCRIPT_PHASE1_DEAD);
+		evt_phase1(iph1, EVT_PHASE1_DPD_TIMEOUT, NULL);
 		purge_remote(iph1);
 
 		/* Do not reschedule here: phase1 is deleted,
@@ -1659,12 +1547,13 @@
 	memcpy(ru->i_ck, iph1->index.i_ck, sizeof(cookie_t));
 	memcpy(ru->r_ck, iph1->index.r_ck, sizeof(cookie_t));
 
-	if (iph1->dpd_seq == 0){
+	if (iph1->dpd_seq == 0) {
 		/* generate a random seq which is not too big */
-		srand(time(NULL));
-		iph1->dpd_seq = rand() & 0x0fff;
+		iph1->dpd_seq = iph1->dpd_last_ack = rand() & 0x0fff;
 	}
 
+	iph1->dpd_seq++;
+	iph1->dpd_fails++;
 	ru->data = htonl(iph1->dpd_seq);
 
 	error = isakmp_info_send_common(iph1, payload, ISAKMP_NPTYPE_N, 0);
@@ -1673,12 +1562,6 @@
 	plog(LLV_DEBUG, LOCATION, iph1->remote,
 		 "DPD R-U-There sent (%d)\n", error);
 
-	/* will be decreased if ACK received... */
-	iph1->dpd_fails++;
-
-	/* XXX should be increased only when ACKed ? */
-	iph1->dpd_seq++;
-
 	/* Reschedule the r_u_there with a short delay,
 	 * will be deleted/rescheduled if ACK received before */
 	isakmp_sched_r_u(iph1, 1);
@@ -1703,11 +1586,11 @@
 		return 0;
 
 	if(retry)
-		iph1->dpd_r_u = sched_new(iph1->rmconf->dpd_retry,
-								  isakmp_info_send_r_u, iph1);
+		sched_schedule(&iph1->dpd_r_u, iph1->rmconf->dpd_retry,
+			       isakmp_info_send_r_u);
 	else
-		iph1->dpd_r_u = sched_new(iph1->rmconf->dpd_interval,
-								  isakmp_info_send_r_u, iph1);
+		sched_schedule(&iph1->dpd_r_u, iph1->rmconf->dpd_interval,
+			       isakmp_info_send_r_u);
 
 	return 0;
 }
diff --git a/src/racoon/isakmp_inf.h b/src/racoon/isakmp_inf.h
index c7682d9..40cdc02 100644
--- a/src/racoon/isakmp_inf.h
+++ b/src/racoon/isakmp_inf.h
@@ -1,4 +1,4 @@
-/*	$NetBSD: isakmp_inf.h,v 1.4 2006/09/09 16:22:09 manu Exp $	*/
+/*	$NetBSD: isakmp_inf.h,v 1.5 2008/07/14 05:40:13 tteras Exp $	*/
 
 /* Id: isakmp_inf.h,v 1.6 2005/05/07 14:15:59 manubsd Exp */
 
@@ -48,7 +48,8 @@
 extern vchar_t * isakmp_add_pl_n __P((vchar_t *, u_int8_t **, int,
 	struct saproto *, vchar_t *));
 
-extern void isakmp_check_notify __P((struct isakmp_gen *, struct ph1handle *));
+extern int isakmp_log_notify __P((struct ph1handle *, struct isakmp_pl_n *, const char *exchange));
+extern int isakmp_info_recv_initialcontact __P((struct ph1handle *, struct ph2handle *));
 
 #ifdef ENABLE_DPD
 extern int isakmp_sched_r_u __P((struct ph1handle *, int));
diff --git a/src/racoon/isakmp_quick.c b/src/racoon/isakmp_quick.c
index 963438d..056e905 100644
--- a/src/racoon/isakmp_quick.c
+++ b/src/racoon/isakmp_quick.c
@@ -1,4 +1,4 @@
-/*	$NetBSD: isakmp_quick.c,v 1.11.4.1 2007/08/01 11:52:21 vanhu Exp $	*/
+/*	$NetBSD: isakmp_quick.c,v 1.29 2011/03/14 17:18:13 tteras Exp $	*/
 
 /* Id: isakmp_quick.c,v 1.29 2006/08/22 18:17:17 manubsd Exp */
 
@@ -53,9 +53,6 @@
 #  include <time.h>
 # endif
 #endif
-#ifdef ENABLE_HYBRID
-#include <resolv.h>
-#endif
 
 #include PATH_IPSEC_H
 
@@ -87,10 +84,47 @@
 #include "admin.h"
 #include "strnames.h"
 
+#ifdef ENABLE_HYBRID
+#include <resolv.h>
+#include "isakmp_xauth.h"
+#include "isakmp_cfg.h"
+#endif
+
+#ifdef ENABLE_NATT
+#include "nattraversal.h"
+#endif
+
 /* quick mode */
 static vchar_t *quick_ir1mx __P((struct ph2handle *, vchar_t *, vchar_t *));
 static int get_sainfo_r __P((struct ph2handle *));
 static int get_proposal_r __P((struct ph2handle *));
+static int ph2_recv_n __P((struct ph2handle *, struct isakmp_gen *));
+static void quick_timeover_stub __P((struct sched *));
+static void quick_timeover __P((struct ph2handle *));
+
+/* called from scheduler */
+static void
+quick_timeover_stub(p)
+	struct sched *p;
+{
+	quick_timeover(container_of(p, struct ph2handle, sce));
+}
+
+static void
+quick_timeover(iph2)
+	struct ph2handle *iph2;
+{
+	plog(LLV_ERROR, LOCATION, NULL,
+		"%s give up to get IPsec-SA due to time up to wait.\n",
+		saddrwop2str(iph2->dst));
+
+	/* If initiator side, send error to kernel by SADB_ACQUIRE. */
+	if (iph2->side == INITIATOR)
+		pk_sendeacquire(iph2);
+
+	remph2(iph2);
+	delph2(iph2);
+}
 
 /* %%%
  * Quick Mode
@@ -131,8 +165,8 @@
 
 	plog(LLV_DEBUG, LOCATION, NULL, "pfkey getspi sent.\n");
 
-	iph2->sce = sched_new(lcconf->wait_ph2complete,
-		pfkey_timeover_stub, iph2);
+	sched_schedule(&iph2->sce, lcconf->wait_ph2complete,
+		       quick_timeover_stub);
 
 	error = 0;
 
@@ -142,7 +176,7 @@
 
 /*
  * send to responder
- * 	HDR*, HASH(1), SA, Ni [, KE ] [, IDi2, IDr2 ]
+ * 	HDR*, HASH(1), SA, Ni [, KE ] [, IDi2, IDr2 ] [, NAT-OAi, NAT-OAr ]
  */
 int
 quick_i1send(iph2, msg)
@@ -155,9 +189,14 @@
 	char *p;
 	int tlen;
 	int error = ISAKMP_INTERNAL_ERROR;
+	int natoa = ISAKMP_NPTYPE_NONE;
 	int pfsgroup, idci, idcr;
 	int np;
 	struct ipsecdoi_id_b *id, *id_p;
+#ifdef ENABLE_NATT
+	vchar_t *nat_oai = NULL;
+	vchar_t *nat_oar = NULL;
+#endif
 
 	/* validity check */
 	if (msg != NULL) {
@@ -217,17 +256,49 @@
 	 * - no MIP6 or proxy
 	 * - id payload suggests to encrypt all the traffic (no specific
 	 *   protocol type)
+	 * - SA endpoints and IKE addresses for the nego are the same
+	 *   (iph2->src/dst)
 	 */
 	id = (struct ipsecdoi_id_b *)iph2->id->v;
 	id_p = (struct ipsecdoi_id_b *)iph2->id_p->v;
-	if (id->proto_id == 0
-	 && id_p->proto_id == 0
-	 && iph2->ph1->rmconf->support_proxy == 0
-	 && ipsecdoi_transportmode(iph2->proposal)) {
+	if (id->proto_id == 0 &&
+	    id_p->proto_id == 0 &&
+	    iph2->ph1->rmconf->support_proxy == 0 &&
+	    iph2->sa_src == NULL && iph2->sa_dst == NULL &&
+	    ipsecdoi_transportmode(iph2->proposal)) {
 		idci = idcr = 0;
 	} else
 		idci = idcr = 1;
 
+#ifdef ENABLE_NATT
+	/*
+	 * RFC3947 5.2. if we propose UDP-Encapsulated-Transport
+	 * we should send NAT-OA
+	 */
+	if (ipsecdoi_transportmode(iph2->proposal)
+	 && (iph2->ph1->natt_flags & NAT_DETECTED)) {
+		natoa = iph2->ph1->natt_options->payload_nat_oa;
+
+		nat_oai = ipsecdoi_sockaddr2id(iph2->src,
+			IPSECDOI_PREFIX_HOST, IPSEC_ULPROTO_ANY);
+		nat_oar = ipsecdoi_sockaddr2id(iph2->dst,
+			IPSECDOI_PREFIX_HOST, IPSEC_ULPROTO_ANY);
+
+		if (nat_oai == NULL || nat_oar == NULL) {
+			plog(LLV_ERROR, LOCATION, NULL,
+				"failed to generate NAT-OA payload.\n");
+			goto end;
+		}
+
+		plog(LLV_DEBUG, LOCATION, NULL, "NAT-OAi:\n");
+		plogdump(LLV_DEBUG, nat_oai->v, nat_oai->l);
+		plog(LLV_DEBUG, LOCATION, NULL, "NAT-OAr:\n");
+		plogdump(LLV_DEBUG, nat_oar->v, nat_oar->l);
+	} else {
+		natoa = ISAKMP_NPTYPE_NONE;
+	}
+#endif
+
 	/* create SA;NONCE payload, and KE if need, and IDii, IDir. */
 	tlen = + sizeof(*gen) + iph2->sa->l
 		+ sizeof(*gen) + iph2->nonce->l;
@@ -237,6 +308,10 @@
 		tlen += sizeof(*gen) + iph2->id->l;
 	if (idcr)
 		tlen += sizeof(*gen) + iph2->id_p->l;
+#ifdef ENABLE_NATT
+	if (natoa != ISAKMP_NPTYPE_NONE)
+		tlen += 2 * sizeof(*gen) + nat_oai->l + nat_oar->l;
+#endif
 
 	body = vmalloc(tlen);
 	if (body == NULL) {
@@ -256,22 +331,30 @@
 	else if (idci || idcr)
 		np = ISAKMP_NPTYPE_ID;
 	else
-		np = ISAKMP_NPTYPE_NONE;
+		np = natoa;
 	p = set_isakmp_payload(p, iph2->nonce, np);
 
 	/* add KE payload if need. */
-	np = (idci || idcr) ? ISAKMP_NPTYPE_ID : ISAKMP_NPTYPE_NONE;
+	np = (idci || idcr) ? ISAKMP_NPTYPE_ID : natoa;
 	if (pfsgroup)
 		p = set_isakmp_payload(p, iph2->dhpub, np);
 
 	/* IDci */
-	np = (idcr) ? ISAKMP_NPTYPE_ID : ISAKMP_NPTYPE_NONE;
+	np = (idcr) ? ISAKMP_NPTYPE_ID : natoa;
 	if (idci)
 		p = set_isakmp_payload(p, iph2->id, np);
 
 	/* IDcr */
 	if (idcr)
-		p = set_isakmp_payload(p, iph2->id_p, ISAKMP_NPTYPE_NONE);
+		p = set_isakmp_payload(p, iph2->id_p, natoa);
+
+#ifdef ENABLE_NATT
+	/* NAT-OA */
+	if (natoa != ISAKMP_NPTYPE_NONE) {
+		p = set_isakmp_payload(p, nat_oai, natoa);
+		p = set_isakmp_payload(p, nat_oar, ISAKMP_NPTYPE_NONE);
+	}
+#endif
 
 	/* generate HASH(1) */
 	hash = oakley_compute_hash1(iph2->ph1, iph2->msgid, body);
@@ -284,8 +367,7 @@
 		goto end;
 
 	/* send the packet, add to the schedule to resend */
-	iph2->retry_counter = iph2->ph1->rmconf->retry_counter;
-	if (isakmp_ph2resend(iph2) == -1)
+	if (isakmp_ph2send(iph2) == -1)
 		goto end;
 
 	/* change status of isakmp status entry */
@@ -298,13 +380,19 @@
 		vfree(body);
 	if (hash != NULL)
 		vfree(hash);
+#ifdef ENABLE_NATT
+	if (nat_oai != NULL)
+		vfree(nat_oai);
+	if (nat_oar != NULL)
+		vfree(nat_oar);
+#endif
 
 	return error;
 }
 
 /*
  * receive from responder
- * 	HDR*, HASH(2), SA, Nr [, KE ] [, IDi2, IDr2 ]
+ * 	HDR*, HASH(2), SA, Nr [, KE ] [, IDi2, IDr2 ] [, NAT-OAi, NAT-OAr ]
  */
 int
 quick_i2recv(iph2, msg0)
@@ -314,10 +402,11 @@
 	vchar_t *msg = NULL;
 	vchar_t *hbuf = NULL;	/* for hash computing. */
 	vchar_t *pbuf = NULL;	/* for payload parsing */
+	vchar_t *idci = NULL;
+	vchar_t *idcr = NULL;
 	struct isakmp_parse_t *pa;
 	struct isakmp *isakmp = (struct isakmp *)msg0->v;
 	struct isakmp_pl_hash *hash = NULL;
-	int f_id;
 	char *p;
 	int tlen;
 	int error = ISAKMP_INTERNAL_ERROR;
@@ -391,7 +480,6 @@
 	 * copy non-HASH payloads into hbuf, so that we can validate HASH.
 	 */
 	iph2->sa_ret = NULL;
-	f_id = 0;	/* flag to use checking ID */
 	tlen = 0;	/* count payload length except of HASH payload. */
 	for (; pa->type; pa++) {
 
@@ -407,54 +495,84 @@
 					"isn't supported.\n");
 				break;
 			}
-			if (isakmp_p2ph(&iph2->sa_ret, pa->ptr) < 0)
+			if (isakmp_p2ph(&iph2->sa_ret, pa->ptr) < 0) {
+				plog(LLV_ERROR, LOCATION, iph2->ph1->remote,
+					"duplicate ISAKMP_NPTYPE_SA.\n");
 				goto end;
+			}
 			break;
 
 		case ISAKMP_NPTYPE_NONCE:
-			if (isakmp_p2ph(&iph2->nonce_p, pa->ptr) < 0)
+			if (isakmp_p2ph(&iph2->nonce_p, pa->ptr) < 0) {
+				plog(LLV_ERROR, LOCATION, iph2->ph1->remote,
+					"duplicate ISAKMP_NPTYPE_NONCE.\n");
 				goto end;
+			}
 			break;
 
 		case ISAKMP_NPTYPE_KE:
-			if (isakmp_p2ph(&iph2->dhpub_p, pa->ptr) < 0)
+			if (isakmp_p2ph(&iph2->dhpub_p, pa->ptr) < 0) {
+				plog(LLV_ERROR, LOCATION, iph2->ph1->remote,
+					"duplicate ISAKMP_NPTYPE_KE.\n");
 				goto end;
+			}
 			break;
 
 		case ISAKMP_NPTYPE_ID:
-		    {
-			vchar_t *vp;
-
-			/* check ID value */
-			if (f_id == 0) {
-				/* for IDci */
-				f_id = 1;
-				vp = iph2->id;
+			if (idci == NULL) {
+				if (isakmp_p2ph(&idci, pa->ptr) < 0)
+					goto end;
+			} else if (idcr == NULL) {
+				if (isakmp_p2ph(&idcr, pa->ptr) < 0)
+					goto end;
 			} else {
-				/* for IDcr */
-				vp = iph2->id_p;
-			}
-
-#ifndef ANDROID_PATCHED
-			if (memcmp(vp->v, (caddr_t)pa->ptr + sizeof(struct isakmp_gen), vp->l)) {
-
-				plog(LLV_ERROR, LOCATION, NULL,
-					"mismatched ID was returned.\n");
-				error = ISAKMP_NTYPE_ATTRIBUTES_NOT_SUPPORTED;
+				plog(LLV_ERROR, LOCATION, iph2->ph1->remote,
+					"too many ISAKMP_NPTYPE_ID payloads.\n");
 				goto end;
 			}
-#endif
-		    }
 			break;
 
 		case ISAKMP_NPTYPE_N:
-			isakmp_check_notify(pa->ptr, iph2->ph1);
+			ph2_recv_n(iph2, pa->ptr);
 			break;
 
 #ifdef ENABLE_NATT
 		case ISAKMP_NPTYPE_NATOA_DRAFT:
 		case ISAKMP_NPTYPE_NATOA_RFC:
-			/* Ignore original source/destination messages */
+		    {
+			struct sockaddr_storage addr;
+			struct sockaddr *daddr;
+			u_int8_t prefix;
+			u_int16_t ul_proto;
+			vchar_t *vp = NULL;
+
+			if (isakmp_p2ph(&vp, pa->ptr) < 0)
+				goto end;
+
+			error = ipsecdoi_id2sockaddr(vp,
+					(struct sockaddr *) &addr,
+					&prefix, &ul_proto);
+
+			vfree(vp);
+
+			if (error)
+				goto end;
+
+			daddr = dupsaddr((struct sockaddr *) &addr);
+			if (daddr == NULL)
+				goto end;
+
+			if (iph2->natoa_src == NULL)
+				iph2->natoa_src = daddr;
+			else if (iph2->natoa_dst == NULL)
+				iph2->natoa_dst = daddr;
+			else {
+				racoon_free(daddr);
+				plog(LLV_ERROR, LOCATION, iph2->ph1->remote,
+					"too many ISAKMP_NPTYPE_NATOA payloads.\n");
+				goto end;
+			}
+		    }
 			break;
 #endif
 
@@ -480,6 +598,118 @@
 		goto end;
 	}
 
+#ifdef ANDROID_PATCHED
+        if (idcr != NULL) {
+                struct ipsecdoi_id_b *id_b = idcr->v;
+                if (id_b->type != IPSECDOI_ID_IPV4_ADDR &&
+                    id_b->type != IPSECDOI_ID_IPV4_ADDR_SUBNET &&
+                    id_b->type != IPSECDOI_ID_IPV6_ADDR &&
+                    id_b->type != IPSECDOI_ID_IPV6_ADDR_SUBNET) {
+                        vfree(idcr);
+                        idcr = NULL;
+                }
+        }
+#endif
+
+	/* identity check */
+	if (idci != NULL) {
+		struct sockaddr_storage proposed_addr, got_addr;
+		u_int8_t proposed_prefix, got_prefix;
+		u_int16_t proposed_ulproto, got_ulproto;
+
+		error = ipsecdoi_id2sockaddr(iph2->id,
+					(struct sockaddr *) &proposed_addr,
+					&proposed_prefix, &proposed_ulproto);
+		if (error)
+			goto end;
+
+		error = ipsecdoi_id2sockaddr(idci,
+					(struct sockaddr *) &got_addr,
+					&got_prefix, &got_ulproto);
+		if (error)
+			goto end;
+
+		if (proposed_prefix != got_prefix
+		 || proposed_ulproto != got_ulproto) {
+			plog(LLV_DEBUG, LOCATION, NULL,
+				"IDci prefix/ulproto does not match proposal.\n");
+			error = ISAKMP_NTYPE_ATTRIBUTES_NOT_SUPPORTED;
+			goto end;
+		}
+#ifdef ENABLE_NATT
+		set_port(iph2->natoa_src,
+			 extract_port((struct sockaddr *) &proposed_addr));
+#endif
+
+		if (cmpsaddr((struct sockaddr *) &proposed_addr,
+			     (struct sockaddr *) &got_addr) == CMPSADDR_MATCH) {
+			plog(LLV_DEBUG, LOCATION, NULL,
+				"IDci matches proposal.\n");
+#ifdef ENABLE_NATT
+		} else if (iph2->natoa_src != NULL
+			&& cmpsaddr(iph2->natoa_src,
+				    (struct sockaddr *) &got_addr) == 0) {
+			plog(LLV_DEBUG, LOCATION, NULL,
+				"IDci matches NAT-OAi.\n");
+#endif
+#ifndef ANDROID_PATCHED
+		} else {
+			plog(LLV_ERROR, LOCATION, NULL,
+				"mismatched IDci was returned.\n");
+			error = ISAKMP_NTYPE_ATTRIBUTES_NOT_SUPPORTED;
+			goto end;
+#endif
+		}
+	}
+	if (idcr != NULL) {
+		struct sockaddr_storage proposed_addr, got_addr;
+		u_int8_t proposed_prefix, got_prefix;
+		u_int16_t proposed_ulproto, got_ulproto;
+
+		error = ipsecdoi_id2sockaddr(iph2->id_p,
+					(struct sockaddr *) &proposed_addr,
+					&proposed_prefix, &proposed_ulproto);
+		if (error)
+			goto end;
+
+		error = ipsecdoi_id2sockaddr(idcr,
+					(struct sockaddr *) &got_addr,
+					&got_prefix, &got_ulproto);
+		if (error)
+			goto end;
+
+		if (proposed_prefix != got_prefix
+		 || proposed_ulproto != got_ulproto) {
+			plog(LLV_DEBUG, LOCATION, NULL,
+				"IDcr prefix/ulproto does not match proposal.\n");
+			error = ISAKMP_NTYPE_ATTRIBUTES_NOT_SUPPORTED;
+			goto end;
+		}
+
+#ifdef ENABLE_NATT
+		set_port(iph2->natoa_dst,
+			 extract_port((struct sockaddr *) &proposed_addr));
+#endif
+
+		if (cmpsaddr((struct sockaddr *) &proposed_addr,
+			     (struct sockaddr *) &got_addr) == CMPSADDR_MATCH) {
+			plog(LLV_DEBUG, LOCATION, NULL,
+				"IDcr matches proposal.\n");
+#ifdef ENABLE_NATT
+		} else if (iph2->natoa_dst != NULL
+			&& cmpsaddr(iph2->natoa_dst,
+				    (struct sockaddr *) &got_addr) == CMPSADDR_MATCH) {
+			plog(LLV_DEBUG, LOCATION, NULL,
+				"IDcr matches NAT-OAr.\n");
+#endif
+		} else {
+			plog(LLV_ERROR, LOCATION, NULL,
+				"mismatched IDcr was returned.\n");
+			error = ISAKMP_NTYPE_ATTRIBUTES_NOT_SUPPORTED;
+			goto end;
+		}
+	}
+
 	/* Fixed buffer for calculating HASH */
 	memcpy(hbuf->v, iph2->nonce->v, iph2->nonce->l);
 	plog(LLV_DEBUG, LOCATION, NULL,
@@ -516,6 +746,8 @@
 
 	/* validity check SA payload sent from responder */
 	if (ipsecdoi_checkph2proposal(iph2) < 0) {
+		plog(LLV_ERROR, LOCATION, iph2->ph1->remote,
+			"proposal check failed.\n");
 		error = ISAKMP_NTYPE_NO_PROPOSAL_CHOSEN;
 		goto end;
 	}
@@ -532,6 +764,10 @@
 		vfree(pbuf);
 	if (msg)
 		vfree(msg);
+	if (idci)
+		vfree(idci);
+	if (idcr)
+		vfree(idcr);
 
 	if (error) {
 		VPTRINIT(iph2->sa_ret);
@@ -539,6 +775,16 @@
 		VPTRINIT(iph2->dhpub_p);
 		VPTRINIT(iph2->id);
 		VPTRINIT(iph2->id_p);
+#ifdef ENABLE_NATT
+		if (iph2->natoa_src) {
+			racoon_free(iph2->natoa_src);
+			iph2->natoa_src = NULL;
+		}
+		if (iph2->natoa_dst) {
+			racoon_free(iph2->natoa_dst);
+			iph2->natoa_dst = NULL;
+		}
+#endif
 	}
 
 	return error;
@@ -619,8 +865,7 @@
 	/* if there is commit bit, need resending */
 	if (ISSET(iph2->flags, ISAKMP_FLAG_C)) {
 		/* send the packet, add to the schedule to resend */
-		iph2->retry_counter = iph2->ph1->rmconf->retry_counter;
-		if (isakmp_ph2resend(iph2) == -1)
+		if (isakmp_ph2send(iph2) == -1)
 			goto end;
 	} else {
 		/* send the packet */
@@ -735,7 +980,7 @@
 				    "Ignoring multiples notifications\n");
 				break;
 			}
-			isakmp_check_notify(pa->ptr, iph2->ph1);
+			ph2_recv_n(iph2, pa->ptr);
 			notify = vmalloc(pa->len);
 			if (notify == NULL) {
 				plog(LLV_ERROR, LOCATION, NULL,
@@ -828,7 +1073,7 @@
 
 /*
  * receive from initiator
- * 	HDR*, HASH(1), SA, Ni [, KE ] [, IDi2, IDr2 ]
+ * 	HDR*, HASH(1), SA, Ni [, KE ] [, IDi2, IDr2 ] [, NAT-OAi, NAT-OAr ]
  */
 int
 quick_r1recv(iph2, msg0)
@@ -862,8 +1107,11 @@
 	}
 	/* decrypt packet */
 	msg = oakley_do_decrypt(iph2->ph1, msg0, iph2->ivm->iv, iph2->ivm->ive);
-	if (msg == NULL)
+	if (msg == NULL) {
+		plog(LLV_ERROR, LOCATION, iph2->ph1->remote,
+			"Packet decryption failed.\n");
 		goto end;
+	}
 
 	/* create buffer for using to validate HASH(1) */
 	/*
@@ -947,18 +1195,27 @@
 					"Multi SAs isn't supported.\n");
 				goto end;
 			}
-			if (isakmp_p2ph(&iph2->sa, pa->ptr) < 0)
+			if (isakmp_p2ph(&iph2->sa, pa->ptr) < 0) {
+				plog(LLV_ERROR, LOCATION, iph2->ph1->remote,
+					"duplicate ISAKMP_NPTYPE_SA.\n");
 				goto end;
+			}
 			break;
 
 		case ISAKMP_NPTYPE_NONCE:
-			if (isakmp_p2ph(&iph2->nonce_p, pa->ptr) < 0)
+			if (isakmp_p2ph(&iph2->nonce_p, pa->ptr) < 0) {
+				plog(LLV_ERROR, LOCATION, iph2->ph1->remote,
+					"duplicate ISAKMP_NPTYPE_NONCE.\n");
 				goto end;
+			}
 			break;
 
 		case ISAKMP_NPTYPE_KE:
-			if (isakmp_p2ph(&iph2->dhpub_p, pa->ptr) < 0)
+			if (isakmp_p2ph(&iph2->dhpub_p, pa->ptr) < 0) {
+				plog(LLV_ERROR, LOCATION, iph2->ph1->remote,
+					"duplicate ISAKMP_NPTYPE_KE.\n");
 				goto end;
+			}
 			break;
 
 		case ISAKMP_NPTYPE_ID:
@@ -991,13 +1248,47 @@
 			break;
 
 		case ISAKMP_NPTYPE_N:
-			isakmp_check_notify(pa->ptr, iph2->ph1);
+			ph2_recv_n(iph2, pa->ptr);
 			break;
 
 #ifdef ENABLE_NATT
 		case ISAKMP_NPTYPE_NATOA_DRAFT:
 		case ISAKMP_NPTYPE_NATOA_RFC:
-			/* Ignore original source/destination messages */
+		    {
+			struct sockaddr_storage addr;
+			struct sockaddr *daddr;
+			u_int8_t prefix;
+			u_int16_t ul_proto;
+			vchar_t *vp = NULL;
+
+			if (isakmp_p2ph(&vp, pa->ptr) < 0)
+				goto end;
+
+			error = ipsecdoi_id2sockaddr(vp,
+					(struct sockaddr *) &addr,
+					&prefix, &ul_proto);
+
+			vfree(vp);
+
+			if (error)
+				goto end;
+
+			daddr = dupsaddr((struct sockaddr *) &addr);
+			if (daddr == NULL)
+				goto end;
+
+			if (iph2->natoa_dst == NULL)
+				iph2->natoa_dst = daddr;
+			else if (iph2->natoa_src == NULL)
+				iph2->natoa_src = daddr;
+			else {
+				racoon_free(daddr);
+				plog(LLV_ERROR, LOCATION, iph2->ph1->remote,
+					"received too many NAT-OA payloads.\n");
+				error = ISAKMP_NTYPE_PAYLOAD_MALFORMED;
+				goto end;
+			}
+		    }
 			break;
 #endif
 
@@ -1080,12 +1371,15 @@
 			plog(LLV_ERROR, LOCATION, NULL,
 				"failed to generate a proposal template "
 				"from client's proposal.\n");
-			return ISAKMP_INTERNAL_ERROR;
+			error = ISAKMP_INTERNAL_ERROR;
+			goto end;
 		}
 		/*FALLTHROUGH*/
 	case 0:
 		/* select single proposal or reject it. */
 		if (ipsecdoi_selectph2proposal(iph2) < 0) {
+			plog(LLV_ERROR, LOCATION, iph2->ph1->remote,
+				"no proposal chosen.\n");
 			error = ISAKMP_NTYPE_NO_PROPOSAL_CHOSEN;
 			goto end;
 		}
@@ -1135,6 +1429,16 @@
 		VPTRINIT(iph2->dhpub_p);
 		VPTRINIT(iph2->id);
 		VPTRINIT(iph2->id_p);
+#ifdef ENABLE_NATT
+		if (iph2->natoa_src) {
+			racoon_free(iph2->natoa_src);
+			iph2->natoa_src = NULL;
+		}
+		if (iph2->natoa_dst) {
+			racoon_free(iph2->natoa_dst);
+			iph2->natoa_dst = NULL;
+		}
+#endif
 	}
 
 	return error;
@@ -1165,8 +1469,8 @@
 
 	plog(LLV_DEBUG, LOCATION, NULL, "pfkey getspi sent.\n");
 
-	iph2->sce = sched_new(lcconf->wait_ph2complete,
-		pfkey_timeover_stub, iph2);
+	sched_schedule(&iph2->sce, lcconf->wait_ph2complete,
+		       quick_timeover_stub);
 
 	error = 0;
 
@@ -1176,7 +1480,7 @@
 
 /*
  * send to initiator
- * 	HDR*, HASH(2), SA, Nr [, KE ] [, IDi2, IDr2 ]
+ * 	HDR*, HASH(2), SA, Nr [, KE ] [, IDi2, IDr2 ] [, NAT-OAi, NAT-OAr ]
  */
 int
 quick_r2send(iph2, msg)
@@ -1189,8 +1493,13 @@
 	char *p;
 	int tlen;
 	int error = ISAKMP_INTERNAL_ERROR;
+	int natoa = ISAKMP_NPTYPE_NONE;
 	int pfsgroup;
 	u_int8_t *np_p = NULL;
+#ifdef ENABLE_NATT
+	vchar_t *nat_oai = NULL;
+	vchar_t *nat_oar = NULL;
+#endif
 
 	/* validity check */
 	if (msg != NULL) {
@@ -1231,6 +1540,33 @@
 		}
 	}
 
+#ifdef ENABLE_NATT
+	/*
+	 * RFC3947 5.2. if we chose UDP-Encapsulated-Transport
+	 * we should send NAT-OA
+	 */
+	if (ipsecdoi_transportmode(iph2->proposal)
+	 && (iph2->ph1->natt_flags & NAT_DETECTED)) {
+		natoa = iph2->ph1->natt_options->payload_nat_oa;
+
+		nat_oai = ipsecdoi_sockaddr2id(iph2->dst,
+			IPSECDOI_PREFIX_HOST, IPSEC_ULPROTO_ANY);
+		nat_oar = ipsecdoi_sockaddr2id(iph2->src,
+			IPSECDOI_PREFIX_HOST, IPSEC_ULPROTO_ANY);
+
+		if (nat_oai == NULL || nat_oar == NULL) {
+			plog(LLV_ERROR, LOCATION, NULL,
+				"failed to generate NAT-OA payload.\n");
+			goto end;
+		}
+
+		plog(LLV_DEBUG, LOCATION, NULL, "NAT-OAi:\n");
+		plogdump(LLV_DEBUG, nat_oai->v, nat_oai->l);
+		plog(LLV_DEBUG, LOCATION, NULL, "NAT-OAr:\n");
+		plogdump(LLV_DEBUG, nat_oar->v, nat_oar->l);
+	}
+#endif
+
 	/* create SA;NONCE payload, and KE and ID if need */
 	tlen = sizeof(*gen) + iph2->sa_ret->l
 		+ sizeof(*gen) + iph2->nonce->l;
@@ -1239,6 +1575,10 @@
 	if (iph2->id_p != NULL)
 		tlen += (sizeof(*gen) + iph2->id_p->l
 			+ sizeof(*gen) + iph2->id->l);
+#ifdef ENABLE_NATT
+	if (natoa != ISAKMP_NPTYPE_NONE)
+		tlen += 2 * sizeof(*gen) + nat_oai->l + nat_oar->l;
+#endif
 
 	body = vmalloc(tlen);
 	if (body == NULL) { 
@@ -1258,14 +1598,14 @@
 				? ISAKMP_NPTYPE_KE
 				: (iph2->id_p != NULL
 					? ISAKMP_NPTYPE_ID
-					: ISAKMP_NPTYPE_NONE));
+					: natoa));
 
 	/* add KE payload if need. */
 	if (iph2->dhpub_p != NULL && pfsgroup != 0) {
 		np_p = &((struct isakmp_gen *)p)->np;	/* XXX */
 		p = set_isakmp_payload(p, iph2->dhpub,
 			(iph2->id_p == NULL)
-				? ISAKMP_NPTYPE_NONE
+				? natoa
 				: ISAKMP_NPTYPE_ID);
 	}
 
@@ -1275,9 +1615,17 @@
 		p = set_isakmp_payload(p, iph2->id_p, ISAKMP_NPTYPE_ID);
 		/* IDcr */
 		np_p = &((struct isakmp_gen *)p)->np;	/* XXX */
-		p = set_isakmp_payload(p, iph2->id, ISAKMP_NPTYPE_NONE);
+		p = set_isakmp_payload(p, iph2->id, natoa);
 	}
 
+#ifdef ENABLE_NATT
+	/* NAT-OA */
+	if (natoa != ISAKMP_NPTYPE_NONE) {
+		p = set_isakmp_payload(p, nat_oai, natoa);
+		p = set_isakmp_payload(p, nat_oar, ISAKMP_NPTYPE_NONE);
+	}
+#endif
+
 	/* add a RESPONDER-LIFETIME notify payload if needed */
     {
 	vchar_t *data = NULL;
@@ -1350,8 +1698,7 @@
 		goto end;
 
 	/* send the packet, add to the schedule to resend */
-	iph2->retry_counter = iph2->ph1->rmconf->retry_counter;
-	if (isakmp_ph2resend(iph2) == -1)
+	if (isakmp_ph2send(iph2) == -1)
 		goto end;
 
 	/* the sending message is added to the received-list. */
@@ -1371,6 +1718,12 @@
 		vfree(body);
 	if (hash != NULL)
 		vfree(hash);
+#ifdef ENABLE_NATT
+	if (nat_oai != NULL)
+		vfree(nat_oai);
+	if (nat_oar != NULL)
+		vfree(nat_oar);
+#endif
 
 	return error;
 }
@@ -1378,6 +1731,7 @@
 /*
  * receive from initiator
  * 	HDR*, HASH(3)
+
  */
 int
 quick_r3recv(iph2, msg0)
@@ -1421,7 +1775,7 @@
 			hash = (struct isakmp_pl_hash *)pa->ptr;
 			break;
 		case ISAKMP_NPTYPE_N:
-			isakmp_check_notify(pa->ptr, iph2->ph1);
+			ph2_recv_n(iph2, pa->ptr);
 			break;
 		default:
 			/* don't send information, see ident_r1recv() */
@@ -1802,25 +2156,11 @@
 get_sainfo_r(iph2)
 	struct ph2handle *iph2;
 {
-	vchar_t *idsrc = NULL, *iddst = NULL;
-	int prefixlen;
+	vchar_t *idsrc = NULL, *iddst = NULL, *client = NULL;
 	int error = ISAKMP_INTERNAL_ERROR;
-	int remoteid = 0;
 
 	if (iph2->id == NULL) {
-		switch (iph2->src->sa_family) {
-		case AF_INET:
-			prefixlen = sizeof(struct in_addr) << 3;
-			break;
-		case AF_INET6:
-			prefixlen = sizeof(struct in6_addr) << 3;
-			break;
-		default:
-			plog(LLV_ERROR, LOCATION, NULL,
-				"invalid family: %d\n", iph2->src->sa_family);
-			goto end;
-		}
-		idsrc = ipsecdoi_sockaddr2id(iph2->src, prefixlen,
+		idsrc = ipsecdoi_sockaddr2id(iph2->src, IPSECDOI_PREFIX_HOST,
 					IPSEC_ULPROTO_ANY);
 	} else {
 		idsrc = vdup(iph2->id);
@@ -1832,19 +2172,7 @@
 	}
 
 	if (iph2->id_p == NULL) {
-		switch (iph2->dst->sa_family) {
-		case AF_INET:
-			prefixlen = sizeof(struct in_addr) << 3;
-			break;
-		case AF_INET6:
-			prefixlen = sizeof(struct in6_addr) << 3;
-			break;
-		default:
-			plog(LLV_ERROR, LOCATION, NULL,
-				"invalid family: %d\n", iph2->dst->sa_family);
-			goto end;
-		}
-		iddst = ipsecdoi_sockaddr2id(iph2->dst, prefixlen,
+		iddst = ipsecdoi_sockaddr2id(iph2->dst, IPSECDOI_PREFIX_HOST,
 					IPSEC_ULPROTO_ANY);
 	} else {
 		iddst = vdup(iph2->id_p);
@@ -1855,19 +2183,34 @@
 		goto end;
 	}
 
-	{
-		struct remoteconf *conf;
-		conf = getrmconf(iph2->dst);
-		if (conf != NULL)
-			remoteid=conf->ph1id;
-		else{
-			plog(LLV_DEBUG, LOCATION, NULL, "Warning: no valid rmconf !\n");
-			remoteid=0;
+#ifdef ENABLE_HYBRID
+
+	/* clientaddr check : obtain modecfg address */
+	if (iph2->ph1->mode_cfg != NULL) {
+		if ((iph2->ph1->mode_cfg->flags & ISAKMP_CFG_ADDR4_EXTERN) ||
+		    (iph2->ph1->mode_cfg->flags & ISAKMP_CFG_ADDR4_LOCAL)){
+			struct sockaddr saddr;
+			saddr.sa_family = AF_INET;
+#ifndef __linux__
+			saddr.sa_len = sizeof(struct sockaddr_in);
+#endif
+			((struct sockaddr_in *)&saddr)->sin_port = IPSEC_PORT_ANY;
+			memcpy(&((struct sockaddr_in *)&saddr)->sin_addr, 
+				&iph2->ph1->mode_cfg->addr4, sizeof(struct in_addr));
+			client = ipsecdoi_sockaddr2id(&saddr, 32, IPSEC_ULPROTO_ANY);
 		}
-		
 	}
 
-	iph2->sainfo = getsainfo(idsrc, iddst, iph2->ph1->id_p, remoteid);
+	/* clientaddr check, fallback to peer address */
+	if (client == NULL)
+	{
+		client = ipsecdoi_sockaddr2id(iph2->dst, IPSECDOI_PREFIX_HOST,
+					IPSEC_ULPROTO_ANY);
+	}
+#endif
+
+	/* obtain a matching sainfo section */
+	iph2->sainfo = getsainfo(idsrc, iddst, iph2->ph1->id_p, client, iph2->ph1->rmconf->ph1id);
 	if (iph2->sainfo == NULL) {
 		plog(LLV_ERROR, LOCATION, NULL,
 			"failed to get sainfo.\n");
@@ -1890,6 +2233,8 @@
 		vfree(idsrc);
 	if (iddst)
 		vfree(iddst);
+	if (client)
+		vfree(client);
 
 	return error;
 }
@@ -1921,8 +2266,8 @@
 		return ISAKMP_NTYPE_INVALID_ID_INFORMATION;
 	}
 
-	/* make sure if id[src,dst] is null. */
-	if (iph2->src_id || iph2->dst_id) {
+	/* make sure if sa_[src, dst] are null. */
+	if (iph2->sa_src || iph2->sa_dst) {
 		plog(LLV_ERROR, LOCATION, NULL,
 			"Why do ID[src,dst] exist already.\n");
 		return ISAKMP_INTERNAL_ERROR;
@@ -2026,29 +2371,45 @@
 		}
 #endif
 
-		/* make id[src,dst] if both ID types are IP address and same */
-		if (_XIDT(iph2->id_p) == idi2type
-		 && spidx.dst.ss_family == spidx.src.ss_family) {
-			iph2->src_id = dupsaddr((struct sockaddr *)&spidx.dst);
-			if (iph2->src_id  == NULL) {
-				plog(LLV_ERROR, LOCATION, NULL,
-				    "buffer allocation failed.\n");
-				return ISAKMP_INTERNAL_ERROR;
-			}
-			iph2->dst_id = dupsaddr((struct sockaddr *)&spidx.src);
-			if (iph2->dst_id  == NULL) {
-				plog(LLV_ERROR, LOCATION, NULL,
-				    "buffer allocation failed.\n");
-				return ISAKMP_INTERNAL_ERROR;
-			}
-		}
+		/* Before setting iph2->[sa_src, sa_dst] with the addresses
+		 * provided in ID payloads, we check:
+		 * - they are both addresses of same family
+		 * - sainfo has not been selected only based on ID payload
+		 *   information but also based on specific Phase 1
+		 *   credentials (iph2->sainfo->id_i is defined), i.e.
+		 *   local configuration _explicitly_ expect that user
+		 *   (e.g. from asn1dn "C=FR, ...") with those IDs) */
+		if (_XIDT(iph2->id_p) == idi2type &&
+		    spidx.dst.ss_family == spidx.src.ss_family &&
+		    iph2->sainfo && iph2->sainfo->id_i) {
 
+			iph2->sa_src = dupsaddr((struct sockaddr *)&spidx.dst);
+			if (iph2->sa_src  == NULL) {
+				plog(LLV_ERROR, LOCATION, NULL,
+				    "buffer allocation failed.\n");
+				return ISAKMP_INTERNAL_ERROR;
+			}
+
+			iph2->sa_dst = dupsaddr((struct sockaddr *)&spidx.src);
+			if (iph2->sa_dst  == NULL) {
+				plog(LLV_ERROR, LOCATION, NULL,
+				    "buffer allocation failed.\n");
+				return ISAKMP_INTERNAL_ERROR;
+			}
+		} else {
+			plog(LLV_DEBUG, LOCATION, NULL,
+			     "Either family (%d - %d), types (%d - %d) of ID "
+			     "from initiator differ or matching sainfo "
+			     "has no id_i defined for the peer. Not filling "
+			     "iph2->sa_src and iph2->sa_dst.\n",
+			     spidx.src.ss_family, spidx.dst.ss_family,
+			     _XIDT(iph2->id_p),idi2type);
+		}
 	} else {
 		plog(LLV_DEBUG, LOCATION, NULL,
-			"get a source address of SP index "
-			"from phase1 address "
-			"due to no ID payloads found "
-			"OR because ID type is not address.\n");
+		     "get a source address of SP index from Phase 1"
+		     "addresses due to no ID payloads found"
+		     "OR because ID type is not address.\n");
 
 		/* see above comment. */
 		memcpy(&spidx.src, iph2->dst, sysdep_sa_len(iph2->dst));
@@ -2070,7 +2431,7 @@
 #undef _XIDT
 
 	plog(LLV_DEBUG, LOCATION, NULL,
-		"get a src address from ID payload "
+		"get src address from ID payload "
 		"%s prefixlen=%u ul_proto=%u\n",
 		saddr2str((struct sockaddr *)&spidx.src),
 		spidx.prefs, spidx.ul_proto);
@@ -2184,6 +2545,76 @@
 	}
 #endif /* HAVE_SECCTX */
 
+	iph2->spid = sp_in->id;
+
+	return 0;
+}
+
+/*
+ * handle a notification payload inside phase2 exchange.
+ * phase2 is always encrypted, so it does not need to be checked
+ * for explicitely.
+ */
+static int
+ph2_recv_n(iph2, gen)
+	struct ph2handle *iph2;
+	struct isakmp_gen *gen;
+{
+	struct ph1handle *iph1 = iph2->ph1;
+	struct isakmp_pl_n *notify = (struct isakmp_pl_n *) gen;
+	u_int type;
+	int check_level;
+
+	type = ntohs(notify->type);
+	switch (type) {
+	case ISAKMP_NTYPE_CONNECTED:
+		break;
+	case ISAKMP_NTYPE_INITIAL_CONTACT:
+		return isakmp_info_recv_initialcontact(iph1, iph2);
+	case ISAKMP_NTYPE_RESPONDER_LIFETIME:
+		ipsecdoi_parse_responder_lifetime(notify,
+			&iph2->lifetime_secs, &iph2->lifetime_kb);
+
+		if (iph1 != NULL && iph1->rmconf != NULL) {
+			check_level = iph1->rmconf->pcheck_level;
+		} else {
+			if (iph1 != NULL)
+				plog(LLV_DEBUG, LOCATION, NULL,
+					"No phase1 rmconf found !\n");
+			else
+				plog(LLV_DEBUG, LOCATION, NULL,
+					"No phase1 found !\n");
+			check_level = PROP_CHECK_EXACT;
+		}
+
+		switch (check_level) {
+		case PROP_CHECK_OBEY:
+			break;
+		case PROP_CHECK_STRICT:
+		case PROP_CHECK_CLAIM:
+			if (iph2->sainfo == NULL
+			 || iph2->sainfo->lifetime <= iph2->lifetime_secs) {
+				plog(LLV_WARNING, LOCATION, NULL,
+					"RESPONDER-LIFETIME: lifetime mismatch\n");
+				iph2->lifetime_secs = 0;
+			}
+			break;
+		case PROP_CHECK_EXACT:
+			if (iph2->sainfo == NULL
+			 || iph2->sainfo->lifetime != iph2->lifetime_secs) {
+				plog(LLV_WARNING, LOCATION, NULL,
+					"RESPONDER-LIFETIME: lifetime mismatch\n");
+				iph2->lifetime_secs = 0;
+			}
+			break;
+		}
+		break;
+	default:
+		isakmp_log_notify(iph2->ph1, notify, "phase2 exchange");
+		isakmp_info_send_n2(iph2, ISAKMP_NTYPE_INVALID_PAYLOAD_TYPE,
+			NULL);
+		break;
+	}
 	return 0;
 }
 
diff --git a/src/racoon/isakmp_unity.c b/src/racoon/isakmp_unity.c
index 9873f59..a1bf793 100644
--- a/src/racoon/isakmp_unity.c
+++ b/src/racoon/isakmp_unity.c
@@ -1,4 +1,4 @@
-/*	$NetBSD: isakmp_unity.c,v 1.7 2006/10/09 06:17:20 manu Exp $	*/
+/*	$NetBSD: isakmp_unity.c,v 1.9 2007/10/19 03:37:19 manu Exp $	*/
 
 /* Id: isakmp_unity.c,v 1.10 2006/07/31 04:49:23 manubsd Exp */
 
@@ -305,32 +305,41 @@
 	struct unity_network * network;
 	int *count;
 {
-	struct unity_netentry * newentry;
+	struct unity_netentry * nentry;
+
+	/*
+	 * search for network in current list
+	 * to avoid adding duplicates
+	 */
+	for (nentry = *list; nentry != NULL; nentry = nentry->next)
+		if (memcmp(&nentry->network, network,
+			   sizeof(struct unity_network)) == 0)
+			return 0;	/* it's a dupe */
 
 	/*
 	 * allocate new netentry and copy
-         * new splitnet network data
+	 * new splitnet network data
 	 */
-	newentry = (struct unity_netentry *)
+	nentry = (struct unity_netentry *)
 		racoon_malloc(sizeof(struct unity_netentry));
-	if (newentry == NULL)
+	if (nentry == NULL)
 		return -1;
 
-	memcpy(&newentry->network,network,
+	memcpy(&nentry->network,network,
 		sizeof(struct unity_network));
-	newentry->next = NULL;
+	nentry->next = NULL;
 
 	/*
 	 * locate the last netentry in our
 	 * splitnet list and add our entry
 	 */
 	if (*list == NULL)
-		*list = newentry;
+		*list = nentry;
 	else {
 		struct unity_netentry * tmpentry = *list;
 		while (tmpentry->next != NULL)
 			tmpentry = tmpentry->next;
-		tmpentry->next = newentry;
+		tmpentry->next = nentry;
 	}
 
 	(*count)++;
@@ -354,8 +363,9 @@
 	}
 }
 
-char * splitnet_list_2str(list)
+char * splitnet_list_2str(list, splitnet_ipaddr)
 	struct unity_netentry * list;
+	enum splinet_ipaddr splitnet_ipaddr;
 {
 	struct unity_netentry * netentry;
 	char tmp1[40];
@@ -389,8 +399,17 @@
 
 		inet_ntop(AF_INET, &netentry->network.addr4, tmp1, 40);
 		inet_ntop(AF_INET, &netentry->network.mask4, tmp2, 40);
+		if (splitnet_ipaddr == CIDR) {
+			uint32_t tmp3;
+			int cidrmask;
 
-		len += sprintf(str+len, "%s/%s ", tmp1, tmp2);
+			tmp3 = ntohl(netentry->network.mask4.s_addr);
+			for (cidrmask = 0; tmp3 != 0; cidrmask++)
+				tmp3 <<= 1;
+			len += sprintf(str+len, "%s/%d ", tmp1, cidrmask);
+		} else {
+			len += sprintf(str+len, "%s/%s ", tmp1, tmp2);
+		}
 
 		netentry = netentry->next;
 	}
diff --git a/src/racoon/isakmp_unity.h b/src/racoon/isakmp_unity.h
index b52f02c..3667d0d 100644
--- a/src/racoon/isakmp_unity.h
+++ b/src/racoon/isakmp_unity.h
@@ -1,4 +1,4 @@
-/*	$NetBSD: isakmp_unity.h,v 1.4 2006/09/09 16:22:09 manu Exp $	*/
+/*	$NetBSD: isakmp_unity.h,v 1.5 2007/10/19 03:37:19 manu Exp $	*/
 
 /*	$KAME$ */
 
@@ -31,6 +31,8 @@
  * SUCH DAMAGE.
  */
 
+enum splinet_ipaddr { NETMASK, CIDR }; 
+
 /* ISAKMP notifies specific to the Unity vendor Id */
 /* Sent during xauth if the user types his password too slowly */
 #define ISAKMP_NTYPE_UNITY_HEARTBEAT	40500
@@ -66,7 +68,7 @@
 
 int	splitnet_list_add(struct unity_netentry **, struct unity_network *, int *);
 void	splitnet_list_free(struct unity_netentry *, int *);
-char *	splitnet_list_2str(struct unity_netentry *);
+char *	splitnet_list_2str(struct unity_netentry *, enum splinet_ipaddr);
 
 vchar_t *isakmp_unity_req(struct ph1handle *, struct isakmp_data *);
 void isakmp_unity_reply(struct ph1handle *, struct isakmp_data *);
diff --git a/src/racoon/isakmp_var.h b/src/racoon/isakmp_var.h
index f4ef45d..09e4e7f 100644
--- a/src/racoon/isakmp_var.h
+++ b/src/racoon/isakmp_var.h
@@ -1,11 +1,11 @@
-/*	$NetBSD: isakmp_var.h,v 1.6.6.1 2007/02/20 09:08:49 vanhu Exp $	*/
+/*	$NetBSD: isakmp_var.h,v 1.17 2010/11/12 10:36:37 tteras Exp $	*/
 
 /* Id: isakmp_var.h,v 1.12 2005/05/07 14:45:31 manubsd Exp */
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
  * All rights reserved.
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
@@ -17,7 +17,7 @@
  * 3. Neither the name of the project nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
- * 
+ *
  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@@ -35,6 +35,7 @@
 #define _ISAKMP_VAR_H
 
 #include "vmbuf.h"
+#include "policy.h"
 
 #define PORT_ISAKMP 500
 #define PORT_ISAKMP_NATT 4500
@@ -56,40 +57,39 @@
 struct ph1handle;
 struct ph2handle;
 struct remoteconf;
-struct isakmp_gen;
 struct ipsecdoi_pl_id;	/* XXX */
 struct isakmp_pl_ke;	/* XXX */
 struct isakmp_pl_nonce;	/* XXX */
 
-extern int isakmp_handler __P((int));
-extern int isakmp_ph1begin_i __P((struct remoteconf *, struct sockaddr *,
-	struct sockaddr *));
+extern struct ph1handle *isakmp_ph1begin_i __P((struct remoteconf *,
+	struct sockaddr *, struct sockaddr *));
 
 extern vchar_t *isakmp_parsewoh __P((int, struct isakmp_gen *, int));
 extern vchar_t *isakmp_parse __P((vchar_t *));
 
 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 int isakmp_open __P((struct sockaddr *, int));
+extern void isakmp_close __P((int fd));
 extern int isakmp_send __P((struct ph1handle *, vchar_t *));
 
-extern void isakmp_ph1resend_stub __P((void *));
-extern int isakmp_ph1resend __P((struct ph1handle *));
-extern void isakmp_ph2resend_stub __P((void *));
-extern int isakmp_ph2resend __P((struct ph2handle *));
-extern void isakmp_ph1expire_stub __P((void *));
+extern int isakmp_ph1send __P((struct ph1handle *));
+extern int isakmp_ph2send __P((struct ph2handle *));
+extern void isakmp_ph1dying_stub __P((struct sched *));
+extern void isakmp_ph1dying __P((struct ph1handle *));
+extern void isakmp_ph1expire_stub __P((struct sched *));
 extern void isakmp_ph1expire __P((struct ph1handle *));
-extern void isakmp_ph1delete_stub __P((void *));
+extern void isakmp_ph1delete_stub __P((struct sched *));
 extern void isakmp_ph1delete __P((struct ph1handle *));
-extern void isakmp_ph2expire_stub __P((void *));
+extern void isakmp_ph2expire_stub __P((struct sched *));
 extern void isakmp_ph2expire __P((struct ph2handle *));
-extern void isakmp_ph2delete_stub __P((void *));
+extern void isakmp_ph2delete_stub __P((struct sched *));
 extern void isakmp_ph2delete __P((struct ph2handle *));
 
-extern int isakmp_post_acquire __P((struct ph2handle *));
+extern int isakmp_get_sainfo __P((struct ph2handle *, struct secpolicy *, struct secpolicy *));
+extern int isakmp_post_acquire __P((struct ph2handle *, struct ph1handle *, int));
 extern int isakmp_post_getspi __P((struct ph2handle *));
-extern void isakmp_chkph1there_stub __P((void *));
+extern void isakmp_chkph1there_stub __P((struct sched *));
 extern void isakmp_chkph1there __P((struct ph2handle *));
 
 extern caddr_t isakmp_set_attr_v __P((caddr_t, int, caddr_t, int));
@@ -106,8 +106,19 @@
 extern caddr_t set_isakmp_header2 __P((vchar_t *, struct ph2handle *, int));
 extern caddr_t set_isakmp_payload __P((caddr_t, vchar_t *, int));
 
-extern struct payload_list *isakmp_plist_append __P((struct payload_list *plist, 
-	vchar_t *payload, int payload_type));
+extern struct payload_list *isakmp_plist_append_full __P((
+	struct payload_list *plist, vchar_t *payload,
+	u_int8_t payload_type, u_int8_t free));
+
+static inline struct payload_list *isakmp_plist_append(plist, payload, payload_type)
+	struct payload_list *plist;
+	vchar_t *payload;
+	u_int8_t payload_type;
+{
+	return isakmp_plist_append_full(plist, payload, payload_type, 0);
+}
+
+
 extern vchar_t *isakmp_plist_set_all __P((struct payload_list **plist,
 	struct ph1handle *iph1));
 
@@ -120,7 +131,7 @@
 	struct remoteconf *, struct sockaddr *, struct sockaddr *));
 extern void log_ph1established __P((const struct ph1handle *));
 
-extern void script_hook __P((struct ph1handle *, int)); 
+extern void script_hook __P((struct ph1handle *, int));
 extern int script_env_append __P((char ***, int *, char *, char *));
 extern int script_exec __P((char *, int, char * const *));
 
@@ -129,4 +140,5 @@
 #ifdef INET6
 u_int32_t setscopeid __P((struct sockaddr *, struct sockaddr *));
 #endif
+
 #endif /* _ISAKMP_VAR_H */
diff --git a/src/racoon/isakmp_xauth.c b/src/racoon/isakmp_xauth.c
index 12e5ef6..853caaa 100644
--- a/src/racoon/isakmp_xauth.c
+++ b/src/racoon/isakmp_xauth.c
@@ -1,4 +1,4 @@
-/*	$NetBSD: isakmp_xauth.c,v 1.11.6.2 2009/04/20 13:35:36 tteras Exp $	*/
+/*	$NetBSD: isakmp_xauth.c,v 1.22 2011/03/14 15:50:36 vanhu Exp $	*/
 
 /* Id: isakmp_xauth.c,v 1.38 2006/08/22 18:17:17 manubsd Exp */
 
@@ -40,6 +40,7 @@
 
 #include <netinet/in.h>
 
+#include <assert.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
@@ -95,9 +96,9 @@
 
 #ifdef HAVE_LIBRADIUS
 #include <radlib.h>
-
 struct rad_handle *radius_auth_state = NULL;
 struct rad_handle *radius_acct_state = NULL;
+struct xauth_rad_config xauth_rad_config;
 #endif
 
 #ifdef HAVE_LIBPAM
@@ -129,7 +130,7 @@
 	size_t tlen;
 
 	/* Status checks */
-	if (iph1->status != PHASE1ST_ESTABLISHED) {
+	if (iph1->status < PHASE1ST_ESTABLISHED) {
 		plog(LLV_ERROR, LOCATION, NULL, 
 		    "Xauth request while phase 1 is not completed\n");
 		return;
@@ -311,7 +312,7 @@
 		 * On failure, throttle the connexion for the remote host
 		 * in order to make password attacks more difficult.
 		 */
-		throttle_delay = throttle_host(iph1->remote, res) - time(NULL);
+		throttle_delay = throttle_host(iph1->remote, res);
 		if (throttle_delay > 0) {
 			char *str;
 
@@ -329,7 +330,7 @@
 		if (throttle_delay != 0) {
 			struct xauth_reply_arg *xra;
 
-			if ((xra = racoon_malloc(sizeof(*xra))) == NULL) {
+			if ((xra = racoon_calloc(1, sizeof(*xra))) == NULL) {
 				plog(LLV_ERROR, LOCATION, NULL, 
 				    "malloc failed, bypass throttling\n");
 				return xauth_reply(iph1, port, id, res);
@@ -344,7 +345,8 @@
 			xra->port = port;
 			xra->id = id;
 			xra->res = res;
-			sched_new(throttle_delay, xauth_reply_stub, xra);
+			sched_schedule(&xra->sc, throttle_delay,
+				       xauth_reply_stub);
 		} else {
 			return xauth_reply(iph1, port, id, res);
 		}
@@ -354,10 +356,10 @@
 }
 
 void 
-xauth_reply_stub(args)
-	void *args;
+xauth_reply_stub(sc)
+	struct sched *sc;
 {
-	struct xauth_reply_arg *xra = (struct xauth_reply_arg *)args;
+	struct xauth_reply_arg *xra = container_of(sc, struct xauth_reply_arg, sc);
 	struct ph1handle *iph1;
 
 	if ((iph1 = getph1byindex(&xra->index)) != NULL)
@@ -367,7 +369,6 @@
 		    "Delayed Xauth reply: phase 1 no longer exists.\n"); 
 
 	racoon_free(xra);
-	return;
 }
 
 int
@@ -390,7 +391,7 @@
 		xst->status = XAUTHST_NOTYET;
 
 		/* Delete Phase 1 SA */
-		if (iph1->status == PHASE1ST_ESTABLISHED)
+		if (iph1->status >= PHASE1ST_ESTABLISHED)
 			isakmp_info_send_d1(iph1);
 		remph1(iph1);
 		delph1(iph1);
@@ -447,6 +448,31 @@
 
 #ifdef HAVE_LIBRADIUS
 int
+xauth_radius_init_conf(int free)
+{
+	/* free radius config resources */
+	if (free) {
+		int i;
+		for (i = 0; i < xauth_rad_config.auth_server_count; i++) {
+			vfree(xauth_rad_config.auth_server_list[i].host);
+			vfree(xauth_rad_config.auth_server_list[i].secret);
+		}
+		for (i = 0; i < xauth_rad_config.acct_server_count; i++) {
+			vfree(xauth_rad_config.acct_server_list[i].host);
+			vfree(xauth_rad_config.acct_server_list[i].secret);
+		}
+		if (radius_auth_state != NULL)
+			rad_close(radius_auth_state);
+		if (radius_acct_state != NULL)
+			rad_close(radius_acct_state);
+	}
+
+	/* initialize radius config */
+	memset(&xauth_rad_config, 0, sizeof(xauth_rad_config));
+	return 0;
+}
+
+int
 xauth_radius_init(void)
 {
 	/* For first time use, initialize Radius */
@@ -458,13 +484,35 @@
 			return -1;
 		}
 
-		if (rad_config(radius_auth_state, NULL) != 0) {
-			plog(LLV_ERROR, LOCATION, NULL, 
-			    "Cannot open librarius config file: %s\n", 
-			    rad_strerror(radius_auth_state));
-			rad_close(radius_auth_state);
-			radius_auth_state = NULL;
-			return -1;
+		int auth_count = xauth_rad_config.auth_server_count;
+		int auth_added = 0;
+		if (auth_count) {
+			int i;
+			for (i = 0; i < auth_count; i++) {
+				if(!rad_add_server(
+					radius_auth_state,
+					xauth_rad_config.auth_server_list[i].host->v,
+					xauth_rad_config.auth_server_list[i].port,
+					xauth_rad_config.auth_server_list[i].secret->v,
+					xauth_rad_config.timeout,
+					xauth_rad_config.retries ))
+					auth_added++;
+				else
+					plog(LLV_WARNING, LOCATION, NULL,
+						"could not add radius auth server %s\n",
+						xauth_rad_config.auth_server_list[i].host->v);
+			}
+		}
+
+		if (!auth_added) {
+			if (rad_config(radius_auth_state, NULL) != 0) {
+				plog(LLV_ERROR, LOCATION, NULL, 
+				    "Cannot open libradius config file: %s\n", 
+				    rad_strerror(radius_auth_state));
+				rad_close(radius_auth_state);
+				radius_auth_state = NULL;
+				return -1;
+			}
 		}
 	}
 
@@ -476,13 +524,35 @@
 			return -1;
 		}
 
-		if (rad_config(radius_acct_state, NULL) != 0) {
-			plog(LLV_ERROR, LOCATION, NULL, 
-			    "Cannot open librarius config file: %s\n", 
-			    rad_strerror(radius_acct_state));
-			rad_close(radius_acct_state);
-			radius_acct_state = NULL;
-			return -1;
+		int acct_count = xauth_rad_config.acct_server_count;
+		int acct_added = 0;
+		if (acct_count) {
+			int i;
+			for (i = 0; i < acct_count; i++) {
+				if(!rad_add_server(
+					radius_acct_state,
+					xauth_rad_config.acct_server_list[i].host->v,
+					xauth_rad_config.acct_server_list[i].port,
+					xauth_rad_config.acct_server_list[i].secret->v,
+					xauth_rad_config.timeout,
+					xauth_rad_config.retries ))
+					acct_added++;
+				else
+					plog(LLV_WARNING, LOCATION, NULL,
+						"could not add radius account server %s\n",
+						xauth_rad_config.acct_server_list[i].host->v);
+			}
+		}
+
+		if (!acct_added) {
+			if (rad_config(radius_acct_state, NULL) != 0) {
+				plog(LLV_ERROR, LOCATION, NULL, 
+				    "Cannot open libradius config file: %s\n", 
+				    rad_strerror(radius_acct_state));
+				rad_close(radius_acct_state);
+				radius_acct_state = NULL;
+				return -1;
+			}
 		}
 	}
 
@@ -670,7 +740,7 @@
 		    "cannot allocate memory: %s\n", strerror(errno)); 
 		goto out;
 	}
-	
+
 	if ((error = pam_set_item(pam, PAM_RHOST, remote)) != 0) {
 		plog(LLV_ERROR, LOCATION, NULL, 
 		    "pam_set_item failed: %s\n", 
@@ -678,6 +748,13 @@
 		goto out;
 	}
 
+	if ((error = pam_set_item(pam, PAM_RUSER, usr)) != 0) {
+		plog(LLV_ERROR, LOCATION, NULL, 
+		    "pam_set_item failed: %s\n", 
+		    pam_strerror(pam, error));
+		goto out;
+	}
+
 	PAM_usr = usr;
 	PAM_pwd = pwd;
 	error = pam_authenticate(pam, 0);
@@ -720,7 +797,7 @@
 
 #ifdef HAVE_LIBLDAP
 int 
-xauth_ldap_init(void)
+xauth_ldap_init_conf(void)
 {
 	int tmplen;
 	int error = -1;
@@ -1255,7 +1332,7 @@
 	 * status. It does it if the chose authmethod is using Xauth.
 	 * On the client side (roadwarrior), we don't check anything.
 	 */
-	switch (AUTHMETHOD(iph1)) {
+	switch (iph1->approval->authmethod) {
 	case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_R:
 	case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_R:
 	case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_R:
@@ -1546,9 +1623,9 @@
 		 * when running as a client (initiator).
 		 */
 		xst = &iph1->mode_cfg->xauth;
-		switch(AUTHMETHOD(iph1)) {
+		switch (iph1->approval->authmethod) {
 		case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I:
-		case FICTIVE_AUTH_METHOD_XAUTH_PSKEY_I:
+		case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_I:
 		case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_I:
 		/* Not implemented ... */
 		case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_I:
@@ -1568,13 +1645,11 @@
 			plog(LLV_ERROR, LOCATION, NULL, 
 			    "Xauth authentication failed\n");
 
-			EVT_PUSH(iph1->local, iph1->remote, 
-			    EVTT_XAUTH_FAILED, NULL);
+			evt_phase1(iph1, EVT_PHASE1_XAUTH_FAILED, NULL);
 
 			iph1->mode_cfg->flags |= ISAKMP_CFG_DELETE_PH1;
 		} else {
-			EVT_PUSH(iph1->local, iph1->remote, 
-			    EVTT_XAUTH_SUCCESS, NULL);
+			evt_phase1(iph1, EVT_PHASE1_XAUTH_SUCCESS, NULL);
 		}
 
 
@@ -1689,3 +1764,42 @@
 
 	return;
 }
+
+struct xauth_rmconf *
+xauth_rmconf_dup(xauth_rmconf)
+	struct xauth_rmconf *xauth_rmconf;
+{
+	struct xauth_rmconf *new;
+
+	if (xauth_rmconf != NULL) {
+		new = racoon_malloc(sizeof(*new));
+		if (new == NULL) {
+			plog(LLV_ERROR, LOCATION, NULL, 
+			    "xauth_rmconf_dup: malloc failed\n");
+			return NULL;
+		}
+
+		memcpy(new, xauth_rmconf, sizeof(*new));
+
+		if (xauth_rmconf->login != NULL) {
+			new->login = vdup(xauth_rmconf->login);
+			if (new->login == NULL) {
+				plog(LLV_ERROR, LOCATION, NULL, 
+				    "xauth_rmconf_dup: malloc failed (login)\n");
+				return NULL;
+			}
+		}
+		if (xauth_rmconf->pass != NULL) {
+			new->pass = vdup(xauth_rmconf->pass);
+			if (new->pass == NULL) {
+				plog(LLV_ERROR, LOCATION, NULL, 
+				    "xauth_rmconf_dup: malloc failed (password)\n");
+				return NULL;
+			}
+		}
+
+		return new;
+	}
+
+	return NULL;
+}
diff --git a/src/racoon/isakmp_xauth.h b/src/racoon/isakmp_xauth.h
index ebb5214..f9e778f 100644
--- a/src/racoon/isakmp_xauth.h
+++ b/src/racoon/isakmp_xauth.h
@@ -1,4 +1,4 @@
-/*	$NetBSD: isakmp_xauth.h,v 1.4 2006/09/09 16:22:09 manu Exp $	*/
+/*	$NetBSD: isakmp_xauth.h,v 1.7 2011/03/14 15:50:36 vanhu Exp $	*/
 
 /*	$KAME$ */
 
@@ -34,6 +34,8 @@
 #ifndef _ISAKMP_XAUTH_H
 #define _ISAKMP_XAUTH_H
 
+#include "schedule.h"
+
 /* ISAKMP mode config attribute types specific to the Xauth vendor ID */
 #define	XAUTH_TYPE                16520
 #define	XAUTH_USER_NAME           16521
@@ -90,6 +92,7 @@
 #define XAUTHST_OK	2
 
 struct xauth_reply_arg {
+	struct sched sc;
 	isakmp_index index;
 	int port;
 	int id;
@@ -107,20 +110,43 @@
 vchar_t *isakmp_xauth_req(struct ph1handle *, struct isakmp_data *);
 vchar_t *isakmp_xauth_set(struct ph1handle *, struct isakmp_data *);
 void xauth_rmstate(struct xauth_state *);
-void xauth_reply_stub(void *);
+void xauth_reply_stub(struct sched *);
 int xauth_reply(struct ph1handle *, int, int, int);
 int xauth_rmconf_used(struct xauth_rmconf **);
 void xauth_rmconf_delete(struct xauth_rmconf **);
-
-#ifdef HAVE_LIBRADIUS
-int xauth_login_radius(struct ph1handle *, char *, char *);
-int xauth_radius_init(void);
-#endif
+struct xauth_rmconf * xauth_rmconf_dup(struct xauth_rmconf *);
 
 #ifdef HAVE_LIBPAM
 int xauth_login_pam(int, struct sockaddr *, char *, char *);
 #endif
 
+#ifdef HAVE_LIBRADIUS
+
+#define RADIUS_MAX_SERVERS 5
+
+struct rad_serv {
+	vchar_t		*host;
+	int		port;
+	vchar_t		*secret;
+};
+
+struct xauth_rad_config {
+	struct rad_serv	auth_server_list[RADIUS_MAX_SERVERS];
+	int		auth_server_count;
+	struct rad_serv	acct_server_list[RADIUS_MAX_SERVERS];
+	int		acct_server_count;
+	int		timeout;
+	int		retries;
+};
+
+extern struct xauth_rad_config xauth_rad_config;
+
+int xauth_radius_init_conf(int free);
+int xauth_radius_init(void);
+int xauth_login_radius(struct ph1handle *, char *, char *);
+
+#endif
+
 #ifdef HAVE_LIBLDAP
 
 #define LDAP_DFLT_HOST		"localhost"
@@ -148,8 +174,9 @@
 
 extern struct xauth_ldap_config xauth_ldap_config;
 
-int xauth_ldap_init(void);
+int xauth_ldap_init_conf(void);
 int xauth_login_ldap(struct ph1handle *, char *, char *);
+
 #endif
 
 #endif /* _ISAKMP_XAUTH_H */
diff --git a/src/racoon/kmpstat.c b/src/racoon/kmpstat.c
index c59e43a..50c478d 100644
--- a/src/racoon/kmpstat.c
+++ b/src/racoon/kmpstat.c
@@ -1,4 +1,4 @@
-/*	$NetBSD: kmpstat.c,v 1.4.6.2 2007/11/06 16:41:33 vanhu Exp $	*/
+/*	$NetBSD: kmpstat.c,v 1.7 2010/11/12 09:08:26 tteras Exp $	*/
 
 /*	$KAME: kmpstat.c,v 1.33 2004/08/16 08:20:28 itojun Exp $	*/
 
@@ -138,7 +138,7 @@
 {
 	struct admin_com h, *com;
 	caddr_t buf;
-	int len;
+	int len, rlen;
 	int l = 0;
 	caddr_t p;
 
@@ -153,19 +153,25 @@
 	if (len < sizeof(h))
 		goto bad1;
 
-	if (h.ac_errno) {
+	if (h.ac_errno && !(h.ac_cmd & ADMIN_FLAG_LONG_REPLY)) {
 		errno = h.ac_errno;
 		goto bad1;
 	}
 
+	/* real length */
+	if (h.ac_cmd & ADMIN_FLAG_LONG_REPLY)
+		rlen = ((u_int32_t)h.ac_len) + (((u_int32_t)h.ac_len_high) << 16);
+	else
+		rlen = h.ac_len;
+
 	/* allocate buffer */
-	if ((*combufp = vmalloc(h.ac_len)) == NULL)
+	if ((*combufp = vmalloc(rlen)) == NULL)
 		goto bad1;
 
 	/* read real message */
 	p = (*combufp)->v;
-	while (l < len) {
-		if ((len = recv(so, p, h.ac_len, 0)) < 0) {
+	while (l < rlen) {
+		if ((len = recv(so, p, rlen - l, 0)) < 0) {
 			perror("recv");
 			goto bad2;
 		}
diff --git a/src/racoon/localconf.c b/src/racoon/localconf.c
index ede1d9b..a512953 100644
--- a/src/racoon/localconf.c
+++ b/src/racoon/localconf.c
@@ -1,4 +1,4 @@
-/*	$NetBSD: localconf.c,v 1.4 2006/09/09 16:22:09 manu Exp $	*/
+/*	$NetBSD: localconf.c,v 1.7 2008/12/23 14:04:42 tteras Exp $	*/
 
 /*	$KAME: localconf.c,v 1.33 2001/08/09 07:32:19 sakane Exp $	*/
 
@@ -85,18 +85,14 @@
 	int i;
 
 	setdefault();
-	clear_myaddr(&lcconf->myaddrs);
+	myaddr_flush();
+
 	for (i = 0; i < LC_PATHTYPE_MAX; i++) {
 		if (lcconf->pathinfo[i]) {
 			racoon_free(lcconf->pathinfo[i]);
 			lcconf->pathinfo[i] = NULL;
 		}
 	}
-	for (i = 0; i < LC_IDENTTYPE_MAX; i++) {
-		if (lcconf->ident[i])
-			vfree(lcconf->ident[i]);
-		lcconf->ident[i] = NULL;
-	}
 }
 
 static void
@@ -105,7 +101,6 @@
 	lcconf->uid = 0;
 	lcconf->gid = 0;
 	lcconf->chroot = NULL;
-	lcconf->autograbaddr = 1;
 	lcconf->port_isakmp = PORT_ISAKMP;
 	lcconf->port_isakmp_natt = PORT_ISAKMP_NATT;
 	lcconf->default_af = AF_INET;
@@ -124,6 +119,7 @@
 	lcconf->complex_bundle = TRUE; /*XXX FALSE;*/
 	lcconf->gss_id_enc = LC_GSSENC_UTF16LE; /* Windows compatibility */
 	lcconf->natt_ka_interval = LC_DEFAULT_NATT_KA_INTERVAL;
+	lcconf->pfkey_buffer_size = LC_DEFAULT_PFKEY_BUFFER_SIZE;
 }
 
 /*
@@ -340,21 +336,12 @@
 	int f;
 {
 	static u_int16_t s_port_isakmp;
-#ifdef ENABLE_ADMINPORT
-	static u_int16_t s_port_admin;
-#endif
 
 	/* 0: save, 1: restore */
 	if (f) {
 		lcconf->port_isakmp = s_port_isakmp;
-#ifdef ENABLE_ADMINPORT
-		lcconf->port_admin = s_port_admin;
-#endif
 	} else {
 		s_port_isakmp = lcconf->port_isakmp;
-#ifdef ENABLE_ADMINPORT
-		s_port_admin = lcconf->port_admin;
-#endif
 	}
 }
 
diff --git a/src/racoon/localconf.h b/src/racoon/localconf.h
index f7cf33a..04ac8e4 100644
--- a/src/racoon/localconf.h
+++ b/src/racoon/localconf.h
@@ -1,4 +1,4 @@
-/*	$NetBSD: localconf.h,v 1.4 2006/09/09 16:22:09 manu Exp $	*/
+/*	$NetBSD: localconf.h,v 1.7 2008/12/23 14:04:42 tteras Exp $	*/
 
 /* Id: localconf.h,v 1.13 2005/11/06 18:13:18 monas Exp */
 
@@ -57,11 +57,10 @@
 #define LC_DEFAULT_RETRY_CHECKPH1	30
 #define LC_DEFAULT_WAIT_PH2COMPLETE	30
 #define LC_DEFAULT_NATT_KA_INTERVAL	20
+#define LC_DEFAULT_PFKEY_BUFFER_SIZE	0
 
 #define LC_DEFAULT_SECRETSIZE	16	/* 128 bits */
 
-#define LC_IDENTTYPE_MAX	5	/* XXX */
-
 #define	LC_GSSENC_UTF16LE	0	/* GSS ID in UTF-16LE */
 #define	LC_GSSENC_LATIN1	1	/* GSS ID in ISO-Latin-1 */
 #define	LC_GSSENC_MAX		2
@@ -74,18 +73,13 @@
 	char *chroot;			/* chroot path */
 	u_int16_t port_isakmp;		/* port for isakmp as default */
 	u_int16_t port_isakmp_natt;	/* port for NAT-T use */
-	u_int16_t port_admin;		/* port for admin */
 	int default_af;			/* default address family */
 
 	int sock_admin;
 	int sock_pfkey;
 	int rtsock;			/* routing socket */
 
-	int autograbaddr;
-	struct myaddrs *myaddrs;
-
 	char *pathinfo[LC_PATHTYPE_MAX];
-	vchar_t *ident[LC_IDENTTYPE_MAX]; /* base of Identifier payload. */
 
 	int pad_random;
 	int pad_randomlen;
@@ -118,6 +112,7 @@
 		 */
 
 	int gss_id_enc;			/* GSS ID encoding to use */
+	int pfkey_buffer_size;		/* Set socket buffer size for pfkey */
 };
 
 extern struct localconf *lcconf;
diff --git a/src/racoon/main.c b/src/racoon/main.c
index 094026e..ab71b3e 100644
--- a/src/racoon/main.c
+++ b/src/racoon/main.c
@@ -1,4 +1,4 @@
-/*	$NetBSD: main.c,v 1.6.6.2 2008/11/27 15:25:26 vanhu Exp $	*/
+/*	$NetBSD: main.c,v 1.12 2009/01/26 18:13:06 tteras Exp $	*/
 
 /* Id: main.c,v 1.25 2006/06/20 20:31:34 manubsd Exp */
 
@@ -66,12 +66,6 @@
 
 #include "cfparse_proto.h"
 #include "isakmp_var.h"
-#ifdef ENABLE_HYBRID
-#include <resolv.h>
-#include "isakmp.h"
-#include "isakmp_xauth.h"
-#include "isakmp_cfg.h"
-#endif
 #include "remoteconf.h"
 #include "localconf.h"
 #include "session.h"
@@ -84,10 +78,10 @@
 
 #include "package_version.h"
 
+int dump_config = 0;	/* dump parsed config file. */
 int f_local = 0;	/* local test mode.  behave like a wall. */
 int vflag = 1;		/* for print-isakmp.c */
 static int loading_sa = 0;	/* install sa when racoon boots up. */
-static int dump_config = 0;	/* dump parsed config file. */
 
 #ifdef TOP_PACKAGE
 static char version[] = "@(#)" TOP_PACKAGE_STRING " (" TOP_PACKAGE_URL ")";
@@ -95,197 +89,77 @@
 static char version[] = "@(#) racoon / IPsec-tools";
 #endif /* TOP_PACKAGE */
 
-int main __P((int, char **));
-static void usage __P((void));
-static void parse __P((int, char **));
-#if 0
-static void cleanup_pidfile __P((void));
-#endif
-
-void
-usage()
+static void
+print_version()
 {
-	printf("usage: racoon [-BdFv%s] %s[-f (file)] [-l (file)] [-p (port)]\n",
+	printf("%s\n"
+	       "\n"
+	       "Compiled with:\n"
+	       "- %s (http://www.openssl.org/)\n"
 #ifdef INET6
-		"46",
-#else
-		"",
+	       "- IPv6 support\n"
+#endif
+#ifdef ENABLE_DPD
+	       "- Dead Peer Detection\n"
+#endif
+#ifdef ENABLE_FRAG
+	       "- IKE fragmentation\n"
+#endif
+#ifdef ENABLE_HYBRID
+	       "- Hybrid authentication\n"
+#endif
+#ifdef ENABLE_GSSAPI
+	       "- GSS-API authentication\n"
+#endif
+#ifdef ENABLE_NATT
+	       "- NAT Traversal\n"
+#endif
+#ifdef ENABLE_STATS
+	       "- Timing statistics\n"
 #endif
 #ifdef ENABLE_ADMINPORT
-		"[-a (port)] "
-#else
-		""
+	       "- Admin port\n"
 #endif
-		);
-	printf("   -B: install SA to the kernel from the file "
-		"specified by the configuration file.\n");
-	printf("   -d: debug level, more -d will generate more debug message.\n");
-	printf("   -C: dump parsed config file.\n");
-	printf("   -L: include location in debug messages\n");
-	printf("   -F: run in foreground, do not become daemon.\n");
-	printf("   -v: be more verbose\n");
-#ifdef INET6
-	printf("   -4: IPv4 mode.\n");
-	printf("   -6: IPv6 mode.\n");
+#ifdef HAVE_CLOCK_MONOTONIC
+	       "- Monotonic clock\n"
 #endif
-#ifdef ENABLE_ADMINPORT
-	printf("   -a: port number for admin port.\n");
-#endif
-	printf("   -f: pathname for configuration file.\n");
-	printf("   -l: pathname for log file.\n");
-	printf("   -p: port number for isakmp (default: %d).\n", PORT_ISAKMP);
-	printf("   -P: port number for NAT-T (default: %d).\n", PORT_ISAKMP_NATT);
-	exit(1);
-}
-
-int
-main(ac, av)
-	int ac;
-	char **av;
-{
-	int error;
-
-	if (geteuid() != 0) {
-		errx(1, "must be root to invoke this program.");
-		/* NOTREACHED*/
-	}
-
-	/*
-	 * Don't let anyone read files I write.  Although some files (such as
-	 * the PID file) can be other readable, we dare to use the global mask,
-	 * because racoon uses fopen(3), which can't specify the permission
-	 * at the creation time.
-	 */
-	umask(077);
-	if (umask(077) != 077) {
-		errx(1, "could not set umask");
-		/* NOTREACHED*/
-	}
-
-#ifdef DEBUG_RECORD_MALLOCATION
-	DRM_init();
-#endif
-
 #ifdef HAVE_SECCTX
-	init_avc();
+	       "- Security context\n"
 #endif
-	eay_init();
-	initlcconf();
-	initrmconf();
-	oakley_dhinit();
-	compute_vendorids();
-
-	parse(ac, av);
-
-	ploginit();
-
-	plog(LLV_INFO, LOCATION, NULL, "%s\n", version);
-	plog(LLV_INFO, LOCATION, NULL, "@(#)"
-	    "This product linked %s (http://www.openssl.org/)"
-	    "\n", eay_version());
-	plog(LLV_INFO, LOCATION, NULL, "Reading configuration from \"%s\"\n", 
-	    lcconf->racoon_conf);
-
-	if (pfkey_init() < 0) {
-		errx(1, "something error happened "
-			"while pfkey initializing.");
-		/* NOTREACHED*/
-	}
-
-#ifdef ENABLE_HYBRID
-	if (isakmp_cfg_init(ISAKMP_CFG_INIT_COLD))
-		errx(1, "could not initialize ISAKMP mode config structures");
-#endif
-
-#ifdef HAVE_LIBLDAP
-	if (xauth_ldap_init() != 0)
-		errx(1, "could not initialize libldap");
-#endif
-
-	/*
-	 * in order to prefer the parameters by command line,
-	 * saving some parameters before parsing configuration file.
-	 */
-	save_params();
-	error = cfparse();
-	if (error != 0)
-		errx(1, "failed to parse configuration file.");
-	restore_params();
-
-#ifdef ENABLE_HYBRID
-	if(isakmp_cfg_config.network4 && isakmp_cfg_config.pool_size == 0)
-		if ((error = isakmp_cfg_resize_pool(ISAKMP_CFG_MAX_CNX)) != 0)
-			return error;
-#endif
-
-	if (dump_config)
-		dumprmconf ();
-
-#ifdef HAVE_LIBRADIUS
-	if (xauth_radius_init() != 0) {
-		errx(1, "could not initialize libradius");
-		/* NOTREACHED*/
-	}
-#endif
-
-	/*
-	 * install SAs from the specified file.  If the file is not specified
-	 * by the configuration file, racoon will exit.
-	 */
-	if (loading_sa && !f_local) {
-		if (backupsa_from_file() != 0)
-			errx(1, "something error happened "
-				"SA recovering.");
-	}
-
-	if (f_foreground)
-		close(0);
-	else {
-		if (daemon(0, 0) < 0) {
-			errx(1, "failed to be daemon. (%s)",
-				strerror(errno));
-		}
-#ifndef __linux__
-		/*
-		 * In case somebody has started inetd manually, we need to
-		 * clear the logname, so that old servers run as root do not
-		 * get the user's logname..
-		 */
-		if (setlogin("") < 0) {
-			plog(LLV_ERROR, LOCATION, NULL,
-				"cannot clear logname: %s\n", strerror(errno));
-			/* no big deal if it fails.. */
-		}
-#endif
-		if (!f_local) {
-#if 0
-			if (atexit(cleanup_pidfile) < 0) {
-				plog(LLV_ERROR, LOCATION, NULL,
-					"cannot register pidfile cleanup");
-			}
-#endif
-		}
-	}
-
-	session();
-
+	       "\n",
+	       version,
+	       eay_version());
 	exit(0);
 }
 
-#if 0
 static void
-cleanup_pidfile()
+usage()
 {
-	pid_t p = getpid();
-
-	/* if it's not child process, clean everything */
-	if (racoon_pid == p) {
-		const char *pid_file = _PATH_VARRUN "racoon.pid";
-
-		(void) unlink(pid_file);
-	}
-}
+	printf("usage: racoon [-BdFv"
+#ifdef INET6
+		"46"
 #endif
+		"] [-f (file)] [-l (file)] [-p (port)] [-P (natt port)]\n"
+		"   -B: install SA to the kernel from the file "
+		"specified by the configuration file.\n"
+		"   -d: debug level, more -d will generate more debug message.\n"
+		"   -C: dump parsed config file.\n"
+		"   -L: include location in debug messages\n"
+		"   -F: run in foreground, do not become daemon.\n"
+		"   -v: be more verbose\n"
+		"   -V: print version and exit\n"
+#ifdef INET6
+		"   -4: IPv4 mode.\n"
+		"   -6: IPv6 mode.\n"
+#endif
+		"   -f: pathname for configuration file.\n"
+		"   -l: pathname for log file.\n"
+		"   -p: port number for isakmp (default: %d).\n"
+		"   -P: port number for NAT-T (default: %d).\n"
+		"\n",
+		PORT_ISAKMP, PORT_ISAKMP_NATT);
+	exit(1);
+}
 
 static void
 parse(ac, av)
@@ -305,7 +179,7 @@
 	else
 		pname = *av;
 
-	while ((c = getopt(ac, av, "dLFp:P:a:f:l:vZBC"
+	while ((c = getopt(ac, av, "dLFp:P:f:l:vVZBC"
 #ifdef YYDEBUG
 			"y"
 #endif
@@ -330,15 +204,6 @@
 		case 'P':
 			lcconf->port_isakmp_natt = atoi(optarg);
 			break;
-		case 'a':
-#ifdef ENABLE_ADMINPORT
-			lcconf->port_admin = atoi(optarg);
-			break;
-#else
-			fprintf(stderr, "%s: the option is disabled "
-			    "in the configuration\n", pname);
-			exit(1);
-#endif
 		case 'f':
 			lcconf->racoon_conf = optarg;
 			break;
@@ -348,6 +213,9 @@
 		case 'v':
 			vflag++;
 			break;
+		case 'V':
+			print_version();
+			break;
 		case 'Z':
 			/*
 			 * only local test.
@@ -393,6 +261,89 @@
 		usage();
 		/* NOTREACHED */
 	}
-
-	return;
 }
+
+int
+main(ac, av)
+	int ac;
+	char **av;
+{
+	int error;
+
+	initlcconf();
+	parse(ac, av);
+
+	if (geteuid() != 0) {
+		errx(1, "must be root to invoke this program.");
+		/* NOTREACHED*/
+	}
+
+	/*
+	 * Don't let anyone read files I write.  Although some files (such as
+	 * the PID file) can be other readable, we dare to use the global mask,
+	 * because racoon uses fopen(3), which can't specify the permission
+	 * at the creation time.
+	 */
+	umask(077);
+	if (umask(077) != 077) {
+		errx(1, "could not set umask");
+		/* NOTREACHED*/
+	}
+
+#ifdef DEBUG_RECORD_MALLOCATION
+	DRM_init();
+#endif
+
+#ifdef HAVE_SECCTX
+	init_avc();
+#endif
+	eay_init();
+	initrmconf();
+	oakley_dhinit();
+	compute_vendorids();
+
+	ploginit();
+
+	plog(LLV_INFO, LOCATION, NULL, "%s\n", version);
+	plog(LLV_INFO, LOCATION, NULL, "@(#)"
+	    "This product linked %s (http://www.openssl.org/)"
+	    "\n", eay_version());
+	plog(LLV_INFO, LOCATION, NULL, "Reading configuration from \"%s\"\n", 
+	    lcconf->racoon_conf);
+
+	/*
+	 * install SAs from the specified file.  If the file is not specified
+	 * by the configuration file, racoon will exit.
+	 */
+	if (loading_sa && !f_local) {
+		if (backupsa_from_file() != 0)
+			errx(1, "something error happened "
+				"SA recovering.");
+	}
+
+	if (f_foreground)
+		close(0);
+	else {
+		if (daemon(0, 0) < 0) {
+			errx(1, "failed to be daemon. (%s)",
+				strerror(errno));
+		}
+#ifndef __linux__
+		/*
+		 * In case somebody has started inetd manually, we need to
+		 * clear the logname, so that old servers run as root do not
+		 * get the user's logname..
+		 */
+		if (setlogin("") < 0) {
+			plog(LLV_ERROR, LOCATION, NULL,
+				"cannot clear logname: %s\n", strerror(errno));
+			/* no big deal if it fails.. */
+		}
+#endif
+	}
+
+	session();
+
+	return 0;
+}
+
diff --git a/src/racoon/misc.c b/src/racoon/misc.c
index 4daa0ed..91b8e77 100644
--- a/src/racoon/misc.c
+++ b/src/racoon/misc.c
@@ -1,4 +1,4 @@
-/*	$NetBSD: misc.c,v 1.4.6.1 2008/07/15 00:55:48 mgrooms Exp $	*/
+/*	$NetBSD: misc.c,v 1.6 2008/07/15 00:47:09 mgrooms Exp $	*/
 
 /*	$KAME: misc.c,v 1.23 2001/08/16 14:37:29 itojun Exp $	*/
 
@@ -44,6 +44,7 @@
 #include <errno.h>
 #include <syslog.h>
 #include <ctype.h>
+#include <fcntl.h>
 
 #include "var.h"
 #include "misc.h"
@@ -154,6 +155,16 @@
 }
 
 /*
+ * set the close-on-exec flag for file descriptor fd.
+ */
+void
+close_on_exec(fd)
+	int fd;
+{
+	fcntl(fd, F_SETFD, FD_CLOEXEC);
+}
+
+/*
  * calculate the difference between two times.
  * t1: start
  * t2: end
diff --git a/src/racoon/misc.h b/src/racoon/misc.h
index 66e42b1..3e758d9 100644
--- a/src/racoon/misc.h
+++ b/src/racoon/misc.h
@@ -1,4 +1,4 @@
-/*	$NetBSD: misc.h,v 1.4.6.1 2008/07/15 00:55:48 mgrooms Exp $	*/
+/*	$NetBSD: misc.h,v 1.6 2008/07/15 00:47:09 mgrooms Exp $	*/
 
 /* Id: misc.h,v 1.9 2006/04/06 14:00:06 manubsd Exp */
 
@@ -50,6 +50,7 @@
 struct timeval;
 extern double timedelta __P((struct timeval *, struct timeval *));
 char *strdup __P((const char *));
+extern void close_on_exec __P((int fd));
 
 #if defined(__APPLE__) && defined(__MACH__)
 #define RACOON_TAILQ_FOREACH_REVERSE(var, head, headname ,field)	\
diff --git a/src/racoon/nattraversal.c b/src/racoon/nattraversal.c
index 9fd4bcd..b04cc1b 100644
--- a/src/racoon/nattraversal.c
+++ b/src/racoon/nattraversal.c
@@ -1,4 +1,4 @@
-/*	$NetBSD: nattraversal.c,v 1.6.6.2 2009/05/18 17:01:07 tteras Exp $	*/
+/*	$NetBSD: nattraversal.c,v 1.14 2011/03/14 17:18:13 tteras Exp $	*/
 
 /*
  * Copyright (C) 2004 SuSE Linux AG, Nuernberg, Germany.
@@ -77,6 +77,7 @@
 };
 
 static TAILQ_HEAD(_natt_ka_addrs, natt_ka_addrs) ka_tree;
+static struct sched sc_natt = SCHED_INITIALIZER();
 
 /*
  * check if the given vid is NAT-T.
@@ -126,10 +127,14 @@
   char *ptr;
   void *addr_ptr, *addr_port;
   size_t buf_size, addr_size;
+  int natt_force = 0;
+
+  if (iph1->rmconf != NULL && iph1->rmconf->nat_traversal == NATT_FORCE)
+	  natt_force = 1;
 
   plog (LLV_INFO, LOCATION, addr, "Hashing %s with algo #%d %s\n",
 	saddr2str(addr), iph1->approval->hashtype, 
-	(iph1->rmconf->nat_traversal == NATT_FORCE)?"(NAT-T forced)":"");
+	natt_force?"(NAT-T forced)":"");
   
   if (addr->sa_family == AF_INET) {
     addr_size = sizeof (struct in_addr);	/* IPv4 address */
@@ -163,7 +168,7 @@
   ptr += sizeof (cookie_t);
   
   /* Copy-in Address (or zeroes if NATT_FORCE) */
-  if (iph1->rmconf->nat_traversal == NATT_FORCE)
+  if (natt_force)
     memset (ptr, 0, addr_size);
   else
     memcpy (ptr, addr_ptr, addr_size);
@@ -186,7 +191,8 @@
   u_int32_t flag;
   int verified = 0;
 
-  if (iph1->rmconf->nat_traversal == NATT_FORCE)
+  if (iph1->rmconf != NULL &&
+      iph1->rmconf->nat_traversal == NATT_FORCE)
     return verified;
 
   if (natd_seq == 0) {
@@ -302,9 +308,28 @@
 	natt_keepalive_add_ph1 (iph1);
 }
 
+static int
+natt_is_enabled (struct remoteconf *rmconf, void *args)
+{
+  if (rmconf->nat_traversal)
+    return 1;
+  return 0;
+}
+
 void
 natt_handle_vendorid (struct ph1handle *iph1, int vid_numeric)
 {
+  if (iph1->rmconf == NULL) {
+    /* Check if any candidate remote conf allows nat-t */
+    struct rmconfselector rmconf;
+    rmconf_selector_from_ph1(&rmconf, iph1);
+    if (enumrmconf(&rmconf, natt_is_enabled, NULL) == 0)
+      return;
+  } else {
+    if (!iph1->rmconf->nat_traversal)
+      return;
+  }
+
   if (! iph1->natt_options)
     iph1->natt_options = racoon_calloc (1, sizeof (*iph1->natt_options));
 
@@ -330,7 +355,7 @@
 
 /* NAT keepalive functions */
 static void
-natt_keepalive_send (void *param)
+natt_keepalive_send (struct sched *param)
 {
   struct natt_ka_addrs	*ka, *next = NULL;
   char keepalive_packet[] = { 0xff };
@@ -340,7 +365,7 @@
   for (ka = TAILQ_FIRST(&ka_tree); ka; ka = next) {
     next = TAILQ_NEXT(ka, chain);
     
-    s = getsockmyaddr(ka->src);
+    s = myaddr_getfd(ka->src);
     if (s == -1) {
       natt_keepalive_delete(ka);
       continue;
@@ -354,7 +379,7 @@
 	   strerror (errno));
   }
   
-  sched_new (lcconf->natt_ka_interval, natt_keepalive_send, NULL);
+  sched_schedule (&sc_natt, lcconf->natt_ka_interval, natt_keepalive_send);
 }
 
 void
@@ -364,7 +389,7 @@
 
   /* To disable sending KAs set natt_ka_interval=0 */
   if (lcconf->natt_ka_interval > 0)
-    sched_new (lcconf->natt_ka_interval, natt_keepalive_send, NULL);
+    sched_schedule (&sc_natt, lcconf->natt_ka_interval, natt_keepalive_send);
 }
 
 int
@@ -373,8 +398,8 @@
   struct natt_ka_addrs *ka = NULL, *new_addr;
   
   TAILQ_FOREACH (ka, &ka_tree, chain) {
-    if (cmpsaddrstrict(ka->src, src) == 0 && 
-	cmpsaddrstrict(ka->dst, dst) == 0) {
+    if (cmpsaddr(ka->src, src) == CMPSADDR_MATCH &&
+	cmpsaddr(ka->dst, dst) == CMPSADDR_MATCH) {
       ka->in_use++;
       plog (LLV_INFO, LOCATION, NULL, "KA found: %s (in_use=%u)\n",
 	    saddr2str_fromto("%s->%s", src, dst), ka->in_use);
@@ -437,8 +462,8 @@
     plog (LLV_DEBUG, LOCATION, NULL, "KA tree dump: %s (in_use=%u)\n",
 	  saddr2str_fromto("%s->%s", src, dst), ka->in_use);
 
-    if (cmpsaddrstrict(ka->src, src) == 0 && 
-	cmpsaddrstrict(ka->dst, dst) == 0 &&
+    if (cmpsaddr(ka->src, src) == CMPSADDR_MATCH &&
+	cmpsaddr(ka->dst, dst) == CMPSADDR_MATCH &&
 	-- ka->in_use <= 0) {
 
       plog (LLV_DEBUG, LOCATION, NULL, "KA removing this one...\n");
@@ -451,16 +476,16 @@
   }
 }
 
-static struct remoteconf *
+static int
 natt_enabled_in_rmconf_stub (struct remoteconf *rmconf, void *data)
 {
-  return (rmconf->nat_traversal ? rmconf : NULL);
+  return rmconf->nat_traversal ? 1 : 0;
 }
 
 int
 natt_enabled_in_rmconf ()
 {
-  return foreachrmconf (natt_enabled_in_rmconf_stub, NULL) != NULL;
+  return enumrmconf(NULL, natt_enabled_in_rmconf_stub, NULL) != 0;
 }
 
 
diff --git a/src/racoon/nattraversal.h b/src/racoon/nattraversal.h
index cec5815..3b0b03b 100644
--- a/src/racoon/nattraversal.h
+++ b/src/racoon/nattraversal.h
@@ -1,4 +1,4 @@
-/*	$NetBSD: nattraversal.h,v 1.6 2006/09/09 16:22:09 manu Exp $	*/
+/*	$NetBSD: nattraversal.h,v 1.7 2010/09/22 07:34:51 vanhu Exp $	*/
 
 /*
  * Copyright (C) 2004 SuSE Linux AG, Nuernberg, Germany.
@@ -42,12 +42,12 @@
 #define	NAT_KA_QUEUED		(1L<<4)
 #define	NAT_ADD_NON_ESP_MARKER	(1L<<5)
 
-#define	NATT_AVAILABLE(ph1)	((iph1)->natt_flags & NAT_ANNOUNCED)
+#define	NATT_AVAILABLE(_ph1)	((_ph1)->natt_flags & NAT_ANNOUNCED)
 
 #define	NAT_DETECTED	(NAT_DETECTED_ME | NAT_DETECTED_PEER)
 
 #define	NON_ESP_MARKER_LEN	sizeof(u_int32_t)
-#define	NON_ESP_MARKER_USE(iph1)	((iph1)->natt_flags & NAT_ADD_NON_ESP_MARKER)
+#define	NON_ESP_MARKER_USE(_ph1)	((_ph1)->natt_flags & NAT_ADD_NON_ESP_MARKER)
 
 /* These are the values from parsing "remote {}" 
    block of the config file. */
diff --git a/src/racoon/oakley.c b/src/racoon/oakley.c
index 183ac2f..4a106df 100644
--- a/src/racoon/oakley.c
+++ b/src/racoon/oakley.c
@@ -1,4 +1,4 @@
-/*	$NetBSD: oakley.c,v 1.9.6.4 2009/08/13 09:18:45 vanhu Exp $	*/
+/*	$NetBSD: oakley.c,v 1.22 2011/03/17 14:42:58 vanhu Exp $	*/
 
 /* Id: oakley.c,v 1.32 2006/05/26 12:19:46 manubsd Exp */
 
@@ -123,13 +123,63 @@
 
 static int oakley_check_dh_pub __P((vchar_t *, vchar_t **));
 static int oakley_compute_keymat_x __P((struct ph2handle *, int, int));
-static int get_cert_fromlocal __P((struct ph1handle *, int));
-static int get_plainrsa_fromlocal __P((struct ph1handle *, int));
 static int oakley_check_certid __P((struct ph1handle *iph1));
 static int check_typeofcertname __P((int, int));
-static cert_t *save_certbuf __P((struct isakmp_gen *));
-static cert_t *save_certx509 __P((X509 *));
 static int oakley_padlen __P((int, int));
+static int get_plainrsa_fromlocal __P((struct ph1handle *, int));
+
+int oakley_get_certtype(cert)
+	vchar_t *cert;
+{
+	if (cert == NULL)
+		return ISAKMP_CERT_NONE;
+
+	return cert->v[0];
+}
+
+static vchar_t *
+dump_isakmp_payload(gen)
+	struct isakmp_gen *gen;
+{
+	vchar_t p;
+
+	if (ntohs(gen->len) <= sizeof(*gen)) {
+		plog(LLV_ERROR, LOCATION, NULL,
+		     "Len is too small !!.\n");
+		return NULL;
+	}
+
+	p.v = (caddr_t) (gen + 1);
+	p.l = ntohs(gen->len) - sizeof(*gen);
+
+	return vdup(&p);
+}
+
+static vchar_t *
+dump_x509(cert)
+	X509 *cert;
+{
+	vchar_t *pl;
+	u_char *bp;
+	int len;
+
+	len = i2d_X509(cert, NULL);
+
+	pl = vmalloc(len + 1);
+	if (pl == NULL) {
+		plog(LLV_ERROR, LOCATION, NULL,
+		     "Failed to copy CERT from packet.\n");
+		return NULL;
+	}
+
+	pl->v[0] = ISAKMP_CERT_X509SIGN;
+	bp = (u_char *) &pl->v[1];
+	i2d_X509(cert, &bp);
+
+	return pl;
+}
+
+
 
 int
 oakley_get_defaultlifetime()
@@ -418,7 +468,7 @@
 	res = alg_oakley_hashdef_one(type, buf);
 	if (res == NULL) {
 		plog(LLV_ERROR, LOCATION, NULL,
-			"invalid hash algoriym %d.\n", type);
+			"invalid hash algorithm %d.\n", type);
 		return NULL;
 	}
 
@@ -858,7 +908,7 @@
 		+ (sw == GENERATE ? iph1->id->l : iph1->id_p->l);
 
 #ifdef HAVE_GSSAPI
-	if (AUTHMETHOD(iph1) == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB) {
+	if (iph1->approval->authmethod == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB) {
 		if (iph1->gi_i != NULL && iph1->gi_r != NULL) {
 			bp = (sw == GENERATE ? iph1->gi_i : iph1->gi_r);
 			len += bp->l;
@@ -919,7 +969,7 @@
 	p += bp->l;
 
 #ifdef HAVE_GSSAPI
-	if (AUTHMETHOD(iph1) == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB) {
+	if (iph1->approval->authmethod == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB) {
 		if (iph1->gi_i != NULL && iph1->gi_r != NULL) {
 			bp = (sw == GENERATE ? iph1->gi_i : iph1->gi_r);
 			memcpy(p, bp->v, bp->l);
@@ -980,7 +1030,7 @@
 		return NULL;
 	}
 
-	switch (AUTHMETHOD(iph1)) {
+	switch (iph1->approval->authmethod) {
 	case OAKLEY_ATTR_AUTH_METHOD_PSKEY:
 	case OAKLEY_ATTR_AUTH_METHOD_RSAENC:
 	case OAKLEY_ATTR_AUTH_METHOD_RSAREV:
@@ -989,7 +1039,7 @@
 	case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAENC_R:
 	case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAREV_I:
 	case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAREV_R:
-	case FICTIVE_AUTH_METHOD_XAUTH_PSKEY_I:
+	case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_I:
 	case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_R:
 #endif
 		if (iph1->skeyid == NULL) {
@@ -1121,7 +1171,7 @@
 		return NULL;
 	}
 
-	switch(AUTHMETHOD(iph1)) {
+	switch (iph1->approval->authmethod) {
 	case OAKLEY_ATTR_AUTH_METHOD_DSSSIG:
 	case OAKLEY_ATTR_AUTH_METHOD_RSASIG:
 #ifdef ENABLE_HYBRID
@@ -1133,7 +1183,7 @@
 	case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_R:
 	case OAKLEY_ATTR_AUTH_METHOD_XAUTH_DSSSIG_I:
 	case OAKLEY_ATTR_AUTH_METHOD_XAUTH_DSSSIG_R:
-	case FICTIVE_AUTH_METHOD_XAUTH_PSKEY_I:
+	case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_I:
 #endif
 		break;
 	default:
@@ -1249,10 +1299,10 @@
 	gettimeofday(&start, NULL);
 #endif
 
-	switch (AUTHMETHOD(iph1)) {
+	switch (iph1->approval->authmethod) {
 	case OAKLEY_ATTR_AUTH_METHOD_PSKEY:
 #ifdef ENABLE_HYBRID
-	case FICTIVE_AUTH_METHOD_XAUTH_PSKEY_I:
+	case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_I:
 	case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_R:
 #endif
 		/* validate HASH */
@@ -1265,7 +1315,7 @@
 			return ISAKMP_NTYPE_PAYLOAD_MALFORMED;
 		}
 #ifdef ENABLE_HYBRID
-		if (AUTHMETHOD(iph1) == FICTIVE_AUTH_METHOD_XAUTH_PSKEY_I &&
+		if (iph1->approval->authmethod == OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_I &&
 		    ((iph1->mode_cfg->flags & ISAKMP_CFG_VENDORID_XAUTH) == 0))
 		{
 			plog(LLV_ERROR, LOCATION, NULL, "No SIG was passed, "
@@ -1323,7 +1373,7 @@
 #endif
 	    {
 		int error = 0;
-		int certtype = 0;
+		int certtype;
 
 		/* validation */
 		if (iph1->id_p == NULL) {
@@ -1341,132 +1391,104 @@
 		plogdump(LLV_DEBUG, iph1->sig_p->v, iph1->sig_p->l);
 
 		/* get peer's cert */
-		switch (iph1->rmconf->getcert_method) {
-		case ISAKMP_GETCERT_PAYLOAD:
+		certtype = oakley_get_certtype(iph1->rmconf->peerscert);
+		switch (certtype) {
+		case ISAKMP_CERT_NONE:
+			/* expect to receive one from peer */
 			if (iph1->cert_p == NULL) {
 				plog(LLV_ERROR, LOCATION, NULL,
-					"no peer's CERT payload found.\n");
+				     "no peer's CERT payload found.\n");
 				return ISAKMP_INTERNAL_ERROR;
 			}
-			break;
-		case ISAKMP_GETCERT_LOCALFILE:
-			switch (iph1->rmconf->certtype) {
-				case ISAKMP_CERT_X509SIGN:
-					if (iph1->rmconf->peerscertfile == NULL) {
-						plog(LLV_ERROR, LOCATION, NULL,
-							"no peer's CERT file found.\n");
-						return ISAKMP_INTERNAL_ERROR;
-					}
+			/* verify the cert if needed */
+			if (!iph1->rmconf->verify_cert)
+				break;
 
-					/* don't use cached cert */
-					if (iph1->cert_p != NULL) {
-						oakley_delcert(iph1->cert_p);
-						iph1->cert_p = NULL;
-					}
+			switch (oakley_get_certtype(iph1->cert_p)) {
+			case ISAKMP_CERT_X509SIGN: {
+				char path[MAXPATHLEN];
+				char *ca;
 
-					error = get_cert_fromlocal(iph1, 0);
-#ifdef ANDROID_PATCHED
-					if (!error)
-						break;
-				default:
-					return ISAKMP_INTERNAL_ERROR;
-#else
-					break;
+				if (iph1->rmconf->cacertfile != NULL) {
+					getpathname(path, sizeof(path),
+						    LC_PATHTYPE_CERT,
+						    iph1->rmconf->cacertfile);
+					ca = path;
+				} else {
+					ca = NULL;
+				}
 
-				case ISAKMP_CERT_PLAINRSA:
-					error = get_plainrsa_fromlocal(iph1, 0);
-					break;
-			}
-			if (error)
-				return ISAKMP_INTERNAL_ERROR;
-			break;
-		case ISAKMP_GETCERT_DNS:
-			if (iph1->rmconf->peerscertfile != NULL) {
+				error = eay_check_x509cert(
+					iph1->cert_p,
+					lcconf->pathinfo[LC_PATHTYPE_CERT],
+					ca, 0);
+				break;
+				}
+			default:
 				plog(LLV_ERROR, LOCATION, NULL,
-					"why peer's CERT file is defined "
-					"though getcert method is dns ?\n");
+					"peers_cert certtype %d was not expected\n",
+					certtype);
 				return ISAKMP_INTERNAL_ERROR;
 			}
 
-			/* don't use cached cert */
+			if (error != 0) {
+				plog(LLV_ERROR, LOCATION, NULL,
+				     "the peer's certificate is not verified.\n");
+				return ISAKMP_NTYPE_INVALID_CERT_AUTHORITY;
+			}
+			break;
+		case ISAKMP_CERT_X509SIGN:
+			if (iph1->rmconf->peerscert == NULL) {
+				plog(LLV_ERROR, LOCATION, NULL,
+				     "no peer's CERT file found.\n");
+				return ISAKMP_INTERNAL_ERROR;
+			}
+			/* don't use received cert */
 			if (iph1->cert_p != NULL) {
-				oakley_delcert(iph1->cert_p);
+				vfree(iph1->cert_p);
+				iph1->cert_p = NULL;
+			}
+			/* copy from remoteconf instead */
+			iph1->cert_p = vdup(iph1->rmconf->peerscert);
+			break;
+#ifndef ANDROID_PATCHED
+		case ISAKMP_CERT_PLAINRSA:
+			if (get_plainrsa_fromlocal(iph1, 0))
+				return ISAKMP_INTERNAL_ERROR;
+			break;
+		case ISAKMP_CERT_DNS:
+			/* don't use received cert */
+			if (iph1->cert_p != NULL) {
+				vfree(iph1->cert_p);
 				iph1->cert_p = NULL;
 			}
 
 			iph1->cert_p = dnssec_getcert(iph1->id_p);
 			if (iph1->cert_p == NULL) {
 				plog(LLV_ERROR, LOCATION, NULL,
-					"no CERT RR found.\n");
+				     "no CERT RR found.\n");
 				return ISAKMP_INTERNAL_ERROR;
-#endif
 			}
 			break;
+#endif
 		default:
 			plog(LLV_ERROR, LOCATION, NULL,
-				"invalid getcert_mothod: %d\n",
-				iph1->rmconf->getcert_method);
+			     "invalid certificate type: %d\n",
+			     oakley_get_certtype(iph1->rmconf->peerscert));
 			return ISAKMP_INTERNAL_ERROR;
 		}
 
 		/* compare ID payload and certificate name */
-		if (iph1->rmconf->verify_cert &&
-		    (error = oakley_check_certid(iph1)) != 0)
+		if ((error = oakley_check_certid(iph1)) != 0)
 			return error;
 
-		/* verify certificate */
-		if (iph1->rmconf->verify_cert
-		 && iph1->rmconf->getcert_method == ISAKMP_GETCERT_PAYLOAD) {
-			certtype = iph1->rmconf->certtype;
-#ifdef ENABLE_HYBRID
-			switch (AUTHMETHOD(iph1)) {
-			case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I:
-			case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_I:
-				certtype = iph1->cert_p->type;
-				break;
-			default:
-				break;
-			}
-#endif
-			switch (certtype) {
-			case ISAKMP_CERT_X509SIGN: {
-				char path[MAXPATHLEN];
-				char *ca;
-
-				if (iph1->rmconf->cacertfile != NULL) {
-					getpathname(path, sizeof(path), 
-					    LC_PATHTYPE_CERT, 
-					    iph1->rmconf->cacertfile);
-					ca = path;
-				} else {
-					ca = NULL;
-				}
-
-				error = eay_check_x509cert(&iph1->cert_p->cert,
-					lcconf->pathinfo[LC_PATHTYPE_CERT], 
-					ca, 0);
-				break;
-			}
-			
-			default:
-				plog(LLV_ERROR, LOCATION, NULL,
-					"no supported certtype %d\n", certtype);
-				return ISAKMP_INTERNAL_ERROR;
-			}
-			if (error != 0) {
-				plog(LLV_ERROR, LOCATION, NULL,
-					"the peer's certificate is not verified.\n");
-				return ISAKMP_NTYPE_INVALID_CERT_AUTHORITY;
-			}
-		}
-	
-		/* Generate a warning if verify_cert == 0
-		 */
-		if (iph1->rmconf->verify_cert){
-			plog(LLV_DEBUG, LOCATION, NULL, "CERT validated\n");
-		}else{
+		/* Generate a warning if verify_cert */
+		if (iph1->rmconf->verify_cert) {
+			plog(LLV_DEBUG, LOCATION, NULL,
+			     "CERT validated\n");
+		} else {
 			plog(LLV_WARNING, LOCATION, NULL,
-				"CERT validation disabled by configuration\n");
+			     "CERT validation disabled by configuration\n");
 		}
 
 		/* compute hash */
@@ -1489,38 +1511,30 @@
 		if (my_hash == NULL)
 			return ISAKMP_INTERNAL_ERROR;
 
-
-		certtype = iph1->rmconf->certtype;
-#ifdef ENABLE_HYBRID
-		switch (AUTHMETHOD(iph1)) {
-		case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I:
-		case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_I:
-			certtype = iph1->cert_p->type;
-			break;
-		default:
-			break;
-		}
-#endif
 		/* check signature */
+		certtype = oakley_get_certtype(iph1->cert_p);
+		if (certtype == ISAKMP_CERT_NONE)
+			certtype = oakley_get_certtype(iph1->rmconf->peerscert);
 		switch (certtype) {
 		case ISAKMP_CERT_X509SIGN:
 		case ISAKMP_CERT_DNS:
 			error = eay_check_x509sign(my_hash,
-					iph1->sig_p,
-					&iph1->cert_p->cert);
+						   iph1->sig_p,
+						   iph1->cert_p);
 			break;
 #ifndef ANDROID_PATCHED
 		case ISAKMP_CERT_PLAINRSA:
 			iph1->rsa_p = rsa_try_check_rsasign(my_hash,
 					iph1->sig_p, iph1->rsa_candidates);
 			error = iph1->rsa_p ? 0 : -1;
-
+			genlist_free(iph1->rsa_candidates, NULL);
+			iph1->rsa_candidates = NULL;
 			break;
 #endif
 		default:
 			plog(LLV_ERROR, LOCATION, NULL,
-				"no supported certtype %d\n",
-				certtype);
+			     "cannot check signature for certtype %d\n",
+			     certtype);
 			vfree(my_hash);
 			return ISAKMP_INTERNAL_ERROR;
 		}
@@ -1634,115 +1648,26 @@
 oakley_getmycert(iph1)
 	struct ph1handle *iph1;
 {
-	switch (iph1->rmconf->certtype) {
-		case ISAKMP_CERT_X509SIGN:
-			if (iph1->cert)
-				return 0;
-			return get_cert_fromlocal(iph1, 1);
-
-#ifndef ANDROID_PATCHED
-		case ISAKMP_CERT_PLAINRSA:
-			if (iph1->rsa)
-				return 0;
-			return get_plainrsa_fromlocal(iph1, 1);
-#endif
-
-		default:
-			plog(LLV_ERROR, LOCATION, NULL,
-			     "Unknown certtype #%d\n",
-			     iph1->rmconf->certtype);
-			return -1;
-	}
-
-}
-
-/*
- * get a CERT from local file.
- * IN:
- *	my != 0 my cert.
- *	my == 0 peer's cert.
- */
-static int
-get_cert_fromlocal(iph1, my)
-	struct ph1handle *iph1;
-	int my;
-{
-	char path[MAXPATHLEN];
-	vchar_t *cert = NULL;
-	cert_t **certpl;
-	char *certfile;
-	int error = -1;
-
-	if (my) {
-		certfile = iph1->rmconf->mycertfile;
-		certpl = &iph1->cert;
-	} else {
-		certfile = iph1->rmconf->peerscertfile;
-		certpl = &iph1->cert_p;
-	}
-	if (!certfile) {
-		plog(LLV_ERROR, LOCATION, NULL, "no CERT defined.\n");
-		return 0;
-	}
-
-	switch (iph1->rmconf->certtype) {
+	switch (oakley_get_certtype(iph1->rmconf->mycert)) {
 	case ISAKMP_CERT_X509SIGN:
-	case ISAKMP_CERT_DNS:
-		/* make public file name */
-		getpathname(path, sizeof(path), LC_PATHTYPE_CERT, certfile);
-		cert = eay_get_x509cert(path);
-		if (cert) {
-			char *p = NULL;
-			p = eay_get_x509text(cert);
-			plog(LLV_DEBUG, LOCATION, NULL, "%s", p ? p : "\n");
-			racoon_free(p);
-		};
+		if (iph1->cert)
+			return 0;
+		iph1->cert = vdup(iph1->rmconf->mycert);
 		break;
-
+#ifndef ANDROID_PATCHED
+	case ISAKMP_CERT_PLAINRSA:
+		if (iph1->rsa)
+			return 0;
+		return get_plainrsa_fromlocal(iph1, 1);
+#endif
 	default:
 		plog(LLV_ERROR, LOCATION, NULL,
-			"not supported certtype %d\n",
-			iph1->rmconf->certtype);
-		goto end;
+		     "Unknown certtype #%d\n",
+		     oakley_get_certtype(iph1->rmconf->mycert));
+		return -1;
 	}
 
-	if (!cert) {
-		plog(LLV_ERROR, LOCATION, NULL,
-			"failed to get %s CERT.\n",
-			my ? "my" : "peers");
-		goto end;
-	}
-
-	*certpl = oakley_newcert();
-	if (!*certpl) {
-		plog(LLV_ERROR, LOCATION, NULL,
-			"failed to get cert buffer.\n");
-		goto end;
-	}
-	(*certpl)->pl = vmalloc(cert->l + 1);
-	if ((*certpl)->pl == NULL) {
-		plog(LLV_ERROR, LOCATION, NULL,
-			"failed to get cert buffer\n");
-		oakley_delcert(*certpl);
-		*certpl = NULL;
-		goto end;
-	}
-	memcpy((*certpl)->pl->v + 1, cert->v, cert->l);
-	(*certpl)->pl->v[0] = iph1->rmconf->certtype;
-	(*certpl)->type = iph1->rmconf->certtype;
-	(*certpl)->cert.v = (*certpl)->pl->v + 1;
-	(*certpl)->cert.l = (*certpl)->pl->l - 1;
-
-	plog(LLV_DEBUG, LOCATION, NULL, "created CERT payload:\n");
-	plogdump(LLV_DEBUG, (*certpl)->pl->v, (*certpl)->pl->l);
-
-	error = 0;
-
-end:
-	if (cert != NULL)
-		vfree(cert);
-
-	return error;
+	return 0;
 }
 
 #ifndef ANDROID_PATCHED
@@ -1808,7 +1733,7 @@
 	vchar_t *privkey = NULL;
 	int error = -1;
 
-	switch (iph1->rmconf->certtype) {
+	switch (oakley_get_certtype(iph1->rmconf->mycert)) {
 	case ISAKMP_CERT_X509SIGN:
 	case ISAKMP_CERT_DNS:
 		if (iph1->rmconf->myprivfile == NULL) {
@@ -1828,7 +1753,6 @@
 		}
 		plog(LLV_DEBUG2, LOCATION, NULL, "private key:\n");
 		plogdump(LLV_DEBUG2, privkey->v, privkey->l);
-
 		iph1->sig = eay_get_x509sign(iph1->hash, privkey);
 		break;
 #ifndef ANDROID_PATCHED
@@ -1839,7 +1763,7 @@
 	default:
 		plog(LLV_ERROR, LOCATION, NULL,
 		     "Unknown certtype #%d\n",
-		     iph1->rmconf->certtype);
+		     oakley_get_certtype(iph1->rmconf->mycert));
 		goto end;
 	}
 
@@ -1873,8 +1797,11 @@
 	int idlen, type;
 	int error;
 
+	if (iph1->rmconf == NULL || iph1->rmconf->verify_cert == FALSE)
+		return 0;
+
 	if (iph1->id_p == NULL || iph1->cert_p == NULL) {
-		plog(LLV_ERROR, LOCATION, NULL, "no ID nor CERT found.\n");
+		plog(LLV_ERROR, LOCATION, iph1->remote, "no ID nor CERT found.\n");
 		return ISAKMP_NTYPE_INVALID_ID_INFORMATION;
 	}
 
@@ -1883,27 +1810,30 @@
 
 	switch (id_b->type) {
 	case IPSECDOI_ID_DER_ASN1_DN:
-		name = eay_get_x509asn1subjectname(&iph1->cert_p->cert);
+		name = eay_get_x509asn1subjectname(iph1->cert_p);
 		if (!name) {
-			plog(LLV_ERROR, LOCATION, NULL,
+			plog(LLV_ERROR, LOCATION, iph1->remote,
 				"failed to get subjectName\n");
 			return ISAKMP_NTYPE_INVALID_CERTIFICATE;
 		}
 		if (idlen != name->l) {
-			plog(LLV_ERROR, LOCATION, NULL,
+			plog(LLV_ERROR, LOCATION, iph1->remote,
 				"Invalid ID length in phase 1.\n");
 			vfree(name);
 			return ISAKMP_NTYPE_INVALID_ID_INFORMATION;
 		}
 		error = memcmp(id_b + 1, name->v, idlen);
-		vfree(name);
 		if (error != 0) {
-			plog(LLV_ERROR, LOCATION, NULL,
+			plog(LLV_ERROR, LOCATION, iph1->remote,
 				"ID mismatched with ASN1 SubjectName.\n");
 			plogdump(LLV_DEBUG, id_b + 1, idlen);
 			plogdump(LLV_DEBUG, name->v, idlen);
-			return ISAKMP_NTYPE_INVALID_ID_INFORMATION;
+			if (iph1->rmconf->verify_identifier) {
+				vfree(name);
+				return ISAKMP_NTYPE_INVALID_ID_INFORMATION;
+			}
 		}
+		vfree(name);
 		return 0;
 	case IPSECDOI_ID_IPV4_ADDR:
 	case IPSECDOI_ID_IPV6_ADDR:
@@ -1918,7 +1848,7 @@
 		int pos;
 
 		for (pos = 1; ; pos++) {
-			if (eay_get_x509subjectaltname(&iph1->cert_p->cert,
+			if (eay_get_x509subjectaltname(iph1->cert_p,
 					&altname, &type, pos) !=0) {
 				plog(LLV_ERROR, LOCATION, NULL,
 					"failed to get subjectAltName\n");
@@ -1944,10 +1874,11 @@
 		hints.ai_socktype = SOCK_RAW;
 		hints.ai_flags = AI_NUMERICHOST;
 		error = getaddrinfo(altname, NULL, &hints, &res);
+		racoon_free(altname);
+		altname = NULL;
 		if (error != 0) {
 			plog(LLV_ERROR, LOCATION, NULL,
 				"no proper subjectAltName.\n");
-			racoon_free(altname);
 			return ISAKMP_NTYPE_INVALID_CERTIFICATE;
 		}
 		switch (res->ai_family) {
@@ -1962,7 +1893,6 @@
 		default:
 			plog(LLV_ERROR, LOCATION, NULL,
 				"family not supported: %d.\n", res->ai_family);
-			racoon_free(altname);
 			freeaddrinfo(res);
 			return ISAKMP_NTYPE_INVALID_CERTIFICATE;
 		}
@@ -1974,7 +1904,8 @@
 				"ID mismatched with subjectAltName.\n");
 			plogdump(LLV_DEBUG, id_b + 1, idlen);
 			plogdump(LLV_DEBUG, a, idlen);
-			return ISAKMP_NTYPE_INVALID_ID_INFORMATION;
+			if (iph1->rmconf->verify_identifier)
+				return ISAKMP_NTYPE_INVALID_ID_INFORMATION;
 		}
 		return 0;
 	}
@@ -1984,7 +1915,7 @@
 		int pos;
 
 		for (pos = 1; ; pos++) {
-			if (eay_get_x509subjectaltname(&iph1->cert_p->cert,
+			if (eay_get_x509subjectaltname(iph1->cert_p,
 					&altname, &type, pos) != 0){
 				plog(LLV_ERROR, LOCATION, NULL,
 					"failed to get subjectAltName\n");
@@ -2078,7 +2009,7 @@
 	struct ph1handle *iph1;
 	struct isakmp_gen *gen;
 {
-	cert_t **c;
+	vchar_t **c;
 	u_int8_t type;
 	STACK_OF(X509) *certs=NULL;
 	PKCS7 *p7;
@@ -2173,7 +2104,7 @@
 			     "Trying PKCS#7 cert %d.\n", i);
 
 			/* We'll just try each cert in turn */
-			*c = save_certx509(cert);
+			*c = dump_x509(cert);
 
 			if (!*c) {
 				plog(LLV_ERROR, LOCATION, NULL,
@@ -2185,19 +2116,18 @@
 			 * XXX If verify cert is disabled, we still just take
 			 * the first certificate....
 			 */
-			if(iph1->rmconf->verify_cert &&
-			   oakley_check_certid(iph1)) {
+			if (oakley_check_certid(iph1)) {
 				plog(LLV_DEBUG, LOCATION, NULL,
 				     "Discarding CERT: does not match ID.\n");
-				oakley_delcert((*c));
+				vfree((*c));
 				*c = NULL;
 				continue;
 			}
 
 			{
-				char *p = eay_get_x509text(&(*c)->cert);
+				char *p = eay_get_x509text(*c);
 				plog(LLV_DEBUG, LOCATION, NULL, "CERT saved:\n");
-				plogdump(LLV_DEBUG, (*c)->cert.v, (*c)->cert.l);
+				plogdump(LLV_DEBUG, (*c)->v, (*c)->l);
 				plog(LLV_DEBUG, LOCATION, NULL, "%s", 
 				     p ? p : "\n");
 				racoon_free(p);
@@ -2205,21 +2135,15 @@
 			break;
 		}
 		PKCS7_free(p7);
-
 	} else {
-		*c = save_certbuf(gen);
+		*c = dump_isakmp_payload(gen);
 		if (!*c) {
 			plog(LLV_ERROR, LOCATION, NULL,
 			     "Failed to get CERT buffer.\n");
 			return -1;
 		}
 
-		switch ((*c)->type) {
-		case ISAKMP_CERT_DNS:
-			plog(LLV_WARNING, LOCATION, NULL,
-			     "CERT payload is unnecessary in DNSSEC. "
-			     "ignore it.\n");
-			return 0;
+		switch (type) {
 		case ISAKMP_CERT_PGP:
 		case ISAKMP_CERT_X509SIGN:
 		case ISAKMP_CERT_KERBEROS:
@@ -2228,33 +2152,32 @@
 			 * XXX If verify cert is disabled, we still just take
 			 * the first certificate....
 			 */
-			if(iph1->rmconf->verify_cert &&
-			   oakley_check_certid(iph1)){
+			if (oakley_check_certid(iph1)){
 				plog(LLV_DEBUG, LOCATION, NULL,
 				     "Discarding CERT: does not match ID.\n");
-				oakley_delcert((*c));
+				vfree((*c));
 				*c = NULL;
 				return 0;
 			}
 
 			{
-				char *p = eay_get_x509text(&(*c)->cert);
+				char *p = eay_get_x509text(*c);
 				plog(LLV_DEBUG, LOCATION, NULL, "CERT saved:\n");
-				plogdump(LLV_DEBUG, (*c)->cert.v, (*c)->cert.l);
+				plogdump(LLV_DEBUG, (*c)->v, (*c)->l);
 				plog(LLV_DEBUG, LOCATION, NULL, "%s", p ? p : "\n");
 				racoon_free(p);
 			}
 			break;
 		case ISAKMP_CERT_CRL:
 			plog(LLV_DEBUG, LOCATION, NULL, "CRL saved:\n");
-			plogdump(LLV_DEBUG, (*c)->cert.v, (*c)->cert.l);
+			plogdump(LLV_DEBUG, (*c)->v, (*c)->l);
 			break;
 		case ISAKMP_CERT_X509KE:
 		case ISAKMP_CERT_X509ATTR:
 		case ISAKMP_CERT_ARL:
 		default:
 			/* XXX */
-			oakley_delcert((*c));
+			vfree(*c);
 			*c = NULL;
 			return 0;
 		}
@@ -2271,11 +2194,11 @@
 	struct ph1handle *iph1;
 	struct isakmp_gen *gen;
 {
-	cert_t **c;
+	vchar_t *cert;
+	vchar_t **c;
 	u_int8_t type;
 
 	type = *(u_int8_t *)(gen + 1) & 0xff;
-
 	switch (type) {
 	case ISAKMP_CERT_DNS:
 		plog(LLV_WARNING, LOCATION, NULL,
@@ -2301,119 +2224,109 @@
 		return -1;
 	}
 
-	*c = save_certbuf(gen);
-	if (!*c) {
+	/* Already found an acceptable CR? */
+	if (*c != NULL)
+		return 0;
+
+	cert = dump_isakmp_payload(gen);
+	if (cert == NULL) {
 		plog(LLV_ERROR, LOCATION, NULL,
 			"Failed to get CR buffer.\n");
 		return -1;
 	}
 
-	plog(LLV_DEBUG, LOCATION, NULL, "CR saved:\n");
-	plogdump(LLV_DEBUG, (*c)->cert.v, (*c)->cert.l);
+	plog(LLV_DEBUG, LOCATION, NULL, "CR received:\n");
+	plogdump(LLV_DEBUG, cert->v, cert->l);
 
+	*c = cert;
+	if (resolveph1rmconf(iph1) == 0) {
+		/* Found unique match */
+		plog(LLV_DEBUG, LOCATION, NULL, "CR saved.\n");
+	} else {
+		/* Still ambiguous or matches nothing, ignore this CR */
+		*c = NULL;
+		vfree(cert);
+	}
 	return 0;
 }
 
-static cert_t *
-save_certbuf(gen)
-	struct isakmp_gen *gen;
+/*
+ * Add a single CR.
+ */
+struct append_cr_ctx {
+	struct ph1handle *iph1;
+	struct payload_list *plist;
+};
+
+static int
+oakley_append_rmconf_cr(rmconf, ctx)
+	struct remoteconf *rmconf;
+	void *ctx;
 {
-	cert_t *new;
+	struct append_cr_ctx *actx = (struct append_cr_ctx *) ctx;
+	vchar_t *buf, *asn1dn = NULL;
+	int type;
 
-	if(ntohs(gen->len) <= sizeof(*gen)){
-		plog(LLV_ERROR, LOCATION, NULL,
-			 "Len is too small !!.\n");
-		return NULL;
+	/* Do we want to send CR about this? */
+	if (rmconf->send_cr == FALSE)
+		return 0;
+
+	if (rmconf->peerscert != NULL) {
+		type = oakley_get_certtype(rmconf->peerscert);
+		asn1dn = eay_get_x509asn1issuername(rmconf->peerscert);
+	} else if (rmconf->cacert != NULL) {
+		type = oakley_get_certtype(rmconf->cacert);
+		asn1dn = eay_get_x509asn1subjectname(rmconf->cacert);
+	} else
+		return 0;
+
+	if (asn1dn == NULL) {
+		plog(LLV_ERROR, LOCATION, actx->iph1->remote,
+		     "Failed to get CR ASN1 DN from certificate\n");
+		return 0;
 	}
 
-	new = oakley_newcert();
-	if (!new) {
-		plog(LLV_ERROR, LOCATION, NULL,
-			"Failed to get CERT buffer.\n");
-		return NULL;
-	}
+	buf = vmalloc(1 + asn1dn->l);
+	if (buf == NULL)
+		goto err;
 
-	new->pl = vmalloc(ntohs(gen->len) - sizeof(*gen));
-	if (new->pl == NULL) {
-		plog(LLV_ERROR, LOCATION, NULL,
-			"Failed to copy CERT from packet.\n");
-		oakley_delcert(new);
-		new = NULL;
-		return NULL;
-	}
-	memcpy(new->pl->v, gen + 1, new->pl->l);
-	new->type = new->pl->v[0] & 0xff;
-	new->cert.v = new->pl->v + 1;
-	new->cert.l = new->pl->l - 1;
+	buf->v[0] = type;
+	memcpy(&buf->v[1], asn1dn->v, asn1dn->l);
 
-	return new;
-}
+	plog(LLV_DEBUG, LOCATION, actx->iph1->remote,
+	     "appending CR: %s\n",
+	     s_isakmp_certtype(buf->v[0]));
+	plogdump(LLV_DEBUG, buf->v, buf->l);
 
-static cert_t *
-save_certx509(cert)
-	X509 *cert;
-{
-	cert_t *new;
-        int len;
-        u_char *bp;
+	actx->plist = isakmp_plist_append_full(actx->plist, buf, ISAKMP_NPTYPE_CR, 1);
 
-	new = oakley_newcert();
-	if (!new) {
-		plog(LLV_ERROR, LOCATION, NULL,
-			"Failed to get CERT buffer.\n");
-		return NULL;
-	}
-
-        len = i2d_X509(cert, NULL);
-	new->pl = vmalloc(len);
-	if (new->pl == NULL) {
-		plog(LLV_ERROR, LOCATION, NULL,
-			"Failed to copy CERT from packet.\n");
-		oakley_delcert(new);
-		new = NULL;
-		return NULL;
-	}
-        bp = (u_char *) new->pl->v;
-        len = i2d_X509(cert, &bp);
-	new->type = ISAKMP_CERT_X509SIGN;
-	new->cert.v = new->pl->v;
-	new->cert.l = new->pl->l;
-
-	return new;
+err:
+	vfree(asn1dn);
+	return 0;
 }
 
 /*
- * get my CR.
- * NOTE: No Certificate Authority field is included to CR payload at the
- * moment. Becuase any certificate authority are accepted without any check.
- * The section 3.10 in RFC2408 says that this field SHOULD not be included,
- * if there is no specific certificate authority requested.
+ * Append list of acceptable CRs.
+ * RFC2048 3.10
  */
-vchar_t *
-oakley_getcr(iph1)
+struct payload_list *
+oakley_append_cr(plist, iph1)
+	struct payload_list *plist;
 	struct ph1handle *iph1;
 {
-	vchar_t *buf;
+	struct append_cr_ctx ctx;
+	struct rmconfselector sel;
 
-	buf = vmalloc(1);
-	if (buf == NULL) {
-		plog(LLV_ERROR, LOCATION, NULL,
-			"failed to get cr buffer\n");
-		return NULL;
-	}
-	if(iph1->rmconf->certtype == ISAKMP_CERT_NONE) {
-		buf->v[0] = iph1->rmconf->cacerttype;
-		plog(LLV_DEBUG, LOCATION, NULL, "create my CR: NONE, using %s instead\n",
-		s_isakmp_certtype(iph1->rmconf->cacerttype));
+	ctx.iph1 = iph1;
+	ctx.plist = plist;
+	if (iph1->rmconf == NULL) {
+		rmconf_selector_from_ph1(&sel, iph1);
+		enumrmconf(&sel, oakley_append_rmconf_cr, &ctx);
 	} else {
-		buf->v[0] = iph1->rmconf->certtype;
-		plog(LLV_DEBUG, LOCATION, NULL, "create my CR: %s\n",
-		s_isakmp_certtype(iph1->rmconf->certtype));
+		oakley_append_rmconf_cr(iph1->rmconf, &ctx);
 	}
-	if (buf->l > 1)
-		plogdump(LLV_DEBUG, buf->v, buf->l);
 
-	return buf;
+	return ctx.plist;
 }
 
 /*
@@ -2423,17 +2336,20 @@
 oakley_checkcr(iph1)
 	struct ph1handle *iph1;
 {
+	int type;
+
 	if (iph1->cr_p == NULL)
 		return 0;
 
 	plog(LLV_DEBUG, LOCATION, iph1->remote,
 		"peer transmitted CR: %s\n",
-		s_isakmp_certtype(iph1->cr_p->type));
+		s_isakmp_certtype(oakley_get_certtype(iph1->cr_p)));
 
-	if (iph1->cr_p->type != iph1->rmconf->certtype) {
+	type = oakley_get_certtype(iph1->cr_p);
+	if (type != oakley_get_certtype(iph1->rmconf->mycert)) {
 		plog(LLV_ERROR, LOCATION, iph1->remote,
-			"such a cert type isn't supported: %d\n",
-			(char)iph1->cr_p->type);
+		     "such a cert type isn't supported: %d\n",
+		     type);
 		return -1;
 	}
 
@@ -2482,10 +2398,10 @@
 	int error = -1;
 	
 	/* SKEYID */
-	switch (AUTHMETHOD(iph1)) {
+	switch (iph1->approval->authmethod) {
 	case OAKLEY_ATTR_AUTH_METHOD_PSKEY:
 #ifdef ENABLE_HYBRID
-	case FICTIVE_AUTH_METHOD_XAUTH_PSKEY_I:
+	case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_I:
 	case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_R:
 #endif
 		if (iph1->etype != ISAKMP_ETYPE_IDENT) {
@@ -2748,7 +2664,7 @@
 					iph1->approval->encklen);
 	if (keylen == -1) {
 		plog(LLV_ERROR, LOCATION, NULL,
-			"invalid encryption algoritym %d, "
+			"invalid encryption algorithm %d, "
 			"or invalid key length %d.\n",
 			iph1->approval->enctype,
 			iph1->approval->encklen);
@@ -2852,7 +2768,7 @@
 	if (iph1->approval->enctype > ARRAYLEN(oakley_encdef)
 	 || oakley_encdef[iph1->approval->enctype].weakkey == NULL) {
 		plog(LLV_ERROR, LOCATION, NULL,
-			"encryption algoritym %d isn't supported.\n",
+			"encryption algorithm %d isn't supported.\n",
 			iph1->approval->enctype);
 		goto end;
 	}
@@ -2872,36 +2788,6 @@
 	return error;
 }
 
-/* allocated new buffer for CERT */
-cert_t *
-oakley_newcert()
-{
-	cert_t *new;
-
-	new = racoon_calloc(1, sizeof(*new));
-	if (new == NULL) {
-		plog(LLV_ERROR, LOCATION, NULL,
-			"failed to get cert's buffer\n");
-		return NULL;
-	}
-
-	new->pl = NULL;
-
-	return new;
-}
-
-/* delete buffer for CERT */
-void
-oakley_delcert(cert)
-	cert_t *cert;
-{
-	if (!cert)
-		return;
-	if (cert->pl)
-		VPTRINIT(cert->pl);
-	racoon_free(cert);
-}
-
 /*
  * compute IV and set to ph1handle
  *	IV = hash(g^xi | g^xr)
@@ -2956,7 +2842,7 @@
 	newivm->iv->l = alg_oakley_encdef_blocklen(iph1->approval->enctype);
 	if (newivm->iv->l == -1) {
 		plog(LLV_ERROR, LOCATION, NULL,
-			"invalid encryption algoriym %d.\n",
+			"invalid encryption algorithm %d.\n",
 			iph1->approval->enctype);
 		vfree(buf);
 		oakley_delivm(newivm);
@@ -3038,7 +2924,7 @@
 	newivm->iv->l = alg_oakley_encdef_blocklen(iph1->approval->enctype);
 	if (newivm->iv->l == -1) {
 		plog(LLV_ERROR, LOCATION, NULL,
-			"invalid encryption algoriym %d.\n",
+			"invalid encryption algorithm %d.\n",
 			iph1->approval->enctype);
 		goto end;
 	}
@@ -3102,7 +2988,7 @@
 	blen = alg_oakley_encdef_blocklen(iph1->approval->enctype);
 	if (blen == -1) {
 		plog(LLV_ERROR, LOCATION, NULL,
-			"invalid encryption algoriym %d.\n",
+			"invalid encryption algorithm %d.\n",
 			iph1->approval->enctype);
 		goto end;
 	}
@@ -3224,7 +3110,7 @@
 	blen = alg_oakley_encdef_blocklen(iph1->approval->enctype);
 	if (blen == -1) {
 		plog(LLV_ERROR, LOCATION, NULL,
-			"invalid encryption algoriym %d.\n",
+			"invalid encryption algorithm %d.\n",
 			iph1->approval->enctype);
 		goto end;
 	}
diff --git a/src/racoon/oakley.h b/src/racoon/oakley.h
index a8dbbd2..f8cdb76 100644
--- a/src/racoon/oakley.h
+++ b/src/racoon/oakley.h
@@ -1,4 +1,4 @@
-/*	$NetBSD: oakley.h,v 1.5 2006/10/06 12:02:27 manu Exp $	*/
+/*	$NetBSD: oakley.h,v 1.7 2009/03/12 10:57:26 tteras Exp $	*/
 
 /* Id: oakley.h,v 1.13 2005/05/30 20:12:43 fredsen Exp */
 
@@ -89,21 +89,18 @@
 #define OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAREV_R	65010
 #endif
 
-					/*	65500 -> still private
-					 * to avoid clash with GSSAPI_KRB below 
-					 */
-#define FICTIVE_AUTH_METHOD_XAUTH_PSKEY_I	65500
+/*
+ * The following are valid when the Vendor ID is one of
+ * the following:
+ *
+ *	MD5("A GSS-API Authentication Method for IKE")
+ *	MD5("GSSAPI") (recognized by Windows 2000)
+ *	MD5("MS NT5 ISAKMPOAKLEY") (sent by Windows 2000)
+ */
 
+#define OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB	(65001 + 0x10000)
+#define OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB_REAL	65001
 
-	/*
-	 * The following are valid when the Vendor ID is one of
-	 * the following:
-	 *
-	 *	MD5("A GSS-API Authentication Method for IKE")
-	 *	MD5("GSSAPI") (recognized by Windows 2000)
-	 *	MD5("MS NT5 ISAKMPOAKLEY") (sent by Windows 2000)
-	 */
-#define   OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB	65001
 #define OAKLEY_ATTR_GRP_DESC		4 /* B */
 #define   OAKLEY_ATTR_GRP_DESC_MODP768		1
 #define   OAKLEY_ATTR_GRP_DESC_MODP1024		2
@@ -163,13 +160,6 @@
 	vchar_t *order;
 };
 
-/* certificate holder */
-typedef struct cert_t_tag {
-	u_int8_t type;		/* type of CERT, must be same to pl->v[0]*/
-	vchar_t cert;		/* pointer to the CERT */
-	vchar_t *pl;		/* CERT payload minus isakmp general header */
-} cert_t;
-
 struct ph1handle;
 struct ph2handle;
 struct isakmp_ivm;
@@ -200,10 +190,13 @@
 extern vchar_t *oakley_ph1hash_base_i __P((struct ph1handle *, int));
 extern vchar_t *oakley_ph1hash_base_r __P((struct ph1handle *, int));
 
+extern int oakley_get_certtype __P((vchar_t *));
 extern int oakley_validate_auth __P((struct ph1handle *));
 extern int oakley_getmycert __P((struct ph1handle *));
 extern int oakley_getsign __P((struct ph1handle *));
 extern vchar_t *oakley_getcr __P((struct ph1handle *));
+extern struct payload_list *oakley_append_cr __P((struct payload_list *,
+						  struct ph1handle *));
 extern int oakley_checkcr __P((struct ph1handle *));
 extern int oakley_needcr __P((int));
 struct isakmp_gen;
@@ -214,8 +207,6 @@
 extern int oakley_skeyid_dae __P((struct ph1handle *));
 
 extern int oakley_compute_enckey __P((struct ph1handle *));
-extern cert_t *oakley_newcert __P((void));
-extern void oakley_delcert __P((cert_t *));
 extern int oakley_newiv __P((struct ph1handle *));
 extern struct isakmp_ivm *oakley_newiv2 __P((struct ph1handle *, u_int32_t));
 extern void oakley_delivm __P((struct isakmp_ivm *));
@@ -224,20 +215,4 @@
 extern vchar_t *oakley_do_encrypt __P((struct ph1handle *,
 	vchar_t *, vchar_t *, vchar_t *));
 
-#ifdef ENABLE_HYBRID
-#define AUTHMETHOD(iph1)						     \
-    (((iph1)->rmconf->xauth &&						     \
-    (iph1)->approval->authmethod == OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_I) ? \
-	FICTIVE_AUTH_METHOD_XAUTH_PSKEY_I : (iph1)->approval->authmethod)
-#define RMAUTHMETHOD(iph1)						     \
-    (((iph1)->rmconf->xauth &&						     \
-    (iph1)->rmconf->proposal->authmethod ==                                  \
-	OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_I) ?                             \
-	FICTIVE_AUTH_METHOD_XAUTH_PSKEY_I :                                  \
-	(iph1)->rmconf->proposal->authmethod)
-#else
-#define AUTHMETHOD(iph1) (iph1)->approval->authmethod
-#define RMAUTHMETHOD(iph1) (iph1)->rmconf->proposal->authmethod
-#endif /* ENABLE_HYBRID */
-
 #endif /* _OAKLEY_H */
diff --git a/src/racoon/pfkey.c b/src/racoon/pfkey.c
index e73acc8..e69cb94 100644
--- a/src/racoon/pfkey.c
+++ b/src/racoon/pfkey.c
@@ -1,11 +1,11 @@
-/*	$NetBSD: pfkey.c,v 1.18.4.5 2008/03/05 22:14:24 mgrooms Exp $	*/
+/*	$NetBSD: pfkey.c,v 1.57 2011/03/15 13:20:14 vanhu Exp $	*/
 
-/* $Id: pfkey.c,v 1.18.4.5 2008/03/05 22:14:24 mgrooms Exp $ */
+/* $Id: pfkey.c,v 1.57 2011/03/15 13:20:14 vanhu Exp $ */
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
  * All rights reserved.
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
@@ -17,7 +17,7 @@
  * 3. Neither the name of the project nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
- * 
+ *
  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@@ -77,6 +77,7 @@
 #include "vmbuf.h"
 #include "plog.h"
 #include "sockmisc.h"
+#include "session.h"
 #include "debug.h"
 
 #include "schedule.h"
@@ -94,6 +95,7 @@
 #include "algorithm.h"
 #include "sainfo.h"
 #include "admin.h"
+#include "evt.h"
 #include "privsep.h"
 #include "strnames.h"
 #include "backupsa.h"
@@ -129,6 +131,9 @@
 static int pk_recvspdget __P((caddr_t *));
 static int pk_recvspddump __P((caddr_t *));
 static int pk_recvspdflush __P((caddr_t *));
+#if defined(SADB_X_MIGRATE) && defined(SADB_X_EXT_KMADDRESS)
+static int pk_recvmigrate __P((caddr_t *));
+#endif
 static struct sadb_msg *pk_recv __P((int, int *));
 
 static int (*pkrecvf[]) __P((caddr_t *)) = {
@@ -156,17 +161,21 @@
 pk_recvspdexpire,
 NULL,	/* SADB_X_SPDDELETE2 */
 NULL,	/* SADB_X_NAT_T_NEW_MAPPING */
+#if defined(SADB_X_MIGRATE) && defined(SADB_X_EXT_KMADDRESS)
+pk_recvmigrate,
+#else
 NULL,	/* SADB_X_MIGRATE */
+#endif
 #if (SADB_MAX > 24)
 #error "SADB extra message?"
 #endif
 };
 
-static int addnewsp __P((caddr_t *));
+static int addnewsp __P((caddr_t *, struct sockaddr *, struct sockaddr *));
 
 /* cope with old kame headers - ugly */
 #ifndef SADB_X_AALG_MD5
-#define SADB_X_AALG_MD5		SADB_AALG_MD5	
+#define SADB_X_AALG_MD5		SADB_AALG_MD5
 #endif
 #ifndef SADB_X_AALG_SHA
 #define SADB_X_AALG_SHA		SADB_AALG_SHA
@@ -192,8 +201,10 @@
  *	0: success
  *	-1: fail
  */
-int
-pfkey_handler()
+static int
+pfkey_handler(ctx, fd)
+	void *ctx;
+	int fd;
 {
 	struct sadb_msg *msg;
 	int len;
@@ -202,9 +213,16 @@
 
 	/* receive pfkey message. */
 	len = 0;
-	msg = (struct sadb_msg *)pk_recv(lcconf->sock_pfkey, &len);
+	msg = (struct sadb_msg *) pk_recv(fd, &len);
 	if (msg == NULL) {
 		if (len < 0) {
+		        /* do not report EAGAIN as error; well get
+		         * called from main loop later. and it's normal
+		         * when spd dump is received during reload and
+		         * this function is called in loop. */
+		        if (errno == EAGAIN)
+		                goto end;
+
 			plog(LLV_ERROR, LOCATION, NULL,
 				"failed to recv from pfkey (%s)\n",
 				strerror(errno));
@@ -215,7 +233,7 @@
 		}
 	}
 
-	plog(LLV_DEBUG, LOCATION, NULL, "get pfkey %s message\n",
+	plog(LLV_DEBUG, LOCATION, NULL, "got pfkey %s message\n",
 		s_pfkey_type(msg->sadb_msg_type));
 	plogdump(LLV_DEBUG2, msg, msg->sadb_msg_len << 3);
 
@@ -271,7 +289,7 @@
 	if ((pkrecvf[msg->sadb_msg_type])(mhp) < 0)
 		goto end;
 
-	error = 0;
+	error = 1;
 end:
 	if (msg)
 		racoon_free(msg);
@@ -285,20 +303,32 @@
 pfkey_dump_sadb(satype)
 	int satype;
 {
-	int s = -1;
+	int s;
 	vchar_t *buf = NULL;
 	pid_t pid = getpid();
 	struct sadb_msg *msg = NULL;
 	size_t bl, ml;
 	int len;
+	int bufsiz;
 
-	if ((s = privsep_pfkey_open()) < 0) {
+	if ((s = privsep_socket(PF_KEY, SOCK_RAW, PF_KEY_V2)) < 0) {
 		plog(LLV_ERROR, LOCATION, NULL,
 			"libipsec failed pfkey open: %s\n",
 			ipsec_strerror());
 		return NULL;
 	}
 
+	if ((bufsiz = pfkey_set_buffer_size(s, lcconf->pfkey_buffer_size)) < 0) {
+		plog(LLV_ERROR, LOCATION, NULL,
+		     "libipsec failed pfkey set buffer size to %d: %s\n",
+		     lcconf->pfkey_buffer_size, ipsec_strerror());
+		return NULL;
+	} else if (bufsiz < lcconf->pfkey_buffer_size) {
+		plog(LLV_WARNING, LOCATION, NULL,
+		     "pfkey socket receive buffer set to %dKB, instead of %d\n",
+		     bufsiz, lcconf->pfkey_buffer_size);
+	}
+
 	plog(LLV_DEBUG, LOCATION, NULL, "call pfkey_send_dump\n");
 	if (pfkey_send_dump(s, satype) < 0) {
 		plog(LLV_ERROR, LOCATION, NULL,
@@ -325,7 +355,7 @@
 			 "type %i, pid %i\n", msg->sadb_msg_type, msg->sadb_msg_pid);
 		    continue;
 		}
-		
+
 
 		ml = msg->sadb_msg_len << 3;
 		bl = buf ? buf->l : 0;
@@ -349,8 +379,7 @@
 done:
 	if (msg)
 		racoon_free(msg);
-	if (s >= 0)
-		privsep_pfkey_close(s);
+	close(s);
 	return buf;
 }
 
@@ -400,12 +429,25 @@
 pfkey_init()
 {
 	int i, reg_fail;
+	int bufsiz;
 
-	if ((lcconf->sock_pfkey = privsep_pfkey_open()) < 0) {
+	if ((lcconf->sock_pfkey = pfkey_open()) < 0) {
 		plog(LLV_ERROR, LOCATION, NULL,
 			"libipsec failed pfkey open (%s)\n", ipsec_strerror());
 		return -1;
 	}
+	if ((bufsiz = pfkey_set_buffer_size(lcconf->sock_pfkey,
+					    lcconf->pfkey_buffer_size)) < 0) {
+		plog(LLV_ERROR, LOCATION, NULL,
+		     "libipsec failed to set pfkey buffer size to %d (%s)\n",
+		     lcconf->pfkey_buffer_size, ipsec_strerror());
+		return -1;
+	} else if (bufsiz < lcconf->pfkey_buffer_size) {
+		plog(LLV_WARNING, LOCATION, NULL,
+		     "pfkey socket receive buffer set to %dKB, instead of %d\n",
+		     bufsiz, lcconf->pfkey_buffer_size);
+	}
+
 	if (fcntl(lcconf->sock_pfkey, F_SETFL, O_NONBLOCK) == -1)
 		plog(LLV_WARNING, LOCATION, NULL,
 		    "failed to set the pfkey socket to NONBLOCK\n");
@@ -447,6 +489,25 @@
 		return -1;
 	}
 #endif
+	monitor_fd(lcconf->sock_pfkey, pfkey_handler, NULL, 0);
+	return 0;
+}
+
+int
+pfkey_reload()
+{
+	flushsp();
+
+	if (pfkey_send_spddump(lcconf->sock_pfkey) < 0) {
+		plog(LLV_ERROR, LOCATION, NULL,
+			"libipsec sending spddump failed: %s\n",
+			ipsec_strerror());
+		return -1;
+	}
+
+	while (pfkey_handler(NULL, lcconf->sock_pfkey) > 0)
+		continue;
+
 	return 0;
 }
 
@@ -717,6 +778,29 @@
 	return res;
 }
 
+void
+pk_fixup_sa_addresses(mhp)
+	caddr_t *mhp;
+{
+	struct sockaddr *src, *dst;
+
+	src = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_SRC]);
+	dst = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_DST]);
+	set_port(src, PORT_ISAKMP);
+	set_port(dst, PORT_ISAKMP);
+
+#ifdef ENABLE_NATT
+	if (PFKEY_ADDR_X_NATTYPE(mhp[SADB_X_EXT_NAT_T_TYPE])) {
+		/* NAT-T is enabled for this SADB entry; copy
+		 * the ports from NAT-T extensions */
+		if(mhp[SADB_X_EXT_NAT_T_SPORT] != NULL)
+			set_port(src, PFKEY_ADDR_X_PORT(mhp[SADB_X_EXT_NAT_T_SPORT]));
+		if(mhp[SADB_X_EXT_NAT_T_DPORT] != NULL)
+			set_port(dst, PFKEY_ADDR_X_PORT(mhp[SADB_X_EXT_NAT_T_DPORT]));
+	}
+#endif
+}
+
 int
 pfkey_convertfromipsecdoi(proto_id, t_id, hashtype,
 		e_type, e_keylen, a_type, a_keylen, flags)
@@ -757,7 +841,7 @@
 			goto bad;
 		*a_keylen >>= 3;
 
-		if (t_id == IPSECDOI_ATTR_AUTH_HMAC_MD5 
+		if (t_id == IPSECDOI_ATTR_AUTH_HMAC_MD5
 		 && hashtype == IPSECDOI_ATTR_AUTH_KPDK) {
 			/* AH_MD5 + Auth(KPDK) = RFC1826 keyed-MD5 */
 			*a_type = SADB_X_AALG_MD5;
@@ -798,35 +882,6 @@
 	return -1;
 }
 
-/* called from scheduler */
-void
-pfkey_timeover_stub(p)
-	void *p;
-{
-
-	pfkey_timeover((struct ph2handle *)p);
-}
-
-void
-pfkey_timeover(iph2)
-	struct ph2handle *iph2;
-{
-	plog(LLV_ERROR, LOCATION, NULL,
-		"%s give up to get IPsec-SA due to time up to wait.\n",
-		saddrwop2str(iph2->dst));
-	SCHED_KILL(iph2->sce);
-
-	/* If initiator side, send error to kernel by SADB_ACQUIRE. */
-	if (iph2->side == INITIATOR)
-		pk_sendeacquire(iph2);
-
-	unbindph12(iph2);
-	remph2(iph2);
-	delph2(iph2);
-
-	return;
-}
-
 /*%%%*/
 /* send getspi message per ipsec protocol per remote address */
 /*
@@ -843,25 +898,28 @@
 	struct saprop *pp;
 	struct saproto *pr;
 	u_int32_t minspi, maxspi;
-	int proxy = 0;
+	u_int8_t natt_type = 0;
+	u_int16_t sport = 0, dport = 0;
 
-	if (iph2->side == INITIATOR) {
+	if (iph2->side == INITIATOR)
 		pp = iph2->proposal;
-		proxy = iph2->ph1->rmconf->support_proxy;
-	} else {
+	else
 		pp = iph2->approval;
-		if (iph2->sainfo && iph2->sainfo->id_i)
-			proxy = 1;
+
+	if (iph2->sa_src && iph2->sa_dst) {
+		/* MIPv6: Use SA addresses, not IKE ones */
+		src = dupsaddr(iph2->sa_src);
+		dst = dupsaddr(iph2->sa_dst);
+	} else {
+		/* Common case: SA addresses and IKE ones are the same */
+		src = dupsaddr(iph2->src);
+		dst = dupsaddr(iph2->dst);
 	}
 
-	/* 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 (src == NULL || dst == NULL) {
+		racoon_free(src);
+		racoon_free(dst);
+		return -1;
 	}
 
 	for (pr = pp->head; pr != NULL; pr = pr->next) {
@@ -871,6 +929,8 @@
 		if (satype == ~0) {
 			plog(LLV_ERROR, LOCATION, NULL,
 				"invalid proto_id %d\n", pr->proto_id);
+			racoon_free(src);
+			racoon_free(dst);
 			return -1;
 		}
 		/* this works around a bug in Linux kernel where it allocates 4 byte
@@ -887,30 +947,36 @@
 		if (mode == ~0) {
 			plog(LLV_ERROR, LOCATION, NULL,
 				"invalid encmode %d\n", pr->encmode);
+			racoon_free(src);
+			racoon_free(dst);
 			return -1;
 		}
 
 #ifdef ENABLE_NATT
-		/* XXX should we do a copy of src/dst for each pr ?
-		 */
-		if (! pr->udp_encap) {
-			/* Remove port information, that SA doesn't use it */
-			set_port(src, 0);
-			set_port(dst, 0);
+		if (pr->udp_encap) {
+			natt_type = iph2->ph1->natt_options->encaps_type;
+			sport=extract_port(src);
+			dport=extract_port(dst);
 		}
 #endif
+
 		plog(LLV_DEBUG, LOCATION, NULL, "call pfkey_send_getspi\n");
-		if (pfkey_send_getspi(
+		if (pfkey_send_getspi_nat(
 				lcconf->sock_pfkey,
 				satype,
 				mode,
 				dst,			/* src of SA */
 				src,			/* dst of SA */
+				natt_type,
+				dport,
+				sport,
 				minspi, maxspi,
 				pr->reqid_in, iph2->seq) < 0) {
 			plog(LLV_ERROR, LOCATION, NULL,
 				"ipseclib failed send getspi (%s)\n",
 				ipsec_strerror());
+			racoon_free(src);
+			racoon_free(dst);
 			return -1;
 		}
 		plog(LLV_DEBUG, LOCATION, NULL,
@@ -918,6 +984,8 @@
 			sadbsecas2str(dst, src, satype, 0, mode));
 	}
 
+	racoon_free(src);
+	racoon_free(dst);
 	return 0;
 }
 
@@ -925,13 +993,13 @@
  * receive GETSPI from kernel.
  */
 static int
-pk_recvgetspi(mhp) 
+pk_recvgetspi(mhp)
 	caddr_t *mhp;
 {
 	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;
@@ -939,14 +1007,17 @@
 
 	/* 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;
 	}
 	msg = (struct sadb_msg *)mhp[0];
 	sa = (struct sadb_sa *)mhp[SADB_EXT_SA];
+	pk_fixup_sa_addresses(mhp);
 	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()) {
@@ -986,7 +1057,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)));
@@ -998,7 +1069,7 @@
 	if (notfound) {
 		plog(LLV_ERROR, LOCATION, NULL,
 			"get spi for unknown address %s\n",
-			saddrwop2str(iph2->dst));
+			saddrwop2str(dst));
 		return -1;
 	}
 
@@ -1008,7 +1079,6 @@
 		if (isakmp_post_getspi(iph2) < 0) {
 			plog(LLV_ERROR, LOCATION, NULL,
 				"failed to start post getspi.\n");
-			unbindph12(iph2);
 			remph2(iph2);
 			delph2(iph2);
 			iph2 = NULL;
@@ -1028,34 +1098,38 @@
 {
 	struct saproto *pr;
 	struct pfkey_send_sa_args sa_args;
-	int proxy = 0;
 
 	/* sanity check */
 	if (iph2->approval == NULL) {
 		plog(LLV_ERROR, LOCATION, NULL,
 			"no approvaled SAs found.\n");
+		return -1;
 	}
 
-	if (iph2->side == INITIATOR)
-		proxy = iph2->ph1->rmconf->support_proxy;
-	else if (iph2->sainfo && iph2->sainfo->id_i)
-		proxy = 1;
-
 	/* fill in some needed for pfkey_send_update2 */
 	memset (&sa_args, 0, sizeof (sa_args));
 	sa_args.so = lcconf->sock_pfkey;
-	sa_args.l_addtime = iph2->approval->lifetime;
-	sa_args.seq = iph2->seq; 
+	if (iph2->lifetime_secs)
+		sa_args.l_addtime = iph2->lifetime_secs;
+	else
+		sa_args.l_addtime = iph2->approval->lifetime;
+	sa_args.seq = iph2->seq;
 	sa_args.wsize = 4;
 
-	/* for mobile IPv6 */
-	if (proxy && iph2->src_id && iph2->dst_id &&
-	    ipsecdoi_transportmode(iph2->approval)) {
-		sa_args.dst = iph2->src_id;
-		sa_args.src = iph2->dst_id;
+	if (iph2->sa_src && iph2->sa_dst) {
+		/* MIPv6: Use SA addresses, not IKE ones */
+		sa_args.dst = dupsaddr(iph2->sa_src);
+		sa_args.src = dupsaddr(iph2->sa_dst);
 	} else {
-		sa_args.dst = iph2->src;
-		sa_args.src = iph2->dst;
+		/* Common case: SA addresses and IKE ones are the same */
+		sa_args.dst = dupsaddr(iph2->src);
+		sa_args.src = dupsaddr(iph2->dst);
+	}
+
+	if (sa_args.src == NULL || sa_args.dst == NULL) {
+		racoon_free(sa_args.src);
+		racoon_free(sa_args.dst);
+		return -1;
 	}
 
 	for (pr = iph2->approval->head; pr != NULL; pr = pr->next) {
@@ -1064,6 +1138,8 @@
 		if (sa_args.satype == ~0) {
 			plog(LLV_ERROR, LOCATION, NULL,
 				"invalid proto_id %d\n", pr->proto_id);
+			racoon_free(sa_args.src);
+			racoon_free(sa_args.dst);
 			return -1;
 		}
 		else if (sa_args.satype == SADB_X_SATYPE_IPCOMP) {
@@ -1077,6 +1153,8 @@
 		if (sa_args.mode == ~0) {
 			plog(LLV_ERROR, LOCATION, NULL,
 				"invalid encmode %d\n", pr->encmode);
+			racoon_free(sa_args.src);
+			racoon_free(sa_args.dst);
 			return -1;
 		}
 #endif
@@ -1087,9 +1165,12 @@
 				pr->head->trns_id,
 				pr->head->authtype,
 				&sa_args.e_type, &sa_args.e_keylen,
-				&sa_args.a_type, &sa_args.a_keylen, 
-				&sa_args.flags) < 0)
+				&sa_args.a_type, &sa_args.a_keylen,
+				&sa_args.flags) < 0){
+			racoon_free(sa_args.src);
+			racoon_free(sa_args.dst);
 			return -1;
+		}
 
 #if 0
 		sa_args.l_bytes = iph2->approval->lifebyte * 1024,
@@ -1109,19 +1190,15 @@
 #ifdef ENABLE_NATT
 		if (pr->udp_encap) {
 			sa_args.l_natt_type = iph2->ph1->natt_options->encaps_type;
-			sa_args.l_natt_sport = extract_port (iph2->ph1->remote);
-			sa_args.l_natt_dport = extract_port (iph2->ph1->local);
-			sa_args.l_natt_oa = NULL;  // FIXME: Here comes OA!!!
+			sa_args.l_natt_sport = extract_port(iph2->ph1->remote);
+			sa_args.l_natt_dport = extract_port(iph2->ph1->local);
+			sa_args.l_natt_oa = iph2->natoa_src;
 #ifdef SADB_X_EXT_NAT_T_FRAG
 			sa_args.l_natt_frag = iph2->ph1->rmconf->esp_frag;
 #endif
-		} else {
-			/* Remove port information, that SA doesn't use it */
-			set_port(sa_args.src, 0);
-			set_port(sa_args.dst, 0);
 		}
-
 #endif
+
 		/* more info to fill in */
 		sa_args.spi = pr->spi;
 		sa_args.reqid = pr->reqid_in;
@@ -1132,6 +1209,8 @@
 			plog(LLV_ERROR, LOCATION, NULL,
 				"libipsec failed send update (%s)\n",
 				ipsec_strerror());
+			racoon_free(sa_args.src);
+			racoon_free(sa_args.dst);
 			return -1;
 		}
 
@@ -1145,11 +1224,11 @@
 		 * But it is impossible because there is not key in the
 		 * information from the kernel.
 		 */
-		
+
 		/* change some things before backing up */
 		sa_args.wsize = 4;
 		sa_args.l_bytes = iph2->approval->lifebyte * 1024;
-		
+
 		if (backupsa_to_file(&sa_args) < 0) {
 			plog(LLV_ERROR, LOCATION, NULL,
 				"backuped SA failed: %s\n",
@@ -1163,6 +1242,8 @@
 #endif
 	}
 
+	racoon_free(sa_args.src);
+	racoon_free(sa_args.dst);
 	return 0;
 }
 
@@ -1192,6 +1273,7 @@
 		return -1;
 	}
 	msg = (struct sadb_msg *)mhp[0];
+	pk_fixup_sa_addresses(mhp);
 	src = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_SRC]);
 	dst = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_DST]);
 	sa = (struct sadb_sa *)mhp[SADB_EXT_SA];
@@ -1246,14 +1328,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));
 		}
@@ -1266,10 +1348,11 @@
 		return 0;
 
 	/* turn off the timer for calling pfkey_timeover() */
-	SCHED_KILL(iph2->sce);
-	
+	sched_cancel(&iph2->sce);
+
 	/* update status */
 	iph2->status = PHASE2ST_ESTABLISHED;
+	evt_phase2(iph2, EVT_PHASE2_UP, NULL);
 
 #ifdef ENABLE_STATS
 	gettimeofday(&iph2->end, NULL);
@@ -1277,29 +1360,15 @@
 		"phase2", "quick", timedelta(&iph2->start, &iph2->end));
 #endif
 
-	/* count up */
-	iph2->ph1->ph2cnt++;
-
 	/* turn off schedule */
-	SCHED_KILL(iph2->scr);
-
-	/* Force the update of ph2's ports, as there is at least one
-	 * situation where they'll mismatch with ph1's values
-	 */
-
-#ifdef ENABLE_NATT
-	set_port(iph2->src, extract_port(iph2->ph1->local));
-	set_port(iph2->dst, extract_port(iph2->ph1->remote));
-#endif
+	sched_cancel(&iph2->scr);
 
 	/*
 	 * 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);
+	sched_schedule(&iph2->sce, iph2->approval->lifetime,
+		       isakmp_ph2expire_stub);
 
 	plog(LLV_DEBUG, LOCATION, NULL, "===\n");
 	return 0;
@@ -1313,7 +1382,6 @@
 	struct ph2handle *iph2;
 {
 	struct saproto *pr;
-	int proxy = 0;
 	struct pfkey_send_sa_args sa_args;
 
 	/* sanity check */
@@ -1323,26 +1391,30 @@
 		return -1;
 	}
 
-	if (iph2->side == INITIATOR)
-		proxy = iph2->ph1->rmconf->support_proxy;
-	else if (iph2->sainfo && iph2->sainfo->id_i)
-		proxy = 1;
-
 	/* fill in some needed for pfkey_send_update2 */
 	memset (&sa_args, 0, sizeof (sa_args));
 	sa_args.so = lcconf->sock_pfkey;
-	sa_args.l_addtime = iph2->approval->lifetime;
+	if (iph2->lifetime_secs)
+		sa_args.l_addtime = iph2->lifetime_secs;
+	else
+		sa_args.l_addtime = iph2->approval->lifetime;
 	sa_args.seq = iph2->seq;
 	sa_args.wsize = 4;
 
-	/* for mobile IPv6 */
-	if (proxy && iph2->src_id && iph2->dst_id &&
-	    ipsecdoi_transportmode(iph2->approval)) {
-		sa_args.src = iph2->src_id;
-		sa_args.dst = iph2->dst_id;
+	if (iph2->sa_src && iph2->sa_dst) {
+		/* MIPv6: Use SA addresses, not IKE ones */
+		sa_args.src = dupsaddr(iph2->sa_src);
+		sa_args.dst = dupsaddr(iph2->sa_dst);
 	} else {
-		sa_args.src = iph2->src;
-		sa_args.dst = iph2->dst;
+		/* Common case: SA addresses and IKE ones are the same */
+		sa_args.src = dupsaddr(iph2->src);
+		sa_args.dst = dupsaddr(iph2->dst);
+	}
+
+	if (sa_args.src == NULL || sa_args.dst == NULL) {
+		racoon_free(sa_args.src);
+		racoon_free(sa_args.dst);
+		return -1;
 	}
 
 	for (pr = iph2->approval->head; pr != NULL; pr = pr->next) {
@@ -1351,6 +1423,8 @@
 		if (sa_args.satype == ~0) {
 			plog(LLV_ERROR, LOCATION, NULL,
 				"invalid proto_id %d\n", pr->proto_id);
+			racoon_free(sa_args.src);
+			racoon_free(sa_args.dst);
 			return -1;
 		}
 		else if (sa_args.satype == SADB_X_SATYPE_IPCOMP) {
@@ -1364,6 +1438,8 @@
 		if (sa_args.mode == ~0) {
 			plog(LLV_ERROR, LOCATION, NULL,
 				"invalid encmode %d\n", pr->encmode);
+			racoon_free(sa_args.src);
+			racoon_free(sa_args.dst);
 			return -1;
 		}
 #endif
@@ -1375,9 +1451,12 @@
 				pr->head->trns_id,
 				pr->head->authtype,
 				&sa_args.e_type, &sa_args.e_keylen,
-				&sa_args.a_type, &sa_args.a_keylen, 
-				&sa_args.flags) < 0)
+				&sa_args.a_type, &sa_args.a_keylen,
+				&sa_args.flags) < 0){
+			racoon_free(sa_args.src);
+			racoon_free(sa_args.dst);
 			return -1;
+		}
 
 #if 0
 		sa_args.l_bytes = iph2->approval->lifebyte * 1024,
@@ -1402,22 +1481,12 @@
 			sa_args.l_natt_type = UDP_ENCAP_ESPINUDP;
 			sa_args.l_natt_sport = extract_port(iph2->ph1->local);
 			sa_args.l_natt_dport = extract_port(iph2->ph1->remote);
-			sa_args.l_natt_oa = NULL; // FIXME: Here comes OA!!!
+			sa_args.l_natt_oa = iph2->natoa_dst;
 #ifdef SADB_X_EXT_NAT_T_FRAG
 			sa_args.l_natt_frag = iph2->ph1->rmconf->esp_frag;
 #endif
-		} else {
-			/* Remove port information, that SA doesn't use it */
-			set_port(sa_args.src, 0);
-			set_port(sa_args.dst, 0);
 		}
-
-#else
-		/* Remove port information, it is not used without NAT-T */
-		set_port(sa_args.src, 0);
-		set_port(sa_args.dst, 0);
 #endif
-
 		/* more info to fill in */
 		sa_args.spi = pr->spi_p;
 		sa_args.reqid = pr->reqid_out;
@@ -1428,6 +1497,8 @@
 			plog(LLV_ERROR, LOCATION, NULL,
 				"libipsec failed send add (%s)\n",
 				ipsec_strerror());
+			racoon_free(sa_args.src);
+			racoon_free(sa_args.dst);
 			return -1;
 		}
 
@@ -1453,6 +1524,8 @@
 			sa_args.satype, sa_args.spi, sa_args.mode));
 #endif
 	}
+	racoon_free(sa_args.src);
+	racoon_free(sa_args.dst);
 	return 0;
 }
 
@@ -1480,6 +1553,7 @@
 		return -1;
 	}
 	msg = (struct sadb_msg *)mhp[0];
+	pk_fixup_sa_addresses(mhp);
 	src = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_SRC]);
 	dst = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_DST]);
 	sa = (struct sadb_sa *)mhp[SADB_EXT_SA];
@@ -1514,7 +1588,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");
@@ -1544,6 +1618,7 @@
 	}
 	msg = (struct sadb_msg *)mhp[0];
 	sa = (struct sadb_sa *)mhp[SADB_EXT_SA];
+	pk_fixup_sa_addresses(mhp);
 	src = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_SRC]);
 	dst = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_DST]);
 
@@ -1577,54 +1652,63 @@
 			    sa_mode));
 		return 0;
 	}
-	if (iph2->status != PHASE2ST_ESTABLISHED) {
+
+	/* resent expiry message? */
+	if (iph2->status > PHASE2ST_ESTABLISHED)
+		return 0;
+
+	/* still negotiating? */
+	if (iph2->status < PHASE2ST_ESTABLISHED) {
+		/* not a hard timeout? */
+		if (mhp[SADB_EXT_LIFETIME_HARD] == NULL)
+			return 0;
+
 		/*
-		 * If the status is not equal to PHASE2ST_ESTABLISHED,
-		 * racoon ignores this expire message.  There are two reason.
-		 * One is that the phase 2 probably starts because there is
-		 * a potential that racoon receives the acquire message
-		 * without receiving a expire message.  Another is that racoon
-		 * may receive the multiple expire messages from the kernel.
+		 * We were negotiating for that SA (w/o much success
+		 * from current status) and kernel has decided our time
+		 * is over trying (xfrm_larval_drop controls that and
+		 * is enabled by default on Linux >= 2.6.28 kernels).
 		 */
 		plog(LLV_WARNING, LOCATION, NULL,
-			"the expire message is received "
-			"but the handler has not been established.\n");
-		return 0;
+		     "PF_KEY EXPIRE message received from kernel for SA"
+		     " being negotiated. Stopping negotiation.\n");
 	}
 
-	/* turn off the timer for calling isakmp_ph2expire() */ 
-	SCHED_KILL(iph2->sce);
+	/* turn off the timer for calling isakmp_ph2expire() */
+	sched_cancel(&iph2->sce);
 
-	iph2->status = PHASE2ST_EXPIRED;
-
-	/* INITIATOR, begin phase 2 exchange. */
-	/* allocate buffer for status management of pfkey message */
-	if (iph2->side == INITIATOR) {
-
-		initph2(iph2);
+	if (iph2->status == PHASE2ST_ESTABLISHED &&
+	    iph2->side == INITIATOR) {
+		struct ph1handle *iph1hint;
+		/*
+		 * Active phase 2 expired and we were initiator.
+		 * Begin new phase 2 exchange, so we can keep on sending
+		 * traffic.
+		 */
 
 		/* update status for re-use */
+		iph1hint = iph2->ph1;
+		initph2(iph2);
 		iph2->status = PHASE2ST_STATUS2;
 
-		/* start isakmp initiation by using ident exchange */
-		if (isakmp_post_acquire(iph2) < 0) {
+		/* start quick exchange */
+		if (isakmp_post_acquire(iph2, iph1hint, FALSE) < 0) {
 			plog(LLV_ERROR, LOCATION, iph2->dst,
 				"failed to begin ipsec sa "
 				"re-negotication.\n");
-			unbindph12(iph2);
 			remph2(iph2);
 			delph2(iph2);
 			return -1;
 		}
 
 		return 0;
-		/*NOTREACHED*/
 	}
 
-	/* If not received SADB_EXPIRE, INITIATOR delete ph2handle. */
-	/* RESPONDER always delete ph2handle, keep silent.  RESPONDER doesn't
-	 * manage IPsec SA, so delete the list */
-	unbindph12(iph2);
+	/*
+	 * We are responder or the phase 2 was not established.
+	 * Just remove the ph2handle to reflect SADB.
+	 */
+	iph2->status = PHASE2ST_EXPIRED;
 	remph2(iph2);
 	delph2(iph2);
 
@@ -1638,17 +1722,15 @@
 	struct sadb_msg *msg;
 	struct sadb_x_policy *xpl;
 	struct secpolicy *sp_out = NULL, *sp_in = NULL;
-#define MAXNESTEDSA	5	/* XXX */
-	struct ph2handle *iph2[MAXNESTEDSA];
-	struct sockaddr *src, *dst;
-	int n;	/* # of phase 2 handler */
-	int remoteid=0;
+	struct ph2handle *iph2;
+	struct sockaddr *src, *dst;     /* IKE addresses (for exchanges) */
+	struct sockaddr *sp_src, *sp_dst;   /* SP addresses (selectors). */
+	struct sockaddr *sa_src = NULL, *sa_dst = NULL ; /* SA addresses */
 #ifdef HAVE_SECCTX
 	struct sadb_x_sec_ctx *m_sec_ctx;
 #endif /* HAVE_SECCTX */
 	struct policyindex spidx;
 
-
 	/* ignore this message because of local test mode. */
 	if (f_local)
 		return 0;
@@ -1664,8 +1746,11 @@
 	}
 	msg = (struct sadb_msg *)mhp[0];
 	xpl = (struct sadb_x_policy *)mhp[SADB_X_EXT_POLICY];
-	src = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_SRC]);
-	dst = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_DST]);
+	/* acquire does not have nat-t ports; so do not bother setting
+	 * the default port 500; just use the port zero for wildcard
+	 * matching the get a valid natted destination */
+	sp_src = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_SRC]);
+	sp_dst = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_DST]);
 
 #ifdef HAVE_SECCTX
 	m_sec_ctx = (struct sadb_x_sec_ctx *)mhp[SADB_X_EXT_SEC_CTX];
@@ -1673,7 +1758,7 @@
 	if (m_sec_ctx != NULL) {
 		plog(LLV_INFO, LOCATION, NULL, "security context doi: %u\n",
 		     m_sec_ctx->sadb_x_ctx_doi);
-		plog(LLV_INFO, LOCATION, NULL, 
+		plog(LLV_INFO, LOCATION, NULL,
 		     "security context algorithm: %u\n",
 		     m_sec_ctx->sadb_x_ctx_alg);
 		plog(LLV_INFO, LOCATION, NULL, "security context length: %u\n",
@@ -1690,50 +1775,81 @@
 		return 0;
 	}
 
-	/* ignore it if src is multicast address */
-    {
-	struct sockaddr *sa = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_DST]);
-
-	if ((sa->sa_family == AF_INET
-	  && IN_MULTICAST(ntohl(((struct sockaddr_in *)sa)->sin_addr.s_addr)))
+	/* ignore it if src or dst are multicast addresses. */
+	if ((sp_dst->sa_family == AF_INET
+	  && IN_MULTICAST(ntohl(((struct sockaddr_in *)sp_dst)->sin_addr.s_addr)))
 #ifdef INET6
-	 || (sa->sa_family == AF_INET6
-	  && IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6 *)sa)->sin6_addr))
+	 || (sp_dst->sa_family == AF_INET6
+	  && IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6 *)sp_dst)->sin6_addr))
 #endif
 	) {
 		plog(LLV_DEBUG, LOCATION, NULL,
-			"ignore due to multicast address: %s.\n",
-			saddrwop2str(sa));
+			"ignore due to multicast destination address: %s.\n",
+			saddrwop2str(sp_dst));
 		return 0;
 	}
-    }
-   	
-    	/* ignore, if we do not listen on source address */
-	{
-		/* reasons behind:
-		 * - if we'll contact peer from address we do not listen -
-		 *   we will be unable to complete negotiation;
-		 * - if we'll negotiate using address we're listening -
-		 *   remote peer will send packets to address different
-		 *   than one in the policy, so kernel will drop them;
-		 * => therefore this acquire is not for us! --Aidas
-		 */
-		struct sockaddr *sa = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_SRC]);
-		struct myaddrs *p;
-		int do_listen = 0;
-		for (p = lcconf->myaddrs; p; p = p->next) {
-			if (!cmpsaddrwop(p->addr, sa)) {
-				do_listen = 1;
-				break;
-			}
-		}
 
-		if (!do_listen) {
-			plog(LLV_DEBUG, LOCATION, NULL,
-				"ignore because do not listen on source address : %s.\n",
-				saddrwop2str(sa));
-			return 0;
-		}
+	if ((sp_src->sa_family == AF_INET
+	  && IN_MULTICAST(ntohl(((struct sockaddr_in *)sp_src)->sin_addr.s_addr)))
+#ifdef INET6
+	 || (sp_src->sa_family == AF_INET6
+	  && IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6 *)sp_src)->sin6_addr))
+#endif
+	) {
+		plog(LLV_DEBUG, LOCATION, NULL,
+			"ignore due to multicast source address: %s.\n",
+			saddrwop2str(sp_src));
+		return 0;
+	}
+
+	/* search for proper policyindex */
+	sp_out = getspbyspid(xpl->sadb_x_policy_id);
+	if (sp_out == NULL) {
+		plog(LLV_ERROR, LOCATION, NULL, "no policy found: id:%d.\n",
+			xpl->sadb_x_policy_id);
+		return -1;
+	}
+	plog(LLV_DEBUG, LOCATION, NULL,
+		"suitable outbound SP found: %s.\n", spidx2str(&sp_out->spidx));
+
+	/* Before going further, let first get the source and destination
+	 * address that would be used for IKE negotiation. The logic is:
+	 * - if SP from SPD image contains local and remote hints, we
+	 *   use them (provided by MIGRATE).
+	 * - otherwise, we use the ones from the ipsecrequest, which means:
+	 *   - the addresses from the request for transport mode
+	 *   - the endpoints addresses for tunnel mode
+	 *
+	 * Note that:
+	 * 1) racoon does not support negotiation of bundles which
+	 *    simplifies the lookup for the addresses in the ipsecrequest
+	 *    list, as we expect only one.
+	 * 2) We do source and destination parts all together and do not
+	 *    accept semi-defined information. This is just a decision,
+	 *    there might be needs.
+	 *
+	 * --arno
+	 */
+	if (sp_out->req && sp_out->req->saidx.mode == IPSEC_MODE_TUNNEL) {
+		/* For Tunnel mode, SA addresses are the endpoints */
+		src = (struct sockaddr *) &sp_out->req->saidx.src;
+		dst = (struct sockaddr *) &sp_out->req->saidx.dst;
+	} else {
+		/* Otherwise use requested addresses.
+		 *
+		 * We need to explicitly setup sa_src and sa_dst too,
+		 * since the SA ports are different from IKE port. And
+		 * src/dst ports will be overwritten when the matching
+		 * phase1 is found. */
+		src = sa_src = sp_src;
+		dst = sa_dst = sp_dst;
+	}
+	if (sp_out->local && sp_out->remote) {
+		/* hints available, let's use them */
+		sa_src = src;
+		sa_dst = dst;
+		src = (struct sockaddr *) sp_out->local;
+		dst = (struct sockaddr *) sp_out->remote;
 	}
 
 	/*
@@ -1746,27 +1862,25 @@
 	 *       has to prcesss such a acquire message because racoon may
 	 *       lost the expire message.
 	 */
-	iph2[0] = getph2byid(src, dst, xpl->sadb_x_policy_id);
-	if (iph2[0] != NULL) {
-		if (iph2[0]->status < PHASE2ST_ESTABLISHED) {
+	iph2 = getph2byid(src, dst, xpl->sadb_x_policy_id);
+	if (iph2 != NULL) {
+		if (iph2->status < PHASE2ST_ESTABLISHED) {
 			plog(LLV_DEBUG, LOCATION, NULL,
 				"ignore the acquire because ph2 found\n");
 			return -1;
 		}
-		if (iph2[0]->status == PHASE2ST_EXPIRED)
-			iph2[0] = NULL;
+		if (iph2->status == PHASE2ST_EXPIRED)
+			iph2 = NULL;
 		/*FALLTHROUGH*/
 	}
 
-	/* search for proper policyindex */
-	sp_out = getspbyspid(xpl->sadb_x_policy_id);
-	if (sp_out == NULL) {
-		plog(LLV_ERROR, LOCATION, NULL, "no policy found: id:%d.\n",
-			xpl->sadb_x_policy_id);
-		return -1;
+	/* Check we are listening on source address. If not, ignore. */
+	if (myaddr_getsport(src) == -1) {
+		plog(LLV_DEBUG, LOCATION, NULL,
+		     "Not listening on source address %s. Ignoring ACQUIRE.\n",
+		     saddrwop2str(src));
+		return 0;
 	}
-	plog(LLV_DEBUG, LOCATION, NULL,
-		"suitable outbound SP found: %s.\n", spidx2str(&sp_out->spidx));
 
 	/* get inbound policy */
     {
@@ -1802,119 +1916,67 @@
 	}
     }
 
-	memset(iph2, 0, MAXNESTEDSA);
-
-	n = 0;
-
 	/* allocate a phase 2 */
-	iph2[n] = newph2();
-	if (iph2[n] == NULL) {
+	iph2 = newph2();
+	if (iph2 == NULL) {
 		plog(LLV_ERROR, LOCATION, NULL,
 			"failed to allocate phase2 entry.\n");
 		return -1;
 	}
-	iph2[n]->side = INITIATOR;
-	iph2[n]->spid = xpl->sadb_x_policy_id;
-	iph2[n]->satype = msg->sadb_msg_satype;
-	iph2[n]->seq = msg->sadb_msg_seq;
-	iph2[n]->status = PHASE2ST_STATUS2;
+	iph2->side = INITIATOR;
+	iph2->spid = xpl->sadb_x_policy_id;
+	iph2->satype = msg->sadb_msg_satype;
+	iph2->seq = msg->sadb_msg_seq;
+	iph2->status = PHASE2ST_STATUS2;
 
-	/* set end addresses of SA */
-	iph2[n]->dst = dupsaddr(PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_DST]));
-	if (iph2[n]->dst == NULL) {
-		delph2(iph2[n]);
+	/* set address used by IKE for the negotiation (might differ from
+	 * SA address, i.e. might not be tunnel endpoints or addresses
+	 * of transport mode SA) */
+	iph2->dst = dupsaddr(dst);
+	if (iph2->dst == NULL) {
+		delph2(iph2);
 		return -1;
 	}
-	iph2[n]->src = dupsaddr(PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_SRC]));
-	if (iph2[n]->src == NULL) {
-		delph2(iph2[n]);
+	iph2->src = dupsaddr(src);
+	if (iph2->src == NULL) {
+		delph2(iph2);
 		return -1;
 	}
 
-	plog(LLV_DEBUG, LOCATION, NULL,
-		"new acquire %s\n", spidx2str(&sp_out->spidx));
-
-	/* get sainfo */
-    {
-	vchar_t *idsrc, *iddst;
-
-	idsrc = ipsecdoi_sockaddr2id((struct sockaddr *)&sp_out->spidx.src,
-				sp_out->spidx.prefs, sp_out->spidx.ul_proto);
-	if (idsrc == NULL) {
-		plog(LLV_ERROR, LOCATION, NULL,
-			"failed to get ID for %s\n",
-			spidx2str(&sp_out->spidx));
-		delph2(iph2[n]);
-		return -1;
-	}
-	iddst = ipsecdoi_sockaddr2id((struct sockaddr *)&sp_out->spidx.dst,
-				sp_out->spidx.prefd, sp_out->spidx.ul_proto);
-	if (iddst == NULL) {
-		plog(LLV_ERROR, LOCATION, NULL,
-			"failed to get ID for %s\n",
-			spidx2str(&sp_out->spidx));
-		vfree(idsrc);
-		delph2(iph2[n]);
-		return -1;
-	}
-	{
-		struct remoteconf *conf;
-		conf = getrmconf(iph2[n]->dst);
-		if (conf != NULL)
-			remoteid=conf->ph1id;
-		else{
-			plog(LLV_DEBUG, LOCATION, NULL, "Warning: no valid rmconf !\n");
-			remoteid=0;
-		}
-	}
-	iph2[n]->sainfo = getsainfo(idsrc, iddst, NULL, remoteid);
-	vfree(idsrc);
-	vfree(iddst);
-	if (iph2[n]->sainfo == NULL) {
-		plog(LLV_ERROR, LOCATION, NULL,
-			"failed to get sainfo.\n");
-		delph2(iph2[n]);
-		return -1;
-		/* XXX should use the algorithm list from register message */
+	/* If sa_src and sa_dst have been set, this mean we have to
+	 * set iph2->sa_src and iph2->sa_dst to provide the addresses
+	 * of the SA because iph2->src and iph2->dst are only the ones
+	 * used for the IKE exchanges. Those that need these addresses
+	 * are for instance pk_sendupdate() or pk_sendgetspi() */
+	if (sa_src) {
+		iph2->sa_src = dupsaddr(sa_src);
+		iph2->sa_dst = dupsaddr(sa_dst);
 	}
 
-	plog(LLV_DEBUG, LOCATION, NULL,
-		"selected sainfo: %s\n", sainfo2str(iph2[n]->sainfo));
-    }
-
-	if (set_proposal_from_policy(iph2[n], sp_out, sp_in) < 0) {
-		plog(LLV_ERROR, LOCATION, NULL,
-			"failed to create saprop.\n");
-		delph2(iph2[n]);
+	if (isakmp_get_sainfo(iph2, sp_out, sp_in) < 0) {
+		delph2(iph2);
 		return -1;
 	}
+
 #ifdef HAVE_SECCTX
 	if (m_sec_ctx) {
-		set_secctx_in_proposal(iph2[n], spidx);
+		set_secctx_in_proposal(iph2, spidx);
 	}
 #endif /* HAVE_SECCTX */
 
-	insph2(iph2[n]);
+	insph2(iph2);
 
 	/* start isakmp initiation by using ident exchange */
 	/* XXX should be looped if there are multiple phase 2 handler. */
-	if (isakmp_post_acquire(iph2[n]) < 0) {
+	if (isakmp_post_acquire(iph2, NULL, TRUE) < 0) {
 		plog(LLV_ERROR, LOCATION, NULL,
 			"failed to begin ipsec sa negotication.\n");
-		goto err;
+		remph2(iph2);
+		delph2(iph2);
+		return -1;
 	}
 
 	return 0;
-
-err:
-	while (n >= 0) {
-		unbindph12(iph2[n]);
-		remph2(iph2[n]);
-		delph2(iph2[n]);
-		iph2[n] = NULL;
-		n--;
-	}
-	return -1;
 }
 
 static int
@@ -1942,6 +2004,7 @@
 	}
 	msg = (struct sadb_msg *)mhp[0];
 	sa = (struct sadb_sa *)mhp[SADB_EXT_SA];
+	pk_fixup_sa_addresses(mhp);
 	src = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_SRC]);
 	dst = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_DST]);
 
@@ -1973,14 +2036,13 @@
 
 	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 */
 	if (iph2->status == PHASE2ST_ESTABLISHED)
 		isakmp_info_send_d2(iph2);
 
-	unbindph12(iph2);
 	remph2(iph2);
 	delph2(iph2);
 
@@ -2014,6 +2076,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;
@@ -2032,11 +2095,19 @@
 	/* get policy buffer size */
 	policylen = sizeof(struct sadb_x_policy);
 	if (type != SADB_X_SPDDELETE) {
+		if (iph2->sa_src && iph2->sa_dst) {
+			src = iph2->sa_src; /* MIPv6: Use SA addresses, */
+			dst = iph2->sa_dst; /* not IKE ones             */
+		} else {
+			src = iph2->src; /* Common case: SA addresses */
+			dst = iph2->dst; /* and IKE ones are the same */
+		}
+
 		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);
@@ -2082,7 +2153,7 @@
 		p->sadb_x_ctx_len = spidx->sec_ctx.ctx_strlen;
 		p->sadb_x_ctx_doi = spidx->sec_ctx.ctx_doi;
 		p->sadb_x_ctx_alg = spidx->sec_ctx.ctx_alg;
- 
+
 		memcpy(p + 1,spidx->sec_ctx.ctx_str,spidx->sec_ctx.ctx_strlen);
 		len += ctxlen;
 	}
@@ -2121,7 +2192,7 @@
 			goto err;
 		}
 
-		/* 
+		/*
 		 * the policy level cannot be unique because the policy
 		 * is defined later than SA, so req_id cannot be bound to SA.
 		 */
@@ -2141,20 +2212,20 @@
 		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;
 		}
 
 		xisr->sadb_x_ipsecrequest_len = PFKEY_ALIGN8(xisrlen);
 		xisr = (struct sadb_x_ipsecrequest *)p;
-		
+
 	}
 	racoon_free(pr_rlist);
 
@@ -2219,10 +2290,12 @@
 {
 	struct sadb_address *saddr, *daddr;
 	struct sadb_x_policy *xpl;
- 	struct sadb_lifetime *lt;
+	struct sadb_lifetime *lt;
 	struct policyindex spidx;
 	struct secpolicy *sp;
- 	u_int64_t created;
+	struct sockaddr *local=NULL, *remote=NULL;
+	u_int64_t created;
+	int ret;
 
 	/* sanity check */
 	if (mhp[0] == NULL
@@ -2277,15 +2350,29 @@
 
 	sp = getsp(&spidx);
 	if (sp == NULL) {
-		plog(LLV_ERROR, LOCATION, NULL,
-			"such policy does not already exist: \"%s\"\n",
+		plog(LLV_DEBUG, LOCATION, NULL,
+			"this policy did not exist for removal: \"%s\"\n",
 			spidx2str(&spidx));
 	} else {
+		/* preserve hints before deleting the SP */
+		local = sp->local;
+		remote = sp->remote;
+		sp->local = NULL;
+		sp->remote = NULL;
+
 		remsp(sp);
 		delsp(sp);
 	}
 
-	if (addnewsp(mhp) < 0)
+	/* Add new SP (with old hints) */
+	ret = addnewsp(mhp, local, remote);
+
+	if (local != NULL)
+		racoon_free(local);
+	if (remote != NULL)
+		racoon_free(remote);
+
+	if (ret < 0)
 		return -1;
 
 	return 0;
@@ -2344,7 +2431,9 @@
 	struct sadb_lifetime *lt;
 	struct policyindex spidx;
 	struct secpolicy *sp;
+	struct sockaddr *local = NULL, *remote = NULL;
 	u_int64_t created;
+	int ret;
 
 	/* sanity check */
 	if (mhp[0] == NULL
@@ -2403,11 +2492,26 @@
 			"such policy already exists. "
 			"anyway replace it: %s\n",
 			spidx2str(&spidx));
+
+		/* preserve hints before deleting the SP */
+		local = sp->local;
+		remote = sp->remote;
+		sp->local = NULL;
+		sp->remote = NULL;
+
 		remsp(sp);
 		delsp(sp);
 	}
 
-	if (addnewsp(mhp) < 0)
+	/* Add new SP (with old hints) */
+	ret = addnewsp(mhp, local, remote);
+
+	if (local != NULL)
+		racoon_free(local);
+	if (remote != NULL)
+		racoon_free(remote);
+
+	if (ret < 0)
 		return -1;
 
 	return 0;
@@ -2628,7 +2732,9 @@
 	struct sadb_lifetime *lt;
 	struct policyindex spidx;
 	struct secpolicy *sp;
+	struct sockaddr *local=NULL, *remote=NULL;
 	u_int64_t created;
+	int ret;
 
 	/* sanity check */
 	if (mhp[0] == NULL) {
@@ -2637,7 +2743,6 @@
 		return -1;
 	}
 	msg = (struct sadb_msg *)mhp[0];
-
 	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];
@@ -2692,11 +2797,26 @@
 			"such policy already exists. "
 			"anyway replace it: %s\n",
 			spidx2str(&spidx));
+
+		/* preserve hints before deleting the SP */
+		local = sp->local;
+		remote = sp->remote;
+		sp->local = NULL;
+		sp->remote = NULL;
+
 		remsp(sp);
 		delsp(sp);
 	}
 
-	if (addnewsp(mhp) < 0)
+	/* Add new SP (with old hints) */
+	ret = addnewsp(mhp, local, remote);
+
+	if (local != NULL)
+		racoon_free(local);
+	if (remote != NULL)
+		racoon_free(remote);
+
+	if (ret < 0)
 		return -1;
 
 	return 0;
@@ -2718,10 +2838,731 @@
 	return 0;
 }
 
+#if defined(SADB_X_MIGRATE) && defined(SADB_X_EXT_KMADDRESS)
+
+/* MIGRATE support (pk_recvmigrate() is the handler of MIGRATE message).
+ *
+ * pk_recvmigrate()
+ *   1) some preprocessing and checks
+ *   2) parsing of sadb_x_kmaddress extension
+ *   3) SP lookup using selectors and content of policy extension from MIGRATE
+ *   4) resolution of current local and remote IKE addresses
+ *   5) Use of addresses to get Phase 1 handler if any
+ *   6) Update of IKE addresses in Phase 1 (iph1->local and iph1->remote)
+ *   7) Update of IKE addresses in Phase 2 (iph2->src and iph2->dst)
+ *   8) Update of IKE addresses in SP (sp->local and sp->remote)
+ *   9) Loop on sadb_x_ipsecrequests pairs from MIGRATE
+ *      - update of associated ipsecrequests entries in sp->req (should be
+ *        only one as racoon does not support bundles), i.e. update of
+ *        tunnel endpoints when required.
+ *      - If tunnel mode endpoints have been updated, lookup of associated
+ *        Phase 2 handle to also update sa_src and sa_dst entries
+ *
+ * XXX Note that we do not support yet the update of SA addresses for transport
+ *     mode, but only the update of SA addresses for tunnel mode (endpoints).
+ *     Reasons are:
+ *      - there is no initial need for MIPv6
+ *      - racoon does not support bundles
+ *      - this would imply more work to deal with sainfo update (if feasible).
+ */
+
+/* Generic argument structure for migration callbacks */
+struct migrate_args {
+	struct sockaddr *local;
+	struct sockaddr *remote;
+};
+
+/*
+ * Update local and remote addresses of given Phase 1. Schedule removal
+ * if negotiation was going on and restart a one from updated address.
+ *
+ * -1 is returned on error. 0 if everything went right.
+ */
+static int
+migrate_ph1_ike_addresses(iph1, arg)
+        struct ph1handle *iph1;
+        void *arg;
+{
+	struct migrate_args *ma = (struct migrate_args *) arg;
+	struct remoteconf *rmconf;
+	u_int16_t port;
+
+	/* Already up-to-date? */
+	if (cmpsaddr(iph1->local, ma->local) == CMPSADDR_MATCH &&
+	    cmpsaddr(iph1->remote, ma->remote) == CMPSADDR_MATCH)
+		return 0;
+
+	if (iph1->status < PHASE1ST_ESTABLISHED) {
+		/* Bad luck! We received a MIGRATE *while* negotiating
+		 * Phase 1 (i.e. it was not established yet). If we act as
+		 * initiator we need to restart the negotiation. As
+		 * responder, our best bet is to update our addresses
+		 * and wait for the initiator to do something */
+		plog(LLV_WARNING, LOCATION, NULL, "MIGRATE received *during* "
+		     "Phase 1 negotiation (%s).\n",
+		     saddr2str_fromto("%s => %s", ma->local, ma->remote));
+
+		/* If we are not acting as initiator, let's just leave and
+		 * let the remote peer handle the restart */
+		rmconf = getrmconf(ma->remote, 0);
+		if (rmconf == NULL || !rmconf->passive) {
+			iph1->status = PHASE1ST_EXPIRED;
+			isakmp_ph1delete(iph1);
+
+			/* This is unlikely, but let's just check if a Phase 1
+			 * for the new addresses already exist */
+			if (getph1byaddr(ma->local, ma->remote, 0)) {
+				plog(LLV_WARNING, LOCATION, NULL, "No need "
+				     "to start a new Phase 1 negotiation. One "
+				     "already exists.\n");
+				return 0;
+			}
+
+			plog(LLV_WARNING, LOCATION, NULL, "As initiator, "
+			     "restarting it.\n");
+			 /* Note that the insertion of the new Phase 1 will not
+			  * interfere with the fact we are called from enumph1,
+			  * because it is inserted as first element. --arno */
+			isakmp_ph1begin_i(rmconf, ma->local, ma->remote);
+
+			return 0;
+		}
+	}
+
+	if (iph1->local != NULL) {
+		plog(LLV_DEBUG, LOCATION, NULL, "Migrating Phase 1 local "
+		     "address from %s\n",
+		     saddr2str_fromto("%s to %s", iph1->local, ma->local));
+		port = extract_port(iph1->local);
+		racoon_free(iph1->local);
+	} else
+		port = 0;
+
+	iph1->local = dupsaddr(ma->local);
+	if (iph1->local == NULL) {
+		plog(LLV_ERROR, LOCATION, NULL, "unable to allocate "
+		     "Phase 1 local address.\n");
+		return -1;
+	}
+	set_port(iph1->local, port);
+
+	if (iph1->remote != NULL) {
+		plog(LLV_DEBUG, LOCATION, NULL, "Migrating Phase 1 remote "
+		     "address from %s\n",
+		     saddr2str_fromto("%s to %s", iph1->remote, ma->remote));
+		port = extract_port(iph1->remote);
+		racoon_free(iph1->remote);
+	} else
+		port = 0;
+
+	iph1->remote = dupsaddr(ma->remote);
+	if (iph1->remote == NULL) {
+		plog(LLV_ERROR, LOCATION, NULL, "unable to allocate "
+		     "Phase 1 remote address.\n");
+		return -1;
+	}
+	set_port(iph1->remote, port);
+
+	return 0;
+}
+
+/* Update src and dst of all current Phase 2 handles.
+ * with provided local and remote addresses.
+ * Our intent is NOT to modify IPsec SA endpoints but IKE
+ * addresses so we need to take care to separate those if
+ * they are different. -1 is returned on error. 0 if everything
+ * went right.
+ *
+ * Note: we do not maintain port information as it is not
+ *       expected to be meaningful --arno
+ */
+static int
+migrate_ph2_ike_addresses(iph2, arg)
+	struct ph2handle *iph2;
+	void *arg;
+{
+	struct migrate_args *ma = (struct migrate_args *) arg;
+	struct ph1handle *iph1;
+
+	/* If Phase 2 has an associated Phase 1, migrate addresses */
+	if (iph2->ph1)
+		migrate_ph1_ike_addresses(iph2->ph1, arg);
+
+	/* Already up-to-date? */
+	if (cmpsaddr(iph2->src, ma->local) == CMPSADDR_MATCH &&
+	    cmpsaddr(iph2->dst, ma->remote) == CMPSADDR_MATCH)
+		return 0;
+
+	/* save src/dst as sa_src/sa_dst before rewriting */
+	if (iph2->sa_src == NULL && iph2->sa_dst == NULL) {
+		iph2->sa_src = iph2->src;
+		iph2->sa_dst = iph2->dst;
+		iph2->src = NULL;
+		iph2->dst = NULL;
+	}
+
+	if (iph2->src != NULL)
+		racoon_free(iph2->src);
+	iph2->src = dupsaddr(ma->local);
+	if (iph2->src == NULL) {
+		plog(LLV_ERROR, LOCATION, NULL,
+		     "unable to allocate Phase 2 src address.\n");
+		return -1;
+	}
+
+	if (iph2->dst != NULL)
+		racoon_free(iph2->dst);
+	iph2->dst = dupsaddr(ma->remote);
+	if (iph2->dst == NULL) {
+		plog(LLV_ERROR, LOCATION, NULL,
+		     "unable to allocate Phase 2 dst address.\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+/* Consider existing Phase 2 handles with given spid and update their source
+ * and destination addresses for SA. As racoon does not support bundles, if
+ * we modify multiple occurrences, this probably imply rekeying has happened.
+ *
+ * Both addresses passed to the function are expected not to be NULL and of
+ * same family. -1 is returned on error. 0 if everything went right.
+ *
+ * Specific care is needed to support Phase 2 for which negotiation has
+ * already started but are which not yet established.
+ */
+static int
+migrate_ph2_sa_addresses(iph2, args)
+	struct ph2handle *iph2;
+	void *args;
+{
+	struct migrate_args *ma = (struct migrate_args *) args;
+
+	if (iph2->sa_src != NULL) {
+		racoon_free(iph2->sa_src);
+		iph2->sa_src = NULL;
+	}
+
+	if (iph2->sa_dst != NULL) {
+		racoon_free(iph2->sa_dst);
+		iph2->sa_dst = NULL;
+	}
+
+	iph2->sa_src = dupsaddr(ma->local);
+	if (iph2->sa_src == NULL) {
+		plog(LLV_ERROR, LOCATION, NULL,
+		     "unable to allocate Phase 2 sa_src address.\n");
+		return -1;
+	}
+
+	iph2->sa_dst = dupsaddr(ma->remote);
+	if (iph2->sa_dst == NULL) {
+		plog(LLV_ERROR, LOCATION, NULL,
+		     "unable to allocate Phase 2 sa_dst address.\n");
+		return -1;
+	}
+
+	if (iph2->status < PHASE2ST_ESTABLISHED) {
+		struct remoteconf *rmconf;
+		/* We were negotiating for that SA when we received the MIGRATE.
+		 * We cannot simply update the addresses and let the exchange
+		 * go on. We have to restart the whole negotiation if we are
+		 * the initiator. Otherwise (acting as responder), we just need
+		 * to delete our ph2handle and wait for the initiator to start
+		 * a new negotiation. */
+
+		if (iph2->ph1 && iph2->ph1->rmconf)
+			rmconf = iph2->ph1->rmconf;
+		else
+			rmconf = getrmconf(iph2->dst, 0);
+
+		if (rmconf && !rmconf->passive) {
+			struct ph1handle *iph1hint;
+
+			plog(LLV_WARNING, LOCATION, iph2->dst, "MIGRATE received "
+			     "*during* IPsec SA negotiation. As initiator, "
+			     "restarting it.\n");
+
+			/* Turn off expiration timer ...*/
+			sched_cancel(&iph2->sce);
+			iph2->status = PHASE2ST_EXPIRED;
+
+			/* ... clean Phase 2 handle ... */
+			iph1hint = iph2->ph1;
+			initph2(iph2);
+			iph2->status = PHASE2ST_STATUS2;
+
+			/* and start a new negotiation */
+			if (isakmp_post_acquire(iph2, iph1hint, FALSE) < 0) {
+				plog(LLV_ERROR, LOCATION, iph2->dst, "failed "
+				     "to begin IPsec SA renegotiation after "
+				     "MIGRATE reception.\n");
+				remph2(iph2);
+				delph2(iph2);
+				return -1;
+			}
+		} else {
+			plog(LLV_WARNING, LOCATION, iph2->dst, "MIGRATE received "
+			     "*during* IPsec SA negotiation. As responder, let's"
+			     "wait for the initiator to act.\n");
+
+			/* Simply schedule deletion */
+			isakmp_ph2expire(iph2);
+		}
+	}
+
+	return 0;
+}
+
+/* Update SP hints (local and remote addresses) for future IKE
+ * negotiations of SA associated with that SP. -1 is returned
+ * on error. 0 if everything went right.
+ *
+ * Note: we do not maintain port information as it is not
+ *       expected to be meaningful --arno
+ */
+static int
+migrate_sp_ike_addresses(sp, local, remote)
+        struct secpolicy *sp;
+        struct sockaddr *local, *remote;
+{
+	if (sp == NULL || local == NULL || remote == NULL)
+		return -1;
+
+	if (sp->local != NULL)
+		racoon_free(sp->local);
+
+	sp->local = dupsaddr(local);
+	if (sp->local == NULL) {
+		plog(LLV_ERROR, LOCATION, NULL, "unable to allocate "
+		     "local hint for SP.\n");
+		return -1;
+	}
+
+	if (sp->remote != NULL)
+		racoon_free(sp->remote);
+
+	sp->remote = dupsaddr(remote);
+	if (sp->remote == NULL) {
+		plog(LLV_ERROR, LOCATION, NULL, "unable to allocate "
+		     "remote hint for SP.\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+/* Given current ipsecrequest (isr_cur) to be migrated in considered
+   tree, the function first checks that it matches the expected one
+   (xisr_old) provided in MIGRATE message and then updates the addresses
+   if it is tunnel mode (with content of xisr_new). Various other checks
+   are performed. For transport mode, structures are not modified, only
+   the checks are done. -1 is returned on error. */
+static int
+migrate_ph2_one_isr(spid, isr_cur, xisr_old, xisr_new)
+        u_int32_t spid;
+        struct ipsecrequest *isr_cur;
+	struct sadb_x_ipsecrequest *xisr_old, *xisr_new;
+{
+	struct secasindex *saidx = &isr_cur->saidx;
+	struct sockaddr *osaddr, *odaddr, *nsaddr, *ndaddr;
+	struct ph2selector ph2sel;
+	struct migrate_args ma;
+
+	/* First, check that mode and proto do match */
+	if (xisr_old->sadb_x_ipsecrequest_proto != saidx->proto ||
+	    xisr_old->sadb_x_ipsecrequest_mode != saidx->mode ||
+	    xisr_new->sadb_x_ipsecrequest_proto != saidx->proto ||
+	    xisr_new->sadb_x_ipsecrequest_mode != saidx->mode)
+		return -1;
+
+	/* Then, verify reqid if necessary */
+	if (isr_cur->saidx.reqid &&
+	    (xisr_old->sadb_x_ipsecrequest_reqid != IPSEC_LEVEL_UNIQUE ||
+	     xisr_new->sadb_x_ipsecrequest_reqid != IPSEC_LEVEL_UNIQUE ||
+	     isr_cur->saidx.reqid != xisr_old->sadb_x_ipsecrequest_reqid ||
+	     isr_cur->saidx.reqid != xisr_new->sadb_x_ipsecrequest_reqid))
+		return -1;
+
+	/* If not tunnel mode, our work is over */
+	if (saidx->mode != IPSEC_MODE_TUNNEL) {
+		plog(LLV_DEBUG, LOCATION, NULL, "SADB_X_MIGRATE: "
+		     "non tunnel mode isr, skipping SA address migration.\n");
+		return 0;
+	}
+
+	/* Tunnel mode: let's check addresses do match and then update them. */
+	osaddr = (struct sockaddr *)(xisr_old + 1);
+	odaddr = (struct sockaddr *)(((u_int8_t *)osaddr) + sysdep_sa_len(osaddr));
+	nsaddr = (struct sockaddr *)(xisr_new + 1);
+	ndaddr = (struct sockaddr *)(((u_int8_t *)nsaddr) + sysdep_sa_len(nsaddr));
+
+	/* Check family does match */
+	if (osaddr->sa_family != odaddr->sa_family ||
+	    nsaddr->sa_family != ndaddr->sa_family)
+		return -1;
+
+	/* Check family does match */
+	if (saidx->src.ss_family != osaddr->sa_family)
+		return -1;
+
+	/* We log IPv4 to IPv6 and IPv6 to IPv4 switches */
+	if (nsaddr->sa_family != osaddr->sa_family)
+		plog(LLV_INFO, LOCATION, NULL, "SADB_X_MIGRATE: "
+		     "changing address families (%d to %d) for endpoints.\n",
+		     osaddr->sa_family, nsaddr->sa_family);
+
+	if (cmpsaddr(osaddr, (struct sockaddr *) &saidx->src) != CMPSADDR_MATCH ||
+	    cmpsaddr(odaddr, (struct sockaddr *) &saidx->dst) != CMPSADDR_MATCH) {
+		plog(LLV_DEBUG, LOCATION, NULL, "SADB_X_MIGRATE: "
+		     "mismatch of addresses in saidx and xisr.\n");
+		return -1;
+	}
+
+	/* Excellent. Let's grab associated Phase 2 handle (if any)
+	 * and update its sa_src and sa_dst entries.  Note that we
+	 * make the assumption that racoon does not support bundles
+	 * and make the lookup using spid: we blindly update
+	 * sa_src and sa_dst for _all_ found Phase 2 handles */
+	memset(&ph2sel, 0, sizeof(ph2sel));
+	ph2sel.spid = spid;
+
+	memset(&ma, 0, sizeof(ma));
+	ma.local = nsaddr;
+	ma.remote = ndaddr;
+
+	if (enumph2(&ph2sel, migrate_ph2_sa_addresses, &ma) < 0)
+		return -1;
+
+	/* Now we can do the update of endpoints in secasindex */
+	memcpy(&saidx->src, nsaddr, sysdep_sa_len(nsaddr));
+	memcpy(&saidx->dst, ndaddr, sysdep_sa_len(ndaddr));
+
+	return 0;
+}
+
+/* Process the raw (unparsed yet) list of sadb_x_ipsecrequests of MIGRATE
+ * message. For each sadb_x_ipsecrequest pair (old followed by new),
+ * the corresponding ipsecrequest entry in the SP is updated. Associated
+ * existing Phase 2 handle is also updated (if any) */
+static int
+migrate_sp_isr_list(sp, xisr_list, xisr_list_len)
+        struct secpolicy *sp;
+	struct sadb_x_ipsecrequest *xisr_list;
+	int xisr_list_len;
+{
+	struct sadb_x_ipsecrequest *xisr_new, *xisr_old = xisr_list;
+	int xisr_old_len, xisr_new_len;
+	struct ipsecrequest *isr_cur;
+
+	isr_cur = sp->req; /* ipsecrequest list from from sp */
+
+	while (xisr_list_len > 0 && isr_cur != NULL) {
+		/* Get old xisr (length field is in bytes) */
+		xisr_old_len = xisr_old->sadb_x_ipsecrequest_len;
+		if (xisr_old_len < sizeof(*xisr_old) ||
+		    xisr_old_len + sizeof(*xisr_new) > xisr_list_len) {
+			plog(LLV_ERROR, LOCATION, NULL, "SADB_X_MIGRATE: "
+			     "invalid ipsecrequest length. Exiting.\n");
+			return -1;
+		}
+
+		/* Get new xisr with updated info */
+		xisr_new = (struct sadb_x_ipsecrequest *)(((u_int8_t *)xisr_old) + xisr_old_len);
+		xisr_new_len = xisr_new->sadb_x_ipsecrequest_len;
+		if (xisr_new_len < sizeof(*xisr_new) ||
+		    xisr_new_len + xisr_old_len > xisr_list_len) {
+			plog(LLV_ERROR, LOCATION, NULL, "SADB_X_MIGRATE: "
+			     "invalid ipsecrequest length. Exiting.\n");
+			return -1;
+		}
+
+		/* Start by migrating current ipsecrequest from SP */
+		if (migrate_ph2_one_isr(sp->id, isr_cur, xisr_old, xisr_new) == -1) {
+			plog(LLV_ERROR, LOCATION, NULL, "SADB_X_MIGRATE: "
+			     "Unable to match and migrate isr. Exiting.\n");
+			return -1;
+		}
+
+		/* Update pointers for next round */
+		xisr_list_len -= xisr_old_len + xisr_new_len;
+		xisr_old = (struct sadb_x_ipsecrequest *)(((u_int8_t *)xisr_new) +
+							  xisr_new_len);
+
+		isr_cur = isr_cur->next; /* Get next ipsecrequest from SP */
+	}
+
+	/* Check we had the same amount of pairs in the MIGRATE
+	   as the number of ipsecrequests in the SP */
+	if ((xisr_list_len != 0) || isr_cur != NULL) {
+		plog(LLV_ERROR, LOCATION, NULL, "SADB_X_MIGRATE: "
+		     "number of ipsecrequest does not match the one in SP.\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+/* Parse sadb_x_kmaddress extension and make local and remote
+ * parameters point to the new addresses (zero copy). -1 is
+ * returned on error, meaning that addresses are not usable */
+static int
+parse_kmaddress(kmaddr, local, remote)
+        struct sadb_x_kmaddress *kmaddr;
+	struct sockaddr **local, **remote;
+{
+	int addrslen, local_len=0;
+	struct ph1handle *iph1;
+
+	if (kmaddr == NULL)
+		return -1;
+
+	/* Grab addresses in sadb_x_kmaddress extension */
+	addrslen = PFKEY_EXTLEN(kmaddr) - sizeof(*kmaddr);
+	if (addrslen < sizeof(struct sockaddr))
+		return -1;
+
+	*local = (struct sockaddr *)(kmaddr + 1);
+
+	switch ((*local)->sa_family) {
+	case AF_INET:
+		local_len = sizeof(struct sockaddr_in);
+		break;
+#ifdef INET6
+	case AF_INET6:
+		local_len = sizeof(struct sockaddr_in6);
+		break;
+#endif
+	default:
+		return -1;
+	}
+
+	if (addrslen != PFKEY_ALIGN8(2*local_len))
+		return -1;
+
+	*remote = (struct sockaddr *)(((u_int8_t *)(*local)) + local_len);
+
+	if ((*local)->sa_family != (*remote)->sa_family)
+		return -1;
+
+	return 0;
+}
+
+/* Handler of PF_KEY MIGRATE message. Helpers are above */
+static int
+pk_recvmigrate(mhp)
+	caddr_t *mhp;
+{
+	struct sadb_address *saddr, *daddr;
+	struct sockaddr *old_saddr, *new_saddr;
+	struct sockaddr *old_daddr, *new_daddr;
+	struct sockaddr *old_local, *old_remote;
+	struct sockaddr *local, *remote;
+	struct sadb_x_kmaddress *kmaddr;
+	struct sadb_x_policy *xpl;
+	struct sadb_x_ipsecrequest *xisr_list;
+	struct sadb_lifetime *lt;
+	struct policyindex spidx;
+	struct secpolicy *sp;
+	struct ipsecrequest *isr_cur;
+	struct secasindex *oldsaidx;
+	struct ph2handle *iph2;
+	struct ph1handle *iph1;
+	struct ph2selector ph2sel;
+	struct ph1selector ph1sel;
+	u_int32_t spid;
+	u_int64_t created;
+	int xisr_list_len;
+	int ulproto;
+	struct migrate_args ma;
+
+	/* Some sanity checks */
+
+	if (mhp[0] == NULL
+	 || mhp[SADB_EXT_ADDRESS_SRC] == NULL
+	 || mhp[SADB_EXT_ADDRESS_DST] == NULL
+	 || mhp[SADB_X_EXT_KMADDRESS] == NULL
+	 || mhp[SADB_X_EXT_POLICY] == NULL) {
+		plog(LLV_ERROR, LOCATION, NULL,
+			"SADB_X_MIGRATE: invalid MIGRATE message received.\n");
+		return -1;
+	}
+	kmaddr = (struct sadb_x_kmaddress *)mhp[SADB_X_EXT_KMADDRESS];
+	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;
+
+	if (xpl->sadb_x_policy_type != IPSEC_POLICY_IPSEC) {
+		plog(LLV_WARNING, LOCATION, NULL,"SADB_X_MIGRATE: "
+		     "found non IPsec policy in MIGRATE message. Exiting.\n");
+		return -1;
+	}
+
+	if (PFKEY_EXTLEN(xpl) < sizeof(*xpl)) {
+		plog(LLV_ERROR, LOCATION, NULL, "SADB_X_MIGRATE: "
+		     "invalid size for sadb_x_policy. Exiting.\n");
+		return -1;
+	}
+
+	/* Some logging to help debbugging */
+	if (xpl->sadb_x_policy_dir == IPSEC_DIR_OUTBOUND)
+		plog(LLV_DEBUG, LOCATION, NULL,
+		     "SADB_X_MIGRATE: Outbound SA being migrated.\n");
+	else
+		plog(LLV_DEBUG, LOCATION, NULL,
+		     "SADB_X_MIGRATE: Inbound SA being migrated.\n");
+
+	/* validity check */
+	xisr_list = (struct sadb_x_ipsecrequest *)(xpl + 1);
+	xisr_list_len = PFKEY_EXTLEN(xpl) - sizeof(*xpl);
+	if (xisr_list_len < sizeof(*xisr_list)) {
+		plog(LLV_ERROR, LOCATION, NULL, "SADB_X_MIGRATE: "
+		     "invalid sadb_x_policy message length. Exiting.\n");
+		return -1;
+	}
+
+	if (parse_kmaddress(kmaddr, &local, &remote) == -1) {
+		plog(LLV_ERROR, LOCATION, NULL, "SADB_X_MIGRATE: "
+		     "invalid sadb_x_kmaddress extension. Exiting.\n");
+		return -1;
+	}
+
+	/* 0 means ANY */
+	if (saddr->sadb_address_proto == 0)
+		ulproto = IPSEC_ULPROTO_ANY;
+	else
+		ulproto = saddr->sadb_address_proto;
+
+#ifdef HAVE_PFKEY_POLICY_PRIORITY
+	KEY_SETSECSPIDX(xpl->sadb_x_policy_dir,
+			saddr + 1,
+			daddr + 1,
+			saddr->sadb_address_prefixlen,
+			daddr->sadb_address_prefixlen,
+			ulproto,
+			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,
+			ulproto,
+			created,
+			&spidx);
+#endif
+
+	/* Everything seems ok, let's get the SP.
+	 *
+	 * XXX We could also do the lookup using the spid from xpl.
+	 *     I don't know which one is better.  --arno */
+	sp = getsp(&spidx);
+	if (sp == NULL) {
+		plog(LLV_ERROR, LOCATION, NULL,
+			"SADB_X_MIGRATE: Passed policy does not exist: %s\n",
+			spidx2str(&spidx));
+		return -1;
+	}
+
+	/* Get the best source and destination addresses used for IKE
+	 * negotiation, to find and migrate existing Phase 1 */
+	if (sp->local && sp->remote) {
+		/* hints available, let's use them */
+		old_local  = (struct sockaddr *)sp->local;
+		old_remote = (struct sockaddr *)sp->remote;
+	} else if (sp->req && sp->req->saidx.mode == IPSEC_MODE_TUNNEL) {
+		/* Tunnel mode and no hint, use endpoints */
+		old_local  = (struct sockaddr *)&sp->req->saidx.src;
+		old_remote = (struct sockaddr *)&sp->req->saidx.dst;
+	} else {
+		/* default, use selectors as fallback */
+		old_local  = (struct sockaddr *)&sp->spidx.src;
+		old_remote = (struct sockaddr *)&sp->spidx.dst;
+	}
+
+	/* We migrate all Phase 1 that match our old local and remote
+	 * addresses (no matter their state).
+	 *
+	 * XXX In fact, we should probably havea special treatment for
+	 * Phase 1 that are being established when we receive a MIGRATE.
+	 * This can happen if a movement occurs during the initial IKE
+	 * negotiation. In that case, I wonder if should restart the
+	 * negotiation from the new address or just update things like
+	 * we do it now.
+	 *
+	 * XXX while looking at getph1byaddr(), the comment at the
+	 * beginning of the function expects comparison to happen
+	 * without ports considerations but it uses CMPSADDR() which
+	 * relies either on cmpsaddrstrict() or cmpsaddrwop() based
+	 * on NAT-T support being activated. That make me wonder if I
+	 * should force ports to 0 (ANY) in local and remote values
+	 * used below.
+	 *
+	 * -- arno */
+
+	/* Apply callback data ...*/
+	memset(&ma, 0, sizeof(ma));
+	ma.local = local;
+	ma.remote = remote;
+
+	/* Fill phase1 match criteria ... */
+	memset(&ph1sel, 0, sizeof(ph1sel));
+	ph1sel.local = old_local;
+	ph1sel.remote = old_remote;
+
+
+	/* Have matching Phase 1 found and addresses updated. As this is a
+	 * time consuming task on a busy responder, and MIGRATE messages
+	 * are always sent for *both* inbound and outbound (and possibly
+	 * forward), we only do that for outbound SP. */
+	if (xpl->sadb_x_policy_dir == IPSEC_DIR_OUTBOUND &&
+	    enumph1(&ph1sel, migrate_ph1_ike_addresses, &ma) < 0) {
+		plog(LLV_ERROR, LOCATION, NULL, "SADB_X_MIGRATE: Unable "
+		     "to migrate Phase 1 addresses.\n");
+		return -1;
+	}
+
+	/* We can now update IKE addresses in Phase 2 handle. */
+	memset(&ph2sel, 0, sizeof(ph2sel));
+	ph2sel.spid = sp->id;
+	if (enumph2(&ph2sel, migrate_ph2_ike_addresses, &ma) < 0) {
+		plog(LLV_ERROR, LOCATION, NULL, "SADB_X_MIGRATE: Unable "
+		     "to migrate Phase 2 IKE addresses.\n");
+		return -1;
+	}
+
+	/* and _then_ in SP. */
+	if (migrate_sp_ike_addresses(sp, local, remote) < 0) {
+		plog(LLV_ERROR, LOCATION, NULL,
+		     "SADB_X_MIGRATE: Unable to migrate SP IKE addresses.\n");
+		return -1;
+	}
+
+	/* Loop on sadb_x_ipsecrequest list to possibly update sp->req
+	 * entries and associated live Phase 2 handles (their sa_src
+	 * and sa_dst) */
+	if (migrate_sp_isr_list(sp, xisr_list, xisr_list_len) < 0) {
+		plog(LLV_ERROR, LOCATION, NULL,
+		     "SADB_X_MIGRATE: Unable to migrate isr list.\n");
+		return -1;
+	}
+
+	return 0;
+}
+#endif
+
 #ifndef ANDROID_PATCHED
 
 /*
- * send error against acquire message to kenrel.
+ * send error against acquire message to kernel.
  */
 int
 pk_sendeacquire(iph2)
@@ -2759,8 +3600,8 @@
 #else
 
 int pk_sendeacquire(struct ph2handle *iph2)
-{
-	exit(1);
+{       
+        exit(1);
 }
 
 #endif
@@ -2787,8 +3628,8 @@
 		break;
 	case IPSECDOI_PROTO_IPCOMP:
 		plog(LLV_DEBUG, LOCATION, NULL,
-			"compression algorithm can not be checked "
-			"because sadb message doesn't support it.\n");
+			"no check of compression algorithm; "
+			"not supported in sadb message.\n");
 		return 0;
 	default:
 		plog(LLV_ERROR, LOCATION, NULL,
@@ -2848,6 +3689,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;
 
@@ -2880,8 +3726,9 @@
 }
 
 static int
-addnewsp(mhp)
+addnewsp(mhp, local, remote)
 	caddr_t *mhp;
+	struct sockaddr *local, *remote;
 {
 	struct secpolicy *new = NULL;
 	struct sadb_address *saddr, *daddr;
@@ -3090,6 +3937,12 @@
 	}
 #endif /* HAVE_SECCTX */
 
+	/* Set local and remote hints for that SP, if available */
+	if (local && remote) {
+		new->local = dupsaddr(local);
+		new->remote = dupsaddr(remote);
+	}
+
 	inssp(new);
 
 	return 0;
diff --git a/src/racoon/pfkey.h b/src/racoon/pfkey.h
index 547f94a..cfe111d 100644
--- a/src/racoon/pfkey.h
+++ b/src/racoon/pfkey.h
@@ -1,4 +1,4 @@
-/*	$NetBSD: pfkey.h,v 1.4 2006/09/09 16:22:10 manu Exp $	*/
+/*	$NetBSD: pfkey.h,v 1.8 2009/07/03 06:40:10 tteras Exp $	*/
 
 /* Id: pfkey.h,v 1.3 2004/06/11 16:00:17 ludvigm Exp */
 
@@ -42,16 +42,17 @@
 extern const struct pfkey_satype pfkey_satypes[];
 extern const int pfkey_nsatypes;
 
-extern int pfkey_handler __P((void));
 extern vchar_t *pfkey_dump_sadb __P((int));
 extern void pfkey_flush_sadb __P((u_int));
 extern int pfkey_init __P((void));
+extern int pfkey_reload __P((void));
 
 extern struct pfkey_st *pfkey_getpst __P((caddr_t *, int, int));
 
 extern int pk_checkalg __P((int, int, int));
 
 struct ph2handle;
+extern void pk_fixup_sa_addresses __P((caddr_t *mhp));
 extern int pk_sendgetspi __P((struct ph2handle *));
 extern int pk_sendupdate __P((struct ph2handle *));
 extern int pk_sendadd __P((struct ph2handle *));
@@ -60,9 +61,6 @@
 extern int pk_sendspdadd2 __P((struct ph2handle *));
 extern int pk_sendspddelete __P((struct ph2handle *));
 
-extern void pfkey_timeover_stub __P((void *));
-extern void pfkey_timeover __P((struct ph2handle *));
-
 extern u_int pfkey2ipsecdoi_proto __P((u_int));
 extern u_int ipsecdoi2pfkey_proto __P((u_int));
 extern u_int pfkey2ipsecdoi_mode __P((u_int));
diff --git a/src/racoon/plainrsa-gen.c b/src/racoon/plainrsa-gen.c
index 1bd5f67..cad1861 100644
--- a/src/racoon/plainrsa-gen.c
+++ b/src/racoon/plainrsa-gen.c
@@ -1,4 +1,4 @@
-/*	$NetBSD: plainrsa-gen.c,v 1.4 2006/09/09 16:22:10 manu Exp $	*/
+/*	$NetBSD: plainrsa-gen.c,v 1.6 2011/02/11 10:07:19 tteras Exp $	*/
 
 /* Id: plainrsa-gen.c,v 1.6 2005/04/21 09:08:40 monas Exp */
 /*
@@ -43,11 +43,13 @@
 #include <sys/stat.h>
 #include <sys/socket.h>
 #include <unistd.h>
+#include <fcntl.h>
 
 #include <openssl/bio.h>
 #include <openssl/bn.h>
 #include <openssl/err.h>
 #include <openssl/objects.h>
+#include <openssl/pem.h>
 #include <openssl/rsa.h>
 #include <openssl/evp.h>
 #ifdef HAVE_OPENSSL_ENGINE_H
@@ -72,6 +74,7 @@
 	fprintf(stderr, "  -b bits       Generate <bits> long RSA key (default=1024)\n");
 	fprintf(stderr, "  -e pubexp     Public exponent to use (default=0x3)\n");
 	fprintf(stderr, "  -f filename   Filename to store the key to (default=stdout)\n");
+	fprintf(stderr, "  -i filename   Input source for format conversion\n");
 	fprintf(stderr, "  -h            Help\n");
 	fprintf(stderr, "\n");
 	fprintf(stderr, "Report bugs to <ipsec-tools-devel@lists.sourceforge.net>\n");
@@ -82,7 +85,7 @@
  * See RFC 2065, section 3.5 for details about the output format.
  */
 vchar_t *
-mix_b64_pubkey(RSA *key)
+mix_b64_pubkey(const RSA *key)
 {
 	char *binbuf;
 	long binlen, ret;
@@ -116,17 +119,10 @@
 }
 
 int
-gen_rsa_key(FILE *fp, size_t bits, unsigned long exp)
+print_rsa_key(FILE *fp, const RSA *key)
 {
-	RSA *key;
 	vchar_t *pubkey64 = NULL;
 
-	key = RSA_generate_key(bits, exp, NULL, NULL);
-	if (!key) {
-		fprintf(stderr, "RSA_generate_key(): %s\n", eay_strerror());
-		return -1;
-	}
-	
 	pubkey64 = mix_b64_pubkey(key);
 	if (!pubkey64) {
 		fprintf(stderr, "mix_b64_pubkey(): %s\n", eay_strerror());
@@ -135,7 +131,7 @@
 	
 	fprintf(fp, "# : PUB 0s%s\n", pubkey64->v);
 	fprintf(fp, ": RSA\t{\n");
-	fprintf(fp, "\t# RSA %zu bits\n", bits);
+	fprintf(fp, "\t# RSA %d bits\n", BN_num_bits(key->n));
 	fprintf(fp, "\t# pubkey=0s%s\n", pubkey64->v);
 	fprintf(fp, "\tModulus: 0x%s\n", lowercase(BN_bn2hex(key->n)));
 	fprintf(fp, "\tPublicExponent: 0x%s\n", lowercase(BN_bn2hex(key->e)));
@@ -148,23 +144,92 @@
 	fprintf(fp, "  }\n");
 
 	vfree(pubkey64);
-
 	return 0;
 }
 
 int
+print_public_rsa_key(FILE *fp, const RSA *key)
+{
+	vchar_t *pubkey64 = NULL;
+
+	pubkey64 = mix_b64_pubkey(key);
+	if (!pubkey64) {
+		fprintf(stderr, "mix_b64_pubkey(): %s\n", eay_strerror());
+		return -1;
+	}
+	
+	fprintf(fp, ": PUB 0s%s\n", pubkey64->v);
+
+	vfree(pubkey64);
+	return 0;
+}
+
+int
+convert_rsa_key(FILE *fpout, FILE *fpin)
+{
+	int ret;
+	RSA *key = NULL;
+
+	key = PEM_read_RSAPrivateKey(fpin, NULL, NULL, NULL);
+	if (key) {
+		ret = print_rsa_key(fpout, key);
+		RSA_free(key);
+
+		return ret;
+	}
+	
+	rewind(fpin);
+
+	key = PEM_read_RSA_PUBKEY(fpin, NULL, NULL, NULL);
+	if (key) {
+		ret = print_public_rsa_key(fpout, key);
+		RSA_free(key);
+
+		return ret;
+	}
+
+	/* Implement parsing of input stream containing
+	 * private or public "plainrsa" formatted text.
+	 * Convert the result to PEM formatted output.
+	 *
+	 * This seemingly needs manual use of prsaparse().
+	 * An expert ought to do this. */
+
+	fprintf(stderr, "convert_rsa_key: %s\n", "Only conversion from PEM at this time");
+	return -1;
+}
+
+int
+gen_rsa_key(FILE *fp, size_t bits, unsigned long exp)
+{
+	int ret;
+	RSA *key;
+
+	key = RSA_generate_key(bits, exp, NULL, NULL);
+	if (!key) {
+		fprintf(stderr, "RSA_generate_key(): %s\n", eay_strerror());
+		return -1;
+	}
+	
+	ret = print_rsa_key(fp, key);
+	RSA_free(key);
+
+	return ret;
+}
+
+int
 main (int argc, char *argv[])
 {
-	FILE *fp = stdout;
+	FILE *fp = stdout, *fpin = NULL;
 	size_t bits = 1024;
 	unsigned int pubexp = 0x3;
 	struct stat st;
 	extern char *optarg;
 	extern int optind;
-	int c;
-	char *fname = NULL;
+	int c, fd = -1, fdin = -1;
+	char *fname = NULL, *finput = NULL;
 
-	while ((c = getopt(argc, argv, "e:b:f:h")) != -1)
+	while ((c = getopt(argc, argv, "e:b:f:i:h")) != -1)
 		switch (c) {
 			case 'e':
 				if (strncmp(optarg, "0x", 2) == 0)
@@ -178,31 +243,65 @@
 			case 'f':
 				fname = optarg;
 				break;
+			case 'i':
+				finput = optarg;
+				break;
 			case 'h':
 			default:
 				usage(argv[0]);
 		}
 
 	if (fname) {
-		if (stat(fname, &st) >= 0) {
-			fprintf(stderr, "%s: file exists! Please use a different name.\n", fname);
+		umask(0077);
+		/* Restrictive access due to private key material. */
+		fd = open(fname, O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW, S_IRUSR | S_IWUSR);
+		if (fd < 0) {
+			if (errno == EEXIST)
+				fprintf(stderr, "%s: file exists! Please use a different name.\n", fname);
+			else
+				fprintf(stderr, "%s: %s\n", fname, strerror(errno));
+			exit(1);
+		}
+		fp = fdopen(fd, "w");
+		if (fp == NULL) {
+			fprintf(stderr, "%s: %s\n", fname, strerror(errno));
+			close(fd);
+			exit(1);
+		}
+	}
+
+	if (finput) {
+		/* Restrictive access once more. Do not be fooled by a link. */
+		fdin = open(finput, O_RDONLY | O_NOFOLLOW);
+		if (fdin < 0) {
+			if (errno == ELOOP)
+				fprintf(stderr, "%s: file is a link. Discarded for security.\n", fname);
+			if (fp)
+				fclose(fp);
+			exit(1);
+		}
+		fpin = fdopen(fdin, "r");
+		if (fpin == NULL) {
+			fprintf(stderr, "%s: %s\n", fname, strerror(errno));
+			close(fdin);
+			if (fp)
+				fclose(fp);
 			exit(1);
 		}
 
-		umask(0077);
-		fp = fopen(fname, "w");
-		if (fp == NULL) {
-			fprintf(stderr, "%s: %s\n", fname, strerror(errno));
-			exit(1);
-		}
 	}
 
 	ploginit();
 	eay_init();
 
-	gen_rsa_key(fp, bits, pubexp);
+	if (fpin)
+		convert_rsa_key(fp, fpin);
+	else
+		gen_rsa_key(fp, bits, pubexp);
 
 	fclose(fp);
+	if (fpin)
+		fclose(fpin);
 
 	return 0;
 }
diff --git a/src/racoon/plog.c b/src/racoon/plog.c
index 008260d..aebfed2 100644
--- a/src/racoon/plog.c
+++ b/src/racoon/plog.c
@@ -1,4 +1,4 @@
-/*	$NetBSD: plog.c,v 1.4.6.2 2009/04/20 13:35:36 tteras Exp $	*/
+/*	$NetBSD: plog.c,v 1.7 2011/01/28 12:51:40 tteras Exp $	*/
 
 /* Id: plog.c,v 1.11 2006/06/20 09:57:31 vanhu Exp */
 
@@ -36,6 +36,7 @@
 #include <sys/types.h>
 #include <sys/param.h>
 
+#include <arpa/inet.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
@@ -78,7 +79,7 @@
 static struct log *logp = NULL;
 static char *logfile = NULL;
 
-static char *plog_common __P((int, const char *, const char *));
+static char *plog_common __P((int, const char *, const char *, struct sockaddr *));
 
 static struct plogtags {
 	char *name;
@@ -94,11 +95,13 @@
 };
 
 static char *
-plog_common(pri, fmt, func)
+plog_common(pri, fmt, func, sa)
 	int pri;
 	const char *fmt, *func;
+	struct sockaddr *sa;
 {
 	static char buf[800];	/* XXX shoule be allocated every time ? */
+	void *addr;
 	char *p;
 	int reslen, len;
 
@@ -116,19 +119,43 @@
 		reslen -= len;
 	}
 
+	if (sa && reslen > 3) {
+		addr = NULL;
+		switch (sa->sa_family) {
+		case AF_INET:
+			addr = &((struct sockaddr_in*)sa)->sin_addr;
+			break;
+		case AF_INET6:
+			addr = &((struct sockaddr_in6*)sa)->sin6_addr;
+			break;
+		}
+		if (inet_ntop(sa->sa_family, addr, p + 1, reslen - 3) != NULL) {
+			*p++ = '[';
+			len = strlen(p);
+			p += len;
+			*p++ = ']';
+			*p++ = ' ';
+			reslen -= len + 3;
+		}
+	}
+
 	if (pri < ARRAYLEN(ptab)) {
 		len = snprintf(p, reslen, "%s: ", ptab[pri].name);
-		if (len >= 0 && len < reslen) {
-			p += len;
-			reslen -= len;
-		} else
-			*p = '\0';
+		p += len;
+		reslen -= len;
 	}
 
 	if (print_location)
-		snprintf(p, reslen, "%s: %s", func, fmt);
+		len = snprintf(p, reslen, "%s: %s", func, fmt);
 	else
-		snprintf(p, reslen, "%s", fmt);
+		len = snprintf(p, reslen, "%s", fmt);
+	p += len;
+	reslen -= len;
+
+	/* Force nul termination */
+	if (reslen == 0)
+		p[-1] = 0;
+
 #ifdef BROKEN_PRINTF
 	while ((p = strstr(buf,"%z")) != NULL)
 		p[1] = 'l';
@@ -157,7 +184,7 @@
 	if (pri > loglevel)
 		return;
 
-	newfmt = plog_common(pri, fmt, func);
+	newfmt = plog_common(pri, fmt, func, sa);
 
 	VA_COPY(ap_bak, ap);
 	
diff --git a/src/racoon/plog.h b/src/racoon/plog.h
index 4d9a93f..6c3ac12 100644
--- a/src/racoon/plog.h
+++ b/src/racoon/plog.h
@@ -1,4 +1,4 @@
-/*	$NetBSD: plog.h,v 1.4.6.1 2007/11/06 16:41:27 vanhu Exp $	*/
+/*	$NetBSD: plog.h,v 1.5 2007/10/02 09:47:40 vanhu Exp $	*/
 
 /* Id: plog.h,v 1.7 2006/06/20 09:57:31 vanhu Exp */
 
diff --git a/src/racoon/policy.c b/src/racoon/policy.c
index 29a6818..4c00677 100644
--- a/src/racoon/policy.c
+++ b/src/racoon/policy.c
@@ -1,4 +1,4 @@
-/*	$NetBSD: policy.c,v 1.6.4.1 2007/08/01 11:52:21 vanhu Exp $	*/
+/*	$NetBSD: policy.c,v 1.12 2011/03/14 17:18:13 tteras Exp $	*/
 
 /*	$KAME: policy.c,v 1.46 2001/11/16 04:08:10 sakane Exp $	*/
 
@@ -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 *
@@ -137,16 +141,18 @@
 		saddr2str(iph2->src));
 	plog(LLV_DEBUG, LOCATION, NULL, "src2: %s\n",
 		saddr2str((struct sockaddr *)&spidx->src));
-	if (cmpsaddrwop(iph2->src, (struct sockaddr *)&spidx->src)
-	 || spidx->prefs != prefixlen)
+
+	if (cmpsaddr(iph2->src, (struct sockaddr *) &spidx->src) != CMPSADDR_MATCH ||
+	    spidx->prefs != prefixlen)
 		return NULL;
 
 	plog(LLV_DEBUG, LOCATION, NULL, "dst1: %s\n",
 		saddr2str(iph2->dst));
 	plog(LLV_DEBUG, LOCATION, NULL, "dst2: %s\n",
 		saddr2str((struct sockaddr *)&spidx->dst));
-	if (cmpsaddrwop(iph2->dst, (struct sockaddr *)&spidx->dst)
-	 || spidx->prefd != prefixlen)
+
+	if (cmpsaddr(iph2->dst, (struct sockaddr *) &spidx->dst) != CMPSADDR_MATCH ||
+	    spidx->prefd != prefixlen)
 		return NULL;
 
 	plog(LLV_DEBUG, LOCATION, NULL, "looks to be transport mode\n");
@@ -194,11 +200,11 @@
 	 || a->ul_proto != b->ul_proto)
 		return 1;
 
-	if (cmpsaddrstrict((struct sockaddr *)&a->src,
-			   (struct sockaddr *)&b->src))
+	if (cmpsaddr((struct sockaddr *) &a->src,
+		     (struct sockaddr *) &b->src) != CMPSADDR_MATCH)
 		return 1;
-	if (cmpsaddrstrict((struct sockaddr *)&a->dst,
-			   (struct sockaddr *)&b->dst))
+	if (cmpsaddr((struct sockaddr *) &a->dst,
+		     (struct sockaddr *) &b->dst) != CMPSADDR_MATCH)
 		return 1;
 
 #ifdef HAVE_SECCTX
@@ -228,8 +234,7 @@
 	if (!(b->dir == IPSEC_DIR_ANY || a->dir == b->dir))
 		return 1;
 
-	if (!(a->ul_proto == IPSEC_ULPROTO_ANY ||
-	      b->ul_proto == IPSEC_ULPROTO_ANY ||
+	if (!(b->ul_proto == IPSEC_ULPROTO_ANY ||
 	      a->ul_proto == b->ul_proto))
 		return 1;
 
@@ -256,7 +261,7 @@
 		a, b->prefs, saddr2str((struct sockaddr *)&sa1));
 	plog(LLV_DEBUG, LOCATION, NULL, "%p masked with /%d: %s\n",
 		b, b->prefs, saddr2str((struct sockaddr *)&sa2));
-	if (cmpsaddrwild((struct sockaddr *)&sa1, (struct sockaddr *)&sa2))
+	if (cmpsaddr((struct sockaddr *)&sa1, (struct sockaddr *)&sa2) > CMPSADDR_WILDPORT_MATCH)
 		return 1;
 
 #ifndef __linux__
@@ -274,7 +279,7 @@
 		a, b->prefd, saddr2str((struct sockaddr *)&sa1));
 	plog(LLV_DEBUG, LOCATION, NULL, "%p masked with /%d: %s\n",
 		b, b->prefd, saddr2str((struct sockaddr *)&sa2));
-	if (cmpsaddrwild((struct sockaddr *)&sa1, (struct sockaddr *)&sa2))
+	if (cmpsaddr((struct sockaddr *)&sa1, (struct sockaddr *)&sa2) > CMPSADDR_WILDPORT_MATCH)
 		return 1;
 
 #ifdef HAVE_SECCTX
@@ -309,6 +314,11 @@
 		racoon_free(req);
 	}
 	
+	if (sp->local)
+		racoon_free(sp->local);
+	if (sp->remote)
+		racoon_free(sp->remote);
+
 	racoon_free(sp);
 }
 
diff --git a/src/racoon/policy.h b/src/racoon/policy.h
index 8c47451..ef7f923 100644
--- a/src/racoon/policy.h
+++ b/src/racoon/policy.h
@@ -1,4 +1,4 @@
-/*	$NetBSD: policy.h,v 1.5.4.2 2007/06/07 20:34:19 manu Exp $	*/
+/*	$NetBSD: policy.h,v 1.8 2008/12/05 06:02:20 tteras Exp $	*/
 
 /* Id: policy.h,v 1.5 2004/06/11 16:00:17 ludvigm Exp */
 
@@ -82,6 +82,12 @@
 	struct ipsecrequest *req;
 				/* pointer to the ipsec request tree, */
 				/* if policy == IPSEC else this value == NULL.*/
+
+	/* MIPv6 needs to perform negotiation of SA using different addresses
+	 * than the endpoints of the SA (CoA for the source). In that case,
+	 * MIGRATE msg provides that info (before movement occurs on the MN) */
+	struct sockaddr *local;
+	struct sockaddr *remote;
 };
 
 /* Security Assocciation Index */
@@ -111,7 +117,7 @@
 #ifdef HAVE_PFKEY_POLICY_PRIORITY
 #define KEY_SETSECSPIDX(_dir, s, d, ps, pd, ulp, _priority, _created, idx)              \
 do {                                                                         \
-	memset((idx), 0, sizeof(struct policyindex));                        \
+	bzero((idx), sizeof(struct policyindex));                            \
 	(idx)->dir = (_dir);                                                 \
 	(idx)->prefs = (ps);                                                 \
 	(idx)->prefd = (pd);                                                 \
@@ -124,7 +130,7 @@
 #else
 #define KEY_SETSECSPIDX(_dir, s, d, ps, pd, ulp, _created, idx)              \
 do {                                                                         \
-	memset((idx), 0, sizeof(struct policyindex));                        \
+	bzero((idx), sizeof(struct policyindex));                            \
 	(idx)->dir = (_dir);                                                 \
 	(idx)->prefs = (ps);                                                 \
 	(idx)->prefd = (pd);                                                 \
diff --git a/src/racoon/privsep.c b/src/racoon/privsep.c
index 9e60b89..55a3908 100644
--- a/src/racoon/privsep.c
+++ b/src/racoon/privsep.c
@@ -1,4 +1,4 @@
-/*	$NetBSD: privsep.c,v 1.6 2006/09/09 16:22:10 manu Exp $	*/
+/*	$NetBSD: privsep.c,v 1.21 2011/03/06 08:28:10 tteras Exp $	*/
 
 /* Id: privsep.c,v 1.15 2005/08/08 11:23:44 vanhu Exp */
 
@@ -42,15 +42,17 @@
 #include <signal.h>
 #include <pwd.h>
 
+#include <sys/types.h>
 #include <sys/socket.h>
 #include <sys/param.h>
 
+#include <netinet/in.h>
+
 #include "gcmalloc.h"
 #include "vmbuf.h"
 #include "misc.h"
 #include "plog.h"
 #include "var.h"
-#include "libpfkey.h"
 
 #include "crypto_openssl.h"
 #include "isakmp_var.h"
@@ -75,6 +77,28 @@
 static int unsafe_env(char *const *);
 static int unknown_name(int);
 static int unsafe_path(char *, int);
+static int rec_fd(int);
+static int send_fd(int, int);
+
+struct socket_args {
+	int domain;
+	int type;
+	int protocol;
+};
+
+struct sockopt_args {
+	int s;
+	int level;
+	int optname;
+	const void *optval;
+	socklen_t optlen;
+};
+
+struct bind_args {
+	int s;
+	const struct sockaddr *addr;
+	socklen_t addrlen;
+};
 
 static int
 privsep_send(sock, buf, len)
@@ -116,13 +140,19 @@
 	    sizeof(com), MSG_PEEK, NULL, NULL)) == -1) {
 		if (errno == EINTR)
 			continue;
+		if (errno == ECONNRESET)
+		    return -1;
 
 		plog(LLV_ERROR, LOCATION, NULL,
 		    "privsep_recv failed: %s\n",
 		    strerror(errno));
 		return -1;
 	}
-	
+
+	/* EOF, other side has closed. */
+	if (len == 0)
+	    return -1;
+
 	/* Check for short packets */
 	if (len < sizeof(com)) {
 		plog(LLV_ERROR, LOCATION, NULL,
@@ -142,6 +172,8 @@
 	    com.ac_len, 0, NULL, NULL)) == -1) {
 		if (errno == EINTR)
 			continue;
+		if (errno == ECONNRESET)
+		    return -1;
 		plog(LLV_ERROR, LOCATION, NULL,
 		    "failed to recv privsep command: %s\n", 
 		    strerror(errno));
@@ -174,7 +206,7 @@
 	/* 
 	 * When running privsep, certificate and script paths 
 	 * are mandatory, as they enable us to check path safety
-	 * in the privilegied instance
+	 * in the privileged instance
 	 */
 	if ((lcconf->pathinfo[LC_PATHTYPE_CERT] == NULL) ||
 	    (lcconf->pathinfo[LC_PATHTYPE_SCRIPT] == NULL)) {
@@ -183,7 +215,7 @@
 		return -1;
 	}
 
-	if (socketpair(PF_LOCAL, SOCK_DGRAM, 0, privsep_sock) != 0) {
+	if (socketpair(PF_LOCAL, SOCK_STREAM, 0, privsep_sock) != 0) {
 		plog(LLV_ERROR, LOCATION, NULL, 
 		    "Cannot allocate privsep_sock: %s\n", strerror(errno));
 		return -1;
@@ -197,6 +229,8 @@
 		break;
 
 	case 0: /* Child: drop privileges */
+		(void)close(privsep_sock[0]);
+
 		if (lcconf->chroot != NULL) {
 			if (chdir(lcconf->chroot) != 0) {
 				plog(LLV_ERROR, LOCATION, NULL, 
@@ -243,7 +277,7 @@
 		return 0;
 		break;
 
-	default: /* Parent: privilegied process */
+	default: /* Parent: privileged process */
 		break;
 	}
 
@@ -254,8 +288,6 @@
 	for (i = sysconf(_SC_OPEN_MAX); i > 0; i--) {
 		if (i == privsep_sock[0])
 			continue;
-		if (i == privsep_sock[1])
-			continue;
 		if ((f_foreground) && (i == 1))
 			continue;
 		(void)close(i);
@@ -265,16 +297,20 @@
 	ploginit();
 
 	plog(LLV_INFO, LOCATION, NULL, 
-	    "racoon privilegied process running with PID %d\n", getpid());
+	    "racoon privileged process running with PID %d\n", getpid());
 
-#ifdef __NetBSD__
+	plog(LLV_INFO, LOCATION, NULL,
+	    "racoon unprivileged process running with PID %d\n", child_pid);
+
+#if defined(__NetBSD__) || defined(__FreeBSD__)
 	setproctitle("[priv]");
 #endif
 	
-	/* 
-	 * Don't catch any signal 
+	/*
+	 * Don't catch any signal
 	 * This duplicate session:signals[], which is static...
 	 */
+	signal(SIGPIPE, SIG_IGN);
 	signal(SIGHUP, SIG_DFL);
 	signal(SIGINT, SIG_DFL);
 	signal(SIGTERM, SIG_DFL);
@@ -331,7 +367,7 @@
 		/* 
 		 * XXX Improvement: instead of returning the key, 
 		 * stuff eay_get_pkcs1privkey and eay_get_x509sign
-		 * together and sign the hash in the privilegied 
+		 * together and sign the hash in the privileged 
 		 * instance? 
 		 * pro: the key remains inaccessible to unpriv
 		 * con: a compromised unpriv racoon can still sign anything
@@ -503,6 +539,154 @@
 			break;
 		}
 
+		case PRIVSEP_SOCKET: {
+			struct socket_args socket_args;
+			int s;
+
+			/* Make sure the string is NULL terminated */
+			if (safety_check(combuf, 0) != 0)
+				break;
+
+			if (combuf->bufs.buflen[0] !=
+			    sizeof(struct socket_args)) {
+				plog(LLV_ERROR, LOCATION, NULL, 
+				    "privsep_socket: corrupted message\n");
+				goto out;
+			}
+			memcpy(&socket_args, bufs[0],
+			       sizeof(struct socket_args));
+
+			if (socket_args.domain != PF_INET &&
+			    socket_args.domain != PF_INET6) {
+				plog(LLV_ERROR, LOCATION, NULL, 
+				    "privsep_socket: "
+				     "unauthorized domain (%d)\n",
+				     socket_args.domain);
+				goto out;
+			}
+
+			if ((s = socket(socket_args.domain, socket_args.type,
+					socket_args.protocol)) == -1) {
+				reply->hdr.ac_errno = errno;
+				break;
+			}
+
+			if (send_fd(privsep_sock[0], s) < 0) {
+				plog(LLV_ERROR, LOCATION, NULL, 
+				     "privsep_socket: send_fd failed\n");
+				close(s);
+				goto out;
+			}
+
+			close(s);
+			break;
+		}
+
+		case PRIVSEP_BIND: {
+			struct bind_args bind_args;
+			int err, port = 0;
+
+			/* Make sure the string is NULL terminated */
+			if (safety_check(combuf, 0) != 0)
+				break;
+
+			if (combuf->bufs.buflen[0] !=
+			    sizeof(struct bind_args)) {
+				plog(LLV_ERROR, LOCATION, NULL, 
+				    "privsep_bind: corrupted message\n");
+				goto out;
+			}
+			memcpy(&bind_args, bufs[0], sizeof(struct bind_args));
+
+			if (combuf->bufs.buflen[1] != bind_args.addrlen) {
+				plog(LLV_ERROR, LOCATION, NULL, 
+				    "privsep_bind: corrupted message\n");
+				goto out;
+			}
+			bind_args.addr = (const struct sockaddr *)bufs[1];
+
+			if ((bind_args.s = rec_fd(privsep_sock[0])) < 0) {
+				plog(LLV_ERROR, LOCATION, NULL, 
+				     "privsep_bind: rec_fd failed\n");
+				goto out;
+			}
+
+			port = extract_port(bind_args.addr);
+			if (port != PORT_ISAKMP && port != PORT_ISAKMP_NATT &&
+			    port != lcconf->port_isakmp &&
+			    port != lcconf->port_isakmp_natt) {
+				plog(LLV_ERROR, LOCATION, NULL,
+				     "privsep_bind: "
+				     "unauthorized port (%d)\n",
+				     port);
+				close(bind_args.s);
+				goto out;
+			}
+
+			err = bind(bind_args.s, bind_args.addr,
+				   bind_args.addrlen);
+
+			if (err)
+				reply->hdr.ac_errno = errno;
+
+			close(bind_args.s);
+			break;
+		}
+
+		case PRIVSEP_SETSOCKOPTS: {
+			struct sockopt_args sockopt_args;
+			int err;
+
+			/* Make sure the string is NULL terminated */
+			if (safety_check(combuf, 0) != 0)
+				break;
+
+			if (combuf->bufs.buflen[0] !=
+			    sizeof(struct sockopt_args)) {
+				plog(LLV_ERROR, LOCATION, NULL, 
+				    "privsep_setsockopt: "
+				     "corrupted message\n");
+				goto out;
+			}
+			memcpy(&sockopt_args, bufs[0],
+			       sizeof(struct sockopt_args));
+
+			if (combuf->bufs.buflen[1] != sockopt_args.optlen) {
+				plog(LLV_ERROR, LOCATION, NULL, 
+				    "privsep_setsockopt: corrupted message\n");
+				goto out;
+			}
+			sockopt_args.optval = bufs[1];
+
+			if (sockopt_args.optname != 
+			    (sockopt_args.level == 
+			     IPPROTO_IP ? IP_IPSEC_POLICY :
+			     IPV6_IPSEC_POLICY)) {
+				plog(LLV_ERROR, LOCATION, NULL, 
+				    "privsep_setsockopt: "
+				     "unauthorized option (%d)\n",
+				     sockopt_args.optname);
+				goto out;
+			}
+
+			if ((sockopt_args.s = rec_fd(privsep_sock[0])) < 0) {
+				plog(LLV_ERROR, LOCATION, NULL, 
+				     "privsep_setsockopt: rec_fd failed\n");
+				goto out;
+			}
+
+			err = setsockopt(sockopt_args.s,
+					 sockopt_args.level,
+					 sockopt_args.optname,
+					 sockopt_args.optval,
+					 sockopt_args.optlen);
+			if (err)
+				reply->hdr.ac_errno = errno;
+
+			close(sockopt_args.s);
+			break;
+		}
+
 #ifdef ENABLE_HYBRID
 		case PRIVSEP_ACCOUNTING_SYSTEM: {
 			int pool_size;
@@ -687,14 +871,17 @@
 
 		/* This frees reply */
 		if (privsep_send(privsep_sock[0], 
-		    reply, reply->hdr.ac_len) != 0)
+		    reply, reply->hdr.ac_len) != 0) {
+			racoon_free(reply);
 			goto out;
+		}
 
 		racoon_free(combuf);
 	}
 
 out:
-	plog(LLV_INFO, LOCATION, NULL, "privsep exit\n");
+	plog(LLV_INFO, LOCATION, NULL, 
+	    "racoon privileged process %d terminated\n", getpid());
 	_exit(0);
 }
 
@@ -745,37 +932,6 @@
 	return NULL;
 }
 
-/*
- * No prigilege separation trick here, we just open PFKEY before
- * dropping root privs and we remember it later.
- */
-static int  pfkey_socket = -1;
-int
-privsep_pfkey_open(void)
-{
-	int ps;
-
-	if (pfkey_socket != -1)
-		return pfkey_socket;
-
-	ps = pfkey_open();
-	if (ps != -1)
-		pfkey_socket = ps;
-
-	return ps;
-}
-
-/*
- * Consequence of the above trickery: don't 
- * really close PFKEY as we never re-open it.
- */
-void
-privsep_pfkey_close(ps)
-	int ps;
-{
-	return;
-}
-
 int
 privsep_script_exec(script, name, envp)
 	char *script;
@@ -941,6 +1097,224 @@
 	return NULL;
 }
 
+/*
+ * Create a privileged socket.  On BSD systems a socket obtains special
+ * capabilities if it is created by root; setsockopt(IP_IPSEC_POLICY) will
+ * succeed but will be ineffective if performed on an unprivileged socket.
+ */
+int
+privsep_socket(domain, type, protocol)
+	int domain;
+	int type;
+	int protocol;
+{
+	struct privsep_com_msg *msg;
+	size_t len;
+	char *data;
+	struct socket_args socket_args;
+	int s, saved_errno = 0;
+
+	if (geteuid() == 0)
+		return socket(domain, type, protocol);
+
+	len = sizeof(*msg) + sizeof(socket_args);
+
+	if ((msg = racoon_malloc(len)) == NULL) {
+		plog(LLV_ERROR, LOCATION, NULL, 
+		    "Cannot allocate memory: %s\n", strerror(errno));
+		return -1;
+	}
+	bzero(msg, len);
+	msg->hdr.ac_cmd = PRIVSEP_SOCKET;
+	msg->hdr.ac_len = len;
+
+	socket_args.domain = domain;
+	socket_args.type = type;
+	socket_args.protocol = protocol;
+
+	data = (char *)(msg + 1);
+	msg->bufs.buflen[0] = sizeof(socket_args);
+	memcpy(data, &socket_args, msg->bufs.buflen[0]);
+
+	/* frees msg */
+	if (privsep_send(privsep_sock[1], msg, len) != 0)
+		goto out;
+
+	/* Get the privileged socket descriptor from the privileged process. */
+	if ((s = rec_fd(privsep_sock[1])) == -1)
+		return -1;
+
+	if (privsep_recv(privsep_sock[1], &msg, &len) != 0)
+		goto out;
+
+	if (msg->hdr.ac_errno != 0) {
+		errno = msg->hdr.ac_errno;
+		goto out;
+	}
+
+	racoon_free(msg);
+	return s;
+
+out:
+	racoon_free(msg);
+	return -1;
+}
+
+/*
+ * Bind() a socket to a port.  This works just like regular bind(), except that
+ * if you want to bind to the designated isakmp ports and you don't have the
+ * privilege to do so, it will ask a privileged process to do it.
+ */
+int
+privsep_bind(s, addr, addrlen)
+	int s;
+	const struct sockaddr *addr;
+	socklen_t addrlen;
+{
+	struct privsep_com_msg *msg;
+	size_t len;
+	char *data;
+	struct bind_args bind_args;
+	int err, saved_errno = 0;
+
+	err = bind(s, addr, addrlen);
+	if ((err == 0) || (saved_errno = errno) != EACCES || geteuid() == 0) {
+		if (saved_errno)
+			plog(LLV_ERROR, LOCATION, NULL,
+			     "privsep_bind (%s) = %d\n", strerror(saved_errno), err);
+		errno = saved_errno;
+		return err;
+	}
+
+	len = sizeof(*msg) + sizeof(bind_args) + addrlen;
+
+	if ((msg = racoon_malloc(len)) == NULL) {
+		plog(LLV_ERROR, LOCATION, NULL, 
+		    "Cannot allocate memory: %s\n", strerror(errno));
+		return -1;
+	}
+	bzero(msg, len);
+	msg->hdr.ac_cmd = PRIVSEP_BIND;
+	msg->hdr.ac_len = len;
+
+	bind_args.s = -1;
+	bind_args.addr = NULL;
+	bind_args.addrlen = addrlen;
+
+	data = (char *)(msg + 1);
+	msg->bufs.buflen[0] = sizeof(bind_args);
+	memcpy(data, &bind_args, msg->bufs.buflen[0]);
+
+	data += msg->bufs.buflen[0];
+	msg->bufs.buflen[1] = addrlen;
+	memcpy(data, addr, addrlen);
+
+	/* frees msg */
+	if (privsep_send(privsep_sock[1], msg, len) != 0)
+		goto out;
+
+	/* Send the socket descriptor to the privileged process. */
+	if (send_fd(privsep_sock[1], s) < 0)
+		return -1;
+
+	if (privsep_recv(privsep_sock[1], &msg, &len) != 0)
+		goto out;
+
+	if (msg->hdr.ac_errno != 0) {
+		errno = msg->hdr.ac_errno;
+		goto out;
+	}
+
+	racoon_free(msg);
+	return 0;
+
+out:
+	racoon_free(msg);
+	return -1;
+}
+
+/*
+ * Set socket options.  This works just like regular setsockopt(), except that
+ * if you want to change IP_IPSEC_POLICY or IPV6_IPSEC_POLICY and you don't
+ * have the privilege to do so, it will ask a privileged process to do it.
+ */
+int
+privsep_setsockopt(s, level, optname, optval, optlen)
+	int s;
+	int level;
+	int optname;
+	const void *optval;
+	socklen_t optlen;
+{
+	struct privsep_com_msg *msg;
+	size_t len;
+	char *data;
+	struct sockopt_args sockopt_args;
+	int err, saved_errno = 0;
+
+	if ((err = setsockopt(s, level, optname, optval, optlen) == 0) || 
+	    (saved_errno = errno) != EACCES ||
+	    geteuid() == 0) {
+		if (saved_errno)
+			plog(LLV_ERROR, LOCATION, NULL,
+			     "privsep_setsockopt (%s)\n",
+			     strerror(saved_errno));
+
+		errno = saved_errno;
+		return err;
+	}
+
+	len = sizeof(*msg) + sizeof(sockopt_args) + optlen;
+
+	if ((msg = racoon_malloc(len)) == NULL) {
+		plog(LLV_ERROR, LOCATION, NULL, 
+		    "Cannot allocate memory: %s\n", strerror(errno));
+		return -1;
+	}
+	bzero(msg, len);
+	msg->hdr.ac_cmd = PRIVSEP_SETSOCKOPTS;
+	msg->hdr.ac_len = len;
+
+	sockopt_args.s = -1;
+	sockopt_args.level = level;
+	sockopt_args.optname = optname;
+	sockopt_args.optval = NULL;
+	sockopt_args.optlen = optlen;
+
+	data = (char *)(msg + 1);
+	msg->bufs.buflen[0] = sizeof(sockopt_args);
+	memcpy(data, &sockopt_args, msg->bufs.buflen[0]);
+
+	data += msg->bufs.buflen[0];
+	msg->bufs.buflen[1] = optlen;
+	memcpy(data, optval, optlen);
+
+	/* frees msg */
+	if (privsep_send(privsep_sock[1], msg, len) != 0)
+		goto out;
+
+	if (send_fd(privsep_sock[1], s) < 0)
+		return -1;
+
+	if (privsep_recv(privsep_sock[1], &msg, &len) != 0) {
+	    plog(LLV_ERROR, LOCATION, NULL,
+		 "privsep_recv failed\n");
+		goto out;
+	}
+
+	if (msg->hdr.ac_errno != 0) {
+		errno = msg->hdr.ac_errno;
+		goto out;
+	}
+
+	racoon_free(msg);
+	return 0;
+
+out:
+	racoon_free(msg);
+	return -1;
+}
+
 #ifdef ENABLE_HYBRID
 int
 privsep_xauth_login_system(usr, pwd)
@@ -972,6 +1346,7 @@
 	msg->bufs.buflen[1] = strlen(pwd) + 1;
 	memcpy(data, pwd, msg->bufs.buflen[1]);
 	
+	/* frees msg */
 	if (privsep_send(privsep_sock[1], msg, len) != 0)
 		return -1;
 
@@ -1034,6 +1409,7 @@
 	data += msg->bufs.buflen[2];
 	memcpy(data, &inout, msg->bufs.buflen[3]);
 
+	/* frees msg */
 	if (privsep_send(privsep_sock[1], msg, len) != 0)
 		return -1;
 
@@ -1089,7 +1465,7 @@
 }
 
 /*
- * Filter unsafe environement variables
+ * Filter unsafe environment variables
  */
 static int
 unsafe_env(envp)
@@ -1110,7 +1486,7 @@
 	return 0;
 found:
 	plog(LLV_ERROR, LOCATION, NULL, 
-	    "privsep_script_exec: unsafe environement variable\n");
+	    "privsep_script_exec: unsafe environment variable\n");
 	return -1;
 }
 
@@ -1161,6 +1537,86 @@
 	return 0;
 }
 
+/* Receive a file descriptor through the argument socket */
+static int
+rec_fd(s)
+	int s;
+{
+	struct msghdr msg;
+	struct cmsghdr *cmsg;
+	int *fdptr;
+	int fd;
+	char cmsbuf[1024];
+	struct iovec iov;
+	char iobuf[1];
+
+	iov.iov_base = iobuf;
+	iov.iov_len = 1;
+
+	if (sizeof(cmsbuf) < CMSG_SPACE(sizeof(fd))) {
+		plog(LLV_ERROR, LOCATION, NULL, 
+		    "send_fd: buffer size too small\n");
+		return -1;
+	}
+	bzero(&msg, sizeof(msg));
+	msg.msg_name = NULL;
+	msg.msg_namelen = 0;
+	msg.msg_iov = &iov;
+	msg.msg_iovlen = 1;
+	msg.msg_control = cmsbuf;
+	msg.msg_controllen = CMSG_SPACE(sizeof(fd));
+
+	if (recvmsg(s, &msg, MSG_WAITALL) == -1)
+		return -1;
+
+	cmsg = CMSG_FIRSTHDR(&msg);
+	fdptr = (int *) CMSG_DATA(cmsg);
+	return fdptr[0];
+}
+
+/* Send the file descriptor fd through the argument socket s */
+static int
+send_fd(s, fd)
+	int s;
+	int fd;
+{
+	struct msghdr msg;
+	struct cmsghdr *cmsg;
+	char cmsbuf[1024];
+	struct iovec iov;
+	int *fdptr;
+
+	iov.iov_base = " ";
+	iov.iov_len = 1;
+
+	if (sizeof(cmsbuf) < CMSG_SPACE(sizeof(fd))) {
+		plog(LLV_ERROR, LOCATION, NULL, 
+		    "send_fd: buffer size too small\n");
+		return -1;
+	}
+	bzero(&msg, sizeof(msg));
+	msg.msg_name = NULL;
+	msg.msg_namelen = 0;
+	msg.msg_iov = &iov;
+	msg.msg_iovlen = 1;
+	msg.msg_control = cmsbuf;
+	msg.msg_controllen = CMSG_SPACE(sizeof(fd));
+	msg.msg_flags = 0;
+
+	cmsg = CMSG_FIRSTHDR(&msg);
+	cmsg->cmsg_level = SOL_SOCKET;
+	cmsg->cmsg_type = SCM_RIGHTS;
+	cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
+	fdptr = (int *)CMSG_DATA(cmsg);
+	fdptr[0] = fd;
+	msg.msg_controllen = cmsg->cmsg_len;
+
+	if (sendmsg(s, &msg, 0) == -1)
+		return -1;
+
+	return 0;
+}
+
 #ifdef HAVE_LIBPAM
 int 
 privsep_accounting_pam(port, inout)
@@ -1202,6 +1658,7 @@
 	*inout_data = inout;
 	*pool_size_data = isakmp_cfg_config.pool_size;
 
+	/* frees msg */
 	if (privsep_send(privsep_sock[1], msg, len) != 0)
 		return -1;
 
@@ -1272,6 +1729,7 @@
 	data += msg->bufs.buflen[3];
 	memcpy(data, pwd, msg->bufs.buflen[4]);
 
+	/* frees msg */
 	if (privsep_send(privsep_sock[1], msg, len) != 0)
 		return -1;
 
@@ -1324,6 +1782,7 @@
 	data += msg->bufs.buflen[0];
 	memcpy(data, &isakmp_cfg_config.pool_size, msg->bufs.buflen[1]);
 
+	/* frees msg */
 	if (privsep_send(privsep_sock[1], msg, len) != 0)
 		return;
 
diff --git a/src/racoon/privsep.h b/src/racoon/privsep.h
index 0fa4363..732743c 100644
--- a/src/racoon/privsep.h
+++ b/src/racoon/privsep.h
@@ -1,4 +1,4 @@
-/*	$NetBSD: privsep.h,v 1.4 2006/09/09 16:22:10 manu Exp $	*/
+/*	$NetBSD: privsep.h,v 1.6 2008/12/08 06:00:54 tteras Exp $	*/
 
 /* Id: privsep.h,v 1.5 2005/06/07 12:22:11 fredsen Exp */
 
@@ -42,6 +42,9 @@
 #define PRIVSEP_XAUTH_LOGIN_PAM		0x0807	/* admin_com_bufs follows */
 #define PRIVSEP_CLEANUP_PAM		0x0808	/* admin_com_bufs follows */
 #define PRIVSEP_ACCOUNTING_SYSTEM	0x0809	/* admin_com_bufs follows */
+#define PRIVSEP_SETSOCKOPTS		0x080A	/* admin_com_bufs follows */
+#define PRIVSEP_BIND			0x080B	/* admin_com_bufs follows */
+#define PRIVSEP_SOCKET			0x080C	/* admin_com_bufs follows */
 
 #define PRIVSEP_NBUF_MAX 24
 #define PRIVSEP_BUFLEN_MAX 4096
@@ -58,9 +61,10 @@
 int privsep_init __P((void));
 
 vchar_t *privsep_eay_get_pkcs1privkey __P((char *));
-int privsep_pfkey_open __P((void));
-void privsep_pfkey_close __P((int));
 int privsep_script_exec __P((char *, int, char * const *));
+int privsep_setsockopt __P((int, int, int, const void *, socklen_t));
+int privsep_socket __P((int, int, int));
+int privsep_bind __P((int, const struct sockaddr *, socklen_t));
 vchar_t *privsep_getpsk __P((const char *, const int));
 int privsep_xauth_login_system __P((char *, char *));
 #ifdef HAVE_LIBPAM
diff --git a/src/racoon/proposal.c b/src/racoon/proposal.c
index 26c9274..33dd311 100644
--- a/src/racoon/proposal.c
+++ b/src/racoon/proposal.c
@@ -1,6 +1,6 @@
-/*	$NetBSD: proposal.c,v 1.13.4.2 2008/07/22 13:25:42 vanhu Exp $	*/
+/*	$NetBSD: proposal.c,v 1.17 2008/09/19 11:14:49 tteras Exp $	*/
 
-/* $Id: proposal.c,v 1.13.4.2 2008/07/22 13:25:42 vanhu Exp $ */
+/* $Id: proposal.c,v 1.17 2008/09/19 11:14:49 tteras Exp $ */
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -1186,10 +1186,10 @@
 	 * make my proposal according as the client proposal.
 	 * XXX assumed there is only one proposal even if it's the SA bundle.
 	 */
-        for (i = 0; i < MAXPROPPAIRLEN; i++) {
-                if (pair[i] == NULL)
-                        continue;
-
+	for (i = 0; i < MAXPROPPAIRLEN; i++) {
+		if (pair[i] == NULL)
+			continue;
+		
 		if (pp_peer != NULL)
 			flushsaprop(pp_peer);
 
@@ -1226,8 +1226,6 @@
 
 		for (pr = pp_peer->head; pr; pr = pr->next)
 		{
-			struct remoteconf *conf;
-
 			newpr = newsaproto();
 			if (newpr == NULL)
 			{
@@ -1244,9 +1242,7 @@
 			newpr->reqid_in = 0;
 			newpr->reqid_out = 0;
 
-			conf = getrmconf(iph2->dst);
-			if (conf != NULL &&
-				conf->gen_policy == GENERATE_POLICY_UNIQUE){
+			if (iph2->ph1->rmconf->gen_policy == GENERATE_POLICY_UNIQUE){
 				newpr->reqid_in = g_nextreqid ;
 				newpr->reqid_out = g_nextreqid ++;
 				/* 
diff --git a/src/racoon/proposal.h b/src/racoon/proposal.h
index 60fc531..11fbab8 100644
--- a/src/racoon/proposal.h
+++ b/src/racoon/proposal.h
@@ -1,4 +1,4 @@
-/*	$NetBSD: proposal.h,v 1.6 2006/12/09 05:52:57 manu Exp $	*/
+/*	$NetBSD: proposal.h,v 1.7 2010/02/09 23:05:16 wiz Exp $	*/
 
 /* Id: proposal.h,v 1.5 2004/06/11 16:00:17 ludvigm Exp */
 
@@ -88,7 +88,7 @@
 	int reqid_out;			/* request id (outbound) */
 	int reqid_in;			/* request id (inbound) */
 
-	int ok;				/* if 1, success to set SA in kenrel */
+	int ok;				/* if 1, success to set SA in kernel */
 
 	struct satrns *head;		/* header of transform */
 	struct saproto *next;		/* next protocol */
diff --git a/src/racoon/prsa_par.h b/src/racoon/prsa_par.h
index 3bdb11d..6e845d8 100644
--- a/src/racoon/prsa_par.h
+++ b/src/racoon/prsa_par.h
@@ -1,24 +1,23 @@
-/* A Bison parser, made by GNU Bison 2.3.  */
+
+/* A Bison parser, made by GNU Bison 2.4.1.  */
 
 /* Skeleton interface for Bison's Yacc-like parsers in C
-
-   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+   
+      Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
    Free Software Foundation, Inc.
-
-   This program is free software; you can redistribute it and/or modify
+   
+   This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
-   any later version.
-
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+   
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
-
+   
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301, USA.  */
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 /* As a special exception, you may create a larger work that contains
    part or all of the Bison parser skeleton and distribute that work
@@ -29,10 +28,11 @@
    special exception, which will cause the skeleton and the resulting
    Bison output files to be licensed under the GNU General Public
    License without this special exception.
-
+   
    This special exception was added by the Free Software Foundation in
    version 2.2 of Bison.  */
 
+
 /* Tokens.  */
 #ifndef YYTOKENTYPE
 # define YYTOKENTYPE
@@ -90,21 +90,27 @@
 
 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
 typedef union YYSTYPE
-#line 130 "prsa_par.y"
 {
+
+/* Line 1676 of yacc.c  */
+#line 130 "prsa_par.y"
+
 	BIGNUM *bn;
 	RSA *rsa;
 	char *chr;
 	long num;
 	struct netaddr *naddr;
-}
-/* Line 1489 of yacc.c.  */
-#line 103 "prsa_par.h"
-	YYSTYPE;
+
+
+
+/* Line 1676 of yacc.c  */
+#line 108 "prsa_par.h"
+} YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
 # define yystype YYSTYPE /* obsolescent; will be withdrawn */
 # define YYSTYPE_IS_DECLARED 1
-# define YYSTYPE_IS_TRIVIAL 1
 #endif
 
 extern YYSTYPE prsalval;
 
+
diff --git a/src/racoon/prsa_par.y b/src/racoon/prsa_par.y
index f21a82b..1987e4d 100644
--- a/src/racoon/prsa_par.y
+++ b/src/racoon/prsa_par.y
@@ -1,4 +1,4 @@
-/*	$NetBSD: prsa_par.y,v 1.4 2006/09/09 16:22:10 manu Exp $	*/
+/*	$NetBSD: prsa_par.y,v 1.6 2011/03/02 14:49:21 vanhu Exp $	*/
 
 /* Id: prsa_par.y,v 1.3 2004/11/08 12:04:23 ludvigm Exp */
 
@@ -211,6 +211,7 @@
 			YYABORT;
 		}
 		$$ = base64_pubkey2rsa($2);
+		free($2);
 	}
 	| TAG_PUB HEX
 	{
@@ -236,6 +237,7 @@
 	{
 		int err;
 		struct sockaddr_in *sap;
+		struct addrinfo hints, *res;
 		
 		if ($2 == -1) $2 = 32;
 		if ($2 < 0 || $2 > 32) {
@@ -245,12 +247,17 @@
 		$$ = calloc (sizeof(struct netaddr), 1);
 		$$->prefix = $2;
 		sap = (struct sockaddr_in *)(&$$->sa);
-		sap->sin_family = AF_INET;
-		err = inet_pton(AF_INET, $1, (struct in_addr*)(&sap->sin_addr));
-		if (err <= 0) {
-			prsaerror("inet_pton(%s): %s\n", $1, strerror(errno));
+		memset(&hints, 0, sizeof(hints));
+		hints.ai_family = AF_INET;
+		hints.ai_flags = AI_NUMERICHOST;
+		err = getaddrinfo($1, NULL, &hints, &res);
+		if (err < 0) {
+			prsaerror("getaddrinfo(%s): %s\n", $1, gai_strerror(err));
 			YYABORT;
 		}
+		memcpy(sap, res->ai_addr, res->ai_addrlen);
+		freeaddrinfo(res);
+		free($1);
 	}
 	;
 
@@ -259,6 +266,7 @@
 	{
 		int err;
 		struct sockaddr_in6 *sap;
+		struct addrinfo hints, *res;
 		
 		if ($2 == -1) $2 = 128;
 		if ($2 < 0 || $2 > 128) {
@@ -268,12 +276,17 @@
 		$$ = calloc (sizeof(struct netaddr), 1);
 		$$->prefix = $2;
 		sap = (struct sockaddr_in6 *)(&$$->sa);
-		sap->sin6_family = AF_INET6;
-		err = inet_pton(AF_INET6, $1, (struct in6_addr*)(&sap->sin6_addr));
-		if (err <= 0) {
-			prsaerror("inet_pton(%s): %s\n", $1, strerror(errno));
+		memset(&hints, 0, sizeof(hints));
+		hints.ai_family = AF_INET6;
+		hints.ai_flags = AI_NUMERICHOST;
+		err = getaddrinfo($1, NULL, &hints, &res);
+		if (err < 0) {
+			prsaerror("getaddrinfo(%s): %s\n", $1, gai_strerror(err));
 			YYABORT;
 		}
+		memcpy(sap, res->ai_addr, res->ai_addrlen);
+		freeaddrinfo(res);
+		free($1);
 	}
 	;
 
diff --git a/src/racoon/racoon.8 b/src/racoon/racoon.8
index a6d39d7..58fefdd 100644
--- a/src/racoon/racoon.8
+++ b/src/racoon/racoon.8
@@ -1,4 +1,4 @@
-.\"	$NetBSD: racoon.8,v 1.10 2006/09/09 16:22:10 manu Exp $
+.\"	$NetBSD: racoon.8,v 1.12 2009/01/24 10:42:31 wiz Exp $
 .\"
 .\" Id: racoon.8,v 1.4 2005/04/18 11:07:55 manubsd Exp
 .\"
@@ -29,7 +29,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd November 20, 2000
+.Dd January 23, 2009
 .Dt RACOON 8
 .Os
 .\"
@@ -40,7 +40,7 @@
 .Sh SYNOPSIS
 .Nm racoon
 .Bk -words
-.Op Fl 46BdFLv
+.Op Fl 46BdFLVv
 .Ek
 .Bk -words
 .Op Fl f Ar configfile
@@ -115,6 +115,8 @@
 Listen to the ISAKMP key exchange on port
 .Ar isakmp-port
 instead of the default port number, 500.
+.It Fl V
+Print racoon version and compilation options and exit.
 .It Fl v
 This flag causes the packet dump be more verbose, with higher
 debugging level.
diff --git a/src/racoon/racoon.conf.5 b/src/racoon/racoon.conf.5
index 9ddee80..70c7eda 100644
--- a/src/racoon/racoon.conf.5
+++ b/src/racoon/racoon.conf.5
@@ -1,4 +1,4 @@
-.\"	$NetBSD: racoon.conf.5,v 1.34.4.3 2007/09/03 18:07:29 mgrooms Exp $
+.\"	$NetBSD: racoon.conf.5,v 1.61 2010/06/22 20:51:04 wiz Exp $
 .\"
 .\"	Id: racoon.conf.5,v 1.54 2006/08/22 18:17:17 manubsd Exp
 .\"
@@ -29,7 +29,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd September 19, 2006
+.Dd June 22, 2010
 .Dt RACOON.CONF 5
 .Os
 .\"
@@ -152,7 +152,7 @@
 should switch.
 This can be a quoted user name or a numeric UID.
 .It Ic group Ar group ;
-The group the unprivilegied instance of
+The group the unprivileged instance of
 .Xr racoon 8 ,
 should switch.
 This can be a quoted group name or a numeric GID.
@@ -184,7 +184,8 @@
 .Ic certificate
 and
 .Ic script
-paths are mandatory. A
+paths are mandatory.
+A
 .Xr racoon 8
 restart is required if you want path changes to be taken into account.
 .Bl -tag -width Ds -compact
@@ -223,7 +224,8 @@
 Specifies file where to store PID of process.
 If path starts with
 .Pa /
-it is treated as an absolute path. Otherwise, it is treated as a relative 
+it is treated as an absolute path.
+Otherwise, it is treated as a relative
 path to the VARRUN directory specified at compilation time.
 Default is
 .Pa racoon.pid .
@@ -235,12 +237,6 @@
 Specifies other configuration files to be included.
 .El
 .\"
-.Ss Identifier Specification
-is obsolete.
-It must be defined at each
-.Ic remote
-directive.
-.\"
 .Ss Timer Specification
 .Bl -tag -width Ds -compact
 .It Ic timer { Ar statements Ic }
@@ -319,12 +315,14 @@
 .Ar owner ,
 and
 .Ar group
-values specify the socket path, owner, and group. They must be quoted.
+values specify the socket path, owner, and group.
+They must be quoted.
 The defaults are
 .Pa /var/racoon/racoon.sock ,
 UID 0, and GID 0.
 .Ar mode
-is the access mode in octal. The default is 0600.
+is the access mode in octal.
+The default is 0600.
 .It Ic adminsock disabled ;
 This directive tells racoon to not listen on the admin socket.
 .El
@@ -360,22 +358,66 @@
 .El
 .El
 .\"
+.Pp
+.Bl -tag -width Ds -compact
+.It Ic pfkey_buffer Ar kBytes
+Specifies the socket send/receive buffer size in kilobytes.
+Numerous kernel PF_KEY implementations have problems with dumping
+SAD/SDP with large amount of entries (this happens when 100s to
+1000s of tunnels are configured).
+.Pp
+The default value of 0 leaves everything at the OS-specific default value.
+If the default buffer size is greater than what is specified here racoon
+will not decrease it.
+.Pp
+This problem is known to be fixed in Linux 2.6.25 and later.
+.El
+.\"
 .Ss Remote Nodes Specifications
 .Bl -tag -width Ds -compact
-.It Xo
-.Ic remote ( Ar address | Ic anonymous )
-.Bq Bq Ar port
-.Bq Ic inherit Ar parent
-.Ic { Ar statements Ic }
-.Xc
+.It Ic remote Ar name Bo Ic inherit Ar parent_name Bc Ic { Ar statements Ic }
 Specifies the IKE phase 1 parameters for each remote node.
-The default port is 500.
-If
-.Ic anonymous
-is specified, the statements will apply to any peer that does not match a
-more specific
-.Ic remote
-directive.
+.Pp
+If connection is initiated using racoonctl, a unique match using the
+remote IP must be found or the remote block name has to be given.
+For received acquires (kernel notices traffic requiring a new SA) the
+remote IP and remoteid from matching sainfo block are used to decide
+the remoteblock.
+If no uniquely matching remoteblock is found using
+these criteria, no connection attempt is done.
+.Pp
+When acting as responder, racoon picks the first proposal that has one
+or more acceptable remote configurations.
+When determining if a remote
+specification is matching the following information is checked:
+.Bl -bullet -width Ds -compact
+.It
+The remote IP is checked against
+.Ic remote_address .
+.It
+ISAKMP exchange type is checked against
+.Ic exchange_mode .
+.It
+ISAKMP SA attributes must match a
+.Ic proposal
+block.
+.It
+The remote identity is matched against
+.Ic peers_identifier
+if
+.Ic verify_identifier
+is on.
+.It
+If a certificate request was received, it must match the issuer of
+.Ic "certificate_type x509"
+certificate.
+If certificate request without issuer name was sent, the
+.Ic match_empty_cr
+parameter specifies whether or not remote block matches.
+.El
+.Pp
+Similarly, NAT-T is enabled if any of the initial remote configuration
+candidates allow NAT-T.
 .Pp
 Sections with
 .Ic inherit Ar parent
@@ -393,6 +435,9 @@
 .Pp
 .Bl -tag -width Ds -compact
 .\"
+.It Ic remote_address Ar address ;
+Defines the IP address of the peer.
+.\"
 .It Ic exchange_mode ( main | aggressive | base ) ;
 Defines the exchange mode for phase 1 when racoon is the initiator.
 It also means the acceptable exchange mode when racoon is the responder.
@@ -408,14 +453,7 @@
 Means to use SIT_IDENTITY_ONLY as specified in RFC 2407.
 You can omit this statement.
 .\"
-.It Ic identifier Ar idtype ;
-This statment is obsolete. Instead, use
-.Ic my_identifier .
-.\"
-.It Xo
-.Ic my_identifier Bq Ar qualifier
-.Ar idtype ... ;
-.Xc
+.It Ic my_identifier Bo Ar qualifier Bc Ar idtype ... ;
 Specifies the identifier sent to the remote host
 and the type to use in the phase 1 negotiation.
 .Ic address, fqdn , user_fqdn , keyid ,
@@ -440,10 +478,7 @@
 The type is a USER_FQDN (user fully-qualified domain name).
 .It Ic my_identifier Ic fqdn Ar string ;
 The type is a FQDN (fully-qualified domain name).
-.It Xo
-.Ic my_identifier Ic keyid Bq Ic file
-.Ar file ;
-.Xc
+.It Ic my_identifier Ic keyid Bo Ic file Bc Ar file ;
 The type is a KEY_ID, read from the file.
 .It Ic my_identifier Ic keyid Ic tag Ar string ;
 The type is a KEY_ID, specified in the quoted string.
@@ -482,6 +517,13 @@
 identifier may specified as
 .Ic *
 to match any value (e.g. "C=XX, O=MyOrg, OU=*, CN=Mine").
+The format of the
+specification should correspond to RFC 2253; in particular, commas and certain
+other characters -
+.Ic ,=+\*[Lt]\*[Gt]#;
+- may be included in a name by preceeding them with a backslash "\e", and
+arbitrary characters may be inserted in a name with the "\enn" escape, where
+nn is the hex representation of the ascii value of the desired character.
 Alternative acceptable peer identifiers may be specified by repeating the
 .Ic peers_identifier
 statement.
@@ -509,7 +551,9 @@
 .Bl -tag -width Ds -compact
 .It Ic plain_rsa Ar privkeyfile ;
 .Ar privkeyfile
-means a file name of a private key generated by plainrsa-gen(8).  Required
+means a file name of a private key generated by
+.Xr plainrsa-gen 8 .
+Required
 for RSA authentication.
 .El
 .It Ic ca_type Ar cacertspec ;
@@ -553,16 +597,20 @@
 .Xr racoon 8
 will expect
 .Ar pubkeyfile
-to be the peer's public key that was generated
-by plainrsa-gen(8).
+to be the peer's public key that was generated by
+.Xr plainrsa-gen 8 .
 .\"
 .It Ic script Ar script Ic phase1_up
 .It Ic script Ar script Ic phase1_down
-Shell scripts that get executed when a phase 1 SA goes up or down.
-Both scripts get either
+.It Ic script Ar script Ic phase1_dead
+Shell scripts that get executed when a phase 1 SA goes up or down, or
+when it is detected as dead by DPD.
+All scripts get either
 .Ic phase1_up
-or
+,
 .Ic phase1_down
+or
+.Ic phase1_dead
 as first argument, and the following
 variables are set in their environment:
 .Bl -tag -width Ds -compact
@@ -574,6 +622,8 @@
 The remote address of the phase 1 SA.
 .It Ev REMOTE_PORT
 The remote port used for IKE for the phase 1 SA.
+.It Ev REMOTE_ID
+The remote identity received in IKE for the phase 1 SA.
 .El
 The following variables are only set if
 .Ic mode_cfg
@@ -604,6 +654,10 @@
 The space separated list of IPv4 addresses and masks (address slash mask)
 that define the networks to be considered local, and thus excluded from the
 tunnels ; obtained by ISAKMP mode config.
+.It SPLIT_INCLUDE_CIDR
+Same as SPLIT_INCLUDE, with netmasks in CIDR notation.
+.It SPLIT_LOCAL_CIDR
+Same as SPLIT_LOCAL, with netmasks in CIDR notation.
 .It DEFAULT_DOMAIN
 The DNS default domain name obtained by ISAKMP mode config.
 .El
@@ -617,16 +671,21 @@
 If you do not want to send a certificate request, set this to off.
 The default is on.
 .\"
+.It Ic match_empty_cr (on | off) ;
+Specifies whether this remote block is a valid match when a non-specific
+certificate request is received.
+The default is on.
+.\"
 .It Ic verify_cert (on | off) ;
 By default, the identifier sent by the remote host (as specified in its
 .Ic my_identifier
 statement) is compared with the credentials in the certificate
 used to authenticate the remote host as follows:
 .Bl -tag -width Ds -compact
-.It Type Ic asn1dn:
+.It Type Ic asn1dn :
 The entire certificate subject name is compared with the identifier,
 e.g. "C=XX, O=YY, ...".
-.It Type Ic address, fqdn, or user_fqdn:
+.It Type Ic address, fqdn, or user_fqdn :
 The certificate's subjectAltName is compared with the identifier.
 .El
 If the two do not match the negotiation will fail.
@@ -692,7 +751,7 @@
 It is useful for a server.
 .\"
 .It Ic proposal_check Ar level ;
-Specifies the action of lifetime length, key length and PFS of the phase 2
+Specifies the action of lifetime length, key length, and PFS of the phase 2
 selection on the responder side, and the action of lifetime check in
 phase 1.
 The default level is
@@ -812,6 +871,22 @@
 The default value is
 .Ic 5 .
 .\"
+.It Ic rekey (on | off | force) ;
+Enable automatic renegotiation of expired phase1 when there are non-dying
+phase2 SAs.
+Possible values are:
+.Bl -tag -width Ds -compact
+.It Ic force
+Rekeying is done unconditionally.
+.It Ic on
+Rekeying is done only if DPD monitoring is active.
+This is the default.
+.It Ic off
+No automatic rekeying.
+Do note that turning off automatic rekeying will
+result in inaccurate DPD monitoring.
+.El
+.\"
 .It Ic nonce_size Ar number ;
 define the byte size of nonce value.
 Racoon can send any value although
@@ -819,13 +894,11 @@
 The default size is 16 bytes.
 .\"
 .It Ic ph1id Ar number ;
-An optionnal number to identify the remote proposal and to link it
+An optional number to identify the remote proposal and to link it
 only with sainfos who have the same number.
 Defaults to 0.
 .\"
-.It Xo
-.Ic proposal { Ar sub-substatements Ic }
-.Xc
+.It Ic proposal { Ar sub-substatements Ic }
 .Bl -tag -width Ds -compact
 .\"
 .It Ic encryption_algorithm Ar algorithm ;
@@ -888,30 +961,35 @@
 command.
 .El
 .El
+.Pp
+.It Ic remote Po Ar address | Ic anonymous Pc Bo Bo Ar port Bc Bc \
+Bo Ic inherit Ar parent Bc Ic { Ar statements Ic }
+Deprecated format of specifying a remote block.
+This will be removed in future.
+It is a remnant from time when remote block was decided
+solely based on the peers IP address.
+.Pp
+This is equivalent to:
+.Bd -literal -offset
+remote "address" [inherit "parent-address"] {
+	remote_address address;
+}
+.Ed
 .El
 .\"
-.Ss Policy Specifications
-The policy directive is obsolete, policies are now in the SPD.
-.Xr racoon 8
-will obey the policy configured into the kernel by
-.Xr setkey 8 ,
-and will construct phase 2 proposals by combining
-.Ic sainfo
-specifications in
-.Nm ,
-and policies in the kernel.
-.\"
 .Ss Sainfo Specifications
 .Bl -tag -width Ds -compact
-.It Xo
-.Ic sainfo ( Ar source_id destination_id | Ar source_id Ic anonymous | Ic anonymous Ar destination_id | Ic anonymous ) [ from Ar idtype [ Ar string ] ] [ Ic group Ar string ]
-.Ic { Ar statements Ic }
-.Xc
-defines the parameters of the IKE phase 2 (IPsec-SA establishment).
-.Ar source_id
+.It Ic sainfo Po Ar local_id | Ic anonymous Pc \
+Po Ar remote_id | Ic clientaddr | Ic anonymous Pc \
+Bo Ic from Ar idtype Bo Ar string Bc Bc Bo Ic group Ar string Bc \
+Ic { Ar statements Ic }
+Defines the parameters of the IKE phase 2 (IPsec-SA establishment).
+.Pp
+The
+.Ar local_id
 and
-.Ar destination_id
-are constructed like:
+.Ar remote_id
+strings are constructed like:
 .Pp
 .Ic address Ar address
 .Bq Ic / Ar prefix
@@ -925,17 +1003,11 @@
 .Bq Ic [ Ar port ]
 .Ar ul_proto
 .Pp
-or
-.Pp
-.Ar idtype Ar string
-.Pp
-An id string should be expressed to match the exact value of an ID payload
-(source is the local end, destination is the remote end).
+An id string should be expressed to match the exact value of an ID payload.
 This is not like a filter rule.
 For example, if you define 3ffe:501:4819::/48 as
-.Ar source_id .
+.Ar local_id .
 3ffe:501:4819:1000:/64 will not match.
-.Pp
 In the case of a longest prefix (selecting a single host),
 .Ar address
 instructs to send ID type of ADDRESS while
@@ -943,7 +1015,24 @@
 instructs to send ID type of SUBNET.
 Otherwise, these instructions are identical.
 .Pp
-The group keyword allows an XAuth group membership check to be performed
+The
+.Ic anonymous
+keyword can be used to match any id.
+The
+.Ic clientaddr
+keyword can be used to match a remote id that is equal to either the peer
+ip address or the mode_cfg ip address (if assigned).
+This can be useful
+to restrict policy generation when racoon is acting as a client gateway
+for peers with dynamic ip addresses.
+.Pp
+The
+.Ic from
+keyword allows an sainfo to only match for peers that use a specific phase1
+id value during authentication.
+The
+.Ic group
+keyword allows an XAuth group membership check to be performed
 for this sainfo section.
 When the mode_cfg auth source is set to
 .Ic system
@@ -977,10 +1066,6 @@
 Sainfos will only be used if their remoteid matches the ph1id of the
 remote section used for phase 1.
 Defaults to 0, which is also the default for ph1id.
-.\"
-.It Ic my_identifier Ar idtype ... ;
-is obsolete.
-It does not make sense to specify an identifier in the phase 2.
 .El
 .\"
 .Pp
@@ -1037,7 +1122,7 @@
 .Ar level
 is one of following:
 .Ic error , warning , notify , info , debug
-and
+or
 .Ic debug2 .
 The default is
 .Ic info .
@@ -1091,8 +1176,10 @@
 means to use a RADIUS server.
 It works only if
 .Xr racoon 8
-was built with libradius support. Radius configuration is hanlded by
-.Xr radius.conf 5 .
+was built with libradius support.
+Radius configuration is handled by statements in the
+.Ic radiuscfg
+section.
 .Ar pam
 means to use PAM.
 It works only if
@@ -1102,8 +1189,8 @@
 means to use LDAP.
 It works only if
 .Xr racoon 8
-was built with libldap support. LDAP configuration is handled by
-statements in the
+was built with libldap support.
+LDAP configuration is handled by statements in the
 .Ic ldapcfg
 section.
 .It Ic auth_groups Ar "group1", ... ;
@@ -1111,7 +1198,7 @@
 When defined, the authenticating user must be a member of at least one
 group for Xauth to succeed.
 .It Ic group_source (system | ldap) ;
-Specifies the source for group validataion of users through Xauth.
+Specifies the source for group validation of users through Xauth.
 .Ar system
 means to use the Unix user database.
 This is the default.
@@ -1137,9 +1224,10 @@
 means to use a RADIUS server.
 It works only if
 .Xr racoon 8
-was built with libradius support and requires RADIUS authentiation.
-RADIUS configuration is handled by
-.Xr radius.conf 5 .
+was built with libradius support and requires RADIUS authentication.
+RADIUS configuration is handled by statements in the
+.Ic radiuscfg
+section.
 .Ar ldap
 means to use an LDAP server.
 It works only if
@@ -1164,8 +1252,9 @@
 It works only if
 .Xr racoon 8
 was built with libradius support and requires RADIUS authentication.
-RADIUS configuration is handled by
-.Xr radius.conf 5 .
+RADIUS configuration is handled by statements in the
+.Ic radiuscfg
+section.
 Specifying
 .Ar pam
 enables PAM accounting.
@@ -1198,12 +1287,13 @@
 .Ic dns4
 lines.
 .It Ic wins4 Ar addresses ;
-A list of IPv4 address for WINS servers. The keyword
+A list of IPv4 address for WINS servers.
+The keyword
 .It nbns4
 can also be used as an alias for
 .It wins4 .
 .It Ic split_network (include | local_lan) Ar network/mask, ...
-The network configuration to send, in cidr notation (e.g. 192.168.1.0/24).
+The network configuration to send, in CIDR notation (e.g. 192.168.1.0/24).
 If
 .Ic include
 is specified, the tunnel should be only used to encrypt the indicated
@@ -1255,11 +1345,11 @@
 The host name or ip address of the ldap server.
 The default is
 .Ic localhost .
-.It Ic port Ar number;
+.It Ic port Ar number ;
 The port that the ldap server is configured to listen on.
 The default is
 .Ic 389 .
-.It Ic base Ar distinguished name;
+.It Ic base Ar distinguished name ;
 The ldap search base.
 This option has no default value.
 .It Ic subtree (on | off) ;
@@ -1267,20 +1357,20 @@
 Otherwise, use the one level search scope.
 The default is
 .Ic off .
-.It Ic bind_dn Ar distinguised name;
-The user dn used to optionaly bind as before performing ldap search operations.
+.It Ic bind_dn Ar distinguished name ;
+The user dn used to optionally bind as before performing ldap search operations.
 If this option is not specified, anonymous binds are used.
-.It Ic bind_pw Ar string;
+.It Ic bind_pw Ar string ;
 The password used when binding as
 .Ic bind_dn .
-.It Ic attr_user Ar attribute name;
+.It Ic attr_user Ar attribute name ;
 The attribute used to specify a users name in an ldap directory.
 For example,
 if a user dn is "cn=jdoe,dc=my,dc=net" then the attribute would be "cn".
 The default value is
 .Ic cn .
-.It Ic attr_addr Ar attribute name;
-.It Ic attr_mask Ar attribute name;
+.It Ic attr_addr Ar attribute name ;
+.It Ic attr_mask Ar attribute name ;
 The attributes used to specify a users network address and subnet mask in an
 ldap directory.
 These values are forwarded during mode_cfg negotiation when
@@ -1289,18 +1379,54 @@
 .Ic racoon-address
 and
 .Ic racoon-netmask .
-.It Ic attr_group Ar attribute name;
+.It Ic attr_group Ar attribute name ;
 The attribute used to specify a group name in an ldap directory.
 For example,
 if a group dn is "cn=users,dc=my,dc=net" then the attribute would be "cn".
 The default value is
 .Ic cn .
-.It Ic attr_member Ar attribute name;
+.It Ic attr_member Ar attribute name ;
 The attribute used to specify group membership in an ldap directory.
 The default value is
 .Ic member .
 .El
 .El
+.Ss Radius configuration settings
+.Bl -tag -width Ds -compact
+.It Ic radiuscfg { Ar statements Ic }
+Defines the parameters that will be used to communicate with radius
+servers for
+.Ic xauth
+authentication.
+If radius is selected as the xauth authentication or accounting
+source and no servers are defined in this section, settings from
+the system
+.Xr radius.conf 5
+configuration file will be used instead.
+.Pp
+The following are valid statements:
+.Bl -tag -width Ds -compact
+.It Ic auth Ar (hostname | address) [port] sharedsecret ;
+The host name or ip address, optional port value and shared secret value
+of a radius authentication server.
+Up to 5 radius authentication servers
+may be specified using multiple lines.
+.It Ic acct Ar (hostname | address) [port] sharedsecret ;
+The host name or ip address, optional port value and shared secret value
+of a radius accounting server.
+Up to 5 radius accounting servers may be
+specified using multiple lines.
+.It Ic timeout Ar seconds ;
+The timeout for receiving replies from radius servers.
+The default is
+.Ic 3 .
+.It Ic retries Ar count ;
+The maximum number of repeated requests to make before giving up
+on a radius server.
+The default is
+.Ic 3 .
+.El
+.El
 .Ss Special directives
 .Bl -tag -width Ds -compact
 .It Ic complex_bundle (on | off) ;
diff --git a/src/racoon/racoonctl.8 b/src/racoon/racoonctl.8
index b27b188..697f3ed 100644
--- a/src/racoon/racoonctl.8
+++ b/src/racoon/racoonctl.8
@@ -1,4 +1,4 @@
-.\"	$NetBSD: racoonctl.8,v 1.13 2006/09/09 16:22:10 manu Exp $
+.\"	$NetBSD: racoonctl.8,v 1.22 2009/03/12 14:01:09 wiz Exp $
 .\"
 .\" Id: racoonctl.8,v 1.6 2006/05/07 21:32:59 manubsd Exp
 .\"
@@ -29,7 +29,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd November 16, 2004
+.Dd March 12, 2009
 .Dt RACOONCTL 8
 .Os
 .\"
@@ -39,34 +39,49 @@
 .\"
 .Sh SYNOPSIS
 .Nm
+.Op opts
 reload-config
 .Nm
+.Op opts
 show-schedule
 .Nm
-.Op Fl l Op Fl l
+.Op opts
 show-sa
 .Op isakmp|esp|ah|ipsec
 .Nm
+.Op opts
+get-sa-cert
+.Op inet|inet6
+.Ar src dst
+.Nm
+.Op opts
 flush-sa
 .Op isakmp|esp|ah|ipsec
 .Nm
+.Op opts
 delete-sa
 .Ar saopts
 .Nm
+.Op opts
 establish-sa
+.Op Fl w
+.Op Fl n Ar remoteconf
 .Op Fl u Ar identity
 .Ar saopts
 .Nm
+.Op opts
 vpn-connect
-.Op Fl u identity
+.Op Fl u Ar identity
 .Ar vpn_gateway
 .Nm
+.Op opts
 vpn-disconnect
 .Ar vpn_gateway
 .Nm
+.Op opts
 show-event
-.Op Fl l
 .Nm
+.Op opts
 logout-user
 .Ar login
 .\"
@@ -85,6 +100,19 @@
 .Xr racoon 8
 behavior, so do that with caution.
 .Pp
+The following general options are available:
+.Bl -tag -width Ds
+.It Fl d
+Debug mode.
+Hexdump sent admin port commands.
+.It Fl l
+Increase verbosity.
+Mainly for show-sa command.
+.It Fl s Ar socket
+Specify unix socket name used to connecting racoon.
+.El
+.\"
+.Pp
 The following commands are available:
 .Bl -tag -width Ds
 .It reload-config
@@ -99,33 +127,41 @@
 Use
 .Fl l
 to increase verbosity.
+.It get-sa-cert Oo inet|inet6 Oc Ar src dst
+Output the raw certificate that was used to authenticate the phase 1
+matching
+.Ar src
+and
+.Ar dst .
 .It flush-sa Op isakmp|esp|ah|ipsec
 is used to flush all SAs if no SA class is provided, or a class of SAs,
 either ISAKMP SAs, IPsec ESP SAs, IPsec AH SAs, or all IPsec SAs.
-.It Xo establish-sa
-.Oo Fl u Ar username
-.Oc Ar saopts
-.Xc
+.It establish-sa Oo Fl w Oc Oo Fl n Ar remoteconf Oc Oo Fl u Ar username \
+Oc Ar saopts
 Establish an SA, either an ISAKMP SA, IPsec ESP SA, or IPsec AH SA.
 The optional
 .Fl u Ar username
 can be used when establishing an ISAKMP SA while hybrid auth is in use.
+The exact remote block to use can be specified with
+.Fl n Ar remoteconf .
 .Nm
 will prompt you for the password associated with
 .Ar username
 and these credentials will be used in the Xauth exchange.
 .Pp
+Specifying
+.Fl w
+will make racoonctl wait until the SA is actually established or
+an error occurs.
+.Pp
 .Ar saopts
 has the following format:
 .Bl -tag -width Bl
 .It isakmp {inet|inet6} Ar src Ar dst
 .It {esp|ah} {inet|inet6} Ar src/prefixlen/port Ar dst/prefixlen/port
-{icmp|tcp|udp|any}
+{icmp|tcp|udp|gre|any}
 .El
-.It Xo vpn-connect
-.Oo Fl u Ar username
-.Oc Ar vpn_gateway
-.Xc
+.It vpn-connect Oo Fl u Ar username Oc Ar vpn_gateway
 This is a particular case of the previous command.
 It will establish an ISAKMP SA with
 .Ar vpn_gateway .
@@ -135,16 +171,9 @@
 This is a particular case of the previous command.
 It will kill all SAs associated with
 .Ar vpn_gateway .
-.It show-event Op Fl l
-Dump all events reported by
-.Xr racoon 8 ,
-then quit.
-The
-.Fl l
-flag causes
-.Nm
-to not stop once all the events have been read, but rather to loop
-awaiting and reporting new events.
+.It show-event
+Listen for all events reported by
+.Xr racoon 8 .
 .It logout-user Ar login
 Delete all SA established on behalf of the Xauth user
 .Ar login .
diff --git a/src/racoon/racoonctl.c b/src/racoon/racoonctl.c
index 1dd26f0..da28ecd 100644
--- a/src/racoon/racoonctl.c
+++ b/src/racoon/racoonctl.c
@@ -1,9 +1,10 @@
-/*	$NetBSD: racoonctl.c,v 1.7.6.2 2009/04/20 13:32:57 tteras Exp $	*/
+/*	$NetBSD: racoonctl.c,v 1.18 2010/11/12 09:08:26 tteras Exp $	*/
 
 /*	Id: racoonctl.c,v 1.11 2006/04/06 17:06:25 manubsd Exp */
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * Copyright (C) 2008 Timo Teras.
  * All rights reserved.
  * 
  * Redistribution and use in source and binary forms, with or without
@@ -92,6 +93,7 @@
 static vchar_t *f_reload __P((int, char **));
 static vchar_t *f_getsched __P((int, char **));
 static vchar_t *f_getsa __P((int, char **));
+static vchar_t *f_getsacert __P((int, char **));
 static vchar_t *f_flushsa __P((int, char **));
 static vchar_t *f_deletesa __P((int, char **));
 static vchar_t *f_exchangesa __P((int, char **));
@@ -104,59 +106,59 @@
 
 struct cmd_tag {
 	vchar_t *(*func) __P((int, char **));
-	int cmd;
 	char *str;
 } cmdtab[] = {
-	{ f_reload,	ADMIN_RELOAD_CONF,	"reload-config" },
-	{ f_reload,	ADMIN_RELOAD_CONF,	"rc" },
-	{ f_getsched,	ADMIN_SHOW_SCHED,	"show-schedule" },
-	{ f_getsched,	ADMIN_SHOW_SCHED,	"sc" },
-	{ f_getsa,	ADMIN_SHOW_SA,		"show-sa" },
-	{ f_getsa,	ADMIN_SHOW_SA,		"ss" },
-	{ f_flushsa,	ADMIN_FLUSH_SA,		"flush-sa" },
-	{ f_flushsa,	ADMIN_FLUSH_SA,		"fs" },
-	{ f_deletesa,	ADMIN_DELETE_SA,	"delete-sa" },
-	{ f_deletesa,	ADMIN_DELETE_SA,	"ds" },
-	{ f_exchangesa,	ADMIN_ESTABLISH_SA,	"establish-sa" },
-	{ f_exchangesa,	ADMIN_ESTABLISH_SA,	"es" },
-	{ f_vpnc,	ADMIN_ESTABLISH_SA,	"vpn-connect" },
-	{ f_vpnc,	ADMIN_ESTABLISH_SA,	"vc" },
-	{ f_vpnd,	ADMIN_DELETE_ALL_SA_DST,"vpn-disconnect" },
-	{ f_vpnd,	ADMIN_DELETE_ALL_SA_DST,"vd" },
-	{ f_getevt,	ADMIN_SHOW_EVT,		"show-event" },
-	{ f_getevt,	ADMIN_SHOW_EVT,		"se" },
+	{ f_reload,	"reload-config" },
+	{ f_reload,	"rc" },
+	{ f_getsched,	"show-schedule" },
+	{ f_getsched,	"sc" },
+	{ f_getsa,	"show-sa" },
+	{ f_getsa,	"ss" },
+	{ f_getsacert,	"get-cert" },
+	{ f_getsacert,	"gc" },
+	{ f_flushsa,	"flush-sa" },
+	{ f_flushsa,	"fs" },
+	{ f_deletesa,	"delete-sa" },
+	{ f_deletesa,	"ds" },
+	{ f_exchangesa,	"establish-sa" },
+	{ f_exchangesa,	"es" },
+	{ f_vpnc,	"vpn-connect" },
+	{ f_vpnc,	"vc" },
+	{ f_vpnd,	"vpn-disconnect" },
+	{ f_vpnd,	"vd" },
+	{ f_getevt,	"show-event" },
+	{ f_getevt,	"se" },
 #ifdef ENABLE_HYBRID
-	{ f_logoutusr,	ADMIN_LOGOUT_USER,	"logout-user" },
-	{ f_logoutusr,	ADMIN_LOGOUT_USER,	"lu" },
+	{ f_logoutusr,	"logout-user" },
+	{ f_logoutusr,	"lu" },
 #endif
-	{ NULL, 0, NULL },
+	{ NULL, NULL },
 };
 
 struct evtmsg {
 	int type;
 	char *msg;
-	enum { UNSPEC, ERROR, INFO } level;
 } evtmsg[] = {
-	{ EVTT_PHASE1_UP, "Phase 1 established", INFO },
-	{ EVTT_PHASE1_DOWN, "Phase 1 deleted", INFO },
-	{ EVTT_XAUTH_SUCCESS, "Xauth exchange passed", INFO },
-	{ EVTT_ISAKMP_CFG_DONE, "ISAKMP mode config done", INFO },
-	{ EVTT_PHASE2_UP, "Phase 2 established", INFO },
-	{ EVTT_PHASE2_DOWN, "Phase 2 deleted", INFO },
-	{ EVTT_DPD_TIMEOUT, "Peer not reachable anymore", ERROR },
-	{ EVTT_PEER_NO_RESPONSE, "Peer not responding", ERROR },
-	{ EVTT_PEER_DELETE, "Peer terminated security association", ERROR },
-	{ EVTT_RACOON_QUIT, "Raccon terminated", ERROR },
-	{ EVTT_OVERFLOW, "Event queue overflow", ERROR },
-	{ EVTT_XAUTH_FAILED, "Xauth exchange failed", ERROR },
-	{ EVTT_PEERPH1AUTH_FAILED, "Peer failed phase 1 authentication "
-	    "(certificate problem?)", ERROR },
-	{ EVTT_PEERPH1_NOPROP, "Peer failed phase 1 initiation "
-	    "(proposal problem?)", ERROR },
-	{ 0, NULL, UNSPEC },
-	{ EVTT_NO_ISAKMP_CFG, "No need for ISAKMP mode config ", INFO },
+	{ EVT_RACOON_QUIT,		"Racoon terminated" },
+
+	{ EVT_PHASE1_UP,		"Phase 1 established" },
+	{ EVT_PHASE1_DOWN,		"Phase 1 deleted" },
+	{ EVT_PHASE1_NO_RESPONSE,	"Phase 1 error: peer not responding" },
+	{ EVT_PHASE1_NO_PROPOSAL,	"Phase 1 error: no proposal chosen" },
+	{ EVT_PHASE1_AUTH_FAILED,
+	  "Phase 1 error: authentication failed (bad certificate?)" },
+	{ EVT_PHASE1_DPD_TIMEOUT,	"Phase 1 error: dead peer detected" },
+	{ EVT_PHASE1_MODE_CFG,		"Phase 1 mode configuration done" },
+	{ EVT_PHASE1_XAUTH_SUCCESS,	"Phase 1 Xauth succeeded" },
+	{ EVT_PHASE1_XAUTH_FAILED,	"Phase 1 Xauth failed" },
+
+	{ EVT_PHASE2_NO_PHASE1,		"Phase 2 error: no suitable phase 1" },
+	{ EVT_PHASE2_UP,		"Phase 2 established" },
+	{ EVT_PHASE2_DOWN,		"Phase 2 deleted" },
+	{ EVT_PHASE2_NO_RESPONSE,	"Phase 2 error: no response" },
 };
 
+static vchar_t *get_proto_and_index __P((int, char **, u_int16_t *));
 static int get_proto __P((char *));
 static vchar_t *get_index __P((int, char **));
 static int get_family __P((char *));
@@ -184,6 +186,7 @@
 	{ IPPROTO_ICMP,	"icmp" },
 	{ IPPROTO_TCP,	"tcp" },
 	{ IPPROTO_UDP,	"udp" },
+	{ IPPROTO_GRE,	"gre" },
 	{ 0, NULL },
 };
 
@@ -193,31 +196,13 @@
 
 char *pname;
 int long_format = 0;
-
-#define EVTF_NONE		0x0000	/* Ignore any events */
-#define EVTF_LOOP		0x0001	/* Loop awaiting for new events */
-#define EVTF_CFG_STOP		0x0002	/* Stop after ISAKMP mode config */
-#define EVTF_CFG		0x0004	/* Print ISAKMP mode config info */
-#define EVTF_ALL		0x0008	/* Print any events */
-#define EVTF_PURGE		0x0010	/* Print all available events */
-#define EVTF_PH1DOWN_STOP	0x0020	/* Stop when phase 1 SA gets down */
-#define EVTF_PH1DOWN		0x0040	/* Print that phase 1 SA got down */
-#define EVTF_ERR		0x0080	/* Print any error */
-#define EVTF_ERR_STOP		0x0100	/* Stop on any error */
-
-int evt_filter = EVTF_NONE;
-time_t evt_start;
+int evt_quit_event = 0;
 
 void dump_isakmp_sa __P((char *, int));
 void dump_internal __P((char *, int));
 char *pindex_isakmp __P((isakmp_index *));
 void print_schedule __P((caddr_t, int));
-void print_evt __P((caddr_t, int));
-void print_cfg __P((caddr_t, int));
-void print_err __P((caddr_t, int));
-void print_ph1down __P((caddr_t, int));
-void print_ph1up __P((caddr_t, int));
-int evt_poll __P((void));
+void print_evt __P((struct evt_async *));
 char * fixed_addr __P((char *, char *, int));
 
 static void
@@ -225,14 +210,23 @@
 {
 	printf(
 "Usage:\n"
-"  %s reload-config\n"
-"  %s [-l [-l]] show-sa [protocol]\n"
-"  %s flush-sa [protocol]\n"
-"  %s delete-sa <saopts>\n"
-"  %s establish-sa [-u identity] <saopts>\n"
-"  %s vpn-connect [-u identity] vpn_gateway\n"
-"  %s vpn-disconnect vpn_gateway\n"
+"  %s [opts] reload-config\n"
+"  %s [opts] show-schedule\n"
+"  %s [opts] show-sa [protocol]\n"
+"  %s [opts] flush-sa [protocol]\n"
+"  %s [opts] delete-sa <saopts>\n"
+"  %s [opts] establish-sa [-u identity] [-n remoteconf] [-w] <saopts>\n"
+"  %s [opts] vpn-connect [-u identity] vpn_gateway\n"
+"  %s [opts] vpn-disconnect vpn_gateway\n"
+"  %s [opts] show-event\n"
+"  %s [opts] logout-user login\n"
 "\n"
+"General options:\n"
+"  -d		Debug: hexdump admin messages before sending\n"
+"  -l		Increase output verbosity (mainly for show-sa)\n"
+"  -s <socket>	Specify adminport socket to use (default: %s)\n"
+"\n"
+"Parameter specifications:\n"
 "    <protocol>: \"isakmp\", \"esp\" or \"ah\".\n"
 "        In the case of \"show-sa\" or \"flush-sa\", you can use \"ipsec\".\n"
 "\n"
@@ -240,8 +234,10 @@
 "            : {\"esp\",\"ah\"} <family> <src/prefixlen/port> <dst/prefixlen/port>\n"
 "                              <ul_proto>\n"
 "    <family>: \"inet\" or \"inet6\"\n"
-"    <ul_proto>: \"icmp\", \"tcp\", \"udp\" or \"any\"\n",
-	pname, pname, pname, pname, pname, pname, pname);
+"    <ul_proto>: \"icmp\", \"tcp\", \"udp\", \"gre\" or \"any\"\n"
+"\n",
+		pname, pname, pname, pname, pname, pname, pname, pname, pname, pname,
+		ADMINSOCK_PATH);
 }
 
 /*
@@ -312,54 +308,24 @@
 
 	vfree(combuf);
 
-	if (com_recv(&combuf) != 0)
-		goto bad;
-	if (handle_recv(combuf) != 0)
-		goto bad;
+	do {
+		if (com_recv(&combuf) != 0)
+			goto bad;
+		if (handle_recv(combuf) != 0)
+			goto bad;
+		vfree(combuf);
+	} while (evt_quit_event != 0);
 
-	vfree(combuf);
-
-	if (evt_filter != EVTF_NONE)
-		if (evt_poll() != 0)
-			goto bad;	
-	
+	close(so);
 	exit(0);
 
-    bad:
+bad:
+	close(so);
+	if (errno == EEXIST)
+		exit(0);
 	exit(1);
 }
 
-int
-evt_poll(void) {
-	struct timeval tv;
-	vchar_t *recvbuf;
-	vchar_t *sendbuf;
-
-	if ((sendbuf = f_getevt(0, NULL)) == NULL)
-		errx(1, "Cannot make combuf");
-
-
-	while (evt_filter & (EVTF_LOOP|EVTF_PURGE)) {
-		/* handle_recv closes the socket time, so open it each time */
-		com_init();
-
-		if (com_send(sendbuf) != 0)
-			errx(1, "Cannot send combuf");
-
-		if (com_recv(&recvbuf) == 0) {
-			handle_recv(recvbuf);
-			vfree(recvbuf);
-		}
-
-		tv.tv_sec = 0;
-		tv.tv_usec = 10;
-		(void)select(0, NULL, NULL, NULL, &tv);
-	}
-
-	vfree(sendbuf);
-	return 0;
-}
-
 /* %%% */
 /*
  * return command buffer.
@@ -394,61 +360,42 @@
 }
 
 static vchar_t *
-f_reload(ac, av)
-	int ac;
-	char **av;
+make_request(u_int16_t cmd, u_int16_t proto, size_t len)
 {
 	vchar_t *buf;
 	struct admin_com *head;
 
-	buf = vmalloc(sizeof(*head));
+	buf = vmalloc(sizeof(struct admin_com) + len);
 	if (buf == NULL)
 		errx(1, "not enough core");
 
-	head = (struct admin_com *)buf->v;
+	head = (struct admin_com *) buf->v;
 	head->ac_len = buf->l;
-	head->ac_cmd = ADMIN_RELOAD_CONF;
-	head->ac_errno = 0;
-	head->ac_proto = 0;
+	head->ac_cmd = ADMIN_FLAG_VERSION | cmd;
+	head->ac_version = 1;
+	head->ac_proto = proto;
 
 	return buf;
 }
 
 static vchar_t *
+f_reload(ac, av)
+	int ac;
+	char **av;
+{
+	return make_request(ADMIN_RELOAD_CONF, 0, 0);
+}
+
+static vchar_t *
 f_getevt(ac, av)
 	int ac;
 	char **av;
 {
-	vchar_t *buf;
-	struct admin_com *head;
-
-	/*
-	 * There are 3 ways of getting here
-	 * 1) racoonctl vc => evt_filter = (EVTF_LOOP|EVTF_CFG| ... )
-	 * 2) racoonctl es => evt_filter = EVTF_NONE
-	 * 3) racoonctl es -l => evt_filter = EVTF_LOOP
-	 * Catch the second case: show-event is here to purge all
-	 */
-	if (evt_filter == EVTF_NONE)
-		evt_filter = (EVTF_ALL|EVTF_PURGE);
-
-	if ((ac >= 1) && (strcmp(av[0], "-l") == 0))
-		evt_filter |= EVTF_LOOP;
-
-	if (ac >= 2)
+	evt_quit_event = -1;
+	if (ac >= 1)
 		errx(1, "too many arguments");
 
-	buf = vmalloc(sizeof(*head));
-	if (buf == NULL)
-		errx(1, "not enough core");
-
-	head = (struct admin_com *)buf->v;
-	head->ac_len = buf->l;
-	head->ac_cmd = ADMIN_SHOW_EVT;
-	head->ac_errno = 0;
-	head->ac_proto = 0;
-
-	return buf;
+	return make_request(ADMIN_SHOW_EVT, 0, 0);
 }
 
 static vchar_t *
@@ -456,20 +403,7 @@
 	int ac;
 	char **av;
 {
-	vchar_t *buf;
-	struct admin_com *head;
-
-	buf = vmalloc(sizeof(*head));
-	if (buf == NULL)
-		errx(1, "not enough core");
-
-	head = (struct admin_com *)buf->v;
-	head->ac_len = buf->l;
-	head->ac_cmd = ADMIN_SHOW_SCHED;
-	head->ac_errno = 0;
-	head->ac_proto = 0;
-
-	return buf;
+	return make_request(ADMIN_SHOW_SCHED, 0, 0);
 }
 
 static vchar_t *
@@ -477,8 +411,6 @@
 	int ac;
 	char **av;
 {
-	vchar_t *buf;
-	struct admin_com *head;
 	int proto;
 
 	/* need protocol */
@@ -488,15 +420,29 @@
 	if (proto == -1)
 		errx(1, "unknown protocol %s", *av);
 
-	buf = vmalloc(sizeof(*head));
-	if (buf == NULL)
-		errx(1, "not enough core");
+	return make_request(ADMIN_SHOW_SA, proto, 0);
+}
 
-	head = (struct admin_com *)buf->v;
-	head->ac_len = buf->l;
-	head->ac_cmd = ADMIN_SHOW_SA;
-	head->ac_errno = 0;
-	head->ac_proto = proto;
+static vchar_t *
+f_getsacert(ac, av)
+	int ac;
+	char **av;
+{
+	vchar_t *buf, *index;
+	struct admin_com_indexes *com;
+
+	index = get_index(ac, av);
+	if (index == NULL)
+		return NULL;
+
+	com = (struct admin_com_indexes *) index->v;
+	buf = make_request(ADMIN_GET_SA_CERT, ADMIN_PROTO_ISAKMP, index->l);
+	if (buf == NULL)
+		errx(1, "Cannot allocate buffer");
+
+	memcpy(buf->v+sizeof(struct admin_com), index->v, index->l);
+
+	vfree(index);
 
 	return buf;
 }
@@ -517,17 +463,7 @@
 	if (proto == -1)
 		errx(1, "unknown protocol %s", *av);
 
-	buf = vmalloc(sizeof(*head));
-	if (buf == NULL)
-		errx(1, "not enough core");
-
-	head = (struct admin_com *)buf->v;
-	head->ac_len = buf->l;
-	head->ac_cmd = ADMIN_FLUSH_SA;
-	head->ac_errno = 0;
-	head->ac_proto = proto;
-
-	return buf;
+	return make_request(ADMIN_FLUSH_SA, proto, 0);
 }
 
 static vchar_t *
@@ -536,7 +472,6 @@
 	char **av;
 {
 	vchar_t *buf, *index;
-	struct admin_com *head;
 	int proto;
 
 	/* need protocol */
@@ -566,17 +501,11 @@
 		return NULL;
 	}
 
-	buf = vmalloc(sizeof(*head) + index->l);
+	buf = make_request(ADMIN_DELETE_SA, proto, index->l);
 	if (buf == NULL)
 		goto out;
 
-	head = (struct admin_com *)buf->v;
-	head->ac_len = buf->l + index->l;
-	head->ac_cmd = ADMIN_DELETE_SA;
-	head->ac_errno = 0;
-	head->ac_proto = proto;
-
-	memcpy(buf->v+sizeof(*head), index->v, index->l);
+	memcpy(buf->v + sizeof(struct admin_com), index->v, index->l);
 
 out:
 	if (index != NULL)
@@ -591,47 +520,17 @@
 	char **av;
 {
 	vchar_t *buf, *index;
-	struct admin_com *head;
-	int proto;
+	u_int16_t proto;
 
-	/* need protocol */
-	if (ac < 1)
-		errx(1, "insufficient arguments");
-	proto = get_proto(*av);
-	if (proto == -1)
-		errx(1, "unknown protocol %s", *av);
-
-	/* get index(es) */
-	av++;
-	ac--;
-	switch (proto) {
-	case ADMIN_PROTO_ISAKMP:
-		index = get_index(ac, av);
-		if (index == NULL)
-			return NULL;
-		break;
-	case ADMIN_PROTO_AH:
-	case ADMIN_PROTO_ESP:
-		index = get_index(ac, av);
-		if (index == NULL)
-			return NULL;
-		break;
-	default:
-		errno = EPROTONOSUPPORT;
+	index = get_proto_and_index(ac, av, &proto);
+	if (index == NULL)
 		return NULL;
-	}
 
-	buf = vmalloc(sizeof(*head) + index->l);
+	buf = make_request(ADMIN_DELETE_ALL_SA_DST, proto, index->l);
 	if (buf == NULL)
 		goto out;
 
-	head = (struct admin_com *)buf->v;
-	head->ac_len = buf->l + index->l;
-	head->ac_cmd = ADMIN_DELETE_ALL_SA_DST;
-	head->ac_errno = 0;
-	head->ac_proto = proto;
-
-	memcpy(buf->v+sizeof(*head), index->v, index->l);
+	memcpy(buf->v+sizeof(struct admin_com), index->v, index->l);
 
 out:
 	if (index != NULL)
@@ -646,13 +545,14 @@
 	char **av;
 {
 	vchar_t *buf, *index;
-	struct admin_com *head;
-	int proto;
+	u_int16_t proto;
 	int cmd = ADMIN_ESTABLISH_SA;
 	size_t com_len = 0;
 	char *id = NULL;
 	char *key = NULL;
+	char *remoteconf = NULL;
 	struct admin_com_psk *acp;
+	int wait = 0;
 
 	if (ac < 1)
 		errx(1, "insufficient arguments");
@@ -673,48 +573,57 @@
 		ac -= 2;
 	}
 
-	/* need protocol */
-	if (ac < 1)
-		errx(1, "insufficient arguments");
-	if ((proto = get_proto(*av)) == -1)
-		errx(1, "unknown protocol %s", *av);
-
-	/* get index(es) */
-	av++;
-	ac--;
-	switch (proto) {
-	case ADMIN_PROTO_ISAKMP:
-		index = get_index(ac, av);
-		if (index == NULL)
-			return NULL;
-		break;
-	case ADMIN_PROTO_AH:
-	case ADMIN_PROTO_ESP:
-		index = get_index(ac, av);
-		if (index == NULL)
-			return NULL;
-		break;
-	default:
-		errno = EPROTONOSUPPORT;
-		return NULL;
+	if (ac >= 2 && strcmp(av[0], "-n") == 0) {
+		/* Remoteconf name */
+		remoteconf = av[1];
+		av += 2;
+		ac -= 2;
 	}
 
-	com_len += sizeof(*head) + index->l;
-	if ((buf = vmalloc(com_len)) == NULL)
+	if (ac >= 1 && strcmp(av[0], "-w") == 0) {
+		wait = 1;
+		av++;
+		ac--;
+	}
+
+	index = get_proto_and_index(ac, av, &proto);
+	if (index == NULL)
+		return NULL;
+
+	if (proto == ADMIN_PROTO_ISAKMP && cmd == ADMIN_ESTABLISH_SA &&
+	    remoteconf != NULL)
+		com_len += strlen(remoteconf) + 1;
+
+	if (wait) {
+		switch (proto) {
+		case ADMIN_PROTO_ISAKMP:
+			evt_quit_event = EVT_PHASE1_MODE_CFG;
+			break;
+		case ADMIN_PROTO_AH:
+		case ADMIN_PROTO_ESP:
+			evt_quit_event = EVT_PHASE2_UP;
+			break;
+		default:
+			errno = EPROTONOSUPPORT;
+			return NULL;
+		}
+	}
+
+	com_len += index->l;
+	buf = make_request(cmd, proto, com_len);
+	if (buf == NULL)
 		errx(1, "Cannot allocate buffer");
 
-	head = (struct admin_com *)buf->v;
-	head->ac_len = buf->l;
-	head->ac_cmd = cmd;
-	head->ac_errno = 0;
-	head->ac_proto = proto;
+	memcpy(buf->v+sizeof(struct admin_com), index->v, index->l);
 
-	memcpy(buf->v+sizeof(*head), index->v, index->l);
-
-	if (id && key) {
+	if (proto == ADMIN_PROTO_ISAKMP && cmd == ADMIN_ESTABLISH_SA &&
+	    remoteconf != NULL) {
+		strcpy(buf->v + sizeof(struct admin_com) + index->l,
+		       remoteconf);
+	} else if (id && key) {
 		char *data;
 		acp = (struct admin_com_psk *)
-		    (buf->v + sizeof(*head) + index->l);
+		    (buf->v + sizeof(struct admin_com) + index->l);
 
 		acp->id_type = IDTYPE_USERFQDN;
 		acp->id_len = strlen(id) + 1;
@@ -749,8 +658,7 @@
 	if (ac < 1)
 		errx(1, "insufficient arguments");
 
-	evt_filter = (EVTF_LOOP|EVTF_CFG|EVTF_CFG_STOP|EVTF_ERR|EVTF_ERR_STOP);
-	time(&evt_start);
+	evt_quit_event = EVT_PHASE1_MODE_CFG;
 	
 	/* Optional -u identity */
 	if (strcmp(av[0], "-u") == 0) {
@@ -765,7 +673,7 @@
 	}
 
 	if (ac < 1)
-		errx(1, "VPN gateway required");	
+		errx(1, "VPN gateway required");
 	if (ac > 1)
 		warnx("Extra arguments");
 
@@ -810,12 +718,11 @@
 	char *idx;
 
 	if (ac < 1)
-		errx(1, "VPN gateway required");	
+		errx(1, "VPN gateway required");
 	if (ac > 1)
 		warnx("Extra arguments");
 
-	evt_filter = 
-	    (EVTF_PH1DOWN|EVTF_PH1DOWN_STOP|EVTF_LOOP|EVTF_ERR|EVTF_ERR_STOP);
+	evt_quit_event = EVT_PHASE1_DOWN;
 
 	nav[nac++] = isakmp;
 	nav[nac++] = inet;
@@ -832,7 +739,6 @@
 	char **av;
 {
 	vchar_t *buf;
-	struct admin_com *head;
 	char *user;
 	size_t userlen;
 
@@ -844,22 +750,46 @@
 	if ((user == NULL) || (userlen > LOGINLEN))
 		errx(1, "bad login (too long?)");
 
-	buf = vmalloc(sizeof(*head) + userlen);
+	buf = make_request(ADMIN_LOGOUT_USER, 0, userlen);
 	if (buf == NULL)
 		return NULL;
 
-	head = (struct admin_com *)buf->v;
-	head->ac_len = buf->l;
-	head->ac_cmd = ADMIN_LOGOUT_USER;
-	head->ac_errno = 0;
-	head->ac_proto = 0;
-
-	strncpy((char *)(head + 1), user, userlen);
+	strncpy(buf->v + sizeof(struct admin_com), user, userlen);
 
 	return buf;
 }
 #endif /* ENABLE_HYBRID */
 
+static vchar_t *
+get_proto_and_index(ac, av, proto)
+	int ac;
+	char **av;
+	u_int16_t *proto;
+{
+	vchar_t *index = NULL;
+
+	/* need protocol */
+	if (ac < 1)
+		errx(1, "insufficient arguments");
+	*proto = get_proto(*av);
+	if (*proto == (u_int16_t) -1)
+		errx(1, "unknown protocol %s", *av);
+
+	/* get index(es) */
+	av++;
+	ac--;
+	switch (*proto) {
+	case ADMIN_PROTO_ISAKMP:
+	case ADMIN_PROTO_AH:
+	case ADMIN_PROTO_ESP:
+		index = get_index(ac, av);
+		break;
+	default:
+		errno = EPROTONOSUPPORT;
+		break;
+	}
+	return index;
+}
 
 static int
 get_proto(str)
@@ -1337,84 +1267,32 @@
 
 
 void
-print_evt(buf, len)
-	caddr_t buf;
-	int len;
+print_evt(evtdump)
+	struct evt_async *evtdump;
 {
-	struct evtdump *evtdump = (struct evtdump *)buf;
 	int i;
 	char *srcstr;
 	char *dststr;
 	
-	for (i = 0; evtmsg[i].msg; i++)
-		if (evtmsg[i].type == evtdump->type)
-			break;				
-	
-	if (evtmsg[i].msg == NULL) 
-		printf("Event %d: ", evtdump->type);
+	for (i = 0; i < sizeof(evtmsg) / sizeof(evtmsg[0]); i++)
+		if (evtmsg[i].type == evtdump->ec_type)
+			break;
+
+	if (evtmsg[i].msg == NULL)
+		printf("Event %d: ", evtdump->ec_type);
 	else
 		printf("%s : ", evtmsg[i].msg);
 
-	if ((srcstr = saddr2str((struct sockaddr *)&evtdump->src)) == NULL)
+	if ((srcstr = saddr2str((struct sockaddr *)&evtdump->ec_ph1src)) == NULL)
 		printf("unknown");
-	else 
+	else
 		printf("%s", srcstr);
 	printf(" -> ");
-	if ((dststr = saddr2str((struct sockaddr *)&evtdump->dst)) == NULL)
+	if ((dststr = saddr2str((struct sockaddr *)&evtdump->ec_ph1dst)) == NULL)
 		printf("unknown");
-	else 
+	else
 		printf("%s", dststr);
 	printf("\n");
-
-	return;
-}
-
-void
-print_err(buf, len)
-	caddr_t buf;
-	int len;
-{
-	struct evtdump *evtdump = (struct evtdump *)buf;
-	int i;
-	
-	
-	for (i = 0; evtmsg[i].msg; i++)
-		if (evtmsg[i].type == evtdump->type)
-			break;				
-
-	if (evtmsg[i].level != ERROR)
-		return;
-	
-	if (evtmsg[i].msg == NULL) 
-		printf("Error: Event %d\n", evtdump->type);
-	else
-		printf("Error: %s\n", evtmsg[i].msg);
-
-	if (evt_filter & EVTF_ERR_STOP)
-		evt_filter &= ~EVTF_LOOP;
-
-	return;
-}
-
-/*
- * Print a message when phase 1 SA goes down
- */
-void
-print_ph1down(buf, len)
-	caddr_t buf;
-	int len;
-{
-	struct evtdump *evtdump = (struct evtdump *)buf;
-	
-	if (evtdump->type != EVTT_PHASE1_DOWN)
-		return;
-
-	printf("VPN connexion terminated\n");
-
-	if (evt_filter & EVTF_PH1DOWN_STOP)
-		evt_filter &= ~EVTF_LOOP;
-	
-	return;
 }
 
 /*
@@ -1425,15 +1303,14 @@
 	caddr_t buf;
 	int len;
 {
-	struct evtdump *evtdump = (struct evtdump *)buf;
+	struct evt_async *evtdump = (struct evt_async *)buf;
 	struct isakmp_data *attr;
 	char *banner = NULL;
 	struct in_addr addr4;
 	
 	memset(&addr4, 0, sizeof(addr4));
 
-	if (evtdump->type != EVTT_ISAKMP_CFG_DONE && 
-	    evtdump->type != EVTT_NO_ISAKMP_CFG)
+	if (evtdump->ec_type != EVT_PHASE1_MODE_CFG)
 		return;
 
 	len -= sizeof(*evtdump);
@@ -1486,12 +1363,12 @@
 			    (n + sizeof(*attr) + ntohs(attr->lorv));
 		}
 	}
-	
-	if (evtdump->type == EVTT_ISAKMP_CFG_DONE)
+
+	if (len > 0)
 		printf("Bound to address %s\n", inet_ntoa(addr4));
 	else
 		printf("VPN connexion established\n");
-	
+
 	if (banner) {
 		struct winsize win;
 		int col = 0;
@@ -1508,13 +1385,8 @@
 		printf("\n");
 		racoon_free(banner);
 	}
-	
-	if (evt_filter & EVTF_CFG_STOP)
-		evt_filter &= ~EVTF_LOOP;
-	
-	return;
 }
-	
+
 
 char *
 fixed_addr(addr, port, len)
@@ -1549,49 +1421,54 @@
 handle_recv(combuf)
 	vchar_t *combuf;
 {
-        struct admin_com h, *com;
+        struct admin_com *com;
         caddr_t buf;
         int len;
 
 	com = (struct admin_com *)combuf->v;
-	len = com->ac_len - sizeof(*com);
+	if (com->ac_cmd & ADMIN_FLAG_LONG_REPLY)
+		len = ((u_int32_t)com->ac_len) + (((u_int32_t)com->ac_len_high) << 16);
+	else
+		len = com->ac_len;
+	len -= sizeof(*com);
 	buf = combuf->v + sizeof(*com);
 
-	switch (com->ac_cmd) {
+	switch (com->ac_cmd & ~ADMIN_FLAG_LONG_REPLY) {
 	case ADMIN_SHOW_SCHED:
 		print_schedule(buf, len);
 		break;
 
 	case ADMIN_SHOW_EVT: {
-		struct evtdump *evtdump;
+		struct evt_async *ec;
 
-		/* We got no event */
-		if (len == 0) {
-			/* If we were purging the queue, it is now done */
-			if (evt_filter & EVTF_PURGE)
-				evt_filter &= ~EVTF_PURGE;
+		/* We got no event? */
+		if (len == 0)
 			break;
+
+		if (len < sizeof(struct evt_async))
+			errx(1, "Short buffer\n");
+
+		ec = (struct evt_async *) buf;
+		if (evt_quit_event <= 0)
+			print_evt(ec);
+		else if (evt_quit_event == ec->ec_type) {
+			switch (ec->ec_type) {
+			case EVT_PHASE1_MODE_CFG:
+				print_cfg(ec, len);
+				break;
+			default:
+				print_evt(ec);
+				break;
+			}
+			evt_quit_event = 0;
 		}
-
-		if (len < sizeof(struct evtdump))
-			errx(1, "Short buffer\n");		
-
-		/* Toss outdated events */
-		evtdump = (struct evtdump *)buf;
-		if (evtdump->timestamp < evt_start)
-			break;
-
-		if (evt_filter & EVTF_ALL)
-			print_evt(buf, len);
-		if (evt_filter & EVTF_ERR)
-			print_err(buf, len);
-		if (evt_filter & EVTF_CFG)
-			print_cfg(buf, len);
-		if (evt_filter & EVTF_PH1DOWN)
-			print_ph1down(buf, len);
 		break;
 	}
 
+	case ADMIN_GET_SA_CERT:
+		fwrite(buf, len, 1, stdout);
+		break;
+
 	case ADMIN_SHOW_SA:
 	   {
 		switch (com->ac_proto) {
@@ -1645,10 +1522,8 @@
 		break;
 	}
 
-	close(so);
 	return 0;
 
-    bad:
-	close(so);
+bad:
 	return -1;
 }
diff --git a/src/racoon/remoteconf.c b/src/racoon/remoteconf.c
index c9c803f..74e386c 100644
--- a/src/racoon/remoteconf.c
+++ b/src/racoon/remoteconf.c
@@ -1,11 +1,11 @@
-/*	$NetBSD: remoteconf.c,v 1.9.4.2 2008/06/18 07:30:19 mgrooms Exp $	*/
+/*	$NetBSD: remoteconf.c,v 1.26 2011/03/14 15:50:36 vanhu Exp $	*/
 
 /* Id: remoteconf.c,v 1.38 2006/05/06 15:52:44 manubsd Exp */
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
  * All rights reserved.
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
@@ -17,7 +17,7 @@
  * 3. Neither the name of the project nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
- * 
+ *
  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@@ -63,6 +63,7 @@
 #endif
 #include "isakmp.h"
 #include "ipsec_doi.h"
+#include "crypto_openssl.h"
 #include "oakley.h"
 #include "remoteconf.h"
 #include "localconf.h"
@@ -75,16 +76,307 @@
 #include "algorithm.h"
 #include "nattraversal.h"
 #include "isakmp_frag.h"
+#include "handler.h"
 #include "genlist.h"
+#include "rsalist.h"
 
-static TAILQ_HEAD(_rmtree, remoteconf) rmtree, rmtree_save, rmtree_tmp;
+typedef TAILQ_HEAD(_rmtree, remoteconf) remoteconf_tailq_head_t;
+static remoteconf_tailq_head_t rmtree, rmtree_save;
 
-/* 
+/*
  * Script hook names and script hook paths
  */
-char *script_names[SCRIPT_MAX + 1] = { "phase1_up", "phase1_down" };
+char *script_names[SCRIPT_MAX + 1] = {
+	"phase1_up", "phase1_down", "phase1_dead" };
 
 /*%%%*/
+
+int
+rmconf_match_identity(rmconf, id_p)
+	struct remoteconf *rmconf;
+	vchar_t *id_p;
+{
+	struct ipsecdoi_id_b *id_b = (struct ipsecdoi_id_b *) id_p->v;
+	struct sockaddr *sa;
+	caddr_t sa1, sa2;
+	vchar_t ident;
+	struct idspec *id;
+	struct genlist_entry *gpb;
+
+	/* compare with the ID if specified. */
+	if (!genlist_next(rmconf->idvl_p, 0))
+		return 0;
+
+	for (id = genlist_next(rmconf->idvl_p, &gpb); id; id = genlist_next(0, &gpb)) {
+		/* No ID specified in configuration, so it is ok */
+		if (id->id == 0)
+			return 0;
+
+		/* check the type of both IDs */
+		if (id->idtype != doi2idtype(id_b->type))
+			continue;  /* ID type mismatch */
+
+		/* compare defined ID with the ID sent by peer. */
+		switch (id->idtype) {
+		case IDTYPE_ASN1DN:
+			ident.v = id_p->v + sizeof(*id_b);
+			ident.l = id_p->l - sizeof(*id_b);
+			if (eay_cmp_asn1dn(id->id, &ident) == 0)
+				return 0;
+			break;
+		case IDTYPE_ADDRESS:
+			sa = (struct sockaddr *)id->id->v;
+			sa2 = (caddr_t)(id_b + 1);
+			switch (sa->sa_family) {
+			case AF_INET:
+				if (id_p->l - sizeof(*id_b) != sizeof(struct in_addr))
+					continue;  /* ID value mismatch */
+				sa1 = (caddr_t) &((struct sockaddr_in *)sa)->sin_addr;
+				if (memcmp(sa1, sa2, sizeof(struct in_addr)) == 0)
+					return 0;
+				break;
+#ifdef INET6
+			case AF_INET6:
+				if (id_p->l - sizeof(*id_b) != sizeof(struct in6_addr))
+					continue;  /* ID value mismatch */
+				sa1 = (caddr_t) &((struct sockaddr_in6 *)sa)->sin6_addr;
+				if (memcmp(sa1, sa2, sizeof(struct in6_addr)) == 0)
+					return 0;
+				break;
+#endif
+			default:
+				break;
+			}
+			break;
+		default:
+			if (memcmp(id->id->v, id_b + 1, id->id->l) == 0)
+				return 0;
+			break;
+		}
+	}
+
+	plog(LLV_WARNING, LOCATION, NULL, "No ID match.\n");
+	if (rmconf->verify_identifier)
+		return ISAKMP_NTYPE_INVALID_ID_INFORMATION;
+
+	return 0;
+}
+
+static int
+rmconf_match_etype_and_approval(rmconf, etype, approval)
+	struct remoteconf *rmconf;
+	int etype;
+	struct isakmpsa *approval;
+{
+	struct isakmpsa *p;
+
+	if (check_etypeok(rmconf, (void *) (intptr_t) etype) == 0)
+		return ISAKMP_NTYPE_NO_PROPOSAL_CHOSEN;
+
+	if (approval == NULL)
+		return 0;
+
+	if (etype == ISAKMP_ETYPE_AGG &&
+	    approval->dh_group != rmconf->dh_group)
+		return ISAKMP_NTYPE_NO_PROPOSAL_CHOSEN;
+
+	if (checkisakmpsa(rmconf->pcheck_level, approval,
+			  rmconf->proposal) == NULL)
+		return ISAKMP_NTYPE_NO_PROPOSAL_CHOSEN;
+
+	return 0;
+}
+
+enum rmconf_match_t {
+	MATCH_NONE		= 0,
+	MATCH_BASIC		= 0x0000001,
+	MATCH_ADDRESS		= 0x0000002,
+	MATCH_SA		= 0x0000004,
+	MATCH_IDENTITY		= 0x0000008,
+	MATCH_AUTH_IDENTITY	= 0x0000010,
+};
+
+static int
+rmconf_match_type(rmsel, rmconf)
+	struct rmconfselector *rmsel;
+	struct remoteconf *rmconf;
+{
+	int ret = MATCH_NONE, tmp;
+
+	/* No match at all: unwanted anonymous */
+	if ((rmsel->flags & GETRMCONF_F_NO_ANONYMOUS) &&
+	    rmconf->remote->sa_family == AF_UNSPEC){
+		plog(LLV_DEBUG2, LOCATION, rmsel->remote,
+		     "Not matched: Anonymous conf.\n");
+		return MATCH_NONE;
+	}
+
+	if ((rmsel->flags & GETRMCONF_F_NO_PASSIVE) && rmconf->passive){
+		plog(LLV_DEBUG2, LOCATION, rmsel->remote,
+		     "Not matched: passive conf.\n");
+		return MATCH_NONE;
+	}
+
+	ret |= MATCH_BASIC;
+
+	/* Check address */
+	if (rmsel->remote != NULL) {
+		if (rmconf->remote->sa_family != AF_UNSPEC) {
+			if (cmpsaddr(rmsel->remote, rmconf->remote) == CMPSADDR_MISMATCH){
+				plog(LLV_DEBUG2, LOCATION, rmsel->remote,
+				     "Not matched: address mismatch.\n");
+				return MATCH_NONE;
+			}
+
+			/* Address matched */
+			ret |= MATCH_ADDRESS;
+		}
+	}
+
+	/* Check etype and approval */
+	if (rmsel->etype != ISAKMP_ETYPE_NONE) {
+		tmp=rmconf_match_etype_and_approval(rmconf, rmsel->etype,
+						    rmsel->approval);
+		if (tmp != 0){
+			plog(LLV_DEBUG2, LOCATION, rmsel->remote,
+			     "Not matched: etype (%d)/approval mismatch (%d).\n", rmsel->etype, tmp);
+			return MATCH_NONE;
+		}
+		ret |= MATCH_SA;
+	}
+
+	/* Check identity */
+	if (rmsel->identity != NULL && rmconf->verify_identifier) {
+		if (rmconf_match_identity(rmconf, rmsel->identity) != 0){
+			plog(LLV_DEBUG2, LOCATION, rmsel->remote,
+			     "Not matched: identity mismatch.\n");
+			return MATCH_NONE;
+		}
+		ret |= MATCH_IDENTITY;
+	}
+
+	/* Check certificate request */
+	if (rmsel->certificate_request != NULL) {
+		if (oakley_get_certtype(rmsel->certificate_request) !=
+		    oakley_get_certtype(rmconf->mycert)){
+			plog(LLV_DEBUG2, LOCATION, rmsel->remote,
+			     "Not matched: cert type mismatch.\n");
+			return MATCH_NONE;
+		}
+
+		if (rmsel->certificate_request->l > 1) {
+			vchar_t *issuer;
+
+			issuer = eay_get_x509asn1issuername(rmconf->mycert);
+			if (rmsel->certificate_request->l - 1 != issuer->l ||
+			    memcmp(rmsel->certificate_request->v + 1,
+				   issuer->v, issuer->l) != 0) {
+				vfree(issuer);
+				plog(LLV_DEBUG2, LOCATION, rmsel->remote,
+				     "Not matched: cert issuer mismatch.\n");
+				return MATCH_NONE;
+			}
+			vfree(issuer);
+		} else {
+			if (!rmconf->match_empty_cr){
+				plog(LLV_DEBUG2, LOCATION, rmsel->remote,
+				     "Not matched: empty certificate request.\n");
+				return MATCH_NONE;
+			}
+		}
+
+		ret |= MATCH_AUTH_IDENTITY;
+	}
+
+	return ret;
+}
+
+void rmconf_selector_from_ph1(rmsel, iph1)
+	struct rmconfselector *rmsel;
+	struct ph1handle *iph1;
+{
+	memset(rmsel, 0, sizeof(*rmsel));
+	rmsel->flags = 0;
+	rmsel->remote = iph1->remote;
+	rmsel->etype = iph1->etype;
+	rmsel->approval = iph1->approval;
+	rmsel->identity = iph1->id_p;
+	rmsel->certificate_request = iph1->cr_p;
+}
+
+int
+enumrmconf(rmsel, enum_func, enum_arg)
+	struct rmconfselector *rmsel;
+	int (* enum_func)(struct remoteconf *rmconf, void *arg);
+	void *enum_arg;
+{
+	struct remoteconf *p;
+	int ret = 0;
+
+	RACOON_TAILQ_FOREACH_REVERSE(p, &rmtree, _rmtree, chain) {
+		plog(LLV_DEBUG2, LOCATION, rmsel->remote,
+		     "Checking remote conf \"%s\" %s.\n", p->name,
+		     p->remote->sa_family == AF_UNSPEC ?
+		     "anonymous" : saddr2str(p->remote));
+
+		if (rmsel != NULL) {
+			if (rmconf_match_type(rmsel, p) == MATCH_NONE){
+				plog(LLV_DEBUG2, LOCATION, rmsel->remote,
+				     "Not matched.\n");
+				continue;
+			}
+		}
+
+		plog(LLV_DEBUG2, LOCATION, NULL,
+		     "enumrmconf: \"%s\" matches.\n", p->name);
+
+		ret = (*enum_func)(p, enum_arg);
+		if (ret)
+			break;
+	}
+
+	return ret;
+}
+
+struct rmconf_find_context {
+	struct rmconfselector sel;
+
+	struct remoteconf *rmconf;
+	int match_type;
+	int num_found;
+};
+
+static int
+rmconf_find(rmconf, ctx)
+	struct remoteconf *rmconf;
+	void *ctx;
+{
+	struct rmconf_find_context *fctx = (struct rmconf_find_context *) ctx;
+	int match_type;
+
+	/* First matching remote conf? */
+	match_type = rmconf_match_type(&fctx->sel, rmconf);
+
+	if (fctx->rmconf != NULL) {
+		/* More ambiguous matches are ignored. */
+		if (match_type < fctx->match_type)
+			return 0;
+
+		if (match_type == fctx->match_type) {
+			/* Ambiguous match */
+			fctx->num_found++;
+			return 0;
+		}
+	}
+
+	/* More exact match found */
+	fctx->match_type = match_type;
+	fctx->num_found = 1;
+	fctx->rmconf = rmconf;
+
+	return 0;
+}
+
 /*
  * search remote configuration.
  * don't use port number to search if its value is either IPSEC_PORT_ANY.
@@ -93,76 +385,110 @@
  * OUT:	NULL:	NG
  *	Other:	remote configuration entry.
  */
+
 struct remoteconf *
-getrmconf_strict(remote, allow_anon)
+getrmconf(remote, flags)
 	struct sockaddr *remote;
-	int allow_anon;
+	int flags;
 {
-	struct remoteconf *p;
-	struct remoteconf *anon = NULL;
-	int withport;
-	char buf[NI_MAXHOST + NI_MAXSERV + 10];
-	char addr[NI_MAXHOST], port[NI_MAXSERV];
+	struct rmconf_find_context ctx;
+	int n = 0;
 
-	withport = 0;
+	memset(&ctx, 0, sizeof(ctx));
+	ctx.sel.flags = flags;
+	ctx.sel.remote = remote;
 
-#ifndef ENABLE_NATT
-	/* 
-	 * We never have ports set in our remote configurations, but when
-	 * NAT-T is enabled, the kernel can have policies with ports and
-	 * send us an acquire message for a destination that has a port set.
-	 * If we do this port check here, we don't find the remote config.
-	 *
-	 * In an ideal world, we would be able to have remote conf with
-	 * port, and the port could be a wildcard. That test could be used.
-	 */
-	if (remote->sa_family != AF_UNSPEC &&
-	    extract_port(remote) != IPSEC_PORT_ANY)
-		withport = 1;
-#endif /* ENABLE_NATT */
-
-	if (remote->sa_family == AF_UNSPEC)
-		snprintf (buf, sizeof(buf), "%s", "anonymous");
-	else {
-		GETNAMEINFO(remote, addr, port);
-		snprintf(buf, sizeof(buf), "%s%s%s%s", addr,
-			withport ? "[" : "",
-			withport ? port : "",
-			withport ? "]" : "");
+	if (enumrmconf(&ctx.sel, rmconf_find, &ctx) != 0) {
+		plog(LLV_ERROR, LOCATION, remote,
+		     "multiple exact configurations.\n");
+		return NULL;
 	}
 
-	TAILQ_FOREACH(p, &rmtree, chain) {
-		if ((remote->sa_family == AF_UNSPEC
-		     && remote->sa_family == p->remote->sa_family)
-		 || (!withport && cmpsaddrwop(remote, p->remote) == 0)
-		 || (withport && cmpsaddrstrict(remote, p->remote) == 0)) {
-			plog(LLV_DEBUG, LOCATION, NULL,
-				"configuration found for %s.\n", buf);
-			return p;
-		}
-
-		/* save the pointer to the anonymous configuration */
-		if (p->remote->sa_family == AF_UNSPEC)
-			anon = p;
+	if (ctx.rmconf == NULL) {
+		plog(LLV_DEBUG, LOCATION, remote,
+		     "no remote configuration found.\n");
+		return NULL;
 	}
 
-	if (allow_anon && anon != NULL) {
-		plog(LLV_DEBUG, LOCATION, NULL,
-			"anonymous configuration selected for %s.\n", buf);
-		return anon;
+	if (ctx.num_found != 1) {
+		plog(LLV_DEBUG, LOCATION, remote,
+		     "multiple non-exact configurations found.\n");
+		return NULL;
 	}
 
-	plog(LLV_DEBUG, LOCATION, NULL,
-		"no remote configuration found.\n");
+	plog(LLV_DEBUG, LOCATION, remote,
+	     "configuration \"%s\" selected.\n",
+	     ctx.rmconf->name);
 
-	return NULL;
+	return ctx.rmconf;
 }
 
 struct remoteconf *
-getrmconf(remote)
-	struct sockaddr *remote;
+getrmconf_by_ph1(iph1)
+	struct ph1handle *iph1;
 {
-	return getrmconf_strict(remote, 1);
+	struct rmconf_find_context ctx;
+
+	memset(&ctx, 0, sizeof(ctx));
+	rmconf_selector_from_ph1(&ctx.sel, iph1);
+	if (loglevel >= LLV_DEBUG) {
+		char *idstr = NULL;
+
+		if (iph1->id_p != NULL)
+			idstr = ipsecdoi_id2str(iph1->id_p);
+
+		plog(LLV_DEBUG, LOCATION, iph1->remote,
+			"getrmconf_by_ph1: remote %s, identity %s.\n",
+			saddr2str(iph1->remote), idstr ? idstr : "<any>");
+
+		if (idstr)
+			racoon_free(idstr);
+	}
+
+	if (enumrmconf(&ctx.sel, rmconf_find, &ctx) != 0) {
+		plog(LLV_ERROR, LOCATION, iph1->remote,
+		     "multiple exact configurations.\n");
+		return RMCONF_ERR_MULTIPLE;
+	}
+
+	if (ctx.rmconf == NULL) {
+		plog(LLV_DEBUG, LOCATION, iph1->remote,
+		     "no remote configuration found\n");
+		return NULL;
+	}
+
+	if (ctx.num_found != 1) {
+		plog(LLV_DEBUG, LOCATION, iph1->remote,
+		     "multiple non-exact configurations found.\n");
+		return RMCONF_ERR_MULTIPLE;
+	}
+
+	plog(LLV_DEBUG, LOCATION, iph1->remote,
+	     "configuration \"%s\" selected.\n",
+	     ctx.rmconf->name);
+
+	return ctx.rmconf;
+}
+
+struct remoteconf *
+getrmconf_by_name(name)
+	const char *name;
+{
+	struct remoteconf *p;
+
+	plog(LLV_DEBUG, LOCATION, NULL,
+	     "getrmconf_by_name: remote \"%s\".\n",
+	     name);
+
+	RACOON_TAILQ_FOREACH_REVERSE(p, &rmtree, _rmtree, chain) {
+		if (p->name == NULL)
+			continue;
+
+		if (strcmp(name, p->name) == 0)
+			return p;
+	}
+
+	return NULL;
 }
 
 struct remoteconf *
@@ -191,19 +517,14 @@
 	new->pcheck_level = PROP_CHECK_STRICT;
 	new->verify_identifier = FALSE;
 	new->verify_cert = TRUE;
-	new->getcert_method = ISAKMP_GETCERT_PAYLOAD;
-	new->getcacert_method = ISAKMP_GETCERT_LOCALFILE;
-	new->cacerttype = ISAKMP_CERT_X509SIGN;
-	new->certtype = ISAKMP_CERT_NONE;
 	new->cacertfile = NULL;
 	new->send_cert = TRUE;
 	new->send_cr = TRUE;
+	new->match_empty_cr = FALSE;
 	new->support_proxy = FALSE;
 	for (i = 0; i <= SCRIPT_MAX; i++)
 		new->script[i] = NULL;
 	new->gen_policy = FALSE;
-	new->retry_counter = lcconf->retry_counter;
-	new->retry_interval = lcconf->retry_interval;
 	new->nat_traversal = FALSE;
 	new->rsa_private = genlist_init();
 	new->rsa_public = genlist_init();
@@ -215,34 +536,21 @@
 	new->dpd_retry = 5;
 	new->dpd_maxfails = 5;
 
+	new->rekey = REKEY_ON;
+
 	new->weak_phase1_check = 0;
 
 #ifdef ENABLE_HYBRID
 	new->xauth = NULL;
 #endif
 
-	return new;
-}
-
-struct remoteconf *
-copyrmconf(remote)
-	struct sockaddr *remote;
-{
-	struct remoteconf *new, *old;
-
-	old = getrmconf_strict (remote, 0);
-	if (old == NULL) {
-		plog (LLV_ERROR, LOCATION, NULL,
-		      "Remote configuration for '%s' not found!\n",
-		      saddr2str (remote));
-		return NULL;
-	}
-
-	new = duprmconf (old);
+	new->lifetime = oakley_get_defaultlifetime();
 
 	return new;
 }
 
+#ifndef ANDROID_PATCHED
+
 void *
 dupidvl(entry, arg)
 	void *entry;
@@ -264,29 +572,147 @@
 	return NULL;
 }
 
+void *
+duprsa(entry, arg)
+	void *entry;
+	void *arg;
+{
+	struct rsa_key *new;
+
+	new = rsa_key_dup((struct rsa_key *)entry);
+	if (new == NULL)
+		return (void *) -1;
+	genlist_append(arg, new);
+
+	/* keep genlist_foreach going */
+	return NULL;
+}
+
+/* Creates shallow copy of a remote config. Used for "inherit" keyword. */
 struct remoteconf *
-duprmconf (rmconf)
+duprmconf_shallow (rmconf)
 	struct remoteconf *rmconf;
 {
 	struct remoteconf *new;
+	struct proposalspec *prspec;
 
 	new = racoon_calloc(1, sizeof(*new));
 	if (new == NULL)
 		return NULL;
-	memcpy (new, rmconf, sizeof (*new));
-	// FIXME: We should duplicate the proposal as well.
-	// This is now handled in the cfparse.y
-	// new->proposal = ...;
-	
-	/* duplicate dynamic structures */
-	if (new->etypes)
-		new->etypes=dupetypes(new->etypes);
-	new->idvl_p = genlist_init();
-	genlist_foreach(rmconf->idvl_p, dupidvl, new->idvl_p);
+
+	memcpy(new, rmconf, sizeof(*new));
+	new->name = NULL;
+	new->inherited_from = rmconf;
+
+	new->proposal = NULL; /* will be filled by set_isakmp_proposal() */
 
 	return new;
 }
 
+/* Copies pointer structures of an inherited remote config. 
+ * Used by "inherit" mechanism in a two step copy method, necessary to
+ * prevent both double free() and memory leak during config reload.
+ */
+int
+duprmconf_finish (new)
+	struct remoteconf *new;
+{
+	struct remoteconf *rmconf;
+	int i;
+
+	if (new->inherited_from == NULL)
+		return 0; /* nothing todo, no inheritance */
+
+	rmconf = new->inherited_from;
+
+	/* duplicate dynamic structures unless value overridden */
+	if (new->etypes != NULL && new->etypes == rmconf->etypes)
+		new->etypes = dupetypes(new->etypes);
+	if (new->idvl_p == rmconf->idvl_p) {
+		new->idvl_p = genlist_init();
+		genlist_foreach(rmconf->idvl_p, dupidvl, new->idvl_p);
+	}
+
+	if (new->rsa_private == rmconf->rsa_private) {
+		new->rsa_private = genlist_init();
+		genlist_foreach(rmconf->rsa_private, duprsa, new->rsa_private);
+	}
+	if (new->rsa_public == rmconf->rsa_public) {
+		new->rsa_public = genlist_init();
+		genlist_foreach(rmconf->rsa_public, duprsa, new->rsa_public);
+	}
+	if (new->remote != NULL && new->remote == rmconf->remote) {
+		new->remote = racoon_malloc(sizeof(*new->remote));
+		if (new->remote == NULL) {
+			plog(LLV_ERROR, LOCATION, NULL, 
+			    "duprmconf_finish: malloc failed (remote)\n");
+			exit(1);
+		}
+		memcpy(new->remote, rmconf->remote, sizeof(*new->remote));
+	}
+	if (new->spspec != NULL && new->spspec == rmconf->spspec) {
+		dupspspec_list(new, rmconf);
+	}
+
+	/* proposal has been deep copied already from spspec's, see
+	 * cfparse.y:set_isakmp_proposal, which in turn calls
+	 * cfparse.y:expand_isakmpspec where the copying happens.
+	 */
+
+#ifdef ENABLE_HYBRID
+	if (new->xauth != NULL && new->xauth == rmconf->xauth) {
+		new->xauth = xauth_rmconf_dup(new->xauth);
+		if (new->xauth == NULL)
+			exit(1);
+	}
+#endif
+
+        /* duplicate strings unless value overridden */ 
+	if (new->mycertfile != NULL && new->mycertfile == rmconf->mycertfile) { 
+		new->mycertfile = racoon_strdup(new->mycertfile); 
+		STRDUP_FATAL(new->mycertfile); 
+	} 
+	if (new->myprivfile != NULL && new->myprivfile == rmconf->myprivfile) { 
+		new->myprivfile = racoon_strdup(new->myprivfile); 
+		STRDUP_FATAL(new->myprivfile); 
+	} 
+	if (new->peerscertfile != NULL && new->peerscertfile == rmconf->peerscertfile) { 
+		new->peerscertfile = racoon_strdup(new->peerscertfile); 
+		STRDUP_FATAL(new->peerscertfile); 
+	} 
+	if (new->cacertfile != NULL && new->cacertfile == rmconf->cacertfile) { 
+		new->cacertfile = racoon_strdup(new->cacertfile); 
+		STRDUP_FATAL(new->cacertfile); 
+	} 
+	if (new->idv != NULL && new->idv == rmconf->idv) {
+		new->idv = vdup(new->idv); 
+		STRDUP_FATAL(new->idv); 
+	}
+	if (new->key != NULL && new->key == rmconf->key) {
+		new->key = vdup(new->key); 
+		STRDUP_FATAL(new->key); 
+	}
+	if (new->mycert != NULL && new->mycert == rmconf->mycert) {
+		new->mycert = vdup(new->mycert);
+		STRDUP_FATAL(new->mycert); 
+	}
+	if (new->peerscert != NULL && new->peerscert == rmconf->peerscert) {
+		new->peerscert = vdup(new->peerscert);
+		STRDUP_FATAL(new->peerscert); 
+	}
+	if (new->cacert != NULL && new->cacert == rmconf->cacert) {
+		new->cacert = vdup(new->cacert);
+		STRDUP_FATAL(new->cacert); 
+	}
+	for (i = 0; i <= SCRIPT_MAX; i++)
+		if (new->script[i] != NULL && new->script[i] == rmconf->script[i]) {
+			new->script[i] = vdup(new->script[i]);
+			STRDUP_FATAL(new->script[i]);
+		}
+
+	return 0;
+}
+
 static void
 idspec_free(void *data)
 {
@@ -298,6 +724,8 @@
 delrmconf(rmconf)
 	struct remoteconf *rmconf;
 {
+	int i;
+
 #ifdef ENABLE_HYBRID
 	if (rmconf->xauth)
 		xauth_rmconf_delete(&rmconf->xauth);
@@ -306,15 +734,55 @@
 		deletypes(rmconf->etypes);
 		rmconf->etypes=NULL;
 	}
+	if (rmconf->idv)
+		vfree(rmconf->idv);
+	if (rmconf->key)
+		vfree(rmconf->key);
 	if (rmconf->idvl_p)
 		genlist_free(rmconf->idvl_p, idspec_free);
 	if (rmconf->dhgrp)
 		oakley_dhgrp_free(rmconf->dhgrp);
 	if (rmconf->proposal)
 		delisakmpsa(rmconf->proposal);
+	flushspspec(rmconf);
+	if (rmconf->mycert)
+		vfree(rmconf->mycert);
+	if (rmconf->mycertfile)
+		racoon_free(rmconf->mycertfile);
+	if (rmconf->myprivfile)
+		racoon_free(rmconf->myprivfile);
+	if (rmconf->peerscert)
+		vfree(rmconf->peerscert);
+	if (rmconf->peerscertfile)
+		racoon_free(rmconf->peerscertfile);
+	if (rmconf->cacert)
+		vfree(rmconf->cacert);
+	if (rmconf->cacertfile)
+		racoon_free(rmconf->cacertfile);
+	if (rmconf->rsa_private)
+		genlist_free(rmconf->rsa_private, rsa_key_free);
+	if (rmconf->rsa_public)
+		genlist_free(rmconf->rsa_public, rsa_key_free);
+	if (rmconf->name)
+		racoon_free(rmconf->name);
+	if (rmconf->remote)
+		racoon_free(rmconf->remote);
+	for (i = 0; i <= SCRIPT_MAX; i++)
+		if (rmconf->script[i])
+			vfree(rmconf->script[i]);
+
 	racoon_free(rmconf);
 }
 
+#else
+
+void delrmconf(struct remoteconf *rmconf)
+{
+        exit(1);
+}
+
+#endif
+
 void
 delisakmpsa(sa)
 	struct isakmpsa *sa;
@@ -336,11 +804,11 @@
 {
 	struct etypes *new;
 
-	if (!orig) 
+	if (!orig)
 		return NULL;
 
 	new = racoon_malloc(sizeof(struct etypes));
-	if (new == NULL) 
+	if (new == NULL)
 		return NULL;
 
 	new->type = orig->type;
@@ -368,6 +836,14 @@
 insrmconf(new)
 	struct remoteconf *new;
 {
+	if (new->name == NULL) {
+		new->name = racoon_strdup(saddr2str(new->remote));
+	}
+	if (new->remote == NULL) {
+		new->remote = newsaddr(sizeof(struct sockaddr));
+		new->remote->sa_family = AF_UNSPEC;
+	}
+
 	TAILQ_INSERT_HEAD(&rmtree, new, chain);
 }
 
@@ -397,15 +873,17 @@
 }
 
 void
-save_rmconf()
+rmconf_start_reload()
 {
 	rmtree_save=rmtree;
 	initrmconf();
 }
 
 void
-save_rmconf_flush()
+rmconf_finish_reload()
 {
+	remoteconf_tailq_head_t rmtree_tmp;
+
 	rmtree_tmp=rmtree;
 	rmtree=rmtree_save;
 	flushrmconf();
@@ -416,19 +894,22 @@
 
 
 /* check exchange type to be acceptable */
-struct etypes *
-check_etypeok(rmconf, etype)
+int
+check_etypeok(rmconf, ctx)
 	struct remoteconf *rmconf;
-	u_int8_t etype;
+	void *ctx;
 {
+	u_int8_t etype = (u_int8_t) (intptr_t) ctx;
 	struct etypes *e;
 
 	for (e = rmconf->etypes; e != NULL; e = e->next) {
 		if (e->type == etype)
-			break;
+			return 1;
+		plog(LLV_DEBUG2, LOCATION, NULL,
+		     "Etype mismatch: got %d, expected %d.\n", e->type, etype);
 	}
 
-	return e;
+	return 0;
 }
 
 /*%%%*/
@@ -448,7 +929,6 @@
 	new->vendorid = VENDORID_UNKNOWN;
 
 	new->next = NULL;
-	new->rmconf = NULL;
 #ifdef HAVE_GSSAPI
 	new->gssid = NULL;
 #endif
@@ -466,8 +946,6 @@
 {
 	struct isakmpsa *p;
 
-	new->rmconf = rmconf;
-
 	if (rmconf->proposal == NULL) {
 		rmconf->proposal = new;
 		return;
@@ -476,21 +954,6 @@
 	for (p = rmconf->proposal; p->next != NULL; p = p->next)
 		;
 	p->next = new;
-
-	return;
-}
-
-struct remoteconf *
-foreachrmconf(rmconf_func_t rmconf_func, void *data)
-{
-  struct remoteconf *p, *ret = NULL;
-  RACOON_TAILQ_FOREACH_REVERSE(p, &rmtree, _rmtree, chain) {
-    ret = (*rmconf_func)(p, data);
-    if (ret)
-      break;
-  }
-
-  return ret;
 }
 
 static void *
@@ -507,7 +970,7 @@
 	return NULL;
 }
 
-static struct remoteconf *
+static int
 dump_rmconf_single (struct remoteconf *p, void *data)
 {
 	struct etypes *etype = p->etypes;
@@ -515,10 +978,11 @@
 	char buf[1024], *pbuf;
 
 	pbuf = buf;
-	pbuf += sprintf(pbuf, "remote %s", saddr2str(p->remote));
+
+	pbuf += sprintf(pbuf, "remote \"%s\"", p->name);
 	if (p->inherited_from)
-		pbuf += sprintf(pbuf, " inherit %s",
-				saddr2str(p->inherited_from->remote));
+		pbuf += sprintf(pbuf, " inherit \"%s\"",
+				p->inherited_from->name);
 	plog(LLV_INFO, LOCATION, NULL, "%s {\n", buf);
 	pbuf = buf;
 	pbuf += sprintf(pbuf, "\texchange_type ");
@@ -533,23 +997,30 @@
 	pbuf += sprintf(pbuf, "\tmy_identifier %s", s_idtype (p->idvtype));
 	if (p->idvtype == IDTYPE_ASN1DN) {
 		plog(LLV_INFO, LOCATION, NULL, "%s;\n", buf);
-		plog(LLV_INFO, LOCATION, NULL, "\tcertificate_type %s \"%s\" \"%s\";\n",
-			p->certtype == ISAKMP_CERT_X509SIGN ? "x509" : "*UNKNOWN*",
-			p->mycertfile, p->myprivfile);
-		switch (p->getcert_method) {
-		  case 0:
-		  	break;
-		  case ISAKMP_GETCERT_PAYLOAD:
-			plog(LLV_INFO, LOCATION, NULL, "\t/* peers certificate from payload */\n");
+		plog(LLV_INFO, LOCATION, NULL,
+		     "\tcertificate_type %s \"%s\" \"%s\";\n",
+		     oakley_get_certtype(p->mycert) == ISAKMP_CERT_X509SIGN
+		       ? "x509" : "*UNKNOWN*",
+		     p->mycertfile, p->myprivfile);
+
+		switch (oakley_get_certtype(p->peerscert)) {
+		case ISAKMP_CERT_NONE:
+			plog(LLV_INFO, LOCATION, NULL,
+			     "\t/* peers certificate from payload */\n");
 			break;
-		  case ISAKMP_GETCERT_LOCALFILE:
-			plog(LLV_INFO, LOCATION, NULL, "\tpeers_certfile \"%s\";\n", p->peerscertfile);
+		case ISAKMP_CERT_X509SIGN:
+			plog(LLV_INFO, LOCATION, NULL,
+			     "\tpeers_certfile \"%s\";\n", p->peerscertfile);
 			break;
-		  case ISAKMP_GETCERT_DNS:
-			plog(LLV_INFO, LOCATION, NULL, "\tpeer_certfile dnssec;\n");
+		case ISAKMP_CERT_DNS:
+			plog(LLV_INFO, LOCATION, NULL,
+			     "\tpeers_certfile dnssec;\n");
 			break;
-		  default:
-			plog(LLV_INFO, LOCATION, NULL, "\tpeers_certfile *UNKNOWN* (%d)\n", p->getcert_method);
+		default:
+			plog(LLV_INFO, LOCATION, NULL,
+			     "\tpeers_certfile *UNKNOWN* (%d)\n",
+			     oakley_get_certtype(p->peerscert));
+			break;
 		}
 	}
 	else {
@@ -559,10 +1030,14 @@
 		genlist_foreach(p->idvl_p, &dump_peers_identifiers, NULL);
 	}
 
+	plog(LLV_INFO, LOCATION, NULL, "\trekey %s;\n",
+		p->rekey == REKEY_FORCE ? "force" : s_switch (p->rekey));
 	plog(LLV_INFO, LOCATION, NULL, "\tsend_cert %s;\n",
 		s_switch (p->send_cert));
 	plog(LLV_INFO, LOCATION, NULL, "\tsend_cr %s;\n",
 		s_switch (p->send_cr));
+	plog(LLV_INFO, LOCATION, NULL, "\tmatch_empty_cr %s;\n",
+		s_switch (p->match_empty_cr));
 	plog(LLV_INFO, LOCATION, NULL, "\tverify_cert %s;\n",
 		s_switch (p->verify_cert));
 	plog(LLV_INFO, LOCATION, NULL, "\tverify_identifier %s;\n",
@@ -588,9 +1063,8 @@
 	while (prop) {
 		plog(LLV_INFO, LOCATION, NULL, "\n");
 		plog(LLV_INFO, LOCATION, NULL,
-			"\t/* prop_no=%d, trns_no=%d, rmconf=%s */\n",
-			prop->prop_no, prop->trns_no,
-			saddr2str(prop->rmconf->remote));
+			"\t/* prop_no=%d, trns_no=%d */\n",
+			prop->prop_no, prop->trns_no);
 		plog(LLV_INFO, LOCATION, NULL, "\tproposal {\n");
 		plog(LLV_INFO, LOCATION, NULL, "\t\tlifetime time %lu sec;\n",
 			(long)prop->lifetime);
@@ -598,11 +1072,11 @@
 			prop->lifebyte);
 		plog(LLV_INFO, LOCATION, NULL, "\t\tdh_group %s;\n",
 			alg_oakley_dhdef_name(prop->dh_group));
-		plog(LLV_INFO, LOCATION, NULL, "\t\tencryption_algorithm %s;\n", 
+		plog(LLV_INFO, LOCATION, NULL, "\t\tencryption_algorithm %s;\n",
 			alg_oakley_encdef_name(prop->enctype));
-		plog(LLV_INFO, LOCATION, NULL, "\t\thash_algorithm %s;\n", 
+		plog(LLV_INFO, LOCATION, NULL, "\t\thash_algorithm %s;\n",
 			alg_oakley_hashdef_name(prop->hashtype));
-		plog(LLV_INFO, LOCATION, NULL, "\t\tauthentication_method %s;\n", 
+		plog(LLV_INFO, LOCATION, NULL, "\t\tauthentication_method %s;\n",
 			alg_oakley_authdef_name(prop->authmethod));
 		plog(LLV_INFO, LOCATION, NULL, "\t}\n");
 		prop = prop->next;
@@ -610,13 +1084,13 @@
 	plog(LLV_INFO, LOCATION, NULL, "}\n");
 	plog(LLV_INFO, LOCATION, NULL, "\n");
 
-	return NULL;
+	return 0;
 }
 
 void
 dumprmconf()
 {
-	foreachrmconf (dump_rmconf_single, NULL);
+	enumrmconf(NULL, dump_rmconf_single, NULL);
 }
 
 struct idspec *
@@ -671,25 +1145,115 @@
 struct isakmpsa *
 dupisakmpsa(struct isakmpsa *sa)
 {
-	struct isakmpsa *res=NULL;
+	struct isakmpsa *res = NULL;
 
 	if(sa == NULL)
 		return NULL;
 
-	res=newisakmpsa();
+	res = newisakmpsa();
 	if(res == NULL)
 		return NULL;
 
-	*res=*sa;
+	*res = *sa;
 #ifdef HAVE_GSSAPI
-	/* XXX gssid
-	 */
+	if (sa->gssid != NULL)
+		res->gssid = vdup(sa->gssid);
 #endif
-	res->next=NULL;
+	res->next = NULL;
 
 	if(sa->dhgrp != NULL)
-		oakley_setdhgroup (sa->dh_group, &(res->dhgrp));
+		oakley_setdhgroup(sa->dh_group, &res->dhgrp);
 
 	return res;
 
 }
+
+#ifdef ENABLE_HYBRID
+int
+isakmpsa_switch_authmethod(authmethod)
+	int authmethod;
+{
+	switch(authmethod) {
+	case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_R:
+		authmethod = OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I;
+		break;
+	case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_R:
+		authmethod = OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_I;
+		break;
+	case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_R:
+		authmethod = OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_I;
+		break;
+	case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_R:
+		authmethod = OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_I;
+		break;
+	case OAKLEY_ATTR_AUTH_METHOD_XAUTH_DSSSIG_R:
+		authmethod = OAKLEY_ATTR_AUTH_METHOD_XAUTH_DSSSIG_I;
+		break;
+	case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAENC_R:
+		authmethod = OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAENC_I;
+		break;
+	case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAREV_R:
+		authmethod = OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAREV_I;
+		break;
+	default:
+		break;
+	}
+
+	return authmethod;
+}
+#endif
+
+/*
+ * Given a proposed ISAKMP SA, and a list of acceptable
+ * ISAKMP SAs, it compares using pcheck_level policy and
+ * returns first match (if any).
+ */
+struct isakmpsa *
+checkisakmpsa(pcheck_level, proposal, acceptable)
+	int pcheck_level;
+	struct isakmpsa *proposal, *acceptable;
+{
+	struct isakmpsa *p;
+
+	for (p = acceptable; p != NULL; p = p->next){
+		plog(LLV_DEBUG2, LOCATION, NULL,
+		     "checkisakmpsa:\nauthmethod: %d / %d\n",
+		     isakmpsa_switch_authmethod(proposal->authmethod), isakmpsa_switch_authmethod(p->authmethod));
+		if (isakmpsa_switch_authmethod(proposal->authmethod) != isakmpsa_switch_authmethod(p->authmethod) ||
+		    proposal->enctype != p->enctype ||
+                    proposal->dh_group != p->dh_group ||
+		    proposal->hashtype != p->hashtype)
+			continue;
+
+		switch (pcheck_level) {
+		case PROP_CHECK_OBEY:
+			break;
+
+		case PROP_CHECK_CLAIM:
+		case PROP_CHECK_STRICT:
+			if (proposal->encklen < p->encklen ||
+#if 0
+			    proposal->lifebyte > p->lifebyte ||
+#endif
+			    proposal->lifetime > p->lifetime)
+				continue;
+			break;
+
+		case PROP_CHECK_EXACT:
+			if (proposal->encklen != p->encklen ||
+#if 0
+                            proposal->lifebyte != p->lifebyte ||
+#endif
+			    proposal->lifetime != p->lifetime)
+				continue;
+			break;
+
+		default:
+			continue;
+		}
+
+		return p;
+	}
+
+	return NULL;
+}
diff --git a/src/racoon/remoteconf.h b/src/racoon/remoteconf.h
index ca5945e..3ebe004 100644
--- a/src/racoon/remoteconf.h
+++ b/src/racoon/remoteconf.h
@@ -1,4 +1,4 @@
-/*	$NetBSD: remoteconf.h,v 1.7 2006/10/03 08:01:56 vanhu Exp $	*/
+/*	$NetBSD: remoteconf.h,v 1.16 2011/03/14 15:50:36 vanhu Exp $	*/
 
 /* Id: remoteconf.h,v 1.26 2006/05/06 15:52:44 manubsd Exp */
 
@@ -43,95 +43,14 @@
 #include "isakmp_xauth.h"
 #endif
 
-struct proposalspec;
+struct ph1handle;
+struct secprotospec;
 
 struct etypes {
 	int type;
 	struct etypes *next;
 };
 
-/* Script hooks */
-#define SCRIPT_PHASE1_UP	0
-#define SCRIPT_PHASE1_DOWN	1
-#define SCRIPT_MAX		1
-extern char *script_names[SCRIPT_MAX + 1];
-
-struct remoteconf {
-	struct sockaddr *remote;	/* remote IP address */
-					/* if family is AF_UNSPEC, that is
-					 * for anonymous configuration. */
-
-	struct etypes *etypes;		/* exchange type list. the head
-					 * is a type to be sent first. */
-	int doitype;			/* doi type */
-	int sittype;			/* situation type */
-
-	int idvtype;			/* my identifier type */
-	vchar_t *idv;			/* my identifier */
-	vchar_t *key;			/* my pre-shared key */
-	struct genlist *idvl_p;         /* peer's identifiers list */
-
-	int certtype;			/* certificate type if need */
-	char *mycertfile;		/* file name of my certificate */
-	char *myprivfile;		/* file name of my private key file */
-	char *peerscertfile;		/* file name of peer's certifcate */
-	int getcert_method;		/* the way to get peer's certificate */
-	int cacerttype;			/* CA type is needed */
-	char *cacertfile;		/* file name of CA */
-	int getcacert_method;		/* the way to get the CA */
-	int send_cert;			/* send to CERT or not */
-	int send_cr;			/* send to CR or not */
-	int verify_cert;		/* verify a CERT strictly */
-	int verify_identifier;		/* vefify the peer's identifier */
-	int nonce_size;			/* the number of bytes of nonce */
-	int passive;			/* never initiate */
-	int ike_frag;			/* IKE fragmentation */
-	int esp_frag;			/* ESP fragmentation */
-	int mode_cfg;			/* Gets config through mode config */
-	int support_proxy;		/* support mip6/proxy */
-#define GENERATE_POLICY_NONE   0
-#define GENERATE_POLICY_REQUIRE        1
-#define GENERATE_POLICY_UNIQUE 2
-	int gen_policy;			/* generate policy if no policy found */
-	int ini_contact;		/* initial contact */
-	int pcheck_level;		/* level of propocl checking */
-	int nat_traversal;		/* NAT-Traversal */
-	vchar_t *script[SCRIPT_MAX + 1];/* script hooks paths */
-	int dh_group;			/* use it when only aggressive mode */
-	struct dhgroup *dhgrp;		/* use it when only aggressive mode */
-					/* above two can't be defined by user*/
-
-	int retry_counter;		/* times to retry. */
-	int retry_interval;		/* interval each retry. */
-				/* above 2 values are copied from localconf. */
-
-	int dpd;				/* Negociate DPD support ? */
-	int dpd_retry;			/* in seconds */
-	int dpd_interval;		/* in seconds */
-	int dpd_maxfails; 
-
-	int ph1id; /* ph1id to be matched with sainfo sections */
-
-	int weak_phase1_check;		/* act on unencrypted deletions ? */
-
-	struct isakmpsa *proposal;	/* proposal list */
-	struct remoteconf *inherited_from;	/* the original rmconf 
-						   from which this one 
-						   was inherited */
-	struct proposalspec *prhead;
-
-	struct genlist	*rsa_private,	/* lists of PlainRSA keys to use */
-			*rsa_public;
-
-#ifdef ENABLE_HYBRID
-	struct xauth_rmconf *xauth;
-#endif
-
-	TAILQ_ENTRY(remoteconf) chain;	/* next remote conf */
-};
-
-struct dhgroup;
-
 /* ISAKMP SA specification */
 struct isakmpsa {
 	int prop_no;
@@ -150,42 +69,170 @@
 	struct dhgroup *dhgrp;		/* don't use it if aggressive mode */
 
 	struct isakmpsa *next;		/* next transform */
-	struct remoteconf *rmconf;	/* backpointer to remoteconf */
 };
 
+/* Certificate information */
+struct rmconf_cert {
+	vchar_t *data;			/* certificate payload */
+	char *filename;			/* name of local file */
+};
+
+/* Script hooks */
+#define SCRIPT_PHASE1_UP	0
+#define SCRIPT_PHASE1_DOWN	1
+#define SCRIPT_PHASE1_DEAD	2
+#define SCRIPT_MAX		2
+extern char *script_names[SCRIPT_MAX + 1];
+
+struct remoteconf {
+	char *name;			/* remote configuration name */
+	struct sockaddr *remote;	/* remote IP address */
+					/* if family is AF_UNSPEC, that is
+					 * for anonymous configuration. */
+
+	struct etypes *etypes;		/* exchange type list. the head
+					 * is a type to be sent first. */
+	int doitype;			/* doi type */
+	int sittype;			/* situation type */
+
+	int idvtype;			/* my identifier type */
+	vchar_t *idv;			/* my identifier */
+	vchar_t *key;			/* my pre-shared key */
+	struct genlist *idvl_p;         /* peer's identifiers list */
+
+	char *myprivfile;		/* file name of my private key file */
+	char *mycertfile;		/* file name of my certificate */
+	vchar_t *mycert;		/* my certificate */
+	char *peerscertfile;		/* file name of peer's certifcate */
+	vchar_t *peerscert;		/* peer's certificate */
+	char *cacertfile;		/* file name of CA */
+	vchar_t *cacert;		/* CA certificate */
+
+	int send_cert;			/* send to CERT or not */
+	int send_cr;			/* send to CR or not */
+	int match_empty_cr;		/* does this match if CR is empty */
+	int verify_cert;		/* verify a CERT strictly */
+	int verify_identifier;		/* vefify the peer's identifier */
+	int nonce_size;			/* the number of bytes of nonce */
+	int passive;			/* never initiate */
+	int ike_frag;			/* IKE fragmentation */
+	int esp_frag;			/* ESP fragmentation */
+	int mode_cfg;			/* Gets config through mode config */
+	int support_proxy;		/* support mip6/proxy */
+#define GENERATE_POLICY_NONE	0
+#define GENERATE_POLICY_REQUIRE	1
+#define GENERATE_POLICY_UNIQUE	2
+	int gen_policy;			/* generate policy if no policy found */
+	int ini_contact;		/* initial contact */
+	int pcheck_level;		/* level of propocl checking */
+	int nat_traversal;		/* NAT-Traversal */
+	vchar_t *script[SCRIPT_MAX + 1];/* script hooks paths */
+	int dh_group;			/* use it when only aggressive mode */
+	struct dhgroup *dhgrp;		/* use it when only aggressive mode */
+					/* above two can't be defined by user*/
+
+	int dpd;				/* Negociate DPD support ? */
+	int dpd_retry;			/* in seconds */
+	int dpd_interval;		/* in seconds */
+	int dpd_maxfails;
+
+	int rekey;			/* rekey ph1 when active ph2s? */
+#define REKEY_OFF		FALSE
+#define REKEY_ON		TRUE
+#define REKEY_FORCE		2
+
+	uint32_t ph1id; /* ph1id to be matched with sainfo sections */
+
+	int weak_phase1_check;		/* act on unencrypted deletions ? */
+
+	struct isakmpsa *proposal;	/* proposal list */
+	struct remoteconf *inherited_from;	/* the original rmconf 
+						   from which this one 
+						   was inherited */
+
+	time_t lifetime;		/* for isakmp/ipsec */
+	int lifebyte;			/* for isakmp/ipsec */
+	struct secprotospec *spspec;	/* the head is always current spec. */
+
+	struct genlist	*rsa_private,	/* lists of PlainRSA keys to use */
+			*rsa_public;
+
+#ifdef ENABLE_HYBRID
+	struct xauth_rmconf *xauth;
+#endif
+
+	TAILQ_ENTRY(remoteconf) chain;	/* next remote conf */
+};
+
+#define RMCONF_NONCE_SIZE(rmconf) \
+	(rmconf != NULL ? rmconf->nonce_size : DEFAULT_NONCE_SIZE)
+
+struct dhgroup;
+
 struct idspec {
 	int idtype;                     /* identifier type */
 	vchar_t *id;                    /* identifier */
 };
 
-typedef struct remoteconf * (rmconf_func_t)(struct remoteconf *rmconf, void *data);
+struct rmconfselector {
+	int flags;
+	struct sockaddr *remote;
+	int etype;
+	struct isakmpsa *approval;
+	vchar_t *identity;
+	vchar_t *certificate_request;
+};
 
-extern struct remoteconf *getrmconf __P((struct sockaddr *));
-extern struct remoteconf *getrmconf_strict
-	__P((struct sockaddr *remote, int allow_anon));
-extern struct remoteconf *copyrmconf __P((struct sockaddr *));
+extern void rmconf_selector_from_ph1 __P((struct rmconfselector *rmsel,
+					  struct ph1handle *iph1));
+extern int enumrmconf __P((struct rmconfselector *rmsel,
+			   int (* enum_func)(struct remoteconf *rmconf, void *arg),
+			   void *enum_arg));
+
+#define GETRMCONF_F_NO_ANONYMOUS	0x0001
+#define GETRMCONF_F_NO_PASSIVE		0x0002
+
+#define RMCONF_ERR_MULTIPLE		((struct remoteconf *) -1)
+
+extern int rmconf_match_identity __P((struct remoteconf *rmconf,
+				      vchar_t *id_p));
+extern struct remoteconf *getrmconf __P((struct sockaddr *remote, int flags));
+extern struct remoteconf *getrmconf_by_ph1 __P((struct ph1handle *iph1));
+extern struct remoteconf *getrmconf_by_name __P((const char *name));
+
 extern struct remoteconf *newrmconf __P((void));
-extern struct remoteconf *duprmconf __P((struct remoteconf *));
+extern struct remoteconf *duprmconf_shallow __P((struct remoteconf *));
+extern int duprmconf_finish __P((struct remoteconf *));
 extern void delrmconf __P((struct remoteconf *));
-extern void delisakmpsa __P((struct isakmpsa *));
 extern void deletypes __P((struct etypes *));
 extern struct etypes * dupetypes __P((struct etypes *));
 extern void insrmconf __P((struct remoteconf *));
 extern void remrmconf __P((struct remoteconf *));
 extern void flushrmconf __P((void));
+extern void dupspspec_list __P((struct remoteconf *, struct remoteconf *));
+extern void flushspspec __P((struct remoteconf *));
 extern void initrmconf __P((void));
-extern void save_rmconf __P((void));
-extern void save_rmconf_flush __P((void));
+extern void rmconf_start_reload __P((void));
+extern void rmconf_finish_reload __P((void));
 
-extern struct etypes *check_etypeok
-	__P((struct remoteconf *, u_int8_t));
-extern struct remoteconf *foreachrmconf __P((rmconf_func_t rmconf_func,
-					     void *data));
+extern int check_etypeok __P((struct remoteconf *, void *));
 
 extern struct isakmpsa *newisakmpsa __P((void));
 extern struct isakmpsa *dupisakmpsa __P((struct isakmpsa *));
-
+extern void delisakmpsa __P((struct isakmpsa *));
 extern void insisakmpsa __P((struct isakmpsa *, struct remoteconf *));
+#ifdef ENABLE_HYBRID
+extern int isakmpsa_switch_authmethod __P((int authmethod));
+#else
+static inline int isakmpsa_switch_authmethod(int authmethod)
+{
+	return authmethod;
+}
+#endif
+extern struct isakmpsa * checkisakmpsa __P((int pcheck,
+					    struct isakmpsa *proposal,
+					    struct isakmpsa *acceptable));
+
 
 extern void dumprmconf __P((void));
 
diff --git a/src/racoon/rsalist.c b/src/racoon/rsalist.c
index 850aa4c..f152c82 100644
--- a/src/racoon/rsalist.c
+++ b/src/racoon/rsalist.c
@@ -1,4 +1,4 @@
-/*	$NetBSD: rsalist.c,v 1.4 2006/09/09 16:22:10 manu Exp $	*/
+/*	$NetBSD: rsalist.c,v 1.6 2011/03/14 15:50:36 vanhu Exp $	*/
 
 /* Id: rsalist.c,v 1.3 2004/11/08 12:04:23 ludvigm Exp */
 
@@ -88,6 +88,65 @@
 	return 0;
 }
 
+struct rsa_key *
+rsa_key_dup(struct rsa_key *key)
+{
+	struct rsa_key *new;
+
+	new = calloc(sizeof(struct rsa_key), 1);
+	if (new == NULL)
+		return NULL;
+
+	if (key->rsa) {
+		new->rsa = key->rsa->d != NULL ? RSAPrivateKey_dup(key->rsa) : RSAPublicKey_dup(key->rsa);
+		if (new->rsa == NULL)
+			goto dup_error;
+	}
+
+	if (key->src) {
+		new->src = malloc(sizeof(*new->src));
+		if (new->src == NULL)
+			goto dup_error;
+		memcpy(new->src, key->src, sizeof(*new->src));
+	}	
+	if (key->dst) {
+		new->dst = malloc(sizeof(*new->dst));
+		if (new->dst == NULL)
+			goto dup_error;
+		memcpy(new->dst, key->dst, sizeof(*new->dst));
+	}
+
+	return new;
+
+dup_error:
+	if (new->rsa != NULL)
+		RSA_free(new->rsa);
+	if (new->dst != NULL)
+		free(new->dst);
+	if (new->src != NULL)
+		free(new->src);
+
+	free(new);
+	return NULL;
+}
+
+void
+rsa_key_free(void *data)
+{
+	struct rsa_key *rsa_key;
+
+	
+	rsa_key = (struct rsa_key *)data;
+	if (rsa_key->src)
+		free(rsa_key->src);
+	if (rsa_key->dst)
+		free(rsa_key->dst);
+	if (rsa_key->rsa)
+		RSA_free(rsa_key->rsa);
+
+	free(rsa_key);
+}
+
 static void *
 rsa_key_dump_one(void *entry, void *arg)
 {
diff --git a/src/racoon/rsalist.h b/src/racoon/rsalist.h
index 911670f..bc6a8d9 100644
--- a/src/racoon/rsalist.h
+++ b/src/racoon/rsalist.h
@@ -1,4 +1,4 @@
-/*	$NetBSD: rsalist.h,v 1.4 2006/09/09 16:22:10 manu Exp $	*/
+/*	$NetBSD: rsalist.h,v 1.6 2011/03/14 15:50:36 vanhu Exp $	*/
 
 /* Id: rsalist.h,v 1.2 2004/07/12 20:43:51 ludvigm Exp */
 /*
@@ -53,6 +53,8 @@
 };
 
 int rsa_key_insert(struct genlist *list, struct netaddr *src, struct netaddr *dst, RSA *rsa);
+struct rsa_key *rsa_key_dup(struct rsa_key *key);
+void rsa_key_free(void *data);
 void rsa_key_dump(struct genlist *list);
 
 struct genlist *rsa_lookup_keys(struct ph1handle *iph1, int my);
diff --git a/src/racoon/sainfo.c b/src/racoon/sainfo.c
index afa0aac..b6577c2 100644
--- a/src/racoon/sainfo.c
+++ b/src/racoon/sainfo.c
@@ -1,4 +1,4 @@
-/*	$NetBSD: sainfo.c,v 1.7.6.1 2007/08/01 11:52:22 vanhu Exp $	*/
+/*	$NetBSD: sainfo.c,v 1.14 2011/02/02 15:21:34 vanhu Exp $	*/
 
 /*	$KAME: sainfo.c,v 1.16 2003/06/27 07:32:39 sakane Exp $	*/
 
@@ -64,7 +64,8 @@
 #include "sainfo.h"
 #include "gcmalloc.h"
 
-static LIST_HEAD(_sitree, sainfo) sitree, sitree_save, sitree_tmp;
+typedef LIST_HEAD(_sitree, sainfo) sainfo_tailq_head_t;
+static sainfo_tailq_head_t sitree, sitree_save;
 
 /* %%%
  * modules for ipsec sa info
@@ -76,88 +77,112 @@
  * First pass is for sainfo from a specified peer, second for others.
  */
 struct sainfo *
-getsainfo(loc, rmt, peer, remoteid)
-	const vchar_t *loc, *rmt, *peer;
-	int remoteid;
+getsainfo(loc, rmt, peer, client, remoteid)
+	const vchar_t *loc, *rmt, *peer, *client;
+	uint32_t remoteid;
 {
 	struct sainfo *s = NULL;
-	struct sainfo *anonymous = NULL;
-	int pass = 1;
-
-	if (peer == NULL)
-		pass = 2;
 
 	/* debug level output */
 	if(loglevel >= LLV_DEBUG) {
 		char *dloc, *drmt, *dpeer, *dclient;
- 
+
 		if (loc == NULL)
 			dloc = strdup("ANONYMOUS");
 		else
 			dloc = ipsecdoi_id2str(loc);
- 
-		if (rmt == NULL)
+
+		if (rmt == SAINFO_ANONYMOUS)
 			drmt = strdup("ANONYMOUS");
+		else if (rmt == SAINFO_CLIENTADDR)
+			drmt = strdup("CLIENTADDR");
 		else
 			drmt = ipsecdoi_id2str(rmt);
- 
+
 		if (peer == NULL)
 			dpeer = strdup("NULL");
 		else
 			dpeer = ipsecdoi_id2str(peer);
- 
+
+		if (client == NULL)
+			dclient = strdup("NULL");
+		else
+			dclient = ipsecdoi_id2str(client);
+
 		plog(LLV_DEBUG, LOCATION, NULL,
-			"getsainfo params: loc=\'%s\', rmt=\'%s\', peer=\'%s\', id=%i\n",
-			dloc, drmt, dpeer, remoteid );
+			"getsainfo params: loc=\'%s\' rmt=\'%s\' peer=\'%s\' client=\'%s\' id=%u\n",
+			dloc, drmt, dpeer, dclient, remoteid );
  
                 racoon_free(dloc);
                 racoon_free(drmt);
                 racoon_free(dpeer);
+                racoon_free(dclient);
 	}
 
-    again:
-	plog(LLV_DEBUG, LOCATION, NULL,
-		"getsainfo pass #%i\n", pass);
- 
 	LIST_FOREACH(s, &sitree, chain) {
 		const char *sainfostr = sainfo2str(s);
 		plog(LLV_DEBUG, LOCATION, NULL,
 			"evaluating sainfo: %s\n", sainfostr);
 
-		if(s->remoteid != remoteid)
-			continue;
-
-		if (s->id_i != NULL) {
-			if (pass == 2)
+		if(s->remoteid != remoteid) {
+			plog(LLV_DEBUG, LOCATION, NULL,
+				"remoteid mismatch: %u != %u\n",
+				s->remoteid, remoteid);
 				continue;
+		}
+
+		/* compare 'from' id value */
+		if (s->id_i != NULL)
 			if (ipsecdoi_chkcmpids(peer, s->id_i, 0))
 				continue;
-		} else if (pass == 1)
-			continue;
-		if (s->idsrc == NULL && s->iddst == NULL) {
-			anonymous = s;
+
+		/* compare ids - client */
+		if( s->iddst == SAINFO_CLIENTADDR ) {
+			/*
+			 * This sainfo section enforces client address
+			 * checking. Prevent match if the client value
+			 * ( modecfg or tunnel address ) is NULL.
+			 */
+
+			if (client == NULL)
+				continue;
+
+			if( rmt == SAINFO_CLIENTADDR ) {
+				/*
+				 * In the case where a supplied rmt value is
+				 * also SAINFO_CLIENTADDR, we are comparing
+				 * with another sainfo to check for duplicate.
+				 * Only compare the local values to determine
+				 * a match.
+				 */
+
+				 if (!ipsecdoi_chkcmpids(loc, s->idsrc, 0))
+					return s;
+			}
+			else {
+				/*
+				 * In the case where a supplied rmt value is
+				 * not SAINFO_CLIENTADDR, do a standard match
+				 * for local values and enforce that the rmt
+				 * id matches the client address value.
+				 */
+
+				if (!ipsecdoi_chkcmpids(loc, s->idsrc, 0) &&
+				    !ipsecdoi_chkcmpids(rmt, client, 0))
+					return s;
+			}
+
 			continue;
 		}
 
-		/* anonymous ? */
-		if (loc == NULL) {
-			if (anonymous != NULL)
-				break;
-			continue;
-		}
 
-		/* compare the ids */
+		/* compare ids - standard */
 		if (!ipsecdoi_chkcmpids(loc, s->idsrc, 0) &&
 		    !ipsecdoi_chkcmpids(rmt, s->iddst, 0))
 			return s;
 	}
 
-	if ((anonymous == NULL) && (pass == 1)) {
-		pass++;
-		goto again;
-	}
-
-	return anonymous;
+	return NULL;
 }
 
 struct sainfo *
@@ -186,7 +211,8 @@
 
 	if (si->idsrc)
 		vfree(si->idsrc);
-	if (si->iddst)
+	if (si->iddst != NULL &&
+		si->iddst != SAINFO_CLIENTADDR)
 		vfree(si->iddst);
 
 #ifdef ENABLE_HYBRID
@@ -197,11 +223,75 @@
 	racoon_free(si);
 }
 
+int prisainfo(s)
+	struct sainfo *s;
+{
+	/*
+	 * determine the matching priority
+	 * of an sainfo section
+	 */
+
+	int pri = 0;
+
+	if(s->remoteid)
+		pri += 3;
+
+	if(s->id_i)
+		pri += 3;
+
+	if(s->idsrc)
+		pri++;
+
+	if(s->iddst)
+		pri++;
+
+	return pri;
+}
+
 void
 inssainfo(new)
 	struct sainfo *new;
 {
-	LIST_INSERT_HEAD(&sitree, new, chain);
+	if(LIST_EMPTY(&sitree)) {
+
+		/* first in list */
+		LIST_INSERT_HEAD(&sitree, new, chain);
+	}
+	else {
+		int npri, spri;
+		struct sainfo *s, *n;
+
+		/*
+		 * insert our new sainfo section
+		 * into our list which is sorted
+		 * based on the match priority
+		 */
+
+		npri = prisainfo(new);
+
+		s = LIST_FIRST(&sitree);
+		while (1) {
+
+			spri = prisainfo(s);
+			n = LIST_NEXT(s, chain);
+
+			if(npri > spri)
+			{
+				/* higher priority */
+				LIST_INSERT_BEFORE(s, new, chain);
+				return;
+			}
+
+			if(n == NULL)
+			{
+				/* last in list */
+				LIST_INSERT_AFTER(s, new, chain);
+				return;
+			}
+
+			s = n;
+		}
+	}
 }
 
 void
@@ -276,13 +366,15 @@
 
         char *idloc = NULL, *idrmt = NULL, *id_i;
  
-        if (si->idsrc == NULL)
+        if (si->idsrc == SAINFO_ANONYMOUS)
                 idloc = strdup("ANONYMOUS");
         else
                 idloc = ipsecdoi_id2str(si->idsrc);
  
-        if (si->iddst == NULL)
+        if (si->iddst == SAINFO_ANONYMOUS)
                 idrmt = strdup("ANONYMOUS");
+	else if (si->iddst == SAINFO_CLIENTADDR)
+                idrmt = strdup("CLIENTADDR");
         else
                 idrmt = ipsecdoi_id2str(si->iddst);
  
@@ -291,7 +383,7 @@
         else
                 id_i = ipsecdoi_id2str(si->id_i);
  
-        snprintf(buf, 255, "loc=\'%s\', rmt=\'%s\', peer=\'%s\', id=%i",
+        snprintf(buf, 255, "loc=\'%s\', rmt=\'%s\', peer=\'%s\', id=%u",
 		idloc, idrmt, id_i, si->remoteid);
  
         racoon_free(idloc);
@@ -301,12 +393,14 @@
         return buf;
 }
 
-void save_sainfotree(void){
+void sainfo_start_reload(void){
 	sitree_save=sitree;
 	initsainfo();
 }
 
-void save_sainfotree_flush(void){
+void sainfo_finish_reload(void){
+	sainfo_tailq_head_t sitree_tmp;
+
 	sitree_tmp=sitree;
 	sitree=sitree_save;
 	flushsainfo();
diff --git a/src/racoon/sainfo.h b/src/racoon/sainfo.h
index 357da3f..e708cd6 100644
--- a/src/racoon/sainfo.h
+++ b/src/racoon/sainfo.h
@@ -1,4 +1,4 @@
-/*	$NetBSD: sainfo.h,v 1.5 2006/10/03 08:01:56 vanhu Exp $	*/
+/*	$NetBSD: sainfo.h,v 1.8 2011/02/02 15:21:34 vanhu Exp $	*/
 
 /* Id: sainfo.h,v 1.5 2006/07/09 17:19:38 manubsd Exp */
 
@@ -36,6 +36,9 @@
 
 #include <sys/queue.h>
 
+#define SAINFO_ANONYMOUS	((void *)NULL)
+#define	SAINFO_CLIENTADDR	((void *)~0)
+
 /* SA info */
 struct sainfo {
 	vchar_t *idsrc;
@@ -44,6 +47,7 @@
 		 * idsrc and iddst are constructed body of ID payload.
 		 * that is (struct ipsecdoi_id_b) + ID value.
 		 * If idsrc == NULL, that is anonymous entry.
+		 * If idsrc == ~0, that is client address entry.
 		 */
 
 #ifdef ENABLE_HYBRID
@@ -56,7 +60,7 @@
 	vchar_t *id_i;		/* identifier of the authorized initiator */
 	struct sainfoalg *algs[MAXALGCLASS];
 
-	int remoteid;
+	uint32_t remoteid;
 
 	LIST_ENTRY(sainfo) chain;
 };
@@ -69,7 +73,7 @@
 };
 
 extern struct sainfo *getsainfo __P((const vchar_t *,
-	const vchar_t *, const vchar_t *, int));
+	const vchar_t *, const vchar_t *, const vchar_t *, uint32_t));
 extern struct sainfo *newsainfo __P((void));
 extern void delsainfo __P((struct sainfo *));
 extern void inssainfo __P((struct sainfo *));
@@ -81,8 +85,8 @@
 extern void inssainfoalg __P((struct sainfoalg **, struct sainfoalg *));
 extern const char * sainfo2str __P((const struct sainfo *));
 
-extern void save_sainfotree __P((void));
-extern void save_sainfotree_flush __P((void));
+extern void sainfo_start_reload __P((void));
+extern void sainfo_finish_reload __P((void));
 extern void save_sainfotree_restore __P((void));
 
 #endif /* _SAINFO_H */
diff --git a/src/racoon/samples/roadwarrior/client/phase1-down.sh b/src/racoon/samples/roadwarrior/client/phase1-down.sh
index 8edc187..92f2ba8 100755
--- a/src/racoon/samples/roadwarrior/client/phase1-down.sh
+++ b/src/racoon/samples/roadwarrior/client/phase1-down.sh
@@ -8,10 +8,10 @@
 
 case `uname -s` in
 NetBSD)
-	DEFAULT_GW=`netstat -rn | awk '($1 == "default"){print $2}'`
+	DEFAULT_GW=`netstat -finet -rn | awk '($1 == "default"){print $2; exit}'`
 	;;
 Linux)
-	DEFAULT_GW=`netstat -rn | awk '($1 == "0.0.0.0"){print $2}'`
+	DEFAULT_GW=`netstat --inet -rn | awk '($1 == "0.0.0.0"){print $2; exit}'`
 	;;
 esac
 
@@ -21,24 +21,29 @@
 echo "REMOTE_ADDR = ${REMOTE_ADDR}"
 echo "REMOTE_PORT = ${REMOTE_PORT}"
 echo "DEFAULT_GW = ${DEFAULT_GW}"
+echo "INTERNAL_NETMASK4 = ${INTERNAL_NETMASK4}"
 echo "INTERNAL_ADDR4 = ${INTERNAL_ADDR4}"
 echo "INTERNAL_DNS4 = ${INTERNAL_DNS4}"
 
 echo ${INTERNAL_ADDR4} | grep '[0-9]' > /dev/null || exit 0
+echo ${INTERNAL_NETMASK4} | grep '[0-9]' > /dev/null || exit 0
 echo ${DEFAULT_GW} | grep '[0-9]' > /dev/null || exit 0
 
-test -f /etc/resolv.conf.bak && cp /etc/resolv.conf.bak /etc/resolv.conf
+if [ -f /etc/resolv.conf.bak ]; then
+	rm -f /etc/resolv.conf
+	mv /etc/resolv.conf.bak /etc/resolv.conf
+fi
 
 case `uname -s` in
 NetBSD)
-	if=`netstat -rn|awk '($1 == "default"){print $7}'`
-	ifconfig ${if} delete ${INTERNAL_ADDR4}
+	if=`netstat -finet -rn|awk '($1 == "default"){print $7; exit}'`
 	route delete default
 	route delete ${REMOTE_ADDR}
+	ifconfig ${if} delete ${INTERNAL_ADDR4}
 	route add default ${DEFAULT_GW} -ifa ${LOCAL_ADDR}
 	;;
 Linux)
-	if=`netstat -rn|awk '($1 == "0.0.0.0"){print $8}'`
+	if=`netstat --inet -rn|awk '($1 == "0.0.0.0"){print $8; exit}'`
 	route delete default
 	route delete ${REMOTE_ADDR}
 	ifconfig ${if}:1 del ${INTERNAL_ADDR4}
@@ -54,13 +59,13 @@
 	;;
 esac
 
-# Use this for a NAT-T setup
-LOCAL="${LOCAL_ADDR}[${LOCAL_PORT}]"
-REMOTE="${REMOTE_ADDR}[${REMOTE_PORT}]"
-
-# Use this for a non NAT-T setup
-#LOCAL="${LOCAL_ADDR}"
-#REMOTE="${REMOTE_ADDR}"
+LOCAL="${LOCAL_ADDR}"
+REMOTE="${REMOTE_ADDR}"
+if [ "x${LOCAL_PORT}" != "x500" ]; then
+	# NAT-T setup
+	LOCAL="${LOCAL}[${LOCAL_PORT}]"
+	REMOTE="${REMOTE}[${REMOTE_PORT}]"
+fi
 
 echo "
 deleteall ${REMOTE_ADDR} ${LOCAL_ADDR} esp;
diff --git a/src/racoon/samples/roadwarrior/client/phase1-up.sh b/src/racoon/samples/roadwarrior/client/phase1-up.sh
index e45b648..9275811 100755
--- a/src/racoon/samples/roadwarrior/client/phase1-up.sh
+++ b/src/racoon/samples/roadwarrior/client/phase1-up.sh
@@ -7,10 +7,10 @@
 
 case `uname -s` in
 NetBSD)
-	DEFAULT_GW=`netstat -rn | awk '($1 == "default"){print $2}'`
+	DEFAULT_GW=`netstat -finet -rn | awk '($1 == "default"){print $2; exit}'`
 	;;
 Linux)
-	DEFAULT_GW=`netstat -rn | awk '($1 == "0.0.0.0"){print $2}'`
+	DEFAULT_GW=`netstat --inet -rn | awk '($1 == "0.0.0.0"){print $2; exit}'`
 	;;
 esac
 
@@ -21,25 +21,28 @@
 echo "REMOTE_PORT = ${REMOTE_PORT}"
 echo "DEFAULT_GW = ${DEFAULT_GW}"
 echo "INTERNAL_ADDR4 = ${INTERNAL_ADDR4}"
+echo "INTERNAL_NETMASK4 = ${INTERNAL_NETMASK4}"
 echo "INTERNAL_DNS4 = ${INTERNAL_DNS4}"
 
 echo ${INTERNAL_ADDR4} | grep '[0-9]' > /dev/null || exit 0
+echo ${INTERNAL_NETMASK4} | grep '[0-9]' > /dev/null || exit 0
 echo ${DEFAULT_GW} | grep '[0-9]' > /dev/null || exit 0
 
-test -f /etc/resolv.conf.bak || cp /etc/resolv.conf /etc/resolv.conf.bak
-echo "# Generated by racoon on `date`" > /etc/resolv.conf
+mv /etc/resolv.conf /etc/resolv.conf.bak
+( umask 22; touch /etc/resolv.conf )
+echo "# Generated by racoon on `date`" >> /etc/resolv.conf
 echo "nameserver ${INTERNAL_DNS4}" >> /etc/resolv.conf
 
 case `uname -s` in
 NetBSD)
-	if=`netstat -rn|awk '($1 == "default"){print $7}'`
+	if=`netstat -finet -rn|awk '($1 == "default"){print $7; exit}'`
 	ifconfig ${if} alias ${INTERNAL_ADDR4} netmask ${INTERNAL_NETMASK4}
 	route delete default
 	route add default ${DEFAULT_GW} -ifa ${INTERNAL_ADDR4}
 	route add ${REMOTE_ADDR} ${DEFAULT_GW}
 	;;
 Linux)
-	if=`netstat -rn|awk '($1 == "0.0.0.0"){print $8}'`
+	if=`netstat --inet -rn|awk '($1 == "0.0.0.0"){print $8; exit}'`
 	ifconfig ${if}:1 ${INTERNAL_ADDR4}      
 	route delete default
 	route add ${REMOTE_ADDR} gw ${DEFAULT_GW} dev ${if}
@@ -47,13 +50,13 @@
 	;;
 esac
 
-# Use this for a NAT-T setup
-LOCAL="${LOCAL_ADDR}[${LOCAL_PORT}]"
-REMOTE="${REMOTE_ADDR}[${REMOTE_PORT}]"
-
-# Use this for a non NAT-T setup
-#LOCAL="${LOCAL_ADDR}"
-#REMOTE="${REMOTE_ADDR}"
+LOCAL="${LOCAL_ADDR}"
+REMOTE="${REMOTE_ADDR}"
+if [ "x${LOCAL_PORT}" != "x500" ]; then
+	# NAT-T setup
+	LOCAL="${LOCAL}[${LOCAL_PORT}]"
+	REMOTE="${REMOTE}[${REMOTE_PORT}]"
+fi
 
 
 echo "
diff --git a/src/racoon/schedule.c b/src/racoon/schedule.c
index 04723c5..018f920 100644
--- a/src/racoon/schedule.c
+++ b/src/racoon/schedule.c
@@ -1,9 +1,10 @@
-/*	$NetBSD: schedule.c,v 1.4 2006/09/09 16:22:10 manu Exp $	*/
+/*	$NetBSD: schedule.c,v 1.7 2009/01/23 09:10:13 tteras Exp $	*/
 
 /*	$KAME: schedule.c,v 1.19 2001/11/05 10:53:19 sakane Exp $	*/
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * Copyright (C) 2008 Timo Teras.
  * All rights reserved.
  * 
  * Redistribution and use in source and binary forms, with or without
@@ -40,6 +41,7 @@
 #include <sys/socket.h>
 
 #include <stdlib.h>
+#include <unistd.h>
 #include <stdio.h>
 #include <string.h>
 #include <errno.h>
@@ -51,25 +53,46 @@
 #include "var.h"
 #include "gcmalloc.h"
 
-#define FIXY2038PROBLEM
-
 #ifndef TAILQ_FOREACH
 #define TAILQ_FOREACH(elm, head, field) \
         for (elm = TAILQ_FIRST(head); elm; elm = TAILQ_NEXT(elm, field))
 #endif
 
-static struct timeval timeout;
-
-#ifdef FIXY2038PROBLEM
-#define Y2038TIME_T	0x7fffffff
-static time_t launched;		/* time when the program launched. */
-static time_t deltaY2038;
-#endif
-
 static TAILQ_HEAD(_schedtree, sched) sctree;
 
-static void sched_add __P((struct sched *));
-static time_t current_time __P((void));
+void
+sched_get_monotonic_time(tv)
+	struct timeval *tv;
+{
+#ifdef HAVE_CLOCK_MONOTONIC
+	struct timespec ts;
+
+	clock_gettime(CLOCK_MONOTONIC, &ts);
+	tv->tv_sec = ts.tv_sec;
+	tv->tv_usec = ts.tv_nsec / 1000;
+#else
+	gettimeofday(tv, NULL);
+#endif
+}
+
+time_t
+sched_monotonic_to_time_t(tv, now)
+	struct timeval *tv, *now;
+{
+#ifdef HAVE_CLOCK_MONOTONIC
+	struct timeval mynow, res;
+
+	if (now == NULL) {
+		sched_get_monotonic_time(&mynow);
+		now = &mynow;
+	}
+	timersub(now, tv, &res);
+
+	return time(NULL) + res.tv_sec;
+#else
+	return tv->tv_sec;
+#endif
+}
 
 /*
  * schedule handler
@@ -80,42 +103,26 @@
 struct timeval *
 schedular()
 {
-	time_t now, delta;
-	struct sched *p, *next = NULL;
+	static struct timeval timeout;
+	struct timeval now;
+	struct sched *p;
 
-	now = current_time();
+	sched_get_monotonic_time(&now);
+	while (!TAILQ_EMPTY(&sctree) &&
+		timercmp(&TAILQ_FIRST(&sctree)->xtime, &now, <=)) {
+		void (*func)(struct sched *);
 
-        for (p = TAILQ_FIRST(&sctree); p; p = next) {
-		/* if the entry has been daed, remove it */
-		if (p->dead)
-			goto next_schedule;
-
-		/* if the time hasn't come, proceed to the next entry */
-		if (now < p->xtime) {
-			next = TAILQ_NEXT(p, chain);
-			continue;
-		}
-
-		/* mark it with dead. and call the function. */
-		p->dead = 1;
-		if (p->func != NULL)
-			(p->func)(p->param);
-
-	   next_schedule:
-		next = TAILQ_NEXT(p, chain);
-		TAILQ_REMOVE(&sctree, p, chain);
-		racoon_free(p);
+		p = TAILQ_FIRST(&sctree);
+		func = p->func;
+		sched_cancel(p);
+		func(p);
 	}
 
 	p = TAILQ_FIRST(&sctree);
 	if (p == NULL)
 		return NULL;
 
-	now = current_time();
-
-	delta = p->xtime - now;
-	timeout.tv_sec = delta < 0 ? 0 : delta;
-	timeout.tv_usec = 0;
+	timersub(&p->xtime, &now, &timeout);
 
 	return &timeout;
 }
@@ -123,101 +130,46 @@
 /*
  * add new schedule to schedule table.
  */
-struct sched *
-sched_new(tick, func, param)
+void
+sched_schedule(sc, tick, func)
+	struct sched *sc;
 	time_t tick;
-	void (*func) __P((void *));
-	void *param;
+	void (*func) __P((struct sched *));
 {
 	static long id = 1;
-	struct sched *new;
+	struct sched *p;
+	struct timeval now;
 
-	new = (struct sched *)racoon_malloc(sizeof(*new));
-	if (new == NULL)
-		return NULL;
+	sched_cancel(sc);
 
-	memset(new, 0, sizeof(*new));
-	new->func = func;
-	new->param = param;
-
-	new->id = id++;
-	time(&new->created);
-	new->tick = tick;
-
-	new->xtime = current_time() + tick;
-	new->dead = 0;
+	sc->func = func;
+	sc->id = id++;
+	sc->tick.tv_sec = tick;
+	sc->tick.tv_usec = 0;
+	sched_get_monotonic_time(&now);
+	timeradd(&now, &sc->tick, &sc->xtime);
 
 	/* add to schedule table */
-	sched_add(new);
-
-	return(new);
-}
-
-/* add new schedule to schedule table */
-static void
-sched_add(sc)
-	struct sched *sc;
-{
-	struct sched *p;
-
 	TAILQ_FOREACH(p, &sctree, chain) {
-		if (sc->xtime < p->xtime) {
-			TAILQ_INSERT_BEFORE(p, sc, chain);
-			return;
-		}
+		if (timercmp(&sc->xtime, &p->xtime, <))
+			break;
 	}
 	if (p == NULL)
 		TAILQ_INSERT_TAIL(&sctree, sc, chain);
-
-	return;
+	else
+		TAILQ_INSERT_BEFORE(p, sc, chain);
 }
 
-/* get current time.
- * if defined FIXY2038PROBLEM, base time is the time when called sched_init().
- * Otherwise, conform to time(3).
+/*
+ * cancel scheduled callback
  */
-static time_t
-current_time()
-{
-	time_t n;
-#ifdef FIXY2038PROBLEM
-	time_t t;
-
-	time(&n);
-	t = n - launched;
-	if (t < 0)
-		t += deltaY2038;
-
-	return t;
-#else
-	return time(&n);
-#endif
-}
-
 void
-sched_kill(sc)
+sched_cancel(sc)
 	struct sched *sc;
 {
-	sc->dead = 1;
-
-	return;
-}
-
-/* XXX this function is probably unnecessary. */
-void
-sched_scrub_param(param)
-	void *param;
-{
-	struct sched *sc;
-
-	TAILQ_FOREACH(sc, &sctree, chain) {
-		if (sc->param == param) {
-			if (!sc->dead) {
-				plog(LLV_DEBUG, LOCATION, NULL,
-				    "an undead schedule has been deleted.\n");
-			}
-			sched_kill(sc);
-		}
+	if (sc->func != NULL) {
+		TAILQ_REMOVE(&sctree, sc, chain);
+		sc->func = NULL;
 	}
 }
 
@@ -232,6 +184,7 @@
 	caddr_t new;
 	struct sched *p;
 	struct scheddump *dst;
+	struct timeval now, created;
 	int cnt = 0;
 
 	/* initialize */
@@ -252,12 +205,14 @@
 		return -1;
 	dst = (struct scheddump *)new;
 
-        p = TAILQ_FIRST(&sctree);
+	sched_get_monotonic_time(&now);
+	p = TAILQ_FIRST(&sctree);
 	while (p) {
-		dst->xtime = p->xtime;
+		timersub(&p->xtime, &p->tick, &created);
+		dst->xtime = p->xtime.tv_sec;
 		dst->id = p->id;
-		dst->created = p->created;
-		dst->tick = p->tick;
+		dst->created = sched_monotonic_to_time_t(&created, &now);
+		dst->tick = p->tick.tv_sec;
 
 		p = TAILQ_NEXT(p, chain);
 		if (p == NULL)
@@ -274,15 +229,7 @@
 void
 sched_init()
 {
-#ifdef FIXY2038PROBLEM
-	time(&launched);
-
-	deltaY2038 = Y2038TIME_T - launched;
-#endif
-
 	TAILQ_INIT(&sctree);
-
-	return;
 }
 
 #ifdef STEST
diff --git a/src/racoon/schedule.h b/src/racoon/schedule.h
index bd66593..228e677 100644
--- a/src/racoon/schedule.h
+++ b/src/racoon/schedule.h
@@ -1,9 +1,10 @@
-/*	$NetBSD: schedule.h,v 1.4.6.1 2007/03/21 14:29:48 vanhu Exp $	*/
+/*	$NetBSD: schedule.h,v 1.8 2009/08/17 12:00:53 vanhu Exp $	*/
 
 /* Id: schedule.h,v 1.5 2006/05/03 21:53:42 vanhu Exp */
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * Copyright (C) 2008 Timo Teras.
  * All rights reserved.
  * 
  * Redistribution and use in source and binary forms, with or without
@@ -34,39 +35,47 @@
 #ifndef _SCHEDULE_H
 #define _SCHEDULE_H
 
+#include <stddef.h>
+
 #include <sys/queue.h>
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+#  include <sys/time.h>
+# else
+#  include <time.h>
+# endif
+#endif
 #include "gnuc.h"
 
+#ifndef offsetof
+#ifdef __compiler_offsetof
+#define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER)
+#else
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+#endif
+#endif
+
+#ifndef container_of
+#define container_of(ptr, type, member) ({                      \
+        const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
+        (type *)( (char *)__mptr - offsetof(type,member) );})
+#endif
+
+
 /* scheduling table */
 /* the head is the nearest event. */
 struct sched {
-	time_t xtime;		/* event time which is as time(3). */
-				/*
-				 * if defined FIXY2038PROBLEM, this time
-				 * is from the time when called sched_init().
-				 */
-	void (*func) __P((void *)); /* call this function when timeout. */
-	void *param;		/* pointer to parameter */
-
-	int dead;		/* dead or alive */
-	long id;		/* for debug */
-	time_t created;		/* for debug */
-	time_t tick;		/* for debug */
-
+	void (*func) __P((struct sched *));	/* callback on timeout */
+	struct timeval xtime;			/* expiration time */
+	struct timeval tick;			/* relative timeout */
 	TAILQ_ENTRY(sched) chain;
+	long id;				/* for debug */
 };
 
-/* cancel schedule */
-#define SCHED_KILL(s)                                                          \
-do {                                                                           \
-	if(s != NULL){	   														\
-		sched_kill(s);                                                         \
-		s = NULL;                                                              \
-	}\
-} while(0)
-
-/* must be called after it's called from scheduler. */
-#define SCHED_INIT(s)	(s) = NULL
+#define SCHED_INITIALIZER() { NULL, }
 
 struct scheddump {
 	time_t xtime;
@@ -75,11 +84,16 @@
 	time_t tick;
 };
 
+time_t sched_monotonic_to_time_t __P((struct timeval *tv,
+				      struct timeval *now));
+void sched_get_monotonic_time __P((struct timeval *tv));
+
 struct timeval *schedular __P((void));
-struct sched *sched_new __P((time_t, void (*func) __P((void *)), void *));
-void sched_kill __P((struct sched *));
+void sched_schedule __P((struct sched *, time_t,
+			 void (*func) __P((struct sched *))));
+void sched_cancel __P((struct sched *));
+
 int sched_dump __P((caddr_t *, int *));
 void sched_init __P((void));
-void sched_scrub_param __P((void *));
 
 #endif /* _SCHEDULE_H */
diff --git a/src/racoon/session.c b/src/racoon/session.c
index 9db901d..85e29a3 100644
--- a/src/racoon/session.c
+++ b/src/racoon/session.c
@@ -1,11 +1,11 @@
-/*	$NetBSD: session.c,v 1.7.6.2 2007/08/01 11:52:22 vanhu Exp $	*/
+/*	$NetBSD: session.c,v 1.32 2011/03/02 15:09:16 vanhu Exp $	*/
 
 /*	$KAME: session.c,v 1.32 2003/09/24 02:01:17 jinmei Exp $	*/
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
  * All rights reserved.
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
@@ -17,7 +17,7 @@
  * 3. Neither the name of the project nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
- * 
+ *
  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@@ -59,6 +59,7 @@
 #include <signal.h>
 #include <sys/stat.h>
 #include <paths.h>
+#include <err.h>
 
 #include <netinet/in.h>
 #include <resolv.h>
@@ -77,6 +78,8 @@
 #include "evt.h"
 #include "cfparse_proto.h"
 #include "isakmp_var.h"
+#include "isakmp.h"
+#include "isakmp_var.h"
 #include "isakmp_xauth.h"
 #include "isakmp_cfg.h"
 #include "admin_var.h"
@@ -88,80 +91,174 @@
 #include "localconf.h"
 #include "remoteconf.h"
 #include "backupsa.h"
+#include "remoteconf.h"
 #ifdef ENABLE_NATT
 #include "nattraversal.h"
 #endif
 
-
 #include "algorithm.h" /* XXX ??? */
 
 #include "sainfo.h"
 
+struct fd_monitor {
+	int (*callback)(void *ctx, int fd);
+	void *ctx;
+	int prio;
+	int fd;
+	TAILQ_ENTRY(fd_monitor) chain;
+};
+
+#define NUM_PRIORITIES 2
+
 static void close_session __P((void));
-static void check_rtsock __P((void *));
 static void initfds __P((void));
 static void init_signal __P((void));
 static int set_signal __P((int sig, RETSIGTYPE (*func) __P((int))));
 static void check_sigreq __P((void));
-static void check_flushsa_stub __P((void *));
 static void check_flushsa __P((void));
 static int close_sockets __P((void));
 
-static fd_set mask0;
-static fd_set maskdying;
+static fd_set preset_mask, active_mask;
+static struct fd_monitor fd_monitors[FD_SETSIZE];
+static TAILQ_HEAD(fd_monitor_list, fd_monitor) fd_monitor_tree[NUM_PRIORITIES];
 static int nfds = 0;
+
 static volatile sig_atomic_t sigreq[NSIG + 1];
-static int dying = 0;
+static struct sched scflushsa = SCHED_INITIALIZER();
+
+void
+monitor_fd(int fd, int (*callback)(void *, int), void *ctx, int priority)
+{
+	if (fd < 0 || fd >= FD_SETSIZE) {
+		plog(LLV_ERROR, LOCATION, NULL, "fd_set overrun");
+		exit(1);
+	}
+
+	FD_SET(fd, &preset_mask);
+	if (fd > nfds)
+		nfds = fd;
+	if (priority <= 0)
+		priority = 0;
+	if (priority >= NUM_PRIORITIES)
+		priority = NUM_PRIORITIES - 1;
+
+	fd_monitors[fd].callback = callback;
+	fd_monitors[fd].ctx = ctx;
+	fd_monitors[fd].prio = priority;
+	fd_monitors[fd].fd = fd;
+	TAILQ_INSERT_TAIL(&fd_monitor_tree[priority],
+			  &fd_monitors[fd], chain);
+}
+
+void
+unmonitor_fd(int fd)
+{
+	if (fd < 0 || fd >= FD_SETSIZE) {
+		plog(LLV_ERROR, LOCATION, NULL, "fd_set overrun");
+		exit(1);
+	}
+
+	if (fd_monitors[fd].callback == NULL)
+		return;
+
+	FD_CLR(fd, &preset_mask);
+	FD_CLR(fd, &active_mask);
+	fd_monitors[fd].callback = NULL;
+	fd_monitors[fd].ctx = NULL;
+	TAILQ_REMOVE(&fd_monitor_tree[fd_monitors[fd].prio],
+		     &fd_monitors[fd], chain);
+}
 
 int
 session(void)
 {
-	fd_set rfds;
 	struct timeval *timeout;
 	int error;
-	struct myaddrs *p;
 	char pid_file[MAXPATHLEN];
 	FILE *fp;
 	pid_t racoon_pid = 0;
-	int i;
+	int i, count;
+	struct fd_monitor *fdm;
+
+	nfds = 0;
+	FD_ZERO(&preset_mask);
+
+	for (i = 0; i < NUM_PRIORITIES; i++)
+		TAILQ_INIT(&fd_monitor_tree[i]);
 
 	/* initialize schedular */
 	sched_init();
-
 	init_signal();
 
+	if (pfkey_init() < 0)
+		errx(1, "failed to initialize pfkey socket");
+
+	if (isakmp_init() < 0)
+		errx(1, "failed to initialize ISAKMP structures");
+
+#ifdef ENABLE_HYBRID
+	if (isakmp_cfg_init(ISAKMP_CFG_INIT_COLD))
+		errx(1, "could not initialize ISAKMP mode config structures");
+#endif
+
+#ifdef HAVE_LIBLDAP
+	if (xauth_ldap_init_conf() != 0)
+		errx(1, "could not initialize ldap config");
+#endif
+
+#ifdef HAVE_LIBRADIUS
+	if (xauth_radius_init_conf(0) != 0)
+		errx(1, "could not initialize radius config");
+#endif
+
+	myaddr_init_lists();
+
+	/*
+	 * in order to prefer the parameters by command line,
+	 * saving some parameters before parsing configuration file.
+	 */
+	save_params();
+	if (cfparse() != 0)
+		errx(1, "failed to parse configuration file.");
+	restore_params();
+
 #ifdef ENABLE_ADMINPORT
 	if (admin_init() < 0)
-		exit(1);
+		errx(1, "failed to initialize admin port socket");
 #endif
 
-	initmyaddr();
 
-	if (isakmp_init() < 0)
-		exit(1);
+#ifdef ENABLE_HYBRID
+	if(isakmp_cfg_config.network4 && isakmp_cfg_config.pool_size == 0)
+		if ((error = isakmp_cfg_resize_pool(ISAKMP_CFG_MAX_CNX)) != 0)
+			return error;
+#endif
 
-	initfds();
+	if (dump_config)
+		dumprmconf();
+
+#ifdef HAVE_LIBRADIUS
+	if (xauth_radius_init() != 0)
+		errx(1, "could not initialize libradius");
+#endif
+
+	if (myaddr_init() != 0)
+		errx(1, "failed to listen to configured addresses");
+	myaddr_sync();
 
 #ifdef ENABLE_NATT
 	natt_keepalive_init ();
 #endif
 
-	if (privsep_init() != 0)
-		exit(1);
-
-	for (i = 0; i <= NSIG; i++)
-		sigreq[i] = 0;
-
 	/* write .pid file */
-	racoon_pid = getpid();
-	if (lcconf->pathinfo[LC_PATHTYPE_PIDFILE] == NULL) 
+	if (lcconf->pathinfo[LC_PATHTYPE_PIDFILE] == NULL)
 		strlcpy(pid_file, _PATH_VARRUN "racoon.pid", MAXPATHLEN);
-	else if (lcconf->pathinfo[LC_PATHTYPE_PIDFILE][0] == '/') 
+	else if (lcconf->pathinfo[LC_PATHTYPE_PIDFILE][0] == '/')
 		strlcpy(pid_file, lcconf->pathinfo[LC_PATHTYPE_PIDFILE], MAXPATHLEN);
 	else {
 		strlcat(pid_file, _PATH_VARRUN, MAXPATHLEN);
 		strlcat(pid_file, lcconf->pathinfo[LC_PATHTYPE_PIDFILE], MAXPATHLEN);
-	} 
+	}
 	fp = fopen(pid_file, "w");
 	if (fp) {
 		if (fchmod(fileno(fp),
@@ -170,19 +267,26 @@
 			fclose(fp);
 			exit(1);
 		}
-		fprintf(fp, "%ld\n", (long)racoon_pid);
-		fclose(fp);
 	} else {
 		plog(LLV_ERROR, LOCATION, NULL,
 			"cannot open %s", pid_file);
 	}
 
-	while (1) {
-		if (dying)
-			rfds = maskdying;
-		else
-			rfds = mask0;
+	if (privsep_init() != 0)
+		exit(1);
 
+	/*
+	 * The fork()'ed privileged side will close its copy of fp.  We wait
+	 * until here to get the correct child pid.
+	 */
+	racoon_pid = getpid();
+	fprintf(fp, "%ld\n", (long)racoon_pid);
+	fclose(fp);
+
+	for (i = 0; i <= NSIG; i++)
+		sigreq[i] = 0;
+
+	while (1) {
 		/*
 		 * asynchronous requests via signal.
 		 * make sure to reset sigreq to 0.
@@ -192,7 +296,11 @@
 		/* scheduling */
 		timeout = schedular();
 
-		error = select(nfds, &rfds, (fd_set *)0, (fd_set *)0, timeout);
+		/* schedular can change select() mask, so we reset
+		 * the working copy here */
+		active_mask = preset_mask;
+
+		error = select(nfds + 1, &active_mask, NULL, NULL, timeout);
 		if (error < 0) {
 			switch (errno) {
 			case EINTR:
@@ -206,28 +314,24 @@
 			/*NOTREACHED*/
 		}
 
-#ifdef ENABLE_ADMINPORT
-		if ((lcconf->sock_admin != -1) &&
-		    (FD_ISSET(lcconf->sock_admin, &rfds)))
-			admin_handler();
-#endif
+		count = 0;
+		for (i = 0; i < NUM_PRIORITIES; i++) {
+			TAILQ_FOREACH(fdm, &fd_monitor_tree[i], chain) {
+				if (!FD_ISSET(fdm->fd, &active_mask))
+					continue;
 
-		for (p = lcconf->myaddrs; p; p = p->next) {
-			if (!p->addr)
-				continue;
-			if (FD_ISSET(p->sock, &rfds))
-				isakmp_handler(p->sock);
+				FD_CLR(fdm->fd, &active_mask);
+				if (fdm->callback != NULL) {
+					fdm->callback(fdm->ctx, fdm->fd);
+					count++;
+				} else
+					plog(LLV_ERROR, LOCATION, NULL,
+					"fd %d set, but no active callback\n", i);
+			}
+			if (count != 0)
+				break;
 		}
 
-		if (FD_ISSET(lcconf->sock_pfkey, &rfds))
-			pfkey_handler();
-
-		if (lcconf->rtsock >= 0 && FD_ISSET(lcconf->rtsock, &rfds)) {
-			if (update_myaddrs() && lcconf->autograbaddr)
-				check_rtsock(NULL);
-			else
-				initfds();
-		}
 	}
 }
 
@@ -235,84 +339,20 @@
 static void
 close_session()
 {
-#ifdef ENABLE_FASTQUIT
+	evt_generic(EVT_RACOON_QUIT, NULL);
+	pfkey_send_flush(lcconf->sock_pfkey, SADB_SATYPE_UNSPEC);
 	flushph2();
-#endif
 	flushph1();
+	flushrmconf();
+	flushsainfo();
 	close_sockets();
 	backupsa_clean();
 
-	plog(LLV_INFO, LOCATION, NULL, "racoon shutdown\n");
+	plog(LLV_INFO, LOCATION, NULL, "racoon process %d shutdown\n", getpid());
+
 	exit(0);
 }
 
-static void
-check_rtsock(unused)
-	void *unused;
-{
-	isakmp_close();
-	grab_myaddrs();
-	autoconf_myaddrsport();
-	isakmp_open();
-
-	/* initialize socket list again */
-	initfds();
-}
-
-static void
-initfds()
-{
-	struct myaddrs *p;
-
-	nfds = 0;
-
-	FD_ZERO(&mask0);
-	FD_ZERO(&maskdying);
-
-#ifdef ENABLE_ADMINPORT
-	if (lcconf->sock_admin != -1) {
-		if (lcconf->sock_admin >= FD_SETSIZE) {
-			plog(LLV_ERROR, LOCATION, NULL, "fd_set overrun\n");
-			exit(1);
-		}
-		FD_SET(lcconf->sock_admin, &mask0);
-		/* XXX should we listen on admin socket when dying ?
-		 */
-#if 0
-		FD_SET(lcconf->sock_admin, &maskdying);
-#endif
-		nfds = (nfds > lcconf->sock_admin ? nfds : lcconf->sock_admin);
-	}
-#endif
-	if (lcconf->sock_pfkey >= FD_SETSIZE) {
-		plog(LLV_ERROR, LOCATION, NULL, "fd_set overrun\n");
-		exit(1);
-	}
-	FD_SET(lcconf->sock_pfkey, &mask0);
-	FD_SET(lcconf->sock_pfkey, &maskdying);
-	nfds = (nfds > lcconf->sock_pfkey ? nfds : lcconf->sock_pfkey);
-	if (lcconf->rtsock >= 0) {
-		if (lcconf->rtsock >= FD_SETSIZE) {
-			plog(LLV_ERROR, LOCATION, NULL, "fd_set overrun\n");
-			exit(1);
-		}
-		FD_SET(lcconf->rtsock, &mask0);
-		nfds = (nfds > lcconf->rtsock ? nfds : lcconf->rtsock);
-	}
-
-	for (p = lcconf->myaddrs; p; p = p->next) {
-		if (!p->addr)
-			continue;
-		if (p->sock >= FD_SETSIZE) {
-			plog(LLV_ERROR, LOCATION, NULL, "fd_set overrun\n");
-			exit(1);
-		}
-		FD_SET(p->sock, &mask0);
-		nfds = (nfds > p->sock ? nfds : p->sock);
-	}
-	nfds++;
-}
-
 static int signals[] = {
 	SIGHUP,
 	SIGINT,
@@ -331,10 +371,7 @@
 signal_handler(sig)
 	int sig;
 {
-	/* Do not just set it to 1, because we may miss some signals by just setting
-	 * values to 0/1
-	 */
-	sigreq[sig]++;
+	sigreq[sig] = 1;
 }
 
 
@@ -345,27 +382,28 @@
 
 #ifdef ENABLE_HYBRID
 	if ((isakmp_cfg_init(ISAKMP_CFG_INIT_WARM)) != 0) {
-		plog(LLV_ERROR, LOCATION, NULL, 
+		plog(LLV_ERROR, LOCATION, NULL,
 		    "ISAKMP mode config structure reset failed, "
 		    "not reloading\n");
 		return;
 	}
 #endif
 
-	save_sainfotree();
+	sainfo_start_reload();
 
 	/* TODO: save / restore / flush old lcconf (?) / rmtree
 	 */
-/*	initlcconf();*/ /* racoon_conf ? ! */
+	rmconf_start_reload();
 
-	save_rmconf();
-	initrmconf();
+#ifdef HAVE_LIBRADIUS
+	/* free and init radius configuration */
+	xauth_radius_init_conf(1);
+#endif
 
-	/* Do a part of pfkey_init() ?
-	 * SPD reload ?
-	 */
-	
+	pfkey_reload();
+
 	save_params();
+	flushlcconf();
 	error = cfparse();
 	if (error != 0){
 		plog(LLV_ERROR, LOCATION, NULL, "config reload failed\n");
@@ -374,19 +412,17 @@
 	}
 	restore_params();
 
-#if 0	
+#if 0
 	if (dump_config)
 		dumprmconf ();
 #endif
 
-	/* 
-	 * init_myaddr() ?
-	 * If running in privilege separation, do not reinitialize
-	 * the IKE listener, as we will not have the right to 
-	 * setsockopt(IP_IPSEC_POLICY). 
-	 */
-	if (geteuid() == 0)
-		check_rtsock(NULL);
+	myaddr_sync();
+
+#ifdef HAVE_LIBRADIUS
+	/* re-initialize radius state */
+	xauth_radius_init();
+#endif
 
 	/* Revalidate ph1 / ph2tree !!!
 	 * update ctdtree if removing some ph1 !
@@ -395,44 +431,33 @@
 	/* Update ctdtree ?
 	 */
 
-	save_sainfotree_flush();
-	save_rmconf_flush();
+	sainfo_finish_reload();
+	rmconf_finish_reload();
 }
 
 static void
 check_sigreq()
 {
-	int sig;
+	int sig, s;
 
-	/* 
-	 * XXX We are not able to tell if we got 
-	 * several time the same signal. This is
-	 * not a problem for the current code, 
-	 * but we shall remember this limitation.
-	 */
 	for (sig = 0; sig <= NSIG; sig++) {
 		if (sigreq[sig] == 0)
 			continue;
+		sigreq[sig] = 0;
 
-		sigreq[sig]--;
 		switch(sig) {
 		case 0:
 			return;
-			
-			/* Catch up childs, mainly scripts.
-			 */
+
 		case SIGCHLD:
-	    {
-			pid_t pid;
-			int s;
-			
-			pid = wait(&s);
-	    }
-		break;
+			/* Reap all pending children */
+			while (waitpid(-1, &s, WNOHANG) > 0)
+				;
+			break;
 
 #ifdef DEBUG_RECORD_MALLOCATION
-		/* 
-		 * XXX This operation is signal handler unsafe and may lead to 
+		/*
+		 * XXX This operation is signal handler unsafe and may lead to
 		 * crashes and security breaches: See Henning Brauer talk at
 		 * EuroBSDCon 2005. Do not run in production with this option
 		 * enabled.
@@ -448,108 +473,31 @@
 			break;
 
 		case SIGINT:
-		case SIGTERM:			
-			plog(LLV_INFO, LOCATION, NULL, 
+		case SIGTERM:
+			plog(LLV_INFO, LOCATION, NULL,
 			    "caught signal %d\n", sig);
-			EVT_PUSH(NULL, NULL, EVTT_RACOON_QUIT, NULL);
-			pfkey_send_flush(lcconf->sock_pfkey, 
-			    SADB_SATYPE_UNSPEC);
-#ifdef ENABLE_FASTQUIT
 			close_session();
-#else
-			sched_new(1, check_flushsa_stub, NULL);
-#endif
-			dying = 1;
 			break;
 
 		default:
-			plog(LLV_INFO, LOCATION, NULL, 
+			plog(LLV_INFO, LOCATION, NULL,
 			    "caught signal %d\n", sig);
 			break;
 		}
 	}
 }
 
-/*
- * waiting the termination of processing until sending DELETE message
- * for all inbound SA will complete.
- */
-static void
-check_flushsa_stub(p)
-	void *p;
-{
-
-	check_flushsa();
-}
-
-static void
-check_flushsa()
-{
-	vchar_t *buf;
-	struct sadb_msg *msg, *end, *next;
-	struct sadb_sa *sa;
-	caddr_t mhp[SADB_EXT_MAX + 1];
-	int n;
-
-	buf = pfkey_dump_sadb(SADB_SATYPE_UNSPEC);
-	if (buf == NULL) {
-		plog(LLV_DEBUG, LOCATION, NULL,
-		    "pfkey_dump_sadb: returned nothing.\n");
-		return;
-	}
-
-	msg = (struct sadb_msg *)buf->v;
-	end = (struct sadb_msg *)(buf->v + buf->l);
-
-	/* counting SA except of dead one. */
-	n = 0;
-	while (msg < end) {
-		if (PFKEY_UNUNIT64(msg->sadb_msg_len) < sizeof(*msg))
-			break;
-		next = (struct sadb_msg *)((caddr_t)msg + PFKEY_UNUNIT64(msg->sadb_msg_len));
-		if (msg->sadb_msg_type != SADB_DUMP) {
-			msg = next;
-			continue;
-		}
-
-		if (pfkey_align(msg, mhp) || pfkey_check(mhp)) {
-			plog(LLV_ERROR, LOCATION, NULL,
-				"pfkey_check (%s)\n", ipsec_strerror());
-			msg = next;
-			continue;
-		}
-
-		sa = (struct sadb_sa *)(mhp[SADB_EXT_SA]);
-		if (!sa) {
-			msg = next;
-			continue;
-		}
-
-		if (sa->sadb_sa_state != SADB_SASTATE_DEAD) {
-			n++;
-			msg = next;
-			continue;
-		}
-
-		msg = next;
-	}
-
-	if (buf != NULL)
-		vfree(buf);
-
-	if (n) {
-		sched_new(1, check_flushsa_stub, NULL);
-		return;
-	}
-
-	close_session();
-}
-
 static void
 init_signal()
 {
 	int i;
 
+	/*
+	 * Ignore SIGPIPE as we check the return value of system calls
+	 * that write to pipe-like fds.
+	 */
+	signal(SIGPIPE, SIG_IGN);
+
 	for (i = 0; signals[i] != 0; i++)
 		if (set_signal(signals[i], signal_handler) < 0) {
 			plog(LLV_ERROR, LOCATION, NULL,
@@ -582,7 +530,7 @@
 static int
 close_sockets()
 {
-	isakmp_close();
+	myaddr_close();
 	pfkey_close(lcconf->sock_pfkey);
 #ifdef ENABLE_ADMINPORT
 	(void)admin_close();
diff --git a/src/racoon/session.h b/src/racoon/session.h
index 58799ee..7764c62 100644
--- a/src/racoon/session.h
+++ b/src/racoon/session.h
@@ -1,4 +1,4 @@
-/*	$NetBSD: session.h,v 1.4 2006/09/09 16:22:10 manu Exp $	*/
+/*	$NetBSD: session.h,v 1.9 2010/10/21 06:15:28 tteras Exp $	*/
 
 /* Id: session.h,v 1.3 2004/06/11 16:00:17 ludvigm Exp */
 
@@ -37,4 +37,7 @@
 extern int session __P((void));
 extern RETSIGTYPE signal_handler __P((int));
 
+extern void monitor_fd __P((int fd, int (*callback)(void *, int), void *ctx, int priority));
+extern void unmonitor_fd __P((int fd));
+
 #endif /* _SESSION_H */
diff --git a/src/racoon/sockmisc.c b/src/racoon/sockmisc.c
index 16c949d..48bede1 100644
--- a/src/racoon/sockmisc.c
+++ b/src/racoon/sockmisc.c
@@ -1,4 +1,4 @@
-/*	$NetBSD: sockmisc.c,v 1.8.6.1 2007/08/01 11:52:22 vanhu Exp $	*/
+/*	$NetBSD: sockmisc.c,v 1.19 2011/03/14 17:18:13 tteras Exp $	*/
 
 /* Id: sockmisc.c,v 1.24 2006/05/07 21:32:59 manubsd Exp */
 
@@ -56,117 +56,64 @@
 
 #include "var.h"
 #include "misc.h"
+#include "vmbuf.h"
 #include "plog.h"
 #include "sockmisc.h"
 #include "debug.h"
 #include "gcmalloc.h"
 #include "debugrm.h"
 #include "libpfkey.h"
+#include "isakmp_var.h"
 
-#ifndef IP_IPSEC_POLICY
-#define IP_IPSEC_POLICY 16	/* XXX: from linux/in.h */
-#endif
-
-#ifndef IPV6_IPSEC_POLICY
-#define IPV6_IPSEC_POLICY 34	/* XXX: from linux/???.h per
-				   "Tom Lendacky" <toml@us.ibm.com> */
+#ifdef NOUSE_PRIVSEP
+#define BIND bind
+#define SOCKET socket
+#define SETSOCKOPT setsockopt
+#else
+#include "admin.h"
+#include "privsep.h"
+#define BIND privsep_bind
+#define SOCKET privsep_socket
+#define SETSOCKOPT privsep_setsockopt
 #endif
 
 const int niflags = 0;
 
 /*
- * compare two sockaddr without port number.
- * OUT:	0: equal.
- *	1: not equal.
- */
-int
-cmpsaddrwop(addr1, addr2)
-	const struct sockaddr *addr1;
-	const struct sockaddr *addr2;
-{
-	caddr_t sa1, sa2;
-
-	if (addr1 == 0 && addr2 == 0)
-		return 0;
-	if (addr1 == 0 || addr2 == 0)
-		return 1;
-
-#ifdef __linux__
-	if (addr1->sa_family != addr2->sa_family)
-		return 1;
-#else
-	if (addr1->sa_len != addr2->sa_len
-	 || addr1->sa_family != addr2->sa_family)
-		return 1;
-
-#endif /* __linux__ */
-
-	switch (addr1->sa_family) {
-	case AF_INET:
-		sa1 = (caddr_t)&((struct sockaddr_in *)addr1)->sin_addr;
-		sa2 = (caddr_t)&((struct sockaddr_in *)addr2)->sin_addr;
-		if (memcmp(sa1, sa2, sizeof(struct in_addr)) != 0)
-			return 1;
-		break;
-#ifdef INET6
-	case AF_INET6:
-		sa1 = (caddr_t)&((struct sockaddr_in6 *)addr1)->sin6_addr;
-		sa2 = (caddr_t)&((struct sockaddr_in6 *)addr2)->sin6_addr;
-		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)
-			return 1;
-		break;
-#endif
-	default:
-		return 1;
-	}
-
-	return 0;
-}
-
-/*
  * compare two sockaddr with port, taking care wildcard.
  * addr1 is a subject address, addr2 is in a database entry.
  * OUT:	0: equal.
  *	1: not equal.
  */
 int
-cmpsaddrwild(addr1, addr2)
+cmpsaddr(addr1, addr2)
 	const struct sockaddr *addr1;
 	const struct sockaddr *addr2;
 {
 	caddr_t sa1, sa2;
-	u_short port1, port2;
+	u_short port1 = IPSEC_PORT_ANY;
+	u_short port2 = IPSEC_PORT_ANY;
 
-	if (addr1 == 0 && addr2 == 0)
-		return 0;
-	if (addr1 == 0 || addr2 == 0)
-		return 1;
+	if (addr1 == NULL && addr2 == NULL)
+		return CMPSADDR_MATCH;
 
-#ifdef __linux__
-	if (addr1->sa_family != addr2->sa_family)
-		return 1;
-#else
-	if (addr1->sa_len != addr2->sa_len
-	 || addr1->sa_family != addr2->sa_family)
-		return 1;
+	if (addr1 == NULL || addr2 == NULL)
+		return CMPSADDR_MISMATCH;
 
-#endif /* __linux__ */
+	if (addr1->sa_family != addr2->sa_family ||
+	    sysdep_sa_len(addr1) != sysdep_sa_len(addr2))
+		return CMPSADDR_MISMATCH;
 
 	switch (addr1->sa_family) {
+	case AF_UNSPEC:
+		break;
 	case AF_INET:
 		sa1 = (caddr_t)&((struct sockaddr_in *)addr1)->sin_addr;
 		sa2 = (caddr_t)&((struct sockaddr_in *)addr2)->sin_addr;
 		port1 = ((struct sockaddr_in *)addr1)->sin_port;
 		port2 = ((struct sockaddr_in *)addr2)->sin_port;
-		if (!(port1 == IPSEC_PORT_ANY ||
-		      port2 == IPSEC_PORT_ANY ||
-		      port1 == port2))
-			return 1;
 		if (memcmp(sa1, sa2, sizeof(struct in_addr)) != 0)
-			return 1;
+			return CMPSADDR_MISMATCH;
 		break;
 #ifdef INET6
 	case AF_INET6:
@@ -174,89 +121,31 @@
 		sa2 = (caddr_t)&((struct sockaddr_in6 *)addr2)->sin6_addr;
 		port1 = ((struct sockaddr_in6 *)addr1)->sin6_port;
 		port2 = ((struct sockaddr_in6 *)addr2)->sin6_port;
-		if (!(port1 == IPSEC_PORT_ANY ||
-		      port2 == IPSEC_PORT_ANY ||
-		      port1 == port2))
-			return 1;
 		if (memcmp(sa1, sa2, sizeof(struct in6_addr)) != 0)
-			return 1;
+			return CMPSADDR_MISMATCH;
 		if (((struct sockaddr_in6 *)addr1)->sin6_scope_id !=
 		    ((struct sockaddr_in6 *)addr2)->sin6_scope_id)
-			return 1;
+			return CMPSADDR_MISMATCH;
 		break;
 #endif
 	default:
-		return 1;
+		return CMPSADDR_MISMATCH;
 	}
 
-	return 0;
-}
+	if (port1 == port2)
+		return CMPSADDR_MATCH;
 
-/*
- * compare two sockaddr with strict match on port.
- * OUT:	0: equal.
- *	1: not equal.
- */
-int
-cmpsaddrstrict(addr1, addr2)
-	const struct sockaddr *addr1;
-	const struct sockaddr *addr2;
-{
-	caddr_t sa1, sa2;
-	u_short port1, port2;
+	if (port1 == IPSEC_PORT_ANY ||
+	    port2 == IPSEC_PORT_ANY)
+		return CMPSADDR_WILDPORT_MATCH;
 
-	if (addr1 == 0 && addr2 == 0)
-		return 0;
-	if (addr1 == 0 || addr2 == 0)
-		return 1;
-
-#ifdef __linux__
-	if (addr1->sa_family != addr2->sa_family)
-		return 1;
-#else
-	if (addr1->sa_len != addr2->sa_len
-	 || addr1->sa_family != addr2->sa_family)
-		return 1;
-
-#endif /* __linux__ */
-
-	switch (addr1->sa_family) {
-	case AF_INET:
-		sa1 = (caddr_t)&((struct sockaddr_in *)addr1)->sin_addr;
-		sa2 = (caddr_t)&((struct sockaddr_in *)addr2)->sin_addr;
-		port1 = ((struct sockaddr_in *)addr1)->sin_port;
-		port2 = ((struct sockaddr_in *)addr2)->sin_port;
-		if (port1 != port2)
-			return 1;
-		if (memcmp(sa1, sa2, sizeof(struct in_addr)) != 0)
-			return 1;
-		break;
-#ifdef INET6
-	case AF_INET6:
-		sa1 = (caddr_t)&((struct sockaddr_in6 *)addr1)->sin6_addr;
-		sa2 = (caddr_t)&((struct sockaddr_in6 *)addr2)->sin6_addr;
-		port1 = ((struct sockaddr_in6 *)addr1)->sin6_port;
-		port2 = ((struct sockaddr_in6 *)addr2)->sin6_port;
-		if (port1 != port2)
-			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)
-			return 1;
-		break;
-#endif
-	default:
-		return 1;
-	}
-
-	return 0;
+	return CMPSADDR_WOP_MATCH;
 }
 
 #ifdef ANDROID_PATCHED
 
 struct sockaddr *getlocaladdr(struct sockaddr *remote)
-{
+{   
     struct sockaddr_storage local;
     socklen_t len = sysdep_sa_len(remote);
     int s = socket(remote->sa_family, SOCK_DGRAM, 0);
@@ -266,13 +155,12 @@
         return NULL;
     }
     close(s);
-    set_port((struct sockaddr *)&local, 0);
     return dupsaddr((struct sockaddr *)&local);
 }
 
 int recvfromto(int s, void *buf, size_t len, int flags, struct sockaddr *from,
                socklen_t *fromlen, struct sockaddr *to, unsigned int *tolen)
-{
+{   
     *tolen = sizeof(struct sockaddr_storage);
     if (getsockname(s, to, (socklen_t *)tolen) == -1) {
         return -1;
@@ -282,7 +170,7 @@
 
 int sendfromto(int s, const void *buf, size_t len, struct sockaddr *from,
                struct sockaddr *to, int count)
-{
+{   
     socklen_t tolen = sysdep_sa_len(to);
     int i;
     for (i = 0; i < count; ++i) {
@@ -294,7 +182,7 @@
 }
 
 int setsockopt_bypass(int s, int family)
-{
+{   
     struct sadb_x_policy p = {
         .sadb_x_policy_len = PFKEY_UNIT64(sizeof(struct sadb_x_policy)),
         .sadb_x_policy_exttype = SADB_X_EXT_POLICY,
@@ -315,7 +203,7 @@
     }
     return 0;
 }
-
+ 
 #else
 
 /* get local address against the destination. */
@@ -335,7 +223,7 @@
 	}
 	
 	/* get real interface received packet */
-	if ((s = socket(remote->sa_family, SOCK_DGRAM, 0)) < 0) {
+	if ((s = SOCKET(remote->sa_family, SOCK_DGRAM, 0)) < 0) {
 		plog(LLV_ERROR, LOCATION, NULL,
 			"socket (%s)\n", strerror(errno));
 		goto err;
@@ -382,8 +270,9 @@
 	u_int *tolen;
 {
 	int otolen;
-	u_int len;
-	struct sockaddr_storage ss;
+	socklen_t slen;
+	int len;
+	union sockaddr_any sa;
 	struct msghdr m;
 	struct cmsghdr *cm;
 	struct iovec iov[2];
@@ -396,8 +285,8 @@
 	struct sockaddr_in6 *sin6;
 #endif
 
-	len = sizeof(ss);
-	if (getsockname(s, (struct sockaddr *)&ss, &len) < 0) {
+	slen = sizeof(sa);
+	if (getsockname(s, &sa.sa, &slen) < 0) {
 		plog(LLV_ERROR, LOCATION, NULL,
 			"getsockname (%s)\n", strerror(errno));
 		return -1;
@@ -430,7 +319,7 @@
 			"cmsg %d %d\n", cm->cmsg_level, cm->cmsg_type);)
 #endif
 #if defined(INET6) && defined(INET6_ADVAPI)
-		if (ss.ss_family == AF_INET6
+		if (sa.sa.sa_family == AF_INET6
 		 && cm->cmsg_level == IPPROTO_IPV6
 		 && cm->cmsg_type == IPV6_PKTINFO
 		 && otolen >= sizeof(*sin6)) {
@@ -449,14 +338,13 @@
 				sin6->sin6_scope_id = pi->ipi6_ifindex;
 			else
 				sin6->sin6_scope_id = 0;
-			sin6->sin6_port =
-				((struct sockaddr_in6 *)&ss)->sin6_port;
+			sin6->sin6_port = sa.sin6.sin6_port;
 			otolen = -1;	/* "to" already set */
 			continue;
 		}
 #endif
 #ifdef __linux__
-		if (ss.ss_family == AF_INET
+		if (sa.sa.sa_family == AF_INET
 		 && cm->cmsg_level == IPPROTO_IP
 		 && cm->cmsg_type == IP_PKTINFO
 		 && otolen >= sizeof(sin)) {
@@ -467,14 +355,13 @@
 			sin->sin_family = AF_INET;
 			memcpy(&sin->sin_addr, &pi->ipi_addr,
 				sizeof(sin->sin_addr));
-			sin->sin_port =
-				((struct sockaddr_in *)&ss)->sin_port;
+			sin->sin_port = sa.sin.sin_port;
 			otolen = -1;	/* "to" already set */
 			continue;
 		}
 #endif
 #if defined(INET6) && defined(IPV6_RECVDSTADDR)
-		if (ss.ss_family == AF_INET6
+		if (sa.sa.sa_family == AF_INET6
 		      && cm->cmsg_level == IPPROTO_IPV6
 		      && cm->cmsg_type == IPV6_RECVDSTADDR
 		      && otolen >= sizeof(*sin6)) {
@@ -485,14 +372,13 @@
 			sin6->sin6_len = sizeof(*sin6);
 			memcpy(&sin6->sin6_addr, CMSG_DATA(cm),
 				sizeof(sin6->sin6_addr));
-			sin6->sin6_port =
-				((struct sockaddr_in6 *)&ss)->sin6_port;
+			sin6->sin6_port = sa.sin6.sin6_port;
 			otolen = -1;	/* "to" already set */
 			continue;
 		}
 #endif
 #ifndef __linux__
-		if (ss.ss_family == AF_INET
+		if (sa.sa.sa_family == AF_INET
 		 && cm->cmsg_level == IPPROTO_IP
 		 && cm->cmsg_type == IP_RECVDSTADDR
 		 && otolen >= sizeof(*sin)) {
@@ -503,7 +389,7 @@
 			sin->sin_len = sizeof(*sin);
 			memcpy(&sin->sin_addr, CMSG_DATA(cm),
 				sizeof(sin->sin_addr));
-			sin->sin_port = ((struct sockaddr_in *)&ss)->sin_port;
+			sin->sin_port = sa.sin.sin_port;
 			otolen = -1;	/* "to" already set */
 			continue;
 		}
@@ -523,7 +409,8 @@
 	struct sockaddr *dst;
 {
 	struct sockaddr_storage ss;
-	u_int len;
+	socklen_t slen;
+	int len = 0;
 	int i;
 
 	if (src->sa_family != dst->sa_family) {
@@ -532,8 +419,8 @@
 		return -1;
 	}
 
-	len = sizeof(ss);
-	if (getsockname(s, (struct sockaddr *)&ss, &len) < 0) {
+	slen = sizeof(ss);
+	if (getsockname(s, (struct sockaddr *)&ss, &slen) < 0) {
 		plog(LLV_ERROR, LOCATION, NULL,
 			"getsockname (%s)\n", strerror(errno));
 		return -1;
@@ -701,7 +588,7 @@
 			 * Better approach is to prepare bind'ed udp sockets for
 			 * each of the interface addresses.
 			 */
-			sendsock = socket(src->sa_family, SOCK_DGRAM, 0);
+			sendsock = SOCKET(src->sa_family, SOCK_DGRAM, 0);
 			if (sendsock < 0) {
 				plog(LLV_ERROR, LOCATION, NULL,
 					"socket (%s)\n", strerror(errno));
@@ -736,7 +623,8 @@
 				return -1;
 			}
 
-			if (bind(sendsock, (struct sockaddr *)src, sysdep_sa_len(src)) < 0) {
+			if (BIND(sendsock, (struct sockaddr *)src,
+				 sysdep_sa_len(src)) < 0) {
 				plog(LLV_ERROR, LOCATION, NULL,
 					"bind 1 (%s)\n", strerror(errno));
 				close(sendsock);
@@ -800,7 +688,7 @@
 			ipsec_strerror());
 		return -1;
 	}
-	if (setsockopt(so, level,
+	if (SETSOCKOPT(so, level,
 	               (level == IPPROTO_IP ?
 	                         IP_IPSEC_POLICY : IPV6_IPSEC_POLICY),
 	               buf, ipsec_get_policylen(buf)) < 0) {
@@ -819,7 +707,7 @@
 			ipsec_strerror());
 		return -1;
 	}
-	if (setsockopt(so, level,
+	if (SETSOCKOPT(so, level,
 	               (level == IPPROTO_IP ?
 	                         IP_IPSEC_POLICY : IPV6_IPSEC_POLICY),
 	               buf, ipsec_get_policylen(buf)) < 0) {
@@ -833,6 +721,8 @@
 	return 0;
 }
 
+#endif
+
 struct sockaddr *
 newsaddr(len)
 	int len;
@@ -858,8 +748,6 @@
 	return new;
 }
 
-#endif
-
 struct sockaddr *
 dupsaddr(src)
 	struct sockaddr *src;
@@ -1114,13 +1002,13 @@
 		free(a2);
 		free(a3);
 	}
-	if (cmpsaddrwop(&sa, &naddr->sa.sa) == 0)
+	if (cmpsaddr(&sa, &naddr->sa.sa) <= CMPSADDR_WOP_MATCH)
 		return naddr->prefix + port_score;
 
 	return -1;
 }
 
-/* Some usefull functions for sockaddr port manipulations. */
+/* Some useful functions for sockaddr port manipulations. */
 u_int16_t
 extract_port (const struct sockaddr *addr)
 {
@@ -1130,6 +1018,8 @@
     return port;
 
   switch (addr->sa_family) {
+    case AF_UNSPEC:
+      break;
     case AF_INET:
       port = ((struct sockaddr_in *)addr)->sin_port;
       break;
diff --git a/src/racoon/sockmisc.h b/src/racoon/sockmisc.h
index a035dec..67bfdaf 100644
--- a/src/racoon/sockmisc.h
+++ b/src/racoon/sockmisc.h
@@ -1,4 +1,4 @@
-/*	$NetBSD: sockmisc.h,v 1.7 2006/09/09 16:22:10 manu Exp $	*/
+/*	$NetBSD: sockmisc.h,v 1.13 2011/03/14 17:18:13 tteras Exp $	*/
 
 /* Id: sockmisc.h,v 1.9 2005/10/05 16:55:41 manubsd Exp */
 
@@ -34,26 +34,34 @@
 #ifndef _SOCKMISC_H
 #define _SOCKMISC_H
 
+#ifndef IP_IPSEC_POLICY
+#define IP_IPSEC_POLICY 16	/* XXX: from linux/in.h */
+#endif
+
+#ifndef IPV6_IPSEC_POLICY
+#define IPV6_IPSEC_POLICY 34	/* XXX: from linux/???.h per
+				   "Tom Lendacky" <toml@us.ibm.com> */
+#endif
+
+union sockaddr_any {
+	struct sockaddr sa;
+	struct sockaddr_in sin;
+	struct sockaddr_in6 sin6;
+};
+
 struct netaddr {
-	union {
-		struct sockaddr sa;
-		struct sockaddr_in sin;
-		struct sockaddr_in6 sin6;
-	} sa;
+	union sockaddr_any sa;
 	unsigned long prefix;
 };
 
 extern const int niflags;
 
-extern int cmpsaddrwop __P((const struct sockaddr *, const struct sockaddr *));
-extern int cmpsaddrwild __P((const struct sockaddr *, const struct sockaddr *));
-extern int cmpsaddrstrict __P((const struct sockaddr *, const struct sockaddr *));
+#define CMPSADDR_MATCH		0
+#define CMPSADDR_WILDPORT_MATCH	1
+#define CMPSADDR_WOP_MATCH	2
+#define CMPSADDR_MISMATCH	3
 
-#ifdef ENABLE_NATT 
-#define CMPSADDR(saddr1, saddr2) cmpsaddrstrict((saddr1), (saddr2))
-#else 
-#define CMPSADDR(saddr1, saddr2) cmpsaddrwop((saddr1), (saddr2))
-#endif
+extern int cmpsaddr __P((const struct sockaddr *, const struct sockaddr *));
 
 extern struct sockaddr *getlocaladdr __P((struct sockaddr *));
 
@@ -81,7 +89,7 @@
 				      const struct netaddr *daddr));
 extern int naddr_score(const struct netaddr *naddr, const struct sockaddr *saddr);
 
-/* Some usefull functions for sockaddr port manipulations. */
+/* Some useful functions for sockaddr port manipulations. */
 extern u_int16_t extract_port __P((const struct sockaddr *addr));
 extern u_int16_t *set_port __P((struct sockaddr *addr, u_int16_t new_port));
 extern u_int16_t *get_port_ptr __P((struct sockaddr *addr));
diff --git a/src/racoon/strnames.c b/src/racoon/strnames.c
index fa5df0f..4906b33 100644
--- a/src/racoon/strnames.c
+++ b/src/racoon/strnames.c
@@ -1,4 +1,4 @@
-/*	$NetBSD: strnames.c,v 1.7.6.1 2007/08/01 11:52:22 vanhu Exp $	*/
+/*	$NetBSD: strnames.c,v 1.9 2008/07/14 05:40:13 tteras Exp $	*/
 
 /*	$KAME: strnames.c,v 1.25 2003/11/13 10:53:26 itojun Exp $	*/
 
@@ -276,6 +276,8 @@
 { ISAKMP_NTYPE_RESPONDER_LIFETIME,	"RESPONDER-LIFETIME",		NULL },
 { ISAKMP_NTYPE_REPLAY_STATUS,		"REPLAY-STATUS",		NULL },
 { ISAKMP_NTYPE_INITIAL_CONTACT,		"INITIAL-CONTACT",		NULL },
+{ ISAKMP_NTYPE_R_U_THERE,		"R-U-THERE",			NULL },
+{ ISAKMP_NTYPE_R_U_THERE_ACK,		"R-U-THERE-ACK",		NULL },
 #ifdef ENABLE_HYBRID
 { ISAKMP_NTYPE_UNITY_HEARTBEAT,		"HEARTBEAT (Unity)",		NULL },
 #endif
diff --git a/src/racoon/throttle.c b/src/racoon/throttle.c
index cd7de1f..84a2d6b 100644
--- a/src/racoon/throttle.c
+++ b/src/racoon/throttle.c
@@ -1,4 +1,4 @@
-/*	$NetBSD: throttle.c,v 1.4 2006/09/09 16:22:10 manu Exp $	*/
+/*	$NetBSD: throttle.c,v 1.7 2011/03/14 17:18:13 tteras Exp $	*/
 
 /* Id: throttle.c,v 1.5 2006/04/05 20:54:50 manubsd Exp */
 
@@ -33,23 +33,10 @@
 
 #include "config.h"
 
-#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#if TIME_WITH_SYS_TIME
-# include <sys/time.h>
-# include <time.h> 
-#else 
-# if HAVE_SYS_TIME_H
-#  include <sys/time.h>
-# else
-#  include <time.h>
-# endif 
-#endif
 #include <sys/param.h>
 #include <sys/queue.h>
-#include <sys/socket.h>
-
 #include <netinet/in.h>
 #include <resolv.h>
 
@@ -58,21 +45,21 @@
 #include "plog.h"
 #include "throttle.h"
 #include "sockmisc.h"
-#include "libpfkey.h"
 #include "isakmp_var.h"
 #include "isakmp.h"
 #include "isakmp_xauth.h"
 #include "isakmp_cfg.h"
 #include "gcmalloc.h"
 
-struct throttle_list throttle_list = TAILQ_HEAD_INITIALIZER(throttle_list);
-
+static struct throttle_list throttle_list =
+	TAILQ_HEAD_INITIALIZER(throttle_list);
 
 struct throttle_entry *
 throttle_add(addr)
 	struct sockaddr *addr;
 {
 	struct throttle_entry *te;
+	struct timeval now, penalty;
 	size_t len;
 
 	len = sizeof(*te) 
@@ -82,7 +69,11 @@
 	if ((te = racoon_malloc(len)) == NULL)
 		return NULL;
 
-	te->penalty = time(NULL) + isakmp_cfg_config.auth_throttle;
+	sched_get_monotonic_time(&now);
+	penalty.tv_sec = isakmp_cfg_config.auth_throttle;
+	penalty.tv_usec = 0;
+	timeradd(&now, &penalty, &te->penalty_ends);
+
 	memcpy(&te->host, addr, sysdep_sa_len(addr));
 	TAILQ_INSERT_HEAD(&throttle_list, te, next);
 
@@ -95,26 +86,25 @@
 	int authfail;
 {
 	struct throttle_entry *te;
+	struct timeval now, res;
 	int found = 0;
-	time_t now;
 
 	if (isakmp_cfg_config.auth_throttle == 0)
 		return 0;
 
-	now = time(NULL);
-
+	sched_get_monotonic_time(&now);
 restart:
 	RACOON_TAILQ_FOREACH_REVERSE(te, &throttle_list, throttle_list, next) {
-	  /*
-	   * Remove outdated entries 
-	   */
-		if (te->penalty < now) {
+		/*
+		 * Remove outdated entries
+		 */
+		if (timercmp(&te->penalty_ends, &now, <)) {
 			TAILQ_REMOVE(&throttle_list, te, next);
 			racoon_free(te);
 			goto restart;
 		}
-			
-		if (cmpsaddrwop(addr, (struct sockaddr *)&te->host) == 0) {
+
+		if (cmpsaddr(addr, (struct sockaddr *) &te->host) <= CMPSADDR_WOP_MATCH) {
 			found = 1;
 			break;
 		}
@@ -130,8 +120,7 @@
 			if ((te = throttle_add(addr)) == NULL) {
 				plog(LLV_ERROR, LOCATION, NULL, 
 				    "Throttle insertion failed\n");
-				return (time(NULL) 
-				    + isakmp_cfg_config.auth_throttle);
+				return isakmp_cfg_config.auth_throttle;
 			}
 		}
 		return 0;
@@ -140,19 +129,21 @@
 		 * We had a match and auth failed, increase penalty.
 		 */
 		if (authfail) {
-			time_t remaining;
-			time_t new;
+			struct timeval remaining, penalty;
 
-			remaining = te->penalty - now;
-			new = remaining + isakmp_cfg_config.auth_throttle;
-
-			if (new > THROTTLE_PENALTY_MAX)
-				new = THROTTLE_PENALTY_MAX;
-
-			te->penalty = now + new;
+			timersub(&te->penalty_ends, &now, &remaining);
+			penalty.tv_sec = isakmp_cfg_config.auth_throttle;
+			penalty.tv_usec = 0;
+			timeradd(&penalty, &remaining, &res);
+			if (res.tv_sec >= THROTTLE_PENALTY_MAX) {
+				res.tv_sec = THROTTLE_PENALTY_MAX;
+				res.tv_usec = 0;
+			}
+			timeradd(&now, &res, &te->penalty_ends);
 		}
 	}
-	
-	return te->penalty;
+
+	timersub(&te->penalty_ends, &now, &res);
+	return res.tv_sec;
 }
 
diff --git a/src/racoon/throttle.h b/src/racoon/throttle.h
index baa9af5..54a8ed1 100644
--- a/src/racoon/throttle.h
+++ b/src/racoon/throttle.h
@@ -1,4 +1,4 @@
-/*	$NetBSD: throttle.h,v 1.4 2006/09/09 16:22:10 manu Exp $	*/
+/*	$NetBSD: throttle.h,v 1.5 2009/01/23 08:25:07 tteras Exp $	*/
 
 /* Id: throttle.h,v 1.1 2004/11/30 00:46:09 manubsd Exp */
 
@@ -34,8 +34,10 @@
 #ifndef _THROTTLE_H
 #define _THROTTLE_H
 
+#include "schedule.h"
+
 struct throttle_entry {
-	int penalty;
+	struct timeval penalty_ends;
 	TAILQ_ENTRY(throttle_entry) next;
 	struct sockaddr_storage host;
 };
diff --git a/src/racoon/var.h b/src/racoon/var.h
index 8abb1c2..2946a9f 100644
--- a/src/racoon/var.h
+++ b/src/racoon/var.h
@@ -1,4 +1,4 @@
-/*	$NetBSD: var.h,v 1.4.6.1 2007/06/06 15:36:38 vanhu Exp $	*/
+/*	$NetBSD: var.h,v 1.5 2007/06/06 15:37:15 vanhu Exp $	*/
 
 /* Id: var.h,v 1.6 2004/11/20 16:16:59 monas Exp */
 
diff --git a/src/racoon/vendorid.c b/src/racoon/vendorid.c
index 82ddfe4..81297bd 100644
--- a/src/racoon/vendorid.c
+++ b/src/racoon/vendorid.c
@@ -1,4 +1,4 @@
-/*	$NetBSD: vendorid.c,v 1.4 2006/09/09 16:22:10 manu Exp $	*/
+/*	$NetBSD: vendorid.c,v 1.8 2009/09/01 12:22:09 tteras Exp $	*/
 
 /* Id: vendorid.c,v 1.10 2006/02/22 16:10:21 vanhu Exp */
 
@@ -53,6 +53,16 @@
 #include "isakmp.h"
 #include "vendorid.h"
 #include "crypto_openssl.h"
+#include "handler.h"
+#include "remoteconf.h"
+#ifdef ENABLE_NATT
+#include "nattraversal.h"
+#endif
+#ifdef ENABLE_HYBRID
+#include <resolv.h>
+#include "isakmp_xauth.h"
+#include "isakmp_cfg.h"
+#endif
 
 static struct vendor_id all_vendor_ids[] = {
 { VENDORID_IPSEC_TOOLS, "IPSec-Tools" },
@@ -205,7 +215,7 @@
  *
  * gen ... points to Vendor ID payload.
  */
-int
+static int
 check_vendorid(struct isakmp_gen *gen)
 {
 	vchar_t vid, *vidhash;
@@ -238,6 +248,44 @@
 	return (VENDORID_UNKNOWN);
 }
 
+int
+handle_vendorid(struct ph1handle *iph1, struct isakmp_gen *gen)
+{
+	int vid_numeric;
+
+	vid_numeric = check_vendorid(gen);
+	if (vid_numeric == VENDORID_UNKNOWN)
+		return vid_numeric;
+
+	iph1->vendorid_mask |= BIT(vid_numeric);
+
+#ifdef ENABLE_NATT
+	if (natt_vendorid(vid_numeric))
+		natt_handle_vendorid(iph1, vid_numeric);
+#endif
+#ifdef ENABLE_HYBRID
+	switch (vid_numeric) {
+	case VENDORID_XAUTH:
+		iph1->mode_cfg->flags |= ISAKMP_CFG_VENDORID_XAUTH;
+		break;
+	case VENDORID_UNITY:
+		iph1->mode_cfg->flags |= ISAKMP_CFG_VENDORID_UNITY;
+		break;
+	default:
+		break;
+	}
+#endif
+#ifdef ENABLE_DPD
+	if (vid_numeric == VENDORID_DPD &&
+	    (iph1->rmconf == NULL || iph1->rmconf->dpd)) {
+		iph1->dpd_support = 1;
+		plog(LLV_DEBUG, LOCATION, NULL, "remote supports DPD\n");
+	}
+#endif
+
+	return vid_numeric;
+}
+
 static vchar_t * 
 vendorid_fixup(vendorid, vidhash)
 	int vendorid;		 
diff --git a/src/racoon/vendorid.h b/src/racoon/vendorid.h
index 7e2dcda..1774575 100644
--- a/src/racoon/vendorid.h
+++ b/src/racoon/vendorid.h
@@ -1,4 +1,4 @@
-/*	$NetBSD: vendorid.h,v 1.4 2006/09/09 16:22:10 manu Exp $	*/
+/*	$NetBSD: vendorid.h,v 1.6 2009/01/23 08:06:56 tteras Exp $	*/
 
 /* Id: vendorid.h,v 1.11 2006/02/17 14:09:10 vanhu Exp */
 
@@ -34,25 +34,26 @@
 #ifndef _VENDORID_H
 #define _VENDORID_H
 
-/* The unknown vendor ID. */
-#define	VENDORID_UNKNOWN	-1
+#ifndef BIT
+#define BIT(x) (1 << (x))
+#endif
 
+/* The unknown vendor ID. */
+#define VENDORID_UNKNOWN	-1
 
 /* Our default vendor ID. */
-#define	VENDORID_DEFAULT	VENDORID_IPSEC_TOOLS
+#define VENDORID_DEFAULT	VENDORID_IPSEC_TOOLS
 
-#define	VENDORID_IPSEC_TOOLS 0		
+#define VENDORID_IPSEC_TOOLS	0
 
-/*
- * Refer to draft-ietf-ipsec-isakmp-gss-auth-06.txt.
- */
-#define	VENDORID_GSSAPI_LONG	1
-#define	VENDORID_GSSAPI		2
-#define	VENDORID_MS_NT5		3
-#define	VENDOR_SUPPORTS_GSSAPI(x)					\
-	((x) == VENDORID_GSSAPI_LONG ||					\
-	 (x) == VENDORID_GSSAPI ||					\
-	 (x) == VENDORID_MS_NT5)
+/* Refer to draft-ietf-ipsec-isakmp-gss-auth-06.txt. */
+#define VENDORID_GSSAPI_LONG	1
+#define VENDORID_GSSAPI		2
+#define VENDORID_MS_NT5		3
+
+#define VENDORID_GSSAPI_MASK	(BIT(VENDORID_GSSAPI_LONG) | \
+				 BIT(VENDORID_GSSAPI) | \
+				 BIT(VENDORID_MS_NT5))
 
 /* NAT-T support */
 #define VENDORID_NATT_00	4
@@ -70,8 +71,7 @@
 #define VENDORID_NATT_FIRST	VENDORID_NATT_00
 #define VENDORID_NATT_LAST	VENDORID_NATT_RFC
 
-
-#define MAX_NATT_VID_COUNT	(VENDORID_NATT_LAST - VENDORID_NATT_FIRST + 1 )
+#define MAX_NATT_VID_COUNT	(VENDORID_NATT_LAST - VENDORID_NATT_FIRST + 1)
 
 /* Hybrid auth */
 #define VENDORID_XAUTH		15
@@ -88,8 +88,7 @@
  * XXX: do some cleanup to have separate lists for "real" vendors (to complete)
  * and "features" VendorIDs
  */
-#define	VENDORID_KAME		19
-
+#define VENDORID_KAME		19
 
 struct vendor_id {
 	int		id;
@@ -98,7 +97,7 @@
 };
 
 vchar_t *set_vendorid __P((int));
-int check_vendorid __P((struct isakmp_gen *));
+int handle_vendorid __P((struct ph1handle *, struct isakmp_gen *));
 
 void compute_vendorids __P((void));
 const char *vid_string_by_id __P((int id));