[openswan] Ikev2 changes from rhel6 to fedora

avesh avesh at fedoraproject.org
Tue Aug 7 20:23:00 UTC 2012


commit 5f429c95abcbc6eee1e06dae09a71196544b8303
Author: Avesh Agarwal <avagarwa at redhat.com>
Date:   Tue Aug 7 16:22:28 2012 -0400

    Ikev2 changes from rhel6 to fedora
    
    - Sha256 changes from rhel6 to fedora
    - Fixed 384/512 changes from rhel6 to fedora
    - Ported cisco-openswan interop changes in aggresive/main mode
    - Labeld-ipsec fixes
    - aes-gcm fixes in ikev1 mode
    - updown netkey script changes related to updating/removing
      interface ip address and routes
    - Fixes related to rhbz 609343
    - Fixes related to rhbz 831676

 openswan-2.6-relpath.patch                         |   24 +-
 openswan-cisco-aggr-mode.patch                     |  169 ++
 openswan-cisco-issues.patch                        |  134 -
 openswan-ikev1-aes-gcm-esp-fixes.patch             |  163 +
 openswan-ikev1-ikev2-sha256.patch                  |  165 ++
 openswan-ikev1-ikev2-sha384-512.patch              |  633 ++++
 openswan-ikev2.patch                               | 3116 ++++++++++++++++++++
 openswan-ipsec-help-524146-509318.patch            |   13 +-
 openswan-labeled-ipsec.patch                       |  115 +
 openswan-updown-netkey.patch                       |   83 +
 openswan.spec                                      |   36 +-
 ...g-password-from-a-file-when-creating-keys.patch |   19 +
 rhbz-609343.patch                                  |   32 +
 rhbz-831676.patch                                  |  107 +
 rhbz-841325.patch                                  |   56 +
 15 files changed, 4718 insertions(+), 147 deletions(-)
