Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > e8916e5cb6487118130934db089d8fa5 > files > 30

openswan-2.6.32-9.el5.src.rpm

diff -urNp openswan-2.6.32-patched/include/packet.h openswan-2.6.32-current/include/packet.h
--- openswan-2.6.32-patched/include/packet.h	2012-02-01 13:42:07.071535495 -0500
+++ openswan-2.6.32-current/include/packet.h	2012-02-01 23:32:04.763508320 -0500
@@ -810,6 +810,35 @@ struct ikev2_notify 
 };
 extern struct_desc ikev2_notify_desc;
 
+
+/* IKEv2 Delete Payload
+ * layout from RFC 5996 Section 3.11 
+ * This is followed by a variable length SPI.
+ *
+ *                      1                   2                   3
+ *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Next Payload  !C| RESERVED    !         Payload Length        !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * !  Protocol ID  !   SPI Size    !           Num of SPIs         !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * !                                                               !
+ * ~               Security Parameter Index(es) (SPI)              ~
+ * !                                                               !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+struct ikev2_delete
+{
+    u_int8_t    isad_np;
+    u_int8_t    isad_reserved;
+    u_int16_t   isad_length;
+    u_int8_t    isad_protoid;
+    u_int8_t    isad_spisize;
+    u_int16_t   isad_nospi;
+};
+
+extern struct_desc ikev2_delete_desc;
+
 /* rfc4306, section 3.12, vendor ID, uses generic header */
 extern struct_desc ikev2_vendor_id_desc;
 
@@ -863,6 +892,7 @@ union payload {
     struct ikev2_cert       v2cert;
     struct ikev2_certreq    v2certreq;
     struct ikev2_notify     v2n;
+    struct ikev2_delete     v2delete; 
 };
 
 
diff -urNp openswan-2.6.32-patched/include/pluto_constants.h openswan-2.6.32-current/include/pluto_constants.h
--- openswan-2.6.32-patched/include/pluto_constants.h	2012-02-01 13:42:07.069535494 -0500
+++ openswan-2.6.32-current/include/pluto_constants.h	2012-02-09 00:52:34.065331546 -0500
@@ -288,6 +288,10 @@ enum state_kind {
      * for all work states. */
     STATE_PARENT_R1,
     STATE_PARENT_R2,
+
+    /* IKEv2 Delete States*/
+    STATE_IKESA_DEL,
+    STATE_CHILDSA_DEL,
     
     STATE_IKEv2_ROOF,
 };
@@ -332,8 +336,8 @@ 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)
-#define IS_CHILD_SA_ESTABLISHED(st) (((st->st_state) == STATE_PARENT_I3 || (st->st_state) == STATE_PARENT_R2) && (st->st_childsa != NULL))
+#define IS_PARENT_SA_ESTABLISHED(s) ((s) == STATE_PARENT_I2 || (s) == STATE_PARENT_R1 || (s) == STATE_IKESA_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)
diff -urNp openswan-2.6.32-patched/lib/libpluto/pluto_constants.c openswan-2.6.32-current/lib/libpluto/pluto_constants.c
--- openswan-2.6.32-patched/lib/libpluto/pluto_constants.c	2012-02-01 13:42:06.781535170 -0500
+++ openswan-2.6.32-current/lib/libpluto/pluto_constants.c	2012-02-08 15:49:13.412150293 -0500
@@ -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 -urNp openswan-2.6.32-patched/programs/pluto/ikev2.c openswan-2.6.32-current/programs/pluto/ikev2.c
--- openswan-2.6.32-patched/programs/pluto/ikev2.c	2012-02-01 13:42:06.207534523 -0500
+++ openswan-2.6.32-current/programs/pluto/ikev2.c	2012-02-09 13:14:45.966896827 -0500
@@ -170,6 +170,48 @@ static const struct state_v2_microcode s
       .timeout_event = EVENT_SA_REPLACE,
     },
 
+    /* Informational Exchange*/
+    { .state      = STATE_PARENT_I2,
+      .next_state = STATE_PARENT_I2,
+      .flags      = SMF2_STATENEEDED,
+      .processor  = process_informational_ikev2,
+      .recv_type  = ISAKMP_v2_INFORMATIONAL,
+    },
+
+
+    /* Informational Exchange*/
+    { .state      = STATE_PARENT_R1,
+      .next_state = STATE_PARENT_R1,
+      .flags      = SMF2_STATENEEDED,
+      .processor  = process_informational_ikev2,
+      .recv_type  = ISAKMP_v2_INFORMATIONAL,
+    },
+
+    /* Informational Exchange*/
+    { .state      = STATE_PARENT_I3,
+      .next_state = STATE_PARENT_I3,
+      .flags      = SMF2_STATENEEDED,
+      .processor  = process_informational_ikev2,
+      .recv_type  = ISAKMP_v2_INFORMATIONAL,
+    },
+
+    /* Informational Exchange*/
+    { .state      = STATE_PARENT_R2,
+      .next_state = STATE_PARENT_R2,
+      .flags      = SMF2_STATENEEDED,
+      .processor  = process_informational_ikev2,
+      .recv_type  = ISAKMP_v2_INFORMATIONAL,
+    },
+
+    /* Informational Exchange*/
+    { .state      = STATE_IKESA_DEL,
+      .next_state = STATE_IKESA_DEL,
+      .flags      = SMF2_STATENEEDED,
+      .processor  = process_informational_ikev2,
+      .recv_type  = ISAKMP_v2_INFORMATIONAL,
+    },
+
+
     /* last entry */
     { .state      = STATE_IKEv2_ROOF }
 };
