MME2 changes - Propped commits from openmme/paging branch. Added scripts
for code gen

Change-Id: Ie55032217232214ac8544ca76ea34335205329e4
diff --git a/src/s1ap/handlers/s1ap_msg_delegator.c.bkup b/src/s1ap/handlers/s1ap_msg_delegator.c.bkup
new file mode 100644
index 0000000..9732c6d
--- /dev/null
+++ b/src/s1ap/handlers/s1ap_msg_delegator.c.bkup
@@ -0,0 +1,1279 @@
+/*
+ * Copyright (c) 2003-2018, Great Software Laboratory Pvt. Ltd.
+ * Copyright (c) 2017 Intel Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <pthread.h>
+
+#include "options.h"
+#include "ipc_api.h"
+#include "main.h"
+#include "s1ap.h"
+#include "s1ap_config.h"
+#include "sctp_conn.h"
+#include "s1ap_structs.h"
+#include "s1ap_msg_codes.h"
+#include "s1ap_ie.h"
+#include "ProtocolIE-ID.h"
+#include "ProtocolIE-Field.h"
+static void
+parse_erab_pdu(char *msg,  int nas_msg_len, struct eRAB_elements *erab)
+{
+	//struct eRAB_header *header = (struct eRAB*)msg;
+
+	//char *ie = msg + 5; /*ID(2)+crit(1)+len(1)+mistry(1)*/
+
+	/*TODO: write parse_IEs for erab IEs here going ahead*/
+	/*For now copying directly as it is single structure*/
+	char *ie = msg + 5; /*ID(2)+crit(1)+len(1)*/
+
+	erab->no_of_elements = 1;
+	erab->elements = (union eRAB_IE*)calloc(sizeof(union eRAB_IE), 1);
+	if(NULL == erab->elements) {
+		log_msg(LOG_ERROR, "Memory alloc failed\n");
+		exit(-1);
+	}
+
+	erab->elements[0].su_res.eRAB_id = *ie;
+	++ie;
+	++ie; //what is this identify.
+	memcpy(&(erab->elements[0].su_res.transp_layer_addr), ie, sizeof(unsigned int));
+	erab->elements[0].su_res.transp_layer_addr = ntohl(erab->elements[0].su_res.transp_layer_addr);
+	log_msg(LOG_INFO, "eRAB - Transport layer address : %d\n", erab->elements[0].su_res.transp_layer_addr);
+	//ntohl ??
+	ie+=sizeof(unsigned int);
+
+	memcpy(&(erab->elements[0].su_res.gtp_teid), ie, sizeof(unsigned int));
+	erab->elements[0].su_res.gtp_teid = ntohl(erab->elements[0].su_res.gtp_teid);
+	log_msg(LOG_INFO, "eRAB - Teid : %d\n", erab->elements[0].su_res.gtp_teid);
+	//ntohl ??
+}
+
+void
+parse_nas_pdu(char *msg,  int nas_msg_len, struct nasPDU *nas,
+		unsigned short proc_code)
+{
+	log_msg(LOG_INFO, "NAS PDU proc code: %u\n", proc_code);
+
+	unsigned short msg_len = nas_msg_len;
+
+	char *buffer = NULL;
+	log_msg(LOG_INFO, "NAS PDU msg: %s\n", msg_to_hex_str(msg, msg_len, &buffer));
+	log_buffer_free(&buffer);
+
+#if 0
+	if(S1AP_UL_NAS_TX_MSG_CODE == proc_code) {
+		/*check whether there is security header*/
+		unsigned char header_type;
+		memcpy(&header_type, msg+1, 1);
+		header_type >>= 4;
+		if(0 == header_type) { /*not security header*/
+			log_msg(LOG_INFO, "No security header\n");
+			memcpy(&(nas->header), msg+1, 2);/*copy only till msg type*/
+		} else {
+			log_msg(LOG_INFO, "Security header\n");
+			/*now for esm resp, there is procedure tx identity, why the hell it was not there before.*/
+			/*one more donkey logic, do something!!*/
+			if(4 == header_type || ((7 == (*(msg+7) & 7)))) {
+				memcpy(&(nas->header), msg+7, 2);/*copy only till msg type*/
+				offset = 9;
+			} else {
+				unsigned char tmp;
+				memcpy(&(nas->header.message_type), msg+9, 1);/*copy only till msg type*/
+				memcpy(&(tmp), msg+7, 1);/*copy only till msg type*/
+				nas->header.security_header_type = tmp;
+				offset = 10;
+			}
+		}
+	} else {
+		memcpy(&(nas->header), msg+2, sizeof(nas_pdu_header));
+	}
+
+	if(S1AP_UL_NAS_TX_MSG_CODE == proc_code) {
+		/*check whether there is security header*/
+		unsigned char header_type = 0;
+
+		memcpy(&header_type, msg+1, 1);
+		header_type >>= 4;
+		if(0 == header_type) { /*not security header*/
+			log_msg(LOG_INFO, "No security header\n");
+			memcpy(&(nas->header), msg+1, 2);/*copy only till msg type*/
+		} else {
+			log_msg(LOG_INFO, "Security header\n");
+			/*now for esm resp, there is procedure tx identity, why the hell it was not there before.*/
+			/*one more donkey logic, do something!!*/
+			if(4 == header_type || ((7 == (*(msg+7) & 7)))) {
+				log_msg(LOG_INFO, "header == 4 || 7\n");
+				if(header_type == 4 || header_type == 2) {
+				log_msg(LOG_INFO, "security - cihpered\n");
+				 memcpy(&(nas->header), msg+7, 2);/*copy only till msg type*/
+				 offset = 9;
+				}
+				else {
+				log_msg(LOG_INFO, "security - noned\n");
+				memcpy(&(nas->header), msg+1, 2);/*copy only till msg type*/
+				offset = 3;
+				}
+			} else {
+				unsigned char tmp;
+				memcpy(&(nas->header.message_type), msg+9, 1);/*copy only till msg type*/
+				memcpy(&(tmp), msg+7, 1);/*copy only till msg type*/
+				nas->header.security_header_type = tmp;
+				offset = 10;
+			}
+		}
+	} else if (S1AP_INITIAL_UE_MSG_CODE == proc_code ) {
+#endif
+
+		nas_pdu_header_sec nas_header_sec;
+		nas_pdu_header_short nas_header_short;
+		nas_pdu_header_long nas_header_long;
+
+		unsigned char sec_header_type;
+		unsigned char protocol_discr;
+
+		sec_header_type = msg[0] >> 4;
+		protocol_discr = msg[0] & 0x0F;
+		unsigned char is_ESM = ((unsigned short)protocol_discr == 0x02);  // see TS 24.007
+		log_msg(LOG_INFO, "Security header=%d\n", sec_header_type);
+		log_msg(LOG_INFO, "Protocol discriminator=%d\n", protocol_discr);
+		log_msg(LOG_INFO, "is_ESM=%d\n", is_ESM);
+
+		if(0 != sec_header_type) { /*security header*/
+			log_msg(LOG_INFO, "Security header\n");
+
+			memcpy(&nas_header_sec, msg, sizeof(nas_pdu_header_sec));
+
+			char *buffer = NULL;
+			log_msg(LOG_INFO, "mac=%s\n", msg_to_hex_str((char *)nas_header_sec.mac, MAC_SIZE, &buffer));
+	        log_buffer_free(&buffer);
+
+			log_msg(LOG_INFO, "seq no=%x\n", nas_header_sec.seq_no);
+			msg += 6;
+
+			sec_header_type = msg[0] >> 4;
+			protocol_discr = msg[0] & 0x0F;
+			unsigned char is_ESM = ((unsigned short)protocol_discr == 0x02);  // see TS 24.007
+			log_msg(LOG_INFO, "Security header=%d\n", sec_header_type);
+			log_msg(LOG_INFO, "Protocol discriminator=%d\n", protocol_discr);
+			log_msg(LOG_INFO, "is_ESM=%d\n", is_ESM);
+			if (is_ESM) {
+				log_msg(LOG_INFO, "NAS PDU is ESM\n");
+				memcpy(&nas_header_long, msg, sizeof(nas_header_long)); /*copy only till msg type*/
+				msg += 3;
+
+				nas->header.security_header_type = nas_header_long.security_header_type;
+				nas->header.proto_discriminator = nas_header_long.proto_discriminator;
+				nas->header.procedure_trans_identity = nas_header_long.procedure_trans_identity;
+				nas->header.message_type = nas_header_long.message_type;
+			} else {
+				log_msg(LOG_INFO, "NAS PDU is EMM\n");
+				memcpy(&nas_header_short, msg, sizeof(nas_header_short)); /*copy only till msg type*/
+				msg += 2;
+
+				nas->header.security_header_type = nas_header_short.security_header_type;
+				nas->header.proto_discriminator = nas_header_short.proto_discriminator;
+				nas->header.message_type = nas_header_short.message_type;
+			}
+		} else {
+			log_msg(LOG_INFO, "No security header\n");
+			memcpy(&nas_header_short, msg, sizeof(nas_header_short)); /*copy only till msg type*/
+			msg += 2;
+
+			nas->header.security_header_type = nas_header_short.security_header_type;
+			nas->header.proto_discriminator = nas_header_short.proto_discriminator;
+			nas->header.message_type = nas_header_short.message_type;
+		}
+
+
+	log_msg(LOG_INFO, "Nas msg type: %X\n", nas->header.message_type);
+
+	switch(nas->header.message_type) {
+	case NAS_ESM_RESP:{
+		log_msg(LOG_INFO, "NAS_ESM_RESP recvd\n");
+
+		unsigned char element_id;
+		memcpy(&element_id, msg, 1);
+		msg++;
+		nas->elements_len +=1;
+
+		nas->elements = calloc(sizeof(nas_pdu_elements), 2);
+		//if(NULL == nas.elements)...
+
+		memcpy(&(nas->elements[0].apn.len), msg, 1);
+		msg++;
+		memcpy(nas->elements[0].apn.val, msg, nas->elements[0].apn.len);
+		log_msg(LOG_INFO, "APN name - %s\n", nas->elements[0].apn.val);
+		break;
+		}
+
+	case NAS_SEC_MODE_COMPLETE:
+		log_msg(LOG_INFO, "NAS_SEC_MODE_COMPLETE recvd\n");
+		break;
+
+	case NAS_AUTH_RESP:
+		log_msg(LOG_INFO, "NAS_AUTH_RESP recvd\n");
+		nas->elements_len = 1;
+		nas->elements = calloc(sizeof(nas_pdu_elements), 5);
+		//if(NULL == nas.elements)...
+		unsigned short len = get_length(&msg);
+		memcpy(&(nas->elements[0].auth_resp), msg, sizeof(struct XRES));
+
+		break;
+
+/*	case NAS_AUTH_FAILURE:
+		nas->elements_len = 1;
+		nas->elements = calloc(sizeof(nas_pdu_elements), 1);
+		//if(NULL == nas.elements)...
+        char err = *(char*)(msg);
+        if(err == AUTH_SYNC_FAILURE)
+        {
+            log_msg(LOG_INFO, "AUTH Sync Failure. Start Re-Sync");
+            memcpy(&(nas->elements[0].auth_fail_resp), msg + 2, sizeof(struct AUTS));
+        }
+        else
+        {
+            log_msg(LOG_ERROR, "Authentication Failure. Mac Failure");
+        }
+
+		break;
+*/
+	case NAS_ATTACH_REQUEST:{
+		log_msg(LOG_INFO, "NAS_ATTACH_REQUEST recvd\n");
+		//msg += offset;
+		//short offset = 0;
+		unsigned char tmp = msg[0];
+		nas->header.security_encryption_algo = (tmp & 0xF0) >> 4;
+		nas->header.security_integrity_algo = tmp & 0x0F;
+		msg++;
+
+		nas->elements_len = 6;
+		nas->elements = calloc(sizeof(nas_pdu_elements), 6);
+		//if(NULL == nas.elements)...
+
+		/*EPS mobility identity*/
+		//memcpy(&(nas->elements[0].IMSI), msg+6, BINARY_IMSI_LEN);
+		/*TODO: This encoding/decoding has issue with sprirent and ng40. IMSI
+		 * is packed differently.*/
+		/*Code working with ng40 */
+		unsigned short imsi_len = get_length(&msg);
+		log_msg(LOG_INFO, "IMSI len=%u - %u\n", imsi_len, BINARY_IMSI_LEN);
+		memcpy(&(nas->elements[0].IMSI), msg, imsi_len);
+		msg += imsi_len;
+
+		/*Code working with sprirent and Polaris*/
+		/*
+		memcpy(&(nas->elements[0].IMSI), msg+5, BINARY_IMSI_LEN);
+		offset = 5 + BINARY_IMSI_LEN ;
+		*/
+
+		char *buffer = NULL;
+		log_msg(LOG_INFO, "IMSI=%s [to be read nibble-swapped]\n",
+			msg_to_hex_str((char *)nas->elements[0].IMSI, imsi_len, &buffer));
+	    log_buffer_free(&buffer);
+
+		/*UE network capacity*/
+		nas->elements[1].ue_network.len = msg[0];
+		msg++;
+		memcpy((nas->elements[1].ue_network.capab), msg, nas->elements[1].ue_network.len);
+		msg += nas->elements[1].ue_network.len;
+
+		/*ESM msg container*/
+		len = msg[0] << 8 | msg[1];
+		msg += 2;
+		log_msg(LOG_INFO, "len=%x\n", len);
+		log_msg(LOG_INFO, "msg[0]=%x\n", msg[0]);
+		nas->elements[5].pti = msg[1];
+		unsigned char val = msg[4];
+		log_msg(LOG_INFO, "pti=%x\n", nas->elements[5].pti);
+		log_msg(LOG_INFO, "val=%x\n", val);
+		/*ESM message header len is 4: bearer_id_flags(1)+proc_tx_id(1)+msg_id(1)
+		 * +pdn_type(1)*/
+		/*element id 13(1101....) = "esm required" flag*/
+		nas->elements[2].esm_info_tx_required = false;
+		if(13 == (val>>4)) {
+			nas->elements[2].esm_info_tx_required = true;
+			if(val & 1) {
+				nas->elements[2].esm_info_tx_required = true;
+			}
+		}
+		msg += len;
+
+		/*DRX parameter*/
+		msg += 3;
+
+		/*MS network capability*/
+		nas->elements[4].ms_network.element_id = msg[0];
+		msg++;
+		nas->elements[4].ms_network.len = msg[0];
+		msg++;
+		memcpy(nas->elements[4].ms_network.capab, msg,
+			nas->elements[4].ms_network.len);
+		log_msg(LOG_INFO, "element_id=%x\n", nas->elements[4].ms_network.element_id);
+		log_msg(LOG_INFO, "len=%x\n", nas->elements[4].ms_network.len);
+		log_msg(LOG_INFO, "network.capab=%s\n", msg_to_hex_str((char *)nas->elements[4].ms_network.capab, nas->elements[4].ms_network.len, &buffer));
+		log_buffer_free(&buffer);
+
+		break;
+		}
+
+	case NAS_ATTACH_COMPLETE:
+		log_msg(LOG_INFO, "NAS_ATTACH_COMPLETE recvd\n");
+		/*Other than error check there seems no information to pass to mme. Marking TODO for protocol study*/
+		break;
+
+	case NAS_DETACH_REQUEST: {
+		log_msg(LOG_INFO, "NAS_DETACH_REQUEST recvd\n");
+		nas->elements_len = 1;
+		nas->elements = calloc(sizeof(nas_pdu_elements), 1);
+
+		/*EPS mobility identity*/
+		memcpy(&(nas->elements[0].mi_guti), msg + 11, sizeof(guti));
+		log_msg(LOG_INFO, "M-TMSI - %d\n", nas->elements[0].mi_guti.m_TMSI);
+		break;
+	}
+	
+	case NAS_DETACH_ACCEPT: {
+		 log_msg(LOG_INFO, "NAS_DETACH_ACCEPT recvd\n");
+		 nas->elements_len = 1;
+         nas->elements = calloc(sizeof(nas_pdu_elements), 1);
+
+         /*EPS mobility identity*/
+         memcpy(&(nas->elements[0].mi_guti), msg + 11, sizeof(guti));
+         log_msg(LOG_INFO, "M-TMSI - %d\n", nas->elements[0].mi_guti.m_TMSI);
+         break;
+     }
+
+	default:
+		log_msg(LOG_ERROR, "Unknown NAS IE type- 0x%x\n", nas->header.message_type);
+		break;
+
+	}
+}
+
+
+int
+parse_IEs(char *msg, struct proto_IE *proto_ies, unsigned short proc_code)
+{
+	unsigned short int no_of_IEs=0;
+
+	//short data_size=0;
+	//msg +=1;
+	//memcpy(&data_size, msg, 1);
+
+	//msg +=2;
+	memcpy(&no_of_IEs, msg, 2);
+	//no_of_IEs=msg[0];
+	no_of_IEs = ntohs(no_of_IEs);
+
+	/*Dumb logic....protocol or is creepy. Len sometimes comes in 3 bytes. How to know that??*/
+	if(0 == no_of_IEs) {
+		++msg;
+		memcpy(&no_of_IEs, msg, 2);
+		no_of_IEs = ntohs(no_of_IEs);
+	}
+
+	log_msg(LOG_INFO, "No. of IEs = %d\n", no_of_IEs);
+	proto_ies->no_of_IEs = no_of_IEs;
+	proto_ies->data = calloc(sizeof(struct proto_IE_data), no_of_IEs);
+	//alloc fail chk
+	msg+=2;
+
+	for(int i=0; i < no_of_IEs; ++i) {
+		struct proto_IE_data *ie = &(proto_ies->data[i]);
+		unsigned short IE_type, IE_data_len = 0;
+
+		memcpy(&IE_type, msg, sizeof(short int));
+		IE_type = ntohs(IE_type);
+		ie->IE_type = IE_type;
+		msg +=2;//next to ie type
+		msg +=1;//next to criticality
+
+		IE_data_len = get_length(&msg);
+		log_msg(LOG_INFO, "IE [%d]: type = %d\n", i, IE_type);
+		log_msg(LOG_INFO, "IE [%d]: data len= %x - %u\n", i, IE_data_len, IE_data_len);
+
+		char *buffer = NULL;
+		log_msg(LOG_INFO, "IE [%d]: value= %s\n", i, msg_to_hex_str(msg, IE_data_len, &buffer));
+	    log_buffer_free(&buffer);
+
+		/*Based on IE_Type call the parser to read IE info*/
+		/*TODO: optimize with function ptr etc.*/
+		switch(IE_type) {
+		case S1AP_IE_GLOBAL_ENB_ID:
+			log_msg(LOG_INFO, "IE [%d]: parse global eNB ID\n", i);
+			ie_parse_global_enb_id(msg+6, IE_data_len);
+			break;
+
+		case S1AP_IE_ENB_NAME:
+			log_msg(LOG_INFO, "IE [%d]: parse global eNB name\n", i);
+			ie_parse_enb_name(msg, IE_data_len);
+			break;
+
+		case S1AP_IE_SUPPORTED_TAS:
+			break;
+
+		case S1AP_IE_DEF_PAGING_DRX:
+			break;
+
+		case S1AP_IE_MME_UE_ID:{
+			ie->val.mme_ue_s1ap_id = decode_int_val((unsigned char *)msg,
+					IE_data_len);
+			log_msg(LOG_INFO, "IE [%d]: parse MME_UE_S1AP_ID - %d\n", i,
+					ie->val.mme_ue_s1ap_id);
+			break;
+			}
+
+		case S1AP_IE_ENB_UE_ID:{
+			ie->val.enb_ue_s1ap_id = decode_int_val((unsigned char *)msg,
+					IE_data_len);
+			log_msg(LOG_INFO, "IE [%d]: parse ENB_UE_S1AP_ID - %d\n", i,
+					ie->val.enb_ue_s1ap_id);
+			break;
+			}
+
+		case S1AP_IE_TAI:{
+			log_msg(LOG_INFO, "IE [%d]: TAI parse\n", i);
+			memcpy(&(ie->val.tai), msg+1, sizeof(struct TAI));
+			log_msg(LOG_INFO, "IE [%d]: plmn-%x %x %x, tac-%d\n", i,
+					ie->val.tai.plmn_id.idx[0],
+					ie->val.tai.plmn_id.idx[1], ie->val.tai.plmn_id.idx[2],
+					ie->val.tai.tac);
+			break;
+			}
+
+		case S1AP_IE_UTRAN_CGI:{
+			log_msg(LOG_INFO, "IE [%d]: EUTRAN CGI\n", i);
+			memset(&(ie->val.utran_cgi), 0, sizeof(struct CGI));
+			memcpy(&(ie->val.utran_cgi), msg+1, sizeof(struct CGI));
+			log_msg(LOG_INFO, "IE [%d]: plmn-%x %x %x, cell-%d\n", i,
+					ie->val.utran_cgi.plmn_id.idx[0],
+					ie->val.utran_cgi.plmn_id.idx[1], ie->val.utran_cgi.plmn_id.idx[2],
+					ie->val.utran_cgi.cell_id);
+			break;
+			}
+
+		case S1AP_IE_NAS_PDU: {
+	        log_msg(LOG_INFO, "IE [%d]: NAS msg type parsed = %x\n", i,
+                            ie->val.nas.header.message_type);
+			parse_nas_pdu(msg, IE_data_len, &ie->val.nas, proc_code);
+			break;
+			}
+
+		case S1AP_IE_RRC_EST_CAUSE: {
+			log_msg(LOG_INFO, "IE [%d]: parse RRC establishment code - %d\n", i, 
+                     ie->val.rrc_est_cause);
+			break;
+			}
+
+		case S1AP_ERAB_SETUP_CTX_SUR:
+			log_msg(LOG_INFO, "IE [%d]: parse S1AP_ERAB_SETUP_CTX_SUR parse_erab_pdu \n", i);
+			parse_erab_pdu(msg, IE_data_len, &ie->val.erab);
+			break;
+
+		default:
+			log_msg(LOG_INFO, "IE [%d]: Check IE type %d\n", i, IE_type);
+			break;
+		}
+
+		msg += (IE_data_len);
+		if(128 == IE_data_len) ++msg;//TODO: byte size issue. chk thi.
+	}
+	return 0;
+}
+
+int convertToInitUeProtoIe(InitiatingMessage_t *msg, struct proto_IE* proto_ies)
+{
+    proto_ies->procedureCode = msg->procedureCode;
+    proto_ies->criticality = msg->criticality;
+	int no_of_IEs = 0;
+
+    if(msg->value.present == InitiatingMessage__value_PR_InitialUEMessage)
+    {
+        ProtocolIE_Container_129P32_t* protocolIes = &msg->value.choice.InitialUEMessage.protocolIEs;
+        no_of_IEs = protocolIes->list.count;
+        proto_ies->no_of_IEs = no_of_IEs;
+
+        log_msg(LOG_INFO, "No of IEs = %d\n", no_of_IEs);
+        proto_ies->data = calloc(sizeof(struct proto_IE_data), no_of_IEs);
+        if(proto_ies->data == NULL)
+        {
+            log_msg(LOG_ERROR,"Malloc failed for protocol IE.");
+            return -1;
+        }
+		for (int i = 0; i < protocolIes->list.count; i++) {
+			InitialUEMessage_IEs_t *ie_p;
+			ie_p = protocolIes->list.array[i];
+			switch(ie_p->id) {
+				case ProtocolIE_ID_id_eNB_UE_S1AP_ID:
+					{
+                        ENB_UE_S1AP_ID_t *s1apENBUES1APID_p = NULL;
+                        if(InitialUEMessage_IEs__value_PR_ENB_UE_S1AP_ID == ie_p->value.present)
+                        {
+						    s1apENBUES1APID_p = &ie_p->value.choice.ENB_UE_S1AP_ID;
+                        }
+						
+                        if (s1apENBUES1APID_p == NULL) {
+							log_msg (LOG_ERROR, "Decoding of IE eNB_UE_S1AP_ID failed\n");
+							return -1;
+						}
+
+                        log_msg(LOG_DEBUG, "ENB UE S1ap ID decode Success\n", no_of_IEs);
+                        proto_ies->data[i].IE_type = S1AP_IE_ENB_UE_ID; 
+						memcpy(&proto_ies->data[i].val.enb_ue_s1ap_id, s1apENBUES1APID_p, sizeof(ENB_UE_S1AP_ID_t));
+						s1apENBUES1APID_p = NULL;
+					} break;
+				case ProtocolIE_ID_id_NAS_PDU:
+					{
+                        NAS_PDU_t *s1apNASPDU_p = NULL;
+                        if(InitialUEMessage_IEs__value_PR_NAS_PDU == ie_p->value.present)
+                        {
+						    s1apNASPDU_p = &ie_p->value.choice.NAS_PDU;
+                        }
+						
+                        if (s1apNASPDU_p == NULL) {
+							log_msg (LOG_ERROR, "Decoding of IE NAS PDU failed\n");
+							return -1;
+						}
+
+                        log_msg(LOG_DEBUG, "NAS PDU decode Success\n", no_of_IEs);
+                        proto_ies->data[i].IE_type = S1AP_IE_NAS_PDU; 
+                        parse_nas_pdu((char*)s1apNASPDU_p->buf, s1apNASPDU_p->size, 
+                                       &proto_ies->data[i].val.nas, msg->procedureCode);
+						s1apNASPDU_p = NULL;
+					} break;
+				case ProtocolIE_ID_id_TAI:
+					{
+                        TAI_t *s1apTAI_p = NULL;
+                        if(InitialUEMessage_IEs__value_PR_TAI == ie_p->value.present)
+                        {
+						    s1apTAI_p = &ie_p->value.choice.TAI;
+                        }
+						
+                        if (s1apTAI_p == NULL) {
+							log_msg (LOG_ERROR, "Decoding of IE TAI failed\n");
+							return -1;
+						}
+
+                        log_msg(LOG_DEBUG, "TAI decode Success\n", no_of_IEs);
+                        proto_ies->data[i].IE_type = S1AP_IE_TAI; 
+						memcpy(&proto_ies->data[i].val.tai.tac, s1apTAI_p->tAC.buf, s1apTAI_p->tAC.size);
+						memcpy(&proto_ies->data[i].val.tai.plmn_id, 
+                                s1apTAI_p->pLMNidentity.buf, s1apTAI_p->pLMNidentity.size);
+						s1apTAI_p = NULL;
+					} break;
+				case ProtocolIE_ID_id_EUTRAN_CGI:
+					{
+			            EUTRAN_CGI_t*	 s1apCGI_p = NULL;;
+                        if(InitialUEMessage_IEs__value_PR_EUTRAN_CGI == ie_p->value.present)
+                        {
+						    s1apCGI_p = &ie_p->value.choice.EUTRAN_CGI;
+                        }
+						
+                        if (s1apCGI_p == NULL) {
+							log_msg (LOG_ERROR, "Decoding of IE CGI failed\n");
+							return -1;
+						}
+
+                        log_msg(LOG_DEBUG, "CGI decode Success\n", no_of_IEs);
+                        proto_ies->data[i].IE_type = S1AP_IE_UTRAN_CGI; 
+						memcpy(&proto_ies->data[i].val.utran_cgi.cell_id, 
+                               s1apCGI_p->cell_ID.buf, s1apCGI_p->cell_ID.size);
+						memcpy(&proto_ies->data[i].val.utran_cgi.plmn_id.idx, 
+                                s1apCGI_p->pLMNidentity.buf, s1apCGI_p->pLMNidentity.size);
+						s1apCGI_p = NULL;
+					} break;
+				case ProtocolIE_ID_id_RRC_Establishment_Cause:
+					{
+			            RRC_Establishment_Cause_t	 *s1apRRCEstCause_p;
+                        if(InitialUEMessage_IEs__value_PR_RRC_Establishment_Cause == ie_p->value.present)
+                        {
+						    s1apRRCEstCause_p = &ie_p->value.choice.RRC_Establishment_Cause;
+                        }
+						
+                        if (s1apRRCEstCause_p == NULL) {
+							log_msg (LOG_ERROR, "Decoding of IE RRC Cause failed\n");
+							return -1;
+						}
+
+                        log_msg(LOG_DEBUG, "RRC Cause decode Success\n", no_of_IEs);
+                        proto_ies->data[i].IE_type = S1AP_IE_RRC_EST_CAUSE; 
+						proto_ies->data[i].val.rrc_est_cause = (enum ie_RRC_est_cause) *s1apRRCEstCause_p;
+						s1apRRCEstCause_p = NULL;
+					} break;
+                default:
+                    {
+                        log_msg(LOG_WARNING, "Unhandled IE %d", ie_p->id);
+                    }
+			}
+		}
+     }
+
+    return 0;
+}
+
+static int
+init_ue_msg_handler(InitiatingMessage_t *msg, int enb_fd)
+{
+	//TODO: use static instead of synamic for perf.
+	struct proto_IE proto_ies;
+
+	log_msg(LOG_INFO, "S1AP_INITIAL_UE_MSG msg: \n");
+
+    convertToInitUeProtoIe(msg, &proto_ies);
+	/*Check nas message type*/
+	//TODO: check through all proto IEs for which is nas
+	//currentlyy hard coding to 2 looking at packets
+	log_msg(LOG_INFO, "NAS msg type parsed = %x\n", proto_ies.data[1].val.nas.header.message_type);
+	switch(proto_ies.data[1].val.nas.header.message_type) {
+	case NAS_ATTACH_REQUEST:
+		s1_init_ue_handler(&proto_ies, enb_fd);
+		break;
+
+	case NAS_DETACH_REQUEST:
+		detach_stage1_handler(&proto_ies, true);
+		break;
+		
+	case NAS_DETACH_ACCEPT:
+		detach_accept_from_ue_handler(&proto_ies, true);
+		break;
+	}
+
+	free(proto_ies.data);
+	//TODO: free IEs
+	return SUCCESS;
+}
+
+static int
+UL_NAS_msg_handler(InitiatingMessage_t *msg, int enb_fd)
+{
+	//TODO: use static instead of synamic for perf.
+	struct proto_IE proto_ies;
+
+	log_msg(LOG_INFO, "S1AP_UL_NAS_TX_MSG msg \n");
+
+    convertUplinkNasToProtoIe(msg, &proto_ies);
+
+	/*Check nas message type*/
+	//TODO: check through all proto IEs for which is nas
+	//currentlyy hard coding to 2 looking at packets
+	log_msg(LOG_INFO, "NAS msg type = %x\n", proto_ies.data[2].val.nas.header.message_type);
+	switch(proto_ies.data[2].val.nas.header.message_type) {
+	case NAS_AUTH_RESP:
+		s1_auth_resp_handler(&proto_ies);
+		break;
+/*
+	case NAS_AUTH_FAILURE:
+		s1_auth_fail_handler(&proto_ies);
+		break;
+*/
+	case NAS_ATTACH_REQUEST:
+		s1_init_ue_handler(&proto_ies, enb_fd);
+		break;
+
+	case NAS_SEC_MODE_COMPLETE:
+		s1_secmode_resp_handler(&proto_ies);
+		break;
+
+/*	case NAS_ESM_RESP:
+		s1_esm_resp_handler(&proto_ies);
+		break;
+*/
+	case NAS_ATTACH_COMPLETE:
+		s1_attach_complete_handler(&proto_ies);
+		break;
+
+	case NAS_DETACH_REQUEST:
+		detach_stage1_handler(&proto_ies, false);
+		break;
+		
+	case NAS_DETACH_ACCEPT:
+		detach_accept_from_ue_handler(&proto_ies, false);
+		break;
+	}
+
+	//TODO: free IEs
+	free(proto_ies.data);
+	return SUCCESS;
+}
+
+void
+handle_s1ap_message(void *msg)
+{
+	log_msg(LOG_INFO, "Inside handle_s1ap_message.\n");
+	/*convert message from network to host*/
+
+	/*Call handler for the procedure code. TBD: Tasks pool for handlers*/
+
+	int enb_fd = 0;
+    	int msg_size = 0;
+	memcpy(&enb_fd, msg, sizeof(int));
+	memcpy(&msg_size, msg + sizeof(int), sizeof(int));
+	char *message = ((char *) msg) + 2*sizeof(int);
+	S1AP_PDU_t                              pdu = {(S1AP_PDU_PR_NOTHING)};
+	S1AP_PDU_t                             *pdu_p = &pdu;
+	asn_dec_rval_t                          dec_ret = {(RC_OK)};
+	memset ((void *)pdu_p, 0, sizeof (S1AP_PDU_t));
+	dec_ret = aper_decode (NULL, &asn_DEF_S1AP_PDU, (void **)&pdu_p, message, msg_size, 0, 0);
+
+	if (dec_ret.code != RC_OK) {
+		log_msg(LOG_ERROR, "ASN Decode PDU Failed %d\n", dec_ret.consumed);
+        	free(msg);
+		return;
+	}
+
+	switch (pdu_p->present) {
+	    case S1AP_PDU_PR_initiatingMessage:
+            s1ap_mme_decode_initiating (pdu_p->choice.initiatingMessage, enb_fd);
+            break;
+        case S1AP_PDU_PR_successfulOutcome:
+            s1ap_mme_decode_successfull_outcome (pdu_p->choice.successfulOutcome);
+            break;
+        case S1AP_PDU_PR_unsuccessfulOutcome:
+            s1ap_mme_decode_unsuccessfull_outcome (pdu_p->choice.unsuccessfulOutcome);
+            break;
+        default:
+            log_msg(LOG_WARNING, "Unknown message outcome (%d) or not implemented", (int)pdu_p->present);
+            break;
+      }
+
+    return;
+}
+
+int
+s1ap_mme_decode_successfull_outcome (SuccessfulOutcome_t* msg)
+{
+    log_msg(LOG_DEBUG,"successful outcome decode :");
+    log_msg(LOG_INFO, "proc code %d\n", msg->procedureCode);
+  switch (msg->procedureCode) {
+
+	case S1AP_INITIAL_CTX_RESP_CODE:
+		s1_init_ctx_resp_handler(msg);
+		break;
+	
+	case S1AP_UE_CONTEXT_RELEASE_CODE:
+		s1_ctx_release_complete_handler(msg);
+		break;
+		
+	default:
+		log_msg(LOG_ERROR, "Unknown procedure code - %d\n",
+		         msg->procedureCode & 0x00FF);
+		break;
+	}
+	
+	return 0;
+}
+
+int
+s1ap_mme_decode_unsuccessfull_outcome (UnsuccessfulOutcome_t *msg)
+{
+    log_msg(LOG_DEBUG,"unsuccessful outcome decode : TBD");
+    return 0;
+}
+
+int
+s1ap_mme_decode_initiating (InitiatingMessage_t *initiating_p, int enb_fd) 
+{
+  log_msg(LOG_INFO, "proc code %d\n", initiating_p->procedureCode);
+  switch (initiating_p->procedureCode) {
+
+	case S1AP_SETUP_REQUEST_CODE:
+		s1_setup_handler(initiating_p, enb_fd);
+		break;
+
+	case S1AP_INITIAL_UE_MSG_CODE:
+		init_ue_msg_handler(initiating_p, enb_fd);
+		break;
+
+	case S1AP_UL_NAS_TX_MSG_CODE:
+		UL_NAS_msg_handler(initiating_p, enb_fd);
+		break;
+
+	/*case S1AP_UE_CTX_RELEASE_CODE:
+		s1_ctx_release_resp_handler(initiating_p);
+		break;*/
+		
+	case S1AP_UE_CONTEXT_RELEASE_REQUEST:
+		s1_ctx_release_request_handler(initiating_p);
+		break;
+
+	default:
+		log_msg(LOG_ERROR, "Unknown procedure code - %d\n",
+			initiating_p->procedureCode & 0x00FF);
+		break;
+	}
+	
+  //free(msg);
+	return 0;
+}
+
+int convertUplinkNasToProtoIe(InitiatingMessage_t *msg, struct proto_IE* proto_ies)
+{
+    proto_ies->procedureCode = msg->procedureCode;
+    proto_ies->criticality = msg->criticality;
+	int no_of_IEs = 0;
+
+    if(msg->value.present == InitiatingMessage__value_PR_UplinkNASTransport)
+    {
+        ProtocolIE_Container_129P33_t* protocolIes = &msg->value.choice.UplinkNASTransport.protocolIEs;
+        no_of_IEs = protocolIes->list.count;
+        proto_ies->no_of_IEs = no_of_IEs;
+
+        log_msg(LOG_INFO, "No of IEs = %d\n", no_of_IEs);
+        proto_ies->data = calloc(sizeof(struct proto_IE_data), no_of_IEs);
+        if(proto_ies->data == NULL)
+        {
+            log_msg(LOG_ERROR,"Malloc failed for protocol IE.");
+            return -1;
+        }
+		for (int i = 0; i < protocolIes->list.count; i++) {
+			UplinkNASTransport_IEs_t *ie_p;
+			ie_p = protocolIes->list.array[i];
+			switch(ie_p->id) {
+				case ProtocolIE_ID_id_eNB_UE_S1AP_ID:
+					{
+                        ENB_UE_S1AP_ID_t *s1apENBUES1APID_p = NULL;
+                        if(UplinkNASTransport_IEs__value_PR_ENB_UE_S1AP_ID == ie_p->value.present)
+                        {
+						    s1apENBUES1APID_p = &ie_p->value.choice.ENB_UE_S1AP_ID;
+                        }
+						
+                        if (s1apENBUES1APID_p == NULL) {
+							log_msg (LOG_ERROR, "Decoding of IE eNB_UE_S1AP_ID failed\n");
+							return -1;
+						}
+
+                        proto_ies->data[i].IE_type = S1AP_IE_ENB_UE_ID; 
+						memcpy(&proto_ies->data[i].val.enb_ue_s1ap_id, s1apENBUES1APID_p, sizeof(ENB_UE_S1AP_ID_t));
+						s1apENBUES1APID_p = NULL;
+					} break;
+				case ProtocolIE_ID_id_MME_UE_S1AP_ID:
+					{
+                        MME_UE_S1AP_ID_t *s1apMMEUES1APID_p = NULL;
+                        if(UplinkNASTransport_IEs__value_PR_MME_UE_S1AP_ID == ie_p->value.present)
+                        {
+						    s1apMMEUES1APID_p = &ie_p->value.choice.MME_UE_S1AP_ID;
+                        }
+						
+                        if (s1apMMEUES1APID_p == NULL) {
+							log_msg (LOG_ERROR, "Decoding of IE MME_UE_S1AP_ID failed\n");
+							return -1;
+						}
+
+                        proto_ies->data[i].IE_type = S1AP_IE_MME_UE_ID; 
+						memcpy(&proto_ies->data[i].val.mme_ue_s1ap_id, s1apMMEUES1APID_p, sizeof(MME_UE_S1AP_ID_t));
+						s1apMMEUES1APID_p = NULL;
+					} break;
+				case ProtocolIE_ID_id_NAS_PDU:
+					{
+                        NAS_PDU_t *s1apNASPDU_p = NULL;
+                        if(UplinkNASTransport_IEs__value_PR_NAS_PDU == ie_p->value.present)
+                        {
+						    s1apNASPDU_p = &ie_p->value.choice.NAS_PDU;
+                        }
+						
+                        if (s1apNASPDU_p == NULL) {
+							log_msg (LOG_ERROR, "Decoding of IE NAS PDU failed\n");
+							return -1;
+						}
+
+                        proto_ies->data[i].IE_type = S1AP_IE_NAS_PDU; 
+                        parse_nas_pdu((char*)s1apNASPDU_p->buf, s1apNASPDU_p->size, 
+                                       &proto_ies->data[i].val.nas, msg->procedureCode);
+						s1apNASPDU_p = NULL;
+					} break;
+				case ProtocolIE_ID_id_TAI:
+					{
+                        TAI_t *s1apTAI_p = NULL;
+                        if(UplinkNASTransport_IEs__value_PR_TAI == ie_p->value.present)
+                        {
+						    s1apTAI_p = &ie_p->value.choice.TAI;
+                        }
+						
+                        if (s1apTAI_p == NULL) {
+							log_msg (LOG_ERROR, "Decoding of IE TAI failed\n");
+							return -1;
+						}
+
+                        proto_ies->data[i].IE_type = S1AP_IE_TAI; 
+						memcpy(&proto_ies->data[i].val.tai.tac, s1apTAI_p->tAC.buf, s1apTAI_p->tAC.size);
+						memcpy(&proto_ies->data[i].val.tai.plmn_id, 
+                                s1apTAI_p->pLMNidentity.buf, s1apTAI_p->pLMNidentity.size);
+						s1apTAI_p = NULL;
+					} break;
+				case ProtocolIE_ID_id_EUTRAN_CGI:
+					{
+			            EUTRAN_CGI_t*	 s1apCGI_p = NULL;;
+                        if(UplinkNASTransport_IEs__value_PR_EUTRAN_CGI == ie_p->value.present)
+                        {
+						    s1apCGI_p = &ie_p->value.choice.EUTRAN_CGI;
+                        }
+						
+                        if (s1apCGI_p == NULL) {
+							log_msg (LOG_ERROR, "Decoding of IE CGI failed\n");
+							return -1;
+						}
+
+                        proto_ies->data[i].IE_type = S1AP_IE_UTRAN_CGI; 
+						memcpy(&proto_ies->data[i].val.utran_cgi.cell_id, 
+                               s1apCGI_p->cell_ID.buf, s1apCGI_p->cell_ID.size);
+						memcpy(&proto_ies->data[i].val.utran_cgi.plmn_id.idx, 
+                                s1apCGI_p->pLMNidentity.buf, s1apCGI_p->pLMNidentity.size);
+						s1apCGI_p = NULL;
+					} break;
+                default:
+                    {
+                        log_msg(LOG_WARNING, "Unhandled IE %d", ie_p->id);
+                    }
+			}
+		}
+     }
+
+    return 0;
+}
+
+int convertInitCtxRspToProtoIe(SuccessfulOutcome_t *msg, struct proto_IE* proto_ies)
+{
+    proto_ies->procedureCode = msg->procedureCode;
+    proto_ies->criticality = msg->criticality;
+	int no_of_IEs = 0;
+
+    if(msg->value.present == SuccessfulOutcome__value_PR_InitialContextSetupResponse)
+    {
+        ProtocolIE_Container_129P20_t* protocolIes 
+            = &msg->value.choice.InitialContextSetupResponse.protocolIEs;
+        no_of_IEs = protocolIes->list.count;
+        proto_ies->no_of_IEs = no_of_IEs;
+
+        log_msg(LOG_INFO, "No of IEs = %d\n", no_of_IEs);
+        proto_ies->data = calloc(sizeof(struct proto_IE_data), no_of_IEs);
+        if(proto_ies->data == NULL)
+        {
+            log_msg(LOG_ERROR,"Malloc failed for protocol IE.");
+            return -1;
+        }
+		for (int i = 0; i < protocolIes->list.count; i++) {
+			InitialContextSetupResponseIEs_t *ie_p;
+			ie_p = protocolIes->list.array[i];
+			switch(ie_p->id) {
+				case ProtocolIE_ID_id_eNB_UE_S1AP_ID:
+					{
+                        ENB_UE_S1AP_ID_t *s1apENBUES1APID_p = NULL;
+                        if(InitialContextSetupResponseIEs__value_PR_ENB_UE_S1AP_ID == ie_p->value.present)
+                        {
+						    s1apENBUES1APID_p = &ie_p->value.choice.ENB_UE_S1AP_ID;
+                        }
+						
+                        if (s1apENBUES1APID_p == NULL) {
+							log_msg (LOG_ERROR, "Decoding of IE eNB_UE_S1AP_ID failed\n");
+							return -1;
+						}
+
+                        proto_ies->data[i].IE_type = S1AP_IE_ENB_UE_ID; 
+						memcpy(&proto_ies->data[i].val.enb_ue_s1ap_id, s1apENBUES1APID_p, sizeof(ENB_UE_S1AP_ID_t));
+						s1apENBUES1APID_p = NULL;
+					} break;
+				case ProtocolIE_ID_id_MME_UE_S1AP_ID:
+					{
+                        MME_UE_S1AP_ID_t *s1apMMEUES1APID_p = NULL;
+                        if(InitialContextSetupResponseIEs__value_PR_MME_UE_S1AP_ID == ie_p->value.present)
+                        {
+						    s1apMMEUES1APID_p = &ie_p->value.choice.MME_UE_S1AP_ID;
+                        }
+						
+                        if (s1apMMEUES1APID_p == NULL) {
+							log_msg (LOG_ERROR, "Decoding of IE MME_UE_S1AP_ID failed\n");
+							return -1;
+						}
+
+                        proto_ies->data[i].IE_type = S1AP_IE_MME_UE_ID; 
+						memcpy(&proto_ies->data[i].val.mme_ue_s1ap_id, s1apMMEUES1APID_p, sizeof(MME_UE_S1AP_ID_t));
+						s1apMMEUES1APID_p = NULL;
+					} break;
+				case ProtocolIE_ID_id_E_RABSetupListCtxtSURes:
+					{
+                        E_RABSetupListCtxtSURes_t *s1apErabSetupList_p = NULL;
+                        if(InitialContextSetupResponseIEs__value_PR_E_RABSetupListCtxtSURes == ie_p->value.present)
+                        {
+						    s1apErabSetupList_p = &ie_p->value.choice.E_RABSetupListCtxtSURes;
+                        }
+						
+                        if (s1apErabSetupList_p == NULL) {
+							log_msg (LOG_ERROR, "Decoding of IE s1apErabSetupList failed\n");
+							return -1;
+						}
+
+                        proto_ies->data[i].IE_type = S1AP_ERAB_SETUP_CTX_SUR;
+                        proto_ies->data[i].val.erab.no_of_elements = s1apErabSetupList_p->list.count;
+                        proto_ies->data[i].val.erab.elements = calloc(sizeof(union eRAB_IE), 
+                                                                    s1apErabSetupList_p->list.count);
+                        if(proto_ies->data[i].val.erab.elements == NULL)
+                        {
+                            log_msg(LOG_ERROR,"Malloc failed for protocol IE: Erab elements.");
+                            break;;
+                        }
+                        for (int j = 0; 
+                             j < s1apErabSetupList_p->list.count; j++) 
+                        {
+                            E_RABSetupItemCtxtSUResIEs_t *ie_p;
+                            ie_p = (E_RABSetupItemCtxtSUResIEs_t*)s1apErabSetupList_p->list.array[j];
+                            switch(ie_p->id) {
+                                case ProtocolIE_ID_id_E_RABSetupItemCtxtSURes:
+                                    {
+                                        E_RABSetupItemCtxtSURes_t* s1apErabSetupItem_p = NULL;
+                                        if(E_RABSetupItemCtxtSUResIEs__value_PR_E_RABSetupItemCtxtSURes == ie_p->value.present)
+                                        {
+                                            s1apErabSetupItem_p = &ie_p->value.choice.E_RABSetupItemCtxtSURes;
+                                        }
+
+                                        if (s1apErabSetupItem_p == NULL) {
+                                            log_msg (LOG_ERROR, "Decoding of IE s1apErabSetupItem failed\n");
+                                            return -1;
+                                        }
+
+                                        proto_ies->data[i].val.erab.elements[j].su_res.eRAB_id 
+                                                 = (unsigned short)s1apErabSetupItem_p->e_RAB_ID;
+                                        memcpy(
+                                            &(proto_ies->data[i].val.erab.elements[j].su_res.gtp_teid),
+                                            s1apErabSetupItem_p->gTP_TEID.buf,
+                                            s1apErabSetupItem_p->gTP_TEID.size);
+                                        proto_ies->data[i].val.erab.elements[j].su_res.gtp_teid
+                                            = ntohl(proto_ies->data[i].val.erab.elements[j].su_res.gtp_teid);
+
+                                        memcpy(
+                                           &(proto_ies->data[i].val.erab.elements[j].su_res.transp_layer_addr),
+                                            s1apErabSetupItem_p->transportLayerAddress.buf,
+                                            s1apErabSetupItem_p->transportLayerAddress.size);
+                                        proto_ies->data[i].val.erab.elements[j].su_res.transp_layer_addr
+                                            = ntohl(proto_ies->data[i].val.erab.elements[j].su_res.transp_layer_addr);
+                                        s1apErabSetupItem_p = NULL;
+                                    }break;
+                                default:
+                                    {
+                                        log_msg(LOG_WARNING, "Unhandled List item %d", ie_p->id);
+                                    }
+                            }
+                        }
+
+						s1apErabSetupList_p = NULL;
+					} break;
+                default:
+                    {
+                        log_msg(LOG_WARNING, "Unhandled IE %d", ie_p->id);
+                    }
+			}
+		}
+     }
+
+    return 0;
+}
+
+int convertUeCtxRelComplToProtoIe(SuccessfulOutcome_t *msg, struct proto_IE* proto_ies)
+{
+    proto_ies->procedureCode = msg->procedureCode;
+    proto_ies->criticality = msg->criticality;
+	int no_of_IEs = 0;
+
+    if(msg->value.present == SuccessfulOutcome__value_PR_UEContextReleaseComplete)
+    {
+        ProtocolIE_Container_129P25_t* protocolIes 
+            = &msg->value.choice.UEContextReleaseComplete.protocolIEs;
+        no_of_IEs = protocolIes->list.count;
+        proto_ies->no_of_IEs = no_of_IEs;
+
+        log_msg(LOG_INFO, "No of IEs = %d\n", no_of_IEs);
+        proto_ies->data = calloc(sizeof(struct proto_IE_data), no_of_IEs);
+        if(proto_ies->data == NULL)
+        {
+            log_msg(LOG_ERROR,"Malloc failed for protocol IE.");
+            return -1;
+        }
+		for (int i = 0; i < protocolIes->list.count; i++) {
+			UEContextReleaseComplete_IEs_t *ie_p;
+			ie_p = protocolIes->list.array[i];
+			switch(ie_p->id) {
+				case ProtocolIE_ID_id_eNB_UE_S1AP_ID:
+					{
+                        ENB_UE_S1AP_ID_t *s1apENBUES1APID_p = NULL;
+                        if(UEContextReleaseComplete_IEs__value_PR_ENB_UE_S1AP_ID == ie_p->value.present)
+                        {
+						    s1apENBUES1APID_p = &ie_p->value.choice.ENB_UE_S1AP_ID;
+                        }
+						
+                        if (s1apENBUES1APID_p == NULL) {
+							log_msg (LOG_ERROR, "Decoding of IE eNB_UE_S1AP_ID failed\n");
+							return -1;
+						}
+
+                        proto_ies->data[i].IE_type = S1AP_IE_ENB_UE_ID; 
+						memcpy(&proto_ies->data[i].val.enb_ue_s1ap_id, s1apENBUES1APID_p, sizeof(ENB_UE_S1AP_ID_t));
+						s1apENBUES1APID_p = NULL;
+					} break;
+				case ProtocolIE_ID_id_MME_UE_S1AP_ID:
+					{
+                        MME_UE_S1AP_ID_t *s1apMMEUES1APID_p = NULL;
+                        if(UEContextReleaseComplete_IEs__value_PR_MME_UE_S1AP_ID == ie_p->value.present)
+                        {
+						    s1apMMEUES1APID_p = &ie_p->value.choice.MME_UE_S1AP_ID;
+                        }
+						
+                        if (s1apMMEUES1APID_p == NULL) {
+							log_msg (LOG_ERROR, "Decoding of IE MME_UE_S1AP_ID failed\n");
+							return -1;
+						}
+
+                        proto_ies->data[i].IE_type = S1AP_IE_MME_UE_ID; 
+						memcpy(&proto_ies->data[i].val.mme_ue_s1ap_id, s1apMMEUES1APID_p, sizeof(MME_UE_S1AP_ID_t));
+						s1apMMEUES1APID_p = NULL;
+					} break;
+                default:
+                    {
+                        log_msg(LOG_WARNING, "Unhandled IE %d\n", ie_p->id);
+                    }
+			}
+		}
+     }
+
+    return 0;
+}
+
+int convertUeCtxRelReqToProtoIe(InitiatingMessage_t *msg, struct proto_IE* proto_ies)
+{
+    proto_ies->procedureCode = msg->procedureCode;
+    proto_ies->criticality = msg->criticality;
+	int no_of_IEs = 0;
+
+    if(msg->value.present == InitiatingMessage__value_PR_UEContextReleaseRequest)
+    {
+        ProtocolIE_Container_129P23_t* protocolIes
+            = &msg->value.choice.UEContextReleaseRequest.protocolIEs;
+        no_of_IEs = protocolIes->list.count;
+        proto_ies->no_of_IEs = no_of_IEs;
+
+        log_msg(LOG_INFO, "No of IEs = %d\n", no_of_IEs);
+        proto_ies->data = calloc(sizeof(struct proto_IE_data), no_of_IEs);
+        if(proto_ies->data == NULL)
+        {
+            log_msg(LOG_ERROR,"Malloc failed for protocol IE.");
+            return -1;
+        }
+		for (int i = 0; i < protocolIes->list.count; i++) {
+			UEContextReleaseRequest_IEs_t *ie_p;
+			ie_p = protocolIes->list.array[i];
+			switch(ie_p->id) {
+				case ProtocolIE_ID_id_eNB_UE_S1AP_ID:
+					{
+                        ENB_UE_S1AP_ID_t *s1apENBUES1APID_p = NULL;
+                        if(UEContextReleaseRequest_IEs__value_PR_ENB_UE_S1AP_ID == ie_p->value.present)
+                        {
+						    s1apENBUES1APID_p = &ie_p->value.choice.ENB_UE_S1AP_ID;
+                        }
+
+                        if (s1apENBUES1APID_p == NULL) {
+							log_msg (LOG_ERROR, "Decoding of IE eNB_UE_S1AP_ID failed\n");
+							return -1;
+						}
+
+                        proto_ies->data[i].IE_type = S1AP_IE_ENB_UE_ID;
+						memcpy(&proto_ies->data[i].val.enb_ue_s1ap_id, s1apENBUES1APID_p, sizeof(ENB_UE_S1AP_ID_t));
+						s1apENBUES1APID_p = NULL;
+					} break;
+				case ProtocolIE_ID_id_MME_UE_S1AP_ID:
+					{
+                        MME_UE_S1AP_ID_t *s1apMMEUES1APID_p = NULL;
+                        if(UEContextReleaseRequest_IEs__value_PR_MME_UE_S1AP_ID == ie_p->value.present)
+                        {
+						    s1apMMEUES1APID_p = &ie_p->value.choice.MME_UE_S1AP_ID;
+                        }
+
+                        if (s1apMMEUES1APID_p == NULL) {
+							log_msg (LOG_ERROR, "Decoding of IE MME_UE_S1AP_ID failed\n");
+							return -1;
+						}
+
+                        proto_ies->data[i].IE_type = S1AP_IE_MME_UE_ID;
+						memcpy(&proto_ies->data[i].val.mme_ue_s1ap_id, s1apMMEUES1APID_p, sizeof(MME_UE_S1AP_ID_t));
+						s1apMMEUES1APID_p = NULL;
+					} break;
+				case ProtocolIE_ID_id_Cause:
+					{
+                        Cause_t *s1apCause_p = NULL;
+                        if(UEContextReleaseRequest_IEs__value_PR_Cause == ie_p->value.present)
+                        {
+						    s1apCause_p = &ie_p->value.choice.Cause;
+                        }
+
+                        if (s1apCause_p == NULL) {
+							log_msg (LOG_ERROR, "Decoding of IE Cause failed\n");
+							return -1;
+						}
+
+                        proto_ies->data[i].IE_type = S1AP_IE_CAUSE;
+                        proto_ies->data[i].val.cause.present = s1apCause_p->present;
+                        switch(s1apCause_p->present)
+                        {
+                            case Cause_PR_radioNetwork:
+							    log_msg (LOG_DEBUG, "RadioNetwork case : %d\n",
+                                          s1apCause_p->choice.radioNetwork);
+                                proto_ies->data[i].val.cause.choice.radioNetwork
+                                    = s1apCause_p->choice.radioNetwork;
+                                break;
+                            case Cause_PR_transport:
+							    log_msg (LOG_DEBUG, "Transport case : %d\n",
+                                          s1apCause_p->choice.transport);
+                                proto_ies->data[i].val.cause.choice.transport
+                                    = s1apCause_p->choice.transport;
+                                break;
+                            case Cause_PR_nas:
+							    log_msg (LOG_DEBUG, "Nas case : %d\n",
+                                          s1apCause_p->choice.nas);
+                                proto_ies->data[i].val.cause.choice.nas
+                                    = s1apCause_p->choice.nas;
+                                break;
+                            case Cause_PR_protocol:
+							    log_msg (LOG_DEBUG, "Protocol case : %d\n",
+                                          s1apCause_p->choice.protocol);
+                                proto_ies->data[i].val.cause.choice.protocol
+                                    = s1apCause_p->choice.protocol;
+                                break;
+                            case Cause_PR_misc:
+							    log_msg (LOG_DEBUG, "Misc case : %d\n",
+                                          s1apCause_p->choice.misc);
+                                proto_ies->data[i].val.cause.choice.misc
+                                    = s1apCause_p->choice.misc;
+                                break;
+                            case Cause_PR_NOTHING:
+                            default:
+                                log_msg(LOG_WARNING, "Unknown cause %d\n", s1apCause_p->present);
+
+                        }
+						s1apCause_p = NULL;
+					} break;
+                default:
+                    {
+                        log_msg(LOG_WARNING, "Unhandled IE %d\n", ie_p->id);
+                    }
+			}
+		}
+     }
+
+    return 0;
+}
+