---
diff --git a/openswan-2.6-relpath.patch b/openswan-2.6-relpath.patch
index de4dfa8..caa0913 100644
--- a/openswan-2.6-relpath.patch
+++ b/openswan-2.6-relpath.patch
@@ -1,7 +1,14 @@
-diff -urNp openswan-2.6.38-patched/Makefile.inc openswan-2.6.38-current/Makefile.inc
---- openswan-2.6.38-patched/Makefile.inc	2012-05-14 15:17:33.573272378 -0400
-+++ openswan-2.6.38-current/Makefile.inc	2012-05-14 15:18:40.817270688 -0400
-@@ -129,6 +129,8 @@ FINALRCDIR?=$(shell for d in $(INC_RCDIR
+From 4aa18c8394b9d315332a3a0ab8d62fb60a8102db Mon Sep 17 00:00:00 2001
+From: Avesh Agarwal <avagarwa at redhat.com>
+Date: Thu, 29 Sep 2011 15:57:13 -0400
+Subject: Openswan 2.6 relpath changes
+
+
+diff --git a/Makefile.inc b/Makefile.inc
+index c827328..15e4724 100644
+--- a/Makefile.inc
++++ b/Makefile.inc
+@@ -129,6 +129,8 @@ FINALRCDIR?=$(shell for d in $(INC_RCDIRS) ; \
  		do if test -d $(DESTDIR)/$$d ; \
  		then echo $$d ; exit 0 ; \
  		fi ; done ; echo $(INC_RCDEFAULT) )
@@ -10,10 +17,11 @@ diff -urNp openswan-2.6.38-patched/Makefile.inc openswan-2.6.38-current/Makefile
  RCDIR?=$(DESTDIR)$(FINALRCDIR)
  
  
-diff -urNp openswan-2.6.38-patched/programs/setup/Makefile openswan-2.6.38-current/programs/setup/Makefile
---- openswan-2.6.38-patched/programs/setup/Makefile	2012-05-14 15:17:33.568272379 -0400
-+++ openswan-2.6.38-current/programs/setup/Makefile	2012-05-14 15:18:40.817270688 -0400
-@@ -35,7 +35,7 @@ doinstall:: $(PROGRAM) $(CONFFILES) $(EX
+diff --git a/programs/setup/Makefile b/programs/setup/Makefile
+index 7ac3dbe..872cea3 100644
+--- a/programs/setup/Makefile
++++ b/programs/setup/Makefile
+@@ -35,7 +35,7 @@ doinstall:: $(PROGRAM) $(CONFFILES) $(EXTRA8MAN) $(EXTRA5MAN) $(EXTRA5PROC) $(LI
  	@mkdir -p $(RCDIR) $(BINDIR)
  	# install and link everything
  	@$(INSTALL) $(INSTBINFLAGS) setup $(RCDIR)/ipsec
diff --git a/openswan-cisco-aggr-mode.patch b/openswan-cisco-aggr-mode.patch
new file mode 100644
index 0000000..36c9f2e
--- /dev/null
+++ b/openswan-cisco-aggr-mode.patch
@@ -0,0 +1,169 @@
+From 724b4adf9bcaa144cff6bd7cbc6359d005bff5df Mon Sep 17 00:00:00 2001
+From: Avesh Agarwal <avagarwa at redhat.com>
+Date: Tue, 7 Aug 2012 11:31:21 -0400
+Subject: Fixes to solve interop issues between cisco ASA and openswan in
+ aggressive mode.
+
+
+diff --git a/programs/pluto/connections.c b/programs/pluto/connections.c
+index 6e5dbd9..eb2b492 100644
+--- a/programs/pluto/connections.c
++++ b/programs/pluto/connections.c
+@@ -222,7 +222,7 @@ delete_end(struct connection *c UNUSED, struct spd_route *sr UNUSED, struct end
+     pfreeany(e->host_addr_name);
+ }
+ 
+-static void
++void
+ delete_sr(struct connection *c, struct spd_route *sr)
+ {
+     delete_end(c, sr, &sr->this);
+diff --git a/programs/pluto/connections.h b/programs/pluto/connections.h
+index f385e24..36f8517 100644
+--- a/programs/pluto/connections.h
++++ b/programs/pluto/connections.h
+@@ -321,6 +321,7 @@ extern void release_connection(struct connection *c, bool relations);
+ extern void delete_connection(struct connection *c, bool relations);
+ extern void delete_connections_by_name(const char *name, bool strict);
+ extern void delete_every_connection(void);
++extern void delete_sr(struct connection *c, struct spd_route *sr);
+ extern char *add_group_instance(struct connection *group, const ip_subnet *target);
+ extern void remove_group_instance(const struct connection *group, const char *name);
+ extern void release_dead_interfaces(void);
+diff --git a/programs/pluto/ikev1_aggr.c b/programs/pluto/ikev1_aggr.c
+index 8569e2c..3f722af 100644
+--- a/programs/pluto/ikev1_aggr.c
++++ b/programs/pluto/ikev1_aggr.c
+@@ -813,18 +813,6 @@ aggr_inR1_outI2_tail(struct msg_digest *md
+     }
+ #endif
+ 
+-    if(c->newest_isakmp_sa != SOS_NOBODY && st->st_connection->spd.this.xauth_client && st->st_connection->remotepeertype == CISCO) {
+-    DBG(DBG_CONTROL, DBG_log("This seems to be rekey, and XAUTH is not supposed to be done again"));
+-    st->hidden_variables.st_xauth_client_done = TRUE;
+-    st->st_oakley.xauth = 0; 
+-
+-	if(st->st_connection->spd.this.modecfg_client) {
+-	DBG(DBG_CONTROL, DBG_log("This seems to be rekey, and MODECFG is not supposed to be done again"));
+-	st->hidden_variables.st_modecfg_vars_set = TRUE;
+-        st->hidden_variables.st_modecfg_started = TRUE;
+-	}
+-    }
+-
+     c->newest_isakmp_sa = st->st_serialno;
+ 
+     /* save last IV from phase 1 so it can be restored later so anything 
+@@ -931,18 +919,6 @@ aggr_inI2_tail(struct msg_digest *md
+     }
+ #endif
+ 
+-    if(c->newest_isakmp_sa != SOS_NOBODY && st->st_connection->spd.this.xauth_client && st->st_connection->remotepeertype == CISCO) {
+-    DBG(DBG_CONTROL, DBG_log("This seems to be rekey, and XAUTH is not supposed to be done again"));
+-    st->hidden_variables.st_xauth_client_done = TRUE;
+-    st->st_oakley.xauth = 0; 
+-
+-        if(st->st_connection->spd.this.modecfg_client) {
+-        DBG(DBG_CONTROL, DBG_log("This seems to be rekey, and MODECFG is not supposed to be done again"));
+-        st->hidden_variables.st_modecfg_vars_set = TRUE;
+-        st->hidden_variables.st_modecfg_started = TRUE; 
+-        }
+-   }
+-
+     c->newest_isakmp_sa = st->st_serialno;
+ 
+     update_iv(st);	/* Finalize our Phase 1 IV */
+diff --git a/programs/pluto/xauth.c b/programs/pluto/xauth.c
+index 36a9f07..5d437ca 100644
+--- a/programs/pluto/xauth.c
++++ b/programs/pluto/xauth.c
+@@ -1785,7 +1785,9 @@ modecfg_inR1(struct msg_digest *md)
+ 				 , caddr);
+ 		    
+ 		    if(addrbytesptr(&c->spd.this.host_srcip, NULL) == 0
+-		       || isanyaddr(&c->spd.this.host_srcip)) {
++		       || isanyaddr(&c->spd.this.host_srcip)
++			|| c->remotepeertype == CISCO ) { 
++			/*with remotepeertype == CISCO, overwrite the previous address with the new received address*/
+ 			openswan_log("setting ip source address to %s"
+ 				     , caddr);
+ 			c->spd.this.host_srcip = a;
+@@ -1796,6 +1798,7 @@ modecfg_inR1(struct msg_digest *md)
+ 		
+ 		case INTERNAL_IP4_NETMASK:
+ 		{
++		    //struct connection *c = st->st_connection;	
+ 		    ip_address a;
+ 		    char caddr[SUBNETTOT_BUF];
+ 
+@@ -1806,6 +1809,8 @@ modecfg_inR1(struct msg_digest *md)
+ 
+ 		    addrtot(&a, 0, caddr, sizeof(caddr));
+ 		    openswan_log("Received IP4 NETMASK %s", caddr);
++		    //c->spd.this.client.maskbits = masktocount(&a);
++		    //openswan_log("setting received mask of local client to %d", c->spd.this.client.maskbits);
+ 		}
+ 		resp |= LELEM(attr.isaat_af_type);
+ 		break;
+@@ -1835,7 +1840,11 @@ modecfg_inR1(struct msg_digest *md)
+ 			{
+ 			    /* concatenate new IP address string on end of
+ 			     * existing string, separated by ' '.
++			     * concatenate only if the received DNS is not
++			     * already present in the current string.
+ 			     */
++ 
++			    if( !strstr(c->cisco_dns_info, caddr) ) {
+ 			    size_t sz_old = strlen(old);
+ 			    size_t sz_added = strlen(caddr) + 1;
+ 			    char *new = alloc_bytes(sz_old + 1 + sz_added, "cisco_dns_info+");
+@@ -1845,6 +1854,7 @@ modecfg_inR1(struct msg_digest *md)
+ 			    memcpy(new + sz_old + 1, caddr, sz_added);
+ 			    c->cisco_dns_info = new;
+ 			    pfree(old);
++			   }
+ 			}
+ 		    }
+ 
+@@ -1860,18 +1870,22 @@ modecfg_inR1(struct msg_digest *md)
+ 		    break;
+ 
+ 		case CISCO_BANNER:
++		    /*if received again, free the previous and create the new one*/
++		    pfreeany(st->st_connection->cisco_banner);
+ 		    st->st_connection->cisco_banner = cisco_stringify(&strattr,"Cisco Banner");
+                     resp |= LELEM(attr.isaat_af_type);
+                     break;
+ 
+ 		case CISCO_DEF_DOMAIN:
++		    /*if received again, free the previous one and create the new one*/
++		    pfreeany(st->st_connection->cisco_domain_info);
+ 		    st->st_connection->cisco_domain_info = cisco_stringify(&strattr,"Cisco Domain");
+                     resp |= LELEM(attr.isaat_af_type);
+                     break;
+ 
+ 		case CISCO_SPLIT_INC:
+                 {
+-                    struct spd_route *tmp_spd;
++                    struct spd_route *tmp_spd, *tmp_spd1;
+                     ip_address a;
+                     char caddr[SUBNETTOT_BUF];
+                     size_t len = pbs_left(&strattr);
+@@ -1884,6 +1898,18 @@ modecfg_inR1(struct msg_digest *md)
+                     tmp_spd2->that.has_client_wildcard = FALSE;
+                     }
+ 
++					/* receiving remote subnets information again
++					* free the previous ones before proceeding. 
++					*/
++					tmp_spd = tmp_spd2->next;
++					tmp_spd2->next = NULL;
++					while(tmp_spd ) {
++					delete_sr(c, tmp_spd);
++					tmp_spd1 = tmp_spd->next;
++					pfree(tmp_spd);
++					tmp_spd = tmp_spd1;	    	
++					}
++
+                     while (len > 0) {
+                     u_int32_t *ap;
+                     tmp_spd = clone_thing(c->spd, "remote subnets policies");
diff --git a/openswan-ikev1-aes-gcm-esp-fixes.patch b/openswan-ikev1-aes-gcm-esp-fixes.patch
new file mode 100644
index 0000000..87c34d8
--- /dev/null
+++ b/openswan-ikev1-aes-gcm-esp-fixes.patch
@@ -0,0 +1,163 @@
+From d3ca106d9db9e59b03755c66fe71d618357e16bc Mon Sep 17 00:00:00 2001
+From: Avesh Agarwal <avagarwa at redhat.com>
+Date: Fri, 3 Aug 2012 14:49:06 -0400
+Subject: ikev1 aes-gcm esp fixes
+
+
+diff --git a/lib/libopenswan/alg_info.c b/lib/libopenswan/alg_info.c
+index 796fbfb..b5af2ce 100644
+--- a/lib/libopenswan/alg_info.c
++++ b/lib/libopenswan/alg_info.c
+@@ -621,6 +621,26 @@ parser_alg_info_add(struct parser_context *p_ctx
+ 		p_ctx->err="enc_alg not found";
+ 		goto out;
+ 	    }
++
++	    /*AES_GCM_128, AES_GCM_192, AES_GCM_256*/
++	    if(ealg_id == ESP_AES_GCM_8 
++		|| ealg_id == ESP_AES_GCM_12 
++		|| ealg_id == ESP_AES_GCM_16) {
++
++			/*AES-GCM length key length + 4 bytes (32 bits) */
++			if( p_ctx->eklen != 128 
++				&& p_ctx->eklen != 192 
++				&& p_ctx->eklen != 256 ) {
++				p_ctx->err="wrong encryption key length with AES-GCM";
++				goto out;
++			}
++			else {
++				/* increase key length by 4 bytes, RFC 4106 */
++				p_ctx->eklen = p_ctx->eklen + 4 *  BITS_PER_BYTE;
++			}
++
++	    }
++
+ 	    DBG(DBG_CRYPT, DBG_log("parser_alg_info_add() "
+ 				   "ealg_getbyname(\"%s\")=%d",
+ 				   p_ctx->ealg_buf,
+diff --git a/lib/libopenswan/kernel_alg.c b/lib/libopenswan/kernel_alg.c
+index c611a11..b396109 100644
+--- a/lib/libopenswan/kernel_alg.c
++++ b/lib/libopenswan/kernel_alg.c
+@@ -150,6 +150,25 @@ kernel_alg_esp_enc_ok(int alg_id, unsigned int key_len,
+ 	if (!ret) goto out;
+ 
+ 	alg_p=&esp_ealg[alg_id];
++
++	if(alg_id == ESP_AES_GCM_8 
++		|| alg_id == ESP_AES_GCM_12 
++		|| alg_id == ESP_AES_GCM_16) {
++		if(key_len != 128 && key_len!=192 && key_len!=256 ) {
++
++			ugh = builddiag("kernel_alg_db_add() key_len is incorrect: alg_id=%d, "
++                          "key_len=%d, alg_minbits=%d, alg_maxbits=%d",
++                          alg_id, key_len,
++                          alg_p->sadb_alg_minbits,
++                          alg_p->sadb_alg_maxbits);
++			goto out;
++		}
++		else {
++			/* increase key length by 4 bytes (RFC 4106)*/
++			key_len = key_len + 4 * BITS_PER_BYTE;
++		}
++	}
++
+ 	/* 
+ 	 * test #2: if key_len specified, it must be in range 
+ 	 */
+diff --git a/programs/pluto/kernel_netlink.c b/programs/pluto/kernel_netlink.c
+index 830446e..895607c 100644
+--- a/programs/pluto/kernel_netlink.c
++++ b/programs/pluto/kernel_netlink.c
+@@ -1138,15 +1138,31 @@ linux_pfkey_add_aead(void)
+ 	struct sadb_alg alg;
+ 
+ 	alg.sadb_alg_ivlen = 8;
+-	alg.sadb_alg_minbits = 128;
+-	alg.sadb_alg_maxbits = 256;
++	alg.sadb_alg_minbits = 128 + 4 * BITS_PER_BYTE;
++	alg.sadb_alg_maxbits = 256 + 4 * BITS_PER_BYTE;
+ 
+ 	alg.sadb_alg_id = SADB_X_EALG_AES_GCM_ICV8;
+ 	kernel_alg_add(SADB_SATYPE_ESP, SADB_EXT_SUPPORTED_ENCRYPT, &alg);
++
++        alg.sadb_alg_ivlen = 12;
++        alg.sadb_alg_minbits = 128 + 4 * BITS_PER_BYTE;
++        alg.sadb_alg_maxbits = 256 + 4 * BITS_PER_BYTE;
++
+ 	alg.sadb_alg_id = SADB_X_EALG_AES_GCM_ICV12;
+ 	kernel_alg_add(SADB_SATYPE_ESP, SADB_EXT_SUPPORTED_ENCRYPT, &alg);
++
++        alg.sadb_alg_ivlen = 16;
++        alg.sadb_alg_minbits = 128 + 4 * BITS_PER_BYTE;
++        alg.sadb_alg_maxbits = 256 + 4 * BITS_PER_BYTE;
++
+ 	alg.sadb_alg_id = SADB_X_EALG_AES_GCM_ICV16;
+ 	kernel_alg_add(SADB_SATYPE_ESP, SADB_EXT_SUPPORTED_ENCRYPT, &alg);
++
++	/* keeping aes-ccm behaviour intact as before */
++        alg.sadb_alg_ivlen = 8;
++        alg.sadb_alg_minbits = 128;
++        alg.sadb_alg_maxbits = 256;
++
+ 	alg.sadb_alg_id = SADB_X_EALG_AES_CCM_ICV8;
+ 	kernel_alg_add(SADB_SATYPE_ESP, SADB_EXT_SUPPORTED_ENCRYPT, &alg);
+ 	alg.sadb_alg_id = SADB_X_EALG_AES_CCM_ICV12;
+diff --git a/programs/pluto/plutoalg.c b/programs/pluto/plutoalg.c
+index e94cbea..1a5d73e 100644
+--- a/programs/pluto/plutoalg.c
++++ b/programs/pluto/plutoalg.c
+@@ -471,8 +471,18 @@ kernel_alg_db_add(struct db_context *db_ctx
+ 
+ 	    /*	add keylegth if specified in esp= string */
+ 	    if (esp_info->esp_ealg_keylen) {
+-		db_attr_add_values(db_ctx, 
+-				   KEY_LENGTH, esp_info->esp_ealg_keylen);
++
++		if(esp_info->esp_ealg_id == ESP_AES_GCM_8
++			|| esp_info->esp_ealg_id == ESP_AES_GCM_12
++			|| esp_info->esp_ealg_id == ESP_AES_GCM_16 ) {
++
++			db_attr_add_values(db_ctx, 
++				   KEY_LENGTH, esp_info->esp_ealg_keylen - 4 * BITS_PER_BYTE);
++		}
++		else {
++			db_attr_add_values(db_ctx,
++				KEY_LENGTH, esp_info->esp_ealg_keylen );
++		}
+ 	    }
+ 
+ 	} else if(policy & POLICY_AUTHENTICATE) {
+diff --git a/programs/pluto/spdb_v1_struct.c b/programs/pluto/spdb_v1_struct.c
+index 97faf35..14eb8d0 100644
+--- a/programs/pluto/spdb_v1_struct.c
++++ b/programs/pluto/spdb_v1_struct.c
+@@ -2368,7 +2368,12 @@ parse_ipsec_sa_body(
+ 				}
+ 			    break;
+ #endif
+-			    
++                        case ESP_AES_GCM_8:
++                        case ESP_AES_GCM_12:
++                        case ESP_AES_GCM_16:
++                                loglog(RC_LOG_SERIOUS, "kernel algorithm (AES-GCM) does not like: %s", ugh);
++				continue;
++
+ 			case ESP_DES:          /* NOT safe */
+ 			    loglog(RC_LOG_SERIOUS, "1DES was proposed, it is insecure");
+ 			default:
+@@ -2594,7 +2599,13 @@ parse_ipsec_sa_body(
+ 	    st->st_ah.attrs = ah_attrs;
+ 
+ 	st->st_esp.present = esp_seen;
+-	if (esp_seen){
++	if (esp_seen) {
++		if(esp_attrs.transattrs.encrypt ==  ESP_AES_GCM_8 
++			|| esp_attrs.transattrs.encrypt == ESP_AES_GCM_12 
++			|| esp_attrs.transattrs.encrypt == ESP_AES_GCM_16 ) {
++			esp_attrs.transattrs.enckeylen = esp_attrs.transattrs.enckeylen + 4 * BITS_PER_BYTE;
++		}
++
+ 	    st->st_esp.attrs = esp_attrs;
+ 	}
+ 
diff --git a/openswan-ikev1-ikev2-sha256.patch b/openswan-ikev1-ikev2-sha256.patch
new file mode 100644
index 0000000..ed86fcf
--- /dev/null
+++ b/openswan-ikev1-ikev2-sha256.patch
@@ -0,0 +1,165 @@
+From b024dfd54fb31f0b290e98bbae01813ecf3dd334 Mon Sep 17 00:00:00 2001
+From: Avesh Agarwal <avagarwa at redhat.com>
+Date: Fri, 3 Aug 2012 14:05:27 -0400
+Subject: ikev1/ikev2 sha2-256 related changes
+
+
+diff --git a/lib/libopenswan/constants.c b/lib/libopenswan/constants.c
+index e970509..c16ab74 100644
+--- a/lib/libopenswan/constants.c
++++ b/lib/libopenswan/constants.c
+@@ -1226,9 +1226,18 @@ const char *const trans_type_integ_name[]={
+     "auth-des-mac",
+     "auth-kpdk-md5",
+     "auth-aes-xcbc-96",
++    "AUTH_HMAC_MD5_128",
++    "AUTH_HMAC_SHA1_160",
++    "AUTH_AES_CMAC_96",
++    "AUTH_AES_128_GMAC",
++    "AUTH_AES_192_GMAC",
++    "AUTH_AES_256_GMAC",
++    "AUTH_HMAC_SHA2_256_128",
++    "AUTH_HMAC_SHA2_384_192",
++    "AUTH_HMAC_SHA2_512_256",
+ };
+ enum_names trans_type_integ_names =
+-{ IKEv2_AUTH_NONE, IKEv2_AUTH_AES_XCBC_96, trans_type_integ_name, NULL};
++{ IKEv2_AUTH_NONE, IKEv2_AUTH_HMAC_SHA2_512_256, trans_type_integ_name, NULL};
+ 
+ /* Transform-type Integrity */
+ const char *const trans_type_esn_name[]={
+diff --git a/programs/pluto/kernel.c b/programs/pluto/kernel.c
+index c8c8db8..fb1ad51 100644
+--- a/programs/pluto/kernel.c
++++ b/programs/pluto/kernel.c
+@@ -1746,16 +1746,17 @@ setup_half_ipsec_sa(struct state *st, bool inbound)
+         said_next->esatype = ET_ESP;
+         said_next->replay_window = kernel_ops->replay_window;
+         said_next->authalg = ei->authalg;
+-	if( (said_next->authalg == AUTH_ALGORITHM_HMAC_SHA2_256) && (st->st_connection->sha2_truncbug)) {
+-		if(kernel_ops->sha2_truncbug_support){
+-		   DBG_log(" authalg converted for sha2 truncation at 96bits instead of IETF's mandated 128bits");
+-		   /* We need to tell the kernel to mangle the sha2_256, as instructed by the user */
+-		   said_next->authalg = AUTH_ALGORITHM_HMAC_SHA2_256_TRUNCBUG;
+-		} else {
++
++		if( (said_next->authalg == AUTH_ALGORITHM_HMAC_SHA2_256) && (st->st_connection->sha2_truncbug)) {
++			if(kernel_ops->sha2_truncbug_support){
++			   DBG_log(" authalg converted for sha2 truncation at 96bits instead of IETF's mandated 128bits");
++			   /* We need to tell the kernel to mangle the sha2_256, as instructed by the user */
++			   said_next->authalg = AUTH_ALGORITHM_HMAC_SHA2_256_TRUNCBUG;
++			} else {
+                    loglog(RC_LOG_SERIOUS, "Error: %s stack does not support sha2_truncbug=yes", kernel_ops->kern_name);
+-		   goto fail;
++		   	goto fail;
++			}
+ 		}
+-	}
+         said_next->authkeylen = ei->authkeylen;
+         /* said_next->authkey = esp_dst_keymat + ei->enckeylen; */
+         said_next->authkey = esp_dst_keymat + key_len;
+diff --git a/programs/pluto/kernel_netlink.c b/programs/pluto/kernel_netlink.c
+index ef5cd2f..d917ea2 100644
+--- a/programs/pluto/kernel_netlink.c
++++ b/programs/pluto/kernel_netlink.c
+@@ -847,12 +847,11 @@ netlink_add_sa(struct kernel_sa *sa, bool replace)
+ 	 * an earlier draft. The kernel then introduced a new struct xfrm_algo_auth to
+ 	 * replace struct xfrm_algo to deal with this 
+ 	 */
+-	if( (sa->authalg == AUTH_ALGORITHM_HMAC_SHA2_256) ||
+-	    (sa->authalg == AUTH_ALGORITHM_HMAC_SHA2_256_TRUNCBUG) ) {
++	if(sa->authalg == AUTH_ALGORITHM_HMAC_SHA2_256_TRUNCBUG) {
+ 	struct xfrm_algo_auth algo;
+ 	DBG(DBG_NETKEY, DBG_log("  using new struct xfrm_algo_auth for XFRM message with explicit truncation for sha2_256"));
+ 	algo.alg_key_len = sa->authkeylen * BITS_PER_BYTE;
+-	algo.alg_trunc_len = (sa->authalg == AUTH_ALGORITHM_HMAC_SHA2_256_TRUNCBUG) ? 96 : 128;
++	algo.alg_trunc_len = 128;
+ 	attr->rta_type = XFRMA_ALG_AUTH_TRUNC;
+ 	attr->rta_len = RTA_LENGTH(sizeof(algo) + sa->authkeylen);
+ 	sa->authalg = AUTH_ALGORITHM_HMAC_SHA2_256; /* fixup to the real number, not our private number */
+diff --git a/programs/pluto/spdb.h b/programs/pluto/spdb.h
+index 079b6dc..e36f0ba 100644
+--- a/programs/pluto/spdb.h
++++ b/programs/pluto/spdb.h
+@@ -188,6 +188,7 @@ extern void sa_v2_print(struct db_sa *f);
+ extern struct db_sa *sa_v2_convert(struct db_sa *f);
+ extern enum ikev2_trans_type_encr v1tov2_encr(int oakley);
+ extern enum ikev2_trans_type_integ v1tov2_integ(int oakley);
++extern enum ikev2_trans_type_integ v1phase2tov2child_integ(int ikev1_phase2_auth);
+ extern bool ikev2_acceptable_group(struct state *st, oakley_group_t group);
+ 
+ 
+diff --git a/programs/pluto/spdb_v2_struct.c b/programs/pluto/spdb_v2_struct.c
+index 25c686c..a744100 100644
+--- a/programs/pluto/spdb_v2_struct.c
++++ b/programs/pluto/spdb_v2_struct.c
+@@ -288,6 +288,21 @@ enum ikev2_trans_type_integ v1tov2_integ(int oakley)
+    }
+ }
+ 
++enum ikev2_trans_type_integ v1phase2tov2child_integ(int ikev1_phase2_auth)
++{
++    switch(ikev1_phase2_auth) {
++    case AUTH_ALGORITHM_HMAC_MD5:
++        return IKEv2_AUTH_HMAC_MD5_96;
++    case AUTH_ALGORITHM_HMAC_SHA1:
++        return IKEv2_AUTH_HMAC_SHA1_96;
++    case AUTH_ALGORITHM_HMAC_SHA2_256:
++        return IKEv2_AUTH_HMAC_SHA2_256_128;
++    default:
++        return IKEv2_AUTH_INVALID;
++   }
++}
++
++
+ static enum ikev2_trans_type_prf v1tov2_prf(int oakley)
+ {
+     switch(oakley) {
+@@ -385,7 +400,7 @@ struct db_sa *sa_v2_convert(struct db_sa *f)
+ 		    } else {
+ 			switch(attr->type.ipsec) {
+ 			case AUTH_ALGORITHM:
+-			    dtfone->integ_transid = attr->val;
++			    dtfone->integ_transid = v1phase2tov2child_integ(attr->val);
+ 			    break;
+ 			    
+ 			case KEY_LENGTH:
+@@ -1233,7 +1248,7 @@ ikev2_parse_child_sa_body(
+     bool conjunction, gotmatch;
+     struct ikev2_prop winning_prop;
+     struct db_sa *p2alg;
+-    struct trans_attrs ta;
++    struct trans_attrs ta, ta1;
+     struct connection *c = st->st_connection;
+     struct ikev2_transform_list itl0, *itl;
+ 
+@@ -1250,6 +1265,7 @@ ikev2_parse_child_sa_body(
+     gotmatch = FALSE;
+     conjunction = FALSE;
+     zero(&ta);
++    zero(&ta1);
+ 
+     while(np == ISAKMP_NEXT_P) {
+ 	/*
+@@ -1372,6 +1388,12 @@ ikev2_parse_child_sa_body(
+      * algorithms.
+      */
+     ta.integ_hash  = itl->integ_transforms[itl->integ_i];
++
++    /* here we obtain auth value for esp, 
++     * but loosse what is correct to be sent in the propoasl
++     * so preserve the winning proposal.
++     */
++    ta1 = ta;
+     ta.integ_hash  = alg_info_esp_v2tov1aa(ta.integ_hash);
+ 
+     st->st_esp.attrs.transattrs = ta;
+@@ -1386,7 +1408,7 @@ ikev2_parse_child_sa_body(
+     if (r_sa_pbs != NULL)
+     {
+ 	return ikev2_emit_winning_sa(st, r_sa_pbs
+-				     , ta
++				     , ta1
+ 				     , /*parentSA*/FALSE
+ 				     , winning_prop);
+     }
diff --git a/openswan-ikev1-ikev2-sha384-512.patch b/openswan-ikev1-ikev2-sha384-512.patch
new file mode 100644
index 0000000..af26027
--- /dev/null
+++ b/openswan-ikev1-ikev2-sha384-512.patch
@@ -0,0 +1,633 @@
+From 8467b53a014ebf6dcd400c259d2bb2fa8991df3f Mon Sep 17 00:00:00 2001
+From: Avesh Agarwal <avagarwa at redhat.com>
+Date: Fri, 3 Aug 2012 14:41:50 -0400
+Subject: ikev1/ikev2 sha2(384, 512) changes
+
+
+diff --git a/include/ietf_constants.h b/include/ietf_constants.h
+index 28df5a1..d065509 100644
+--- a/include/ietf_constants.h
++++ b/include/ietf_constants.h
+@@ -605,7 +605,6 @@ enum ikev2_trans_type_integ {
+ 	IKEv2_AUTH_HMAC_SHA2_512_256 = 14, /* RFC4306 */
+ 	/* 15 - 1023 Reserved to IANA         RFC4306 */
+ 	/* 1024 - 65535 Private Use           RFC4306 */
+-	IKEv2_AUTH_HMAC_SHA2_256_128_TRUNCBUG = 252, /* our own value */
+ 	IKEv2_AUTH_INVALID     =65536
+ };
+ 
+@@ -795,6 +794,8 @@ enum ikev1_auth_attribute {
+ 	AUTH_ALGORITHM_AES_CBC=9,
+ 	AUTH_ALGORITHM_NULL_KAME=251, /* why do we load this ? */
+ 	AUTH_ALGORITHM_HMAC_SHA2_256_TRUNCBUG=252,
++	AUTH_ALGORITHM_HMAC_SHA2_384_TRUNCBUG=253,
++	AUTH_ALGORITHM_HMAC_SHA2_512_TRUNCBUG=254,
+ };
+ 
+ typedef u_int16_t ipsec_auth_t;
+diff --git a/include/linux/pfkeyv2.h b/include/linux/pfkeyv2.h
+index 2a53c3d..6cb3b81 100644
+--- a/include/linux/pfkeyv2.h
++++ b/include/linux/pfkeyv2.h
+@@ -279,6 +279,8 @@ struct sadb_x_nat_t_port {
+ #define SADB_X_AALG_RIPEMD160HMAC	8
+ #define SADB_X_AALG_NULL		251	/* kame */
+ #define SADB_X_AALG_SHA2_256HMAC_TRUNCBUG	252
++#define SADB_X_AALG_SHA2_384HMAC_TRUNCBUG       253
++#define SADB_X_AALG_SHA2_512HMAC_TRUNCBUG       254
+ #define SADB_AALG_MAX			255 /* while the AUTH_ALGORITHM is two octets, what is the SADB_AALG? */
+ 
+ /* Encryption algorithms */
+diff --git a/lib/libopenswan/alg_info.c b/lib/libopenswan/alg_info.c
+index 320cbd4..796fbfb 100644
+--- a/lib/libopenswan/alg_info.c
++++ b/lib/libopenswan/alg_info.c
+@@ -84,12 +84,10 @@ alg_info_esp_v2tov1aa(enum ikev2_trans_type_integ ti)
+ 	return AUTH_ALGORITHM_HMAC_SHA1;
+     case IKEv2_AUTH_HMAC_SHA2_256_128: 
+ 	return AUTH_ALGORITHM_HMAC_SHA2_256;
+-    case IKEv2_AUTH_HMAC_SHA2_256_128_TRUNCBUG:
+-	return AUTH_ALGORITHM_HMAC_SHA2_256_TRUNCBUG;
+     case IKEv2_AUTH_HMAC_SHA2_384_192: 
+-	return AUTH_ALGORITHM_HMAC_SHA2_256;
++	return AUTH_ALGORITHM_HMAC_SHA2_384;
+     case IKEv2_AUTH_HMAC_SHA2_512_256: 
+-	return AUTH_ALGORITHM_HMAC_SHA2_256;
++	return AUTH_ALGORITHM_HMAC_SHA2_512;
+ 
+     /* invalid or not yet supported */
+     case IKEv2_AUTH_DES_MAC:
+@@ -635,12 +633,6 @@ parser_alg_info_add(struct parser_context *p_ctx
+ 		goto out;
+ 	    }
+ 
+-#ifdef HAVE_LIBNSS
+-            if ( Pluto_IsFIPS() && ((aalg_id == OAKLEY_SHA2_256 ) ||(aalg_id == OAKLEY_SHA2_384 ) || (aalg_id == OAKLEY_SHA2_512 ))  ) {
+-                p_ctx->err="SHA2 Not supported in FIPS mode with NSS";
+-                goto out;
+-            }
+-#endif
+ 	    DBG(DBG_CRYPT, DBG_log("parser_alg_info_add() "
+ 				   "aalg_getbyname(\"%s\")=%d",
+ 				   p_ctx->aalg_buf,
+diff --git a/linux/include/openswan/pfkeyv2.h b/linux/include/openswan/pfkeyv2.h
+index a3b810c..27a8849 100644
+--- a/linux/include/openswan/pfkeyv2.h
++++ b/linux/include/openswan/pfkeyv2.h
+@@ -276,7 +276,9 @@ enum sadb_aalg {
+ 	K_SADB_X_AALG_SHA2_256HMAC=SADB_X_AALG_SHA2_256HMAC,
+ 	K_SADB_X_AALG_SHA2_256HMAC_TRUNCBUG=SADB_X_AALG_SHA2_256HMAC_TRUNCBUG,
+ 	K_SADB_X_AALG_SHA2_384HMAC=SADB_X_AALG_SHA2_384HMAC,
++	K_SADB_X_AALG_SHA2_384HMAC_TRUNCBUG=SADB_X_AALG_SHA2_384HMAC_TRUNCBUG,
+ 	K_SADB_X_AALG_SHA2_512HMAC=SADB_X_AALG_SHA2_512HMAC,
++	K_SADB_X_AALG_SHA2_512HMAC_TRUNCBUG=SADB_X_AALG_SHA2_512HMAC_TRUNCBUG,
+ 	K_SADB_X_AALG_RIPEMD160HMAC=SADB_X_AALG_RIPEMD160HMAC,
+ 	K_SADB_X_AALG_NULL=SADB_X_AALG_NULL,
+ };
+diff --git a/programs/pluto/crypt_dh.c b/programs/pluto/crypt_dh.c
+index a350acf..e6f6f2e 100644
+--- a/programs/pluto/crypt_dh.c
++++ b/programs/pluto/crypt_dh.c
+@@ -296,7 +296,7 @@ skeyid_preshared(const chunk_t pss
+     chunk_t nir;
+     int k;
+     CK_MECHANISM_TYPE mechanism;
+-    u_char buf1[HMAC_BUFSIZE], buf2[HMAC_BUFSIZE];
++    u_char buf1[HMAC_BUFSIZE*2], buf2[HMAC_BUFSIZE*2];
+     chunk_t buf1_chunk, buf2_chunk;
+     PK11SymKey *shared, *skeyid;
+ 
+@@ -317,9 +317,9 @@ skeyid_preshared(const chunk_t pss
+     memcpy(nir.ptr, ni.ptr, ni.len);
+     memcpy(nir.ptr+ ni.len, nr.ptr, nr.len);
+ 
+-    memset(buf1, '\0', HMAC_BUFSIZE);
++    memset(buf1, '\0', HMAC_BUFSIZE*2);
+ 
+-    if (pss.len <= HMAC_BUFSIZE)
++    if (pss.len <= hasher->hash_block_size)
+     {
+         memcpy(buf1, pss.ptr, pss.len);
+     }
+@@ -330,9 +330,9 @@ skeyid_preshared(const chunk_t pss
+         hasher->hash_final(buf1, &ctx.hash_ctx);
+     }
+ 
+-    memcpy(buf2, buf1, HMAC_BUFSIZE);
++    memcpy(buf2, buf1, hasher->hash_block_size);
+ 
+-    for (k = 0; k < HMAC_BUFSIZE; k++)
++    for (k = 0; k < hasher->hash_block_size; k++)
+     {
+         buf1[k] ^= HMAC_IPAD;
+         buf2[k] ^= HMAC_OPAD;
+@@ -342,16 +342,16 @@ skeyid_preshared(const chunk_t pss
+ 
+     mechanism=nss_key_derivation_mech(hasher);
+     buf1_chunk.ptr=buf1;
+-    buf1_chunk.len=HMAC_BUFSIZE;
++    buf1_chunk.len=hasher->hash_block_size;
+ 
+     buf2_chunk.ptr=buf2;
+-    buf2_chunk.len=HMAC_BUFSIZE;
++    buf2_chunk.len=hasher->hash_block_size;
+ 
+     PK11SymKey *tkey4 = pk11_derive_wrapper_osw(shared, CKM_CONCATENATE_DATA_AND_BASE, buf1_chunk, CKM_EXTRACT_KEY_FROM_KEY, CKA_DERIVE, 0);
+     /* nss_symkey_log(tkey4, "pss+ipad+shared"); */
+ 
+     CK_EXTRACT_PARAMS bs=0;
+-    PK11SymKey *tkey5 = pk11_extract_derive_wrapper_osw(tkey4, bs, CKM_CONCATENATE_BASE_AND_DATA, CKA_DERIVE, HMAC_BUFSIZE);
++    PK11SymKey *tkey5 = pk11_extract_derive_wrapper_osw(tkey4, bs, CKM_CONCATENATE_BASE_AND_DATA, CKA_DERIVE, hasher->hash_block_size);
+     /* nss_symkey_log(tkey5, "pss+ipad"); */
+ 
+     PK11SymKey *tkey6 = pk11_derive_wrapper_osw(tkey5, CKM_CONCATENATE_BASE_AND_DATA, nir, mechanism, CKA_DERIVE, 0);
+@@ -405,7 +405,7 @@ skeyid_digisig(const chunk_t ni
+ #ifdef HAVE_LIBNSS
+     int k;
+     CK_MECHANISM_TYPE mechanism;
+-    u_char buf1[HMAC_BUFSIZE], buf2[HMAC_BUFSIZE];
++    u_char buf1[HMAC_BUFSIZE*2], buf2[HMAC_BUFSIZE*2];
+     chunk_t buf1_chunk, buf2_chunk;
+     PK11SymKey *shared, *skeyid;
+ #endif
+@@ -435,8 +435,8 @@ skeyid_digisig(const chunk_t ni
+     hmac_final_chunk(*skeyid_chunk, "st_skeyid in skeyid_digisig()", &ctx);
+     DBG(DBG_CRYPT, DBG_dump_chunk("keyid: ", *skeyid_chunk));
+ #else
+-    memset(buf1, '\0', HMAC_BUFSIZE);
+-    if (nir.len <= HMAC_BUFSIZE)
++    memset(buf1, '\0', HMAC_BUFSIZE*2);
++    if (nir.len <= hasher->hash_block_size)
+     {
+ 	memcpy(buf1, nir.ptr, nir.len);
+     }
+@@ -447,9 +447,9 @@ skeyid_digisig(const chunk_t ni
+ 	hasher->hash_final(buf1, &ctx.hash_ctx);
+     }
+ 
+-    memcpy(buf2, buf1, HMAC_BUFSIZE);
++    memcpy(buf2, buf1, hasher->hash_block_size);
+ 
+-    for (k = 0; k < HMAC_BUFSIZE; k++)
++    for (k = 0; k < hasher->hash_block_size; k++)
+     {
+ 	buf1[k] ^= HMAC_IPAD;
+ 	buf2[k] ^= HMAC_OPAD;
+@@ -458,10 +458,10 @@ skeyid_digisig(const chunk_t ni
+     pfree(nir.ptr);
+     mechanism=nss_key_derivation_mech(hasher);
+     buf1_chunk.ptr=buf1;
+-    buf1_chunk.len=HMAC_BUFSIZE;
++    buf1_chunk.len=hasher->hash_block_size;
+ 
+     buf2_chunk.ptr=buf2;
+-    buf2_chunk.len=HMAC_BUFSIZE;
++    buf2_chunk.len=hasher->hash_block_size;
+ 
+     PK11SymKey *tkey1 = pk11_derive_wrapper_osw(shared, CKM_CONCATENATE_DATA_AND_BASE, buf1_chunk, mechanism, CKA_DERIVE, 0);
+     PK11SymKey *tkey2 = PK11_Derive_osw(tkey1, mechanism, NULL, CKM_CONCATENATE_DATA_AND_BASE, CKA_DERIVE, 0);
+@@ -562,9 +562,9 @@ calc_skeyids_iv(struct pcr_skeyid_q *skq
+     CK_OBJECT_HANDLE keyhandle;
+     SECItem param, param1;
+ 
+-    hmac_opad = hmac_pads(HMAC_OPAD,HMAC_BUFSIZE);
+-    hmac_ipad = hmac_pads(HMAC_IPAD,HMAC_BUFSIZE);
+-    hmac_pad  = hmac_pads(0x00,HMAC_BUFSIZE-hasher->hash_digest_len);
++    hmac_opad = hmac_pads(HMAC_OPAD,hasher->hash_block_size);
++    hmac_ipad = hmac_pads(HMAC_IPAD,hasher->hash_block_size);
++    hmac_pad  = hmac_pads(0x00,hasher->hash_block_size-hasher->hash_digest_len);
+     hmac_zerobyte = hmac_pads(0x00,1);
+     hmac_val1 = hmac_pads(0x01,1);
+     hmac_val2 = hmac_pads(0x02,1);
+@@ -573,7 +573,7 @@ calc_skeyids_iv(struct pcr_skeyid_q *skq
+ 
+     /*Deriving SKEYID_d = hmac_xxx(SKEYID, g^xy | CKY-I | CKY-R | 0) */
+     PK11SymKey *tkey1 = pk11_derive_wrapper_osw(skeyid, CKM_CONCATENATE_BASE_AND_DATA
+-                                                , hmac_pad,CKM_XOR_BASE_AND_DATA, CKA_DERIVE, HMAC_BUFSIZE);
++                                                , hmac_pad,CKM_XOR_BASE_AND_DATA, CKA_DERIVE, hasher->hash_block_size);
+ 
+     PR_ASSERT(tkey1!=NULL);
+ 
+@@ -742,7 +742,7 @@ calc_skeyids_iv(struct pcr_skeyid_q *skq
+         /* nss_symkey_log(skeyid_e, "skeyid_e"); */
+ 
+         PK11SymKey *tkey25 = pk11_derive_wrapper_osw(skeyid_e, CKM_CONCATENATE_BASE_AND_DATA
+-                                                , hmac_pad,CKM_XOR_BASE_AND_DATA, CKA_DERIVE, HMAC_BUFSIZE);
++                                                , hmac_pad,CKM_XOR_BASE_AND_DATA, CKA_DERIVE, hasher->hash_block_size);
+         PR_ASSERT(tkey25!=NULL);
+ 
+         PK11SymKey *tkey26 = pk11_derive_wrapper_osw(tkey25, CKM_XOR_BASE_AND_DATA
+@@ -776,7 +776,7 @@ calc_skeyids_iv(struct pcr_skeyid_q *skq
+        i += hasher->hash_digest_len;
+ 
+         PK11SymKey *tkey32 = pk11_derive_wrapper_osw(skeyid_e, CKM_CONCATENATE_BASE_AND_DATA
+-                                                , hmac_pad,CKM_XOR_BASE_AND_DATA, CKA_DERIVE, HMAC_BUFSIZE);
++                                                , hmac_pad,CKM_XOR_BASE_AND_DATA, CKA_DERIVE, hasher->hash_block_size);
+         PR_ASSERT(tkey32!=NULL);
+ 
+         PK11SymKey *tkey33 = pk11_derive_wrapper_osw(tkey32, CKM_XOR_BASE_AND_DATA
+@@ -1242,9 +1242,9 @@ calc_skeyseed_v2(struct pcr_skeyid_q *skq
+     passert(encrypter);
+ 
+ 
+-    hmac_opad = hmac_pads(HMAC_OPAD,HMAC_BUFSIZE);
+-    hmac_ipad = hmac_pads(HMAC_IPAD,HMAC_BUFSIZE);
+-    hmac_pad_prf  = hmac_pads(0x00,HMAC_BUFSIZE-hasher->hash_digest_len);
++    hmac_opad = hmac_pads(HMAC_OPAD,hasher->hash_block_size);
++    hmac_ipad = hmac_pads(HMAC_IPAD,hasher->hash_block_size);
++    hmac_pad_prf  = hmac_pads(0x00,hasher->hash_block_size-hasher->hash_digest_len);
+ 
+ 
+     /* generate SKEYSEED from key=(Ni|Nr), hash of shared */
+@@ -1328,7 +1328,7 @@ calc_skeyseed_v2(struct pcr_skeyid_q *skq
+ 
+ 	PK11SymKey *finalkey;
+ 	PK11SymKey *tkey1 = pk11_derive_wrapper_osw(skeyseed_k, CKM_CONCATENATE_BASE_AND_DATA
+-		, hmac_pad_prf,CKM_XOR_BASE_AND_DATA, CKA_DERIVE, HMAC_BUFSIZE);
++		, hmac_pad_prf,CKM_XOR_BASE_AND_DATA, CKA_DERIVE, hasher->hash_block_size);
+ 	PR_ASSERT(tkey1!=NULL);
+ 
+ 
+diff --git a/programs/pluto/crypto.c b/programs/pluto/crypto.c
+index d9bde44..1e568c9 100644
+--- a/programs/pluto/crypto.c
++++ b/programs/pluto/crypto.c
+@@ -127,6 +127,7 @@ static struct hash_desc crypto_hasher_md5 =
+     hash_key_size:   MD5_DIGEST_SIZE,
+     hash_digest_len: MD5_DIGEST_SIZE,
+     hash_integ_len: 0,				/*Not applicable*/
++    hash_block_size: HMAC_BUFSIZE,
+     hash_init: (void (*)(void *)) osMD5Init,
+     hash_update: (void (*)(void *, const u_int8_t *, size_t)) osMD5Update,
+     hash_final: (void (*)(u_char *, void *)) osMD5Final,
+@@ -143,7 +144,8 @@ static struct hash_desc crypto_integ_md5 =
+     hash_ctx_size: sizeof(MD5_CTX),
+     hash_key_size:   MD5_DIGEST_SIZE,
+     hash_digest_len: MD5_DIGEST_SIZE,
+-    hash_integ_len: MD5_DIGEST_SIZE_96,	
++    hash_integ_len: MD5_DIGEST_SIZE_96,
++    hash_block_size: HMAC_BUFSIZE,
+     hash_init: (void (*)(void *)) osMD5Init,
+     hash_update: (void (*)(void *, const u_int8_t *, size_t)) osMD5Update,
+     hash_final: (void (*)(u_char *, void *)) osMD5Final,
+@@ -161,6 +163,7 @@ static struct hash_desc crypto_hasher_sha1 =
+     hash_key_size:   SHA1_DIGEST_SIZE,
+     hash_digest_len: SHA1_DIGEST_SIZE,
+     hash_integ_len: 0,                          /*Not applicable*/
++    hash_block_size: HMAC_BUFSIZE,
+     hash_init: (void (*)(void *)) SHA1Init,
+     hash_update: (void (*)(void *, const u_int8_t *, size_t)) SHA1Update,
+     hash_final: (void (*)(u_char *, void *)) SHA1Final,
+@@ -178,6 +181,7 @@ static struct hash_desc crypto_integ_sha1 =
+     hash_key_size:   SHA1_DIGEST_SIZE,
+     hash_digest_len: SHA1_DIGEST_SIZE,
+     hash_integ_len: SHA1_DIGEST_SIZE_96,
++    hash_block_size: HMAC_BUFSIZE,
+     hash_init: (void (*)(void *)) SHA1Init,
+     hash_update: (void (*)(void *, const u_int8_t *, size_t)) SHA1Update,
+     hash_final: (void (*)(u_char *, void *)) SHA1Final,
+diff --git a/programs/pluto/hmac.c b/programs/pluto/hmac.c
+index 1f129f7..2c009a4 100644
+--- a/programs/pluto/hmac.c
++++ b/programs/pluto/hmac.c
+@@ -71,11 +71,11 @@ hmac_init(struct hmac_ctx *ctx,
+     memcpy(&symkey, key, key_len);
+     klen =  PK11_GetKeyLength(symkey);
+ 
+-    hmac_opad = hmac_pads(HMAC_OPAD,HMAC_BUFSIZE);
+-    hmac_ipad = hmac_pads(HMAC_IPAD,HMAC_BUFSIZE);
+-    hmac_pad  = hmac_pads(0x00,HMAC_BUFSIZE-klen);
++    hmac_opad = hmac_pads(HMAC_OPAD, h->hash_block_size);
++    hmac_ipad = hmac_pads(HMAC_IPAD,h->hash_block_size);
++    hmac_pad  = hmac_pads(0x00,h->hash_block_size-klen);
+ 
+-    if(klen > HMAC_BUFSIZE) 
++    if(klen > h->hash_block_size) 
+     {
+ 	tkey1 = PK11_Derive_osw(symkey, nss_key_derivation_mech(h)
+ 				, NULL, CKM_CONCATENATE_BASE_AND_DATA, CKA_DERIVE, 0);
+@@ -86,7 +86,7 @@ hmac_init(struct hmac_ctx *ctx,
+     }
+ 
+     PK11SymKey *tkey2 = pk11_derive_wrapper_osw(tkey1, CKM_CONCATENATE_BASE_AND_DATA
+-				, hmac_pad,CKM_XOR_BASE_AND_DATA, CKA_DERIVE, HMAC_BUFSIZE);
++				, hmac_pad,CKM_XOR_BASE_AND_DATA, CKA_DERIVE, h->hash_block_size);
+ 
+     PR_ASSERT(tkey2!=NULL);
+     ctx->ikey = pk11_derive_wrapper_osw(tkey2, CKM_XOR_BASE_AND_DATA
+@@ -266,7 +266,7 @@ PK11SymKey * PK11_Derive_osw(PK11SymKey *base, CK_MECHANISM_TYPE mechanism
+ {
+ 	SECOidTag oid;
+ 	PK11Context *ctx;
+-	unsigned char dkey[HMAC_BUFSIZE];
++	unsigned char dkey[HMAC_BUFSIZE*2];
+ 	SECItem dkey_param;
+ 	SECStatus status;
+ 	unsigned int len=0;
+diff --git a/programs/pluto/ike_alg.h b/programs/pluto/ike_alg.h
+index 08b125e..8f56014 100644
+--- a/programs/pluto/ike_alg.h
++++ b/programs/pluto/ike_alg.h
+@@ -38,6 +38,7 @@ struct hash_desc {
+     size_t hash_ctx_size;
+     size_t hash_digest_len;
+     size_t hash_integ_len;        /*truncated output len when used as an integrity algorithm in IKEV2*/
++    size_t hash_block_size;
+     void (*hash_init)(void *ctx);
+     hash_update_t hash_update;
+     void (*hash_final)(u_int8_t *out, void *ctx);
+diff --git a/programs/pluto/ike_alg_sha2.c b/programs/pluto/ike_alg_sha2.c
+index cbcfdc4..09122ef 100644
+--- a/programs/pluto/ike_alg_sha2.c
++++ b/programs/pluto/ike_alg_sha2.c
+@@ -31,6 +31,23 @@ static void sha256_hash_final(u_char *hash, sha256_context *ctx)
+ 	memcpy(hash, &ctx->sha_out[0], SHA2_256_DIGEST_SIZE);
+ #endif
+ }
++
++static void sha384_hash_final(u_char *hash, sha512_context *ctx)
++{
++#ifdef HAVE_LIBNSS
++	unsigned int len;
++	SECStatus s;
++	s = PK11_DigestFinal(ctx->ctx_nss, hash, &len, SHA2_384_DIGEST_SIZE);
++	PR_ASSERT(len==SHA2_384_DIGEST_SIZE);
++	PR_ASSERT(s==SECSuccess);
++	PK11_DestroyContext(ctx->ctx_nss, PR_TRUE);
++	DBG(DBG_CRYPT, DBG_log("NSS SHA 384 hash final : end"));
++#else
++	sha384_final(ctx);
++	memcpy(hash, &ctx->sha_out[0], SHA2_384_DIGEST_SIZE);
++#endif
++}
++
+ static void sha512_hash_final(u_char *hash, sha512_context *ctx)
+ {
+ #ifdef HAVE_LIBNSS
+@@ -46,6 +63,7 @@ static void sha512_hash_final(u_char *hash, sha512_context *ctx)
+ 	memcpy(hash, &ctx->sha_out[0], SHA2_512_DIGEST_SIZE);
+ #endif
+ }
++
+ struct hash_desc hash_desc_sha2_256 = {
+ 	common:{officname:  "sha256",
+ 		algo_type: IKE_ALG_HASH,
+@@ -56,6 +74,7 @@ struct hash_desc hash_desc_sha2_256 = {
+ 	hash_key_size: SHA2_256_DIGEST_SIZE,
+ 	hash_digest_len: SHA2_256_DIGEST_SIZE,
+ 	hash_integ_len: 0,	/*Not applicable*/
++	hash_block_size: HMAC_BUFSIZE,
+ 	hash_init: (void (*)(void *))sha256_init,
+ 	hash_update: (void (*)(void *, const u_char *, size_t ))sha256_write,
+ 	hash_final:(void (*)(u_char *, void *))sha256_hash_final,
+@@ -71,35 +90,93 @@ struct hash_desc integ_desc_sha2_256 = {
+         hash_key_size: SHA2_256_DIGEST_SIZE,
+         hash_digest_len: SHA2_256_DIGEST_SIZE,
+         hash_integ_len: SHA2_256_DIGEST_SIZE/2,
++	hash_block_size: HMAC_BUFSIZE,
+         hash_init: (void (*)(void *))sha256_init,
+         hash_update: (void (*)(void *, const u_char *, size_t ))sha256_write,
+         hash_final:(void (*)(u_char *, void *))sha256_hash_final,
+ };
+ 
++struct hash_desc hash_desc_sha2_384 = {
++	common:{officname:  "sha384",
++		algo_type: IKE_ALG_HASH,
++		algo_id:   OAKLEY_SHA2_384,
++		algo_v2id: IKEv2_PRF_HMAC_SHA2_384,
++		algo_next: NULL, },
++	hash_ctx_size: sizeof(sha512_context),
++	hash_key_size: SHA2_384_DIGEST_SIZE,
++	hash_digest_len: SHA2_384_DIGEST_SIZE,
++	hash_integ_len: 0,	/*Not applicable*/
++	hash_block_size: HMAC_BUFSIZE*2,
++	hash_init: (void (*)(void *))sha384_init,
++	hash_update: (void (*)(void *, const u_char *, size_t ))sha512_write,
++	hash_final:(void (*)(u_char *, void *))sha384_hash_final,
++};
++
++struct hash_desc integ_desc_sha2_384 = {
++        common:{officname:  "sha384",
++                algo_type: IKE_ALG_INTEG,
++                algo_id:   OAKLEY_SHA2_384,
++                algo_v2id: IKEv2_AUTH_HMAC_SHA2_384_192,
++                algo_next: NULL, },
++        hash_ctx_size: sizeof(sha512_context),
++        hash_key_size: SHA2_384_DIGEST_SIZE,
++        hash_digest_len: SHA2_384_DIGEST_SIZE,
++        hash_integ_len: SHA2_384_DIGEST_SIZE/2,
++	hash_block_size: HMAC_BUFSIZE*2,
++        hash_init: (void (*)(void *))sha384_init,
++        hash_update: (void (*)(void *, const u_char *, size_t ))sha512_write,
++        hash_final:(void (*)(u_char *, void *))sha384_hash_final,
++};
++
+ struct hash_desc hash_desc_sha2_512 = {
+ 	common:{officname: "sha512",
+ 		algo_type: IKE_ALG_HASH,
+ 		algo_id:   OAKLEY_SHA2_512,
++		algo_v2id: IKEv2_PRF_HMAC_SHA2_512,
+ 		algo_next: NULL, },
+ 	hash_ctx_size: sizeof(sha512_context),
+-	hash_key_size: 0,
++	hash_key_size: SHA2_512_DIGEST_SIZE,
+ 	hash_digest_len: SHA2_512_DIGEST_SIZE,
+ 	hash_integ_len: 0,      /*Not applicable*/
++	hash_block_size: HMAC_BUFSIZE*2,
+ 	hash_init: (void (*)(void *))sha512_init,
+ 	hash_update: (void (*)(void *, const u_char *, size_t ))sha512_write,
+ 	hash_final:(void (*)(u_char *, void *))sha512_hash_final,
+ };
++
++struct hash_desc integ_desc_sha2_512 = {
++        common:{officname:  "sha512",
++                algo_type: IKE_ALG_INTEG,
++                algo_id:   OAKLEY_SHA2_512,
++                algo_v2id: IKEv2_AUTH_HMAC_SHA2_512_256,
++                algo_next: NULL, },
++        hash_ctx_size: sizeof(sha512_context),
++        hash_key_size: SHA2_512_DIGEST_SIZE,
++        hash_digest_len: SHA2_512_DIGEST_SIZE,
++        hash_integ_len: SHA2_512_DIGEST_SIZE/2,
++	hash_block_size: HMAC_BUFSIZE*2,
++        hash_init: (void (*)(void *))sha512_init,
++        hash_update: (void (*)(void *, const u_char *, size_t ))sha512_write,
++        hash_final:(void (*)(u_char *, void *))sha512_hash_final,
++};
++
+ int ike_alg_sha2_init(void);
+ int
+ ike_alg_sha2_init(void)
+ {
+ 	int ret;
+ 	ret = ike_alg_register_hash(&hash_desc_sha2_512);
+-	if (!ret){
+-	    ret = ike_alg_register_hash(&hash_desc_sha2_256);
+-	    ike_alg_add((struct ike_alg *) &integ_desc_sha2_256);
+-	}
++	if (ret)
++		goto out;
++	ret = ike_alg_register_hash(&hash_desc_sha2_384);
++	if (ret)
++		goto out;
++	ret = ike_alg_register_hash(&hash_desc_sha2_256);
+ 
++	ike_alg_add((struct ike_alg *) &integ_desc_sha2_256);
++	ike_alg_add((struct ike_alg *) &integ_desc_sha2_384);
++	ike_alg_add((struct ike_alg *) &integ_desc_sha2_512);
++out:
+ 	return ret;
+ }
+ /*
+diff --git a/programs/pluto/ikev2_crypto.c b/programs/pluto/ikev2_crypto.c
+index c924910..db3d6c9 100644
+--- a/programs/pluto/ikev2_crypto.c
++++ b/programs/pluto/ikev2_crypto.c
+@@ -65,10 +65,8 @@ void ikev2_derive_child_keys(struct state *st, enum phase1_role role)
+ 
+ 	passert(ipi->attrs.transattrs.ei != NULL);
+ 	memset(&childsacalc, 0, sizeof(childsacalc));
+-	childsacalc.prf_hasher = (struct hash_desc *)
+-		ike_alg_ikev2_find(IKE_ALG_HASH
+-				   , IKEv2_PRF_HMAC_SHA1, 0);
+-	
++	childsacalc.prf_hasher = st->st_oakley.prf_hasher;
++
+ 	setchunk(childsacalc.ni, st->st_ni.ptr, st->st_ni.len);
+ 	setchunk(childsacalc.nr, st->st_nr.ptr, st->st_nr.len);
+ 	childsacalc.spii.len=0;
+diff --git a/programs/pluto/kernel.c b/programs/pluto/kernel.c
+index fb1ad51..9924078 100644
+--- a/programs/pluto/kernel.c
++++ b/programs/pluto/kernel.c
+@@ -1747,14 +1747,31 @@ setup_half_ipsec_sa(struct state *st, bool inbound)
+         said_next->replay_window = kernel_ops->replay_window;
+         said_next->authalg = ei->authalg;
+ 
+-		if( (said_next->authalg == AUTH_ALGORITHM_HMAC_SHA2_256) && (st->st_connection->sha2_truncbug)) {
+-			if(kernel_ops->sha2_truncbug_support){
++		if( (said_next->authalg == AUTH_ALGORITHM_HMAC_SHA2_256 
++			|| said_next->authalg == AUTH_ALGORITHM_HMAC_SHA2_384
++			|| said_next->authalg == AUTH_ALGORITHM_HMAC_SHA2_512 ) && (st->st_connection->sha2_truncbug)) {
++			if(kernel_ops->sha2_truncbug_support) {
+ 			   DBG_log(" authalg converted for sha2 truncation at 96bits instead of IETF's mandated 128bits");
+ 			   /* We need to tell the kernel to mangle the sha2_256, as instructed by the user */
+-			   said_next->authalg = AUTH_ALGORITHM_HMAC_SHA2_256_TRUNCBUG;
++				switch(said_next->authalg)
++				{
++				case AUTH_ALGORITHM_HMAC_SHA2_256:
++					said_next->authalg = AUTH_ALGORITHM_HMAC_SHA2_256_TRUNCBUG;
++					break;
++				case AUTH_ALGORITHM_HMAC_SHA2_384:
++					said_next->authalg = AUTH_ALGORITHM_HMAC_SHA2_384_TRUNCBUG;
++					break;
++				case AUTH_ALGORITHM_HMAC_SHA2_512:
++					said_next->authalg = AUTH_ALGORITHM_HMAC_SHA2_512_TRUNCBUG;
++					break;
++				default:
++					DBG_log("auth truncation: control should not reach here");
++					break;
++				}
++
+ 			} else {
+-                   loglog(RC_LOG_SERIOUS, "Error: %s stack does not support sha2_truncbug=yes", kernel_ops->kern_name);
+-		   	goto fail;
++			   loglog(RC_LOG_SERIOUS, "Error: %s stack does not support sha2_truncbug=yes", kernel_ops->kern_name);
++		   	   goto fail;
+ 			}
+ 		}
+         said_next->authkeylen = ei->authkeylen;
+diff --git a/programs/pluto/kernel_netlink.c b/programs/pluto/kernel_netlink.c
+index d917ea2..830446e 100644
+--- a/programs/pluto/kernel_netlink.c
++++ b/programs/pluto/kernel_netlink.c
+@@ -145,9 +145,10 @@ static sparse_names aalg_list = {
+ 	{ SADB_AALG_SHA1HMAC, "sha1" },
+ 	{ SADB_X_AALG_SHA2_256HMAC, "sha256" },
+ 	{ SADB_X_AALG_SHA2_256HMAC_TRUNCBUG, "hmac(sha256)" },
+-	{ SADB_X_AALG_SHA2_256HMAC, "hmac(sha256)" },
+-	{ SADB_X_AALG_SHA2_384HMAC, "hmac(sha384)" },
+-	{ SADB_X_AALG_SHA2_512HMAC, "hmac(sha512)" },
++	{ SADB_X_AALG_SHA2_384HMAC, "sha384" },
++	{ SADB_X_AALG_SHA2_384HMAC_TRUNCBUG, "hmac(sha384)" },
++	{ SADB_X_AALG_SHA2_512HMAC, "sha512" },
++	{ SADB_X_AALG_SHA2_512HMAC_TRUNCBUG, "hmac(sha512)" },
+ 	{ SADB_X_AALG_RIPEMD160HMAC, "ripemd160" },
+ 	{ 0, sparse_end }
+ };
+@@ -847,14 +848,34 @@ netlink_add_sa(struct kernel_sa *sa, bool replace)
+ 	 * an earlier draft. The kernel then introduced a new struct xfrm_algo_auth to
+ 	 * replace struct xfrm_algo to deal with this 
+ 	 */
+-	if(sa->authalg == AUTH_ALGORITHM_HMAC_SHA2_256_TRUNCBUG) {
++	if(sa->authalg == AUTH_ALGORITHM_HMAC_SHA2_256_TRUNCBUG
++		|| sa->authalg == AUTH_ALGORITHM_HMAC_SHA2_384_TRUNCBUG 
++		|| sa->authalg == AUTH_ALGORITHM_HMAC_SHA2_512_TRUNCBUG ) {
+ 	struct xfrm_algo_auth algo;
+-	DBG(DBG_NETKEY, DBG_log("  using new struct xfrm_algo_auth for XFRM message with explicit truncation for sha2_256"));
++	DBG(DBG_NETKEY, DBG_log("  using new struct xfrm_algo_auth for XFRM message with explicit truncation for sha2_256/384/512"));
+ 	algo.alg_key_len = sa->authkeylen * BITS_PER_BYTE;
+-	algo.alg_trunc_len = 128;
+ 	attr->rta_type = XFRMA_ALG_AUTH_TRUNC;
+ 	attr->rta_len = RTA_LENGTH(sizeof(algo) + sa->authkeylen);
+-	sa->authalg = AUTH_ALGORITHM_HMAC_SHA2_256; /* fixup to the real number, not our private number */
++
++		switch(sa->authalg)
++		{
++		case AUTH_ALGORITHM_HMAC_SHA2_256_TRUNCBUG:
++			algo.alg_trunc_len = 128;
++			sa->authalg = AUTH_ALGORITHM_HMAC_SHA2_256;
++			break;
++		case AUTH_ALGORITHM_HMAC_SHA2_384_TRUNCBUG:
++			algo.alg_trunc_len = 192;
++			sa->authalg = AUTH_ALGORITHM_HMAC_SHA2_384;
++			break;
++		case AUTH_ALGORITHM_HMAC_SHA2_512_TRUNCBUG:
++			algo.alg_trunc_len = 256;
++			sa->authalg = AUTH_ALGORITHM_HMAC_SHA2_512;
++			break;
++		default:
++			DBG_log("kernel_netlink: auth truncation control should not reach here");
++			break;
++		}
++
+ 
+ 	strcpy(algo.alg_name, name);
+ 	memcpy(RTA_DATA(attr), &algo, sizeof(algo));
+diff --git a/programs/pluto/spdb_v2_struct.c b/programs/pluto/spdb_v2_struct.c
+index a744100..a723130 100644
+--- a/programs/pluto/spdb_v2_struct.c
++++ b/programs/pluto/spdb_v2_struct.c
+@@ -283,6 +283,10 @@ enum ikev2_trans_type_integ v1tov2_integ(int oakley)
+         return IKEv2_AUTH_HMAC_SHA1_96;
+     case OAKLEY_SHA2_256:
+         return IKEv2_AUTH_HMAC_SHA2_256_128;
++    case OAKLEY_SHA2_384:
++        return IKEv2_AUTH_HMAC_SHA2_384_192;
++    case OAKLEY_SHA2_512:
++        return IKEv2_AUTH_HMAC_SHA2_512_256;   
+     default:
+         return IKEv2_AUTH_INVALID;
+    }
+@@ -297,6 +301,10 @@ enum ikev2_trans_type_integ v1phase2tov2child_integ(int ikev1_phase2_auth)
+         return IKEv2_AUTH_HMAC_SHA1_96;
+     case AUTH_ALGORITHM_HMAC_SHA2_256:
+         return IKEv2_AUTH_HMAC_SHA2_256_128;
++    case AUTH_ALGORITHM_HMAC_SHA2_384:
++        return IKEv2_AUTH_HMAC_SHA2_384_192;
++    case AUTH_ALGORITHM_HMAC_SHA2_512:
++        return IKEv2_AUTH_HMAC_SHA2_512_256;
+     default:
+         return IKEv2_AUTH_INVALID;
+    }
+@@ -312,6 +320,10 @@ static enum ikev2_trans_type_prf v1tov2_prf(int oakley)
+         return IKEv2_PRF_HMAC_SHA1;
+     case OAKLEY_SHA2_256:
+         return IKEv2_PRF_HMAC_SHA2_256;
++    case OAKLEY_SHA2_384:
++        return IKEv2_PRF_HMAC_SHA2_384;
++    case OAKLEY_SHA2_512:
++        return IKEv2_PRF_HMAC_SHA2_512;
+     default:
+         return IKEv2_PRF_INVALID;
+     }
diff --git a/openswan-ikev2.patch b/openswan-ikev2.patch
new file mode 100644
index 0000000..e060357
--- /dev/null
+++ b/openswan-ikev2.patch
@@ -0,0 +1,3116 @@
+From 3c685356d477d78a630f9f071fd0ceed6f53729a Mon Sep 17 00:00:00 2001
+From: Avesh Agarwal <avagarwa at redhat.com>
+Date: Tue, 7 Aug 2012 11:56:57 -0400
+Subject: IKEv2 RFC4306/5996 related changes
+
+
+diff --git a/include/pluto_constants.h b/include/pluto_constants.h
+index ffdee8f..b55c0a5 100644
+--- a/include/pluto_constants.h
++++ b/include/pluto_constants.h
+@@ -311,6 +311,13 @@ enum phase1_role {
+   RESPONDER=2
+ };
+ 
++enum ikev2_msgtype {
++  req_sent=1,
++  req_recd=2,
++  response_sent=3,
++  response_recd=4
++};
++
+ 
+ #define STATE_IKE_FLOOR	STATE_MAIN_R0
+ 
+@@ -358,12 +365,12 @@ enum phase1_role {
+ #define IS_MODE_CFG_ESTABLISHED(s) ((s) == STATE_MODE_CFG_R2)
+ #endif
+ 
+-#define IS_PARENT_SA_ESTABLISHED(s) ((s) == STATE_PARENT_I2 || (s) == STATE_PARENT_R1 || (s) == STATE_IKESA_DEL)
++#define IS_PARENT_SA_ESTABLISHED(s) ((s) == STATE_PARENT_I3 || (s) == STATE_PARENT_R2)
+ /* 
+  * Issue here is that our child sa appears as a STATE_PARENT_I3/STATE_PARENT_R2 state which it should not 
+  * So we fall back to checking if it is cloned, and therefor really a child
+  */
+-#define IS_CHILD_SA_ESTABLISHED(st) ( (((st->st_state == STATE_PARENT_I3) || (st->st_state == STATE_PARENT_R2)) && (st->st_clonedfrom != SOS_NOBODY)) || (st->st_state == STATE_CHILDSA_DEL) )
++#define IS_CHILD_SA_ESTABLISHED(st) (((st->st_state) == STATE_PARENT_I3 || (st->st_state) == STATE_PARENT_R2 || (st->st_state) == STATE_CHILDSA_DEL) && (st->st_childsa != NULL))
+ 
+ #define IS_CHILD_SA(st)  ((st)->st_clonedfrom != SOS_NOBODY)
+ #define IS_PARENT_SA(st) (!IS_CHILD_SA(st))
+diff --git a/lib/libopenswan/constants.c b/lib/libopenswan/constants.c
+index 9c85cf5..e970509 100644
+--- a/lib/libopenswan/constants.c
++++ b/lib/libopenswan/constants.c
+@@ -40,6 +40,21 @@ static const char *const version_name_1[] = {
+ };
+ static const char *const version_name_2[] = {
+ 	"IKEv2 version 2.0 (rfc4306/rfc5996)",
++	"IKEv2 version 2.0 (rfc4306/rfc5996)",
++	"IKEv2 version 2.0 (rfc4306/rfc5996)",
++	"IKEv2 version 2.0 (rfc4306/rfc5996)",
++	"IKEv2 version 2.0 (rfc4306/rfc5996)",
++	"IKEv2 version 2.0 (rfc4306/rfc5996)",
++	"IKEv2 version 2.0 (rfc4306/rfc5996)",
++	"IKEv2 version 2.0 (rfc4306/rfc5996)",
++	"IKEv2 version 2.0 (rfc4306/rfc5996)",
++	"IKEv2 version 2.0 (rfc4306/rfc5996)",
++	"IKEv2 version 2.0 (rfc4306/rfc5996)",
++	"IKEv2 version 2.0 (rfc4306/rfc5996)",
++	"IKEv2 version 2.0 (rfc4306/rfc5996)",
++	"IKEv2 version 2.0 (rfc4306/rfc5996)",
++	"IKEv2 version 2.0 (rfc4306/rfc5996)",
++	"IKEv2 version 2.0 (rfc4306/rfc5996)",
+ };
+ 
+ enum_names version_names_1 =
+@@ -47,9 +62,10 @@ enum_names version_names_1 =
+ 	ISAKMP_MAJOR_VERSION<<ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION,
+ 	version_name_1, NULL };
+ 
++/* To ignore or (in other words, accept) all IKEv2 minor versions*/
+ enum_names version_names =
+-    { IKEv2_MAJOR_VERSION<<ISA_MAJ_SHIFT | IKEv2_MINOR_VERSION,
+-	IKEv2_MAJOR_VERSION<<ISA_MAJ_SHIFT | IKEv2_MINOR_VERSION,
++    { IKEv2_MAJOR_VERSION<<ISA_MAJ_SHIFT | 0x0,
++	IKEv2_MAJOR_VERSION<<ISA_MAJ_SHIFT | 0xf,
+ 	version_name_2, &version_names_1 };
+ 
+ /* Domain of Interpretation */
+diff --git a/lib/libpluto/packet.c b/lib/libpluto/packet.c
+index ec4288b..bac754a 100644
+--- a/lib/libpluto/packet.c
++++ b/lib/libpluto/packet.c
+@@ -664,7 +664,7 @@ struct_desc ikev2_sa_desc = { "IKEv2 Security Association Payload",
+  */
+ static field_desc ikev2prop_fields[] = {
+     { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
+-    { ft_mbz,  8/BITS_PER_BYTE, NULL, NULL },
++    { ft_nat,  8/BITS_PER_BYTE, "reserved", NULL },
+     { ft_len, 16/BITS_PER_BYTE, "length", NULL },
+     { ft_nat,  8/BITS_PER_BYTE, "prop #", NULL },
+     { ft_nat,  8/BITS_PER_BYTE, "proto ID", NULL },
+@@ -695,10 +695,10 @@ struct_desc ikev2_prop_desc = { "IKEv2 Proposal Substructure Payload",
+  */
+ static field_desc ikev2trans_fields[] = {
+     { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
+-    { ft_mbz,  8/BITS_PER_BYTE, NULL, NULL },
++    { ft_nat,  8/BITS_PER_BYTE, "reserved", NULL },
+     { ft_len, 16/BITS_PER_BYTE, "length", NULL },
+     { ft_nat,  8/BITS_PER_BYTE, "transform type", &trans_type_names },
+-    { ft_mbz,  8/BITS_PER_BYTE, NULL, NULL },
++    { ft_nat,  8/BITS_PER_BYTE, "reserved", NULL },
+     { ft_nat, 16/BITS_PER_BYTE, "transform ID", NULL },
+     { ft_end,  0, NULL, NULL }
+ };
+@@ -757,7 +757,7 @@ static field_desc ikev2ke_fields[] = {
+     { ft_set, 8/BITS_PER_BYTE, "critical bit", critical_names},
+     { ft_len, 16/BITS_PER_BYTE, "length", NULL },
+     { ft_nat, 16/BITS_PER_BYTE, "transform type", &oakley_group_names },
+-    { ft_mbz, 16/BITS_PER_BYTE, NULL, NULL },
++    { ft_nat, 16/BITS_PER_BYTE, "reserved", NULL },
+     { ft_end,  0, NULL, NULL }
+ };
+ 
+@@ -800,8 +800,8 @@ static field_desc ikev2id_fields[] = {
+     { ft_set, 8/BITS_PER_BYTE, "critical bit", critical_names},
+     { ft_len, 16/BITS_PER_BYTE, "length", NULL },
+     { ft_enum, 8/BITS_PER_BYTE, "id_type", &ident_names },
+-    { ft_mbz,  8/BITS_PER_BYTE, NULL, NULL },
+-    { ft_mbz, 16/BITS_PER_BYTE, NULL, NULL },
++    { ft_nat,  8/BITS_PER_BYTE, "reserved", NULL },
++    { ft_nat, 16/BITS_PER_BYTE, "reserved", NULL },
+     { ft_end,  0, NULL, NULL }
+ };
+ 
+@@ -883,8 +883,8 @@ static field_desc ikev2a_fields[] = {
+     { ft_set, 8/BITS_PER_BYTE, "critical bit", critical_names},
+     { ft_len, 16/BITS_PER_BYTE, "length", NULL },
+     { ft_enum, 8/BITS_PER_BYTE, "auth method", &ikev2_auth_names },
+-    { ft_mbz,  8/BITS_PER_BYTE, NULL, NULL },
+-    { ft_mbz, 16/BITS_PER_BYTE, NULL, NULL },
++    { ft_nat,  8/BITS_PER_BYTE, "reserved", NULL },
++    { ft_nat, 16/BITS_PER_BYTE, "reserved", NULL },
+     { ft_end,  0, NULL, NULL }
+ };
+ 
+@@ -948,6 +948,10 @@ static field_desc ikev2_notify_fields[] = {
+   { ft_end,  0, NULL, NULL }
+ };
+ 
++struct_desc ikev2_notify_desc = { "IKEv2 Notify Payload",
++			     ikev2_notify_fields, sizeof(struct ikev2_notify) };
++
++
+ /* IKEv2 Delete Payload
+  * layout from RFC 5996 Section 3.11 
+  * This is followed by a variable length SPI.
+@@ -978,10 +982,6 @@ static field_desc ikev2_delete_fields[] = {
+ struct_desc ikev2_delete_desc = { "IKEv2 Delete Payload",
+                             ikev2_delete_fields, sizeof(struct ikev2_delete) };
+ 
+-
+-struct_desc ikev2_notify_desc = { "IKEv2 Notify Payload",
+-			     ikev2_notify_fields, sizeof(struct ikev2_notify) };
+-
+ /* 
+  * 3.12.  Vendor ID Payload
+  *
+@@ -1029,11 +1029,11 @@ static field_desc ikev2ts_fields[] = {
+     { ft_set, 8/BITS_PER_BYTE, "critical bit", critical_names},
+     { ft_len, 16/BITS_PER_BYTE, "length", NULL },
+     { ft_nat,  8/BITS_PER_BYTE, "number of TS", NULL},
+-    { ft_mbz,  8/BITS_PER_BYTE, NULL, NULL },
+-    { ft_mbz, 16/BITS_PER_BYTE, NULL, NULL },
++    { ft_nat,  8/BITS_PER_BYTE, "reserved", NULL },
++    { ft_nat, 16/BITS_PER_BYTE, "reserved", NULL },
+     { ft_end,  0, NULL, NULL }
+ };
+-struct_desc ikev2_ts_desc = { "IKEv2 Traffic Selector Payload",
++struct_desc ikev2_ts_desc = { "IKEv2 Traffic Selectors",
+ 			     ikev2ts_fields, sizeof(struct ikev2_ts) };
+ 
+ 
+@@ -1066,7 +1066,7 @@ static field_desc ikev2ts1_fields[] = {
+     { ft_nat, 16/BITS_PER_BYTE, "end port", NULL},
+     { ft_end,  0, NULL, NULL }
+ };
+-struct_desc ikev2_ts1_desc = { "IKEv2 Traffic Selector",
++struct_desc ikev2_ts1_desc = { "IKEv2 Traffic Selectors",
+ 			       ikev2ts1_fields, sizeof(struct ikev2_ts1) };
+ 
+ 
+diff --git a/lib/libpluto/pluto_constants.c b/lib/libpluto/pluto_constants.c
+index 0a51292..a66dfd9 100644
+--- a/lib/libpluto/pluto_constants.c
++++ b/lib/libpluto/pluto_constants.c
+@@ -139,6 +139,8 @@ static const char *const state_name[] = {
+ 	"STATE_PARENT_I3",
+ 	"STATE_PARENT_R1",
+ 	"STATE_PARENT_R2",
++	"STATE_IKESA_DEL",
++	"STATE_CHILDSA_DEL",
+ 	"STATE_IKEv2_ROOF"
+ 	
+     };
+@@ -191,6 +193,8 @@ const char *const state_story[] = {
+ 	"PARENT SA established",
+ 	"received v2I1, sent v2R1",
+ 	"received v2I2, PARENT SA established",
++	"sent IKE SA delete request",
++	"sent Child SA delete request",
+ 	"invalid state - IKEv2 roof"
+     };
+ 
+diff --git a/programs/pluto/connections.c b/programs/pluto/connections.c
+index eb2b492..6086840 100644
+--- a/programs/pluto/connections.c
++++ b/programs/pluto/connections.c
+@@ -1683,6 +1683,65 @@ instantiate(struct connection *c, const ip_address *him
+ }
+ 
+ struct connection *
++ikev2_narrow_instantiate(struct connection *c)
++{
++    struct connection *d;
++    int wildcards;
++
++    /*if(!(c->policy & POLICY_IKEV2_ALLOW) && !(c->policy & POLICY_IKEV2_PROPOSE)) {
++    passert(c->kind == CK_TEMPLATE);
++    }
++
++    passert(c->spd.next == NULL);*/
++
++    c->instance_serial++;
++    d = clone_thing(*c, "temporary connection");
++
++    /*if (his_id != NULL)
++    {
++	passert(match_id(his_id, &d->spd.that.id, &wildcards));
++	d->spd.that.id = *his_id;
++	d->spd.that.has_id_wildcards = FALSE;
++    }*/
++
++    unshare_connection_strings(d);
++    unshare_ietfAttrList(&d->spd.this.groups);
++    unshare_ietfAttrList(&d->spd.that.groups);
++
++    d->kind = CK_INSTANCE;
++
++    passert(oriented(*d));
++    /*d->spd.that.host_addr = *him;
++    setportof(htons(c->spd.that.port), &d->spd.that.host_addr);
++    default_end(&d->spd.that, &d->spd.this.host_addr);*/
++
++    /* We cannot guess what our next_hop should be, but if it was
++     * explicitly specified as 0.0.0.0, we set it to be him.
++     * (whack will not allow nexthop to be elided in RW case.)
++     */
++    /*default_end(&d->spd.this, &d->spd.that.host_addr);*/
++    d->spd.next = NULL;
++    d->spd.reqid = gen_reqid();
++
++    /* set internal fields */
++    d->ac_next = connections;
++    connections = d;
++    d->spd.routing = RT_UNROUTED;
++    d->newest_isakmp_sa = SOS_NOBODY;
++    d->newest_ipsec_sa = SOS_NOBODY;
++    d->spd.eroute_owner = SOS_NOBODY;
++
++    /* reset log file info */
++    d->log_file_name = NULL;
++    d->log_file = NULL;
++    d->log_file_err = FALSE;
++
++    connect_to_host_pair(d);
++
++    return d;
++}
++
++struct connection *
+ rw_instantiate(struct connection *c
+ , const ip_address *him
+ , const ip_subnet *his_net
+diff --git a/programs/pluto/connections.h b/programs/pluto/connections.h
+index 36f8517..9bbd145 100644
+--- a/programs/pluto/connections.h
++++ b/programs/pluto/connections.h
+@@ -374,6 +374,7 @@ find_connection_for_clients(struct spd_route **srp
+  */
+ struct gw_info;	/* forward declaration of tag (defined in dnskey.h) */
+ struct alg_info;	/* forward declaration of tag (defined in alg_info.h) */
++extern struct connection *ikev2_narrow_instantiate(struct connection *c);
+ extern struct connection *rw_instantiate(struct connection *c
+ 					 , const ip_address *him
+ 					 , const ip_subnet *his_net
+diff --git a/programs/pluto/hmac.c b/programs/pluto/hmac.c
+index 7d201db..1f129f7 100644
+--- a/programs/pluto/hmac.c
++++ b/programs/pluto/hmac.c
+@@ -158,13 +158,9 @@ hmac_update(struct hmac_ctx *ctx,
+     const u_char *data, size_t data_len)
+ {
+ #ifdef HAVE_LIBNSS
+-    DBG(DBG_CRYPT, DBG_dump("hmac_update data value: ", data, data_len));
+     if(data_len > 0) {
+-	DBG(DBG_CRYPT, DBG_log("hmac_update: inside if"));
+ 	SECStatus status = PK11_DigestOp(ctx->ctx_nss, data, data_len);
+-	DBG(DBG_CRYPT, DBG_log("hmac_update: after digest"));
+ 	PR_ASSERT(status == SECSuccess);
+-	DBG(DBG_CRYPT, DBG_log("hmac_update: after assert"));
+     }
+ #else
+     ctx->h->hash_update(&ctx->hash_ctx, data, data_len);
+diff --git a/programs/pluto/ikev2.c b/programs/pluto/ikev2.c
+index 260e3b5..fc42628 100644
+--- a/programs/pluto/ikev2.c
++++ b/programs/pluto/ikev2.c
+@@ -247,7 +247,6 @@ ikev2_process_payloads(struct msg_digest *md,
+ 	int thisp = np;
+ 	bool unknown_payload = FALSE;
+ 
+-	DBG(DBG_CONTROL, DBG_log("Now lets proceed with payload (%s)",enum_show(&payload_names, thisp)));	
+ 	memset(pd, 0, sizeof(*pd));
+ 	
+ 	if (pd == &md->digest[PAYLIMIT])
+@@ -315,7 +314,6 @@ ikev2_process_payloads(struct msg_digest *md,
+ 	pd++;
+     }
+     
+-    DBG(DBG_CONTROL, DBG_log("Finished and now at the end of ikev2_process_payload"));
+     md->digest_roof = pd;
+     return STF_OK;
+ }
+@@ -349,7 +347,7 @@ process_v2_packet(struct msg_digest **mdp)
+ 
+ 	md->role = RESPONDER;
+ 
+-	DBG(DBG_CONTROL, DBG_log("I am IKE SA Responder"));
++	DBG(DBG_CONTROLMORE, DBG_log("I am IKE SA Responder"));
+ 
+ 	st = find_state_ikev2_parent(md->hdr.isa_icookie
+ 				     , md->hdr.isa_rcookie);
+@@ -360,22 +358,35 @@ process_v2_packet(struct msg_digest **mdp)
+ 	}
+ 
+ 	if(st) {
+-	    if(st->st_msgid_lastrecv >  md->msgid_received){
++	    /* if it is request from Initiator*/
++	    if(!(md->hdr.isa_flags & ISAKMP_FLAGS_R)) {
++		if(st->st_msgid_last_remotereq != INVALID_MSGID && st->st_msgid_last_remotereq > md->msgid_received){
+ 		/* this is an OLD retransmit. we can't do anything */
+-		openswan_log("received too old retransmit: %u < %u"
+-			     , md->msgid_received, st->st_msgid_lastrecv);
++		openswan_log("received too old retransmit, ignoring: %u < %u"
++			     , md->msgid_received, st->st_msgid_last_remotereq);
+ 		return;
+-	    }
+-	    if(st->st_msgid_lastrecv == md->msgid_received){
++		}
++		if(st->st_msgid_last_remotereq != INVALID_MSGID && st->st_msgid_last_remotereq == md->msgid_received){
+ 		/* this is a recent retransmit. */
+ 		send_packet(st, "ikev2-responder-retransmit", FALSE);
+ 		return;
++		}
++	    }
++	    else 
++	    {
++	    /* if it is response from Initiator*/
++		/* it seems that it should not happen 
++		 * why a response will be retransmitted?
++		 */
++		if(st->st_msgid_last_localreq_ack!=INVALID_MSGID &&  st->st_msgid_last_localreq_ack >= md->msgid_received){
++		openswan_log("received an old response, ignoring: %u < %u"
++                             , md->msgid_received, st->st_msgid_last_localreq_ack);
++		}
+ 	    }
+ 	    /* update lastrecv later on */
+ 	}
+-	
+     } else {
+-        /* then I am the initiator, and this is a reply */
++        /* then I am the initiator, and this may be a reply or request */
+ 	
+ 	md->role = INITIATOR;
+ 
+@@ -412,26 +423,31 @@ process_v2_packet(struct msg_digest **mdp)
+ 	}
+ 
+ 	if(st) {
+-	    /*
+-	     * then there is something wrong with the msgid, so
+-	     * maybe they retransmitted for some reason. 
+-	     * Check if it's an old packet being returned, and
+-	     * if so, drop it.
+-	     * NOTE: in_struct() changed the byte order.
+-	     */
+-	    if(st->st_msgid_lastack != INVALID_MSGID
+-	       && md->msgid_received <= st->st_msgid_lastack) {
+-		/* it's fine, it's just a retransmit */
+-		DBG(DBG_CONTROL, DBG_log("responding peer retransmitted msgid %u"
+-					 , md->msgid_received));
++	    /* if it is request from Responder*/
++	    if(!(md->hdr.isa_flags & ISAKMP_FLAGS_R)) {
++		if(st->st_msgid_last_remotereq != INVALID_MSGID && st->st_msgid_last_remotereq > md->msgid_received){
++		/* this is an OLD retransmit. we can't do anything */
++		openswan_log("received too old retransmit, ignoring: %u < %u"
++			     , md->msgid_received, st->st_msgid_last_remotereq);
++		return;
++		}
++		if(st->st_msgid_last_remotereq != INVALID_MSGID && st->st_msgid_last_remotereq == md->msgid_received){
++		/* this is a recent retransmit. */
++		send_packet(st, "ikev2-responder-retransmit", FALSE);
+ 		return;
++		}
++	    }
++	    else 
++	    {
++	    /* if it is response from Responder*/
++		/* it seems that it should not happen 
++		 * why a response will be retransmitted?
++		 */
++		if(st->st_msgid_last_localreq_ack!=INVALID_MSGID &&  st->st_msgid_last_localreq_ack >= md->msgid_received){
++		openswan_log("received an old response, ignoring: %u < %u"
++                             , md->msgid_received, st->st_msgid_last_localreq_ack);
++		}
+ 	    }
+-#if 0
+-	    openswan_log("last msgid ack is %u, received: %u"
+-			 , st->st_msgid_lastack
+-			 , md->msgid_received);
+-	    return;
+-#endif
+ 	}
+     }
+ 	
+@@ -439,7 +455,6 @@ process_v2_packet(struct msg_digest **mdp)
+     if(st) {
+ 
+ 	from_state = st->st_state;
+-	DBG(DBG_CONTROL, DBG_log("state found and its state is (%s)", enum_show(&state_names, from_state)));
+     }
+ 
+     for(svm = state_microcode_table; svm->state != STATE_IKEv2_ROOF; svm++) {
+@@ -451,20 +466,12 @@ process_v2_packet(struct msg_digest **mdp)
+ 	}
+ 	if(svm->state != from_state) continue;
+ 	if(svm->recv_type != ix) continue;
+-
+-	/* I1 receiving NO_PROPOSAL ened up picking the wrong STATE_UNDEFINED state
+- 	   Since the wrong state is a responder, we just add a check for initiator,
+-	   so we hit STATE_IKEv2_ROOF
+-	 */
+-	//if ( ((svm->flags&SMF2_INITIATOR) != 0) != ((md->hdr.isa_flags & ISAKMP_FLAGS_R) != 0) )
+-        //        continue;
+ 	
+ 	/* must be the right state */
+ 	break;
+     }
+ 
+     if(svm->state == STATE_IKEv2_ROOF) {
+-	DBG(DBG_CONTROL, DBG_log("ended up with STATE_IKEv2_ROOF"));
+ 
+ 	/* no useful state */
+ 	if(md->hdr.isa_flags & ISAKMP_FLAGS_I) {
+@@ -480,7 +487,6 @@ process_v2_packet(struct msg_digest **mdp)
+ 	stf_status stf;
+ 	stf = ikev2_process_payloads(md, &md->message_pbs
+ 				     , from_state, md->hdr.isa_np);
+-	DBG(DBG_CONTROL, DBG_log("Finished processing ikev2_process_payloads"));
+ 	
+ 	if(stf != STF_OK) {
+ 	    complete_v2_state_transition(mdp, stf);
+@@ -488,7 +494,6 @@ process_v2_packet(struct msg_digest **mdp)
+ 	}
+     }
+ 
+-    DBG(DBG_CONTROL, DBG_log("Now lets proceed with state specific processing"));
+     DBG(DBG_PARSING,
+ 	if (pbs_left(&md->message_pbs) != 0)
+ 	    DBG_log("removing %d bytes of padding", (int) pbs_left(&md->message_pbs)));
+@@ -667,7 +672,7 @@ send_v2_notification_from_md(struct msg_digest *md UNUSED, u_int16_t type
+ 			 md->hdr.isa_icookie, md->hdr.isa_rcookie, data);
+ }
+ 
+-void ikev2_update_counters(struct msg_digest *md)
++void ikev2_update_counters(struct msg_digest *md, enum ikev2_msgtype msgtype)
+ {
+     struct state *pst= md->pst;
+     struct state *st = md->st;
+@@ -679,17 +684,21 @@ void ikev2_update_counters(struct msg_digest *md)
+ 	if(pst == NULL) pst = st;
+     }
+     
+-    switch(md->role) {
+-    case INITIATOR:
+-	/* update lastuse values */
+-	pst->st_msgid_lastack = md->msgid_received;
+-	pst->st_msgid_nextuse = pst->st_msgid_lastack+1;
+-	break;
+-	
+-    case RESPONDER:
+-	pst->st_msgid_lastrecv= md->msgid_received;
+-	break;
+-    }
++
++	switch(msgtype) {
++	case req_sent:
++		pst->st_msgid_last_localreq = pst->st_msgid_last_localreq == INVALID_MSGID? 0 : pst->st_msgid_last_localreq + 1;
++		break;
++	case req_recd:
++		break;
++	case response_sent:
++		pst->st_msgid_last_remotereq = md->msgid_received;
++		break;
++	case response_recd:
++		pst->st_msgid_last_localreq_ack = md->msgid_received;
++		break;
++	default: break;
++	}
+ }
+ 
+ static void success_v2_state_transition(struct msg_digest **mdp)
+@@ -707,8 +716,6 @@ static void success_v2_state_transition(struct msg_digest **mdp)
+     change_state(st, svm->next_state);
+     w = RC_NEW_STATE + st->st_state;    
+ 
+-    ikev2_update_counters(md);
+-
+ 
+     /* tell whack and log of progress */
+     {
+@@ -740,8 +747,8 @@ static void success_v2_state_transition(struct msg_digest **mdp)
+ 	} else if(IS_PARENT_SA_ESTABLISHED(st->st_state)) {
+ 	    fmt_isakmp_sa_established(st, sadetails,sizeof(sadetails));
+ 	}
+-
+-	if (IS_CHILD_SA_ESTABLISHED(st))
++	
++	if (IS_CHILD_SA_ESTABLISHED(st) || IS_PARENT_SA_ESTABLISHED(st->st_state))
+ 	{
+ 	    /* log our success */
+ 	    w = RC_SUCCESS;
+@@ -901,26 +908,37 @@ void complete_v2_state_transition(struct msg_digest **mdp
+     struct msg_digest *md = *mdp;
+     /* const struct state_v2_microcode *svm=md->svm; */
+     struct state *st;
+-    enum state_kind from_state = STATE_UNDEFINED;
++    enum state_kind from_state;
+     const char *from_state_name;
+ 
+-    cur_state = st = md->st;	/* might have changed */
++    /* advance the state */
++    DBG(DBG_CONTROL
++        , DBG_log("complete v2 state transition with %s"
++                  , enum_name(&stfstatus_name, result)));
++
++    /* this occur when IKE SA state is deleted already */
++    if(md->st == NULL) {
++	goto end;
++    }
+ 
+-    passert(st); /* apparently on STF_TOOMUCH_CRYPTO we have no state? Needs fixing */
++    cur_state = st = md->st;	/* might have changed */
+ 
+     md->result = result;
+     TCLCALLOUT("v2AdjustFailure", st, (st ? st->st_connection : NULL), md);
+     result = md->result;
+ 
+-    /* advance the state */
+-    DBG(DBG_CONTROL
+-	, DBG_log("complete v2 state transition with %s"
+-		  , enum_name(&stfstatus_name, (result > STF_FAIL) ? STF_FAIL : result)));
+ 
+     switch(result) {
+     case STF_IGNORE:
+ 	break;
+ 
++    case STF_INLINE:         /* this is second time through complete
++			      * state transition, so the MD has already
++			      * been freed.
++			      0				  */
++	*mdp = NULL;
++	break;
++
+     case STF_SUSPEND:
+ 	/* update the previous packet history */
+ 	/* IKEv2 XXX */ /* update_retransmit_history(st, md); */
+@@ -929,13 +947,6 @@ void complete_v2_state_transition(struct msg_digest **mdp
+ 	*mdp = NULL;
+ 	break;
+ 
+-    case STF_INLINE:         /* mcr: this is second time through complete
+-			      * state transition, so the MD has already
+-			      * been freed.
+-			      0				  */
+-			      *mdp = NULL;
+-			      /* fall through to STF_OK */
+-
+     case STF_OK:
+ 	/* advance the state */
+ 	success_v2_state_transition(mdp);
+@@ -994,18 +1005,21 @@ void complete_v2_state_transition(struct msg_digest **mdp
+ 		  , from_state_name
+ 		  , enum_name(&ipsec_notification_names, md->note));
+ 
++#if 0
+ 	if(md->note > 0) {
+ 		/* only send a notify is this packet was a question, not if it was an answer */
+ 		if(!(md->hdr.isa_flags & ISAKMP_FLAGS_R)) {
+ 		     SEND_NOTIFICATION(md->note);
+ 		}
+ 	}
++#endif
+ 	
+ 	DBG(DBG_CONTROL,
+ 	    DBG_log("state transition function for %s failed: %s"
+ 		    , from_state_name
+ 		    , (md->note) ? enum_name(&ipsec_notification_names, md->note) : "<no reason given>" )); 
+     }
++end:;
+ }
+ 
+ v2_notification_t
+diff --git a/programs/pluto/ikev2.h b/programs/pluto/ikev2.h
+index 8715114..c60e9b5 100644
+--- a/programs/pluto/ikev2.h
++++ b/programs/pluto/ikev2.h
+@@ -119,39 +119,44 @@ extern stf_status ikev2_verify_psk_auth(struct state *st
+ 				   , unsigned char *idhash
+ 				   , pb_stream *sig_pbs);
+ 
++extern int ikev2_parse_ts(struct payload_digest *const ts_pd
++			, struct traffic_selector *array
++			, unsigned int array_max);
++
+ extern stf_status ikev2_emit_ipsec_sa(struct msg_digest *md
+ 				      , pb_stream *outpbs
+ 				      , unsigned int np
+ 				      , struct connection *c
+ 				      , lset_t policy);
+ 
++extern struct connection *ikev2_create_narrowed_con(struct connection *c
++					, struct traffic_selector *narrowed_tsi
++					, struct traffic_selector *narrowed_tsr
++					, enum phase1_role role);
++
+ extern void ikev2_derive_child_keys(struct state *st
+ 				    , enum phase1_role role);
+ 
+-extern struct traffic_selector ikev2_end_to_ts(struct end *e);
+-extern int ikev2_evaluate_connection_fit(struct connection *d
+-				, struct spd_route *sr
+-				, enum phase1_role role
+-				, struct traffic_selector *tsi
+-				, struct traffic_selector *tsr
+-				, unsigned int tsi_n
+-				, unsigned int tsr_n);
+-
+-extern int ikev2_evaluate_connection_port_fit(struct connection *d
+-				, struct spd_route *sr
+-				, enum phase1_role role
+-				, struct traffic_selector *tsi
+-				, struct traffic_selector *tsr
+-				, unsigned int tsi_n
+-				, unsigned int tsr_n
+-				, unsigned int *best_tsi_i
+-				, unsigned int *best_tsr_i);
++extern bool
++ikev2_perfect_match_ts(struct traffic_selector *tsi
++		,struct traffic_selector *tsr
++		, unsigned int tsi_n
++		, unsigned int tsr_n
++		, struct connection *c
++		, enum phase1_role role);
+ 
+ extern stf_status ikev2_emit_ts(struct msg_digest *md 
+ 				, pb_stream *outpbs   
+ 				, unsigned int np
+ 				, struct traffic_selector *ts
+ 				, enum phase1_role role);
++extern void 
++ikev2_store_ts_instate(struct traffic_selector *array_tsi
++		,struct traffic_selector * array_tsr
++		, unsigned int tsi_n
++		, unsigned int tsr_n
++		, struct traffic_selector *ts_this 
++		, struct traffic_selector *ts_that);
+ 
+ extern stf_status ikev2_calc_emit_ts(struct msg_digest *md
+ 				, pb_stream *outpbs
+@@ -159,18 +164,20 @@ extern stf_status ikev2_calc_emit_ts(struct msg_digest *md
+ 				, struct connection *c0
+ 				, lset_t policy);
+ 
+-extern int ikev2_parse_ts(struct payload_digest *ts_pd
+-				, struct traffic_selector *array
+-				, unsigned int array_max);
++extern bool ikev2_verify_ts(struct traffic_selector *tsi
++			, struct traffic_selector *tsr
++			, unsigned int tsi_n
++			, unsigned int tsr_n
++			, struct traffic_selector *this_ts
++			, struct traffic_selector *that_ts
++			, enum phase1_role role);
+ 
+ extern stf_status ikev2_child_sa_respond(struct msg_digest *md
+ 					 , enum phase1_role role
+ 					 , pb_stream *outpbs);
+ 
+-extern struct traffic_selector ikev2_end_to_ts(struct end *e);
+-extern void ikev2_update_counters(struct msg_digest *md);
+-extern void ikev2_print_ts(struct traffic_selector *ts);
+-
++extern struct traffic_selector ikev2_subnettots(struct end *e);
++extern void ikev2_update_counters(struct msg_digest *md, enum ikev2_msgtype msgtype);
+ 
+ extern void send_v2_notification(struct state *p1st, u_int16_t type
+ 				 , struct state *encst 
+diff --git a/programs/pluto/ikev2_child.c b/programs/pluto/ikev2_child.c
+index af194f2..764ca3a 100644
+--- a/programs/pluto/ikev2_child.c
++++ b/programs/pluto/ikev2_child.c
+@@ -64,40 +64,8 @@
+ #include "virtual.h"
+ #include "hostpair.h"
+ 
+-static void print_ikev2_ts(struct traffic_selector *ts){
+-        char lbx[ADDRTOT_BUF];
+-        char hbx[ADDRTOT_BUF];
+-
+-	DBG_log("PAUL marker ------------------------");
+-        DBG_log("ts_type: %s", enum_name(&ikev2_ts_type_names, ts->ts_type));
+-        DBG_log("ipprotoid: %d", ts->ipprotoid);
+-        DBG_log("startport: %d", ts->startport);
+-        DBG_log("endport: %d", ts->endport);
+-        addrtot(&ts->low,  0, lbx, sizeof(lbx));
+-        addrtot(&ts->high, 0, hbx, sizeof(hbx));
+-        DBG_log("ip low: %s", lbx);
+-        DBG_log("ip high: %s", hbx);
+-	DBG_log("PAUL marker ------------------------");
+-}
+-
+-void ikev2_print_ts(struct traffic_selector *ts){
+-	char lbx[ADDRTOT_BUF];
+-	char hbx[ADDRTOT_BUF];
+-
+-	DBG_log("printing contents struct traffic_selector");
+-	DBG_log("  ts_type: %s", enum_name(&ikev2_ts_type_names, ts->ts_type));
+-	DBG_log("  ipprotoid: %d", ts->ipprotoid);
+-	DBG_log("  startport: %d", ts->startport);
+-	DBG_log("  endport: %d", ts->endport);
+-	addrtot(&ts->low,  0, lbx, sizeof(lbx));
+-	addrtot(&ts->high, 0, hbx, sizeof(hbx));
+-	DBG_log("  ip low: %s", lbx);
+-	DBG_log("  ip high: %s", hbx);
+-}
+-
+-
+ /* rewrite me with addrbytesptr() */
+-struct traffic_selector ikev2_end_to_ts(struct end *e)
++struct traffic_selector ikev2_subnettots(struct end *e)
+ {
+     struct traffic_selector ts;
+     struct in6_addr v6mask;
+@@ -129,9 +97,25 @@ struct traffic_selector ikev2_end_to_ts(struct end *e)
+ 	ts.high.u.v6.sin6_addr.s6_addr32[2]|= ~v6mask.s6_addr32[2];
+ 	ts.high.u.v6.sin6_addr.s6_addr32[3]|= ~v6mask.s6_addr32[3];
+ 	break;
++    }
+ 
+     /* Setting ts_type IKEv2_TS_FC_ADDR_RANGE (RFC-4595) not yet supproted */
+-    }
++
++    /* 
++     * The IKEv2 code used to send 0-65535 as port regardless of
++     * the local policy specified. if local policy states a specific 
++     * protocol and port, then send that protocol value and port to 
++     * other end  -- Avesh
++     * Paul: TODO: I believe IKEv2 allows multiple port ranges?
++     */
++
++    DBG(DBG_CONTROLMORE,
++	{
++	DBG_log("local policy host_addr-port=%d, client-port=%d, port=%d, protocol=%d, has_port_wildcard=%d",
++		ntohs(e->host_addr.u.v4.sin_port), ntohs(e->client.addr.u.v4.sin_port)
++		, e->port, e->protocol, e->has_port_wildcard);
++	}
++    );
+ 
+     ts.ipprotoid = e->protocol;
+ 
+@@ -148,9 +132,60 @@ struct traffic_selector ikev2_end_to_ts(struct end *e)
+ 	   ts.endport = e->port;
+ 	}
+ 
++	ts.next = NULL;
++
+     return ts;
+ }
+ 
++void 
++ikev2_store_ts_instate(struct traffic_selector *array_tsi
++		,struct traffic_selector * array_tsr
++		, unsigned int tsi_n
++		, unsigned int tsr_n
++		, struct traffic_selector *ts_this
++		, struct traffic_selector *ts_that)
++{
++	unsigned int i;
++	struct traffic_selector *curts, *prevts;
++
++	prevts = NULL;
++	curts = ts_this;
++	for(i=0; i<tsi_n; i++) {
++		if(curts == NULL) {
++		curts = alloc_thing(struct traffic_selector, "struct traffic_selector");
++		}
++
++		*curts = array_tsi[i];
++		curts->next = NULL;
++
++		if(prevts!= NULL) {
++		prevts->next = curts;
++		}
++
++		prevts = curts;
++		curts = curts->next;
++	}
++
++	prevts = NULL;
++	curts = ts_that;   
++
++	for(i=0; i<tsr_n; i++) {
++		if(curts == NULL) {
++		curts = alloc_thing(struct traffic_selector, "struct traffic_selector");
++		}
++
++		*curts = array_tsr[i];
++		curts->next = NULL;
++
++		if(prevts!= NULL) {
++		prevts->next = curts;
++		}
++
++		prevts = curts;
++		curts = curts->next;
++	}
++}
++
+ stf_status ikev2_emit_ts(struct msg_digest *md   UNUSED
+ 			 , pb_stream *outpbs   
+ 			 , unsigned int np
+@@ -161,22 +196,30 @@ stf_status ikev2_emit_ts(struct msg_digest *md   UNUSED
+     struct ikev2_ts1 its1;
+     pb_stream ts_pbs;
+     pb_stream ts_pbs2;
++    struct traffic_selector *tmp=ts;
+ 
+     its.isat_np = np;
+     its.isat_critical = ISAKMP_PAYLOAD_NONCRITICAL;
+-    its.isat_num = 1;
++
++    its.isat_num = 0;
++    while(tmp!=NULL) {
++	its.isat_num++;
++	tmp = tmp->next;
++    }
+ 
+     if(!out_struct(&its, &ikev2_ts_desc, outpbs, &ts_pbs))
+ 	return STF_INTERNAL_ERROR;
+ 
++   while(ts!=NULL) {
++
+     switch(ts->ts_type) {
+     case IKEv2_TS_IPV4_ADDR_RANGE:
+ 	its1.isat1_type = IKEv2_TS_IPV4_ADDR_RANGE;
+-	its1.isat1_sellen = 2*4 + 8; /* See RFC 5669 SEction 13.3.1, 8 octet header plus 2 ip addresses */
++	its1.isat1_sellen = 16;
+ 	break;
+     case IKEv2_TS_IPV6_ADDR_RANGE:
+ 	its1.isat1_type = IKEv2_TS_IPV6_ADDR_RANGE;
+-	its1.isat1_sellen = 2*16 + 8; /* See RFC 5669 SEction 13.3.1, 8 octet header plus 2 ip addresses */
++	its1.isat1_sellen = 40;
+ 	break;
+     case IKEv2_TS_FC_ADDR_RANGE:
+ 	DBG_log("IKEv2 Traffic Selector IKEv2_TS_FC_ADDR_RANGE not yet supported");
+@@ -185,6 +228,14 @@ stf_status ikev2_emit_ts(struct msg_digest *md   UNUSED
+ 	DBG_log("IKEv2 Traffic Selector type '%d' not supported", ts->ts_type);
+     }
+ 
++    /* 
++     * The IKEv2 code used to send 0-65535 as port regardless of
++     * the local policy specified. if local policy states a specific 
++     * protocol and port, then send that protocol value and port to 
++     * other end  -- Avesh
++     * Paul: TODO: I believe IKEv2 allows multiple port ranges?
++     */
++
+     its1.isat1_ipprotoid = ts->ipprotoid;      /* protocol as per local policy*/
+     its1.isat1_startport = ts->startport;      /* ports as per local policy*/
+     its1.isat1_endport = ts->endport;  
+@@ -212,11 +263,56 @@ stf_status ikev2_emit_ts(struct msg_digest *md   UNUSED
+     }
+ 
+     close_output_pbs(&ts_pbs2);
++    ts = ts->next;	
++    }
++
+     close_output_pbs(&ts_pbs);
+     
+     return STF_OK;
+ }
+ 
++bool
++ikev2_perfect_match_ts(struct traffic_selector *tsi
++		,struct traffic_selector *tsr
++		, unsigned int tsi_n
++		, unsigned int tsr_n
++		, struct connection *c
++		, enum phase1_role role)
++{
++	struct end *ei, *er;
++	struct traffic_selector tmpi, tmpr;
++
++	if(tsi_n > 1 ||  tsi_n > 1) {
++		return FALSE;
++	}
++
++	if(role == INITIATOR) {
++		ei = &c->spd.this;
++		er = &c->spd.that;
++	} else {
++		ei = &c->spd.that;
++		er = &c->spd.this;
++	}
++
++	tmpi = ikev2_subnettots(ei);
++	tmpr = ikev2_subnettots(er);
++
++	if(addrcmp(&tmpi.low, &tsi[0].low) == 0
++		&& addrcmp(&tmpi.high, &tsi[0].high) == 0
++		&& tmpi.startport == tsi[0].startport
++		&& tmpi.endport == tsi[0].endport
++		&& tmpi.ipprotoid == tsi[0].ipprotoid
++		&& addrcmp(&tmpr.low, &tsr[0].low) == 0
++		&& addrcmp(&tmpr.high, &tsr[0].high) == 0
++		&& tmpr.startport == tsr[0].startport
++		&& tmpr.endport == tsr[0].endport
++		&& tmpr.ipprotoid == tsr[0].ipprotoid)
++	{
++		return TRUE;
++	}
++
++	return FALSE;
++}
+ 
+ stf_status ikev2_calc_emit_ts(struct msg_digest *md
+ 			      , pb_stream *outpbs
+@@ -226,10 +322,8 @@ stf_status ikev2_calc_emit_ts(struct msg_digest *md
+ {
+     struct state *st = md->st;
+     struct traffic_selector *ts_i, *ts_r;
+-    struct spd_route *sr;
+     stf_status ret;
+     
+-    st->st_childsa = c0;
+ 
+     if(role == INITIATOR) {
+ 	ts_i = &st->st_ts_this;
+@@ -239,7 +333,6 @@ stf_status ikev2_calc_emit_ts(struct msg_digest *md
+ 	ts_r = &st->st_ts_this;
+     }
+ 
+-    for(sr=&c0->spd; sr != NULL; sr = sr->next) {
+ 	ret = ikev2_emit_ts(md, outpbs, ISAKMP_NEXT_v2TSr
+ 			    , ts_i, INITIATOR);
+ 	if(ret!=STF_OK) return ret;
+@@ -266,11 +359,83 @@ stf_status ikev2_calc_emit_ts(struct msg_digest *md
+ 	}
+ 
+ 	if(ret!=STF_OK) return ret;
+-    }
+ 
+     return STF_OK;
+ }
+ 
++bool 
++ikev2_verify_ts(struct traffic_selector *tsi
++		, struct traffic_selector *tsr
++		, unsigned int ntsi
++		, unsigned int ntsr
++		, struct traffic_selector *this_ts
++		, struct traffic_selector *that_ts
++		, enum phase1_role role)
++{
++	unsigned int i;	
++	struct traffic_selector *tmptsi, *tmptsr;
++
++
++	if(role == INITIATOR) {
++		tmptsi = this_ts;
++		tmptsr = that_ts;	
++	}
++	else {
++		tmptsi = that_ts;
++		tmptsr = this_ts;
++	}
++	
++	for(i = 0; i < ntsi; i++ ) {
++
++		/* verify addresses*/ 
++		if(addrcmp(&tmptsi->low, &tsi[i].low) > 0
++			|| addrcmp(&tmptsi->high, &tsi[i].high) < 0) 
++		{
++			return FALSE;
++		}
++
++		/* verify port */ 
++		if(tmptsi->startport > tsi[i].startport 
++			|| tmptsi->endport < tsi[i].endport)
++		{
++			return FALSE;
++		}
++
++		/* verify protocol */
++		if( tmptsi->ipprotoid !=0 
++			&& tmptsi->ipprotoid != tsi[i].ipprotoid) 
++		{
++			return FALSE;
++		}
++	} 
++
++	for(i = 0; i < ntsr; i++ ) {
++
++		/* verify addresses*/ 
++		if(addrcmp(&tmptsr->low, &tsr[i].low) > 0
++			|| addrcmp(&tmptsr->high, &tsr[i].high) < 0) 
++		{
++			return FALSE;
++		}
++
++		/* verify port */
++		if(tmptsr->startport > tsr[i].startport
++			|| tmptsr->endport < tsr[i].endport)
++		{
++			return FALSE;
++		}
++
++		/* verify protocol */
++
++		if( tmptsr->ipprotoid !=0
++			&& tmptsr->ipprotoid != tsr[i].ipprotoid)
++		{
++			return FALSE;
++		}
++	}
++	return TRUE;
++}
++
+ /* return number of traffic selectors found */
+ int 
+ ikev2_parse_ts(struct payload_digest *const ts_pd
+@@ -339,271 +504,675 @@ ikev2_parse_ts(struct payload_digest *const ts_pd
+     return i;
+ }
+ 
+-int ikev2_evaluate_connection_port_fit(struct connection *d
+-				  , struct spd_route *sr
+-				  , enum phase1_role role
+-				  , struct traffic_selector *tsi
+-				  , struct traffic_selector *tsr
+-				  , unsigned int tsi_n
+-				  , unsigned int tsr_n
+-				  , unsigned int *best_tsi_i
+-				  , unsigned int *best_tsr_i)
++static bool 
++ikev2_narrowing(struct connection *c
++		  , enum phase1_role role
++		  , struct traffic_selector *tsi
++		  , struct traffic_selector *tsr
++		  , unsigned int tsi_n
++		  , unsigned int tsr_n
++		  , struct traffic_selector **narrowed_tsi
++		  , struct traffic_selector **narrowed_tsr
++		  , struct connection **result) 
+ {
+-	unsigned int tsi_ni, tsr_ni;
+-	int bestfit_p = -1;
+-	struct end *ei, *er;
+-	int narrowing = (d->policy & POLICY_IKEV2_ALLOW_NARROWING);
++struct host_pair *hp = NULL;
++struct connection *d;
++unsigned int i; 
++struct end *ei, *er;
++int  bests=0;
++struct connection *bestc=NULL;
++bool specific_first_ts = FALSE;
+ 
+-	if(role == INITIATOR) {
+-		ei = &sr->this;
+-		er = &sr->that;
+-	} else {
+-		ei = &sr->that;
+-		er = &sr->this;
+-	} 
+-	/* compare tsi/r array to this/that, evaluating port ranges how well it fits */
+-	for(tsi_ni = 0; tsi_ni < tsi_n; tsi_ni++) {
+-		for(tsr_ni=0; tsr_ni<tsr_n; tsr_ni++) {
+-			int fitrange1 = 0;
+-			int fitrange2 = 0;
+-
+-			DBG(DBG_CONTROL,DBG_log("ei->port %d  tsi[tsi_ni].startport %d  tsi[tsi_ni].endport %d narrowing=%s"
+-						,ei->port , tsi[tsi_ni].startport, tsi[tsi_ni].endport, (narrowing ? "yes" : "no")));
+-
+-			if((ei->port) && (( ei->port == tsi[tsi_ni].startport ) && (ei->port == tsi[tsi_ni].endport))) {
+-				fitrange1 = 1; 
+-				DBG(DBG_CONTROL,DBG_log("   tsi[%d] %d  ==  ei->port %d exact match single port  fitrange1 %d"
+-							,tsi_ni, tsi[tsi_ni].startport, ei->port, fitrange1));
+-
+-			}
+-			else if ((!ei->port) && ( ( tsi[tsi_ni].startport == ei->port ) && (tsi[tsi_ni].endport == 65535 ))) {
+-				// we are on range 0 - 64K  will alloow  only the same  with our without narrowing
+-				fitrange1 =  65535;
+-				DBG(DBG_CONTROL,DBG_log("   tsi[%d] %d-%d  ==  ei 0-65535 exact match all ports  fitrange1 %d"
+-							,tsi_ni, tsi[tsi_ni].startport, tsi[tsi_ni].endport, fitrange1));
++
++	hp = find_host_pair(&c->spd.this.host_addr
++				, c->spd.this.host_port
++				, &c->spd.that.host_addr
++				, c->spd.that.host_port);
++
++#ifdef DEBUG
++	if (DBGP(DBG_CONTROLMORE))
++	{
++		char s2[SUBNETTOT_BUF],d2[SUBNETTOT_BUF];
++
++		subnettot(&c->spd.this.client, 0, s2, sizeof(s2));
++		subnettot(&c->spd.that.client, 0, d2, sizeof(d2));
++
++		DBG_log("  checking hostpair %s -> %s is %s"
++			, s2, d2
++			, (hp ? "found" : "not found"));
++	}
++#endif /* DEBUG */
++
++	if(!hp) {
++		return FALSE;
++	}
++
++	/* check if there is any specific first traffic selector */
++	if( addrcmp(&tsi[0].low, &tsi[0].high)==0 && tsi[0].startport == tsi[0].endport &&  tsi[0].ipprotoid!=0 
++		&& addrcmp(&tsr[0].low, &tsr[0].high)==0 && tsr[0].startport ==  tsr[0].endport &&  tsr[0].ipprotoid!=0) {
++		specific_first_ts = TRUE;
++	}
++
++	/*if(!specific_first_ts && (tsi_n >= 2 || tsr_n >= 2) )
++	{
++		return FALSE;
++	}*/
++
++	for (d = hp->connections; d != NULL; d = d->hp_next)
++	{
++		int wildcards, pathlen;  /* XXX */
++		struct traffic_selector tmp,  tmp2;
++		int curs=0;
++		bool found_one_match_tsi = FALSE, found_one_match_tsr = FALSE;
++		
++		if (d->policy & POLICY_GROUP)
++			continue;
++		
++		if (!(same_id(&c->spd.this.id, &d->spd.this.id)
++		      && match_id(&c->spd.that.id, &d->spd.that.id, &wildcards)
++		      && trusted_ca(c->spd.that.ca, d->spd.that.ca, &pathlen)))
++		    continue;
++
++
++		if(ikev2_perfect_match_ts(tsi, tsr, tsi_n, tsr_n, d, role)) {
++			*result = d;
++			return TRUE;
++		}
++
++		if(role == INITIATOR) {
++			ei = &d->spd.this;
++			er = &d->spd.that;
++		} else {
++			ei = &d->spd.that;
++			er = &d->spd.this;
++		}
++
++		tmp = ikev2_subnettots(ei);
++
++
++		for(i=0; i<tsi_n; i++) {
++			
++			/* ip address */
++			if(addrcmp(&tmp.low, &tsi[i].low) >= 0) 
++			{
++				tmp2.low = tmp.low;
++			}
++			else
++			{
++				tmp2.low = tsi[i].low;
++			}
++
++			if(addrcmp(&tmp.high, &tsi[i].high) >= 0) 
++			{
++				tmp2.high = tsi[i].high;
++			}			
++			else
++			{
++				tmp2.high = tmp.high;
++			}
++
++			if(addrcmp(&tmp2.low, &tmp2.high) > 0) {
++				continue;
++			}
++
++			if(addrtypeof(&tmp2.low) != addrtypeof(&tmp2.high)) {
++				continue;
++			}
++
++			/* port */
++			if(tmp.startport >= tsi[i].startport ) 
++			{
++				tmp2.startport=tmp.startport;
++			}
++			else 
++			{
++				tmp2.startport=tsi[i].startport;
++			}
++
++			if(tmp.endport >= tsi[i].endport )
++			{
++				tmp2.endport=tsi[i].endport;
++			}
++			else
++			{
++				tmp2.endport=tmp.endport;
++			}
++		
++			if(tmp2.startport >  tmp2.endport) 
++			{
++				continue;
++			}
++
++			/* protocol */
++			if( !tmp.ipprotoid && !tsi[i].ipprotoid && tmp.ipprotoid!=tsi[i].ipprotoid ) 
++			{
++				continue;
++			}
++
++			curs++;
++			found_one_match_tsi = TRUE;
++		}
++
++		tmp = ikev2_subnettots(er);
++		for(i=0; i<tsr_n; i++) {
++		
++			/* ip address */
++			if(addrcmp(&tmp.low, &tsr[i].low) >= 0) 
++			{
++				tmp2.low = tmp.low;
++			}
++			else
++			{
++				tmp2.low = tsr[i].low;
++			}
++
++			if(addrcmp(&tmp.high, &tsr[i].high) >= 0) 
++			{
++				tmp2.high = tsr[i].high;
++			}			
++			else
++			{
++				tmp2.high = tmp.high;
++			}
++
++			if(addrcmp(&tmp2.low, &tmp2.high) > 0) {
++				continue;
++			}
++
++			if(addrtypeof(&tmp2.low) != addrtypeof(&tmp2.high)) {
++				continue;
++			}
++
++			/* port */
++			if(tmp.startport >= tsr[i].startport ) 
++			{
++				tmp2.startport=tmp.startport;
++			}
++			else 
++			{
++				tmp2.startport=tsr[i].startport;
++			}
++
++			if(tmp.endport >= tsr[i].endport )
++			{
++				tmp2.endport=tsr[i].endport;
++			}
++			else
++			{
++				tmp2.endport=tmp.endport;
++			}
++		
++			if(tmp2.startport >  tmp2.endport) 
++			{
++				continue;
++			}
++
++			/* protocol */
++			if( !tmp.ipprotoid && !tsr[i].ipprotoid && tmp.ipprotoid!=tsr[i].ipprotoid ) 
++			{
++				continue;
++			}
++
++			curs++;
++			found_one_match_tsr = TRUE;
++
++		}
++
++		if(curs > bests && found_one_match_tsi && found_one_match_tsr) 
++		{
++		bests = curs;
++		bestc = d;
++
++		}
++	}
++
++	if(bestc == NULL) {
++		return FALSE;
++	}
++
++	/* creating narrowed traffic selector */
++	{
++		struct traffic_selector tmp,  tmp2, *tmp3;
++
++		*result = bestc;
++
++		if(role == INITIATOR) {
++			ei = &bestc->spd.this;
++			er = &bestc->spd.that;
++		} else {
++			ei = &bestc->spd.that;
++			er = &bestc->spd.this;
++		}
++
++
++		tmp = ikev2_subnettots(ei);
++		for(i=0; i<tsi_n; i++) {
++		
++			/* ip address */
++			if(addrcmp(&tmp.low, &tsi[i].low) >= 0) 
++			{
++				tmp2.low = tmp.low;
++			}
++			else
++			{
++				tmp2.low = tsi[i].low;
++			}
++
++			if(addrcmp(&tmp.high, &tsi[i].high) >= 0) 
++			{
++				tmp2.high = tsi[i].high;
++			}			
++			else
++			{
++				tmp2.high = tmp.high;
++			}
++
++			if(addrcmp(&tmp2.low, &tmp2.high) > 0) {
++				continue;
++			}
++
++			/* port */
++			if(tmp.startport >= tsi[i].startport ) 
++			{
++				tmp2.startport=tmp.startport;
++			}
++			else 
++			{
++				tmp2.startport=tsi[i].startport;
++			}
++
++			if(tmp.endport >= tsi[i].endport )
++			{
++				tmp2.endport=tsi[i].endport;
++			}
++			else
++			{
++				tmp2.endport=tmp.endport;
++			}
++		
++			if(tmp2.startport >  tmp2.endport) 
++			{
++				continue;
++			}
++
++			/* as openswan supports only single port, so picking one port*/
++			if( tmp2.startport > 0){
++				tmp2.endport = tmp2.startport;
++			}
++			else if (tmp2.endport < 65535 ){
++				tmp2.startport = tmp2.endport;
++			}
++
++			/* protocol */
++			if( tmp.ipprotoid > 0 && tsi[i].ipprotoid > 0 && tmp.ipprotoid!=tsi[i].ipprotoid) 
++			{
++				continue;
++			}
++			else if(tmp.ipprotoid == 0)
++			{			
++				tmp2.ipprotoid = tsi[i].ipprotoid;
+ 			} 
+-			else if ( (role == INITIATOR) && narrowing && (!ei->port)) {
+-				DBG(DBG_CONTROL,DBG_log("   narrowing=yes want to narrow ei->port 0-65355 to tsi[%d] %d-%d"
+-						 ,tsi_ni, tsi[tsi_ni].startport, tsi[tsi_ni].endport));	
+-				if( tsi[tsi_ni].startport <= tsi[tsi_ni].endport ) {
+-					fitrange1 = 1 + tsi[tsi_ni].endport - tsi[tsi_ni].startport ;
+-					DBG(DBG_CONTROL,DBG_log("  tsi[%d] %d-%d >= ei->port 0-65535 can be narrowed  fitrange1 %d"
+-								,tsi_ni, tsi[tsi_ni].startport, tsi[tsi_ni].endport, fitrange1));
+-				}
+-				else
+-					DBG(DBG_CONTROL,DBG_log("   cant narrow tsi[%d] %d-%d to ei->port %d"  
+-								,tsi_ni, tsi[tsi_ni].startport, tsi[tsi_ni].endport, ei->port));
++			else 
++			{
++				tmp2.ipprotoid = tmp.ipprotoid;
++			}
+ 
++			/*setting type */
++			switch(tmp2.low.u.v4.sin_family) {
++			case AF_INET:
++				tmp2.ts_type = IKEv2_TS_IPV4_ADDR_RANGE;
++				break;
++			case AF_INET6:
++				tmp2.ts_type = IKEv2_TS_IPV6_ADDR_RANGE;
++				break;
+ 			}		
+-			else if ((role == RESPONDER) && ( narrowing  && ei->port) ) {
+-				DBG(DBG_CONTROL,DBG_log("   narrowing=yes want to narrow ei->port %d to tsi[%d] %d-%d to"
+-						 ,ei->port, tsi_ni, tsi[tsi_ni].startport, tsi[tsi_ni].endport));	
+-				if(( ei->port >= tsi[tsi_ni].startport ) && 
+-						(ei->port <= tsi[tsi_ni].endport)) {
+-					fitrange1 = 1 ;
+-					DBG(DBG_CONTROL,DBG_log("  tsi[%d] %d-%d >= ei->port 0-65535. can be narrowed  fitrange1 %d"
+-								,tsi_ni, tsi[tsi_ni].startport, tsi[tsi_ni].endport, fitrange1));
++
++			tmp3 = alloc_thing(struct traffic_selector, "struct traffic_selector");
++			*tmp3 = tmp2;
++			tmp3->next = NULL;
++			
++			if(*narrowed_tsi == NULL)
++			{
++				*narrowed_tsi = tmp3;
++			}
++			else
++			{
++				struct traffic_selector *tmp4 = *narrowed_tsi;
++				while(tmp4->next!=NULL){
++				tmp4 = tmp4->next;
+ 				}
+-				else
+-					DBG(DBG_CONTROL,DBG_log("   cant narrow tsi[%d] %d-%d to ei->port %d"  
+-								,tsi_ni, tsi[tsi_ni].startport, tsi[tsi_ni].endport, ei->port));
++				tmp4->next = tmp3;
++				
++			}
++		}
++
++		tmp = ikev2_subnettots(er);
++		for(i=0; i<tsr_n; i++) {
++			
++			/* ip address */
++			if(addrcmp(&tmp.low, &tsr[i].low) >= 0) 
++			{
++				tmp2.low = tmp.low;
++			}
++			else
++			{
++				tmp2.low = tsr[i].low;
++			}
++
++			if(addrcmp(&tmp.high, &tsr[i].high) >= 0) 
++			{
++				tmp2.high = tsr[i].high;
++			}			
++			else
++			{
++				tmp2.high = tmp.high;
++			}
+ 
++			if(addrcmp(&tmp2.low, &tmp2.high) > 0) {
++				continue;
+ 			}
+ 
++			/* port */
++			if(tmp.startport >= tsr[i].startport ) 
++			{
++				tmp2.startport=tmp.startport;
++			}
+ 			else 
+-				DBG(DBG_CONTROL,DBG_log("  mismatch tsi[%d] %d-%d to ei->port %d"
+-							,tsi_ni, tsi[tsi_ni].startport, tsi[tsi_ni].endport, ei->port));
++			{
++				tmp2.startport=tsr[i].startport;
++			}
+ 
++			if(tmp.endport >= tsr[i].endport )
++			{
++				tmp2.endport=tsr[i].endport;
++			}
++			else
++			{
++				tmp2.endport=tmp.endport;
++			}
++		
++			if(tmp2.startport >  tmp2.endport) 
++			{
++				continue;
++			}
+ 
+-			if((er->port) && (( er->port == tsr[tsr_ni].startport ) && (er->port == tsr[tsr_ni].endport))) {
+-				fitrange2 = 1; 
+-				DBG(DBG_CONTROL,DBG_log("   tsr[%d] %d  ==  er->port %d exact match single port fitrange2 %d"
+-							,tsr_ni, tsr[tsr_ni].startport, er->port, fitrange2));
++			/* as openswan supports only single port, so picking one port*/
++			if( tmp2.startport > 0){
++				tmp2.endport = tmp2.startport;
++			}
++			else if (tmp2.endport < 65535 ){
++				tmp2.startport = tmp2.endport;
++			}
+ 
++			/* protocol */
++			if( !tmp.ipprotoid && !tsr[i].ipprotoid && tmp.ipprotoid!=tsr[i].ipprotoid ) 
++			{
++				continue;
+ 			}
+-			else if ((!er->port) && ( ( tsr[tsr_ni].startport == er->port ) && (tsr[tsr_ni].endport == 65535 ))) {
+-				// we are on range 0 - 64K  will alloow  only the same  with our without narrowing
+-				fitrange2 =  65535;
+-				DBG(DBG_CONTROL,DBG_log("   tsr[%d] %d-%d  ==  ei 0-65535 exact match all ports fitrange2 %d"
+-							, tsr_ni, tsr[tsr_ni].startport, tsr[tsr_ni].endport, fitrange2));
++			else if(tmp.ipprotoid == 0)
++			{			
++				tmp2.ipprotoid = tsr[i].ipprotoid;
+ 			} 
++			else 
++			{
++				tmp2.ipprotoid = tmp.ipprotoid;
++			}
+ 
+-			else if ( (role == INITIATOR) && narrowing && (!er->port)) {
+-				DBG(DBG_CONTROL,DBG_log("   narrowing=yes want to narrow ei->port 0-65355 to tsi[%d] %d-%d"
+-							,tsr_ni, tsr[tsr_ni].startport, tsr[tsr_ni].endport)); 
+-				if( tsr[tsr_ni].startport <= tsi[tsr_ni].endport ){
+-					fitrange2 = 1 + tsr[tsr_ni].endport - tsr[tsi_ni].startport;
+-						DBG(DBG_CONTROL,DBG_log("  tsr[%d] %d-%d <= er->port 0-65535 can be narrowed  fitrange2 %d"
+-									,tsr_ni, tsr[tsr_ni].startport, tsr[tsr_ni].endport,fitrange2));
+-				}
+-				else
+-					DBG(DBG_CONTROL,DBG_log("   cant narrow tsr[%d] %d-%d to er->port 0-65535"  
+-								,tsr_ni, tsr[tsr_ni].startport, tsr[tsr_ni].endport));
++			/*setting type */
++			switch(tmp2.low.u.v4.sin_family) {
++			case AF_INET:
++				tmp2.ts_type = IKEv2_TS_IPV4_ADDR_RANGE;
++				break;
++			case AF_INET6:
++				tmp2.ts_type = IKEv2_TS_IPV6_ADDR_RANGE;
++				break;
++			}
+ 
+-			} 
+-      else if ((role == RESPONDER) &&  narrowing  && (er->port)) {
+-				DBG(DBG_CONTROL,DBG_log("   narrowing=yes want to narrow ei->port 0-65535 to tsi[%d] %d-%d"
+-							,tsr_ni, tsr[tsr_ni].startport, tsr[tsr_ni].endport)); 
+-				if((  er->port >= tsr[tsr_ni].startport ) && 
+-						(er->port <= tsr[tsr_ni].endport)) {
+-					fitrange2 = 1;
+-					DBG(DBG_CONTROL,DBG_log("  tsr[%d] %d-%d <= er->port %d can be narrowed fitrange2 %d" 
+-								, tsr_ni, tsr[tsr_ni].startport, tsr[tsr_ni].endport, er->port, fitrange2));
+-				}
+-				else
+-					DBG(DBG_CONTROL,DBG_log("   can't narrow tsr[%d] %d-%d to er->port %d"
+-								, tsr_ni, tsr[tsr_ni].startport, tsr[tsr_ni].endport, er->port));
++			tmp3 = alloc_thing(struct traffic_selector, "struct traffic_selector");
++			*tmp3 = tmp2;
++			tmp3->next = NULL;
++			
++			if(*narrowed_tsr == NULL)
++			{
++				*narrowed_tsr = tmp3;
+ 			}
+-			else 
+-				DBG(DBG_CONTROL,DBG_log("  mismatch tsr[%d] %d-%d to er->port %d"  
+-							,tsr_ni, tsr[tsr_ni].startport, tsr[tsr_ni].endport, er->port));
+-
+-
+-			int fitbits  = 0;
+-			if(fitrange1 && fitrange2) {
+-				fitbits = (fitrange1 << 8) + fitrange2;
+-				DBG(DBG_CONTROL,DBG_log("    is a match"));
+-				if(fitbits > bestfit_p) {
+-					*best_tsi_i = tsi_ni;
+-					*best_tsr_i = tsr_ni;
+-					bestfit_p = fitbits;
+-					DBG(DBG_CONTROL,DBG_log("    and is a better fit tsi[%d] fitrange1 %d tsr[%d] fitrange2 %d fitbits %d"
+-								, *best_tsi_i, fitrange1 , *best_tsr_i, fitrange2, fitbits));
+-				} 
+-				else {
+-					DBG(DBG_CONTROL,DBG_log("    and is not a better fit tsi[%d] fitrange %d tsr[%d] fitrange2 %d fitbits %d" 
+-								, *best_tsi_i, fitrange1 , *best_tsr_i, fitrange2, fitbits));
++			else
++			{
++				struct traffic_selector *tmp4 = *narrowed_tsr;
++				while(tmp4->next!=NULL){
++				tmp4 = tmp4->next;
+ 				}
+-			}
+-			else {
+-				DBG(DBG_CONTROL,DBG_log("    is not a match"));
++				
++				tmp4->next = tmp3;		
+ 			}
+ 
+ 		}
+ 	}
+-	DBG(DBG_CONTROL,DBG_log("    port_fitness  %d", bestfit_p));
+-	return bestfit_p;
+-}
+-
+-int ikev2_evaluate_connection_fit(struct connection *d
+-				  , struct spd_route *sr
+-				  , enum phase1_role role
+-				  , struct traffic_selector *tsi
+-				  , struct traffic_selector *tsr
+-				  , unsigned int tsi_n
+-				  , unsigned int tsr_n)
+-{
+-    unsigned int tsi_ni, tsr_ni;
+-    int bestfit = -1;
+-    int best_tsr, best_tsi; 
+-    struct end *ei, *er;
+-    
+-    if(role == INITIATOR) {
+-	ei = &sr->this;
+-	er = &sr->that;
+-    } else {
+-	ei = &sr->that;
+-	er = &sr->this;
+-    }
+-	
+-    DBG(DBG_CONTROLMORE,
+-    {
+-	char ei3[SUBNETTOT_BUF];
+-	char er3[SUBNETTOT_BUF];
+-	subnettot(&ei->client,  0, ei3, sizeof(ei3));
+-	subnettot(&er->client,  0, er3, sizeof(er3));
+-	DBG_log("  ikev2_evaluate_connection_fit evaluating our "
+-		"I=%s:%s:%d/%d R=%s:%d/%d %s to their:"
+-		, d->name, ei3, ei->protocol, ei->port
+-		, er3, er->protocol, er->port
+-		, is_virtual_connection(d) ? "(virt)" : "");
+-    }
+-    );
+-   
+-    /* compare tsi/r array to this/that, evaluating how well it fits */
+-    for(tsi_ni = 0; tsi_ni < tsi_n; tsi_ni++) {
+-	for(tsr_ni=0; tsr_ni<tsr_n; tsr_ni++) {
+-	    /* does it fit at all? */
+ 
++	struct traffic_selector *tmp;
++	tmp = *narrowed_tsi;
++	while(tmp!= NULL) {
++		
+ 	    DBG(DBG_CONTROLMORE,
+ 	    {
+ 		char lbi[ADDRTOT_BUF];
+ 		char hbi[ADDRTOT_BUF];
+-		char lbr[ADDRTOT_BUF];
+-		char hbr[ADDRTOT_BUF];
+-		addrtot(&tsi[tsi_ni].low,  0, lbi, sizeof(lbi));
+-		addrtot(&tsi[tsi_ni].high, 0, hbi, sizeof(hbi));
+-		addrtot(&tsr[tsr_ni].low,  0, lbr, sizeof(lbr));
+-		addrtot(&tsr[tsr_ni].high, 0, hbr, sizeof(hbr));
++		addrtot(&tmp->low,  0, lbi, sizeof(lbi));
++		addrtot(&tmp->high, 0, hbi, sizeof(hbi));
+ 		
+-		DBG_log("    tsi[%u]=%s/%s proto=%d portrange %d-%d, tsr[%u]=%s/%s proto=%d portrange %d-%d"
+-			, tsi_ni, lbi, hbi
+-			,  tsi[tsi_ni].ipprotoid, tsi[tsi_ni].startport, tsi[tsi_ni].endport
+-			, tsr_ni, lbr, hbr
+-			,  tsr[tsr_ni].ipprotoid, tsr[tsr_ni].startport, tsr[tsr_ni].endport);
++		DBG_log("    tsi=%s/%s, port=%d/%d, protocol=%d"
++			,  lbi, hbi, tmp->startport, tmp->endport, tmp->ipprotoid);
+ 	    }
+ 	    );
+-	    /* do addresses fit into the policy? */
+-
+-	    /*
+-	     * NOTE: Our parser/config only allows 1 CIDR, however IKEv2 ranges can be non-CIDR
+-	     *       for now we really support/limit ourselves to a single CIDR
+-	     */
+-	    if(addrinsubnet(&tsi[tsi_ni].low, &ei->client)
+-	       && addrinsubnet(&tsi[tsi_ni].high, &ei->client)
+-	       && addrinsubnet(&tsr[tsr_ni].low,  &er->client)
+-	       && addrinsubnet(&tsr[tsr_ni].high, &er->client)
+-	       && (tsi[tsi_ni].ipprotoid == ei->protocol)
+-	       && (tsr[tsr_ni].ipprotoid == er->protocol)
+-	      )
++
++	tmp=tmp->next;
++	}
++
++	tmp = *narrowed_tsr;
++	while(tmp!= NULL) {
++		
++	    DBG(DBG_CONTROLMORE,
+ 	    {
+-		/*
+-		 * now, how good a fit is it? --- sum of bits gives
+-		 * how good a fit this is.
+-		 */
+-		int ts_range1 = ikev2_calc_iprangediff(tsi[tsi_ni].low
+-						      , tsi[tsi_ni].high);
+-		int maskbits1 = ei->client.maskbits;
+-		int fitbits1  = maskbits1 + ts_range1;
+-
+-		int ts_range2 = ikev2_calc_iprangediff(tsr[tsr_ni].low
+-						      , tsr[tsr_ni].high);
+-		int maskbits2 = er->client.maskbits;
+-		int fitbits2  = maskbits2 + ts_range2;
+-		int fitbits = (fitbits1 << 8) + fitbits2;
+-
+-		/*
+-		 * comparing for ports
+-		 * for finding better local polcy
+-		 */
+-		DBG(DBG_CONTROL,DBG_log("ei->port %d  tsi[tsi_ni].startport %d  tsi[tsi_ni].endport %d",
+-			ei->port , tsi[tsi_ni].startport, tsi[tsi_ni].endport));
+-		if( ei->port && (tsi[tsi_ni].startport == ei->port && tsi[tsi_ni].endport == ei->port)) {
+-		fitbits = fitbits << 1;
+-		}
++		char lbi[ADDRTOT_BUF];
++		char hbi[ADDRTOT_BUF];
++		addrtot(&tmp->low,  0, lbi, sizeof(lbi));
++		addrtot(&tmp->high, 0, hbi, sizeof(hbi));
++		
++		DBG_log("    tsr=%s/%s, port=%d/%d, protocol=%d"
++			,  lbi, hbi, tmp->startport, tmp->endport, tmp->ipprotoid);
++	    }
++	    );
+ 
+-		if( er->port && (tsr[tsr_ni].startport == er->port && tsr[tsr_ni].endport == er->port)) {
+-		fitbits = fitbits << 1;
+-		}
++	tmp=tmp->next;
++	}
++	return TRUE;
++}
+ 
+-		DBG(DBG_CONTROLMORE,
+-		{
+-		    DBG_log("      has ts_range1=%u maskbits1=%u ts_range2=%u maskbits2=%u fitbits=%d <> %d"
+-			    , ts_range1, maskbits1, ts_range2, maskbits2
+-			    , fitbits, bestfit);
+-		}
+-		);
++struct connection *
++ikev2_create_narrowed_con(struct connection *c
++			, struct traffic_selector *narrowed_tsi
++			, struct traffic_selector *narrowed_tsr
++			, enum phase1_role role)
++{
++	struct connection *narrowed_con=NULL;
++	struct spd_route *tmp_spd=NULL, *tmp_spd1=NULL;
++	struct traffic_selector *tmptsi=NULL, *tmptsr=NULL;
+ 
+-		if(fitbits > bestfit) {
+-		    best_tsi = tsi_ni;
+-		    best_tsr = tsr_ni;
+-		    bestfit = fitbits;
++	narrowed_con = ikev2_narrow_instantiate(c);
++	
++	/* setup spds for narrowed connection*/
++	tmp_spd1 = NULL;
++	tmp_spd = &narrowed_con->spd;
++	tmptsi = narrowed_tsi;
++	
++	while(tmptsi != NULL) {
++		ip_subnet tmpsubneti;
++		rangetosubnet(&tmptsi->low, &tmptsi->high, &tmpsubneti);
++		tmptsr = narrowed_tsr;
++
++		while(tmptsr != NULL ) {
++			ip_subnet tmpsubnetr;
++			rangetosubnet(&tmptsr->low, &tmptsr->high, &tmpsubnetr);		
++
++			if(tmp_spd == NULL) {
++				struct spd_route *tmp_spd2 = clone_thing(narrowed_con->spd, "spds from narrowed ts");
++				tmp_spd = tmp_spd2;
++				tmp_spd->next = NULL;
++
++				if(tmp_spd1!= NULL){
++					tmp_spd1->next = tmp_spd;
++				}
++
++				if(tmp_spd != &narrowed_con->spd) {
++				tmp_spd->this.id.name.ptr = NULL;
++				tmp_spd->this.id.name.len = 0;
++                    		tmp_spd->that.id.name.ptr = NULL;
++                    		tmp_spd->that.id.name.len = 0;			
++
++				tmp_spd->this.host_addr_name = NULL;
++				tmp_spd->that.host_addr_name = NULL;
++
++				tmp_spd->this.updown = clone_str(tmp_spd->this.updown, "updown");
++				tmp_spd->that.updown = clone_str(tmp_spd->that.updown, "updown");
++
++				tmp_spd->this.cert_filename = NULL;
++				tmp_spd->that.cert_filename = NULL;
++
++				tmp_spd->this.cert.type = 0;
++				tmp_spd->that.cert.type = 0;
++
++				tmp_spd->this.ca.ptr = NULL;
++				tmp_spd->that.ca.ptr = NULL;
++
++				tmp_spd->this.groups = NULL;
++				tmp_spd->that.groups = NULL;
++
++				tmp_spd->this.virt = NULL;
++				tmp_spd->that.virt = NULL;
++				}
++			}
++
++			if(role == INITIATOR) {
++				tmp_spd->this.client = tmpsubneti;
++				tmp_spd->this.port = tmptsi->startport;
++				tmp_spd->this.protocol = tmptsi->ipprotoid;
++				if( subnetishost(&tmp_spd->this.client) && addrinsubnet(&tmp_spd->this.host_addr, &tmp_spd->this.client)) {
++				tmp_spd->this.has_client = FALSE;
++				}
++				else {
++				tmp_spd->this.has_client = TRUE;
++				}
++				tmp_spd->this.has_client_wildcard =  FALSE;
++				tmp_spd->this.has_port_wildcard = FALSE;
++				setportof(htons(tmp_spd->this.port), &tmp_spd->this.host_addr);
++				setportof(htons(tmp_spd->this.port), &tmp_spd->this.client.addr);
++
++				tmp_spd->that.client = tmpsubnetr;
++				tmp_spd->that.port = tmptsr->startport;
++				tmp_spd->that.protocol = tmptsr->ipprotoid;
++				if( subnetishost(&tmp_spd->that.client) && addrinsubnet(&tmp_spd->that.host_addr, &tmp_spd->that.client)) {
++				tmp_spd->that.has_client = FALSE;
++				}
++				else {
++				tmp_spd->that.has_client = TRUE;
++				}
++				tmp_spd->that.has_client_wildcard =  FALSE;
++				tmp_spd->that.has_port_wildcard = FALSE;
++				setportof(htons(tmp_spd->that.port), &tmp_spd->that.host_addr);
++				setportof(htons(tmp_spd->that.port), &tmp_spd->that.client.addr);		
++			}
++			else {
++				tmp_spd->this.client = tmpsubnetr;
++				tmp_spd->this.port = tmptsr->startport;
++				tmp_spd->this.protocol = tmptsr->ipprotoid;
++				if( subnetishost(&tmp_spd->this.client) && addrinsubnet(&tmp_spd->this.host_addr, &tmp_spd->this.client)) {
++				tmp_spd->this.has_client = FALSE;
++				}
++				else {
++				tmp_spd->this.has_client = TRUE;
++				}
++				tmp_spd->this.has_client_wildcard =  FALSE;
++				tmp_spd->this.has_port_wildcard = FALSE;
++				setportof(htons(tmp_spd->this.port), &tmp_spd->this.host_addr);
++				setportof(htons(tmp_spd->this.port), &tmp_spd->this.client.addr);
++
++				tmp_spd->that.client = tmpsubneti;
++				tmp_spd->that.port = tmptsi->startport;
++				tmp_spd->that.protocol = tmptsi->ipprotoid;
++				if( subnetishost(&tmp_spd->that.client) && addrinsubnet(&tmp_spd->that.host_addr, &tmp_spd->that.client)) {
++				tmp_spd->that.has_client = FALSE;
++				}
++				else {
++				tmp_spd->that.has_client = TRUE;
++				}
++				tmp_spd->that.has_client_wildcard =  FALSE;
++				tmp_spd->that.has_port_wildcard = FALSE;
++				setportof(htons(tmp_spd->that.port), &tmp_spd->that.host_addr);
++				setportof(htons(tmp_spd->that.port), &tmp_spd->that.client.addr);
++			}
++
++		tmp_spd1 = tmp_spd;
++		tmp_spd = tmp_spd1->next;
++		tmptsr = tmptsr->next;	
+ 		}
+-	    }
++	tmptsi = tmptsi->next;
+ 	}
+-    }
+ 
+-    return bestfit;
++                    char buftest[ADDRTOT_BUF];
++                    tmp_spd = &narrowed_con->spd;
++                    int count_spd=0;
++                    do {
++                        DBG(DBG_CONTROLMORE, DBG_log("spd route number: %d", ++count_spd));
++
++                        /**that info**/
++                	DBG(DBG_CONTROLMORE, DBG_log("that id kind: %d",tmp_spd->that.id.kind));
++                	DBG(DBG_CONTROLMORE, 
++				DBG_log("that id ipaddr: %s", (addrtot(&tmp_spd->that.id.ip_addr, 0, buftest, sizeof(buftest)), buftest)));
++
++                	if (tmp_spd->that.id.name.ptr != NULL) {
++                	DBG(DBG_CONTROLMORE, DBG_dump_chunk("that id name",tmp_spd->that.id.name));
++                	}
++
++                	DBG(DBG_CONTROLMORE, 
++                            DBG_log("that host_addr: %s", (addrtot(&tmp_spd->that.host_addr, 0, buftest, sizeof(buftest)), buftest)));
++                	DBG(DBG_CONTROLMORE, 
++                            DBG_log("that nexthop: %s", (addrtot(&tmp_spd->that.host_nexthop, 0, buftest, sizeof(buftest)), buftest)));
++                        DBG(DBG_CONTROLMORE,
++                	    DBG_log("that srcip: %s", (addrtot(&tmp_spd->that.host_srcip, 0, buftest, sizeof(buftest)), buftest)));
++                        DBG(DBG_CONTROLMORE,
++                	    DBG_log("that client_addr: %s, maskbits:%d", (addrtot(&tmp_spd->that.client.addr, 0, 
++							buftest, sizeof(buftest)), buftest),tmp_spd->that.client.maskbits));
++                	DBG(DBG_CONTROLMORE, DBG_log("that has_client: %d", tmp_spd->that.has_client));
++                	DBG(DBG_CONTROLMORE, DBG_log("that has_client_wildcard: %d", tmp_spd->that.has_client_wildcard));
++                	DBG(DBG_CONTROLMORE, DBG_log("that has_port_wildcard: %d", tmp_spd->that.has_port_wildcard));
++                	DBG(DBG_CONTROLMORE, DBG_log("that has_id_wildcards: %d", tmp_spd->that.has_id_wildcards));
++
++                	/**this info**/
++                	DBG(DBG_CONTROLMORE, DBG_log("this id kind: %d",tmp_spd->this.id.kind));
++                	DBG(DBG_CONTROLMORE, 
++                            DBG_log("this id ipaddr: %s", (addrtot(&tmp_spd->this.id.ip_addr, 0, buftest, sizeof(buftest)), buftest)));
++
++                	if (tmp_spd->this.id.name.ptr != NULL) {
++                	DBG_dump_chunk("this id name",tmp_spd->this.id.name);
++                	}
++
++                	DBG(DBG_CONTROLMORE, 
++                            DBG_log("this host_addr: %s", (addrtot(&tmp_spd->this.host_addr, 0, buftest, sizeof(buftest)), buftest)));
++                	DBG(DBG_CONTROLMORE, 
++                            DBG_log("this nexthop: %s", (addrtot(&tmp_spd->this.host_nexthop, 0, buftest, sizeof(buftest)), buftest)));
++                	DBG(DBG_CONTROLMORE, 
++                            DBG_log("this srcip: %s", (addrtot(&tmp_spd->this.host_srcip, 0, buftest, sizeof(buftest)), buftest)));
++                	DBG(DBG_CONTROLMORE, DBG_log("this client_addr: %s, maskbits:%d", (addrtot(&tmp_spd->this.client.addr, 
++								0, buftest, sizeof(buftest)), buftest),tmp_spd->this.client.maskbits));
++                	DBG(DBG_CONTROLMORE, DBG_log("this has_client: %d", tmp_spd->this.has_client));
++                	DBG(DBG_CONTROLMORE, DBG_log("this has_client_wildcard: %d", tmp_spd->this.has_client_wildcard));
++                	DBG(DBG_CONTROLMORE, DBG_log("this has_port_wildcard: %d", tmp_spd->this.has_port_wildcard));
++                	DBG(DBG_CONTROLMORE, DBG_log("this has_id_wildcards: %d", tmp_spd->this.has_id_wildcards));
++
++                        tmp_spd = tmp_spd->next;
++		    } while(tmp_spd!=NULL);
++
++	return narrowed_con;
+ }
+ 
+ stf_status ikev2_child_sa_respond(struct msg_digest *md
+@@ -618,8 +1187,13 @@ stf_status ikev2_child_sa_respond(struct msg_digest *md
+     stf_status ret;
+     struct payload_digest *const tsi_pd = md->chain[ISAKMP_NEXT_v2TSi];
+     struct payload_digest *const tsr_pd = md->chain[ISAKMP_NEXT_v2TSr];
+-    struct traffic_selector tsi[16], tsr[16];
++    struct traffic_selector tsi[16], tsr[16], *narrowed_tsi=NULL, *narrowed_tsr=NULL;
++    struct connection *narrowed_con=NULL, *result=NULL;
+     unsigned int tsi_n, tsr_n;
++    bool ts_negotiation_failed = FALSE;
++
++
++    st1 = duplicate_state(st);
+ 
+     /*
+      * now look at provided TSx, and see if these fit the connection
+@@ -628,195 +1202,117 @@ stf_status ikev2_child_sa_respond(struct msg_digest *md
+     tsi_n = ikev2_parse_ts(tsi_pd, tsi, 16);
+     tsr_n = ikev2_parse_ts(tsr_pd, tsr, 16);
+ 
+-    /*
+-     * now walk through all connections and see if this connection
+-     * was in fact the best.
+-     *
+-     * similar to find_client_connection/fc_try.
+-     */
+-  {
+-	struct connection *b = c;
+-	struct connection *d;
+-	int bestfit_n, newfit, bestfit_p; 
+-	struct spd_route *sra, *bsr;
+-	struct host_pair *hp = NULL;
+-	unsigned int best_tsi_i ,  best_tsr_i;
+-
+-	bsr = NULL;
+-	bestfit_n = -1;
+-	bestfit_p = -1; 
+-	best_tsi_i =  best_tsr_i = -1;
+-
+-	for (sra = &c->spd; sra != NULL; sra = sra->next)
+-	{
+-					int bfit_n=ikev2_evaluate_connection_fit(c,sra,role,tsi,tsr,tsi_n,
+-													tsr_n);
+-					if (bfit_n > bestfit_n) 
+-					{ 
+-									DBG(DBG_CONTROLMORE, DBG_log("bfit_n=ikev2_evaluate_connection_fit found better fit c %s", c->name));
+-									int bfit_p =  ikev2_evaluate_connection_port_fit (c ,sra,role,tsi,tsr,
+-																	tsi_n,tsr_n, &best_tsi_i, &best_tsr_i);
+-									if (bfit_p > bestfit_p) {
+-													DBG(DBG_CONTROLMORE, DBG_log("ikev2_evaluate_connection_port_fit found better fit c %s, tsi[%d],tsr[%d]"
+-																									, c->name, best_tsi_i, best_tsr_i));
+-													bestfit_p = bfit_p;
+-													bestfit_n = bfit_n;
+-													b = c;
+-													bsr = sra;
+-									}
+-					}
+-					else 
+-									DBG(DBG_CONTROLMORE, DBG_log("prefix range fit c %s c->name was rejected by port matching"
+-																					, c->name));  
+-	}
+-
+-	for (sra = &c->spd; hp==NULL && sra != NULL; sra = sra->next)
+-	{
+-		hp = find_host_pair(&sra->this.host_addr
+-				, sra->this.host_port
+-				, &sra->that.host_addr
+-				, sra->that.host_port);
++    if(ikev2_narrowing(c, role, tsi, tsr, tsi_n, tsr_n, &narrowed_tsi , &narrowed_tsr, &result)){
+ 
+-#ifdef DEBUG
+-		if (DBGP(DBG_CONTROLMORE))
+-		{
+-			char s2[SUBNETTOT_BUF],d2[SUBNETTOT_BUF];
++	if(narrowed_tsi == NULL && narrowed_tsr == NULL && result!= NULL) {
++	/*found exact match */
++		narrowed_con = result;
+ 
+-			subnettot(&sra->this.client, 0, s2, sizeof(s2));
+-			subnettot(&sra->that.client, 0, d2, sizeof(d2));
++		/*preparing traffic selectors (need to do: free first narrowed_ts here) */
++		st1->st_ts_this= ikev2_subnettots(&result->spd.this);
++		st1->st_ts_that= ikev2_subnettots(&result->spd.that);
++	}
++	else {
++		narrowed_con = ikev2_create_narrowed_con(result, narrowed_tsi, narrowed_tsr, role);
+ 
+-			DBG_log("  checking hostpair %s -> %s is %s"
+-					, s2, d2
+-					, (hp ? "found" : "not found"));
++		/*preparing traffic selectors (need to do: free first narrowed_ts here) */
++		if(role == INITIATOR) {
++		st1->st_ts_this= *narrowed_tsi;
++		st1->st_ts_that= *narrowed_tsr;
+ 		}
+-#endif /* DEBUG */
+-
+-		if(!hp) continue;
+-
+-		for (d = hp->connections; d != NULL; d = d->hp_next)
+-		{
+-			struct spd_route *sr;
+-			int wildcards, pathlen;  /* XXX */
+-
+-			if (d->policy & POLICY_GROUP)
+-				continue;
+-
+-			if (!(same_id(&c->spd.this.id, &d->spd.this.id)
+-						&& match_id(&c->spd.that.id, &d->spd.that.id, &wildcards)
+-						&& trusted_ca(c->spd.that.ca, d->spd.that.ca, &pathlen)))
+-				continue;
+-
+-
+-			for (sr = &d->spd; sr != NULL; sr = sr->next) {
+-				newfit=ikev2_evaluate_connection_fit(d,sr,role
+-						,tsi,tsr,tsi_n,tsr_n);
+-				if(newfit > bestfit_n) {  /// will complicated this with narrowing
+-					DBG(DBG_CONTROLMORE, DBG_log("bfit=ikev2_evaluate_connection_fit found better fit d %s", d->name)); 
+-					int bfit_p =  ikev2_evaluate_connection_port_fit (c ,sra,role,tsi,tsr,
+-							tsi_n,tsr_n, &best_tsi_i, &best_tsr_i);
+-					if (bfit_p > bestfit_p) {
+-						DBG(DBG_CONTROLMORE, DBG_log("ikev2_evaluate_connection_port_fit found better fit d %s, tsi[%d],tsr[%d]"
+-									, d->name, best_tsi_i, best_tsr_i));
+-						bestfit_p = bfit_p;
+-						bestfit_n = newfit;
+-						b = d;
+-						bsr = sr;
+-					}
+-				}
+-				else 
+-					DBG(DBG_CONTROLMORE, DBG_log("prefix range fit d %s d->name was rejected by port matching", d->name));
+-			}
++		else {
++		st1->st_ts_this= *narrowed_tsr;
++		st1->st_ts_that= *narrowed_tsi;
+ 		}
++
++		pfreeany(narrowed_tsi);
++		pfreeany(narrowed_tsr);
+ 	}
++    }
++    else {
++	ts_negotiation_failed = TRUE;
++    }
+ 
+-	/*
+-	 * now that we have found the best connection, copy the data into
+-	 * the state structure as the tsi/tsr
+-	 *
+-	 */
++    if(narrowed_con!= NULL && !ts_negotiation_failed) {	
++    c = narrowed_con; 
++    }
+ 
+-	/*better connection*/
+-	c=b;
++    st1->st_connection = c;
++    st1->st_childsa = NULL;
++    insert_state(st1);
+ 
+-	/* Paul: should we STF_FAIL here instead of checking for NULL */
+-	if (bsr != NULL) {
+-    st1 = duplicate_state(st);
+-    insert_state(st1); /* needed for delete - we should never have duplicated before we were sure */
+-	
+-		if(role == INITIATOR) {
+-			memcpy (&st1->st_ts_this , &tsi[best_tsi_i],  sizeof(struct traffic_selector));
+-			memcpy (&st1->st_ts_that , &tsr[best_tsr_i],  sizeof(struct traffic_selector));
+-		}
+-		else {
+-			st1->st_ts_this = ikev2_end_to_ts(&bsr->this);
+-			st1->st_ts_that = ikev2_end_to_ts(&bsr->that);
+-		}
+-		ikev2_print_ts(&st1->st_ts_this);
+-		ikev2_print_ts(&st1->st_ts_that);
++    /* start of SA out */
++    {
++	struct isakmp_sa r_sa = sa_pd->payload.sa;
++	notification_t rn;
++	pb_stream r_sa_pbs;
++
++	if(ts_negotiation_failed) {
++	r_sa.isasa_np = ISAKMP_NEXT_v2N;
+ 	}
+ 	else {
+-		if(role == INITIATOR) 
+-				return STF_FAIL;
+-			else
+-			return STF_FAIL + v2N_NO_PROPOSAL_CHOSEN ;
+-		}
++	r_sa.isasa_np = ISAKMP_NEXT_v2TSi;
+ 	}
++  
++	if (!out_struct(&r_sa, &ikev2_sa_desc, outpbs, &r_sa_pbs))
++	    return STF_INTERNAL_ERROR;
+ 
+-	st1->st_connection = c;
+-	md->st = st1;
+-	md->pst= st;
+-
+-	/* start of SA out */
+-	{
+-		struct isakmp_sa r_sa = sa_pd->payload.sa;
+-		notification_t rn;
+-		pb_stream r_sa_pbs;
+-
+-		r_sa.isasa_np = ISAKMP_NEXT_v2TSi;  
+-		if (!out_struct(&r_sa, &ikev2_sa_desc, outpbs, &r_sa_pbs))
+-			return STF_INTERNAL_ERROR;
++	/* SA body in and out */
++	rn = ikev2_parse_child_sa_body(&sa_pd->pbs, &sa_pd->payload.v2sa,
++				       &r_sa_pbs, st1, FALSE);
++	
++	if (rn != NOTHING_WRONG)
++	    return STF_FAIL + rn;
++    }
+ 
+-		/* SA body in and out */
+-		rn = ikev2_parse_child_sa_body(&sa_pd->pbs, &sa_pd->payload.v2sa,
+-				&r_sa_pbs, st1, FALSE);
++    if(ts_negotiation_failed) {
++	chunk_t child_spi, notifiy_data;
++	memset(&child_spi, 0, sizeof(child_spi));
++	memset(&notifiy_data, 0, sizeof(notifiy_data));
++	ship_v2N (ISAKMP_NEXT_NONE, ISAKMP_PAYLOAD_NONCRITICAL, /*PROTO_ISAKMP*/ 0,
++			&child_spi,
++			v2N_TS_UNACCEPTABLE, &notifiy_data, outpbs);
++	change_state(st1, STATE_CHILDSA_DEL);
++	delete_state(st1);
++	return STF_OK;
++    }
+ 
+-		if (rn != NOTHING_WRONG)
+-			return STF_FAIL + rn; // should we delete_state st1?
+-	}
++    md->st = st1;
++    md->pst= st;
+ 
+ 	ret = ikev2_calc_emit_ts(md, outpbs, role
+ 			, c, c->policy);
+ 	if(ret != STF_OK) return ret; // should we delete_state st1?
+ 
+-	if( role == RESPONDER ) {
+-		chunk_t child_spi, notifiy_data;
+-		struct payload_digest *p;
+-		for(p = md->chain[ISAKMP_NEXT_v2N]; p != NULL; p = p->next)
+-		{
+-			if ( p->payload.v2n.isan_type == v2N_USE_TRANSPORT_MODE ) {
+-
+-				if(st1->st_connection->policy & POLICY_TUNNEL) {
+-					DBG_log("Although local policy is tunnel, received USE_TRANSPORT_MODE");
+-					DBG_log("So switching to transport mode, and responding with USE_TRANSPORT_MODE notify");
+-				}
+-				else {
+-					DBG_log("Local policy is transport, received USE_TRANSPORT_MODE");
+-					DBG_log("Now responding with USE_TRANSPORT_MODE notify");
+-				}
+-
+-				memset(&child_spi, 0, sizeof(child_spi));
+-				memset(&notifiy_data, 0, sizeof(notifiy_data));
+-				ship_v2N (ISAKMP_NEXT_NONE, ISAKMP_PAYLOAD_NONCRITICAL, /*PROTO_ISAKMP*/ 0,
+-						&child_spi,
+-						v2N_USE_TRANSPORT_MODE, &notifiy_data, outpbs);
+-
+-				if (st1->st_esp.present == TRUE) {
+-					/*openswan supports only "esp" with ikev2 it seems, look at ikev2_parse_child_sa_body handling*/
+-					st1->st_esp.attrs.encapsulation = ENCAPSULATION_MODE_TRANSPORT;
+-				}
+-				break;
+-			}
+-		}
++    if( role == RESPONDER ) {
++	chunk_t child_spi, notifiy_data;
++	struct payload_digest *p;
++	for(p = md->chain[ISAKMP_NEXT_v2N]; p != NULL; p = p->next)
++	{
++	   if ( p->payload.v2n.isan_type == v2N_USE_TRANSPORT_MODE ) {
++
++	   if(st1->st_connection->policy & POLICY_TUNNEL) {
++		DBG_log("Although local policy is tunnel, received v2N_USE_TRANSPORT_MODE");
++		DBG_log("So switching to transport mode, and responding with v2N_USE_TRANSPORT_MODE notify");
++	   }
++	   else {
++		DBG_log("Local policy is transport, received v2N_USE_TRANSPORT_MODE");
++		DBG_log("Now responding with v2N_USE_TRANSPORT_MODE notify");
++	   }
++
++	   memset(&child_spi, 0, sizeof(child_spi));
++	   memset(&notifiy_data, 0, sizeof(notifiy_data));
++	   ship_v2N (ISAKMP_NEXT_NONE, ISAKMP_PAYLOAD_NONCRITICAL, /*PROTO_ISAKMP*/ 0,
++			&child_spi,
++			v2N_USE_TRANSPORT_MODE, &notifiy_data, outpbs);
++
++	   if (st1->st_esp.present == TRUE) {
++		/*openswan supports only "esp" with ikev2 it seems, look at ikev2_parse_child_sa_body handling*/
++		st1->st_esp.attrs.encapsulation = ENCAPSULATION_MODE_TRANSPORT;
++	   }
++	   break;
++	   }
++	}
+     }
+ 
+     ikev2_derive_child_keys(st1, role);
+@@ -824,6 +1320,8 @@ stf_status ikev2_child_sa_respond(struct msg_digest *md
+     if(!install_ipsec_sa(st1, TRUE))
+ 	return STF_FATAL;
+ 
++    st1->st_childsa = c;
++
+     /* mark the connection as now having an IPsec SA associated with it. */
+     st1->st_connection->newest_ipsec_sa = st1->st_serialno;
+ 
+diff --git a/programs/pluto/ikev2_parent.c b/programs/pluto/ikev2_parent.c
+index 5b1940a..a96ede5 100644
+--- a/programs/pluto/ikev2_parent.c
++++ b/programs/pluto/ikev2_parent.c
+@@ -120,8 +120,9 @@ ikev2parent_outI1(int whack_sock
+     initialize_new_state(st, c, policy, try, whack_sock, importance);
+     st->st_ikev2 = TRUE;
+     change_state(st, STATE_PARENT_I1);
+-    st->st_msgid_lastack = INVALID_MSGID;
+-    st->st_msgid_nextuse = 0;
++    st->st_msgid_last_localreq = INVALID_MSGID;
++    st->st_msgid_last_localreq_ack = INVALID_MSGID;
++    st->st_msgid_last_remotereq=INVALID_MSGID;	
+     st->st_try   = try;
+ 
+     if (HAS_IPSEC_POLICY(policy)) {
+@@ -483,6 +484,7 @@ ikev2_parent_outI1_common(struct msg_digest *md
+ 
+     /* Transmit */
+     send_packet(st, __FUNCTION__, TRUE);
++    ikev2_update_counters(md, req_sent);
+ 
+     /* Set up a retransmission event, half a minute henceforth */
+     TCLCALLOUT("v2_adjustTimers", st, st->st_connection, md);
+@@ -565,8 +567,9 @@ stf_status ikev2parent_inI1outR1(struct msg_digest *md)
+ 	initialize_new_state(st, c, policy, 0, NULL_FD, pcim_stranger_crypto); 
+ 	st->st_ikev2 = TRUE;
+ 	change_state(st, STATE_PARENT_R1);
+-	st->st_msgid_lastack = INVALID_MSGID;
+-	st->st_msgid_nextuse = 0;
++	st->st_msgid_last_localreq = INVALID_MSGID;
++	st->st_msgid_last_localreq_ack = INVALID_MSGID;
++	st->st_msgid_last_remotereq=INVALID_MSGID;
+ 
+ 	md->st = st;
+ 	md->from_state = STATE_IKEv2_BASE;
+@@ -750,6 +753,8 @@ ikev2_parent_inI1outR1_tail(struct pluto_crypto_req_cont *pcrc
+     {
+ 	struct isakmp_hdr r_hdr = md->hdr;
+ 
++	r_hdr.isa_version = IKEv2_MAJOR_VERSION << ISA_MAJ_SHIFT | IKEv2_MINOR_VERSION;
++
+ 	memcpy(r_hdr.isa_rcookie, st->st_rcookie, COOKIE_SIZE);
+ 	r_hdr.isa_np = ISAKMP_NEXT_v2SA;
+ 	r_hdr.isa_flags &= ~ISAKMP_FLAGS_I;
+@@ -761,7 +766,7 @@ ikev2_parent_inI1outR1_tail(struct pluto_crypto_req_cont *pcrc
+ 
+     /* start of SA out */
+     {
+-	struct isakmp_sa r_sa = sa_pd->payload.sa;
++	struct ikev2_sa r_sa = sa_pd->payload.v2sa;
+ 	v2_notification_t rn;
+ 	pb_stream r_sa_pbs;
+ 
+@@ -848,6 +853,8 @@ ikev2_parent_inI1outR1_tail(struct pluto_crypto_req_cont *pcrc
+ 
+     /* note: retransimission is driven by initiator */
+ 
++   ikev2_update_counters(md, response_sent);
++
+     return STF_OK;
+     
+ }
+@@ -897,9 +904,9 @@ stf_status ikev2parent_inR1outI2(struct msg_digest *md)
+ 		md->svm = ikev2_parent_firststate();
+ 
+ 		change_state(st, STATE_PARENT_I1);
+-    	st->st_msgid_lastack = INVALID_MSGID;
+-	md->msgid_received = INVALID_MSGID;  /* AAA hack  */
+-    	st->st_msgid_nextuse = 0;
++		st->st_msgid_last_localreq = INVALID_MSGID;
++		st->st_msgid_last_localreq_ack = INVALID_MSGID;
++		st->st_msgid_last_remotereq=INVALID_MSGID;
+ 
+ 		return ikev2_parent_outI1_common(md, st);  
+     }
+@@ -954,8 +961,8 @@ stf_status ikev2parent_inR1outI2(struct msg_digest *md)
+ 	    return STF_FAIL + rn;
+     }
+ 
+-    /* update state */
+-    ikev2_update_counters(md);
++    /* update state counters */
++    ikev2_update_counters(md, response_recd);
+ 
+     /* now. we need to go calculate the g^xy */
+     {
+@@ -1120,14 +1127,9 @@ static stf_status ikev2_encrypt_msg(struct msg_digest *md,
+     /* okay, authenticate from beginning of IV */
+     {
+ 	struct hmac_ctx ctx;
+-	DBG(DBG_PARSING, DBG_log("Inside authloc"));
+-	DBG(DBG_CRYPT, DBG_dump("authkey value: ", authkey->ptr, authkey->len));
+ 	hmac_init_chunk(&ctx, pst->st_oakley.integ_hasher, *authkey);
+-	DBG(DBG_PARSING, DBG_log("Inside authloc after init"));
+ 	hmac_update(&ctx, authstart, authloc-authstart);
+-	DBG(DBG_PARSING, DBG_log("Inside authloc after update"));
+ 	hmac_final(authloc, &ctx);
+-	DBG(DBG_PARSING, DBG_log("Inside authloc after final"));
+ 
+ 	DBG(DBG_PARSING,
+ 	    DBG_dump("data being hmac:", authstart, authloc-authstart);
+@@ -1317,7 +1319,7 @@ ikev2_parent_inR1outI2_tail(struct pluto_crypto_req_cont *pcrc
+ 
+     pst = st;
+     st = duplicate_state(pst);
+-    st->st_msgid = htonl(pst->st_msgid_nextuse); /* PAUL: note ordering */
++    st->st_msgid = htonl(pst->st_msgid_last_localreq == INVALID_MSGID? 0 : pst->st_msgid_last_localreq + 1);
+     insert_state(st);
+     md->st = st;
+     md->pst= pst;
+@@ -1344,6 +1346,8 @@ ikev2_parent_inR1outI2_tail(struct pluto_crypto_req_cont *pcrc
+     {
+ 	struct isakmp_hdr r_hdr = md->hdr;
+ 
++	r_hdr.isa_version = IKEv2_MAJOR_VERSION << ISA_MAJ_SHIFT | IKEv2_MINOR_VERSION;
++
+ 	r_hdr.isa_np    = ISAKMP_NEXT_v2E;
+ 	r_hdr.isa_xchg  = ISAKMP_v2_AUTH;
+ 	r_hdr.isa_flags = ISAKMP_FLAGS_I;
+@@ -1464,8 +1468,8 @@ ikev2_parent_inR1outI2_tail(struct pluto_crypto_req_cont *pcrc
+ 
+ 	    ikev2_emit_ipsec_sa(md,&e_pbs_cipher,ISAKMP_NEXT_v2TSi,c0, policy);
+ 	    
+-	    st->st_ts_this = ikev2_end_to_ts(&c0->spd.this);
+-	    st->st_ts_that = ikev2_end_to_ts(&c0->spd.that);
++	    st->st_ts_this = ikev2_subnettots(&c0->spd.this);
++	    st->st_ts_that = ikev2_subnettots(&c0->spd.that);
+ 	    
+ 	    ikev2_calc_emit_ts(md, &e_pbs_cipher, INITIATOR, c0, policy);
+ 
+@@ -1522,6 +1526,7 @@ ikev2_parent_inR1outI2_tail(struct pluto_crypto_req_cont *pcrc
+     delete_event(st);
+     event_schedule(EVENT_v2_RETRANSMIT, EVENT_RETRANSMIT_DELAY_0, st);
+ 
++    ikev2_update_counters(md, req_sent);
+     return STF_OK;
+     
+ }
+@@ -1648,7 +1653,6 @@ ikev2_parent_inI2outR2_tail(struct pluto_crypto_req_cont *pcrc
+     unsigned char *idhash_in, *idhash_out;
+     unsigned char *authstart;
+     unsigned int np;
+-    int v2_notify_num = 0;
+ 
+     /* extract calculated values from r */
+     finish_dh_v2(st, r);
+@@ -1672,6 +1676,12 @@ ikev2_parent_inI2outR2_tail(struct pluto_crypto_req_cont *pcrc
+         return STF_FAIL;
+     }
+ 
++
++    /* if it decrypted okay, then things are good, this packet is
++     * well received, and we should change state.
++     */
++    rehash_state(st);
++
+     if(!ikev2_decode_peer_id(md, RESPONDER)) {
+ 	return STF_FAIL + INVALID_ID_INFORMATION;
+     }
+@@ -1784,10 +1794,13 @@ ikev2_parent_inI2outR2_tail(struct pluto_crypto_req_cont *pcrc
+ 	/* HDR out */
+ 	{
+ 	    struct isakmp_hdr r_hdr = md->hdr;
++
++	    r_hdr.isa_version = IKEv2_MAJOR_VERSION << ISA_MAJ_SHIFT | IKEv2_MINOR_VERSION;
+ 	    
+ 	    r_hdr.isa_np    = ISAKMP_NEXT_v2E;
+ 	    r_hdr.isa_xchg  = ISAKMP_v2_AUTH;
+ 	    r_hdr.isa_flags = ISAKMP_FLAGS_R;
++	    r_hdr.isa_msgid = htonl(md->msgid_received);
+ 	    memcpy(r_hdr.isa_icookie, st->st_icookie, COOKIE_SIZE);
+ 	    memcpy(r_hdr.isa_rcookie, st->st_rcookie, COOKIE_SIZE);
+ 	    if (!out_struct(&r_hdr, &isakmp_hdr_desc, &reply_stream, &md->rbody))
+@@ -1902,14 +1915,7 @@ ikev2_parent_inI2outR2_tail(struct pluto_crypto_req_cont *pcrc
+ 	if(np == ISAKMP_NEXT_v2SA) {
+ 	    /* must have enough to build an CHILD_SA */
+ 	    ret = ikev2_child_sa_respond(md, RESPONDER, &e_pbs_cipher);
+-	    if(ret > STF_FAIL) {
+-		v2_notify_num = ret - STF_FAIL;
+-		DBG(DBG_CONTROL,DBG_log("ikev2_child_sa_respond returned STF_FAIL with %s", enum_name(&ikev2_notify_names, v2_notify_num)))
+-		np = ISAKMP_NEXT_NONE;
+-	    } else if(ret != STF_OK) {
+-		DBG_log("ikev2_child_sa_respond returned %s", enum_name(&stfstatus_name, ret));
+-		np = ISAKMP_NEXT_NONE;
+-	    }
++	    if(ret != STF_OK) return ret;
+ 	}
+ 
+ 	ikev2_padup_pre_encrypt(md, &e_pbs_cipher);
+@@ -1944,6 +1950,7 @@ ikev2_parent_inI2outR2_tail(struct pluto_crypto_req_cont *pcrc
+ 
+     /* note: retransimission is driven by initiator */
+ 
++    ikev2_update_counters(md, response_sent);
+     /* if the child failed, delete its state here - we sent the packet */
+     /* PAUL */
+     return STF_OK;
+@@ -1966,6 +1973,8 @@ stf_status ikev2parent_inR2(struct msg_digest *md)
+     struct connection *c = st->st_connection;
+     unsigned char *idhash_in;
+     struct state *pst = st;
++    struct traffic_selector tsi[16], tsr[16];
++    unsigned int tsi_n=0, tsr_n=0;
+ 
+     if(st->st_clonedfrom != 0) {
+ 	pst = state_with_serialno(st->st_clonedfrom);
+@@ -2073,6 +2082,28 @@ stf_status ikev2parent_inR2(struct msg_digest *md)
+      */
+     change_state(pst, STATE_PARENT_I3);
+     c->newest_isakmp_sa = pst->st_serialno;
++
++    {
++	/*check for child sa related errors */
++	/* check for TS_UNACCEPTABLE */
++	struct payload_digest *p;
++
++	for(p = md->chain[ISAKMP_NEXT_v2N]; p != NULL; p = p->next)
++	{
++		if ( p->payload.v2n.isan_type == v2N_TS_UNACCEPTABLE ) {
++			/* we can proceed with successful parent SA */
++			if(st->st_clonedfrom != 0) {
++				delete_event(st);
++				pst = state_with_serialno(st->st_clonedfrom);
++				md->st = pst;
++				md->pst = pst;
++				delete_event(st);
++				delete_state(st);
++			}
++			return STF_OK;
++		}  
++	}
++    }
+     
+     /* authentication good, see if there is a child SA available */
+     if(md->chain[ISAKMP_NEXT_v2SA] == NULL
+@@ -2084,79 +2115,49 @@ stf_status ikev2parent_inR2(struct msg_digest *md)
+ 	/*
+ 	 * Delete previous retransmission event.
+ 	 */
+-	delete_event(st);
++	if(st->st_clonedfrom != 0) {
++		pst = state_with_serialno(st->st_clonedfrom);
++		md->st = pst;
++		md->pst = pst;
++		delete_event(st);
++		delete_state(st);
++	}
+ 	return STF_OK;
+     }
+ 
+     {
+-			int bestfit_n, bestfit_p;
+-			unsigned int best_tsi_i ,  best_tsr_i;
+-			bestfit_n = -1;
+-			bestfit_p = -1;
+-
+-			/* Check TSi/TSr http://tools.ietf.org/html/rfc5996#section-2.9 */
+-			DBG(DBG_CONTROLMORE,DBG_log(" check narrowing - we are responding to I2"));
+-
+-			struct payload_digest *const tsi_pd = md->chain[ISAKMP_NEXT_v2TSi];
+-			struct payload_digest *const tsr_pd = md->chain[ISAKMP_NEXT_v2TSr];
+-			struct traffic_selector tsi[16], tsr[16];
+-			int tsc=0;
+-#if 0
+-			bool instantiate = FALSE;
+-			ip_subnet tsi_subnet, tsr_subnet;
+-			const char *oops;
+-#endif
++	struct payload_digest *const tsi_pd = md->chain[ISAKMP_NEXT_v2TSi];
++	struct payload_digest *const tsr_pd = md->chain[ISAKMP_NEXT_v2TSr];
+ 
+-			unsigned int tsi_n, tsr_n;
+-			tsi_n = ikev2_parse_ts(tsi_pd, tsi, 16);
+-			tsr_n = ikev2_parse_ts(tsr_pd, tsr, 16);
++	/* parse traffic selector */
+ 
+-			DBG_log("Checking TSi(%d)/TSr(%d) selectors, looking for exact match", tsi_n,tsr_n); 
+-			{
+-				struct spd_route *sra ;
+-				sra = &c->spd; 
+-				int bfit_n=ikev2_evaluate_connection_fit(c,sra,INITIATOR,tsi,tsr,tsi_n, tsr_n);
+-				if (bfit_n > bestfit_n)
+-				{
+-					DBG(DBG_CONTROLMORE, DBG_log("bfit_n=ikev2_evaluate_connection_fit found better fit c %s", c->name));
+-					int bfit_p =  ikev2_evaluate_connection_port_fit (c ,sra,INITIATOR,tsi,tsr,
+-							tsi_n,tsr_n, &best_tsi_i, &best_tsr_i);
+-					if (bfit_p > bestfit_p) {
+-						DBG(DBG_CONTROLMORE, DBG_log("ikev2_evaluate_connection_port_fit found better fit c %s, tsi[%d],tsr[%d]"
+-									, c->name, best_tsi_i, best_tsr_i));
+-						bestfit_p = bfit_p;
+-						bestfit_n = bfit_n;
+-					}
+-				}
+-				else
+-					DBG(DBG_CONTROLMORE, DBG_log("prefix range fit c %s c->name was rejected by port matching"
+-								, c->name));
+-			}
++	tsi_n = ikev2_parse_ts(tsi_pd, tsi, 16);
++	tsr_n = ikev2_parse_ts(tsr_pd, tsr, 16);
+ 
+-			if ( ( bestfit_n > 0 )  && (bestfit_p > 0))  {
+-				DBG(DBG_CONTROLMORE, DBG_log(("found an acceptable TSi/TSr Traffic Selector")));
+-				memcpy (&st->st_ts_this , &tsi[best_tsi_i],  sizeof(struct traffic_selector));
+-				memcpy (&st->st_ts_that , &tsr[best_tsr_i],  sizeof(struct traffic_selector));
+-				ikev2_print_ts(&st->st_ts_this);
+-				ikev2_print_ts(&st->st_ts_that);
+-			}
+-			else {
+-				DBG(DBG_CONTROLMORE, DBG_log(("reject responder TSi/TSr Traffic Selector")));
+-				// prevents parent from going to I3
+-				return STF_FAIL + v2N_TS_UNACCEPTABLE;
+-			}
+-    } /* end of TS check block */
+-
+-		{
+-			v2_notification_t rn;
+-			struct payload_digest *const sa_pd = md->chain[ISAKMP_NEXT_v2SA];
++	/* verify if the received traffic selectors are 
++	 * really same/or a subset of what we sent 
++	 */
++	if(ikev2_verify_ts(tsi, tsr, tsi_n, tsr_n
++			, &st->st_ts_this, &st->st_ts_that
++			, md->role) == FALSE) {
++	/* mistmatch in received selectors */
++	/*only proceeding with parent SA*/
++	delete_event(st);
++	return STF_OK;
++	}
+ 
+-			rn = ikev2_parse_child_sa_body(&sa_pd->pbs, &sa_pd->payload.v2sa,
+-					NULL, st, FALSE);
++    }
+ 
+-			if(rn != v2N_NOTHING_WRONG)
+-				return STF_FAIL + rn;
+-		}
++    {
++	v2_notification_t rn;
++	struct payload_digest *const sa_pd = md->chain[ISAKMP_NEXT_v2SA];
++	
++	rn = ikev2_parse_child_sa_body(&sa_pd->pbs, &sa_pd->payload.v2sa,
++				       NULL, st, FALSE);
++	
++	if(rn != v2N_NOTHING_WRONG)
++	    return STF_FAIL + rn;
++    }
+ 
+     {
+ 	struct payload_digest *p;
+@@ -2196,21 +2197,108 @@ stf_status ikev2parent_inR2(struct msg_digest *md)
+ 
+     } /* notification block */
+ 
+-	
+-    ikev2_derive_child_keys(st, md->role);
++    {
++	/*storing received traffic selectors */
+ 
+-	c->newest_ipsec_sa = st->st_serialno;
++	struct traffic_selector *tmp;
++	unsigned int i=0;
+ 
+-	/* now install child SAs */
+-	if(!install_ipsec_sa(st, TRUE))
+-	   return STF_FATAL;
+ 
+-	/*
+-	 * Delete previous retransmission event.
+-	 */
+-	delete_event(st);
++	ikev2_store_ts_instate(tsi, tsr, tsi_n, tsr_n, &st->st_ts_this, &st->st_ts_that);
+ 
+-	return STF_OK;
++	for(i=0; i< tsi_n; i++) {
++
++            DBG(DBG_CONTROLMORE,
++            {
++                char lbi[ADDRTOT_BUF];
++                char hbi[ADDRTOT_BUF];
++                addrtot(&tsi[i].low,  0, lbi, sizeof(lbi));
++                addrtot(&tsi[i].high, 0, hbi, sizeof(hbi));
++
++                DBG_log("tsi=%s/%s, port=%d/%d, protocol=%d"
++                        ,  lbi, hbi, tsi[i].startport, tsi[i].endport, tsi[i].ipprotoid);
++            }
++            );
++
++	}
++       
++	for(i=0; i< tsr_n; i++) {
++
++            DBG(DBG_CONTROLMORE,
++            {
++                char lbi[ADDRTOT_BUF];
++                char hbi[ADDRTOT_BUF];
++                addrtot(&tsr[i].low,  0, lbi, sizeof(lbi));
++                addrtot(&tsr[i].high, 0, hbi, sizeof(hbi));
++    
++                DBG_log("tsr=%s/%s, port=%d/%d, protocol=%d"
++                        ,  lbi, hbi, tsr[i].startport, tsr[i].endport, tsr[i].ipprotoid);
++            }
++            );
++
++	}
++
++
++	tmp = &st->st_ts_this;
++
++        while(tmp!= NULL) {
++
++            DBG(DBG_CONTROLMORE,
++            {
++                char lbi[ADDRTOT_BUF];
++                char hbi[ADDRTOT_BUF];
++                addrtot(&tmp->low,  0, lbi, sizeof(lbi));
++                addrtot(&tmp->high, 0, hbi, sizeof(hbi));
++
++                DBG_log(" R2  this  tsr=%s/%s, port=%d/%d, protocol=%d"
++                        ,  lbi, hbi, tmp->startport, tmp->endport, tmp->ipprotoid);
++            }
++            );
++
++        tmp=tmp->next;
++        }
++
++        tmp = &st->st_ts_that;
++        while(tmp!= NULL) {
++
++            DBG(DBG_CONTROLMORE,
++            {
++                char lbi[ADDRTOT_BUF];
++                char hbi[ADDRTOT_BUF];
++                addrtot(&tmp->low,  0, lbi, sizeof(lbi));
++                addrtot(&tmp->high, 0, hbi, sizeof(hbi));
++
++                DBG_log(" R2  that  tsr=%s/%s, port=%d/%d, protocol=%d"
++                        ,  lbi, hbi, tmp->startport, tmp->endport, tmp->ipprotoid);
++            }
++            );
++
++        tmp=tmp->next;
++        }
++
++	if(!ikev2_perfect_match_ts(tsi, tsr, tsi_n, tsr_n, c, md->role)) {
++		c = ikev2_create_narrowed_con(c, &st->st_ts_this, &st->st_ts_that, md->role);
++		st->st_connection = c;
++	}
++
++    }
++
++    ikev2_derive_child_keys(st, md->role);
++
++    /* now install child SAs */
++    if(!install_ipsec_sa(st, TRUE))
++	return STF_FATAL;
++
++    st->st_childsa = c;
++    c->newest_ipsec_sa = st->st_serialno;
++    /*
++     * Delete previous retransmission event.
++     */
++    delete_event(st);
++    ikev2_update_counters(md, response_recd);
++
++    return STF_OK;
++    
+ }
+ 
+ /*
+@@ -2317,7 +2405,7 @@ send_v2_notification(struct state *p1st, u_int16_t type
+ 	n_hdr.isa_np = ISAKMP_NEXT_v2N;
+ 	n_hdr.isa_flags &= ~ISAKMP_FLAGS_I;
+ 	n_hdr.isa_flags  |=  ISAKMP_FLAGS_R;
+-#warning check msgid code here
++
+ 	// PAUL: shouldn't we set n_hdr.isa_msgid = [htonl](p1st->st_msgid);
+ 	if (!out_struct(&n_hdr, &isakmp_hdr_desc, &reply, &rbody)) 
+ 	{
+@@ -2409,15 +2497,15 @@ stf_status process_informational_ikev2(struct msg_digest *md)
+     {
+ 	stf_status ret; 
+ 
+-	if(md->hdr.isa_flags & ISAKMP_FLAGS_I) {
++	if(!(md->hdr.isa_flags & ISAKMP_FLAGS_R)) {
+ 	DBG(DBG_CONTROLMORE
+-		, DBG_log("received informational exchange request from INITIATOR"));
+-	ret = ikev2_decrypt_msg(md, RESPONDER);
++		, DBG_log("received informational exchange request from %s", md->role == 1? "RESPONDER": "INITIATOR"));
++	ret = ikev2_decrypt_msg(md, md->role);
+ 	}
+ 	else {
+ 	DBG(DBG_CONTROLMORE
+-		, DBG_log("received informational exchange request from RESPONDER"));
+-	ret = ikev2_decrypt_msg(md, INITIATOR);
++		, DBG_log("received informational exchange response from %s", md->role == 1?"RESPONDER": "INITIATOR"));
++	ret = ikev2_decrypt_msg(md, md->role);
+ 	}
+ 
+ 	if(ret != STF_OK) return ret;
+@@ -2439,13 +2527,13 @@ stf_status process_informational_ikev2(struct msg_digest *md)
+ 	int            ivsize;
+ 	unsigned char *encstart;
+ 
+-	/* beginning of data going out */
+-	authstart = reply_stream.cur;
+-
+ 	/* make sure HDR is at start of a clean buffer */
+ 	zero(reply_buffer);
+ 	init_pbs(&reply_stream, reply_buffer, sizeof(reply_buffer), "information exchange reply packet");
+ 
++	/* beginning of data going out */
++	authstart = reply_stream.cur;
++
+ 	/* HDR out */
+ 	{
+ 		struct isakmp_hdr r_hdr ;
+@@ -2645,7 +2733,7 @@ stf_status process_informational_ikev2(struct msg_digest *md)
+ 	close_output_pbs(&md->rbody);
+ 	close_output_pbs(&reply_stream);
+ 
+-	ret = ikev2_encrypt_msg(md, RESPONDER,
++	ret = ikev2_encrypt_msg(md, md->role,
+                                     authstart,
+                                     iv, encstart, authloc,
+                                     &e_pbs, &e_pbs_cipher);
+@@ -2662,14 +2750,19 @@ stf_status process_informational_ikev2(struct msg_digest *md)
+ 			, "reply packet for informational exchange");
+ 
+ 	send_packet(st, __FUNCTION__, TRUE);
++	ikev2_update_counters(md, response_sent);
+ 	}
+ 
+ 	/* Now carry out the actualy task, we can not carry the actual task since 
+  	* we need to send informational responde using existig SAs
+  	*/
+ 
++	if(md->hdr.isa_flags & ISAKMP_FLAGS_R){
++		ikev2_update_counters(md, response_recd);
++	}
++
+ 	{
+-		if(md->chain[ISAKMP_NEXT_v2D] && st->st_state != STATE_IKESA_DEL) {
++		if(md->chain[ISAKMP_NEXT_v2D]) {
+ 
+ 		for(p = md->chain[ISAKMP_NEXT_v2D]; p!=NULL; p = p->next) {
+ 		v2del = &p->payload.v2delete;
+@@ -2704,6 +2797,8 @@ stf_status process_informational_ikev2(struct msg_digest *md)
+ 					else
+ 					{
+ 						change_state(current_st, STATE_IKESA_DEL);
++						md->st = NULL;
++						md->pst = NULL;
+ 					}
+         			delete_state(current_st);
+ 				current_st = next_st;
+@@ -2714,8 +2809,6 @@ stf_status process_informational_ikev2(struct msg_digest *md)
+ 			case PROTO_IPSEC_AH:
+ 			case PROTO_IPSEC_ESP:
+ 				{				
+-				//pb_stream del_pbs;
+-				struct ikev2_delete;
+ 				u_int16_t i;
+ 				u_char *spi;
+ 
+@@ -2796,6 +2889,8 @@ stf_status process_informational_ikev2(struct msg_digest *md)
+ 					else
+ 					{
+ 						change_state(current_st, STATE_IKESA_DEL);
++						md->st = NULL;
++						md->pst = NULL;
+ 					}
+         			delete_state(current_st);
+ 				current_st = next_st;
+@@ -2853,12 +2948,14 @@ void ikev2_delete_out(struct state *st)
+ 	md.st = st;
+ 	md.pst= pst;
+ 	/* beginning of data going out */
+-	authstart = reply_stream.cur;
+ 
+ 	/* make sure HDR is at start of a clean buffer */
+ 	zero(reply_buffer);
+ 	init_pbs(&reply_stream, reply_buffer, sizeof(reply_buffer), "information exchange request packet");
+ 
++	/* beginning of data going out */
++        authstart = reply_stream.cur;
++
+ 	/* HDR out */
+ 	{
+ 		struct isakmp_hdr r_hdr ;
+@@ -2868,7 +2965,7 @@ void ikev2_delete_out(struct state *st)
+ 		memcpy(r_hdr.isa_icookie, pst->st_icookie, COOKIE_SIZE);
+ 		r_hdr.isa_xchg = ISAKMP_v2_INFORMATIONAL;
+ 		r_hdr.isa_np = ISAKMP_NEXT_v2E;
+-		r_hdr.isa_msgid = htonl(pst->st_msgid_nextuse);
++		r_hdr.isa_msgid = htonl(pst->st_msgid_last_localreq == INVALID_MSGID? 0 : pst->st_msgid_last_localreq + 1);
+ 
+ 		/*set initiator bit if we are initiator*/
+ 		if(pst->st_state == STATE_PARENT_I2 || pst->st_state == STATE_PARENT_I3) {
+@@ -2879,8 +2976,6 @@ void ikev2_delete_out(struct state *st)
+ 		role = RESPONDER;
+ 		}
+ 
+-		//r_hdr.isa_flags  |=  ISAKMP_FLAGS_R;
+-
+ 		if (!out_struct(&r_hdr, &isakmp_hdr_desc, &reply_stream, &rbody))
+ 		{
+ 			openswan_log("error initializing hdr for informational message");
+@@ -2916,9 +3011,6 @@ void ikev2_delete_out(struct state *st)
+ 				{
+ 				pb_stream del_pbs;
+ 				struct ikev2_delete v2del_tmp;
+-				//u_int16_t i, j=0;
+-				//u_char *spi;
+-				//char spi_buf[1024];
+ 
+ 				zero(&v2del_tmp);
+ 				v2del_tmp.isad_np = ISAKMP_NEXT_NONE;
+@@ -2984,7 +3076,7 @@ void ikev2_delete_out(struct state *st)
+ 	send_packet(pst, __FUNCTION__, TRUE);
+ 
+ 	/* update state */
+-	ikev2_update_counters(&md);
++	ikev2_update_counters(&md, req_sent);
+ 
+ 	}
+ 	
+diff --git a/programs/pluto/kernel.c b/programs/pluto/kernel.c
+index 70d49ed..c8c8db8 100644
+--- a/programs/pluto/kernel.c
++++ b/programs/pluto/kernel.c
+@@ -2028,6 +2028,31 @@ setup_half_ipsec_sa(struct state *st, bool inbound)
+ 			      , st->st_connection->policy_label
+ #endif
+ 			      );
++
++	if(st->st_ikev2) {
++	   struct spd_route *sr = &c->spd;
++	   for(sr = sr->next; sr != NULL; sr = sr->next) {
++
++            /* MCR - should be passed a spd_eroute structure here */
++            (void) raw_eroute(&sr->that.host_addr   /* this_host */
++			      , &sr->that.client    /* this_client */
++                              , &sr->this.host_addr /* that_host */
++			      , &sr->this.client    /* that_client */
++                              , inner_spi              /* spi */
++			      , proto                  /* proto */
++                              , sr->this.protocol   /* transport_proto */
++                              , esatype                /* esatype */
++                              , proto_info             /* " */
++			      , 0                      /* lifetime */
++                              , ERO_ADD_INBOUND        /* op */
++			      , "add inbound"        /* opname */
++#ifdef HAVE_LABELED_IPSEC
++			      , st->st_connection->policy_label
++#endif
++			      );
++	   }
++	}
++
+         }
+     }
+ 
+@@ -2103,6 +2128,7 @@ teardown_half_ipsec_sa(struct state *st, bool inbound)
+      * first one found.  It may or may not be the only one.
+      */
+     struct connection *c = st->st_connection;
++    struct spd_route *sr;
+     struct {
+         unsigned proto;
+         struct ipsec_proto_info *info;
+@@ -2128,6 +2154,30 @@ teardown_half_ipsec_sa(struct state *st, bool inbound)
+ 			  );
+     }
+ 
++    if(st->st_ikev2) {
++    for(sr = &c->spd.next; sr; sr =sr->next) {
++    if (kernel_ops->inbound_eroute && inbound
++        && sr->eroute_owner == SOS_NOBODY)
++    {
++        (void) raw_eroute(&sr->that.host_addr, &sr->that.client
++                          , &sr->this.host_addr, &sr->this.client
++                          , 256
++			  , IPSEC_PROTO_ANY
++                          , sr->this.protocol
++                          , ET_UNSPEC
++                          , null_proto_info, 0
++                          , ERO_DEL_INBOUND, "delete inbound"
++#ifdef HAVE_LABELED_IPSEC
++			  , c->policy_label
++#endif
++			  );
++    }
++    }
++    }
++
++
++
++
+     if (!kernel_ops->grp_sa)
+     {
+         if (st->st_ah.present)
+diff --git a/programs/pluto/state.c b/programs/pluto/state.c
+index bc89489..47dd189 100644
+--- a/programs/pluto/state.c
++++ b/programs/pluto/state.c
+@@ -347,6 +347,19 @@ release_whack(struct state *st)
+     close_any(st->st_whack_sock);
+ }
+ 
++/* freeing allocated traffic selectors */
++static void delete_ts(struct traffic_selector *ts) {
++	struct traffic_selector *tmp;
++
++	/*first one is not malloced so skiping that*/
++	ts = ts-> next;
++	while(ts!=NULL) {
++		tmp = ts->next;
++		pfreeany(ts);
++		ts = tmp;
++	}
++}
++
+ /* delete a state object */
+ void
+ delete_state(struct state *st)
+@@ -354,8 +367,60 @@ delete_state(struct state *st)
+     struct connection *const c = st->st_connection;
+     struct state *old_cur_state = cur_state == st? NULL : cur_state;
+ 
+-    DBG(DBG_CONTROL, DBG_log("deleting state #%lu", st->st_serialno));
++    if(st->st_ikev2)
++    {
++    /* child sa*/
++    if(st->st_clonedfrom != 0) 
++    {
++	DBG(DBG_CONTROL, DBG_log("received request to delete child state"));
++	if(st->st_state == STATE_CHILDSA_DEL) {
++		DBG(DBG_CONTROL, DBG_log("now deleting the child state"));
++	}
++	else
++	{
++		/* Only send request if child sa is established
++		 * otherwise continue with deletion
++		 */ 
++		if(IS_CHILD_SA_ESTABLISHED(st)) 
++		{
++		DBG(DBG_CONTROL, DBG_log("sending Child SA delete equest"));
++		//change_state(st, STATE_CHILDSA_DEL);
++		send_delete(st);
++		change_state(st, STATE_CHILDSA_DEL);
++		/* actual deletion when we receive peer response*/
++		goto delete_state_end;
++		}
++	}
++    }
++    else 
++    {
++	DBG(DBG_CONTROL, DBG_log("received request to delete IKE parent state"));
++	/* parent sa */
++	if(st->st_state == STATE_IKESA_DEL)
++	{
++		DBG(DBG_CONTROL, DBG_log("now deleting the IKE (or parent) state"));
++	}
++	else
++	{
++		/* Another check to verify if a secured
++		 * INFORMATIONAL exchange can be sent or not 
++		 */
++		if(st->st_skey_ei.ptr && st->st_skey_ai.ptr 
++			&& st->st_skey_er.ptr && st->st_skey_ar.ptr)
++		{
++		DBG(DBG_CONTROL, DBG_log("sending IKE SA delete request"));
++		//change_state(st, STATE_IKESA_DEL);
++		send_delete(st);
++		change_state(st, STATE_IKESA_DEL);
++		/* actual deletion when we receive peer response*/
++                goto delete_state_end;
++		}
++	}
++
++    }
++    }
+ 
++    DBG(DBG_CONTROL, DBG_log("deleting state #%lu", st->st_serialno));
+ 
+     /* If DPD is enabled on this state object, clear any pending events */
+     if(st->st_dpd_event != NULL)
+@@ -455,6 +520,10 @@ delete_state(struct state *st)
+ 	pfreeany(st->st_sec_chunk.ptr);
+     }
+ 
++    /*free selectors if any */
++    delete_ts(&st->st_ts_this);
++    delete_ts(&st->st_ts_that);
++
+     freeanychunk(st->st_firstpacket_me);
+     freeanychunk(st->st_firstpacket_him);
+     freeanychunk(st->st_tpacket);
+@@ -506,6 +575,9 @@ delete_state(struct state *st)
+     pfreeany(st->sec_ctx);
+ #endif
+     pfree(st);
++
++delete_state_end:;
++
+ }
+ 
+ /*
+@@ -596,6 +668,9 @@ static void delete_state_function(struct state *this
+ 		 , enum_show(&state_names, this->st_state));
+ 
+     if(this->st_event != NULL) delete_event(this);
++    if(this->st_ikev2) {
++	this->st_state = this->st_clonedfrom ? STATE_CHILDSA_DEL : STATE_IKESA_DEL;
++    }
+     delete_state(this);
+ }
+ 
+diff --git a/programs/pluto/state.h b/programs/pluto/state.h
+index 80be846..5104adf 100644
+--- a/programs/pluto/state.h
++++ b/programs/pluto/state.h
+@@ -165,6 +165,7 @@ struct traffic_selector {
+     u_int16_t endport;
+     ip_address low;
+     ip_address high;
++    struct traffic_selector *next;
+ };
+ 
+ #ifdef HAVE_LABELED_IPSEC
+@@ -250,12 +251,13 @@ struct state
+     struct msgid_list  *st_used_msgids;        /* used-up msgids */
+ 
+     /* IKEv2 things */
+-    /* message ID sequence for things we send (as initiator) */
+-    msgid_t            st_msgid_lastack;       /* last one peer acknowledged */
+-    msgid_t            st_msgid_nextuse;       /* next one to use */
++    /* message ID sequence for things we send (as request) */
++    msgid_t            st_msgid_last_localreq;       /* last one sent as request by us */
++    msgid_t            st_msgid_last_localreq_ack;       /* last one sent acked by peer */
+ 
+-    /* message ID sequence for things we receive (as responder) */
+-    msgid_t            st_msgid_lastrecv;      /* last one peer sent */
++
++    /* message ID sequence for things we receive (as response) */
++   msgid_t            st_msgid_last_remotereq;       /* last remote request sent by peer */
+ 
+ 
+     /* symmetric stuff */
diff --git a/openswan-ipsec-help-524146-509318.patch b/openswan-ipsec-help-524146-509318.patch
index a4ed01d..102b400 100644
--- a/openswan-ipsec-help-524146-509318.patch
+++ b/openswan-ipsec-help-524146-509318.patch
@@ -1,6 +1,13 @@
-diff -urNp openswan-2.6.38-patched/programs/ipsec/ipsec.in openswan-2.6.38-current/programs/ipsec/ipsec.in
---- openswan-2.6.38-patched/programs/ipsec/ipsec.in	2012-05-14 15:17:33.563272378 -0400
-+++ openswan-2.6.38-current/programs/ipsec/ipsec.in	2012-05-14 15:20:50.952267555 -0400
+From 1bdb95de068810c49d35d3b5681b20eccaf9a40f Mon Sep 17 00:00:00 2001
+From: Avesh Agarwal <avagarwa at redhat.com>
+Date: Thu, 29 Sep 2011 16:18:16 -0400
+Subject: openswan-ipsec-help-524146-509318.patch
+
+
+diff --git a/programs/ipsec/ipsec.in b/programs/ipsec/ipsec.in
+index b8e9d4e..4f73ab1 100755
+--- a/programs/ipsec/ipsec.in
++++ b/programs/ipsec/ipsec.in
 @@ -80,9 +80,9 @@ case "$1" in
  --help)
  	echo "Usage: ipsec command argument ..."
diff --git a/openswan-labeled-ipsec.patch b/openswan-labeled-ipsec.patch
new file mode 100644
index 0000000..a6771c0
--- /dev/null
+++ b/openswan-labeled-ipsec.patch
@@ -0,0 +1,115 @@
+From 41aa84182b0291533745da59beb26bcce80d56a8 Mon Sep 17 00:00:00 2001
+From: Avesh Agarwal <avagarwa at redhat.com>
+Date: Fri, 9 Mar 2012 16:50:05 -0500
+Subject: =?UTF-8?q?Changes=20related=20to=20bz#703985=20not=20merged=20upstr?=
+ =?UTF-8?q?eam.=20Also=20this=20commit=20has=0Asome=20misc=20(not=20necessar?=
+ =?UTF-8?q?y)=20labeled=20ipsec=20changes.?=
+
+
+diff --git a/lib/libipsecconf/confread.c b/lib/libipsecconf/confread.c
+index 6070f3f..4fc6096 100644
+--- a/lib/libipsecconf/confread.c
++++ b/lib/libipsecconf/confread.c
+@@ -1356,6 +1356,9 @@ static void confread_free_conn(struct starter_conn *conn)
+ 
+ 	FREE_STR(conn->connalias);
+ 	FREE_STR(conn->name);
++//#ifdef HAVE_LABELED_IPSEC
++//	FREE_STR(conn->policy_label);
++//#endif
+ 
+ #ifdef ALG_PATCH
+ 	FREE_STR(conn->esp);
+diff --git a/lib/libipsecconf/oeconns.c b/lib/libipsecconf/oeconns.c
+index 72e1a84..c94da0e 100644
+--- a/lib/libipsecconf/oeconns.c
++++ b/lib/libipsecconf/oeconns.c
+@@ -524,6 +524,9 @@ void add_any_oeconns(struct starter_config *cfg,
+ 			conn->right= tconn->right;
+ 			conn->esp  = tconn->esp;
+ 			conn->ike  = tconn->ike;
++//#ifdef HAVE_LABELED_IPSEC
++//			conn->policy_label = tconn->policy_label;
++//#endif
+ 			conn->desired_state = tconn->desired_state;
+ 			conn->policy = tconn->policy;
+ 			conn->state = STATE_LOADED;
+diff --git a/lib/libipsecconf/starterwhack.c b/lib/libipsecconf/starterwhack.c
+index d6ff9f7..73aa6f0 100644
+--- a/lib/libipsecconf/starterwhack.c
++++ b/lib/libipsecconf/starterwhack.c
+@@ -547,12 +547,15 @@ static int starter_whack_basic_add_conn(struct starter_config *cfg
+ 	if(conn->options_set[KBF_LOOPBACK]) {
+ 		msg.loopback=conn->options[KBF_LOOPBACK];
+ 	}
++	starter_log(LOG_LEVEL_INFO, "conn: \"%s\" loopback=%d", conn->name, msg.loopback);
+ 
+         if(conn->options_set[KBF_LABELED_IPSEC]) {
+                 msg.labeled_ipsec=conn->options[KBF_LABELED_IPSEC];
+         }
++	starter_log(LOG_LEVEL_INFO, "conn: \"%s\" labeled_ipsec=%d", conn->name, msg.labeled_ipsec);
+ 
+ 	msg.policy_label = conn->policy_label;
++	starter_log(LOG_LEVEL_INFO, "conn: \"%s\" policy_label=%d", conn->name, msg.policy_label);
+ #endif
+ 
+ 	set_whack_end(cfg, "left",  &msg.left, &conn->left);
+diff --git a/programs/pluto/initiate.c b/programs/pluto/initiate.c
+index 658887c..dd186e6 100644
+--- a/programs/pluto/initiate.c
++++ b/programs/pluto/initiate.c
+@@ -776,19 +776,17 @@ initiate_ondemand_body(struct find_oppo_bundle *b
+ 
+ 
+ #ifdef HAVE_LABELED_IPSEC
+-    char sec_ctx_value[256];
++    char sec_ctx_value[MAX_SECCTX_LEN];
+     memset(sec_ctx_value, 0, sizeof(sec_ctx_value)); 
+     if(uctx != NULL) {
+     memcpy(sec_ctx_value, uctx->sec_ctx_value, uctx->ctx_len);
+     }
+-    snprintf(demandbuf, 256, "initiate on demand from %s:%d to %s:%d proto=%d state: %s because: %s with security context %s"
+-             , ours, ourport, his, hisport, b->transport_proto
+-             , oppo_step_name[b->step], b->want, sec_ctx_value);
+-#else
++    DBG(DBG_CONTROLMORE, DBG_log("received security label string: %s", sec_ctx_value)); 
++#endif
++
+     snprintf(demandbuf, 256, "initiate on demand from %s:%d to %s:%d proto=%d state: %s because: %s"
+ 	     , ours, ourport, his, hisport, b->transport_proto
+ 	     , oppo_step_name[b->step], b->want);
+-#endif
+     
+     if(DBGP(DBG_OPPOINFO)) {
+ 	openswan_log("%s", demandbuf);
+diff --git a/programs/pluto/spdb_v1_struct.c b/programs/pluto/spdb_v1_struct.c
+index 77427b2..97faf35 100644
+--- a/programs/pluto/spdb_v1_struct.c
++++ b/programs/pluto/spdb_v1_struct.c
+@@ -105,11 +105,22 @@ parse_secctx_attr (pb_stream *pbs, struct state *st)
+ 			return FALSE;
+ 		}
+ 
+-		/* reading security label*/
+-		memcpy(sec_ctx_value, pbs->cur, pbs_left(pbs) <= MAX_SECCTX_LEN ? pbs_left(pbs) : MAX_SECCTX_LEN);
+-		i = pbs_left(pbs) <= MAX_SECCTX_LEN ? pbs_left(pbs) : MAX_SECCTX_LEN;
++		/*do not process security labels longer than MAX_SECCTX_LEN*/
++                if(pbs_left(pbs) > MAX_SECCTX_LEN) {
++                        DBG(DBG_PARSING, DBG_log("received security ctx longer than MAX_SECCTX_LEN which is not supported"));
++			return FALSE;
++                }
+ 
+-		/* checking if the received security label contains \0 */
++		/* reading security label*/
++		//memcpy(sec_ctx_value, pbs->cur, pbs_left(pbs) <= MAX_SECCTX_LEN ? pbs_left(pbs) : MAX_SECCTX_LEN);
++		//i = pbs_left(pbs) <= MAX_SECCTX_LEN ? pbs_left(pbs) : MAX_SECCTX_LEN;
++		memcpy(sec_ctx_value, pbs->cur, pbs_left(pbs));
++		i = pbs_left(pbs);
++
++		/* checking if the received security label contains \0,
++		 * We expect received label to have '\0', however to be
++		 * compliant with implementations that dont send \0 
++		 * we can include \0 if there is space left in the buffer.*/
+ 		if( sec_ctx_value[i-1] != '\0') {
+ 			/*check if we have space left and then append \0*/
+ 			if (i < MAX_SECCTX_LEN) {
diff --git a/openswan-updown-netkey.patch b/openswan-updown-netkey.patch
new file mode 100644
index 0000000..74dd113
--- /dev/null
+++ b/openswan-updown-netkey.patch
@@ -0,0 +1,83 @@
+From 4ed4ff4391a100ba8bee37cd50341accbe4aca9f Mon Sep 17 00:00:00 2001
+From: Avesh Agarwal <avagarwa at redhat.com>
+Date: Tue, 7 Aug 2012 13:28:33 -0400
+Subject: =?UTF-8?q?Fixes=20to=20interop=20issues=20(related=20to=20updating/?=
+ =?UTF-8?q?rempoving=20local=20interface=20with=0Aremote=20ip=20address=20an?=
+ =?UTF-8?q?d=20removing=20local=20routes)=20between=20cisco=20ASA=20and=20op?=
+ =?UTF-8?q?enswan.?=
+
+
+diff --git a/programs/_updown.netkey/_updown.netkey.in b/programs/_updown.netkey/_updown.netkey.in
+index bb182bf..155750e 100644
+--- a/programs/_updown.netkey/_updown.netkey.in
++++ b/programs/_updown.netkey/_updown.netkey.in
+@@ -188,6 +188,14 @@ downroute() {
+     ip route flush cache
+ }
+ 
++downrule() {
++        if [ -n "$PLUTO_MY_SOURCEIP" ]
++        then
++            doroute del
++            ip route flush cache
++        fi
++}
++
+ updateresolvconf() {
+     if [ -n "$PLUTO_CISCO_DNS_INFO" ]; then
+ 	if [ -n "`pidof unbound`" -a -n "$PLUTO_CISCO_DOMAIN_INFO"  ]; then
+@@ -316,7 +324,12 @@ addsource() {
+     st=0
+     # check if given sourceip is local and add as alias if not
+     if ! ip -o route get ${PLUTO_MY_SOURCEIP%/*} | grep -q ^local; then
++
++	if [ -z "$PLUTO_IS_PEER_CISCO" -o "$PLUTO_IS_PEER_CISCO" = 0 ]; then
+ 	it="ip addr add ${PLUTO_MY_SOURCEIP%/*}/32 dev ${PLUTO_INTERFACE%:*}"
++	else
++	it="ip addr add ${PLUTO_MY_SOURCEIP%/*}/${PLUTO_PEER_CLIENT##*/} dev ${PLUTO_INTERFACE%:*}"
++	fi
+ 	oops="`eval $it 2>&1`"
+ 	st=$?
+ 	if [ " $oops" = " " -a " $st" != " 0" ]; then
+@@ -341,15 +354,7 @@ delsource() {
+     st=0
+     # check if given sourceip is local and add as alias if not
+     if  ip -o route get ${PLUTO_MY_SOURCEIP%/*} | grep -q ^local; then
+-        #it="ip addr del ${PLUTO_MY_SOURCEIP%/*}/32 label ${PLUTO_INTERFACE%:*}:1 dev ${PLUTO_INTERFACE%:*}"
+-
+-                saddr=${PLUTO_MY_SOURCEIP%/*}/32
+-                if test "${PLUTO_PEER_CLIENT##*/}" != 32
+-                then
+-                saddr=${PLUTO_MY_SOURCEIP%/*}/"${PLUTO_PEER_CLIENT##*/}"
+-                fi
+-
+-        it="ip addr del ${saddr} dev ${PLUTO_INTERFACE%:*}"
++        it="ip addr del ${PLUTO_MY_SOURCEIP%/*}/${PLUTO_PEER_CLIENT##*/} dev ${PLUTO_INTERFACE%:*}"
+ 
+         oops="`eval $it 2>&1`"
+         st=$?
+@@ -365,7 +370,7 @@ delsource() {
+                 ;;
+         esac
+         if [ " $oops" != " " -o " $st" != " 0" ]; then
+-            echo "$0: addsource \`$it' failed ($oops)" >&2
++            echo "$0: delsource \`$it' failed ($oops)" >&2
+         fi
+     fi
+     return $st
+@@ -457,6 +462,7 @@ case "$PLUTO_VERB" in
+ 	;;
+     down-host)
+ 	# connection to me going down
++	downrule
+ 	# If you are doing a custom version, firewall commands go here.
+ 	;;
+     up-client)
+@@ -465,6 +471,7 @@ case "$PLUTO_VERB" in
+ 	;;
+     down-client)
+ 	# connection to my client subnet going down
++	downrule
+ 	# If you are doing a custom version, firewall commands go here.
+ 	;;
+     updateresolvconf-host|updateresolvconf-client)
diff --git a/openswan.spec b/openswan.spec
index a255f4a..f0362bc 100644
--- a/openswan.spec
+++ b/openswan.spec
@@ -10,7 +10,7 @@ Summary: IPSEC implementation with IKEv1 and IKEv2 keying protocols
 Name: openswan
 Version: 2.6.38
 
-Release: 2%{?dist}
+Release: 3%{?dist}
 License: GPLv2+
 Url: http://www.openswan.org/
 Source: openswan-%{version}.tar.gz
@@ -20,7 +20,17 @@ Source3: README.x509
 
 Patch1: openswan-2.6-relpath.patch
 Patch2: openswan-ipsec-help-524146-509318.patch
-Patch3: openswan-cisco-issues.patch
+Patch3: openswan-cisco-aggr-mode.patch
+Patch4: openswan-ikev2.patch
+Patch5: reading-password-from-a-file-when-creating-keys.patch
+Patch6: rhbz-609343.patch
+Patch7: openswan-labeled-ipsec.patch
+Patch8: openswan-ikev1-ikev2-sha256.patch
+Patch9: openswan-ikev1-ikev2-sha384-512.patch
+Patch10: openswan-ikev1-aes-gcm-esp-fixes.patch
+Patch11: rhbz-831676.patch
+Patch12: rhbz-841325.patch
+Patch13: openswan-updown-netkey.patch
 
 Group: System Environment/Daemons
 BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
@@ -85,6 +95,16 @@ install -m 644 %{SOURCE3} docs/README.x509
 %patch1 -p1 -b .relpath
 %patch2 -p1
 %patch3 -p1
+%patch4 -p1
+%patch5 -p1
+%patch6 -p1
+%patch7 -p1
+%patch8 -p1
+%patch9 -p1
+%patch10 -p1
+%patch11 -p1
+%patch12 -p1
+%patch13 -p1
 
 %build
 
@@ -209,6 +229,18 @@ fi
 chkconfig --add ipsec || :
 
 %changelog
+* Tue Aug 7 2012 Avesh Agarwal <avagarwa at redhat.com> - 2.6.38-3
+- Ikev2 changes from rhel6 to fedora
+- Sha256 changes from rhel6 to fedora
+- Fixed 384/512 changes from rhel6 to fedora
+- Ported cisco-openswan interop changes in aggresive/main mode
+- Labeld-ipsec fixes
+- aes-gcm fixes in ikev1 mode
+- updown netkey script changes related to updating/removing 
+  interface ip address and routes
+- Fixes related to rhbz 609343
+- Fixes related to rhbz 831676
+
 * Fri Jul 20 2012 Fedora Release Engineering <rel-eng at lists.fedoraproject.org> - 2.6.38-2
 - Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild
 
diff --git a/reading-password-from-a-file-when-creating-keys.patch b/reading-password-from-a-file-when-creating-keys.patch
new file mode 100644
index 0000000..6bfe7c8
--- /dev/null
+++ b/reading-password-from-a-file-when-creating-keys.patch
@@ -0,0 +1,19 @@
+From bd631c2947f1e9aefd77c6d9fb92230f4c0f5864 Mon Sep 17 00:00:00 2001
+From: Avesh Agarwal <avagarwa at redhat.com>
+Date: Fri, 30 Sep 2011 16:43:39 -0400
+Subject: Reading password from a file when creating keys.
+
+
+diff --git a/programs/rsasigkey/rsasigkey.c b/programs/rsasigkey/rsasigkey.c
+index 94b77d6..2dd7e6b 100644
+--- a/programs/rsasigkey/rsasigkey.c
++++ b/programs/rsasigkey/rsasigkey.c
+@@ -564,7 +564,7 @@ rsasigkey(int nbits, char *configdir, char *password)
+     mpz_init(n);
+     mpz_init(e);
+ 
+-    pwdata.source = password ? PW_PLAINTEXT : PW_NONE;
++    pwdata.source = password ? (strcmp(password, "/etc/ipsec.d/nsspassword")? PW_PLAINTEXT: PW_FROMFILE) : PW_NONE;
+     pwdata.data = password ? password : NULL;
+ 
+     do {
diff --git a/rhbz-609343.patch b/rhbz-609343.patch
new file mode 100644
index 0000000..1d14e31
--- /dev/null
+++ b/rhbz-609343.patch
@@ -0,0 +1,32 @@
+From 0e88f1f2b7959c26a2c05ddd2b756c8b106124fe Mon Sep 17 00:00:00 2001
+From: Avesh Agarwal <avagarwa at redhat.com>
+Date: Fri, 21 Oct 2011 16:33:37 -0400
+Subject: rhbz#609343: pluto crashes when removing logical interface
+
+
+diff --git a/programs/pluto/hostpair.c b/programs/pluto/hostpair.c
+index 4d13e29..1c0bf68 100644
+--- a/programs/pluto/hostpair.c
++++ b/programs/pluto/hostpair.c
+@@ -299,7 +299,8 @@ release_dead_interfaces(void)
+ 		     * move it to the unoriented_connections list.
+ 		     */
+ 		    passert(p == *pp);
+-
++		    
++		    terminate_connection(p->name);
+ 		    p->interface = NULL;
+ 
+ 		    *pp = p->hp_next;	/* advance *pp */
+diff --git a/programs/pluto/initiate.c b/programs/pluto/initiate.c
+index 94ce4f4..658887c 100644
+--- a/programs/pluto/initiate.c
++++ b/programs/pluto/initiate.c
+@@ -133,6 +133,7 @@ orient(struct connection *c)
+ 			    else
+ 				loglog(RC_LOG_SERIOUS, "two interfaces match \"%s\" (%s, %s)"
+ 				       , c->name, c->interface->ip_dev->id_rname, p->ip_dev->id_rname);
++			    terminate_connection(c->name);
+ 			    c->interface = NULL;	/* withdraw orientation */
+ 			    return FALSE;
+ 			}
diff --git a/rhbz-831676.patch b/rhbz-831676.patch
new file mode 100644
index 0000000..782bec6
--- /dev/null
+++ b/rhbz-831676.patch
@@ -0,0 +1,107 @@
+From 863e5dbb482fb82f035c3e17f7d5983c4bc72c63 Mon Sep 17 00:00:00 2001
+From: Avesh Agarwal <avagarwa at redhat.com>
+Date: Fri, 3 Aug 2012 14:53:16 -0400
+Subject: rhbz #831676
+
+Openswan does not pass traffic selectors information in transport mode.
+These fixes avoids loopback (same addresses scenarios).
+
+diff --git a/programs/pluto/kernel.c b/programs/pluto/kernel.c
+index 9924078..eb539bf 100644
+--- a/programs/pluto/kernel.c
++++ b/programs/pluto/kernel.c
+@@ -1438,6 +1438,7 @@ setup_half_ipsec_sa(struct state *st, bool inbound)
+         said_next->dst = &dst.addr;
+         said_next->src_client = &src_client;
+         said_next->dst_client = &dst_client;
++        said_next->transport_proto = c->spd.this.protocol;
+         said_next->spi = ipip_spi;
+         said_next->esatype = ET_IPIP;
+         said_next->text_said = text_said;
+@@ -1530,6 +1531,7 @@ setup_half_ipsec_sa(struct state *st, bool inbound)
+         said_next->dst = &dst.addr;
+         said_next->src_client = &src_client;
+         said_next->dst_client = &dst_client;
++        said_next->transport_proto = c->spd.this.protocol;
+         said_next->spi = ipcomp_spi;
+         said_next->esatype = ET_IPCOMP;
+         said_next->encalg = compalg;
+@@ -1742,6 +1744,7 @@ setup_half_ipsec_sa(struct state *st, bool inbound)
+         said_next->dst = &dst.addr;
+         said_next->src_client = &src_client;
+         said_next->dst_client = &dst_client;
++        said_next->transport_proto = c->spd.this.protocol;
+         said_next->spi = esp_spi;
+         said_next->esatype = ET_ESP;
+         said_next->replay_window = kernel_ops->replay_window;
+@@ -1900,6 +1903,7 @@ setup_half_ipsec_sa(struct state *st, bool inbound)
+         said_next->dst = &dst.addr;
+         said_next->src_client = &src_client;
+         said_next->dst_client = &dst_client;
++        said_next->transport_proto = c->spd.this.protocol;
+         said_next->spi = ah_spi;
+         said_next->esatype = ET_AH;
+         said_next->replay_window = kernel_ops->replay_window;
+diff --git a/programs/pluto/kernel.h b/programs/pluto/kernel.h
+index 772ba14..b843682 100644
+--- a/programs/pluto/kernel.h
++++ b/programs/pluto/kernel.h
+@@ -79,6 +79,7 @@ struct kernel_sa {
+ 
+ 	ipsec_spi_t spi;
+ 	unsigned proto;
++	unsigned int transport_proto;
+ 	enum eroute_type esatype;
+ 	unsigned replay_window;
+ 	unsigned reqid;
+diff --git a/programs/pluto/kernel_netlink.c b/programs/pluto/kernel_netlink.c
+index 895607c..351b0eb 100644
+--- a/programs/pluto/kernel_netlink.c
++++ b/programs/pluto/kernel_netlink.c
+@@ -818,6 +818,46 @@ netlink_add_sa(struct kernel_sa *sa, bool replace)
+     else
+     {
+ 	req.p.mode = XFRM_MODE_TRANSPORT;
++
++	if(!sameaddr(sa->src, sa->dst)) {
++	req.p.sel.sport = portof(&sa->src_client->addr);
++	req.p.sel.dport = portof(&sa->dst_client->addr);
++
++	/* As per RFC 4301/5996, icmp type is put in the most significant 8 bits
++	* and icmp code is in the least significant 8 bits of port field. 
++	* Although Openswan does not have any configuration options for 
++	* icmp type/code values, it is possible to specify icmp type and code 
++	* using protoport option. For example, icmp echo request (type 8/code 0) 
++	* needs to be encoded as 0x0800 in the port field and can be specified 
++	* as left/rightprotoport=icmp/2048. Now with NETKEY, icmp type and code
++	* need to be passed as source and destination ports, respectively.
++	* therefore, this code extracts upper 8 bits and lower 8 bits and puts
++	* into source and destination ports before passing to NETKEY. */
++
++
++	if( 1 == sa->transport_proto /*icmp*/ || 58 == sa->transport_proto /*ipv6-icmp*/) {
++
++	u_int16_t icmp_type;
++	u_int16_t icmp_code;
++
++	icmp_type = ntohs(req.p.sel.sport) >> 8;
++	icmp_code = ntohs(req.p.sel.sport) & 0xFF;
++
++	req.p.sel.sport = htons(icmp_type);
++	req.p.sel.dport = htons(icmp_code);
++
++	}
++
++	req.p.sel.sport_mask = (req.p.sel.sport) ? ~0:0;
++	req.p.sel.dport_mask = (req.p.sel.dport) ? ~0:0;
++	ip2xfrm(&sa->src_client->addr, &req.p.sel.saddr);
++	ip2xfrm(&sa->dst_client->addr, &req.p.sel.daddr);
++	req.p.sel.prefixlen_s = sa->src_client->maskbits;
++	req.p.sel.prefixlen_d = sa->dst_client->maskbits;
++	req.p.sel.proto = sa->transport_proto;
++	req.p.sel.family = sa->src_client->addr.u.v4.sin_family;
++	}
++
+     }
+ 
+     req.p.replay_window = sa->replay_window > 32 ? 32 : sa->replay_window; 
diff --git a/rhbz-841325.patch b/rhbz-841325.patch
new file mode 100644
index 0000000..23d03ce
--- /dev/null
+++ b/rhbz-841325.patch
@@ -0,0 +1,56 @@
+From e1280ce2abf5d8217b0690874fd9e5298fe37bca Mon Sep 17 00:00:00 2001
+From: Avesh Agarwal <avagarwa at redhat.com>
+Date: Tue, 7 Aug 2012 12:53:58 -0400
+Subject: rhbz #841325
+
+Fixes to interop issues between cisco ASA and openswan in main mode.
+These fixes prevents xauth/modecfg negotiation during IKE rekey in main mode.
+
+diff --git a/programs/pluto/ikev1_main.c b/programs/pluto/ikev1_main.c
+index cd4be12..9c1e660 100644
+--- a/programs/pluto/ikev1_main.c
++++ b/programs/pluto/ikev1_main.c
+@@ -2231,6 +2231,21 @@ main_inI3_outR3_tail(struct msg_digest *md
+     st->st_ph1_iv_len = st->st_new_iv_len;
+     set_ph1_iv(st, st->st_new_iv);
+ 
++    /* It seems as per Cisco implementation, XAUTH and MODECFG 
++     * are not supposed to be performed again during rekey */
++    if(st->st_connection->newest_isakmp_sa != SOS_NOBODY &&
++        st->st_connection->spd.this.xauth_client) {
++           DBG(DBG_CONTROL, DBG_log("Skipping XAUTH for rekey for Cisco Peer compatibility."));
++           st->hidden_variables.st_xauth_client_done = TRUE;
++           st->st_oakley.xauth = 0;
++
++           if(st->st_connection->spd.this.modecfg_client) {
++                DBG(DBG_CONTROL, DBG_log("Skipping ModeCFG for rekey for Cisco Peer compatibility."));
++                st->hidden_variables.st_modecfg_vars_set = TRUE;
++                st->hidden_variables.st_modecfg_started = TRUE;
++           }
++    }
++
+     ISAKMP_SA_established(st->st_connection, st->st_serialno);
+ 
+     /* ??? If st->st_connectionc->gw_info != NULL,
+@@ -2288,6 +2303,21 @@ main_inR3_tail(struct msg_digest *md
+      */
+     memcpy(st->st_ph1_iv, st->st_new_iv, st->st_new_iv_len);
+     st->st_ph1_iv_len = st->st_new_iv_len;
++
++    /* It seems as per Cisco implementation, XAUTH and MODECFG 
++     * are not supposed to be performed again during rekey */
++    if(st->st_connection->newest_isakmp_sa != SOS_NOBODY &&
++        st->st_connection->spd.this.xauth_client) {
++           DBG(DBG_CONTROL, DBG_log("Skipping XAUTH for rekey for Cisco Peer compatibility."));
++           st->hidden_variables.st_xauth_client_done = TRUE;
++           st->st_oakley.xauth = 0;
++
++           if(st->st_connection->spd.this.modecfg_client) {
++                DBG(DBG_CONTROL, DBG_log("Skipping ModeCFG for rekey for Cisco Peer compatibility."));
++                st->hidden_variables.st_modecfg_vars_set = TRUE;
++                st->hidden_variables.st_modecfg_started = TRUE;
++           }
++    }
+     
+     ISAKMP_SA_established(st->st_connection, st->st_serialno);
+ 


More information about the scm-commits mailing list