@@ -203,7 +245,8 @@ ikev2_process_payloads(struct msg_digest
 	struct_desc *sd = np < ISAKMP_NEXT_ROOF? payload_descs[np] : NULL;
 	int thisp = np;
 	bool unknown_payload = FALSE;
-	
+
+	DBG(DBG_CONTROL, DBG_log("Now lets proceed with payload (%)",enum_show(&payload_names, thisp)));	
 	memset(pd, 0, sizeof(*pd));
 	
 	if (pd == &md->digest[PAYLIMIT])
@@ -218,16 +261,12 @@ ikev2_process_payloads(struct msg_digest
 	    unknown_payload = TRUE;
 	    sd = &ikev2_generic_desc;
 	}
-	
-	if (!in_struct(&pd->payload, sd, in_pbs, &pd->pbs))
-	{
-	    loglog(RC_LOG_SERIOUS, "%smalformed payload in packet", excuse);
-	    SEND_NOTIFICATION(PAYLOAD_MALFORMED);
-	    return STF_FAIL;
-	}
 
+	/* why to process an unknown payload*/
+	/* critical bit in RFC 4306/5996 is just 1 bit not a byte*/
+	/* As per RFC other 7 bits are RESERVED and should be ignored*/
 	if(unknown_payload) {
-	    if(pd->payload.v2gen.isag_critical) {
+	    if(pd->payload.v2gen.isag_critical & ISAKMP_PAYLOAD_CRITICAL) {
 		/* it was critical */
 		loglog(RC_LOG_SERIOUS, "critical payload (%s) was not understood. Message dropped."
 		       , enum_show(&payload_names, thisp));
@@ -238,6 +277,13 @@ ikev2_process_payloads(struct msg_digest
 		   , enum_show(&payload_names, thisp));
 	}
 		
+	if (!in_struct(&pd->payload, sd, in_pbs, &pd->pbs))
+	{
+	    loglog(RC_LOG_SERIOUS, "%smalformed payload in packet", excuse);
+	    SEND_NOTIFICATION(PAYLOAD_MALFORMED);
+	    return STF_FAIL;
+	}
+	
 	
 	DBG(DBG_PARSING
 	    , DBG_log("processing payload: %s (len=%u)\n"
@@ -268,6 +314,7 @@ ikev2_process_payloads(struct msg_digest
 	pd++;
     }
     
+    DBG(DBG_CONTROL, DBG_log("Finished and now at the end of ikev2_process_payload"));
     md->digest_roof = pd;
     return STF_OK;
 }
@@ -299,9 +346,9 @@ process_v2_packet(struct msg_digest **md
 
 	/* TODO: this code allows a packet to both set ISAKMP_FLAGS_I and ISAKMP_FLAGS_R */
 
-    if( (md->hdr.isa_flags & ISAKMP_FLAGS_I) && (md->hdr.isa_flags & ISAKMP_FLAGS_R) ) {
-	openswan_log("received packet that claimed to be  both (I)nitiator and (R)esponder, msgid=%u", md->msgid_received);
-}
+    //if( (md->hdr.isa_flags & ISAKMP_FLAGS_I) && (md->hdr.isa_flags & ISAKMP_FLAGS_R) ) {
+    //	openswan_log("received packet that claimed to be  both (I)nitiator and (R)esponder, msgid=%u", md->msgid_received);
+    //}
 
     if(md->hdr.isa_flags & ISAKMP_FLAGS_I) {
 	/* then I am the responder */
@@ -309,6 +356,8 @@ process_v2_packet(struct msg_digest **md
 
 	md->role = RESPONDER;
 
+	DBG(DBG_CONTROL, DBG_log("I am IKE SA Responder"));
+
 	st = find_state_ikev2_parent(md->hdr.isa_icookie
 				     , md->hdr.isa_rcookie);
 
@@ -331,13 +380,15 @@ process_v2_packet(struct msg_digest **md
 	    }
 	    /* update lastrecv later on */
 	}
-    } else if(!(md->hdr.isa_flags & ISAKMP_FLAGS_R)) {
-	openswan_log("received packet that was neither (I)nitiator or (R)esponder, msgid=%u", md->msgid_received);
+    //} else if(!(md->hdr.isa_flags & ISAKMP_FLAGS_R)) {
+	//openswan_log("received packet that was neither (I)nitiator or (R)esponder, msgid=%u", md->msgid_received);
 	
     } else {
         /* then I am the initiator, and this is a reply */
 	
 	md->role = INITIATOR;
+
+	DBG(DBG_CONTROL, DBG_log("I am IKE SA Initiator"));
 	
 	if(md->msgid_received==MAINMODE_MSGID) {
 	    st = find_state_ikev2_parent(md->hdr.isa_icookie
@@ -395,7 +446,9 @@ process_v2_packet(struct msg_digest **md
 	
     ix = md->hdr.isa_xchg;
     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++) {
@@ -412,14 +465,16 @@ process_v2_packet(struct msg_digest **md
  	   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;
+	//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) {
 	    /* must be an initiator message, so we are the responder */
@@ -434,6 +489,7 @@ process_v2_packet(struct msg_digest **md
 	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);
@@ -441,7 +497,7 @@ process_v2_packet(struct msg_digest **md
 	}
     }
 
-
+    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)));
@@ -656,6 +712,7 @@ static void success_v2_state_transition(
     openswan_log("transition from state %s to state %s"
                  , enum_name(&state_names, from_state)
                  , enum_name(&state_names, svm->next_state));
+
     change_state(st, svm->next_state);
     w = RC_NEW_STATE + st->st_state;    
 
diff -urNp openswan-2.6.32-patched/programs/pluto/ikev2.h openswan-2.6.32-current/programs/pluto/ikev2.h
--- openswan-2.6.32-patched/programs/pluto/ikev2.h	2012-02-01 13:42:06.148534456 -0500
+++ openswan-2.6.32-current/programs/pluto/ikev2.h	2012-02-06 13:13:42.087924082 -0500
@@ -33,6 +33,7 @@ extern bool ikev2_out_sa(pb_stream *outs
 extern void complete_v2_state_transition(struct msg_digest **mdp
 					 , stf_status result);
 
+extern stf_status process_informational_ikev2(struct msg_digest *md);
 extern stf_status ikev2parent_inI1outR1(struct msg_digest *md);
 extern stf_status ikev2parent_inR1(struct msg_digest *md);
 extern stf_status ikev2parent_inR1outI2(struct msg_digest *md);
diff -urNp openswan-2.6.32-patched/programs/pluto/ikev2_parent.c openswan-2.6.32-current/programs/pluto/ikev2_parent.c
--- openswan-2.6.32-patched/programs/pluto/ikev2_parent.c	2012-02-01 13:42:06.146534451 -0500
+++ openswan-2.6.32-current/programs/pluto/ikev2_parent.c	2012-02-09 14:51:00.051000712 -0500
@@ -760,8 +760,8 @@ ikev2_parent_inI1outR1_tail(struct pluto
     {
 	notification_t rn;
 	chunk_t dc;
-    keyex_pbs = &md->chain[ISAKMP_NEXT_v2KE]->pbs;
-    /* KE in */
+	keyex_pbs = &md->chain[ISAKMP_NEXT_v2KE]->pbs;
+	/* KE in */
 	rn=accept_KE(&st->st_gi, "Gi", st->st_oakley.group, keyex_pbs);
 	if(rn != NOTHING_WRONG) {
 	//char group_number[2];
@@ -772,8 +772,7 @@ ikev2_parent_inI1outR1_tail(struct pluto
 	delete_state(st);
 	return STF_FAIL + rn;
 	}
-    //RETURN_STF_FAILURE(accept_KE(&st->st_gi, "Gi", st->st_oakley.group, keyex_pbs));
-
+	//RETURN_STF_FAILURE(accept_KE(&st->st_gi, "Gi", st->st_oakley.group, keyex_pbs));
     } 
 
     /* Ni in */
@@ -1097,10 +1096,14 @@ static stf_status ikev2_encrypt_msg(stru
     /* 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);
@@ -1711,6 +1714,9 @@ ikev2_parent_inI2outR2_tail(struct pluto
      * new state now */
     change_state(st, STATE_PARENT_R2);
     c->newest_isakmp_sa = st->st_serialno;
+
+    delete_event(st);
+    event_schedule(EVENT_SA_REPLACE, c->sa_ike_life_seconds, st);
     
     authstart = reply_stream.cur;
     /* send response */
@@ -2034,10 +2040,24 @@ stf_status ikev2parent_inR2(struct msg_d
     }
 
     {
-	struct payload_digest *p;	
+	struct payload_digest *p;
 
 	for(p = md->chain[ISAKMP_NEXT_v2N]; p != NULL; p = p->next)
-	{
+	{   
+	   /* RFC 5996 */
+	   /*Types in the range 0 - 16383 are intended for reporting errors.  An
+	    * implementation receiving a Notify payload with one of these types
+	    * that it does not recognize in a response MUST assume that the
+	    * corresponding request has failed entirely.  Unrecognized error types
+	    * in a request and status types in a request or response MUST be
+	    * ignored, and they should be logged.*/
+
+	    if(enum_name(&ikev2_notify_names, p->payload.v2n.isan_type) == NULL) {
+		if(p->payload.v2n.isan_type < INITIAL_CONTACT) {
+		return STF_FAIL + p->payload.v2n.isan_type;
+		}
+	    }
+
 	    if ( p->payload.v2n.isan_type == USE_TRANSPORT_MODE ) {
 		if ( st->st_connection->policy & POLICY_TUNNEL) {
 		/*This means we did not send USE_TRANSPORT, however responder is sending it in now (inR2), seems incorrect*/
@@ -2052,18 +2072,10 @@ stf_status ikev2parent_inR2(struct msg_d
 			st->st_esp.attrs.encapsulation = ENCAPSULATION_MODE_TRANSPORT;
 			}
 		}
-	    break;
 	    }
-	}
+	}/*for*/
 
-        if (!p) {
-                if ( !(st->st_connection->policy & POLICY_TUNNEL) ) {
-                /*This means we sent USE_TRANSPORT, however responder did not send it or did not agree with that*/
-                        DBG(DBG_CONTROLMORE,
-			DBG_log("Initiator policy is transport, responder did not send USE_TRANSPORT_MODE, so falling back to tunnel mode (rfc 4306)"));
-                }
-        }
-    }
+    } /*notification block */
 
 	
     ikev2_derive_child_keys(st, md->role);
@@ -2241,6 +2253,430 @@ bool ship_v2N (unsigned int np, u_int8_t
 	return TRUE;
 }
 	     
+/*
+ *
+ ***************************************************************
+ *                       INFORMATIONAL                     *****
+ ***************************************************************
+ *  - 
+ *  
+ *
+ */
+stf_status process_informational_ikev2(struct msg_digest *md)
+{
+    /* verify that there is in fact an encrypted payload */
+    if(!md->chain[ISAKMP_NEXT_v2E]) {
+	openswan_log("Informational exchange should receive an encrypted payload");
+	return STF_IGNORE;
+    }
+
+    /* decrypt things. */
+    {
+	stf_status ret; 
+
+	if(md->hdr.isa_flags & ISAKMP_FLAGS_I) {
+	DBG(DBG_CONTROLMORE
+		, DBG_log("received informational exchange request from INITIATOR"));
+	ret = ikev2_decrypt_msg(md, RESPONDER);
+	}
+	else {
+	DBG(DBG_CONTROLMORE
+		, DBG_log("received informational exchange request from RESPONDER"));
+	ret = ikev2_decrypt_msg(md, INITIATOR);
+	}
+
+	if(ret != STF_OK) return ret;
+    }
+
+
+    {
+	struct payload_digest *p;
+	struct ikev2_delete *v2del=NULL;
+	stf_status ret;
+	struct state *const st = md->st;
+
+	/* Only send response if it is request*/
+	if (!(md->hdr.isa_flags & ISAKMP_FLAGS_R)) {
+	unsigned char *authstart;
+	pb_stream      e_pbs, e_pbs_cipher;
+	struct ikev2_generic e;
+	unsigned char *iv;
+	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");
+
+	/* HDR out */
+	{
+		struct isakmp_hdr r_hdr ;
+		zero(&r_hdr);     /* default to 0 */  /* AAA should we copy from MD? */
+		r_hdr.isa_version = IKEv2_MAJOR_VERSION << ISA_MAJ_SHIFT | IKEv2_MINOR_VERSION;
+		memcpy(r_hdr.isa_rcookie, st->st_rcookie, COOKIE_SIZE);
+		memcpy(r_hdr.isa_icookie, st->st_icookie, COOKIE_SIZE);
+		r_hdr.isa_xchg = ISAKMP_v2_INFORMATIONAL;
+		r_hdr.isa_np = ISAKMP_NEXT_v2E;
+		r_hdr.isa_msgid = htonl(md->msgid_received);
+
+		/*set initiator bit if we are initiator*/
+		if(md->role == INITIATOR) {
+		r_hdr.isa_flags |= ISAKMP_FLAGS_I;
+		}
+
+		r_hdr.isa_flags  |=  ISAKMP_FLAGS_R;
+
+
+		if (!out_struct(&r_hdr, &isakmp_hdr_desc, &reply_stream, &md->rbody))
+		{
+			openswan_log("error initializing hdr for informational message");
+			return STF_INTERNAL_ERROR;
+		}
+
+	}/*HDR Done*/
+
+
+	/* insert an Encryption payload header */
+	if(md->chain[ISAKMP_NEXT_v2D]) 
+	{
+		bool ikesa_flag = FALSE;
+		/* Search if there is a IKE SA delete payload*/
+		for(p = md->chain[ISAKMP_NEXT_v2D]; p!=NULL; p = p->next) {
+			if(p->payload.v2delete.isad_protoid == PROTO_ISAKMP) 
+			{
+			e.isag_np = ISAKMP_NEXT_NONE;
+			ikesa_flag = TRUE; 
+			break;
+			}
+		}
+		/* if there is no IKE SA DELETE PAYLOAD*/
+		/* That means, there are AH OR ESP*/
+		if(!ikesa_flag) { 
+			e.isag_np = ISAKMP_NEXT_v2D;
+		}
+	
+
+	}
+	else 
+	{
+		e.isag_np = ISAKMP_NEXT_NONE;
+	}
+
+	e.isag_critical = ISAKMP_PAYLOAD_NONCRITICAL;
+
+	if(!out_struct(&e, &ikev2_e_desc, &md->rbody, &e_pbs)) {
+		return STF_INTERNAL_ERROR;
+	}
+
+	/* insert IV */
+	iv     = e_pbs.cur;
+	ivsize = st->st_oakley.encrypter->iv_size;
+	if(!out_zero(ivsize, &e_pbs, "iv")) {
+		return STF_INTERNAL_ERROR;
+	}
+	get_rnd_bytes(iv, ivsize);
+
+	/* note where cleartext starts */
+	init_pbs(&e_pbs_cipher, e_pbs.cur, e_pbs.roof - e_pbs.cur, "cleartext");
+	e_pbs_cipher.container = &e_pbs;
+	e_pbs_cipher.desc = NULL;
+	e_pbs_cipher.cur = e_pbs.cur;
+	encstart = e_pbs_cipher.cur;
+
+	if(md->chain[ISAKMP_NEXT_v2D]) {
+
+		for(p = md->chain[ISAKMP_NEXT_v2D]; p!=NULL; p = p->next) {
+		v2del = &p->payload.v2delete;
+
+			switch (v2del->isad_protoid) 
+			{
+			case PROTO_ISAKMP: 
+				/* My understanding is that delete payload for IKE SA 
+				 *  should be the only payload in the informational exchange
+				 */ 
+				break;
+
+			case PROTO_IPSEC_AH:
+			case PROTO_IPSEC_ESP:
+				{
+				char spi_buf[1024];
+				pb_stream del_pbs;
+				struct ikev2_delete v2del_tmp;
+				u_int16_t i, j=0;
+				bool bogus;
+				u_char *spi;
+
+				for(i = 0; i < v2del->isad_nospi; i++ ) 
+				{
+					spi = p->pbs.cur + (i * v2del->isad_spisize);
+					DBG(DBG_CONTROLMORE, DBG_log("received delete request for %s SA(0x%08lx)"
+								, enum_show(&protocol_names, v2del->isad_protoid)
+								, (unsigned long)ntohl((unsigned long)*(ipsec_spi_t *)spi)));
+
+					struct state *dst = find_state_ikev2_child_to_delete (st->st_icookie
+										, st->st_rcookie
+										, v2del->isad_protoid
+										, *(ipsec_spi_t *)spi);
+
+					if(dst != NULL) 
+					{
+						struct ipsec_proto_info *pr = v2del->isad_protoid == PROTO_IPSEC_AH? &dst->st_ah : &dst->st_esp;
+						DBG(DBG_CONTROLMORE, DBG_log("our side spi that needs to be sent: %s SA(0x%08lx)"
+                                                                , enum_show(&protocol_names, v2del->isad_protoid)
+                                                                , (unsigned long)ntohl(pr->our_spi)));
+						
+						memcpy(spi_buf + (j * v2del->isad_spisize), (u_char *)&pr->our_spi, v2del->isad_spisize);
+						j++;
+					}
+					else 
+					{
+						DBG(DBG_CONTROLMORE, DBG_log("received delete request for %s SA(0x%08lx) but local state is not found"
+								, enum_show(&protocol_names, v2del->isad_protoid)
+								, (unsigned long)ntohl((unsigned long)*(ipsec_spi_t *)spi)));
+					}
+				}
+
+				if( !j ) 
+				{
+					DBG(DBG_CONTROLMORE, DBG_log("This delete payload does not contain a single spi that has any local state, ignoring"));
+					return STF_IGNORE;		
+				}
+				else 
+				{
+					DBG(DBG_CONTROLMORE, DBG_log("No. of SPIs to be sent %d", j);
+						DBG_dump(" Emit SPIs", spi_buf, j*v2del->isad_spisize));
+				}
+
+				zero(&v2del_tmp);
+
+				if(p->next != NULL) 
+				{
+				v2del_tmp.isad_np = ISAKMP_NEXT_v2D;
+				}
+				else 
+				{
+				v2del_tmp.isad_np = ISAKMP_NEXT_NONE;
+				}
+
+				v2del_tmp.isad_protoid = v2del->isad_protoid;
+				v2del_tmp.isad_spisize = v2del->isad_spisize;
+				v2del_tmp.isad_nospi = j;
+
+				/* Emit delete payload header out*/
+				if (!out_struct(&v2del_tmp, &ikev2_delete_desc, &e_pbs_cipher, &del_pbs))
+				{
+					openswan_log("error initializing hdr for delete payload");
+					return STF_INTERNAL_ERROR;
+				}		
+
+				/* Emit values of spi to be sent to the peer*/
+				if (!out_raw(spi_buf, j* v2del->isad_spisize, &del_pbs, "local spis"))
+				{
+					openswan_log("error sending spi values in delete payload");
+					return STF_INTERNAL_ERROR;
+				}
+				
+				close_output_pbs(&del_pbs);
+
+				}
+				break;
+			default:
+				/*Unrecongnized protocol */
+				return STF_IGNORE;
+			}
+
+			/* this will break from for loop*/
+			if(v2del->isad_protoid == PROTO_ISAKMP) {
+			break;
+			}
+
+		}
+	}
+
+	/*If there are no payloads or in other words empty payload in request
+	 * that means it is check for liveliness, so send an empty payload message
+	 * this will end up sending an empty payload
+	 */
+
+	ikev2_padup_pre_encrypt(md, &e_pbs_cipher);
+	close_output_pbs(&e_pbs_cipher);
+
+	{
+	unsigned char *authloc = ikev2_authloc(md, &e_pbs);
+	if(authloc == NULL) return STF_INTERNAL_ERROR;
+	close_output_pbs(&e_pbs);
+	close_output_pbs(&md->rbody);
+	close_output_pbs(&reply_stream);
+
+	ret = ikev2_encrypt_msg(md, RESPONDER,
+                                    authstart,
+                                    iv, encstart, authloc,
+                                    &e_pbs, &e_pbs_cipher);
+	if(ret != STF_OK) return ret;
+        }
+
+
+	/* let TCL hack it before we mark the length. */
+	TCLCALLOUT("v2_avoidEmitting", st, st->st_connection, md);
+
+	/* keep it for a retransmit if necessary */
+	freeanychunk(st->st_tpacket);
+	clonetochunk(st->st_tpacket, reply_stream.start, pbs_offset(&reply_stream)
+			, "reply packet for informational exchange");
+
+	send_packet(st, __FUNCTION__, TRUE);
+	}
+
+	/* 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->chain[ISAKMP_NEXT_v2D] && st->st_state != STATE_IKESA_DEL) {
+
+		for(p = md->chain[ISAKMP_NEXT_v2D]; p!=NULL; p = p->next) {
+		v2del = &p->payload.v2delete;
+
+			switch (v2del->isad_protoid) 
+			{
+			case PROTO_ISAKMP: 
+				{
+				/* My understanding is that delete payload for IKE SA 
+				 *  should be the only payload in the informational
+				 * Now delete the IKE SA state and all its child states
+				 */
+				struct state *current_st = st;
+				struct state *next_st = NULL;
+				struct state *first_st = NULL;
+
+				/* Find the first state in the hash chain*/
+				while(current_st != (struct state *) NULL) 
+				{
+				first_st = current_st;
+				current_st = first_st->st_hashchain_prev;
+				}
+				
+				current_st = first_st;
+				while (current_st != (struct state *) NULL) 
+				{
+				next_st = current_st->st_hashchain_next;
+					if(current_st->st_clonedfrom !=0 )
+					{
+						change_state(current_st, STATE_CHILDSA_DEL);
+					}
+					else
+					{
+						change_state(current_st, STATE_IKESA_DEL);
+					}
+        			delete_state(current_st);
+				current_st = next_st;
+				}
+				}
+				break;
+
+			case PROTO_IPSEC_AH:
+			case PROTO_IPSEC_ESP:
+				{				
+				char spi_buf[1024];
+				//pb_stream del_pbs;
+				struct ikev2_delete v2del_tmp;
+				u_int16_t i;
+				bool bogus;
+				u_char *spi;
+
+				for(i = 0; i < v2del->isad_nospi; i++ ) 
+				{
+					spi = p->pbs.cur + (i * v2del->isad_spisize);
+					DBG(DBG_CONTROLMORE, DBG_log("Now doing actual deletion for request: %s SA(0x%08lx)"
+								, enum_show(&protocol_names, v2del->isad_protoid)
+								, (unsigned long)ntohl((unsigned long)*(ipsec_spi_t *)spi)));
+
+					struct state *dst = find_state_ikev2_child_to_delete (st->st_icookie
+										, st->st_rcookie
+										, v2del->isad_protoid
+										, *(ipsec_spi_t *)spi);
+
+					if(dst != NULL) 
+					{
+						struct ipsec_proto_info *pr = v2del->isad_protoid == PROTO_IPSEC_AH? &dst->st_ah : &dst->st_esp;
+						DBG(DBG_CONTROLMORE, DBG_log("our side spi that needs to be deleted: %s SA(0x%08lx)"
+                                                                , enum_show(&protocol_names, v2del->isad_protoid)
+                                                                , (unsigned long)ntohl(pr->our_spi)));
+						
+						/* now delete the state*/
+						change_state(dst, STATE_CHILDSA_DEL);
+						delete_state(dst);
+					}
+					else 
+					{
+						DBG(DBG_CONTROLMORE, DBG_log("received delete request for %s SA(0x%08lx) but local state is not found"
+								, enum_show(&protocol_names, v2del->isad_protoid)
+								, (unsigned long)ntohl((unsigned long)*(ipsec_spi_t *)spi)));
+					}
+				}
+				}
+				break;
+
+			default:
+				/*Unrecongnized protocol */
+				return STF_IGNORE;
+			}
+
+			/* this will break from for loop*/
+			if(v2del->isad_protoid == PROTO_ISAKMP) {
+			break;
+			}
+
+		} /* for */ 
+
+		} /* if*/
+		else 
+		{
+			/* empty response to our IKESA delete request*/
+			if((md->hdr.isa_flags & ISAKMP_FLAGS_R) && st->st_state == STATE_IKESA_DEL)
+			{
+				/* My understanding is that delete payload for IKE SA 
+				 *  should be the only payload in the informational
+				 * Now delete the IKE SA state and all its child states
+				 */
+				struct state *current_st = st;
+				struct state *next_st = NULL;
+				struct state *first_st = NULL;
+
+				/* Find the first state in the hash chain*/
+				while(current_st != (struct state *) NULL) 
+				{
+				first_st = current_st;
+				current_st = first_st->st_hashchain_prev;
+				}
+				
+				current_st = first_st;
+				while (current_st != (struct state *) NULL) 
+				{
+				next_st = current_st->st_hashchain_next;
+					if(current_st->st_clonedfrom !=0 )
+					{
+						change_state(current_st, STATE_CHILDSA_DEL);
+					}
+					else
+					{
+						change_state(current_st, STATE_IKESA_DEL);
+					}
+        			delete_state(current_st);
+				current_st = next_st;
+				}
+				
+			}
+		}
+	}
+
+    }
+
+    return STF_OK;
+}
 
 /*
  *
@@ -2249,9 +2685,218 @@ bool ship_v2N (unsigned int np, u_int8_t
  ***************************************************************
  *
  */
-void ikev2_delete_out(struct state *st UNUSED)
+void ikev2_delete_out(struct state *st)
 {
-    /* XXX */
+	struct state *pst = NULL;
+
+	if(st->st_clonedfrom != 0)
+	{
+		/*child SA*/
+		pst = state_with_serialno(st->st_clonedfrom);
+
+		if(!pst) {
+		DBG(DBG_CONTROL, DBG_log("IKE SA does not exist for this child SA"));
+		DBG(DBG_CONTROL, DBG_log("INFORMATIONAL exchange can not be sent, deleting state"));
+		goto end;
+		}
+	}
+	else
+	{
+		/* Parent SA*/
+		pst = st;
+
+	}
+
+	{
+	unsigned char *authstart;
+	pb_stream      e_pbs, e_pbs_cipher;
+	pb_stream rbody;
+	struct ikev2_generic e;
+	unsigned char *iv;
+	int            ivsize;
+	unsigned char *encstart;
+	struct msg_digest md;
+	enum phase1_role role;
+
+	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");
+
+	/* HDR out */
+	{
+		struct isakmp_hdr r_hdr ;
+		zero(&r_hdr);     /* default to 0 */  /* AAA should we copy from MD? */
+		r_hdr.isa_version = IKEv2_MAJOR_VERSION << ISA_MAJ_SHIFT | IKEv2_MINOR_VERSION;
+		memcpy(r_hdr.isa_rcookie, pst->st_rcookie, COOKIE_SIZE);
+		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);
+
+		/*set initiator bit if we are initiator*/
+		if(pst->st_state == STATE_PARENT_I2 || pst->st_state == STATE_PARENT_I3) {
+		r_hdr.isa_flags |= ISAKMP_FLAGS_I;
+		role = INITIATOR;
+		}
+		else {
+		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");
+			goto end;
+		}
+
+	}/*HDR Done*/
+
+
+	/* insert an Encryption payload header */
+	e.isag_np = ISAKMP_NEXT_v2D;
+	e.isag_critical = ISAKMP_PAYLOAD_NONCRITICAL;
+
+	if(!out_struct(&e, &ikev2_e_desc, &rbody, &e_pbs)) {
+		goto end;
+	}
+
+	/* insert IV */
+	iv     = e_pbs.cur;
+	ivsize = pst->st_oakley.encrypter->iv_size;
+	if(!out_zero(ivsize, &e_pbs, "iv")) {
+		goto end;
+	}
+	get_rnd_bytes(iv, ivsize);
+
+	/* note where cleartext starts */
+	init_pbs(&e_pbs_cipher, e_pbs.cur, e_pbs.roof - e_pbs.cur, "cleartext");
+	e_pbs_cipher.container = &e_pbs;
+	e_pbs_cipher.desc = NULL;
+	e_pbs_cipher.cur = e_pbs.cur;
+	encstart = e_pbs_cipher.cur;
+
+				{
+				pb_stream del_pbs;
+				struct ikev2_delete v2del_tmp;
+				//u_int16_t i, j=0;
+				//bool bogus;
+				//u_char *spi;
+				//char spi_buf[1024];
+
+				zero(&v2del_tmp);
+				v2del_tmp.isad_np = ISAKMP_NEXT_NONE;
+
+				if(st->st_clonedfrom != 0 ) {
+				v2del_tmp.isad_protoid = PROTO_IPSEC_ESP;
+				v2del_tmp.isad_spisize = sizeof(ipsec_spi_t);
+				v2del_tmp.isad_nospi = 1;
+				}
+				else {
+				v2del_tmp.isad_protoid = PROTO_ISAKMP;
+				v2del_tmp.isad_spisize = 0;
+				v2del_tmp.isad_nospi = 0;
+				}
+
+				/* Emit delete payload header out*/
+				if (!out_struct(&v2del_tmp, &ikev2_delete_desc, &e_pbs_cipher, &del_pbs))
+				{
+					openswan_log("error initializing hdr for delete payload");
+					goto end;
+				}		
+
+				/* Emit values of spi to be sent to the peer*/
+				if(st->st_clonedfrom != 0){
+				if (!out_raw( (u_char *)&st->st_esp.our_spi ,sizeof(ipsec_spi_t), &del_pbs, "local spis"))
+				{
+					openswan_log("error sending spi values in delete payload");
+					goto end;
+				}
+				}
+				
+				close_output_pbs(&del_pbs);
+
+				}
+
+	ikev2_padup_pre_encrypt(&md, &e_pbs_cipher);
+	close_output_pbs(&e_pbs_cipher);
+
+	{
+	stf_status ret;
+	unsigned char *authloc = ikev2_authloc(&md, &e_pbs);
+	if(authloc == NULL) goto end;
+	close_output_pbs(&e_pbs);
+	close_output_pbs(&rbody);
+	close_output_pbs(&reply_stream);
+
+	ret = ikev2_encrypt_msg(&md, role,
+                                    authstart,
+                                    iv, encstart, authloc,
+                                    &e_pbs, &e_pbs_cipher);
+	if(ret != STF_OK) goto end;
+        }
+
+
+	/* let TCL hack it before we mark the length. */
+	TCLCALLOUT("v2_avoidEmitting", pst, pst->st_connection, &md);
+
+	/* keep it for a retransmit if necessary */
+	freeanychunk(pst->st_tpacket);
+	clonetochunk(pst->st_tpacket, reply_stream.start, pbs_offset(&reply_stream)
+			, "request packet for informational exchange");
+
+	send_packet(pst, __FUNCTION__, TRUE);
+
+	/* update state */
+	ikev2_update_counters(&md);
+
+	}
+	
+	/* If everything is fine, and we sent packet, goto real_end*/
+	goto real_end;
+
+end:
+	/* If some error occurs above that prevents us sending a request packet*/
+	/* delete the states right now*/
+
+	if(st->st_clonedfrom != 0) {
+		change_state(st, STATE_CHILDSA_DEL);
+		delete_state(st);
+	}
+	else
+	{
+
+		struct state *current_st = pst;
+		struct state *next_st = NULL;
+		struct state *first_st = NULL;
+
+		/* Find the first state in the hash chain*/
+		while(current_st != (struct state *) NULL) {
+		first_st = current_st;
+		current_st = first_st->st_hashchain_prev;
+		}
+
+		current_st = first_st;
+		while (current_st != (struct state *) NULL) {
+		next_st = current_st->st_hashchain_next;
+			if(current_st->st_clonedfrom !=0 ){
+				change_state(current_st, STATE_CHILDSA_DEL);
+			}
+			else
+			{
+				change_state(current_st, STATE_IKESA_DEL);
+			}
+		delete_state(current_st);
+		current_st = next_st;
+		}
+	}
+
+real_end:;
 }
 
 
diff -urNp openswan-2.6.32-patched/programs/pluto/state.c openswan-2.6.32-current/programs/pluto/state.c
--- openswan-2.6.32-patched/programs/pluto/state.c	2012-02-01 13:42:06.165534475 -0500
+++ openswan-2.6.32-current/programs/pluto/state.c	2012-02-09 15:45:39.585946327 -0500
@@ -358,8 +358,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 && st->st_state != STATE_PARENT_R1 && st->st_state != STATE_PARENT_R2)
+    {
+    /* 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)
@@ -510,6 +562,9 @@ delete_state(struct state *st)
     pfreeany(st->sec_ctx);
 #endif
     pfree(st);
+
+delete_state_end:;
+
 }
 
 /*
@@ -600,6 +655,9 @@ static void delete_state_function(struct
 		 , 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);
 }
 
@@ -1124,6 +1182,50 @@ find_state_ikev2_child(const u_char *ico
 }
 
 /*
+ * Find a state object for an IKEv2 child state to delete.
+ * In IKEv2, child states can only be distingusihed based on protocols and SPIs
+ */
+struct state *
+find_state_ikev2_child_to_delete(const u_char *icookie
+		       , const u_char *rcookie
+		       , u_int8_t protoid
+		       , ipsec_spi_t spi)
+{
+    struct state *st = *state_hash(icookie, rcookie, NULL);
+
+    while (st != (struct state *) NULL)
+    {
+	if (memcmp(icookie, st->st_icookie, COOKIE_SIZE) == 0
+	    && memcmp(rcookie, st->st_rcookie, COOKIE_SIZE) == 0
+	    && st->st_ikev2 == TRUE)
+	{
+                struct ipsec_proto_info *pr = protoid == PROTO_IPSEC_AH
+                    ? &st->st_ah : &st->st_esp;
+
+                if (pr->present)
+                {
+                    if (pr->attrs.spi == spi)
+                        break;
+                    if (pr->our_spi == spi)
+                        break;
+                }
+
+	}
+	st = st->st_hashchain_next;
+    }
+
+    DBG(DBG_CONTROL,
+	if (st == NULL)
+	    DBG_log("v2 child state object not found");
+	else
+	    DBG_log("v2 child state object #%lu found, in %s"
+		, st->st_serialno
+		, enum_show(&state_names, st->st_state)));
+
+    return st;
+}
+
+/*
  * Find a state object.
  */
 struct state *
diff -urNp openswan-2.6.32-patched/programs/pluto/state.h openswan-2.6.32-current/programs/pluto/state.h
--- openswan-2.6.32-patched/programs/pluto/state.h	2012-02-01 13:42:06.166534474 -0500
+++ openswan-2.6.32-current/programs/pluto/state.h	2012-02-08 14:30:36.793040057 -0500
@@ -440,6 +440,11 @@ extern struct state *find_state_ikev2_ch
 					    , const u_char *rcookie
 					    , msgid_t msgid);
 
+extern struct state *find_state_ikev2_child_to_delete(const u_char *icookie
+					    , const u_char *rcookie
+					    , u_int8_t protoid
+					    , ipsec_spi_t spi);
+
 extern struct state *find_info_state(const u_char *icookie
 				     , const u_char *rcookie
 				     , const ip_address *peer