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

Change-Id: Ie55032217232214ac8544ca76ea34335205329e4
diff --git a/src/s1ap/handlers/attach_authreq.c b/src/s1ap/handlers/attach_authreq.c
new file mode 100644
index 0000000..46981f3
--- /dev/null
+++ b/src/s1ap/handlers/attach_authreq.c
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 2003-2018, Great Software Laboratory Pvt. Ltd.
+ * Copyright (c) 2017 Intel Corporation
+ * Copyright (c) 2019, Infosys Ltd.
+ *
+ * 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 <pthread.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "log.h"
+#include "err_codes.h"
+#include "s1ap.h"
+#include "message_queues.h"
+#include "ipc_api.h"
+#include "main.h"
+#include "sctp_conn.h"
+#include "msgType.h"
+
+void
+buffer_copy(struct Buffer *buffer, void *value, size_t size)
+{
+	memcpy(buffer->buf + buffer->pos , value, size);
+	buffer->pos += size;
+	return;
+}
+
+/**
+* Get ProtocolIE value for Auth Request sent by mme-app
+*/
+static int
+get_authreq_protoie_value(struct proto_IE *value, struct authreq_info *g_authreqInfo)
+{
+	value->no_of_IEs = AUTH_REQ_NO_OF_IES;
+
+	value->data = (proto_IEs *) malloc(SEC_MODE_NO_OF_IES *
+			sizeof(proto_IEs));
+
+	value->data[0].val.mme_ue_s1ap_id = g_authreqInfo->ue_idx;
+	value->data[1].val.enb_ue_s1ap_id = g_authreqInfo->enb_s1ap_ue_id;
+
+	log_msg(LOG_INFO, "mme_ue_s1ap_id %d and enb_ue_s1ap_id %d\n",
+			g_authreqInfo->ue_idx, g_authreqInfo->enb_s1ap_ue_id);
+
+	/* TODO: Add enum for security header type */
+	value->data[2].val.nas.header.security_header_type = 0;
+	value->data[2].val.nas.header.proto_discriminator = EPSMobilityManagementMessages;
+	value->data[2].val.nas.header.message_type = AuthenticationRequest;
+	value->data[2].val.nas.header.nas_security_param = AUTHREQ_NAS_SECURITY_PARAM;
+
+	value->data[2].val.nas.elements = (nas_pdu_elements *)
+			malloc(AUTH_REQ_NO_OF_NAS_IES * sizeof(nas_pdu_elements));
+
+	memcpy(value->data[2].val.nas.elements[0].pduElement.rand,
+			g_authreqInfo->rand, NAS_RAND_SIZE);
+	memcpy(value->data[2].val.nas.elements[1].pduElement.autn,
+			g_authreqInfo->autn, NAS_AUTN_SIZE);
+
+
+	return SUCCESS;
+}
+
+
+/**
+* Stage specific message processing.
+*/
+static int
+authreq_processing(struct authreq_info *g_authreqInfo)
+{
+	struct Buffer g_buffer;
+	struct Buffer g_value_buffer;
+	struct Buffer g_nas_buffer;
+
+	struct s1ap_PDU s1apPDU= {0};
+
+	/* Assigning values to s1apPDU */
+	s1apPDU.procedurecode = id_downlinkNASTransport;
+	s1apPDU.criticality = CRITICALITY_IGNORE;
+
+	get_authreq_protoie_value(&s1apPDU.value, g_authreqInfo);
+
+	/* Copy values to buffer from s1apPDU */
+
+	g_buffer.pos = 0;
+
+	uint8_t initiating_message = 0; /* TODO: Add enum */
+	buffer_copy(&g_buffer, &initiating_message,
+			sizeof(initiating_message));
+
+	buffer_copy(&g_buffer, &s1apPDU.procedurecode,
+			sizeof(s1apPDU.procedurecode));
+
+	buffer_copy(&g_buffer, &s1apPDU.criticality,
+			sizeof(s1apPDU.criticality));
+
+	/* Copy values in g_value_buffer */
+	g_value_buffer.pos = 0;
+
+	/* TODO remove hardcoded values */
+	unsigned char chProtoIENo[3] = {0,0,3};
+
+	buffer_copy(&g_value_buffer, chProtoIENo, 3);
+
+	unsigned char tmpStr[4];
+	/* id-MME-UE-S1AP-ID */
+	uint16_t protocolIe_Id = id_MME_UE_S1AP_ID;
+	copyU16(tmpStr, protocolIe_Id);
+	buffer_copy(&g_value_buffer, tmpStr,
+					sizeof(protocolIe_Id));
+
+	uint8_t protocolIe_criticality = CRITICALITY_REJECT;
+	buffer_copy(&g_value_buffer, &protocolIe_criticality,
+					sizeof(protocolIe_criticality));
+
+	uint8_t datalen = 2;
+
+	/* TODO needs proper handling*/
+	unsigned char mme_ue_id[3];
+	datalen = copyU16(mme_ue_id,
+			s1apPDU.value.data[0].val.mme_ue_s1ap_id);
+	buffer_copy(&g_value_buffer, &datalen, sizeof(datalen));
+	buffer_copy(&g_value_buffer, mme_ue_id, datalen);
+
+	/* id-eNB-UE-S1AP-ID */
+
+	protocolIe_Id = id_eNB_UE_S1AP_ID;
+	copyU16(tmpStr, protocolIe_Id);
+	buffer_copy(&g_value_buffer, tmpStr,
+						sizeof(protocolIe_Id));
+
+	buffer_copy(&g_value_buffer, &protocolIe_criticality,
+					sizeof(protocolIe_criticality));
+
+
+	/* TODO needs proper handling*/
+	unsigned char enb_ue_id[3];
+	datalen = copyU16(enb_ue_id,
+			s1apPDU.value.data[1].val.enb_ue_s1ap_id);
+	buffer_copy(&g_value_buffer, &datalen, sizeof(datalen));
+	buffer_copy(&g_value_buffer, enb_ue_id, datalen);
+	//STIMER_GET_CURRENT_TP(g_attach_stats[s1apPDU.value.enb_ue_s1ap_id].esm_in);
+
+	/* id-NAS-PDU */
+	protocolIe_Id = id_NAS_PDU;
+	copyU16(tmpStr, protocolIe_Id);
+	buffer_copy(&g_value_buffer, tmpStr,
+						sizeof(protocolIe_Id));
+
+	buffer_copy(&g_value_buffer, &protocolIe_criticality,
+					sizeof(protocolIe_criticality));
+
+	struct nasPDU *nas = &(s1apPDU.value.data[2].val.nas);
+	uint8_t value = (nas->header.security_header_type) |
+			nas->header.proto_discriminator;
+
+	g_nas_buffer.pos = 0;
+
+	buffer_copy(&g_nas_buffer, &value, sizeof(value));
+
+	buffer_copy(&g_nas_buffer, &nas->header.message_type,
+						sizeof(nas->header.message_type));
+
+	buffer_copy(&g_nas_buffer, &nas->header.nas_security_param,
+						sizeof(nas->header.nas_security_param));
+
+	buffer_copy(&g_nas_buffer, 
+	     &nas->elements[0].pduElement.rand,
+	     sizeof(nas->elements[0].pduElement.rand));
+
+	datalen = 16;
+	buffer_copy(&g_nas_buffer, &datalen, sizeof(datalen));
+
+	buffer_copy(&g_nas_buffer, 
+	   &nas->elements[1].pduElement.autn,
+	   sizeof(nas->elements[1].pduElement.autn));
+
+	datalen = g_nas_buffer.pos + 1;
+	buffer_copy(&g_value_buffer, &datalen,
+						sizeof(datalen));
+
+	buffer_copy(&g_value_buffer, &g_nas_buffer.pos,
+						sizeof(g_nas_buffer.pos));
+
+
+	buffer_copy(&g_value_buffer, &g_nas_buffer,
+						g_nas_buffer.pos);
+
+	buffer_copy(&g_buffer, &g_value_buffer.pos,
+						sizeof(g_value_buffer.pos));
+
+	buffer_copy(&g_buffer, &g_value_buffer,
+						g_value_buffer.pos);
+
+	free(s1apPDU.value.data[2].val.nas.elements);
+	free(s1apPDU.value.data);
+
+	send_sctp_msg(g_authreqInfo->enb_fd, g_buffer.buf, g_buffer.pos, 1);
+
+	return SUCCESS;
+}
+
+void*
+authreq_handler(void *data)
+{
+	log_msg(LOG_INFO, "AuthReq handler.\n");
+
+	authreq_processing((struct authreq_info *)data);
+
+	return NULL;
+}
diff --git a/src/s1ap/handlers/attach_authresp.c b/src/s1ap/handlers/attach_authresp.c
new file mode 100644
index 0000000..c8aae42
--- /dev/null
+++ b/src/s1ap/handlers/attach_authresp.c
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2003-2018, Great Software Laboratory Pvt. Ltd.
+ * Copyright (c) 2017 Intel Corporation
+ * Copyright (c) 2019, Infosys Ltd.
+ *
+ * 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 "err_codes.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 "msgType.h"
+
+
+extern int g_enb_fd;
+extern ipc_handle ipc_S1ap_Hndl;
+extern struct time_stat g_attach_stats[];
+
+int
+s1_auth_resp_handler(struct proto_IE *s1_auth_resp_ies)
+{
+	//TODO: use static instead of synamic for perf.
+	struct s1_incoming_msg_data_t auth_resp= {0};
+
+	/*****Message structure***
+	*/
+	log_msg(LOG_INFO, "Parse s1ap auth resp message:--\n");
+
+	/*Validate all eNB info*/
+
+	/*Add eNB info to hash*/
+
+	/*Create Q structure for stage 1 to MME.
+	  contains init UE information.*/
+	auth_resp.msg_type = auth_response;	
+		
+	for(int i = 0; i < s1_auth_resp_ies->no_of_IEs; i++)
+    {
+        switch(s1_auth_resp_ies->data[i].IE_type)
+        {
+            case S1AP_IE_MME_UE_ID:
+                {
+	                auth_resp.ue_idx = s1_auth_resp_ies->data[i].val.mme_ue_s1ap_id;
+                }break;
+            case S1AP_IE_NAS_PDU:
+                {
+                    if(s1_auth_resp_ies->data[i].val.nas.header.message_type != NAS_AUTH_RESP)
+                    {
+                        auth_resp.msg_data.authresp_Q_msg_m.status = S1AP_AUTH_FAILED;//Error in authentication
+                    }
+                    else
+                    {
+                        auth_resp.msg_data.authresp_Q_msg_m.status = SUCCESS;
+                    }
+
+                    memcpy(&(auth_resp.msg_data.authresp_Q_msg_m.res), 
+                           &(s1_auth_resp_ies->data[i].val.nas.elements[0].pduElement.auth_resp),
+                           sizeof(struct XRES));
+                }break;
+            default:
+                log_msg(LOG_WARNING,"Unhandled IE");
+        }
+    }
+
+	auth_resp.destInstAddr = htonl(mmeAppInstanceNum_c);
+	auth_resp.srcInstAddr = htonl(s1apAppInstanceNum_c);
+
+	//STIMER_GET_CURRENT_TP(g_attach_stats[s1_auth_resp_ies->data[1].enb_ue_s1ap_id].auth_to_mme);
+	send_tipc_message(ipc_S1ap_Hndl, mmeAppInstanceNum_c, (char *)&auth_resp, S1_READ_MSG_BUF_SIZE);
+
+	/*Send S1Setup response*/
+	log_msg(LOG_INFO, "Auth resp send to mme-app stage3.\n");
+
+	//TODO: free IEs
+	return SUCCESS;
+}
+
+int
+s1_auth_fail_handler(struct proto_IE *s1_auth_resp_ies)
+{
+	//TODO: use static instead of synamic for perf.
+	struct s1_incoming_msg_data_t auth_resp;
+
+	/*****Message structure***
+	*/
+	log_msg(LOG_INFO, "Parse s1ap auth fail resp:--\n");
+
+	/*Validate all eNB info*/
+
+	/*Add eNB info to hash*/
+
+	/*Create Q structure for stage 1 to MME.
+	  contains init UE information.*/
+	  
+	  /* msg_type for auth_failure
+	  ?auth_resp.msg_type =?;*/
+    for(int i = 0; i < s1_auth_resp_ies->no_of_IEs; i++)
+    {
+        switch(s1_auth_resp_ies->data[i].IE_type)
+        {
+            case S1AP_IE_MME_UE_ID:
+                {
+	                auth_resp.ue_idx = s1_auth_resp_ies->data[i].val.mme_ue_s1ap_id;
+                }break;
+            case S1AP_IE_NAS_PDU:
+                {
+                    auth_resp.msg_data.authresp_Q_msg_m.status = S1AP_AUTH_FAILED;//Error in authentication
+	                memcpy(&(auth_resp.msg_data.authresp_Q_msg_m.auts), 
+                           &(s1_auth_resp_ies->data[i].val.nas.elements[0].pduElement.auth_fail_resp),
+		                   sizeof(struct AUTS));
+                }break;
+            default:
+                log_msg(LOG_WARNING,"Unhandled IE");
+        }
+    }
+	
+    auth_resp.destInstAddr = htonl(mmeAppInstanceNum_c);
+	auth_resp.srcInstAddr = htonl(s1apAppInstanceNum_c);
+
+	//STIMER_GET_CURRENT_TP(g_attach_stats[s1_auth_resp_ies->data[1].enb_ue_s1ap_id].auth_to_mme);
+	send_tipc_message(ipc_S1ap_Hndl, mmeAppInstanceNum_c, (char *)&auth_resp, S1_READ_MSG_BUF_SIZE);
+
+	/*Send S1Setup response*/
+	log_msg(LOG_INFO, "Auth resp send to mme-app stage3.\n");
+
+	//TODO: free IEs
+	return SUCCESS;
+}
+
diff --git a/src/s1ap/handlers/attach_complete.c b/src/s1ap/handlers/attach_complete.c
new file mode 100644
index 0000000..d2a9a67
--- /dev/null
+++ b/src/s1ap/handlers/attach_complete.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2003-2018, Great Software Laboratory Pvt. Ltd.
+ * Copyright (c) 2017 Intel Corporation
+ * Copyright (c) 2019, Infosys Ltd.
+ *
+ * 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 "err_codes.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 "msgType.h"
+
+
+extern int g_enb_fd;
+extern int g_sctp_fd;
+extern ipc_handle ipc_S1ap_Hndl;
+
+int
+s1_attach_complete_handler(struct proto_IE *s1_esm_resp_ies)
+{
+	struct s1_incoming_msg_data_t attachComplete= {0};
+
+	/*****Message structure***
+	*/
+	log_msg(LOG_INFO, "Parse s1ap-nas attach complete message:--\n");
+
+	/*Validate all eNB info*/
+
+	/*Create Q structure for stage 1 to MME.
+	  contains init UE information.*/
+	attachComplete.msg_type = attach_complete;	
+	for(int i = 0; i < s1_esm_resp_ies->no_of_IEs; i++)
+    {
+        switch(s1_esm_resp_ies->data[i].IE_type)
+        {
+            case S1AP_IE_MME_UE_ID:
+                {
+	                attachComplete.ue_idx = s1_esm_resp_ies->data[i].val.mme_ue_s1ap_id;
+                }break;
+            default:
+                log_msg(LOG_WARNING,"Unhandled IE");
+        }
+    }
+	
+    attachComplete.msg_data.attach_complete_Q_msg_m.status = SUCCESS;
+	
+	
+	attachComplete.destInstAddr = htonl(mmeAppInstanceNum_c);
+	attachComplete.srcInstAddr = htonl(s1apAppInstanceNum_c);
+
+	int i = send_tipc_message(ipc_S1ap_Hndl, mmeAppInstanceNum_c, (char *)&attachComplete, S1_READ_MSG_BUF_SIZE);
+
+	if (i < 0) {
+		log_msg(LOG_ERROR, "Error to write in s1_attach_complete_handler\n");
+	} else {
+		/*Send S1Setup response*/
+		log_msg(LOG_INFO, "Attach complete send to mme-app stage8. Bytes send %d\n", i);
+	}
+
+	//Anjana: Socket cleanup
+	/*close(g_sctp_fd);
+	if (g_enb_fd != 0)
+		close(g_enb_fd);*/
+	//TODO: free IEs
+	return SUCCESS;
+}
+
diff --git a/src/s1ap/handlers/attach_esmreq.c b/src/s1ap/handlers/attach_esmreq.c
new file mode 100644
index 0000000..39f16bb
--- /dev/null
+++ b/src/s1ap/handlers/attach_esmreq.c
@@ -0,0 +1,226 @@
+/*
+ * 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 <pthread.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdint.h>
+
+#include "err_codes.h"
+#include "ipc_api.h"
+#include "main.h"
+#include "msgType.h"
+#include "s1ap.h"
+#include  "log.h"
+#include "snow_3g.h"
+
+/****Globals and externs ***/
+
+/*Making global just to avoid stack passing*/
+static Buffer g_esm_buffer;
+static Buffer g_esm_value_buffer;
+static Buffer g_esm_nas_buffer;
+
+
+/****Global and externs end***/
+extern ipc_handle ipc_S1ap_Hndl;
+/**
+* Get ProtocolIE value for Sec Request sent by mme-app
+*/
+static int
+get_esmreq_protoie_value(struct proto_IE *value, struct esm_req_Q_msg * g_esmReqInfo)
+{
+	value->no_of_IEs = ESM_REQ_NO_OF_IES;
+
+	value->data = (proto_IEs *) malloc(ESM_REQ_NO_OF_IES *
+			sizeof(proto_IEs));
+
+	value->data[0].val.mme_ue_s1ap_id = g_esmReqInfo->ue_idx;
+	value->data[1].val.enb_ue_s1ap_id = g_esmReqInfo->enb_s1ap_ue_id;
+
+	value->data[2].val.nas.header.security_header_type =
+			IntegrityProtectedCiphered;
+
+	value->data[2].val.nas.header.proto_discriminator =
+			EPSMobilityManagementMessages;
+
+	/* placeholder for mac. mac value will be calculated later */
+	uint8_t mac[MAC_SIZE] = {0};
+	memcpy(value->data[2].val.nas.header.mac, mac, MAC_SIZE);
+
+	value->data[2].val.nas.header.seq_no = g_esmReqInfo->dl_seq_no;
+
+	value->data[2].val.nas.header.message_type = ESMInformationRequest;
+
+	/* TODO: Remove hardcoded value */
+	value->data[2].val.nas.header.eps_bearer_identity = 0;
+	value->data[2].val.nas.header.procedure_trans_identity = g_esmReqInfo->pti;
+
+	return SUCCESS;
+}
+
+
+/**
+* Stage specific message processing.
+*/
+static int
+esmreq_processing(struct esm_req_Q_msg * g_esmReqInfo)
+{
+	unsigned char tmpStr[4];
+	struct s1ap_PDU s1apPDU= {0};
+	uint8_t mac_data_pos;
+
+	s1apPDU.procedurecode = id_downlinkNASTransport;
+	s1apPDU.criticality = CRITICALITY_IGNORE;
+
+	get_esmreq_protoie_value(&s1apPDU.value, g_esmReqInfo);
+
+	/* Copy values to g_sec_nas_buffer */
+
+	/* id-NAS-PDU */
+	g_esm_nas_buffer.pos = 0;
+	nasPDU nas = s1apPDU.value.data[2].val.nas;
+
+	unsigned char value = (nas.header.security_header_type << 4 |
+			nas.header.proto_discriminator);
+	buffer_copy(&g_esm_nas_buffer, &value, sizeof(value));
+
+	/* placeholder for mac. mac value will be calculated later */
+	buffer_copy(&g_esm_nas_buffer, &nas.header.mac, MAC_SIZE);
+	mac_data_pos = g_esm_nas_buffer.pos;
+
+	buffer_copy(&g_esm_nas_buffer, &nas.header.seq_no,
+			sizeof(nas.header.seq_no));
+
+	nas.header.proto_discriminator = EPSSessionManagementMessage;
+	value = (nas.header.eps_bearer_identity << 4 |
+				nas.header.proto_discriminator);
+	buffer_copy(&g_esm_nas_buffer, &value, sizeof(value));
+
+	buffer_copy(&g_esm_nas_buffer,
+			&nas.header.procedure_trans_identity,
+			sizeof(nas.header.procedure_trans_identity));
+
+	buffer_copy(&g_esm_nas_buffer, &nas.header.message_type,
+			sizeof(nas.header.message_type));
+
+	/* Calculate mac */
+	uint8_t direction = 1;
+	uint8_t bearer = 0;
+
+	calculate_mac(g_esmReqInfo->int_key, nas.header.seq_no, direction,
+			bearer, &g_esm_nas_buffer.buf[mac_data_pos],
+			g_esm_nas_buffer.pos - mac_data_pos,
+			&g_esm_nas_buffer.buf[mac_data_pos - MAC_SIZE]);
+
+	/* Copy values in g_sec_value_buffer */
+	g_esm_value_buffer.pos = 0;
+
+	/* TODO remove hardcoded values */
+	char chProtoIENo[3] = {0,0,3};
+	buffer_copy(&g_esm_value_buffer, chProtoIENo, 3);
+
+	/* id-MME-UE-S1AP-ID */
+	uint16_t protocolIe_Id = id_MME_UE_S1AP_ID;
+	copyU16(tmpStr, protocolIe_Id);
+	buffer_copy(&g_esm_value_buffer, tmpStr,
+					sizeof(protocolIe_Id));
+
+	unsigned char protocolIe_criticality = CRITICALITY_REJECT;
+	buffer_copy(&g_esm_value_buffer, &protocolIe_criticality,
+					sizeof(protocolIe_criticality));
+
+	unsigned char datalen = 2;
+
+	/* TODO need to add proper handling*/
+	unsigned char mme_ue_id[3];
+	datalen = copyU16(mme_ue_id, s1apPDU.value.data[0].val.mme_ue_s1ap_id);
+	buffer_copy(&g_esm_value_buffer, &datalen, sizeof(datalen));
+	buffer_copy(&g_esm_value_buffer, mme_ue_id, datalen);
+
+	/* id-eNB-UE-S1AP-ID */
+	protocolIe_Id = id_eNB_UE_S1AP_ID;
+	copyU16(tmpStr, protocolIe_Id);
+	buffer_copy(&g_esm_value_buffer, tmpStr,
+						sizeof(protocolIe_Id));
+
+	buffer_copy(&g_esm_value_buffer, &protocolIe_criticality,
+					sizeof(protocolIe_criticality));
+
+	/* TODO needs proper handling*/
+	unsigned char enb_ue_id[3];
+	datalen = copyU16(enb_ue_id, s1apPDU.value.data[1].val.enb_ue_s1ap_id);
+	buffer_copy(&g_esm_value_buffer, &datalen, sizeof(datalen));
+	buffer_copy(&g_esm_value_buffer, enb_ue_id, datalen);
+
+
+	/* id-NAS-PDU */
+	protocolIe_Id = id_NAS_PDU;
+	copyU16(tmpStr, protocolIe_Id);
+	buffer_copy(&g_esm_value_buffer, tmpStr,
+			sizeof(protocolIe_Id));
+
+	buffer_copy(&g_esm_value_buffer, &protocolIe_criticality,
+			sizeof(protocolIe_criticality));
+
+
+	datalen = g_esm_nas_buffer.pos + 1;
+	buffer_copy(&g_esm_value_buffer, &datalen,
+			sizeof(datalen));
+
+	buffer_copy(&g_esm_value_buffer, &g_esm_nas_buffer.pos,
+			sizeof(g_esm_nas_buffer.pos));
+
+	buffer_copy(&g_esm_value_buffer, &g_esm_nas_buffer,
+			g_esm_nas_buffer.pos);
+
+	/* Copy values in g_sec_buffer */
+	g_esm_buffer.pos = 0;
+
+	unsigned char initiating_message = 0; /* TODO: Add enum */
+	buffer_copy(&g_esm_buffer, &initiating_message,
+			sizeof(initiating_message));
+
+	buffer_copy(&g_esm_buffer, &s1apPDU.procedurecode,
+			sizeof(s1apPDU.procedurecode));
+
+	buffer_copy(&g_esm_buffer, &s1apPDU.criticality,
+			sizeof(s1apPDU.criticality));
+
+	buffer_copy(&g_esm_buffer, &g_esm_value_buffer.pos,
+			sizeof(g_esm_value_buffer.pos));
+
+	buffer_copy(&g_esm_buffer, &g_esm_value_buffer,
+			g_esm_value_buffer.pos);
+
+	send_sctp_msg(g_esmReqInfo->enb_fd, g_esm_buffer.buf, g_esm_buffer.pos, 1);
+
+	free(s1apPDU.value.data);
+
+	return SUCCESS;
+}
+
+void*
+esmreq_handler(void *data)
+{
+	log_msg(LOG_INFO, "ESM Info Request handler\n");
+	esmreq_processing((struct esm_req_Q_msg *)data);
+
+	return NULL;
+}
diff --git a/src/s1ap/handlers/attach_esmresp.c b/src/s1ap/handlers/attach_esmresp.c
new file mode 100644
index 0000000..99522a2
--- /dev/null
+++ b/src/s1ap/handlers/attach_esmresp.c
@@ -0,0 +1,94 @@
+/*
+ * 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 "err_codes.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 "msgType.h"
+
+extern int g_enb_fd;
+extern ipc_handle ipc_S1ap_Hndl;
+
+int
+s1_esm_resp_handler(struct proto_IE *s1_esm_resp_ies)
+{
+	struct s1_incoming_msg_data_t esm_resp= {0};
+	esm_resp.msg_type = esm_info_response;
+
+	/*****Message structure***
+	*/
+	log_msg(LOG_INFO, "Parse s1ap ESM response message:--\n");
+
+	/*Validate all eNB info*/
+
+	/*Add eNB info to hash*/
+
+	/*Create Q structure for stage 1 to MME.
+	  contains init UE information.*/
+    for(int i = 0; i < s1_esm_resp_ies->no_of_IEs; i++)
+    {
+        switch(s1_esm_resp_ies->data[i].IE_type)
+        {
+            case S1AP_IE_MME_UE_ID:
+                {
+	                esm_resp.ue_idx = s1_esm_resp_ies->data[i].val.mme_ue_s1ap_id;
+                }break;
+            case S1AP_IE_NAS_PDU:
+                {
+                    if(s1_esm_resp_ies->data[i].val.nas.header.message_type != NAS_ESM_RESP)
+                    {
+                        esm_resp.msg_data.esm_resp_Q_msg_m.status = S1AP_SECMODE_FAILED;//Error in authentication
+                    }
+                    else
+                    {
+                        esm_resp.msg_data.esm_resp_Q_msg_m.status = SUCCESS;
+	                    memcpy(&(esm_resp.msg_data.esm_resp_Q_msg_m.apn), &(s1_esm_resp_ies->data[i].val.nas.elements[0].pduElement.apn),
+		                       sizeof(struct apn_name));
+                    }
+
+                }break;
+            default:
+                log_msg(LOG_WARNING,"Unhandled IE");
+        }
+    }
+
+
+        esm_resp.destInstAddr = htonl(mmeAppInstanceNum_c);
+        esm_resp.srcInstAddr = htonl(s1apAppInstanceNum_c);
+
+        //STIMER_GET_CURRENT_TP(g_attach_stats[s1_auth_resp_ies->data[1].enb_ue_s1ap_id].auth_to_mme);
+        send_tipc_message(ipc_S1ap_Hndl, mmeAppInstanceNum_c, (char *)&esm_resp, S1_READ_MSG_BUF_SIZE);
+
+        /*Send S1Setup response*/
+        log_msg(LOG_INFO, "ESM Info resp send to mme-app\n");
+
+	//TODO: free IEs
+	return SUCCESS;
+}
+
diff --git a/src/s1ap/handlers/attach_icsreq.c b/src/s1ap/handlers/attach_icsreq.c
new file mode 100644
index 0000000..23c00a5
--- /dev/null
+++ b/src/s1ap/handlers/attach_icsreq.c
@@ -0,0 +1,744 @@
+/*
+ * Copyright (c) 2003-2018, Great Software Laboratory Pvt. Ltd.
+ * Copyright (c) 2017 Intel Corporation
+ * Copyright (c) 2019, Infosys Ltd.
+ *
+ * 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 <pthread.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdint.h>
+
+#include "log.h"
+#include "err_codes.h"
+#include "message_queues.h"
+#include "ipc_api.h"
+#include "s1ap_config.h"
+#include "main.h"
+#include "s1ap.h"
+#include "msgType.h"
+
+extern s1ap_config g_s1ap_cfg;
+
+static void
+get_negotiated_qos_value(struct esm_qos *qos)
+{
+	qos->delay_class = 1;
+	qos->reliability_class = 3;
+	qos->peak_throughput = 5;
+	qos->precedence_class = 2;
+	qos->mean_throughput = 31;
+	qos->traffic_class = 3;
+	qos->delivery_order = 2;
+	qos->delivery_err_sdu = 3;
+	qos->max_sdu_size = 140;
+	qos->mbr_ul = 254;
+	qos->mbr_dl = 86;
+	qos->residual_ber = 7;
+	qos->sdu_err_ratio = 6;
+	qos->transfer_delay = 18;
+	qos->trffic_prio = 3;
+	qos->gbr_ul = 86;
+	qos->gbr_dl = 86;
+	qos->sig_ind = 0;
+	qos->src_stat_desc = 0;
+	qos->mbr_dl_ext = 108;
+	qos->gbr_dl_ext = 0;
+	qos->mbr_ul_ext = 108;
+	qos->gbr_ul_ext = 0;
+
+	return;
+}
+
+/**
+* Get ProtocolIE value for ICS Request sent by mme-app
+*/
+static int
+get_icsreq_protoie_value(struct proto_IE *value, struct init_ctx_req_Q_msg *g_icsReqInfo)
+{
+	uint8_t ieCnt = 0;
+	uint8_t nasIeCnt = 0;
+
+	value->no_of_IEs = ICS_REQ_NO_OF_IES;
+
+	value->data = (proto_IEs *) malloc(ICS_REQ_NO_OF_IES *
+			sizeof(proto_IEs));
+	
+
+	value->data[ieCnt].val.mme_ue_s1ap_id = g_icsReqInfo->ue_idx;
+	ieCnt++;
+
+	value->data[ieCnt].val.enb_ue_s1ap_id = g_icsReqInfo->enb_s1ap_ue_id;
+	ieCnt++;
+
+	log_msg(LOG_INFO, "mme_ue_s1ap_id %d and enb_ue_s1ap_id %d\n",
+                        g_icsReqInfo->ue_idx, g_icsReqInfo->enb_s1ap_ue_id);
+
+	value->data[ieCnt].val.ue_aggrt_max_bit_rate.uEaggregateMaxBitRateDL =
+			g_icsReqInfo->exg_max_dl_bitrate;
+	value->data[ieCnt].val.ue_aggrt_max_bit_rate.uEaggregateMaxBitRateUL =
+				g_icsReqInfo->exg_max_ul_bitrate;
+	ieCnt++;
+
+	/* E-RABToBeSetupItemCtxtSUReq start */
+	ERABSetup *e_rab = &(value->data[ieCnt].val.E_RABToBeSetupItemCtxtSUReq);
+	/* TODO: Remove hardcoded values. */
+	e_rab->e_RAB_ID = 1;
+	e_rab->e_RAB_QoS_Params.qci = 9;
+	e_rab->e_RAB_QoS_Params.arPrio.prioLevel = 15;
+	e_rab->e_RAB_QoS_Params.arPrio.preEmptionCapab = 1;
+	e_rab->e_RAB_QoS_Params.arPrio.preEmptionVulnebility = 1;
+
+	/*S1u information : transport layer addr and teid*/
+	e_rab->transportLayerAddress = htonl(g_icsReqInfo->gtp_teid.ip.ipv4.s_addr);
+	//e_rab->gtp_teid = htonl(g_icsReqInfo->gtp_teid.header.teid_gre);
+	{
+		char *dst = (char *)&(e_rab->gtp_teid);
+		char *src = (char *)&(g_icsReqInfo->gtp_teid.header.teid_gre);
+		memcpy(dst, src+3, 1);
+		memcpy(dst+1, src+2, 1);
+		memcpy(dst+2, src+1, 1);
+		memcpy(dst+3, src, 1);
+	}
+
+	/* NAS PDU values start */
+	e_rab->nas.header.security_header_type =
+				IntegrityProtectedCiphered;
+	e_rab->nas.header.proto_discriminator =
+			EPSMobilityManagementMessages;
+
+	/* placeholder for mac. mac value will be calculated later */
+	uint8_t mac[MAC_SIZE] = {0};
+	memcpy(e_rab->nas.header.mac, mac, MAC_SIZE);
+
+	e_rab->nas.header.seq_no = g_icsReqInfo->dl_seq_no;
+	e_rab->nas.header.message_type = AttachAccept;
+	/* TODO: Remove hardcoded value */
+	e_rab->nas.header.eps_bearer_identity = 0;
+	e_rab->nas.header.procedure_trans_identity = 1;
+
+	e_rab->nas.elements_len = ICS_REQ_NO_OF_NAS_IES;
+	e_rab->nas.elements = (nas_pdu_elements *)
+			malloc(ICS_REQ_NO_OF_NAS_IES * sizeof(nas_pdu_elements));
+
+	nas_pdu_elements *nasIEs = e_rab->nas.elements;
+	nasIEs[nasIeCnt].pduElement.attach_res = 2; /* EPS Only */
+	nasIeCnt++;
+
+    /* Refer : 24008. Section - 10.5.7.3. We want to disable TAU request coming from UE. 
+     */
+//#define DISABLE_TAU 0
+#if DISABLE_TAU
+	nasIEs[nasIeCnt].pduElement.t3412 = 224; 
+#else
+	nasIEs[nasIeCnt].pduElement.t3412 = 0x21; // per min
+#endif
+	nasIeCnt++;
+
+	nasIEs[nasIeCnt].pduElement.tailist.type = 1;
+	nasIEs[nasIeCnt].pduElement.tailist.num_of_elements = 0;
+
+    	/* S1AP TAI mcc 123, mnc 456 : 214365 */
+    	/* NAS GUTI mcc 123, mnc 456 : 216354 */
+	if ((g_icsReqInfo->tai.plmn_id.idx[1] & 0xF0) != 0xF0)
+	{
+    	unsigned char x3 = g_icsReqInfo->tai.plmn_id.idx[2];
+    	unsigned char x2 = g_icsReqInfo->tai.plmn_id.idx[1]; 
+    	unsigned char x31 = x3 >> 4;
+   	    unsigned char x32 = x3 & 0xf;
+    	unsigned char x21 = x2 >> 4;
+    	unsigned char x22  = x2 & 0xf;
+    	x3 = x21 | (x32 <<4);
+    	x2 = (x31 << 4) | x22;
+    	g_icsReqInfo->tai.plmn_id.idx[1] = x2;
+    	g_icsReqInfo->tai.plmn_id.idx[2] = x3;
+	}
+
+	memcpy(&(nasIEs[nasIeCnt].pduElement.tailist.partial_list[0]),
+			&(g_icsReqInfo->tai), sizeof(g_icsReqInfo->tai));
+	nasIeCnt++;
+
+	nasIEs[nasIeCnt].pduElement.esm_msg.eps_bearer_id = 5; /* TODO: revisit */
+	nasIEs[nasIeCnt].pduElement.esm_msg.proto_discriminator = 2;
+	memcpy(&(nasIEs[nasIeCnt].pduElement.esm_msg.procedure_trans_identity), &(g_icsReqInfo->pti), 1);
+	nasIEs[nasIeCnt].pduElement.esm_msg.session_management_msgs =
+			ESM_MSG_ACTV_DEF_BEAR__CTX_REQ;
+	nasIEs[nasIeCnt].pduElement.esm_msg.eps_qos = 9;
+
+	/* TODO: Remove hardcoded value */
+	/*char apnname[4] = "apn1";
+	memcpy(&(nasIEs[nasIeCnt].esm_msg.apn.val), apnname, 4);
+	nasIEs[nasIeCnt].esm_msg.apn.len =  4;
+	*/
+	nasIEs[nasIeCnt].pduElement.esm_msg.apn.len = g_icsReqInfo->apn.len;
+	memcpy(nasIEs[nasIeCnt].pduElement.esm_msg.apn.val,
+			g_icsReqInfo->apn.val, g_icsReqInfo->apn.len);
+
+
+	nasIEs[nasIeCnt].pduElement.esm_msg.pdn_addr.type = 1;
+    /*TODO : endian issue */
+	nasIEs[nasIeCnt].pduElement.esm_msg.pdn_addr.ipv4 = htonl(g_icsReqInfo->pdn_addr.ip_type.ipv4.s_addr);
+	nasIEs[nasIeCnt].pduElement.esm_msg.linked_ti.flag = 0;
+	nasIEs[nasIeCnt].pduElement.esm_msg.linked_ti.val = 0;
+	get_negotiated_qos_value(&nasIEs[nasIeCnt].pduElement.esm_msg.negotiated_qos);
+	nasIeCnt++;
+
+        /* Send the allocated GUTI to UE  */
+	nasIEs[nasIeCnt].pduElement.mi_guti.odd_even_indication = 0;
+	nasIEs[nasIeCnt].pduElement.mi_guti.id_type = 6;
+
+	memcpy(&(nasIEs[nasIeCnt].pduElement.mi_guti.plmn_id),
+			&(g_icsReqInfo->tai.plmn_id), sizeof(struct PLMN));
+	nasIEs[nasIeCnt].pduElement.mi_guti.mme_grp_id = htons(g_s1ap_cfg.mme_group_id);
+	nasIEs[nasIeCnt].pduElement.mi_guti.mme_code = g_s1ap_cfg.mme_code;
+	/* TODO : Revisit, temp fix for handling detach request retransmit.
+	 * M-TMSI should come from MME */
+	nasIEs[nasIeCnt].pduElement.mi_guti.m_TMSI = htonl(g_icsReqInfo->m_tmsi);
+	nasIeCnt++;
+
+	ieCnt++;
+	/* NAS PDU values end */
+	/* E-RABToBeSetupItemCtxtSUReq values end */
+
+
+	/* TODO Get value of ue_sec_capabilities
+	 *
+	 * value->data[ieCnt].ue_sec_capabilities = ??
+	 *
+	 * */
+
+
+	ieCnt++;
+
+	/* TODO: remove hard coded value */
+	/*char sec_key[32] = "abcdefghijklmnopqrstuvwxyz012345";
+	memcpy(value->data[ieCnt].sec_key, sec_key,
+			SECURITY_KEY_SIZE);
+	*/
+
+	memcpy(value->data[ieCnt].val.sec_key, g_icsReqInfo->sec_key,
+			SECURITY_KEY_SIZE);
+
+	ieCnt++;
+
+	return SUCCESS;
+}
+
+
+
+/**
+* Stage specific message processing.
+*/
+static int
+icsreq_processing(struct init_ctx_req_Q_msg *g_icsReqInfo)
+{
+
+    Buffer g_ics_buffer;
+    Buffer g_s1ap_buffer;
+    Buffer g_rab1_buffer;
+    Buffer g_rab2_buffer;
+    Buffer g_nas_buffer;
+
+	unsigned char tmpStr[4];
+	struct s1ap_PDU s1apPDU;
+	uint16_t protocolIe_Id;
+	uint8_t protocolIe_criticality;
+	uint8_t initiating_msg = 0;
+	uint8_t datalen = 0;
+	//uint8_t s1ap_len_pos;
+	//uint8_t erab_len_pos;
+	//uint8_t erab_item_len_pos;
+	//uint8_t nas_len_pos;
+	uint16_t esm_len_pos;
+	uint8_t u8value = 0;
+	uint8_t mac_data_pos;
+
+	s1apPDU.procedurecode = id_InitialContextSetup;
+	s1apPDU.criticality = CRITICALITY_REJECT;
+
+	get_icsreq_protoie_value(&s1apPDU.value, g_icsReqInfo);
+
+	g_ics_buffer.pos = 0;
+
+	buffer_copy(&g_ics_buffer, &initiating_msg,
+			sizeof(initiating_msg));
+
+	buffer_copy(&g_ics_buffer, &s1apPDU.procedurecode,
+			sizeof(s1apPDU.procedurecode));
+
+	buffer_copy(&g_ics_buffer, &s1apPDU.criticality,
+				sizeof(s1apPDU.criticality));
+
+	/* TODO: revisit , why 128 (0x80) required */
+#if 0
+	s1ap_len_pos = g_ics_buffer.pos;
+	u8value = 128;
+	buffer_copy(&g_ics_buffer, &u8value, sizeof(u8value));
+
+	
+
+
+	u8value = 0;
+	buffer_copy(&g_ics_buffer, &u8value, sizeof(u8value));
+#endif
+
+    g_s1ap_buffer.pos = 0; 
+
+	/* TODO remove hardcoded values */
+	uint8_t chProtoIENo[3] = {0,0,6};
+	buffer_copy(&g_s1ap_buffer, chProtoIENo, 3);
+
+	/* id-MME-UE-S1AP-ID */
+	protocolIe_Id = id_MME_UE_S1AP_ID;
+	copyU16(tmpStr, protocolIe_Id);
+	buffer_copy(&g_s1ap_buffer, tmpStr, sizeof(protocolIe_Id));
+	protocolIe_criticality = CRITICALITY_REJECT;
+	buffer_copy(&g_s1ap_buffer, &protocolIe_criticality,
+					sizeof(protocolIe_criticality));
+	datalen = 2;
+	/* TODO need to add proper handling*/
+	unsigned char mme_ue_id[3];
+	datalen = copyU16(mme_ue_id, s1apPDU.value.data[0].val.mme_ue_s1ap_id);
+	buffer_copy(&g_s1ap_buffer, &datalen, sizeof(datalen));
+	buffer_copy(&g_s1ap_buffer, mme_ue_id, datalen);
+
+	/* id-eNB-UE-S1AP-ID */
+	protocolIe_Id = id_eNB_UE_S1AP_ID;
+	copyU16(tmpStr, protocolIe_Id);
+	buffer_copy(&g_s1ap_buffer, tmpStr, sizeof(protocolIe_Id));
+	buffer_copy(&g_s1ap_buffer, &protocolIe_criticality,
+					sizeof(protocolIe_criticality));
+	/* TODO needs proper handling*/
+	unsigned char enb_ue_id[3];
+	datalen = copyU16(enb_ue_id, s1apPDU.value.data[1].val.enb_ue_s1ap_id);
+	buffer_copy(&g_s1ap_buffer, &datalen, sizeof(datalen));
+	buffer_copy(&g_s1ap_buffer, enb_ue_id, datalen);
+
+	protocolIe_Id = id_uEaggregatedMaximumBitrate;
+	copyU16(tmpStr, protocolIe_Id);
+	buffer_copy(&g_s1ap_buffer, tmpStr, sizeof(protocolIe_Id));
+	buffer_copy(&g_s1ap_buffer, &protocolIe_criticality,
+					sizeof(protocolIe_criticality));
+	datalen = 10;
+
+	uint8_t maximum_bit_rate_dl = 0x18;
+	uint8_t maximum_bit_rate_ul = 0x60;
+
+	buffer_copy(&g_s1ap_buffer, &datalen, sizeof(datalen));
+
+	buffer_copy(&g_s1ap_buffer, &maximum_bit_rate_dl, sizeof(maximum_bit_rate_dl));
+
+	uint32_t temp_bitrate = htonl(g_icsReqInfo->exg_max_dl_bitrate);
+	memset(tmpStr, 0, sizeof(tmpStr));
+	memcpy(tmpStr, &temp_bitrate, sizeof(temp_bitrate));
+
+	buffer_copy(&g_s1ap_buffer, tmpStr,
+			sizeof(tmpStr));
+
+	temp_bitrate = 0;
+	temp_bitrate = htonl(g_icsReqInfo->exg_max_ul_bitrate);
+	memset(tmpStr, 0, sizeof(tmpStr));
+	memcpy(tmpStr, &temp_bitrate, sizeof(temp_bitrate));
+
+	buffer_copy(&g_s1ap_buffer, &maximum_bit_rate_ul,
+			sizeof(maximum_bit_rate_ul));
+	buffer_copy(&g_s1ap_buffer, tmpStr,
+			sizeof(tmpStr));
+
+
+	/* id-E-RABToBeSetupListCtxtSUReq */
+	ERABSetup *erab = &(s1apPDU.value.data[3].val.E_RABToBeSetupItemCtxtSUReq);
+	protocolIe_Id = id_ERABToBeSetupListCtxtSUReq;
+	copyU16(tmpStr, protocolIe_Id);
+	buffer_copy(&g_s1ap_buffer, tmpStr, sizeof(protocolIe_Id));
+	buffer_copy(&g_s1ap_buffer, &protocolIe_criticality,
+					sizeof(protocolIe_criticality));
+
+    /* Lets put this in new buffer  */
+    /*rab_len_1 */
+#if 0
+	erab_len_pos = g_s1ap_buffer.pos;
+	datalen = 0;
+	buffer_copy(&g_ics_buffer, &datalen, sizeof(datalen));
+#endif
+    g_rab1_buffer.pos = 0;
+
+	buffer_copy(&g_rab1_buffer, &initiating_msg,
+			sizeof(initiating_msg));
+
+	protocolIe_Id = id_ERABToBeSetupItemCtxtSUReq;
+	copyU16(tmpStr, protocolIe_Id);
+	buffer_copy(&g_rab1_buffer, tmpStr, sizeof(protocolIe_Id));
+	buffer_copy(&g_rab1_buffer, &protocolIe_criticality,
+					sizeof(protocolIe_criticality));
+
+    /*rab_len_2 */
+#if 0
+	erab_item_len_pos = g_rab1_buffer.pos;  
+    datalen = 0;
+	buffer_copy(&g_ics_buffer, &datalen, sizeof(datalen));
+#endif
+
+	/*
+	buffer_copy(&g_ics_buffer, &(erab->e_RAB_ID),
+			sizeof(erab->e_RAB_ID));
+	*/
+    g_rab2_buffer.pos = 0;
+	/* TODO : Remove hardcoded value of erab id */
+	u8value =69; // 0x45 //1;
+	buffer_copy(&g_rab2_buffer, &u8value, sizeof(u8value));
+	/* TODO: Need to revisit why add 00 before qci value? */
+	u8value = 0;
+	buffer_copy(&g_rab2_buffer, &u8value, sizeof(u8value));
+	buffer_copy(&g_rab2_buffer, &(erab->e_RAB_QoS_Params.qci),
+			sizeof(erab->e_RAB_QoS_Params.qci));
+	buffer_copy(&g_rab2_buffer, &(erab->e_RAB_QoS_Params.arPrio),
+			sizeof(erab->e_RAB_QoS_Params.arPrio));
+
+	/* TODO: Revisit why we need to add 0f 80 before transport add? */
+
+	u8value = 15;
+	buffer_copy(&g_rab2_buffer, &u8value, sizeof(u8value));
+	u8value = 128;
+	buffer_copy(&g_rab2_buffer, &u8value, sizeof(u8value));
+
+	buffer_copy(&g_rab2_buffer, &(erab->transportLayerAddress),
+				sizeof(erab->transportLayerAddress));
+
+	buffer_copy(&g_rab2_buffer, &(erab->gtp_teid),
+				sizeof(erab->gtp_teid));
+
+
+	/* E_RABToBeSetupListCtxtSUReq NAS PDU start */
+    // at the end we will do.... rab2_buf + <nas_len> + nas_buffer 
+
+#if 0
+	nas_len_pos = g_rab2_buffer.pos;
+	datalen = 0;
+	buffer_copy(&g_ics_buffer, &datalen, sizeof(datalen));
+#endif
+
+	nas_pdu_header *nas_hdr = &(erab->nas.header);
+
+    g_nas_buffer.pos = 0; 
+	/* security header and protocol discriminator */
+	u8value = (nas_hdr->security_header_type << 4 |
+			nas_hdr->proto_discriminator);
+	buffer_copy(&g_nas_buffer, &u8value, sizeof(u8value));
+
+	/* mac */
+	/* placeholder for mac. mac value will be calculated later */
+	buffer_copy(&g_nas_buffer, nas_hdr->mac, MAC_SIZE);
+	mac_data_pos = g_nas_buffer.pos;
+
+	/* sequence number */
+	buffer_copy(&g_nas_buffer, &(nas_hdr->seq_no),
+			sizeof(nas_hdr->seq_no));
+
+	/* security header and protocol discriminator */
+	nas_hdr->security_header_type = Plain;
+	u8value = (nas_hdr->security_header_type << 4 |
+			nas_hdr->proto_discriminator);
+	buffer_copy(&g_nas_buffer, &u8value, sizeof(u8value));
+
+	/* message type */
+	buffer_copy(&g_nas_buffer, &(nas_hdr->message_type),
+			sizeof(nas_hdr->message_type));
+
+	nas_pdu_elements *ies = erab->nas.elements;
+
+	/* eps attach result */
+	buffer_copy(&g_nas_buffer, &(ies[0].pduElement.attach_res), sizeof(u8value));
+
+	/* GPRS timer */
+#define DISABLE_TAU 1
+#if DISABLE_TAU
+    uint8_t temp_timer = 224; /*e0*/
+#else
+    uint8_t temp_timer = 0x21; /*per min */
+#endif
+	//buffer_copy(&g_ics_buffer, &(ies[1].t3412), sizeof(ies[1].t3412));
+	buffer_copy(&g_nas_buffer, &temp_timer, sizeof(temp_timer));
+
+	/* TAI list */
+	u8value = 6;
+	buffer_copy(&g_nas_buffer, &u8value, sizeof(u8value));
+	u8value = 32; /* TODO: use value from tai list */
+	buffer_copy(&g_nas_buffer, &u8value, sizeof(u8value));
+	buffer_copy(&g_nas_buffer, &(ies[2].pduElement.tailist.partial_list[0].plmn_id.idx), 3);
+	buffer_copy(&g_nas_buffer, &(ies[2].pduElement.tailist.partial_list[0].tac), 2);
+
+	esm_len_pos = g_nas_buffer.pos;
+
+	/* esm message container length */
+	char tmplen[2] = {0, 0};
+	buffer_copy(&g_nas_buffer, tmplen, 2);
+
+	/* ESM message container start */
+
+	/* esm message bearer id and protocol discriminator */
+	u8value = (ies[3].pduElement.esm_msg.eps_bearer_id << 4 |
+			ies[3].pduElement.esm_msg.proto_discriminator);
+	buffer_copy(&g_nas_buffer, &u8value, sizeof(u8value));
+
+	/* esm message procedure identity */
+	buffer_copy(&g_nas_buffer, &(ies[3].pduElement.esm_msg.procedure_trans_identity),
+			sizeof(ies[3].pduElement.esm_msg.procedure_trans_identity));
+
+	/* esm message session management message */
+	buffer_copy(&g_nas_buffer, &(ies[3].pduElement.esm_msg.session_management_msgs),
+			sizeof(ies[3].pduElement.esm_msg.session_management_msgs));
+
+	/* eps qos */
+	datalen = 1;
+	buffer_copy(&g_nas_buffer, &datalen, sizeof(datalen));
+	buffer_copy(&g_nas_buffer, &(ies[3].pduElement.esm_msg.eps_qos),
+			sizeof(ies[3].pduElement.esm_msg.eps_qos));
+
+	/* apn */
+	char apn_name[25]={};
+	strncpy(apn_name, (char *)ies[3].pduElement.esm_msg.apn.val, 
+             ies[3].pduElement.esm_msg.apn.len);
+	datalen = ies[3].pduElement.esm_msg.apn.len;
+	buffer_copy(&g_nas_buffer, &datalen, sizeof(datalen));
+	buffer_copy(&g_nas_buffer, (char *)ies[3].pduElement.esm_msg.apn.val, datalen);
+	
+	/* pdn address */
+	//datalen = sizeof(ies[3].esm_msg.pdn_addr);
+	datalen = 5; //sizeof(ies[3].esm_msg.pdn_addr);
+	buffer_copy(&g_nas_buffer, &datalen, sizeof(datalen));
+	u8value = 1;
+	buffer_copy(&g_nas_buffer, &u8value, sizeof(u8value));
+	//buffer_copy(&g_ics_buffer, &(ies[3].esm_msg.pdn_addr.pdn_type), 1);
+	buffer_copy(&g_nas_buffer, &(ies[3].pduElement.esm_msg.pdn_addr.ipv4), datalen-1);
+
+	/* linked ti */
+	u8value = 0x5d; /* element id TODO: define macro or enum */
+	buffer_copy(&g_nas_buffer, &u8value, sizeof(u8value));
+	datalen = 1;//sizeof(ies[3].esm_msg.linked_ti);
+	buffer_copy(&g_nas_buffer, &datalen, sizeof(datalen));
+	buffer_copy(&g_nas_buffer, &(ies[3].pduElement.esm_msg.linked_ti), datalen);
+
+	/* negotiated qos */
+	u8value = 0x30; /* element id TODO: define macro or enum */
+	buffer_copy(&g_nas_buffer, &u8value, sizeof(u8value));
+	datalen = 16;//sizeof(ies[3].esm_msg.negotiated_qos);
+	buffer_copy(&g_nas_buffer, &datalen, sizeof(datalen));
+	buffer_copy(&g_nas_buffer, &(ies[3].pduElement.esm_msg.negotiated_qos), datalen);
+
+	/* apn ambr */
+#if 0
+	u8value = 0x5e; /* element id TODO: define macro or enum */
+	buffer_copy(&g_ics_buffer, &u8value, sizeof(u8value));
+	datalen = sizeof(ies[3].esm_msg.apn_ambr);
+	buffer_copy(&g_ics_buffer, &datalen, sizeof(datalen));
+	buffer_copy(&g_ics_buffer, &(ies[3].esm_msg.apn_ambr), datalen);
+#endif
+	/* TODO: remove hardcoded values of apn ambr */
+	char apn_ambr[8] = {0x5e, 0x06, 0x80, 0x00, 0x04, 0x05, 0x06, 0x07};
+	buffer_copy(&g_nas_buffer, apn_ambr, 8);
+
+#if 1
+    char pco_options[29] = {0x27, 0x1B, 0x80, 0x80, 0x21, 0x10, 0x03, 0x00, 0x00,0x10, 0x81, 0x06, 0x08,0x08,0x08, 0x08,0x83,0x06,0x08,0x08,0x08,0x04,0x00,0x0d, 0x04,0x08,0x08,0x08,0x08};
+	buffer_copy(&g_nas_buffer, &pco_options[0], 29);
+#endif
+
+	/* ESM message container end */
+
+	/* Copy esm container length to esm container length field */
+	uint16_t esm_datalen = g_nas_buffer.pos - esm_len_pos - 2;
+	unsigned char esm_len[2];
+	copyU16(esm_len, esm_datalen);
+	/* memcpy(&g_ics_buffer.buf[esm_len_pos], tmplen, sizeof(esm_datalen)); */
+	/*TODO: needs proper handling */
+	g_nas_buffer.buf[esm_len_pos] = esm_len[0];
+	g_nas_buffer.buf[esm_len_pos + 1] = esm_len[1];
+
+	/* EPS mobile identity GUTI */
+#if 0
+	u8value = 0x50; /* element id TODO: define macro or enum */
+	buffer_copy(&g_ics_buffer, &u8value, sizeof(u8value));
+	datalen = sizeof(ies[4].mi_guti);
+	buffer_copy(&g_ics_buffer, &datalen, sizeof(datalen));
+	buffer_copy(&g_ics_buffer, &(ies[4].mi_guti), datalen);
+#endif
+
+	u8value = 0x50; /* element id TODO: define macro or enum */
+	buffer_copy(&g_nas_buffer, &u8value, sizeof(u8value));
+	datalen = 11;
+	buffer_copy(&g_nas_buffer, &datalen, sizeof(datalen));
+
+	u8value = 246; /* TODO: remove hard coding */
+	buffer_copy(&g_nas_buffer, &u8value, sizeof(u8value));
+	buffer_copy(&g_nas_buffer, &(ies[4].pduElement.mi_guti.plmn_id.idx), 3);
+	buffer_copy(&g_nas_buffer, &(ies[4].pduElement.mi_guti.mme_grp_id),
+			sizeof(ies[4].pduElement.mi_guti.mme_grp_id));
+	buffer_copy(&g_nas_buffer, &(ies[4].pduElement.mi_guti.mme_code),
+			sizeof(ies[4].pduElement.mi_guti.mme_code));
+	buffer_copy(&g_nas_buffer, &(ies[4].pduElement.mi_guti.m_TMSI),
+			sizeof(ies[4].pduElement.mi_guti.m_TMSI));
+
+#if 0
+    {
+        // sending mobile identity to UE 
+    /*TODO : Experiment */
+	u8value = 0x23; /* element id TODO: define macro or enum */
+	buffer_copy(&g_nas_buffer, &u8value, sizeof(u8value));
+	datalen = 0x05;
+	buffer_copy(&g_nas_buffer, &datalen, sizeof(datalen));
+    u8value = 0xf4; //
+	buffer_copy(&g_nas_buffer, &u8value, sizeof(u8value));
+	buffer_copy(&g_nas_buffer, &(ies[4].pduElement.mi_guti.m_TMSI),
+			sizeof(ies[4].pduElement.mi_guti.m_TMSI));
+    }
+#endif
+	/* E_RABToBeSetupListCtxtSUReq NAS PDU end */
+
+	/* Calculate mac */
+	uint8_t direction = 1;
+	uint8_t bearer = 0;
+
+	calculate_mac(g_icsReqInfo->int_key, nas_hdr->seq_no,
+			direction, bearer, &g_nas_buffer.buf[mac_data_pos],
+			g_nas_buffer.pos - mac_data_pos,
+			&g_nas_buffer.buf[mac_data_pos - MAC_SIZE]);
+
+	/* Copy nas length to nas length field */
+    //uint16_t nas_pay_len = g_nas_buffer.pos - nas_len_pos - 1;
+	log_msg(LOG_INFO, "NAS payload length %d\n", g_nas_buffer.pos);
+
+    /* start: RAB2 + NAS start */
+    /* Now lets append NAS buffer to rab2....so rab2 = rab2_buf + nas_length + nas_buf  */
+    if(g_nas_buffer.pos <= 127 )
+    {
+	  /* datalen = g_nas_buffer.pos - nas_len_pos - 1; */
+        datalen = g_nas_buffer.pos;
+	    buffer_copy(&g_rab2_buffer, &datalen, sizeof(datalen));
+    }
+    else
+    {
+        uint16_t nas_pay_len  = g_nas_buffer.pos | 0x8000; // set MSB to 1 
+        unsigned char lenStr[2];
+        lenStr[0] = nas_pay_len >> 8;
+        lenStr[1] = nas_pay_len & 0xff;
+	    buffer_copy(&g_rab2_buffer, lenStr, sizeof(lenStr));
+    }
+	buffer_copy(&g_rab2_buffer, &g_nas_buffer.buf[0], g_nas_buffer.pos);
+    /* end : RAB2 + NAS done */
+
+	log_msg(LOG_INFO, "RAB2 payload length %d\n", g_rab2_buffer.pos);
+    /* Now lets append rab2 to rab1 */ 
+    if(g_rab2_buffer.pos <= 127)
+    {
+        datalen = g_rab2_buffer.pos;
+	    buffer_copy(&g_rab1_buffer, &datalen, sizeof(datalen));
+    }
+    else
+    {
+        uint16_t rab2_pay_len  = g_rab2_buffer.pos | 0x8000; // set MSB to 1 
+        unsigned char lenStr[2];
+        lenStr[0] = rab2_pay_len >> 8;
+        lenStr[1] = rab2_pay_len & 0xff;
+	    buffer_copy(&g_rab1_buffer, lenStr, sizeof(lenStr));
+    }
+	buffer_copy(&g_rab1_buffer, &g_rab2_buffer.buf[0], g_rab2_buffer.pos);
+    /* rab1 + rab2 is appended */ 
+    // rab1 is combined now ... 
+
+    /*g_s1ap_buffer is having rab appended to it.. */
+
+	log_msg(LOG_INFO, "RAB1 payload length %d\n", g_rab1_buffer.pos);
+    if(g_rab1_buffer.pos <= 127)
+    {
+        datalen = g_rab1_buffer.pos;
+	    buffer_copy(&(g_s1ap_buffer), &datalen, sizeof(datalen));
+    }
+    else
+    {
+        uint16_t rab1_pay_len  = g_rab1_buffer.pos | 0x8000; // set MSB to 1 
+        unsigned char lenStr[2];
+        lenStr[0] = rab1_pay_len >> 8;
+        lenStr[1] = rab1_pay_len & 0xff;
+	    buffer_copy(&g_s1ap_buffer, lenStr, sizeof(lenStr));
+    }
+	buffer_copy(&g_s1ap_buffer, &g_rab1_buffer.buf[0], g_rab1_buffer.pos);
+    /* RAB is appended to s1ap payload now */ 
+
+	/* id-UESecurityCapabilities */
+	char ue_sec_capab[5] = {0x1c, 0x00, 0x0c, 0x00, 0x00};
+	protocolIe_Id = id_UESecurityCapabilities;
+	copyU16(tmpStr, protocolIe_Id);
+	buffer_copy(&g_s1ap_buffer, tmpStr, sizeof(protocolIe_Id));
+	protocolIe_criticality = CRITICALITY_REJECT;
+	buffer_copy(&g_s1ap_buffer, &protocolIe_criticality,
+					sizeof(protocolIe_criticality));
+	datalen = 5;
+	buffer_copy(&g_s1ap_buffer, &datalen, sizeof(datalen));
+	buffer_copy(&g_s1ap_buffer, ue_sec_capab, 5);
+
+	protocolIe_Id = id_SecurityKey;
+	copyU16(tmpStr, protocolIe_Id);
+	buffer_copy(&g_s1ap_buffer, tmpStr, sizeof(protocolIe_Id));
+	protocolIe_criticality = CRITICALITY_REJECT;
+	buffer_copy(&g_s1ap_buffer, &protocolIe_criticality,
+					sizeof(protocolIe_criticality));
+	datalen = SECURITY_KEY_SIZE;
+	buffer_copy(&g_s1ap_buffer, &datalen, sizeof(datalen));
+	buffer_copy(&g_s1ap_buffer, s1apPDU.value.data[5].val.sec_key,
+					SECURITY_KEY_SIZE);
+
+	/* Copy length to s1ap length field */
+	//datalen = g_s1ap_buffer.pos - s1ap_len_pos - 1;
+	//uint16_t s1aplen = g_s1ap_buffer.pos - s1ap_len_pos - 1;
+	log_msg(LOG_INFO, "S1AP payload length %d\n", g_s1ap_buffer.pos);
+	uint16_t s1aplen = g_s1ap_buffer.pos;
+    if(s1aplen <= 127 )
+    {
+        datalen = s1aplen; 
+	    buffer_copy(&g_ics_buffer, &datalen, sizeof(datalen));
+    }
+    else
+    {
+        s1aplen  = g_s1ap_buffer.pos | 0x8000; // set MSB to 1 
+        unsigned char lenStr[2];
+        lenStr[0] = s1aplen >> 8;
+        lenStr[1] = s1aplen & 0xff;
+	    buffer_copy(&g_ics_buffer, lenStr, sizeof(lenStr));
+    }
+
+    /* this is my final s1ap buffer */
+	buffer_copy(&g_ics_buffer, &g_s1ap_buffer.buf[0], g_s1ap_buffer.pos);
+
+	free(s1apPDU.value.data[3].val.E_RABToBeSetupItemCtxtSUReq.nas.elements);
+	free(s1apPDU.value.data);
+
+	send_sctp_msg(g_icsReqInfo->enb_fd, g_ics_buffer.buf, g_ics_buffer.pos, 1);
+	log_msg(LOG_INFO,"Initial Context Setup Request sent successfully\n");
+	return SUCCESS;
+}
+
+void*
+icsreq_handler(void *data)
+{
+	log_msg(LOG_INFO, "icsreq handler ready.\n");
+
+
+	icsreq_processing((struct init_ctx_req_Q_msg *)data);
+
+
+	return NULL;
+}
diff --git a/src/s1ap/handlers/attach_id_req.c b/src/s1ap/handlers/attach_id_req.c
new file mode 100644
index 0000000..45b1dcc
--- /dev/null
+++ b/src/s1ap/handlers/attach_id_req.c
@@ -0,0 +1,213 @@
+/*
+* Copyright 2019-present Open Networking Foundation
+*
+* SPDX-License-Identifier: Apache-2.0
+*
+* 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 <pthread.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdint.h>
+
+#include "log.h"
+#include "err_codes.h"
+#include "s1ap.h"
+#include "message_queues.h"
+#include "ipc_api.h"
+
+#include "main.h"
+#include "sctp_conn.h"
+#include "msgType.h"
+
+
+
+/**
+* Get ProtocolIE value ID Request sent by mme-app
+*/
+static int
+get_attach_id_request_protoie_value(struct proto_IE *value,struct attachIdReq_info *g_attachIdReqInfo)
+{
+	
+	
+	value->no_of_IEs = ATTACH_ID_REQUEST_NO_OF_IES;
+	
+	value->data = (proto_IEs *) malloc(ATTACH_ID_REQUEST_NO_OF_IES*
+			sizeof(proto_IEs));
+	
+
+	value->data[0].val.mme_ue_s1ap_id = g_attachIdReqInfo->ue_idx;
+	
+	value->data[1].val.enb_ue_s1ap_id = g_attachIdReqInfo->s1ap_enb_ue_id;
+    
+
+	log_msg(LOG_INFO, "mme_ue_s1ap_id %d and enb_ue_s1ap_id %d\n",
+			g_attachIdReqInfo->ue_idx, g_attachIdReqInfo->s1ap_enb_ue_id);
+
+	/* TODO: Add enum for security header type */
+	value->data[2].val.nas.header.security_header_type = 0;
+	value->data[2].val.nas.header.proto_discriminator = EPSMobilityManagementMessages;
+	value->data[2].val.nas.header.message_type = IdentityRequest;
+	value->data[2].val.nas.header.nas_security_param = 0;
+
+	return SUCCESS;
+}
+
+
+/**
+* Stage specific message processing.
+*/
+static int
+s1ap_attach_id_req_processing(struct attachIdReq_info *g_attachIdReqInfo)
+{
+	struct Buffer g_buffer;
+	struct Buffer g_value_buffer;
+	struct Buffer g_nas_buffer;
+
+	struct s1ap_PDU s1apPDU= {0};
+
+
+	s1apPDU.procedurecode = id_downlinkNASTransport;
+	s1apPDU.criticality = CRITICALITY_IGNORE;
+
+	get_attach_id_request_protoie_value(&s1apPDU.value,g_attachIdReqInfo);
+
+	/* Copy values to buffer from s1apPDU */
+
+	g_buffer.pos = 0;
+
+	uint8_t initiating_message = 0; /* TODO: Add enum */
+	buffer_copy(&g_buffer, &initiating_message,
+			sizeof(initiating_message));
+
+	buffer_copy(&g_buffer, &s1apPDU.procedurecode,
+			sizeof(s1apPDU.procedurecode));
+
+	buffer_copy(&g_buffer, &s1apPDU.criticality,
+			sizeof(s1apPDU.criticality));
+
+	/* Copy values in g_value_buffer */
+	g_value_buffer.pos = 0;
+
+	/* TODO remove hardcoded values */
+	unsigned char chProtoIENo[3] = {0,0,3};
+
+	buffer_copy(&g_value_buffer, chProtoIENo, 3);
+
+	unsigned char tmpStr[4];
+	/* id-MME-UE-S1AP-ID */
+	uint16_t protocolIe_Id = id_MME_UE_S1AP_ID;
+	copyU16(tmpStr, protocolIe_Id);
+	buffer_copy(&g_value_buffer, tmpStr,
+					sizeof(protocolIe_Id));
+
+	uint8_t protocolIe_criticality = CRITICALITY_REJECT;
+	buffer_copy(&g_value_buffer, &protocolIe_criticality,
+					sizeof(protocolIe_criticality));
+
+	uint8_t datalen = 2;
+
+	/* TODO needs proper handling*/
+	unsigned char mme_ue_id[3];
+	datalen = copyU16(mme_ue_id,
+			s1apPDU.value.data[0].val.mme_ue_s1ap_id);
+	buffer_copy(&g_value_buffer, &datalen, sizeof(datalen));
+	buffer_copy(&g_value_buffer, mme_ue_id, datalen);
+
+	/* id-eNB-UE-S1AP-ID */
+
+	protocolIe_Id = id_eNB_UE_S1AP_ID;
+	copyU16(tmpStr, protocolIe_Id);
+	buffer_copy(&g_value_buffer, tmpStr,
+						sizeof(protocolIe_Id));
+
+	buffer_copy(&g_value_buffer, &protocolIe_criticality,
+					sizeof(protocolIe_criticality));
+
+
+	/* TODO needs proper handling*/
+	unsigned char enb_ue_id[3];
+	datalen = copyU16(enb_ue_id,
+			s1apPDU.value.data[1].val.enb_ue_s1ap_id);
+	buffer_copy(&g_value_buffer, &datalen, sizeof(datalen));
+	buffer_copy(&g_value_buffer, enb_ue_id, datalen);
+	
+
+	/* id-NAS-PDU */
+	protocolIe_Id = id_NAS_PDU;
+	copyU16(tmpStr, protocolIe_Id);
+	buffer_copy(&g_value_buffer, tmpStr,
+						sizeof(protocolIe_Id));
+
+	buffer_copy(&g_value_buffer, &protocolIe_criticality,
+					sizeof(protocolIe_criticality));
+
+	struct nasPDU *nas = &(s1apPDU.value.data[2].val.nas);
+	uint8_t value = (nas->header.security_header_type) |
+			nas->header.proto_discriminator;
+
+	g_nas_buffer.pos = 0;
+
+	buffer_copy(&g_nas_buffer, &value, sizeof(value));
+
+	buffer_copy(&g_nas_buffer, &nas->header.message_type,
+						sizeof(nas->header.message_type));
+
+    value = g_attachIdReqInfo->ue_type; 
+	buffer_copy(&g_nas_buffer, &value, sizeof(value));
+
+	datalen = g_nas_buffer.pos + 1;
+
+	buffer_copy(&g_value_buffer, &datalen,
+						sizeof(datalen));
+
+	buffer_copy(&g_value_buffer, &g_nas_buffer.pos,
+						sizeof(g_nas_buffer.pos));
+
+
+	buffer_copy(&g_value_buffer, &g_nas_buffer,
+						g_nas_buffer.pos);
+
+	buffer_copy(&g_buffer, &g_value_buffer.pos,
+						sizeof(g_value_buffer.pos));
+
+	buffer_copy(&g_buffer, &g_value_buffer,
+						g_value_buffer.pos);
+
+	free(s1apPDU.value.data[2].val.nas.elements);
+	free(s1apPDU.value.data);
+
+	send_sctp_msg(g_attachIdReqInfo->enb_fd, g_buffer.buf, g_buffer.pos, 1);
+	
+	return SUCCESS;
+}
+
+
+
+/**
+* Thread function for stage.
+*/
+void*
+idreq_handler(void *data)
+{
+	
+	log_msg(LOG_INFO, "S1Ap attach Id Request handler ready.\n");
+
+	s1ap_attach_id_req_processing((struct attachIdReq_info *)data);
+
+	return NULL;
+}
+
diff --git a/src/s1ap/handlers/attach_id_resp.c b/src/s1ap/handlers/attach_id_resp.c
new file mode 100644
index 0000000..3c8c4c8
--- /dev/null
+++ b/src/s1ap/handlers/attach_id_resp.c
@@ -0,0 +1,96 @@
+/*
+ * 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 "err_codes.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 "msgType.h"
+
+
+extern int g_enb_fd;
+extern ipc_handle ipc_S1ap_Hndl;
+extern struct time_stat g_attach_stats[];
+
+int
+s1_identity_resp_handler(struct proto_IE *s1_id_resp_ies)
+{
+	struct s1_incoming_msg_data_t id_resp= {0};
+
+	/*****Message structure***
+	*/
+	log_msg(LOG_INFO, "Parse s1ap identity resp message:--\n");
+
+	/*Validate all eNB info*/
+
+	/*Add eNB info to hash*/
+
+	/*Create Q structure for stage 1 to MME.
+	  contains init UE information.*/
+	id_resp.msg_type = id_response;
+    for(int i = 0; i < s1_id_resp_ies->no_of_IEs; i++)
+    {
+        switch(s1_id_resp_ies->data[i].IE_type)
+        {
+            case S1AP_IE_MME_UE_ID:
+                {
+	                id_resp.ue_idx = s1_id_resp_ies->data[i].val.mme_ue_s1ap_id;
+                }break;
+            case S1AP_IE_NAS_PDU:
+                {
+                    if(s1_id_resp_ies->data[i].val.nas.header.message_type != NAS_IDENTITY_RESPONSE)
+                    {
+                        id_resp.msg_data.identityResp_Q_msg_m.status  = S1AP_IDENTITY_FAILED; 
+                    }
+                    else
+                    {
+                        id_resp.msg_data.identityResp_Q_msg_m.status = SUCCESS;
+                    }
+
+                    memcpy(&(id_resp.msg_data.identityResp_Q_msg_m.IMSI), 
+                           &(s1_id_resp_ies->data[i].val.nas.elements[0].pduElement.IMSI),
+                           BINARY_IMSI_LEN);
+                }break;
+            default:
+                log_msg(LOG_WARNING,"Unhandled IE In identification Response %d",s1_id_resp_ies->data[i].IE_type);
+        }
+    }
+	id_resp.destInstAddr = htonl(mmeAppInstanceNum_c);
+	id_resp.srcInstAddr = htonl(s1apAppInstanceNum_c);
+
+	//STIMER_GET_CURRENT_TP(g_attach_stats[s1_id_resp_ies->data[1].enb_ue_s1ap_id].auth_to_mme);
+	send_tipc_message(ipc_S1ap_Hndl, mmeAppInstanceNum_c, (char *)&id_resp, S1_READ_MSG_BUF_SIZE);
+
+	/*Send S1Setup response*/
+	log_msg(LOG_INFO, "Id resp send to mme-app stage3.\n");
+
+	//TODO: free IEs
+	return SUCCESS;
+}
+
+
diff --git a/src/s1ap/handlers/attach_initctxresp.c b/src/s1ap/handlers/attach_initctxresp.c
new file mode 100644
index 0000000..3c3404b
--- /dev/null
+++ b/src/s1ap/handlers/attach_initctxresp.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2003-2018, Great Software Laboratory Pvt. Ltd.
+ * Copyright (c) 2017 Intel Corporation
+ * Copyright (c) 2019, Infosys Ltd.
+ *
+ * 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 "err_codes.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 "msgType.h"
+
+
+extern int g_enb_fd;
+extern ipc_handle ipc_S1ap_Hndl;
+
+int
+s1_init_ctx_resp_handler(SuccessfulOutcome_t *msg)
+{
+	struct proto_IE s1_ics_ies;
+	struct s1_incoming_msg_data_t ics_resp= {0};
+
+	/*****Message structure****/
+	log_msg(LOG_INFO, "Parse int ctx s1ap response message:--\n");
+	/*parse_IEs(msg+2, &s1_ics_ies, S1AP_INITIAL_CTX_RESP_CODE);*/
+	convertInitCtxRspToProtoIe(msg, &s1_ics_ies);
+    
+	ics_resp.msg_type = init_ctxt_response;
+	
+	for(int i = 0; i < s1_ics_ies.no_of_IEs; i++)
+    {
+        switch(s1_ics_ies.data[i].IE_type)
+        {
+            case S1AP_IE_MME_UE_ID:
+                {
+	                ics_resp.ue_idx = s1_ics_ies.data[i].val.mme_ue_s1ap_id;
+                }break;
+            case S1AP_ERAB_SETUP_CTX_SUR:
+                {
+                    for(int j = 0; j < s1_ics_ies.data[i].val.erab.no_of_elements; j++)
+                    {
+                        /*TBD: Handle multiple erabs in ics rsp*/
+	                    ics_resp.msg_data.initctx_resp_Q_msg_m.transp_layer_addr = s1_ics_ies.data[i].val.erab.elements[j].su_res.transp_layer_addr;
+	                    ics_resp.msg_data.initctx_resp_Q_msg_m.gtp_teid = s1_ics_ies.data[i].val.erab.elements[j].su_res.gtp_teid;
+                        break;
+                    }
+                }break;
+            default:
+                log_msg(LOG_WARNING,"Unhandled IE");
+        }
+    }
+	
+	
+	
+	ics_resp.destInstAddr = htonl(mmeAppInstanceNum_c);
+	ics_resp.srcInstAddr = htonl(s1apAppInstanceNum_c);
+	int i = send_tipc_message(ipc_S1ap_Hndl, mmeAppInstanceNum_c, (char *)&ics_resp, S1_READ_MSG_BUF_SIZE);
+
+	if (i < 0) {
+		log_msg(LOG_ERROR, "Error to write in s1_init_ctx_resp_handler\n");
+	}
+	/*Send S1Setup response*/
+	log_msg(LOG_INFO, "Init ctx resp send to mme-app stage7. Bytes send %d\n", i);
+
+	//TODO: free IEs
+	return SUCCESS;
+}
diff --git a/src/s1ap/handlers/attach_initue.c b/src/s1ap/handlers/attach_initue.c
new file mode 100644
index 0000000..f62394f
--- /dev/null
+++ b/src/s1ap/handlers/attach_initue.c
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2003-2018, Great Software Laboratory Pvt. Ltd.
+ * Copyright (c) 2017 Intel Corporation
+ * Copyright (c) 2019, Infosys Ltd.
+ *
+ * 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 "err_codes.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 "msgType.h"
+
+extern int g_enb_fd;
+extern ipc_handle ipc_S1ap_Hndl;
+extern struct time_stat g_attach_stats[];
+
+int
+s1_init_ue_handler(struct proto_IE *s1_init_ies, int enodeb_fd)
+{
+	struct s1_incoming_msg_data_t ue_info = {0};
+    	int nas_index = 0;
+
+	/*****Message structure***
+	*/
+	log_msg(LOG_INFO, "Parse s1ap initial UE message\n");
+
+	/*Validate all eNB info*/
+
+	/*Add eNB info to hash*/
+	//STIMER_GET_CURRENT_TP(g_attach_stats[s1_init_ies->data[0].enb_ue_s1ap_id].init_ue);
+
+	/*Create Q structure for stage 1 to MME.
+	  contains init UE information.*/
+	ue_info.msg_type = attach_request;
+			
+	ue_info.msg_data.ue_attach_info_m.enb_fd = enodeb_fd;
+	ue_info.msg_data.ue_attach_info_m.criticality = s1_init_ies->criticality;//TBD
+    for(int i = 0; i < s1_init_ies->no_of_IEs; i++)
+    {
+        switch(s1_init_ies->data[i].IE_type)
+        {
+            case S1AP_IE_ENB_UE_ID:
+                {
+	                ue_info.msg_data.ue_attach_info_m.s1ap_enb_ue_id = s1_init_ies->data[i].val.enb_ue_s1ap_id;
+                }break;
+            case S1AP_IE_TAI:
+                {
+                    memcpy(&(ue_info.msg_data.ue_attach_info_m.tai), &(s1_init_ies->data[i].val.tai), sizeof(struct TAI));
+                }break;
+            case S1AP_IE_UTRAN_CGI:
+                {
+                    memcpy(&(ue_info.msg_data.ue_attach_info_m.utran_cgi), &(s1_init_ies->data[i].val.utran_cgi),
+                           sizeof(struct CGI));
+                }break;
+            case S1AP_IE_NAS_PDU:
+                {
+                    while(nas_index < s1_init_ies->data[i].val.nas.elements_len)
+                    {
+                        log_msg(LOG_INFO, "nasIndex %d, msgType %d\n",
+                                nas_index,
+                                s1_init_ies->data[i].val.nas.elements[nas_index].msgType);
+                        ue_info.msg_data.ue_attach_info_m.seq_no = s1_init_ies->data[i].val.nas.header.seq_no;
+                        switch(s1_init_ies->data[i].val.nas.elements[nas_index].msgType)
+                        {
+                            case NAS_IE_TYPE_ESM_MSG:
+                                {
+                                    break;
+                                }
+                            case NAS_IE_TYPE_EPS_MOBILE_ID_IMSI:
+                                {
+                                    ue_info.msg_data.ue_attach_info_m.flags = s1_init_ies->data[i].val.nas.flags;
+                                    if(UE_ID_IMSI(s1_init_ies->data[i].val.nas.flags))
+                                    { 
+                                        memcpy(&(ue_info.msg_data.ue_attach_info_m.IMSI), 
+                                               &(s1_init_ies->data[i].val.nas.elements[nas_index].pduElement.IMSI),
+                                               BINARY_IMSI_LEN);
+                                    }
+                                    else if(UE_ID_GUTI(s1_init_ies->data[i].val.nas.flags))
+                                    {
+                                        memcpy(&(ue_info.msg_data.ue_attach_info_m.mi_guti), &(s1_init_ies->data[i].val.nas.elements[nas_index].pduElement.mi_guti),
+                                               sizeof(struct guti));
+                                    }
+                                    break;
+                                }
+                            case NAS_IE_TYPE_UE_NETWORK_CAPABILITY:
+                                {
+                                    memcpy(&(ue_info.msg_data.ue_attach_info_m.ue_net_capab),
+                                           &(s1_init_ies->data[i].val.nas.\
+                                             elements[nas_index].pduElement.ue_network),
+                                           sizeof(struct UE_net_capab));
+
+                                    break;
+                                }
+                            case NAS_IE_TYPE_MS_NETWORK_CAPABILITY:
+                                {
+                                    memcpy(&(ue_info.msg_data.ue_attach_info_m.ms_net_capab),
+                                           &(s1_init_ies->data[i].val.nas.\
+                                             elements[nas_index].pduElement.ms_network),
+                                           sizeof(struct MS_net_capab));
+
+                                    break;
+                                }
+                            case NAS_IE_TYPE_TX_FLAG:
+                                {
+                                    ue_info.msg_data.ue_attach_info_m.esm_info_tx_required =
+                                        s1_init_ies->data[i].val.nas.elements[nas_index].pduElement.esm_info_tx_required;
+				    log_msg(LOG_INFO, "ESM info flag %d \n", ue_info.msg_data.ue_attach_info_m.esm_info_tx_required);
+                                    break;
+                                }
+                            case NAS_IE_TYPE_PTI:
+                                {
+                                    ue_info.msg_data.ue_attach_info_m.pti =
+                                        s1_init_ies->data[i].val.nas.elements[nas_index].pduElement.pti;
+                                    break;
+                                }
+                            case NAS_IE_TYPE_PCO:
+                                {
+                                    for(int pco=0; pco < 10; pco++)
+                                    {
+                                        ue_info.msg_data.ue_attach_info_m.pco_options[pco] = 
+                                            s1_init_ies->data[i].val.nas.elements[nas_index].pduElement.pco_options[pco];
+                                    }
+                                    break;
+                                }
+                            default:
+                                {
+                                    log_msg(LOG_INFO, "nas element not handled\n");
+                                }
+                        }
+
+                        nas_index++;
+                    }
+
+                }break;
+            default:
+                log_msg(LOG_WARNING,"Unhandled IE");
+        }
+    }
+
+	ue_info.destInstAddr = htonl(mmeAppInstanceNum_c);
+	ue_info.srcInstAddr = htonl(s1apAppInstanceNum_c);
+
+	send_tipc_message(ipc_S1ap_Hndl, mmeAppInstanceNum_c, (char *)&ue_info, S1_READ_MSG_BUF_SIZE);
+
+	/*Send S1Setup response*/
+	log_msg(LOG_INFO, "Send to mme-app stage1.\n");
+
+	return SUCCESS;
+}
+
+
diff --git a/src/s1ap/handlers/attach_reject.c b/src/s1ap/handlers/attach_reject.c
new file mode 100644
index 0000000..38c20dd
--- /dev/null
+++ b/src/s1ap/handlers/attach_reject.c
@@ -0,0 +1,231 @@
+/*
+* Copyright 2019-present Open Networking Foundation
+*
+* SPDX-License-Identifier: Apache-2.0
+*
+* 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 <pthread.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "log.h"
+#include "err_codes.h"
+#include "s1ap.h"
+#include "message_queues.h"
+#include "ipc_api.h"
+#include "main.h"
+#include "sctp_conn.h"
+#include "msgType.h"
+
+
+
+
+/**
+* Get ProtocolIE value for Auth Request sent by mme-app
+*/
+static int
+get_attachReject_protoie_value(struct proto_IE *value, struct attachReqRej_info *g_attachReqRejInfo)
+{
+	value->no_of_IEs = AUTH_REQ_NO_OF_IES;
+
+	value->data = (proto_IEs *) malloc(ATTACH_REJECT_NO_OF_IES*
+			sizeof(proto_IEs));
+
+	value->data[0].val.mme_ue_s1ap_id = g_attachReqRejInfo->ue_idx;
+	value->data[1].val.enb_ue_s1ap_id = g_attachReqRejInfo->s1ap_enb_ue_id;
+
+	log_msg(LOG_INFO, "mme_ue_s1ap_id %d and enb_ue_s1ap_id %d\n",
+			g_attachReqRejInfo->ue_idx, g_attachReqRejInfo->s1ap_enb_ue_id);
+
+	/* TODO: Add enum for security header type */
+	value->data[2].val.nas.header.security_header_type = 0;
+	value->data[2].val.nas.header.proto_discriminator = EPSMobilityManagementMessages;
+	value->data[2].val.nas.header.message_type = AttachReject;
+	value->data[2].val.nas.header.nas_security_param = 0;
+
+#if 0
+	value->data[2].nas.elements = (nas_pdu_elements *)
+			malloc(AUTH_REQ_NO_OF_NAS_IES * sizeof(nas_pdu_elements));
+
+	memcpy(value->data[2].nas.elements[0].rand,
+			g_attachReqRejInfo->rand, NAS_RAND_SIZE);
+	memcpy(value->data[2].nas.elements[1].autn,
+			g_attachReqRejInfo->autn, NAS_AUTN_SIZE);
+#endif
+
+
+	return SUCCESS;
+}
+
+
+/**
+* Stage specific message processing.
+*/
+static int
+s1ap_attach_reject_processing(struct attachReqRej_info *g_attachReqRejInfo)
+{
+	struct Buffer g_buffer;
+	struct Buffer g_value_buffer;
+	struct Buffer g_nas_buffer;
+	struct s1ap_PDU s1apPDU= {0};
+
+
+
+	/* Assigning values to s1apPDU */
+	s1apPDU.procedurecode = id_downlinkNASTransport;
+	s1apPDU.criticality = CRITICALITY_IGNORE;
+
+	get_attachReject_protoie_value(&s1apPDU.value,g_attachReqRejInfo);
+
+	/* Copy values to buffer from s1apPDU */
+
+	g_buffer.pos = 0;
+
+	uint8_t initiating_message = 0; /* TODO: Add enum */
+	buffer_copy(&g_buffer, &initiating_message,
+			sizeof(initiating_message));
+
+	buffer_copy(&g_buffer, &s1apPDU.procedurecode,
+			sizeof(s1apPDU.procedurecode));
+
+	buffer_copy(&g_buffer, &s1apPDU.criticality,
+			sizeof(s1apPDU.criticality));
+
+	/* Copy values in g_value_buffer */
+	g_value_buffer.pos = 0;
+
+	/* TODO remove hardcoded values */
+	unsigned char chProtoIENo[3] = {0,0,3};
+
+	buffer_copy(&g_value_buffer, chProtoIENo, 3);
+
+	unsigned char tmpStr[4];
+
+	/* id-MME-UE-S1AP-ID */
+	uint16_t protocolIe_Id = id_MME_UE_S1AP_ID;
+	copyU16(tmpStr, protocolIe_Id);
+	buffer_copy(&g_value_buffer, tmpStr,
+					sizeof(protocolIe_Id));
+
+	uint8_t protocolIe_criticality = CRITICALITY_REJECT;
+	buffer_copy(&g_value_buffer, &protocolIe_criticality,
+					sizeof(protocolIe_criticality));
+
+	uint8_t datalen = 2;
+
+	/* TODO needs proper handling*/
+	unsigned char mme_ue_id[3];
+	datalen = copyU16(mme_ue_id,
+			s1apPDU.value.data[0].val.mme_ue_s1ap_id);
+	buffer_copy(&g_value_buffer, &datalen, sizeof(datalen));
+	buffer_copy(&g_value_buffer, mme_ue_id, datalen);
+
+	/* id-eNB-UE-S1AP-ID */
+
+	protocolIe_Id = id_eNB_UE_S1AP_ID;
+	copyU16(tmpStr, protocolIe_Id);
+	buffer_copy(&g_value_buffer, tmpStr,
+						sizeof(protocolIe_Id));
+
+	buffer_copy(&g_value_buffer, &protocolIe_criticality,
+					sizeof(protocolIe_criticality));
+
+
+	/* TODO needs proper handling*/
+	unsigned char enb_ue_id[3];
+	datalen = copyU16(enb_ue_id,
+			s1apPDU.value.data[1].val.enb_ue_s1ap_id);
+	buffer_copy(&g_value_buffer, &datalen, sizeof(datalen));
+	buffer_copy(&g_value_buffer, enb_ue_id, datalen);
+
+	/* id-NAS-PDU */
+	protocolIe_Id = id_NAS_PDU;
+	copyU16(tmpStr, protocolIe_Id);
+	buffer_copy(&g_value_buffer, tmpStr,
+						sizeof(protocolIe_Id));
+
+	buffer_copy(&g_value_buffer, &protocolIe_criticality,
+					sizeof(protocolIe_criticality));
+
+	struct nasPDU *nas = &(s1apPDU.value.data[2].val.nas);
+	uint8_t value = (nas->header.security_header_type) |
+			nas->header.proto_discriminator;
+
+	g_nas_buffer.pos = 0;
+
+	buffer_copy(&g_nas_buffer, &value, sizeof(value));
+
+	buffer_copy(&g_nas_buffer, &nas->header.message_type,
+						sizeof(nas->header.message_type));
+
+#if 0
+	buffer_copy(&g_nas_buffer, &nas->header.nas_security_param,
+						sizeof(nas->header.nas_security_param));
+
+#endif
+    value = 0x09; // UE identity can not be derived by the network
+	buffer_copy(&g_nas_buffer, &value, sizeof(value));
+
+#if 0
+	buffer_copy(&g_nas_buffer, &nas->elements[0].pduElement.rand,
+						sizeof(nas->elements[0].pduElement.rand));
+
+	datalen = 16;
+	buffer_copy(&g_nas_buffer, &datalen, sizeof(datalen));
+
+	buffer_copy(&g_nas_buffer, &nas->elements[1].pduElement.autn,
+						sizeof(nas->elements[1].pduElement.autn));
+
+    /* Done with filling NAS message */
+#endif
+	datalen = g_nas_buffer.pos + 1;
+
+	buffer_copy(&g_value_buffer, &datalen,
+						sizeof(datalen));
+
+	buffer_copy(&g_value_buffer, &g_nas_buffer.pos,
+						sizeof(g_nas_buffer.pos));
+
+
+	buffer_copy(&g_value_buffer, &g_nas_buffer,
+						g_nas_buffer.pos);
+
+	buffer_copy(&g_buffer, &g_value_buffer.pos,
+						sizeof(g_value_buffer.pos));
+
+	buffer_copy(&g_buffer, &g_value_buffer,
+						g_value_buffer.pos);
+
+	free(s1apPDU.value.data[2].val.nas.elements);
+	free(s1apPDU.value.data);
+	send_sctp_msg(g_attachReqRejInfo->enb_fd, g_buffer.buf, g_buffer.pos,1);
+	return SUCCESS;
+}
+
+
+void*
+attach_reject_handler(void *data)
+{
+	
+	log_msg(LOG_INFO, "S1Ap attach Reject handler ready.\n");
+
+s1ap_attach_reject_processing((struct attachReqRej_info *)data);
+
+	
+	return NULL;
+}
+
diff --git a/src/s1ap/handlers/attach_secmoderesp.c b/src/s1ap/handlers/attach_secmoderesp.c
new file mode 100644
index 0000000..0215075
--- /dev/null
+++ b/src/s1ap/handlers/attach_secmoderesp.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2003-2018, Great Software Laboratory Pvt. Ltd.
+ * Copyright (c) 2017 Intel Corporation
+ * Copyright (c) 2019, Infosys Ltd.
+ *
+ * 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 "err_codes.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 "msgType.h"
+
+
+extern int g_enb_fd;
+extern ipc_handle ipc_S1ap_Hndl;
+
+int
+s1_secmode_resp_handler(struct proto_IE *s1_sec_resp_ies)
+{
+	//TODO: use static instead of synamic for perf.
+	struct s1_incoming_msg_data_t secmode_resp= {0};
+
+	/*****Message structure***
+	*/
+	log_msg(LOG_INFO, "Parse s1ap sec mode complete message:--\n");
+
+	/*Validate all eNB info*/
+
+	/*Add eNB info to hash*/
+
+	/*Create Q structure for stage 1 to MME.
+	  contains init UE information.*/
+	secmode_resp.msg_type = sec_mode_complete;
+	
+	for(int i = 0; i < s1_sec_resp_ies->no_of_IEs; i++)
+    {
+        switch(s1_sec_resp_ies->data[i].IE_type)
+        {
+            case S1AP_IE_MME_UE_ID:
+                {
+	                secmode_resp.ue_idx = s1_sec_resp_ies->data[i].val.mme_ue_s1ap_id;
+                }break;
+            case S1AP_IE_NAS_PDU:
+                {
+                    if(s1_sec_resp_ies->data[i].val.nas.header.message_type != NAS_SEC_MODE_COMPLETE)
+                    {
+                        secmode_resp.msg_data.secmode_resp_Q_msg_m.status = S1AP_SECMODE_FAILED;//Error in authentication
+                    }
+                    else
+                    {
+                        secmode_resp.msg_data.secmode_resp_Q_msg_m.status = SUCCESS;
+                    }
+
+                }break;
+            default:
+                log_msg(LOG_WARNING,"Unhandled IE");
+        }
+    }
+
+	/*Copy xres from response, send to mme for verification*/
+	//...
+	//auth_res.res.len = a1_secmode_resp_ies[2].data.nas.authresp_len;
+	//memcpy(&(auth_res.res.val, s1_sec_resp_ies[2].data.nas.RES, authres.res.len);
+
+	secmode_resp.destInstAddr = htonl(mmeAppInstanceNum_c);
+	secmode_resp.srcInstAddr = htonl(s1apAppInstanceNum_c);
+	send_tipc_message(ipc_S1ap_Hndl, mmeAppInstanceNum_c, (char *)&secmode_resp, S1_READ_MSG_BUF_SIZE);
+
+	/*Send S1Setup response*/
+	log_msg(LOG_INFO, "Auth resp send to mme-app stage4.\n");
+
+	//TODO: free IEs
+	return SUCCESS;
+}
+
diff --git a/src/s1ap/handlers/attach_secreq.c b/src/s1ap/handlers/attach_secreq.c
new file mode 100644
index 0000000..8dfff86
--- /dev/null
+++ b/src/s1ap/handlers/attach_secreq.c
@@ -0,0 +1,293 @@
+/*
+ * Copyright (c) 2003-2018, Great Software Laboratory Pvt. Ltd.
+ * Copyright (c) 2017 Intel Corporation
+ * Copyright (c) 2019, Infosys Ltd.
+ *
+ * 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 <pthread.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdint.h>
+
+#include "err_codes.h"
+#include "message_queues.h"
+#include "ipc_api.h"
+#include "log.h"
+#include "main.h"
+#include "s1ap.h"
+#include "sctp_conn.h"
+#include "msgType.h"
+#include "snow_3g.h"
+
+/**
+* Get ProtocolIE value for Sec Request sent by mme-app
+*/
+static int
+get_secreq_protoie_value(struct proto_IE *value, struct sec_mode_Q_msg * g_secReqInfo)
+{
+	value->no_of_IEs = SEC_MODE_NO_OF_IES;
+
+	value->data = (proto_IEs *) malloc(SEC_MODE_NO_OF_IES *
+			sizeof(proto_IEs));
+
+	value->data[0].val.mme_ue_s1ap_id = g_secReqInfo->ue_idx;
+	value->data[1].val.enb_ue_s1ap_id = g_secReqInfo->enb_s1ap_ue_id;
+
+	value->data[2].val.nas.header.security_header_type =
+			IntegrityProtectedEPSSecCntxt;
+
+	value->data[2].val.nas.header.proto_discriminator =
+			EPSMobilityManagementMessages;
+
+	/* placeholder for mac. mac value will be calculated later */
+	uint8_t mac[MAC_SIZE] = {0};
+	memcpy(value->data[2].val.nas.header.mac, mac, MAC_SIZE);
+
+	value->data[2].val.nas.header.seq_no = g_secReqInfo->dl_seq_no;
+
+	value->data[2].val.nas.header.message_type = SecurityModeCommand;
+
+	value->data[2].val.nas.header.security_encryption_algo = Algo_EEA0;
+
+	value->data[2].val.nas.header.security_integrity_algo = Algo_128EIA1;
+
+	/* Security Param (1 octet) =
+	 * Spare half octet, Type of Security, NAS KSI
+	 * TODO: Remove hard coded value
+	 */
+	value->data[2].val.nas.header.nas_security_param = AUTHREQ_NAS_SECURITY_PARAM;
+
+	value->data[2].val.nas.elements_len = SEC_MODE_NO_OF_NAS_IES;
+
+	value->data[2].val.nas.elements = (nas_pdu_elements *)
+			malloc(SEC_MODE_NO_OF_NAS_IES * sizeof(nas_pdu_elements));
+
+	value->data[2].val.nas.elements->pduElement.ue_network.len =
+			g_secReqInfo->ue_network.len;
+	if(g_secReqInfo->ue_network.len >= 4)
+	{
+        /*Copy first 4 bytes of security algo info*/
+	    memcpy(value->data[2].val.nas.elements->pduElement.ue_network.capab, 
+               g_secReqInfo->ue_network.capab, 4);
+	   
+        log_msg(LOG_DEBUG, "UE network length : %d", g_secReqInfo->ue_network.len);
+        if(g_secReqInfo->ms_net_capab.pres == true)
+	    {
+	        /*The MS Network capability contains the GEA
+		* capability. The MSB of 1st Byte and the 2nd to
+		* 7th Bit of 2nd byte contain the GEA info.
+		* Thus the masks 0x7F : for GEA/1
+		* and mask 0x7D: for GEA2 -GEA7
+		*/
+            log_msg(LOG_DEBUG, "MS network present"); 
+	        value->data[2].val.nas.elements->pduElement.ue_network.len = 5;
+	    	unsigned char val = 0x00;
+		    val = g_secReqInfo->ms_net_capab.capab[0]&0x80;
+            val |= g_secReqInfo->ms_net_capab.capab[1]&0x7E;
+            val >>= 1;
+	        value->data[2].val.nas.elements->pduElement.ue_network.capab[4] = val;
+	    }
+	    else
+	    {
+	        /*If MS capability is not present. Then only 
+		* Capability till UMTS Algorithms is sent.*/
+            log_msg(LOG_DEBUG, "MS network not present"); 
+	        value->data[2].val.nas.elements->pduElement.ue_network.len = 4;
+	    }
+	}
+	else
+	{
+	    /*Copy as much info of UE network capability 
+	    * as received.
+	    */
+            log_msg(LOG_DEBUG, "UE network length again: %d", g_secReqInfo->ue_network.len);
+            memcpy(value->data[2].val.nas.elements->pduElement.ue_network.capab,
+               g_secReqInfo->ue_network.capab, g_secReqInfo->ue_network.len);
+	}
+
+	return SUCCESS;
+}
+
+
+/**
+* Stage specific message processing.
+*/
+static int
+secreq_processing(struct sec_mode_Q_msg * g_secReqInfo)
+{
+	Buffer g_sec_buffer;
+	Buffer g_sec_value_buffer;
+	Buffer g_sec_nas_buffer;
+
+	unsigned char tmpStr[4];
+	struct s1ap_PDU s1apPDU= {0};
+	uint8_t mac_data_pos;
+
+	s1apPDU.procedurecode = id_downlinkNASTransport;
+	s1apPDU.criticality = CRITICALITY_IGNORE;
+
+	get_secreq_protoie_value(&s1apPDU.value, g_secReqInfo);
+
+	/* Copy values to g_sec_nas_buffer */
+
+	/* id-NAS-PDU */
+	g_sec_nas_buffer.pos = 0;
+	nasPDU nas = s1apPDU.value.data[2].val.nas;
+
+	unsigned char value = (nas.header.security_header_type << 4 |
+			nas.header.proto_discriminator);
+
+	buffer_copy(&g_sec_nas_buffer, &value, sizeof(value));
+
+	/* placeholder for mac. mac value will be calculated later */
+	buffer_copy(&g_sec_nas_buffer, &nas.header.mac, MAC_SIZE);
+
+	mac_data_pos = g_sec_nas_buffer.pos;
+
+	buffer_copy(&g_sec_nas_buffer, &nas.header.seq_no,
+			sizeof(nas.header.seq_no));
+
+	nas.header.security_header_type = Plain;
+	value = nas.header.security_header_type |
+				nas.header.proto_discriminator;
+	buffer_copy(&g_sec_nas_buffer, &value, sizeof(value));
+
+	buffer_copy(&g_sec_nas_buffer, &nas.header.message_type,
+			sizeof(nas.header.message_type));
+
+	value = (nas.header.security_encryption_algo << 4 |
+				nas.header.security_integrity_algo);
+	buffer_copy(&g_sec_nas_buffer, &value, sizeof(value));
+
+	buffer_copy(&g_sec_nas_buffer, &nas.header.nas_security_param,
+			sizeof(nas.header.nas_security_param));
+
+	buffer_copy(&g_sec_nas_buffer, &nas.elements->pduElement.ue_network.len,
+			sizeof(nas.elements->pduElement.ue_network.len));
+
+	buffer_copy(&g_sec_nas_buffer, &nas.elements->pduElement.ue_network.capab,
+			nas.elements->pduElement.ue_network.len);
+
+	/* Calculate mac */
+	uint8_t direction = 1;
+	uint8_t bearer = 0;
+
+	calculate_mac(g_secReqInfo->int_key, nas.header.seq_no,
+			direction, bearer, &g_sec_nas_buffer.buf[mac_data_pos],
+			g_sec_nas_buffer.pos - mac_data_pos,
+			&g_sec_nas_buffer.buf[mac_data_pos - MAC_SIZE]);
+
+	/* Copy values in g_sec_value_buffer */
+	g_sec_value_buffer.pos = 0;
+
+	/* TODO remove hardcoded values */
+	char chProtoIENo[3] = {0,0,3};
+	buffer_copy(&g_sec_value_buffer, chProtoIENo, 3);
+
+	/* id-MME-UE-S1AP-ID */
+	uint16_t protocolIe_Id = id_MME_UE_S1AP_ID;
+	copyU16(tmpStr, protocolIe_Id);
+	buffer_copy(&g_sec_value_buffer, tmpStr,
+					sizeof(protocolIe_Id));
+
+	unsigned char protocolIe_criticality = CRITICALITY_REJECT;
+	buffer_copy(&g_sec_value_buffer, &protocolIe_criticality,
+					sizeof(protocolIe_criticality));
+
+	unsigned char datalen = 2;
+
+	/* TODO need to add proper handling*/
+	unsigned char mme_ue_id[3];
+	datalen = copyU16(mme_ue_id, s1apPDU.value.data[0].val.mme_ue_s1ap_id);
+	buffer_copy(&g_sec_value_buffer, &datalen, sizeof(datalen));
+	buffer_copy(&g_sec_value_buffer, mme_ue_id, datalen);
+
+	/* id-eNB-UE-S1AP-ID */
+	protocolIe_Id = id_eNB_UE_S1AP_ID;
+	copyU16(tmpStr, protocolIe_Id);
+	buffer_copy(&g_sec_value_buffer, tmpStr,
+						sizeof(protocolIe_Id));
+
+	buffer_copy(&g_sec_value_buffer, &protocolIe_criticality,
+					sizeof(protocolIe_criticality));
+
+	/* TODO needs proper handling*/
+	unsigned char enb_ue_id[3];
+	datalen = copyU16(enb_ue_id, s1apPDU.value.data[1].val.enb_ue_s1ap_id);
+	buffer_copy(&g_sec_value_buffer, &datalen, sizeof(datalen));
+	buffer_copy(&g_sec_value_buffer, enb_ue_id, datalen);
+
+	/* id-NAS-PDU */
+	protocolIe_Id = id_NAS_PDU;
+	copyU16(tmpStr, protocolIe_Id);
+	buffer_copy(&g_sec_value_buffer, tmpStr,
+			sizeof(protocolIe_Id));
+
+	buffer_copy(&g_sec_value_buffer, &protocolIe_criticality,
+			sizeof(protocolIe_criticality));
+
+
+	datalen = g_sec_nas_buffer.pos + 1;
+	buffer_copy(&g_sec_value_buffer, &datalen,
+			sizeof(datalen));
+
+	buffer_copy(&g_sec_value_buffer, &g_sec_nas_buffer.pos,
+			sizeof(g_sec_nas_buffer.pos));
+
+	buffer_copy(&g_sec_value_buffer, &g_sec_nas_buffer,
+			g_sec_nas_buffer.pos);
+
+	/* Copy values in g_sec_buffer */
+	g_sec_buffer.pos = 0;
+
+	unsigned char initiating_message = 0; /* TODO: Add enum */
+	buffer_copy(&g_sec_buffer, &initiating_message,
+			sizeof(initiating_message));
+
+	buffer_copy(&g_sec_buffer, &s1apPDU.procedurecode,
+			sizeof(s1apPDU.procedurecode));
+
+	buffer_copy(&g_sec_buffer, &s1apPDU.criticality,
+			sizeof(s1apPDU.criticality));
+
+	buffer_copy(&g_sec_buffer, &g_sec_value_buffer.pos,
+			sizeof(g_sec_value_buffer.pos));
+
+	buffer_copy(&g_sec_buffer, &g_sec_value_buffer,
+			g_sec_value_buffer.pos);
+
+	free(s1apPDU.value.data[2].val.nas.elements);
+	free(s1apPDU.value.data);
+	//STIMER_GET_CURRENT_TP(g_attach_stats[s1apPDU.value.data[1].enb_ue_s1ap_id].secreq_out);
+
+	send_sctp_msg(g_secReqInfo->enb_fd, g_sec_buffer.buf, g_sec_buffer.pos, 1);
+
+	return SUCCESS;
+}
+
+/**
+* Thread function for stage.
+*/
+void*
+secreq_handler(void *data)
+{
+	log_msg(LOG_INFO, "SecReq handler ready.\n");
+
+	secreq_processing((struct sec_mode_Q_msg *)data);
+
+	return NULL;
+}
diff --git a/src/s1ap/handlers/ctxrelease_cmp.c b/src/s1ap/handlers/ctxrelease_cmp.c
new file mode 100644
index 0000000..009f23d
--- /dev/null
+++ b/src/s1ap/handlers/ctxrelease_cmp.c
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2019, Infosys Ltd.
+ * 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 "err_codes.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 "msgType.h"
+
+
+extern int g_enb_fd;
+extern ipc_handle ipc_S1ap_Hndl;
+
+int
+s1_ctx_release_complete_handler(SuccessfulOutcome_t *msg)
+{
+	struct s1_incoming_msg_data_t release_complete= {0};
+	struct proto_IE s1_ctx_release_ies;
+
+	log_msg(LOG_INFO, "Parse s1ap context release complete message:--\n");
+
+	 convertUeCtxRelComplToProtoIe(msg, &s1_ctx_release_ies);
+
+	/*TODO: Validate all eNB info*/
+     for(int i = 0; i < s1_ctx_release_ies.no_of_IEs; i++)
+    {
+        switch(s1_ctx_release_ies.data[i].IE_type)
+        {
+            case S1AP_IE_MME_UE_ID:
+                {
+	                release_complete.ue_idx = s1_ctx_release_ies.data[i].val.mme_ue_s1ap_id;
+                }break;
+            default:
+                log_msg(LOG_WARNING,"Unhandled IE");
+        }
+    }
+
+	release_complete.msg_type = s1_release_complete;
+	release_complete.destInstAddr = htonl(mmeAppInstanceNum_c);
+	release_complete.srcInstAddr = htonl(s1apAppInstanceNum_c);
+	int i = 0;
+	i = send_tipc_message(ipc_S1ap_Hndl,mmeAppInstanceNum_c,
+				(char *)&release_complete,
+				S1_READ_MSG_BUF_SIZE);
+	if (i < 0) {
+
+		log_msg(LOG_ERROR,"Error To write in s1_ctx_release_code_handler\n");
+	}
+
+	log_msg(LOG_INFO, "Ctx Release complete sent to mme-app."
+				"Bytes sent %d\n", i);
+
+	//TODO: free IEs
+	return SUCCESS;
+}
+
diff --git a/src/s1ap/handlers/ctxrelease_req.c b/src/s1ap/handlers/ctxrelease_req.c
new file mode 100644
index 0000000..2a9305a
--- /dev/null
+++ b/src/s1ap/handlers/ctxrelease_req.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2019, Infosys Ltd.
+ *
+ * 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 "err_codes.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 "msgType.h"
+
+
+extern int g_enb_fd;
+extern ipc_handle ipc_S1ap_Hndl;
+
+int
+s1_ctx_release_request_handler(InitiatingMessage_t *msg)
+{
+	struct s1_incoming_msg_data_t release_request= {0};
+	struct proto_IE s1_ctx_rel_req_ies;
+
+	log_msg(LOG_INFO, "Parse s1ap context release request message:--\n");
+
+	convertUeCtxRelReqToProtoIe(msg, &s1_ctx_rel_req_ies);
+
+	/*TODO: Validate all eNB info*/
+     for(int i = 0; i < s1_ctx_rel_req_ies.no_of_IEs; i++)
+    {
+        switch(s1_ctx_rel_req_ies.data[i].IE_type)
+        {
+            case S1AP_IE_MME_UE_ID:
+                {
+	                release_request.ue_idx = s1_ctx_rel_req_ies.data[i].val.mme_ue_s1ap_id;
+                }break;
+            default:
+                log_msg(LOG_WARNING,"Unhandled IE.\n");
+        }
+    }
+
+	
+    release_request.msg_type = s1_release_request;
+	release_request.destInstAddr = htonl(mmeAppInstanceNum_c);
+	release_request.srcInstAddr = htonl(s1apAppInstanceNum_c);
+	int i = 0;
+	i = send_tipc_message(ipc_S1ap_Hndl,mmeAppInstanceNum_c,
+				(char *)&release_request,
+				S1_READ_MSG_BUF_SIZE);
+				
+	if (i < 0) {
+
+		log_msg(LOG_ERROR,"Error To write in s1_ctx_release_request_handler\n");
+	}
+
+	log_msg(LOG_INFO, "Ctx Release request sent to mme-app."
+				"Bytes send %d\n", i);
+
+	//TODO: free IEs
+	return SUCCESS;
+}
diff --git a/src/s1ap/handlers/ctxrelease_resp.c b/src/s1ap/handlers/ctxrelease_resp.c
new file mode 100644
index 0000000..4489ae4
--- /dev/null
+++ b/src/s1ap/handlers/ctxrelease_resp.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2003-2018, Great Software Laboratory Pvt. Ltd.
+ * Copyright (c) 2017 Intel Corporation
+ * Copyright (c) 2019, Infosys Ltd.
+ *
+ * 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 "err_codes.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 "msgType.h"
+
+
+extern int g_enb_fd;
+extern ipc_handle ipc_S1ap_Hndl;
+
+int
+s1_ctx_release_resp_handler(SuccessfulOutcome_t *msg)
+{
+	struct s1_incoming_msg_data_t release_complete= {0};
+	struct proto_IE s1_ctx_release_ies;
+
+	log_msg(LOG_INFO, "Parse s1ap context release complete message:--\n");
+
+	 convertUeCtxRelComplToProtoIe(msg, &s1_ctx_release_ies);
+
+	/*TODO: Validate all eNB info*/
+     for(int i = 0; i < s1_ctx_release_ies.no_of_IEs; i++)
+    {
+        switch(s1_ctx_release_ies.data[i].IE_type)
+        {
+            case S1AP_IE_MME_UE_ID:
+                {
+	                release_complete.ue_idx = s1_ctx_release_ies.data[i].val.mme_ue_s1ap_id;
+                }break;
+            default:
+                log_msg(LOG_WARNING,"Unhandled IE");
+        }
+    }
+
+	release_complete.msg_type = s1_release_complete;
+	release_complete.destInstAddr = htonl(mmeAppInstanceNum_c);
+	release_complete.srcInstAddr = htonl(s1apAppInstanceNum_c);
+	int i = 0;
+	i = send_tipc_message(ipc_S1ap_Hndl,mmeAppInstanceNum_c,
+				(char *)&release_complete,
+				S1_READ_MSG_BUF_SIZE);
+	if (i < 0) {
+
+		log_msg(LOG_ERROR,"Error To write in s1_ctx_release_code_handler\n");
+	}
+
+	log_msg(LOG_INFO, "Ctx Release complete sent to mme-app."
+				"Bytes sent %d\n", i);
+
+	//TODO: free IEs
+	return SUCCESS;
+}
+
diff --git a/src/s1ap/handlers/detach_accept.c b/src/s1ap/handlers/detach_accept.c
new file mode 100644
index 0000000..b0e8c1f
--- /dev/null
+++ b/src/s1ap/handlers/detach_accept.c
@@ -0,0 +1,328 @@
+/*
+ * 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 <pthread.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdint.h>
+
+#include "log.h"
+#include "err_codes.h"
+#include "message_queues.h"
+#include "ipc_api.h"
+#include "s1ap.h"
+#include "s1ap_config.h"
+#include "main.h"
+#include "msgType.h"
+
+static int
+get_detach_accept_protoie_value(struct proto_IE *value, struct detach_accept_Q_msg *g_acptReqInfo)
+{
+	uint8_t ieCnt = 0;
+
+	value->no_of_IEs = DTCH_ACCEPT_NO_OF_IES;
+
+	value->data = (proto_IEs *) malloc(DTCH_ACCEPT_NO_OF_IES *
+			sizeof(proto_IEs));
+
+	value->data[ieCnt].val.mme_ue_s1ap_id = g_acptReqInfo->ue_idx;
+	ieCnt++;
+
+	value->data[ieCnt].val.enb_ue_s1ap_id = g_acptReqInfo->enb_s1ap_ue_id;
+	ieCnt++;
+
+	struct nasPDU *nas = &(value->data[ieCnt].val.nas);
+	nas->header.security_header_type = IntegrityProtectedCiphered;
+	nas->header.proto_discriminator = EPSMobilityManagementMessages;
+
+	/* placeholder for mac. mac value will be calculated later */
+	uint8_t mac[MAC_SIZE] = {0};
+	memcpy(nas->header.mac, mac, MAC_SIZE);
+
+	nas->header.seq_no = g_acptReqInfo->dl_seq_no;
+	nas->header.message_type = DetachAccept;
+
+	ieCnt++;
+
+	return SUCCESS;
+}
+
+/**
+* Stage specific message processing.
+*/
+static int
+detach_accept_processing(struct detach_accept_Q_msg *g_acptReqInfo)
+{
+	unsigned char tmpStr[4];
+	struct s1ap_PDU s1apPDU= {0};
+	uint16_t protocolIe_Id;
+	uint8_t protocolIe_criticality = CRITICALITY_REJECT;
+	uint8_t initiating_msg = 0;
+	uint8_t datalen = 0;
+	uint8_t s1ap_len_pos;
+	uint8_t nas_len_pos;
+	uint8_t u8value = 0;
+	uint8_t mac_data_pos;
+
+	Buffer g_acpt_buffer;
+
+	s1apPDU.procedurecode = id_downlinkNASTransport;
+	s1apPDU.criticality = CRITICALITY_IGNORE;
+
+	get_detach_accept_protoie_value(&s1apPDU.value, g_acptReqInfo);
+
+	g_acpt_buffer.pos = 0;
+
+	buffer_copy(&g_acpt_buffer, &initiating_msg,
+			sizeof(initiating_msg));
+
+	buffer_copy(&g_acpt_buffer, &s1apPDU.procedurecode,
+			sizeof(s1apPDU.procedurecode));
+
+	buffer_copy(&g_acpt_buffer, &s1apPDU.criticality,
+				sizeof(s1apPDU.criticality));
+
+	s1ap_len_pos = g_acpt_buffer.pos;
+
+	/* length of Detach Accept */
+	u8value = 0;
+	buffer_copy(&g_acpt_buffer, &u8value, sizeof(u8value));
+
+	/* TODO remove hardcoded values */
+	uint8_t chProtoIENo[3] = {0,0,3};
+	buffer_copy(&g_acpt_buffer, chProtoIENo, 3);
+
+	/* id-MME-UE-S1AP-ID */
+	protocolIe_Id = id_MME_UE_S1AP_ID;
+	copyU16(tmpStr, protocolIe_Id);
+	buffer_copy(&g_acpt_buffer, tmpStr, sizeof(protocolIe_Id));
+	buffer_copy(&g_acpt_buffer, &protocolIe_criticality,
+					sizeof(protocolIe_criticality));
+	datalen = 2;
+	/* TODO need to add proper handling*/
+	unsigned char mme_ue_id[3];
+	datalen = copyU16(mme_ue_id, s1apPDU.value.data[0].val.mme_ue_s1ap_id);
+	buffer_copy(&g_acpt_buffer, &datalen, sizeof(datalen));
+	buffer_copy(&g_acpt_buffer, mme_ue_id, datalen);
+
+	/* id-eNB-UE-S1AP-ID */
+	protocolIe_Id = id_eNB_UE_S1AP_ID;
+	copyU16(tmpStr, protocolIe_Id);
+	buffer_copy(&g_acpt_buffer, tmpStr, sizeof(protocolIe_Id));
+	buffer_copy(&g_acpt_buffer, &protocolIe_criticality,
+					sizeof(protocolIe_criticality));
+	/* TODO needs proper handling*/
+	unsigned char enb_ue_id[3];
+	datalen = copyU16(enb_ue_id, s1apPDU.value.data[1].val.enb_ue_s1ap_id);
+	buffer_copy(&g_acpt_buffer, &datalen, sizeof(datalen));
+	buffer_copy(&g_acpt_buffer, enb_ue_id, datalen);
+
+	/* NAS PDU start */
+	protocolIe_Id = id_NAS_PDU;
+	copyU16(tmpStr, protocolIe_Id);
+	buffer_copy(&g_acpt_buffer, tmpStr, sizeof(protocolIe_Id));
+	buffer_copy(&g_acpt_buffer, &protocolIe_criticality,
+					sizeof(protocolIe_criticality));
+
+	nas_len_pos = g_acpt_buffer.pos;
+
+	datalen = 0;
+	buffer_copy(&g_acpt_buffer, &datalen, sizeof(datalen));
+
+	buffer_copy(&g_acpt_buffer, &datalen, sizeof(datalen));
+
+	nas_pdu_header *nas_hdr = &(s1apPDU.value.data[2].val.nas.header);
+
+	/* security header and protocol discriminator */
+	u8value = (nas_hdr->security_header_type << 4 |
+			nas_hdr->proto_discriminator);
+	buffer_copy(&g_acpt_buffer, &u8value, sizeof(u8value));
+
+	/* mac */
+	/* placeholder for mac. mac value will be calculated later */
+	buffer_copy(&g_acpt_buffer, nas_hdr->mac, MAC_SIZE);
+	mac_data_pos = g_acpt_buffer.pos;
+
+	/* sequence number */
+	buffer_copy(&g_acpt_buffer, &(nas_hdr->seq_no),
+			sizeof(nas_hdr->seq_no));
+
+	/* security header and protocol discriminator */
+	nas_hdr->security_header_type = Plain;
+	u8value = (nas_hdr->security_header_type << 4 |
+			nas_hdr->proto_discriminator);
+	buffer_copy(&g_acpt_buffer, &u8value, sizeof(u8value));
+
+	/* message type */
+	buffer_copy(&g_acpt_buffer, &(nas_hdr->message_type),
+			sizeof(nas_hdr->message_type));
+
+	/* NAS PDU end */
+
+	/* Calculate mac */
+	uint8_t direction = 1;
+	uint8_t bearer = 0;
+
+	calculate_mac(g_acptReqInfo->int_key, nas_hdr->seq_no,
+			direction, bearer, &g_acpt_buffer.buf[mac_data_pos],
+			g_acpt_buffer.pos - mac_data_pos,
+			&g_acpt_buffer.buf[mac_data_pos - MAC_SIZE]);
+
+	/* Copy nas length to nas length field */
+	datalen = g_acpt_buffer.pos - nas_len_pos -1;
+	memcpy(&(g_acpt_buffer.buf[nas_len_pos]), &datalen, sizeof(datalen));
+
+	/* Copy nas length to nas length field */
+	datalen = g_acpt_buffer.pos - nas_len_pos - 2;
+	memcpy(&(g_acpt_buffer.buf[nas_len_pos + 1]), &datalen, sizeof(datalen));
+
+	/* Copy length to s1ap length field */
+	datalen = g_acpt_buffer.pos - s1ap_len_pos - 1;
+	memcpy(g_acpt_buffer.buf + s1ap_len_pos, &datalen, sizeof(datalen));
+
+	/* TODO: temp fix */
+	//g_ics_buffer.buf[1] = 0x09;
+	send_sctp_msg(g_acptReqInfo->enb_fd, g_acpt_buffer.buf, g_acpt_buffer.pos,1);
+
+	log_msg(LOG_INFO, "Detach Accept sent to UE.");
+
+	return SUCCESS;
+}
+
+/**
+* essage processing for ue context release
+*/
+static int
+ue_ctx_release_processing(struct detach_accept_Q_msg *g_acptReqInfo)
+{
+	Buffer g_ctxrel_buffer;
+	unsigned char tmpStr[4];
+	struct s1ap_PDU s1apPDU;
+	uint16_t protocolIe_Id;
+	uint8_t protocolIe_criticality = CRITICALITY_REJECT;
+	uint8_t initiating_msg = 0;
+	uint8_t datalen = 0;
+	uint8_t s1ap_len_pos;
+	uint8_t u8value = 0;
+
+	s1apPDU.procedurecode = id_UEContexRelease;
+	s1apPDU.criticality = CRITICALITY_IGNORE;
+
+	g_ctxrel_buffer.pos = 0;
+
+	buffer_copy(&g_ctxrel_buffer, &initiating_msg,
+			sizeof(initiating_msg));
+
+	buffer_copy(&g_ctxrel_buffer, &s1apPDU.procedurecode,
+			sizeof(s1apPDU.procedurecode));
+
+	buffer_copy(&g_ctxrel_buffer, &s1apPDU.criticality,
+				sizeof(s1apPDU.criticality));
+
+	s1ap_len_pos = g_ctxrel_buffer.pos;
+
+	/* length of UE Context Release */
+	u8value = 0;
+	buffer_copy(&g_ctxrel_buffer, &u8value, sizeof(u8value));
+
+	/* TODO remove hardcoded values */
+	uint8_t chProtoIENo[3] = {0,0,2};
+	buffer_copy(&g_ctxrel_buffer, chProtoIENo, 3);
+
+	/* id-UE-S1AP-IDs */
+	protocolIe_Id = id_UE_S1AP_IDs;
+	copyU16(tmpStr, protocolIe_Id);
+	buffer_copy(&g_ctxrel_buffer, tmpStr, sizeof(protocolIe_Id));
+	buffer_copy(&g_ctxrel_buffer, &protocolIe_criticality,
+					sizeof(protocolIe_criticality));
+
+	uint8_t mme_ue_id[4];
+	uint8_t mme_ue_id_len = copyU16(mme_ue_id,
+				s1apPDU.value.data[0].val.mme_ue_s1ap_id);
+
+	if (mme_ue_id[0] == 0x40 || mme_ue_id[0] == 0x80)
+		mme_ue_id[0] = ((mme_ue_id[0] & 0x0F)<<4 |
+				(mme_ue_id[0] & 0xF0)>>4);
+
+	uint8_t enb_ue_id[4];
+	uint8_t enb_ue_id_len = copyU16(enb_ue_id,
+				s1apPDU.value.data[1].val.enb_ue_s1ap_id);
+
+	datalen = mme_ue_id_len + enb_ue_id_len;
+	buffer_copy(&g_ctxrel_buffer, &datalen, sizeof(datalen));
+	buffer_copy(&g_ctxrel_buffer, mme_ue_id, mme_ue_id_len);
+	buffer_copy(&g_ctxrel_buffer, enb_ue_id, enb_ue_id_len);
+
+#if 0
+	/* id-MME-UE-S1AP-ID */
+	protocolIe_Id = id_MME_UE_S1AP_ID;
+	copyU16(tmpStr, protocolIe_Id);
+	buffer_copy(&g_ctxrel_buffer, tmpStr,
+	                                sizeof(protocolIe_Id));
+
+	protocolIe_criticality = CRITICALITY_REJECT;
+	buffer_copy(&g_ctxrel_buffer, &protocolIe_criticality,
+	                                sizeof(protocolIe_criticality));
+
+	datalen = 2;
+
+	/* TODO needs proper handling*/
+	unsigned char mme_ue_id[4];
+	datalen = copyU16(mme_ue_id, s1apPDU.value.data[0].val.mme_ue_s1ap_id);
+	buffer_copy(&g_ctxrel_buffer, &datalen, sizeof(datalen));
+	buffer_copy(&g_ctxrel_buffer, mme_ue_id, datalen);
+#endif
+
+	/* id-Cause */
+	protocolIe_Id = id_Cause;
+	protocolIe_criticality = CRITICALITY_IGNORE;
+	copyU16(tmpStr, protocolIe_Id);
+	buffer_copy(&g_ctxrel_buffer, tmpStr, sizeof(protocolIe_Id));
+	buffer_copy(&g_ctxrel_buffer, &protocolIe_criticality,
+					sizeof(protocolIe_criticality));
+	datalen = 1;
+	buffer_copy(&g_ctxrel_buffer, &datalen, sizeof(datalen));
+	/* TODO : Revisit. cause : nas(2) and value : detach (2), why 0x24 ? */
+	u8value = 0x24;
+	buffer_copy(&g_ctxrel_buffer, &u8value, sizeof(u8value));
+
+	/* Copy length to s1ap length field */
+	datalen = g_ctxrel_buffer.pos - s1ap_len_pos - 1;
+	memcpy(g_ctxrel_buffer.buf + s1ap_len_pos, &datalen, sizeof(datalen));
+	send_sctp_msg(g_acptReqInfo->enb_fd, g_ctxrel_buffer.buf, g_ctxrel_buffer.pos,1);
+
+	log_msg(LOG_INFO,"S1 Release sent to UE");
+
+	return SUCCESS;
+}
+
+/**
+* Thread function for stage.
+*/
+void*
+detach_accept_handler(void *data)
+{
+   log_msg(LOG_INFO, "detach accept handler ready.\n");
+   struct detach_accept_Q_msg *msg = (struct detach_accept_Q_msg *)data;
+
+   detach_accept_processing(msg);
+   ue_ctx_release_processing(msg);
+
+   return NULL;
+}
diff --git a/src/s1ap/handlers/detach_accept_from_ue.c b/src/s1ap/handlers/detach_accept_from_ue.c
new file mode 100644
index 0000000..1489af5
--- /dev/null
+++ b/src/s1ap/handlers/detach_accept_from_ue.c
@@ -0,0 +1,91 @@
+/*
+ * 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 "err_codes.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 "msgType.h"
+//#include "detach_stage1_info.h"
+
+extern int g_enb_fd;
+extern ipc_handle ipc_S1ap_Hndl;
+
+int
+detach_accept_from_ue_handler(struct proto_IE *detach_ies, bool retransmit)
+{
+	struct s1_incoming_msg_data_t acpt= {0};
+
+	/*****Message structure***
+	*/
+	log_msg(LOG_INFO, "Parse s1ap ni detach accept message\n");
+
+
+	/*Validate all eNB info*/
+
+	/*Add eNB info to hash*/
+
+	/*Create Q structure for detach stage 1 to MME.
+	  contains init UE information.*/
+	/* TODO : Revisit, in InitialContextSetup Request we are sending
+	 * MME UE S1AP Id as M-TMSI.
+	 */
+	acpt.msg_type = detach_accept_from_ue;
+	for(int i = 0; i < detach_ies->no_of_IEs; i++)
+    	{
+        switch(detach_ies->data[i].IE_type)
+        {
+            case S1AP_IE_MME_UE_ID:
+                {
+                    if (!retransmit)
+                    {
+                        acpt.ue_idx = detach_ies->data[i].val.mme_ue_s1ap_id;
+                    }
+                }
+		break;
+            case S1AP_IE_ENB_UE_ID:
+                {
+                    acpt.s1ap_enb_ue_id = detach_ies->data[i].val.enb_ue_s1ap_id;
+                }
+		break;
+            default:
+                log_msg(LOG_WARNING,"Unhandled IE");
+        }
+    	}
+
+	acpt.destInstAddr = htonl(mmeAppInstanceNum_c);
+	acpt.srcInstAddr = htonl(s1apAppInstanceNum_c);
+	send_tipc_message(ipc_S1ap_Hndl, mmeAppInstanceNum_c, (char *)&acpt, S1_READ_MSG_BUF_SIZE);
+
+	/*Send S1Setup response*/
+	log_msg(LOG_INFO, "Send to mme-app stage1.\n");
+
+	return SUCCESS;
+}
+
+
diff --git a/src/s1ap/handlers/detach_req.c b/src/s1ap/handlers/detach_req.c
new file mode 100644
index 0000000..5ff68d2
--- /dev/null
+++ b/src/s1ap/handlers/detach_req.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2003-2018, Great Software Laboratory Pvt. Ltd.
+ * Copyright (c) 2017 Intel Corporation
+ * Copyright (c) 2019, Infosys Ltd.
+ *
+ * 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 "err_codes.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 "msgType.h"
+
+
+extern int g_enb_fd;
+extern ipc_handle ipc_S1ap_Hndl;
+
+int
+detach_stage1_handler(struct proto_IE *detach_ies, bool retransmit)
+{
+	struct s1_incoming_msg_data_t req= {0};
+
+	/*****Message structure***
+	*/
+	log_msg(LOG_INFO, "Parse s1ap detach request message\n");
+
+	/*Validate all eNB info*/
+
+	/*Add eNB info to hash*/
+
+	/*Create Q structure for detach stage 1 to MME.
+	  contains init UE information.*/
+	/* TODO : Revisit, in InitialContextSetup Request we are sending
+	 * MME UE S1AP Id as M-TMSI.
+	 */
+	req.msg_type = detach_request;
+	for(int i = 0; i < detach_ies->no_of_IEs; i++)
+    {
+        switch(detach_ies->data[i].IE_type)
+        {
+            case S1AP_IE_MME_UE_ID:
+                {
+                    if (!retransmit)
+                    {
+                        req.ue_idx = detach_ies->data[i].val.mme_ue_s1ap_id;
+                    }
+                }break;
+            case S1AP_IE_ENB_UE_ID:
+                {
+                    req.s1ap_enb_ue_id = detach_ies->data[i].val.enb_ue_s1ap_id;
+                }break;
+            case S1AP_IE_NAS_PDU:
+                {
+                    if(retransmit)
+                    {
+                        req.msg_data.detachReq_Q_msg_m.ue_m_tmsi = ntohl(detach_ies->data[i].val.nas.elements[0].pduElement.mi_guti.m_TMSI);
+                    }
+                }break;
+            default:
+                log_msg(LOG_WARNING,"Unhandled IE");
+        }
+    }
+
+	req.destInstAddr = htonl(mmeAppInstanceNum_c);
+	req.srcInstAddr = htonl(s1apAppInstanceNum_c);
+	send_tipc_message(ipc_S1ap_Hndl, mmeAppInstanceNum_c, (char *)&req, S1_READ_MSG_BUF_SIZE);
+
+	/*Send S1Setup response*/
+	log_msg(LOG_INFO, "Send to mme-app stage1.\n");
+
+	return SUCCESS;
+}
+
+
diff --git a/src/s1ap/handlers/ics_req_paging.c b/src/s1ap/handlers/ics_req_paging.c
new file mode 100644
index 0000000..a26db1a
--- /dev/null
+++ b/src/s1ap/handlers/ics_req_paging.c
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2019, Infosys Ltd.
+ *
+ * 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 <pthread.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdint.h>
+#include "common_proc_info.h"
+#include "log.h"
+#include "err_codes.h"
+#include "message_queues.h"
+#include "ipc_api.h"
+#include "s1ap.h"
+#include "s1ap_config.h"
+#include "main.h"
+#include "msgType.h"
+
+
+/*static int
+get_uectxtrelcmd_protoie_value(struct proto_IE *value, struct s1relcmd_info *g_uectxtrelcmd)
+{
+	//uint8_t ieCnt = 0;
+
+	value->no_of_IEs = UE_CTX_RELEASE_NO_OF_IES;
+
+	value->data = (proto_IEs *) malloc(UE_CTX_RELEASE_NO_OF_IES *
+			sizeof(proto_IEs));
+
+	value->data[0].mme_ue_s1ap_id = g_uectxtrelcmd->ue_idx;
+	
+	value->data[1].enb_ue_s1ap_id = g_uectxtrelcmd->enb_s1ap_ue_id;
+	
+	log_msg(LOG_INFO, "mme_ue_s1ap_id %d and enb_ue_s1ap_id %d\n",
+					g_uectxtrelcmd->ue_idx,g_uectxtrelcmd->enb_s1ap_ue_id);
+	return SUCCESS;
+}*/
+
+/**
+* Stage specific message processing.
+*/
+static int
+ics_req_paging_processing(struct ics_req_paging_Q_msg *g_icsreq)
+{
+	log_msg(LOG_DEBUG,"Process Init Ctxt Req for service Request.");
+	uint32_t length = 0;
+    	uint8_t *buffer = NULL;
+	
+	Buffer g_ics_req_buffer;
+	struct s1ap_common_req_Q_msg req= {0};
+	
+        log_msg(LOG_DEBUG,"Inside ics_req_paging processing\n");	
+	
+    	req.IE_type = S1AP_INIT_CTXT_SETUP_REQ;
+    	req.ue_idx = g_icsreq->ue_idx;
+	req.enb_fd = g_icsreq->enb_fd;
+	req.enb_s1ap_ue_id = g_icsreq->enb_s1ap_ue_id;
+    	req.mme_s1ap_ue_id = g_icsreq->ue_idx;
+	req.ueag_max_dl_bitrate = g_icsreq->ueag_max_dl_bitrate;
+	req.ueag_max_ul_bitrate = g_icsreq->ueag_max_ul_bitrate;
+	req.bearer_id = g_icsreq->bearer_id;
+	memcpy(&(req.gtp_teid), &(g_icsreq->gtp_teid), sizeof(struct fteid));
+	memcpy(&(req.sec_key), &(g_icsreq->sec_key), KENB_SIZE);	
+	
+	log_msg(LOG_DEBUG,"Before s1ap_encoder\n");
+
+	int ret = s1ap_mme_encode_initiating(&req, &buffer, &length);
+	log_msg(LOG_DEBUG,"Invoked s1ap_encoder\n");
+    	if(ret == -1)
+    	{
+        	log_msg(LOG_ERROR, "Encoding ics_req_paging failed.\n");
+        	return E_FAIL;
+    	}
+
+	buffer_copy(&g_ics_req_buffer, buffer, length);
+	send_sctp_msg(g_icsreq->enb_fd, g_ics_req_buffer.buf, g_ics_req_buffer.pos,1);
+	log_msg(LOG_INFO, "\n----ICS Req for paging sent to UE.---\n");
+	return SUCCESS;
+	
+}
+
+
+/**
+* Thread function for stage.
+*/
+void*
+ics_req_paging_handler(void *data)
+{
+
+	log_msg(LOG_INFO,"ICS Req for paging handler ready.\n");
+	
+	ics_req_paging_processing((struct ics_req_paging_Q_msg *)data);
+
+	return NULL;
+}
+
+
diff --git a/src/s1ap/handlers/ie_parsers.c b/src/s1ap/handlers/ie_parsers.c
new file mode 100644
index 0000000..1d9cfc0
--- /dev/null
+++ b/src/s1ap/handlers/ie_parsers.c
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2003-2018, Great Software Laboratory Pvt. Ltd.
+ * Copyright (c) 2017 Intel Corporation
+ * Copyright (c) 2019, Infosys Ltd.
+ *
+ * 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 <pthread.h>
+#include <string.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+
+#include "log.h"
+#include "err_codes.h"
+#include "message_queues.h"
+#include "s1ap_ie.h"
+
+void* 
+ie_parse_global_enb_id(char *msg, int len)
+{
+	/*8 bytes
+	1- ignore
+	2,3,4 - plmn
+	5,6,7,8 - mactoeNBID*/
+	static struct ie_global_enb_id global_enb_id;
+	
+	memcpy(&(global_enb_id.plmn), msg, sizeof(int));
+	memcpy(&(global_enb_id.macro_enb_id), msg+(sizeof(int)), MACRO_ENB_ID_SIZE);
+	global_enb_id.plmn = ntohl(global_enb_id.plmn);
+	//global_enb_id.macro_enb_id = ntohl(global_enb_id.macro_enb_id);
+	log_msg(LOG_INFO, "plmn %x\n", global_enb_id.plmn);
+	log_msg(LOG_INFO, "Macro enb id %x-%x-%x-%x\n", global_enb_id.macro_enb_id[0],
+		global_enb_id.macro_enb_id[4],global_enb_id.macro_enb_id[8],global_enb_id.macro_enb_id[12]);
+	
+	return (void*)&global_enb_id;
+}
+
+void* 
+ie_parse_enb_name(char *msg, int len)
+{
+	return NULL;
+}
+
+void* 
+ie_parse_supported_TAs(char *msg, int len)
+{
+	return NULL;
+}
+
+void* 
+ie_parse_pagins_DRX(char *msg, int len)
+{
+	return NULL;
+}
diff --git a/src/s1ap/handlers/mme_msg_delegator.c b/src/s1ap/handlers/mme_msg_delegator.c
new file mode 100644
index 0000000..6ba0162
--- /dev/null
+++ b/src/s1ap/handlers/mme_msg_delegator.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2019, Infosys Ltd.
+ *
+ * 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 "err_codes.h"
+#include "msgType.h"
+
+extern void* authreq_handler(void *data);
+extern void* secreq_handler(void *data);
+extern void* icsreq_handler(void *data);
+extern void* detach_accept_handler(void *data);
+extern void* ni_detach_request_handler(void *data);
+extern void* paging_handler(void *data);
+extern void* ics_req_paging_handler(void *data);
+extern void* tau_response_handler(void *data);
+
+void
+handle_mmeapp_message(void * data)
+{
+	log_msg(LOG_INFO, "handle mme-app message ");
+	
+	char *msg = ((char *) data) + (sizeof(uint32_t)*2);
+
+	msg_type_t* msg_type = (msg_type_t*)(msg);
+
+	switch(*msg_type)		
+	{	 
+    case id_request:
+        idreq_handler(msg);
+        break;
+	case auth_request:
+		authreq_handler(msg);
+		break;
+	case sec_mode_command:
+		secreq_handler(msg);
+		break;
+	case esm_info_request:
+		esmreq_handler(msg);
+		break;
+	case init_ctxt_request:
+		icsreq_handler(msg);
+		break;
+	case detach_accept:
+		detach_accept_handler(msg);
+		break;
+	case s1_release_command:
+		s1_release_command_handler(msg);
+		break;
+	case ni_detach_request:
+		ni_detach_request_handler(msg);
+		break;
+	case paging_request:
+		paging_handler(msg);
+		break;
+	case ics_req_paging:
+		ics_req_paging_handler(msg);
+		break;
+	case tau_response:
+		tau_response_handler(msg);
+		break;
+	default:
+		log_msg(LOG_ERROR,"Unhandled mme-app message\n");
+		break;
+	}
+	free(data);
+}
diff --git a/src/s1ap/handlers/ni_detach_request.c b/src/s1ap/handlers/ni_detach_request.c
new file mode 100644
index 0000000..6ecd11c
--- /dev/null
+++ b/src/s1ap/handlers/ni_detach_request.c
@@ -0,0 +1,228 @@
+/*
+ * 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 <pthread.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdint.h>
+
+#include "log.h"
+#include "err_codes.h"
+#include "message_queues.h"
+#include "ipc_api.h"
+#include "s1ap.h"
+#include "s1ap_config.h"
+#include "main.h"
+#include "msgType.h"
+
+static int
+get_ni_detach_request_protoie_value(struct proto_IE *value, struct ni_detach_request_Q_msg *g_acptReqInfo)
+{
+	uint8_t ieCnt = 0;
+
+	value->no_of_IEs = NI_DTCH_REQUEST_NO_OF_IES;
+
+	value->data = (proto_IEs *) malloc(NI_DTCH_REQUEST_NO_OF_IES *
+			sizeof(proto_IEs));
+
+	value->data[ieCnt].val.mme_ue_s1ap_id = g_acptReqInfo->ue_idx;
+	ieCnt++;
+
+	value->data[ieCnt].val.enb_ue_s1ap_id = g_acptReqInfo->enb_s1ap_ue_id;
+	ieCnt++;
+
+	struct nasPDU *nas = &(value->data[ieCnt].val.nas);
+	nas->header.security_header_type = IntegrityProtectedCiphered;
+	nas->header.proto_discriminator = EPSMobilityManagementMessages;
+
+	/* placeholder for mac. mac value will be calculated later */
+	uint8_t mac[MAC_SIZE] = {0};
+	memcpy(nas->header.mac, mac, MAC_SIZE);
+
+	nas->header.seq_no = g_acptReqInfo->dl_seq_no;
+	nas->header.message_type = DetachRequest;
+	nas->header.detach_type = 00000002;
+	log_msg(LOG_DEBUG,"NAS Msg Type: %x\n",nas->header.message_type);
+
+	ieCnt++;
+
+	return SUCCESS;
+}
+
+/**
+* Stage specific message processing.
+*/
+static int
+ni_detach_request_processing(struct ni_detach_request_Q_msg *g_acptReqInfo)
+{
+	unsigned char tmpStr[4];
+	struct s1ap_PDU s1apPDU= {0};
+	uint16_t protocolIe_Id;
+	uint8_t protocolIe_criticality = CRITICALITY_REJECT;
+	uint8_t initiating_msg = 0;
+	uint8_t datalen = 0;
+	uint8_t s1ap_len_pos;
+	uint8_t nas_len_pos;
+	uint8_t u8value = 0;
+	uint8_t mac_data_pos;
+
+	Buffer g_acpt_buffer;
+
+	s1apPDU.procedurecode = id_downlinkNASTransport;
+	s1apPDU.criticality = CRITICALITY_IGNORE;
+
+	get_ni_detach_request_protoie_value(&s1apPDU.value, g_acptReqInfo);
+
+	g_acpt_buffer.pos = 0;
+
+	buffer_copy(&g_acpt_buffer, &initiating_msg,
+			sizeof(initiating_msg));
+
+	buffer_copy(&g_acpt_buffer, &s1apPDU.procedurecode,
+			sizeof(s1apPDU.procedurecode));
+
+	buffer_copy(&g_acpt_buffer, &s1apPDU.criticality,
+				sizeof(s1apPDU.criticality));
+
+	s1ap_len_pos = g_acpt_buffer.pos;
+
+	/* length of NI Detach Request */
+	u8value = 0;
+	buffer_copy(&g_acpt_buffer, &u8value, sizeof(u8value));
+
+	/* TODO remove hardcoded values */
+	uint8_t chProtoIENo[3] = {0,0,3};
+	buffer_copy(&g_acpt_buffer, chProtoIENo, 3);
+
+	/* id-MME-UE-S1AP-ID */
+	protocolIe_Id = id_MME_UE_S1AP_ID;
+	copyU16(tmpStr, protocolIe_Id);
+	buffer_copy(&g_acpt_buffer, tmpStr, sizeof(protocolIe_Id));
+	buffer_copy(&g_acpt_buffer, &protocolIe_criticality,
+					sizeof(protocolIe_criticality));
+	datalen = 2;
+	/* TODO need to add proper handling*/
+	unsigned char mme_ue_id[3];
+	datalen = copyU16(mme_ue_id, s1apPDU.value.data[0].val.mme_ue_s1ap_id);
+	buffer_copy(&g_acpt_buffer, &datalen, sizeof(datalen));
+	buffer_copy(&g_acpt_buffer, mme_ue_id, datalen);
+
+	/* id-eNB-UE-S1AP-ID */
+	protocolIe_Id = id_eNB_UE_S1AP_ID;
+	copyU16(tmpStr, protocolIe_Id);
+	buffer_copy(&g_acpt_buffer, tmpStr, sizeof(protocolIe_Id));
+	buffer_copy(&g_acpt_buffer, &protocolIe_criticality,
+					sizeof(protocolIe_criticality));
+	/* TODO needs proper handling*/
+	unsigned char enb_ue_id[3];
+	datalen = copyU16(enb_ue_id, s1apPDU.value.data[1].val.enb_ue_s1ap_id);
+	buffer_copy(&g_acpt_buffer, &datalen, sizeof(datalen));
+	buffer_copy(&g_acpt_buffer, enb_ue_id, datalen);
+
+	/* NAS PDU start */
+	protocolIe_Id = id_NAS_PDU;
+	copyU16(tmpStr, protocolIe_Id);
+	buffer_copy(&g_acpt_buffer, tmpStr, sizeof(protocolIe_Id));
+	buffer_copy(&g_acpt_buffer, &protocolIe_criticality,
+					sizeof(protocolIe_criticality));
+
+	nas_len_pos = g_acpt_buffer.pos;
+
+	datalen = 0;
+	buffer_copy(&g_acpt_buffer, &datalen, sizeof(datalen));
+
+	buffer_copy(&g_acpt_buffer, &datalen, sizeof(datalen));
+
+	nas_pdu_header *nas_hdr = &(s1apPDU.value.data[2].val.nas.header);
+
+	/* security header and protocol discriminator */
+	u8value = (nas_hdr->security_header_type << 4 |
+			nas_hdr->proto_discriminator);
+	buffer_copy(&g_acpt_buffer, &u8value, sizeof(u8value));
+
+	/* mac */
+	/* placeholder for mac. mac value will be calculated later */
+	buffer_copy(&g_acpt_buffer, nas_hdr->mac, MAC_SIZE);
+	mac_data_pos = g_acpt_buffer.pos;
+
+	/* sequence number */
+	buffer_copy(&g_acpt_buffer, &(nas_hdr->seq_no),
+			sizeof(nas_hdr->seq_no));
+
+	/* security header and protocol discriminator */
+	nas_hdr->security_header_type = Plain;
+	u8value = (nas_hdr->security_header_type << 4 |
+			nas_hdr->proto_discriminator);
+	buffer_copy(&g_acpt_buffer, &u8value, sizeof(u8value));
+
+	/* message type */
+	buffer_copy(&g_acpt_buffer, &(nas_hdr->message_type),
+			sizeof(nas_hdr->message_type));	
+	/* detach type */
+        buffer_copy(&g_acpt_buffer, &(nas_hdr->detach_type),
+                        sizeof(nas_hdr->detach_type));
+
+	/* NAS PDU end */
+
+	/* Calculate mac */
+	uint8_t direction = 1;
+	uint8_t bearer = 0;
+
+	calculate_mac(g_acptReqInfo->int_key, nas_hdr->seq_no,
+			direction, bearer, &g_acpt_buffer.buf[mac_data_pos],
+			g_acpt_buffer.pos - mac_data_pos,
+			&g_acpt_buffer.buf[mac_data_pos - MAC_SIZE]);
+
+	/* Copy nas length to nas length field */
+	datalen = g_acpt_buffer.pos - nas_len_pos -1;
+	memcpy(&(g_acpt_buffer.buf[nas_len_pos]), &datalen, sizeof(datalen));
+
+	/* Copy nas length to nas length field */
+	datalen = g_acpt_buffer.pos - nas_len_pos - 2;
+	memcpy(&(g_acpt_buffer.buf[nas_len_pos + 1]), &datalen, sizeof(datalen));
+
+	/* Copy length to s1ap length field */
+	datalen = g_acpt_buffer.pos - s1ap_len_pos - 1;
+	memcpy(g_acpt_buffer.buf + s1ap_len_pos, &datalen, sizeof(datalen));
+
+	/* TODO: temp fix */
+	//g_ics_buffer.buf[1] = 0x09;
+	send_sctp_msg(g_acptReqInfo->enb_fd, g_acpt_buffer.buf, g_acpt_buffer.pos,1);
+
+	log_msg(LOG_INFO, "NI Detach Request sent to UE.");
+
+	return SUCCESS;
+}
+
+
+
+/**
+* Thread function for stage.
+*/
+void*
+ni_detach_request_handler(void *data)
+{
+   log_msg(LOG_INFO, "NI detach request handler ready.\n");
+   struct ni_detach_request_Q_msg *msg = (struct ni_detach_request_Q_msg *)data;
+
+   ni_detach_request_processing(msg);
+   
+   return NULL;
+}
+
diff --git a/src/s1ap/handlers/paging.c b/src/s1ap/handlers/paging.c
new file mode 100644
index 0000000..d2c6bf1
--- /dev/null
+++ b/src/s1ap/handlers/paging.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2019, Infosys Ltd.
+ *
+ * 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 <pthread.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdint.h>
+
+#include "ProtocolIE-Container.h"
+#include "ProtocolIE-ID.h"
+#include "ProtocolIE-Field.h"
+#include "log.h"
+#include "err_codes.h"
+#include "message_queues.h"
+#include "ipc_api.h"
+#include "s1ap.h"
+#include "s1ap_config.h"
+#include "main.h"
+#include "msgType.h"
+#include "common_proc_info.h"
+
+
+/*Stage specific message processing.
+*/
+static int
+paging_processing(struct paging_req_Q_msg *g_paging)
+{
+	log_msg(LOG_DEBUG,"Process paging.");
+	uint32_t length = 0;
+    	uint8_t *buffer = NULL;
+	
+	Buffer g_paging_buffer;
+	struct s1ap_common_req_Q_msg req= {0};
+
+	req.IE_type = S1AP_PAGING_REQ;
+        req.enb_fd = g_paging->enb_fd;
+        req.ue_idx = g_paging->ue_idx;
+        req.enb_s1ap_ue_id = g_paging->enb_s1ap_ue_id;
+	req.cn_domain = g_paging->cn_domain;
+	memcpy(req.imsi, g_paging->IMSI, BINARY_IMSI_LEN);
+	memcpy(&req.tai, &g_paging->tai, sizeof(struct TAI));
+
+	
+
+	int ret = s1ap_mme_encode_initiating(&req, &buffer, &length);
+
+    	if(ret == -1)
+    	{
+	        log_msg(LOG_ERROR, "Encoding paging request failed.\n");
+        	return E_FAIL;
+   	}
+
+
+	buffer_copy(&g_paging_buffer, buffer, length);
+	send_sctp_msg(g_paging->enb_fd, g_paging_buffer.buf, g_paging_buffer.pos,1);
+	log_msg(LOG_INFO, "\n-----Paging sent to UE.---\n");
+	return SUCCESS;
+}
+
+
+/**
+* Thread function for stage.
+*/
+void*
+paging_handler(void *data)
+{
+
+	log_msg(LOG_INFO, "paging handler ready.\n");
+	
+	paging_processing((struct paging_req_Q_msg*)data);
+
+	return NULL;
+}
+
+
diff --git a/src/s1ap/handlers/s1ap_encoder.c b/src/s1ap/handlers/s1ap_encoder.c
new file mode 100644
index 0000000..46ea3ce
--- /dev/null
+++ b/src/s1ap/handlers/s1ap_encoder.c
@@ -0,0 +1,471 @@
+/*
+ *
+ * Copyright (c) 2003-2018, Great Software Laboratory Pvt. Ltd.
+ * Copyright (c) 2017 Intel Corporation
+ * Copyright (c) 2019-Present, Infosys Ltd.
+ *
+ * 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"
+#include "common_proc_info.h"
+#include "InitiatingMessage.h"
+#include "UE-S1AP-ID-pair.h"
+#include "msgType.h"
+
+extern s1ap_config g_s1ap_cfg;
+
+int s1ap_mme_encode_initiating(
+  struct s1ap_common_req_Q_msg *message_p,
+  uint8_t **buffer,
+  uint32_t *length)
+{
+    log_msg(LOG_INFO, "MME initiating msg Encode.\n");
+    switch (message_p->IE_type) {
+        case S1AP_CTX_REL_CMD:
+            log_msg(LOG_INFO, "Ue Context release Command Encode.\n");
+            return s1ap_mme_encode_ue_context_release_command(
+                      message_p, buffer, length);
+        case S1AP_PAGING_REQ:
+            log_msg(LOG_INFO, "Paging req Encode.\n");
+            return s1ap_mme_encode_paging_request(
+                      message_p, buffer, length);
+	case S1AP_INIT_CTXT_SETUP_REQ:
+	    log_msg(LOG_INFO, "Init context setup req encode\n");
+	    return s1ap_mme_encode_initial_context_setup_request(
+		      message_p, buffer, length); 
+        default:
+            log_msg(
+                  LOG_WARNING,
+                  "Unknown procedure ID (%d) for initiating message_p\n",
+                  (int) message_p->IE_type);
+      }
+
+  return -1;
+}
+
+int s1ap_mme_encode_ue_context_release_command(
+  struct s1ap_common_req_Q_msg *s1apPDU,
+  uint8_t **buffer,
+  uint32_t *length)
+{
+	log_msg(LOG_DEBUG,"Inside s1ap_encoder\n");
+
+	S1AP_PDU_t                              pdu = {(S1AP_PDU_PR_NOTHING)};
+    InitiatingMessage_t *initiating_msg = NULL;
+	S1AP_PDU_t                             *pdu_p = &pdu;
+	int                                     enc_ret = -1;
+	memset ((void *)pdu_p, 0, sizeof (S1AP_PDU_t));
+
+    pdu.present = S1AP_PDU_PR_initiatingMessage;
+    pdu.choice.initiatingMessage = calloc(sizeof(InitiatingMessage_t), sizeof(uint8_t));
+    if(pdu.choice.initiatingMessage == NULL)
+    {
+        log_msg(LOG_ERROR,"calloc failed.\n");
+        return -1;
+    }
+    initiating_msg = pdu.choice.initiatingMessage;
+    initiating_msg->procedureCode = ProcedureCode_id_UEContextRelease;
+    initiating_msg->criticality = 0;
+    initiating_msg->value.present = InitiatingMessage__value_PR_UEContextReleaseCommand;  
+    
+    UEContextReleaseCommand_IEs_t val[2];
+    memset(val, 0, 2 * sizeof(UEContextReleaseCommand_IEs_t));
+    
+    UE_S1AP_IDs_t ue_id_val;
+    memset(&ue_id_val, 0, sizeof(UE_S1AP_IDs_t));
+     
+    struct UE_S1AP_ID_pair s1apId_pair;
+    if((s1apPDU->mme_s1ap_ue_id != 0xFFFFFFFF) 
+        && (s1apPDU->enb_s1ap_ue_id != 0xFFFFFFFF))
+    {
+        log_msg(LOG_INFO,"S1ap Id pair.\n");
+        ue_id_val.present = UE_S1AP_IDs_PR_uE_S1AP_ID_pair;
+        s1apId_pair.eNB_UE_S1AP_ID = s1apPDU->enb_s1ap_ue_id;
+        s1apId_pair.mME_UE_S1AP_ID = s1apPDU->mme_s1ap_ue_id;
+        ue_id_val.choice.uE_S1AP_ID_pair = calloc(sizeof(struct UE_S1AP_ID_pair), sizeof(uint8_t));
+        if(ue_id_val.choice.uE_S1AP_ID_pair == NULL)
+        {
+            log_msg(LOG_ERROR,"calloc failed.\n");
+            free(pdu.choice.initiatingMessage);
+            return -1;
+        }
+        memcpy(ue_id_val.choice.uE_S1AP_ID_pair, &s1apId_pair, sizeof(struct UE_S1AP_ID_pair));
+    }
+    else if(s1apPDU->mme_s1ap_ue_id != 0xFFFFFFFF)
+    {
+        ue_id_val.present = UE_S1AP_IDs_PR_mME_UE_S1AP_ID;
+        ue_id_val.choice.mME_UE_S1AP_ID = s1apPDU->mme_s1ap_ue_id;
+    }
+    else
+    {
+        ue_id_val.present = UE_S1AP_IDs_PR_NOTHING;
+    }
+
+    val[0].id = ProtocolIE_ID_id_UE_S1AP_IDs;
+    val[0].criticality = 0;
+    val[0].value.present = UEContextReleaseCommand_IEs__value_PR_UE_S1AP_IDs;
+    memcpy(&val[0].value.choice.UE_S1AP_IDs, &ue_id_val, sizeof(UE_S1AP_IDs_t));
+
+    val[1].id = ProtocolIE_ID_id_Cause;
+    val[1].criticality = 1;
+    val[1].value.present = UEContextReleaseCommand_IEs__value_PR_Cause;
+    //memcpy(&val[1].value.choice.Cause, &s1apPDU->cause, sizeof(Cause_t));
+    val[1].value.choice.Cause.present = s1apPDU->cause.present;
+    switch(s1apPDU->cause.present)
+    {
+        case Cause_PR_radioNetwork:
+            val[1].value.choice.Cause.choice.radioNetwork
+                = s1apPDU->cause.choice.radioNetwork;
+        break;
+        case Cause_PR_transport:
+            val[1].value.choice.Cause.choice.transport
+                = s1apPDU->cause.choice.transport;
+        break;
+        case Cause_PR_nas:
+            val[1].value.choice.Cause.choice.nas
+                = s1apPDU->cause.choice.nas;
+        break;
+        case Cause_PR_protocol:
+            val[1].value.choice.Cause.choice.protocol
+                = s1apPDU->cause.choice.protocol;
+        break;
+        case Cause_PR_misc:
+            val[1].value.choice.Cause.choice.misc
+                = s1apPDU->cause.choice.misc;
+        break;
+        case Cause_PR_NOTHING:
+        default:
+            log_msg(LOG_WARNING,"Unknown Cause type:%d\n",s1apPDU->cause.present);
+    }
+
+    log_msg(LOG_INFO,"Add values to list.\n");
+    ASN_SEQUENCE_ADD(&initiating_msg->value.choice.UEContextReleaseCommand.protocolIEs.list, &val[0]);
+    ASN_SEQUENCE_ADD(&initiating_msg->value.choice.UEContextReleaseCommand.protocolIEs.list, &val[1]);
+
+    if ((enc_ret = aper_encode_to_new_buffer (&asn_DEF_S1AP_PDU, 0, &pdu, (void **)buffer)) < 0) 
+    {
+        log_msg(LOG_ERROR, "Encoding of Ctx Release Cmd failed\n");
+        return -1;
+    }
+
+    log_msg(LOG_INFO,"free allocated msgs");
+    free(ue_id_val.choice.uE_S1AP_ID_pair);
+    free(pdu.choice.initiatingMessage);
+    
+    *length = enc_ret;
+    return enc_ret; 
+}
+
+int s1ap_mme_encode_initial_context_setup_request(
+  struct s1ap_common_req_Q_msg *s1apPDU,
+  uint8_t **buffer,
+  uint32_t *length)
+{
+    S1AP_PDU_t                              pdu = {(S1AP_PDU_PR_NOTHING)};
+    InitiatingMessage_t *initiating_msg = NULL;
+    S1AP_PDU_t                             *pdu_p = &pdu;
+    int                                     enc_ret = -1;
+    memset ((void *)pdu_p, 0, sizeof (S1AP_PDU_t));
+
+    pdu.present = S1AP_PDU_PR_initiatingMessage;
+    pdu.choice.initiatingMessage = calloc (sizeof(InitiatingMessage_t), sizeof(uint8_t));
+    if(pdu.choice.initiatingMessage == NULL)
+    {
+        log_msg(LOG_ERROR,"calloc failed.\n");
+        return -1;
+    }
+    initiating_msg = pdu.choice.initiatingMessage;
+    initiating_msg->procedureCode = ProcedureCode_id_InitialContextSetup;
+    initiating_msg->criticality = 0;
+    initiating_msg->value.present = InitiatingMessage__value_PR_InitialContextSetupRequest;
+
+    InitialContextSetupRequestIEs_t val[6];
+    memset(val, 0, 6 * (sizeof(InitialContextSetupRequestIEs_t)));
+
+    val[0].id = ProtocolIE_ID_id_MME_UE_S1AP_ID;
+    val[0].criticality = 0;
+    val[0].value.present = InitialContextSetupRequestIEs__value_PR_MME_UE_S1AP_ID;
+    val[0].value.choice.MME_UE_S1AP_ID = s1apPDU->mme_s1ap_ue_id;
+
+    val[1].id = ProtocolIE_ID_id_eNB_UE_S1AP_ID;
+    val[1].criticality = 0;
+    val[1].value.present = InitialContextSetupRequestIEs__value_PR_ENB_UE_S1AP_ID;
+    val[1].value.choice.ENB_UE_S1AP_ID = s1apPDU->enb_s1ap_ue_id;
+
+    val[2].id = ProtocolIE_ID_id_uEaggregateMaximumBitrate;
+    val[2].criticality = 0;
+    val[2].value.present = InitialContextSetupRequestIEs__value_PR_UEAggregateMaximumBitrate;
+
+    val[2].value.choice.UEAggregateMaximumBitrate.uEaggregateMaximumBitRateDL.size = 5;
+    val[2].value.choice.UEAggregateMaximumBitrate.uEaggregateMaximumBitRateDL.buf = calloc (5, sizeof(uint8_t));
+    val[2].value.choice.UEAggregateMaximumBitrate.uEaggregateMaximumBitRateDL.buf[0] = 0x0; 
+    uint32_t temp_bitrate = htonl(s1apPDU->ueag_max_dl_bitrate);
+    memcpy (&(val[2].value.choice.UEAggregateMaximumBitrate.uEaggregateMaximumBitRateDL.buf[1]), &temp_bitrate, sizeof(uint32_t));
+
+    val[2].value.choice.UEAggregateMaximumBitrate.uEaggregateMaximumBitRateUL.size =  5;
+    val[2].value.choice.UEAggregateMaximumBitrate.uEaggregateMaximumBitRateUL.buf = calloc (5, sizeof(uint8_t));
+    val[2].value.choice.UEAggregateMaximumBitrate.uEaggregateMaximumBitRateUL.buf[0] = 0x0; 
+    temp_bitrate = htonl(s1apPDU->ueag_max_ul_bitrate);
+    memcpy (&(val[2].value.choice.UEAggregateMaximumBitrate.uEaggregateMaximumBitRateUL.buf[1]), &temp_bitrate, sizeof(uint32_t));
+
+    val[3].id = ProtocolIE_ID_id_E_RABToBeSetupListCtxtSUReq;
+    val[3].criticality = 0;
+    val[3].value.present = InitialContextSetupRequestIEs__value_PR_E_RABToBeSetupListCtxtSUReq;
+
+    E_RABToBeSetupItemCtxtSUReqIEs_t erab_to_be_setup_item;
+    memset(&erab_to_be_setup_item, 0, sizeof(E_RABToBeSetupItemCtxtSUReqIEs_t));
+    E_RABToBeSetupItemCtxtSUReq_t* erab_to_be_setup = &(erab_to_be_setup_item.value.choice.E_RABToBeSetupItemCtxtSUReq);
+
+    erab_to_be_setup_item.id = ProtocolIE_ID_id_E_RABToBeSetupItemCtxtSUReq;
+    erab_to_be_setup_item.criticality = 0;
+    erab_to_be_setup_item.value.present = E_RABToBeSetupItemCtxtSUReqIEs__value_PR_E_RABToBeSetupItemCtxtSUReq;
+
+    erab_to_be_setup->e_RAB_ID = 5;
+
+    erab_to_be_setup->e_RABlevelQoSParameters.allocationRetentionPriority.priorityLevel = 15;
+    erab_to_be_setup->e_RABlevelQoSParameters.allocationRetentionPriority.pre_emptionCapability = 1;
+    erab_to_be_setup->e_RABlevelQoSParameters.allocationRetentionPriority.pre_emptionVulnerability = 1;
+    erab_to_be_setup->e_RABlevelQoSParameters.qCI = 9;
+
+    erab_to_be_setup->transportLayerAddress.size = 4;
+    erab_to_be_setup->transportLayerAddress.buf = calloc(4, sizeof(uint8_t));
+    uint32_t transport_layer_address = htonl(s1apPDU->gtp_teid.ip.ipv4.s_addr);
+    memcpy(erab_to_be_setup->transportLayerAddress.buf, &transport_layer_address, sizeof(uint32_t));
+    
+
+    erab_to_be_setup->gTP_TEID.size = 4;
+    erab_to_be_setup->gTP_TEID.buf = calloc(4, sizeof(uint8_t));
+    erab_to_be_setup->gTP_TEID.buf[0] =  s1apPDU->gtp_teid.header.teid_gre >> 24;
+    erab_to_be_setup->gTP_TEID.buf[1] =  s1apPDU->gtp_teid.header.teid_gre >> 16;
+    erab_to_be_setup->gTP_TEID.buf[2] =  s1apPDU->gtp_teid.header.teid_gre >> 8;
+    erab_to_be_setup->gTP_TEID.buf[3] =  s1apPDU->gtp_teid.header.teid_gre;
+
+    ASN_SEQUENCE_ADD(&(val[3].value.choice.E_RABToBeSetupListCtxtSUReq.list), &erab_to_be_setup_item);
+
+    val[4].id = ProtocolIE_ID_id_UESecurityCapabilities;
+    val[4].criticality = 0;
+    val[4].value.present = InitialContextSetupRequestIEs__value_PR_UESecurityCapabilities;
+    val[4].value.choice.UESecurityCapabilities.encryptionAlgorithms.buf = calloc(2, sizeof(uint8_t));
+    val[4].value.choice.UESecurityCapabilities.encryptionAlgorithms.size = 2;
+    val[4].value.choice.UESecurityCapabilities.encryptionAlgorithms.buf[0] = 0xe0;
+    val[4].value.choice.UESecurityCapabilities.encryptionAlgorithms.buf[1] = 0x00;
+    val[4].value.choice.UESecurityCapabilities.integrityProtectionAlgorithms.buf = calloc(2, sizeof(uint8_t));
+    val[4].value.choice.UESecurityCapabilities.integrityProtectionAlgorithms.size = 2;
+    val[4].value.choice.UESecurityCapabilities.integrityProtectionAlgorithms.buf[0] = 0xc0;
+    val[4].value.choice.UESecurityCapabilities.integrityProtectionAlgorithms.buf[1] = 0x00;
+
+    val[5].id = ProtocolIE_ID_id_SecurityKey;
+    val[5].criticality = 0;
+    val[5].value.present = InitialContextSetupRequestIEs__value_PR_SecurityKey;
+    val[5].value.choice.SecurityKey.size = SECURITY_KEY_SIZE;
+    val[5].value.choice.SecurityKey.buf = calloc(SECURITY_KEY_SIZE, sizeof(uint8_t));
+    memcpy(val[5].value.choice.SecurityKey.buf, s1apPDU->sec_key, SECURITY_KEY_SIZE);
+
+    ASN_SEQUENCE_ADD(&initiating_msg->value.choice.InitialContextSetupRequest.protocolIEs.list, &val[0]);
+    ASN_SEQUENCE_ADD(&initiating_msg->value.choice.InitialContextSetupRequest.protocolIEs.list, &val[1]);
+    ASN_SEQUENCE_ADD(&initiating_msg->value.choice.InitialContextSetupRequest.protocolIEs.list, &val[2]);
+    ASN_SEQUENCE_ADD(&initiating_msg->value.choice.InitialContextSetupRequest.protocolIEs.list, &val[3]);
+    ASN_SEQUENCE_ADD(&initiating_msg->value.choice.InitialContextSetupRequest.protocolIEs.list, &val[4]);
+    ASN_SEQUENCE_ADD(&initiating_msg->value.choice.InitialContextSetupRequest.protocolIEs.list, &val[5]);
+
+    if ((enc_ret = aper_encode_to_new_buffer (&asn_DEF_S1AP_PDU, 0, &pdu, (void **)buffer)) < 0)
+    {
+        log_msg(LOG_ERROR, "Encoding of Initial Context Setup Request failed\n");
+        return -1;
+    }
+
+    log_msg(LOG_INFO,"free allocated messages\n");
+
+    free(val[5].value.choice.SecurityKey.buf);
+    free(val[4].value.choice.UESecurityCapabilities.integrityProtectionAlgorithms.buf);
+    free(val[4].value.choice.UESecurityCapabilities.encryptionAlgorithms.buf);
+    free(erab_to_be_setup->gTP_TEID.buf);
+    free(erab_to_be_setup->transportLayerAddress.buf);
+    free(val[2].value.choice.UEAggregateMaximumBitrate.uEaggregateMaximumBitRateUL.buf);
+    free(val[2].value.choice.UEAggregateMaximumBitrate.uEaggregateMaximumBitRateDL.buf);
+    free(pdu.choice.initiatingMessage);
+
+    *length = enc_ret;
+    return enc_ret;
+}
+
+int s1ap_mme_encode_paging_request(
+  struct s1ap_common_req_Q_msg *s1apPDU,
+  uint8_t **buffer,
+  uint32_t *length)
+{
+    
+
+    S1AP_PDU_t pdu = {(S1AP_PDU_PR_NOTHING)};
+    InitiatingMessage_t *initiating_msg = NULL;
+    S1AP_PDU_t *pdu_p = &pdu;
+    int enc_ret = -1;
+    memset ((void *)pdu_p, 0, sizeof (S1AP_PDU_t));
+
+    pdu.present = S1AP_PDU_PR_initiatingMessage;
+    pdu.choice.initiatingMessage = calloc (sizeof(InitiatingMessage_t), sizeof(uint8_t));
+    if(pdu.choice.initiatingMessage == NULL)
+    {
+        log_msg(LOG_ERROR,"calloc failed.\n");
+        return -1;
+    }
+
+    initiating_msg = pdu.choice.initiatingMessage;
+    initiating_msg->procedureCode = ProcedureCode_id_Paging;
+    initiating_msg->criticality = 0;
+    initiating_msg->value.present = InitiatingMessage__value_PR_Paging;  
+
+    PagingIEs_t val[4];
+    memset(val, 0, 4 * sizeof(PagingIEs_t));
+
+    val[0].id = ProtocolIE_ID_id_UEIdentityIndexValue;
+    val[0].criticality = 0;
+    val[0].value.present = PagingIEs__value_PR_UEIdentityIndexValue;
+
+    UEIdentityIndexValue_t* UEIdentityIndexValue = &val[0].value.choice.UEIdentityIndexValue;
+    uint64_t ue_imsi_value = 0;
+    /* Set UE Identity Index value : IMSI mod 4096 */
+    UEIdentityIndexValue->size = 2;
+    UEIdentityIndexValue->buf = calloc(2, sizeof(uint8_t));
+
+    /* Conver string to value */
+    uint8_t imsi_bcd[BCD_IMSI_STR_LEN];
+	convert_imsi_to_bcd_str(s1apPDU->imsi, imsi_bcd);
+    for (int i = 0; i < BCD_IMSI_STR_LEN; i++)
+    {
+        ue_imsi_value = ue_imsi_value*10 + (imsi_bcd[i] - '0');
+    }
+
+    /* index(10bit) = ue_imsi_value mod 1024 */
+    uint16_t index_value = ue_imsi_value % 1024;
+    UEIdentityIndexValue->buf[0] = index_value >> 2;
+    UEIdentityIndexValue->buf[1] = (index_value & 0x3f) << 6;
+    UEIdentityIndexValue->bits_unused = 6;
+
+    log_msg(LOG_DEBUG,"Encoding STMSI\n");
+
+    val[1].id = ProtocolIE_ID_id_UEPagingID;
+    val[1].criticality = 0;
+    val[1].value.present = PagingIEs__value_PR_UEPagingID;
+
+    UEPagingID_t pagingId;
+    pagingId.present = UEPagingID_PR_s_TMSI;
+    pagingId.choice.s_TMSI = calloc(sizeof(struct S_TMSI), sizeof(uint8_t));
+    if(pagingId.choice.s_TMSI == NULL)
+    {
+        log_msg(LOG_ERROR,"malloc failed.\n");
+        free(pdu.choice.initiatingMessage);
+        return -1;
+    }
+
+    pagingId.choice.s_TMSI->mMEC.buf = calloc(1, sizeof(uint8_t));
+    if(NULL == pagingId.choice.s_TMSI->mMEC.buf)
+    {
+        log_msg(LOG_ERROR,"malloc failed.\n");
+        free(pdu.choice.initiatingMessage);
+        free(pagingId.choice.s_TMSI);
+        return -1;
+    }
+
+    memcpy(pagingId.choice.s_TMSI->mMEC.buf, &g_s1ap_cfg.mme_code, sizeof(uint8_t));
+    pagingId.choice.s_TMSI->mMEC.size = sizeof(uint8_t);
+    
+    pagingId.choice.s_TMSI->m_TMSI.buf = calloc(sizeof(uint32_t), sizeof(uint8_t));
+    if(NULL == pagingId.choice.s_TMSI->m_TMSI.buf)
+    {
+        log_msg(LOG_ERROR,"malloc failed.\n");
+        free(pdu.choice.initiatingMessage);
+        free(pagingId.choice.s_TMSI);
+        free(pagingId.choice.s_TMSI->mMEC.buf);
+        return -1;
+    }
+
+    uint32_t ue_idx = htonl(s1apPDU->ue_idx);
+    memcpy(pagingId.choice.s_TMSI->m_TMSI.buf, &ue_idx, sizeof(uint32_t));
+    pagingId.choice.s_TMSI->m_TMSI.size = sizeof(uint32_t);
+    memcpy(&val[1].value.choice.UEPagingID, &pagingId, sizeof(UEPagingID_t));
+
+    log_msg(LOG_INFO, "Encoding CNDomain\n");
+
+    val[2].id = ProtocolIE_ID_id_CNDomain;
+    val[2].criticality = 0;
+    val[2].value.present = PagingIEs__value_PR_CNDomain;
+    val[2].value.choice.CNDomain = s1apPDU->cn_domain;
+    
+    log_msg(LOG_DEBUG,"Encoding TAI List\n");
+	
+    val[3].id = ProtocolIE_ID_id_TAIList;
+    val[3].criticality = 0;
+    val[3].value.present = PagingIEs__value_PR_TAIList;
+
+    TAIItemIEs_t tai_item;
+    memset(&tai_item, 0, sizeof(TAIItemIEs_t));
+
+    tai_item.id = ProtocolIE_ID_id_TAIItem;
+    tai_item.criticality = 0;
+    tai_item.value.present = TAIItemIEs__value_PR_TAIItem;
+
+    log_msg(LOG_DEBUG,"TAI List - Encode PLMN ID\n");
+    tai_item.value.choice.TAIItem.tAI.pLMNidentity.size = 3;
+    tai_item.value.choice.TAIItem.tAI.pLMNidentity.buf = calloc(3, sizeof(uint8_t));
+    memcpy(tai_item.value.choice.TAIItem.tAI.pLMNidentity.buf, &s1apPDU->tai.plmn_id.idx, 3);
+
+    log_msg(LOG_DEBUG,"TAI List - Encode TAC\n");
+    tai_item.value.choice.TAIItem.tAI.tAC.size = 2;
+    tai_item.value.choice.TAIItem.tAI.tAC.buf = calloc(2, sizeof(uint8_t));
+    memcpy(tai_item.value.choice.TAIItem.tAI.tAC.buf, &s1apPDU->tai.tac, 2);
+
+    ASN_SEQUENCE_ADD(&val[3].value.choice.TAIList.list, &tai_item);
+
+    log_msg(LOG_INFO,"Add values to list.\n");
+    ASN_SEQUENCE_ADD(&initiating_msg->value.choice.Paging.protocolIEs.list, &val[0]);
+    ASN_SEQUENCE_ADD(&initiating_msg->value.choice.Paging.protocolIEs.list, &val[1]);
+    ASN_SEQUENCE_ADD(&initiating_msg->value.choice.Paging.protocolIEs.list, &val[2]);
+    ASN_SEQUENCE_ADD(&initiating_msg->value.choice.Paging.protocolIEs.list, &val[3]);
+
+    if ((enc_ret = aper_encode_to_new_buffer (&asn_DEF_S1AP_PDU, 0, &pdu, (void **)buffer)) < 0) 
+    {
+        log_msg(LOG_ERROR, "Encoding of Paging failed\n");
+        return -1;
+    }
+
+    log_msg(LOG_INFO,"free allocated msgs");
+    free(pdu.choice.initiatingMessage);
+    free(UEIdentityIndexValue->buf);
+    free(pagingId.choice.s_TMSI->mMEC.buf);
+    free(pagingId.choice.s_TMSI->m_TMSI.buf);
+    free(pagingId.choice.s_TMSI);
+    free(tai_item.value.choice.TAIItem.tAI.pLMNidentity.buf);
+    free(tai_item.value.choice.TAIItem.tAI.tAC.buf);
+    
+    *length = enc_ret;
+    return enc_ret; 
+}
diff --git a/src/s1ap/handlers/s1ap_msg_delegator.c b/src/s1ap/handlers/s1ap_msg_delegator.c
new file mode 100644
index 0000000..735652c
--- /dev/null
+++ b/src/s1ap/handlers/s1ap_msg_delegator.c
@@ -0,0 +1,1524 @@
+/*
+ * 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* msg_end = msg + 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) & 0x0F;
+		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");
+			if(SERVICE_REQ_SECURITY_HEADER == sec_header_type)
+            		{
+                		log_msg(LOG_INFO, "Recvd security header for Service request.");
+                		nas->header.security_header_type = sec_header_type;
+                		nas->header.proto_discriminator = protocol_discr;
+                		msg += 1;
+                		nas->header.ksi = msg[0] >> 4;
+                		nas->header.seq_no = msg[0] & 0x0F;
+                		msg += 1;
+                		memcpy(nas->header.short_mac, msg, SHORT_MAC_SIZE);
+                		nas->header.message_type = NAS_SERVICE_REQUEST;
+                		return;
+            		}
+
+			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);
+			nas->header.seq_no = 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)...
+
+		nas->elements[0].msgType = NAS_IE_TYPE_APN;
+		memcpy(&(nas->elements[0].pduElement.apn.len), msg, 1);
+		msg++;
+		memcpy(nas->elements[0].pduElement.apn.val, msg, nas->elements[0].pduElement.apn.len);
+		log_msg(LOG_INFO, "APN name - %s\n", nas->elements[0].pduElement.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].pduElement.auth_resp), msg, sizeof(struct XRES));
+
+		break;
+    
+	case NAS_IDENTITY_RESPONSE: {
+		log_msg(LOG_INFO, "NAS_IDENTITY_RESPONSE recvd\n");
+        nas->elements_len = 1;
+		nas->elements = calloc(sizeof(nas_pdu_elements), 1);
+		unsigned short imsi_len = get_length(&msg);
+		/*EPS mobility identity. TODO : More error checking */
+        memcpy(&(nas->elements[0].pduElement.IMSI), msg, imsi_len);
+        break;
+	}
+	
+	case NAS_TAU_REQUEST:
+		log_msg(LOG_INFO, "NAS_TAU_REQUEST recvd\n");
+		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");
+			nas->elements[0].msgType = NAS_IE_TYPE_AUTH_FAIL_PARAM;
+			memcpy(&(nas->elements[0].pduElement.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");
+		
+		unsigned char tmp = msg[0];
+		nas->header.security_encryption_algo = (tmp & 0xF0) >> 4;
+		nas->header.security_integrity_algo = tmp & 0x0F;
+		msg++;
+
+		nas->elements_len = 7;
+		nas->elements = calloc(sizeof(nas_pdu_elements), nas->elements_len);
+		
+		
+		int index = 0;
+		unsigned short imsi_len = get_length(&msg);
+		
+		bool odd = msg[0] & 0x08;
+		unsigned char eps_identity = msg[0] & 0x07;
+		switch(eps_identity) {
+                case 0x01: {
+                    // Mobile Identity contains imsi
+                    nas->flags |= NAS_MSG_UE_IE_IMSI;
+                    log_msg(LOG_INFO, "IMSI len=%u - %u\n", imsi_len, BINARY_IMSI_LEN);
+                    nas->elements[index].msgType = NAS_IE_TYPE_EPS_MOBILE_ID_IMSI;
+                    memcpy(&(nas->elements[index].pduElement.IMSI), msg, imsi_len);
+                    break;
+                }
+                case 0x06: {
+                    log_msg(LOG_INFO, "Mobile identity GUTI Rcvd \n");
+                    // Mobile Identity contains GUTI
+                    // MCC+MNC offset = 3
+                    // MME Group Id   = 2
+                    // MME Code       = 1
+                    // MTMSI offset from start of this AVP = 3 + 2 + 1
+                    nas->elements[index].msgType = NAS_IE_TYPE_EPS_MOBILE_ID_IMSI;
+                    memcpy(&nas->elements[index].pduElement.mi_guti.plmn_id.idx, &msg[1], 3);
+                    nas->elements[index].pduElement.mi_guti.mme_grp_id = ntohs(*(short int *)(&msg[4]));
+                    nas->elements[index].pduElement.mi_guti.mme_code = msg[6];
+                    nas->elements[index].pduElement.mi_guti.m_TMSI = ntohl(*((unsigned int *)(&msg[7])));
+                    log_msg(LOG_INFO, "NAS Attach Request Rcvd ID: GUTI. PLMN id %d %d %d \n", nas->elements[index].pduElement.mi_guti.plmn_id.idx[0], 
+                            nas->elements[index].pduElement.mi_guti.plmn_id.idx[1], 
+                            nas->elements[index].pduElement.mi_guti.plmn_id.idx[2] );
+                    log_msg(LOG_INFO, "NAS Attach Request Rcvd ID: GUTI. mme group id = %d, MME code %d  mtmsi = %d\n", 
+                            nas->elements[index].pduElement.mi_guti.mme_grp_id, 
+                            nas->elements[index].pduElement.mi_guti.mme_code,
+                            nas->elements[index].pduElement.mi_guti.m_TMSI);
+                    nas->flags |= NAS_MSG_UE_IE_GUTI;
+                    break;
+                }
+                case 0x03: {
+                    // Mobile Identity contains imei
+                    break;
+                }
+            }
+
+            msg += imsi_len;
+            char *buffer = NULL;
+            log_msg(LOG_INFO, "IMSI=%s [to be read nibble-swapped]\n",
+                    msg_to_hex_str((char *)nas->elements[index].pduElement.IMSI, imsi_len, &buffer));
+            log_buffer_free(&buffer);
+
+            /*UE network capacity*/
+            index++;
+            nas->elements[index].msgType = 
+                NAS_IE_TYPE_UE_NETWORK_CAPABILITY;
+            nas->elements[index].pduElement.ue_network.len = msg[0];
+            msg++;
+            memcpy(
+                   (nas->elements[index].pduElement.ue_network.capab)
+                   ,msg,
+                   nas->elements[index].pduElement.ue_network.len);
+            msg += nas->elements[index].pduElement.ue_network.len;
+
+            index++;
+            /*ESM msg container*/
+            len = msg[0] << 8 | msg[1];
+            msg += 2;
+            //now msg points to ESM message contents
+            log_msg(LOG_INFO, "len=%x\n", len);
+            log_msg(LOG_INFO, "msg[0]=%x\n", msg[0]);
+            nas->elements[index].pduElement.pti = msg[1];
+            nas->elements[index].msgType = NAS_IE_TYPE_PTI;
+            log_msg(LOG_INFO, "pti=%x\n", nas->elements[index].pduElement.pti);
+            unsigned short int msg_offset = 4;
+            /*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*/
+            //if tx_flag is absent then it means flag is set to false 
+            //nas->elements[index].pduElement.esm_info_tx_required = false;
+            while(msg_offset < len)
+            {
+                unsigned char val = msg[msg_offset];
+                log_msg(LOG_INFO, "ESM container AVP val=%x\n", val);
+                if(13 == (val>>4))
+                {
+                    index++;
+                    nas->elements[index].msgType = NAS_IE_TYPE_TX_FLAG;
+                    // byte 0 - EBI+PD, byte1 - pti, byte2 - message type, byte3 - pdntype+reqtype, byte4 - ESM info transfer flag == Total 5 bytes... msg[0] to msg[4]
+                    //nas->elements[2].esm_info_tx_required = true;
+                    if(val & 1) {
+                        nas->elements[index].pduElement.esm_info_tx_required = true;
+                        log_msg(LOG_INFO, "ESM information requested ");
+                    }
+                    msg_offset++; /* just one byte AVP */
+                    continue;
+
+                }
+
+                if(0x27 == val)
+                {
+                    unsigned short int pco_offset =  msg_offset;
+                    unsigned char pco_length = msg[msg_offset+1];
+                    pco_offset += 2; // now points to first pco payload byte
+                    pco_offset += 1; // 1 byte header skipping Extension + Configuration Protocol
+                    unsigned short int pco_options=0;
+                    log_msg(LOG_INFO, "PCO length %d Msg offset = %d , pco offset = %d ", pco_length, msg_offset, pco_offset);
+                    index++;
+                    nas->elements[index].msgType = NAS_IE_TYPE_PCO;
+                    while(pco_offset < (msg_offset + pco_length))
+                    {
+                        log_msg(LOG_INFO, "Inside PCO length %d Msg offset = %d , pco offset = %d ", pco_length, msg_offset, pco_offset);
+                        unsigned short int type;
+                        unsigned char oct_len;
+                        memcpy(&type, &msg[pco_offset], sizeof(type));
+                        type = htons(type);
+                        pco_offset += 2;
+                        oct_len = msg[pco_offset];
+                        pco_offset += 1;
+                        log_msg(LOG_INFO, "pco element_id=%x len %d \n", type, oct_len);
+                        if(type == 0x8021)
+                        {
+                            nas->elements[index].pduElement.pco_options[pco_options] = 0x8021;
+                            pco_options++;
+                        }
+                        else if(type == 0x000d)
+                        {
+                            nas->elements[index].pduElement.pco_options[pco_options] = 0x000d;
+                            pco_options++;
+                        }
+                        else if(type == 0x000a)
+                        {
+                            nas->elements[index].pduElement.pco_options[pco_options] = 0x000a;
+                            pco_options++;
+                        }
+                        else if(type == 0x0005)
+                        {
+                            nas->elements[index].pduElement.pco_options[pco_options] = 0x0005;
+                            pco_options++;
+                        }
+                        else if(type == 0x0010)
+                        {
+                            nas->elements[index].pduElement.pco_options[pco_options] = 0x0010;
+                            pco_options++;
+                        }
+                        else if(type == 0x0011)
+                        {
+                            nas->elements[index].pduElement.pco_options[pco_options] = 0x0011;
+                            pco_options++;
+                        }
+                        pco_offset += oct_len;
+                    }
+
+                    //pco
+                    msg_offset = pco_length + 2; // msg offset was already at PCO AVP type. Now it should point to next AVP type
+                    continue;
+                }
+                break; // unhandled ESM AVP...Add support..for now just break out..else we would be in tight loop
+            }
+            msg += len;
+
+            unsigned char elem_id = msg[0];
+            while(msg != msg_end)
+            {
+                elem_id = msg[0];
+                elem_id >>= 4;
+                if((NAS_IE_TYPE_GUTI_TYPE == elem_id)
+                    || (NAS_IE_TYPE_TMSI_STATUS == elem_id)
+                    || (NAS_IE_TYPE_MS_NETWORK_FEATURE_SUPPORT == elem_id))
+                {
+                    switch(elem_id)
+                    {
+                        case NAS_IE_TYPE_GUTI_TYPE:
+                            {
+                                log_msg(LOG_DEBUG, "Old guti type : Skipping.\n");
+                                msg++;
+                            }break;
+                        case NAS_IE_TYPE_TMSI_STATUS:
+                            {
+                                log_msg(LOG_DEBUG, "TMSI Status : Skipping.\n");
+                                msg++;
+                            }break;
+                        case NAS_IE_TYPE_MS_NETWORK_FEATURE_SUPPORT:
+                            {
+                                log_msg(LOG_DEBUG, "MS Network feature support : Skipping.\n");
+                                msg++;
+                            }break;
+                        default:
+                            log_msg(LOG_WARNING, "Unknown AVP in attach msg. %d \n",elem_id);
+                            msg++;
+                    }
+
+                    continue;
+                }
+                else
+                {
+                    elem_id = msg[0];
+                    switch(elem_id)
+                    {
+                        case NAS_IE_TYPE_DRX_PARAM:
+                            {
+                                log_msg(LOG_DEBUG, "DRX Param : Skipping.\n");
+                                msg += 3;
+                            }break;
+                        case NAS_IE_TYPE_TAI:
+                            {
+                                log_msg(LOG_DEBUG, "TAI : Skipping.\n");
+                                msg += 6;
+                            }break;
+                        case NAS_IE_TYPE_MS_CLASSMARK_2:
+                            {
+                                log_msg(LOG_DEBUG, "MS classmark 2 : Skipping.\n");
+                                int len = msg[1];
+                                msg += len + 2; //msgid + len field + len;
+                            }break;
+                        case NAS_IE_TYPE_VOICE_DOMAIN_PREF_UE_USAGE_SETTING:
+                            {
+                                log_msg(LOG_DEBUG, "Voice domain UE Usage : Skipping.\n");
+                                int len = msg[1];
+                                msg += len + 2; //msgid + len field + len;
+                            }break;
+                        case NAS_IE_TYPE_MS_NETWORK_CAPABILITY:
+                            {
+                                log_msg(LOG_DEBUG, "MS Network capability : Handling.\n");
+                                index++;
+                                nas->elements[index].msgType = NAS_IE_TYPE_MS_NETWORK_CAPABILITY;
+                                nas->elements[index].pduElement.ms_network.pres = true;
+                                nas->elements[index].pduElement.ms_network.element_id 
+                                    = msg[0];
+                                msg++;
+                                nas->elements[index].pduElement.ms_network.len = msg[0];
+                                msg++;
+                                memcpy(
+                                       (nas->elements[index].pduElement.ms_network.capab), 
+                                       msg, 
+                                       nas->elements[index].pduElement.ms_network.len);
+                                msg += 
+                                    nas->elements[index].pduElement.ms_network.len;
+                            }break;
+                        default:
+                            log_msg(LOG_WARNING, "Unknown AVP in Attach Req  %d \n", elem_id);
+                            msg++;
+                    }
+                
+                    continue;
+                }
+            }
+            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].pduElement.mi_guti), msg + 11, sizeof(guti));
+		log_msg(LOG_INFO, "M-TMSI - %d\n", nas->elements[0].pduElement.mi_guti.m_TMSI);
+		break;
+	}
+	
+	case NAS_DETACH_ACCEPT: {
+		log_msg(LOG_INFO, "NAS_DETACH_ACCEPT recvd\n");
+        break;
+     	}
+
+    default:
+        log_msg(LOG_ERROR, "Unknown NAS Message 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;
+
+    if(msg->value.present == InitiatingMessage__value_PR_InitialUEMessage)
+    {
+        ProtocolIE_Container_129P32_t* protocolIes = &msg->value.choice.InitialUEMessage.protocolIEs;
+        proto_ies->no_of_IEs = protocolIes->list.count;
+
+        log_msg(LOG_INFO, "No of IEs = %d\n", proto_ies->no_of_IEs);
+        proto_ies->data = calloc(sizeof(struct proto_IE_data), proto_ies->no_of_IEs);
+        if(proto_ies->data == NULL) {
+            log_msg(LOG_ERROR,"Calloc 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");
+                        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");
+                        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");
+                        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.idx,
+                                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");
+                        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");
+                        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;
+				case ProtocolIE_ID_id_S_TMSI:
+					{
+			            S_TMSI_t*	 s1apStmsi_p = NULL;;
+                        if(InitialUEMessage_IEs__value_PR_S_TMSI == ie_p->value.present)
+                        {
+						    s1apStmsi_p = &ie_p->value.choice.S_TMSI;
+                        }
+
+                        if (s1apStmsi_p == NULL) {
+							log_msg (LOG_ERROR, "Decoding of IE STMSI failed\n");
+							return -1;
+						}
+
+                        //struct STMSI     s_tmsi
+                        proto_ies->data[i].IE_type = S1AP_IE_S_TMSI;
+						memcpy(&proto_ies->data[i].val.s_tmsi.mme_code,
+                               s1apStmsi_p->mMEC.buf, sizeof(uint8_t));
+						memcpy(&proto_ies->data[i].val.s_tmsi.m_TMSI,
+                                s1apStmsi_p->m_TMSI.buf, sizeof(uint32_t));
+						s1apStmsi_p = NULL;
+					} break;
+                default:
+                    {
+                        log_msg(LOG_WARNING, "Unhandled IE %d in initial UE message ", 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");
+
+    /* TODO : Error handling. Bad message will lead crash. 
+     * Preferably reject the message, increment stats.
+     */
+	int decode_result = convertToInitUeProtoIe(msg, &proto_ies);
+    if(decode_result < 0 )
+    {
+	  log_msg(LOG_ERROR, "S1ap message decode failed. Dropping message");
+      return E_FAIL;
+    }
+
+	/*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_SERVICE_REQUEST:
+		s1_init_ue_service_req_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;
+
+	case NAS_TAU_REQUEST:
+	    tau_request_handler(&proto_ies, enb_fd);
+	    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;
+
+	case NAS_IDENTITY_RESPONSE:
+        s1_identity_resp_handler(&proto_ies);
+        break;
+
+	case NAS_TAU_REQUEST:
+	    tau_request_handler(&proto_ies, enb_fd);
+	    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);
+		ASN__DECODE_FAILED;
+        	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_CONTEXT_RELEASE_REQUEST_CODE:
+		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;
+}
+
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;
+}
+
diff --git a/src/s1ap/handlers/s1ap_tau_request_handler.c b/src/s1ap/handlers/s1ap_tau_request_handler.c
new file mode 100644
index 0000000..ae93f88
--- /dev/null
+++ b/src/s1ap/handlers/s1ap_tau_request_handler.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2019-present Open Networking Foundation
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <pthread.h>
+
+
+#include "err_codes.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 "msgType.h"
+
+
+extern int g_enb_fd;
+extern ipc_handle ipc_S1ap_Hndl;
+
+int
+tau_request_handler(struct proto_IE *s1_tau_req_ies, int enb_fd)
+{
+	struct s1_incoming_msg_data_t req= {0};
+
+	log_msg(LOG_INFO, "S1ap received tau Request:--\n");
+
+	req.msg_type = tau_request;
+    	req.msg_data.tauReq_Q_msg_m.enb_fd = enb_fd;
+
+    for(int i = 0; i < s1_tau_req_ies->no_of_IEs; i++)
+    {
+        switch(s1_tau_req_ies->data[i].IE_type)
+        {
+		case S1AP_IE_ENB_UE_ID:
+		{
+			req.s1ap_enb_ue_id = s1_tau_req_ies->data[i].val.enb_ue_s1ap_id;
+		}break;
+		
+		case S1AP_IE_MME_UE_ID:
+		{
+			req.ue_idx = s1_tau_req_ies->data[i].val.mme_ue_s1ap_id;	
+		}break;
+
+            	case S1AP_IE_NAS_PDU:
+            	{
+                	nas_pdu_header *hdr = &s1_tau_req_ies->data[i].val.nas.header;
+                	req.msg_data.tauReq_Q_msg_m.seq_num = hdr->seq_no;
+            	}break;
+            	default:
+			// Once MME starts handlign this request we can parse and send the content 
+			log_msg(LOG_WARNING,"Unhandled IE In tau request %d",s1_tau_req_ies->data[i].IE_type);
+		}
+	}
+	
+	req.destInstAddr = htonl(mmeAppInstanceNum_c);
+    	req.srcInstAddr = htonl(s1apAppInstanceNum_c);
+    	send_tipc_message(ipc_S1ap_Hndl, mmeAppInstanceNum_c, (char *)&req, S1_READ_MSG_BUF_SIZE);
+
+
+	log_msg(LOG_INFO, "Sent TAU request to mme-app\n");
+	return SUCCESS;
+}
+
diff --git a/src/s1ap/handlers/s1ap_tau_response_handler.c b/src/s1ap/handlers/s1ap_tau_response_handler.c
new file mode 100644
index 0000000..8838da3
--- /dev/null
+++ b/src/s1ap/handlers/s1ap_tau_response_handler.c
@@ -0,0 +1,345 @@
+/*
+ * Copyright 2019-present Open Networking Foundation
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdint.h>
+
+
+
+#include "log.h"
+#include "err_codes.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 "msgType.h"
+extern s1ap_config g_s1ap_cfg;
+extern ipc_handle ipc_S1ap_Hndl;
+static Buffer g_buffer;
+static int
+get_tau_rsp_protoie_value(struct proto_IE *value, struct tauResp_Q_msg *g_tauRespInfo)
+{
+    
+	value->no_of_IEs = TAU_RSP_NO_OF_IES;
+
+	value->data = (proto_IEs *) malloc(TAU_RSP_NO_OF_IES*
+			sizeof(proto_IEs));
+
+	value->data[0].val.mme_ue_s1ap_id = g_tauRespInfo->ue_idx;
+	value->data[1].val.enb_ue_s1ap_id = g_tauRespInfo->s1ap_enb_ue_id;
+
+	log_msg(LOG_INFO, "mme_ue_s1ap_id %d and enb_ue_s1ap_id %d\n",
+			g_tauRespInfo->ue_idx, g_tauRespInfo->s1ap_enb_ue_id);
+
+	/* TODO: Add enum for security header type */
+	value->data[2].val.nas.header.security_header_type = IntegrityProtectedCiphered;
+	value->data[2].val.nas.header.proto_discriminator = EPSMobilityManagementMessages;
+    if(g_tauRespInfo->status == 0)
+	  value->data[2].val.nas.header.message_type = TauAccept;
+    else
+	  value->data[2].val.nas.header.message_type = TauReject;
+	value->data[2].val.nas.header.nas_security_param = 0;
+	/* placeholder for mac. mac value will be calculated later */
+	uint8_t mac[MAC_SIZE] = {0};
+	memcpy(value->data[2].val.nas.header.mac, mac, MAC_SIZE);
+	value->data[2].val.nas.header.seq_no = g_tauRespInfo->dl_seq_no;
+	value->data[2].val.nas.header.eps_bearer_identity = 0;
+	value->data[2].val.nas.header.procedure_trans_identity = 1;
+	value->data[2].val.nas.elements_len = TAU_RSP_NO_OF_NAS_IES;
+	value->data[2].val.nas.elements = (nas_pdu_elements *) malloc(TAU_RSP_NO_OF_NAS_IES * sizeof(nas_pdu_elements));
+	nas_pdu_elements *nasIEs = value->data[2].val.nas.elements;
+	uint8_t nasIeCnt = 0;
+	nasIEs[nasIeCnt].pduElement.eps_res = 0; /* TA updated */
+	nasIeCnt++;
+	nasIEs[nasIeCnt].pduElement.spare = 0; /* TA updated */
+	nasIeCnt++;
+
+	return SUCCESS;
+}
+
+static int
+tau_rsp_processing(struct tauResp_Q_msg *g_tauRespInfo)
+{
+
+	struct s1ap_PDU s1apPDU= {0};
+    
+	uint8_t nas_len_pos;
+	uint8_t s1ap_len_pos;
+	uint8_t mac_data_pos;
+	uint8_t datalen;
+	uint8_t u8value;
+
+    if(g_tauRespInfo->status != 0)
+    {
+	  /* Assigning values to s1apPDU */
+	  s1apPDU.procedurecode = id_errorIndication;
+	  s1apPDU.criticality = CRITICALITY_IGNORE;
+	  get_tau_rsp_protoie_value(&s1apPDU.value,g_tauRespInfo);
+          g_buffer.pos = 0;
+
+	  uint8_t initiating_message = 0; /* TODO: Add enum */
+	  buffer_copy(&g_buffer, &initiating_message,
+	  		sizeof(initiating_message));
+
+	  buffer_copy(&g_buffer, &s1apPDU.procedurecode,
+	  		sizeof(s1apPDU.procedurecode));
+
+	  buffer_copy(&g_buffer, &s1apPDU.criticality,
+	  		sizeof(s1apPDU.criticality));
+
+	  s1ap_len_pos = g_buffer.pos;
+
+	  /* length of S1ap message */
+	  u8value = 0;
+	  buffer_copy(&g_buffer, &u8value, sizeof(u8value));
+
+	  /* TODO remove hardcoded values */
+	  unsigned char chProtoIENo[3] = {0,0,2};
+
+	  buffer_copy(&g_buffer, chProtoIENo, 3);
+
+	  unsigned char tmpStr[4];
+
+      /* id-eNB-UE-S1AP-ID */
+
+	  uint16_t protocolIe_Id = id_eNB_UE_S1AP_ID;
+	  uint8_t protocolIe_criticality = CRITICALITY_REJECT;
+	  copyU16(tmpStr, protocolIe_Id);
+	  buffer_copy(&g_buffer, tmpStr,
+	  					sizeof(protocolIe_Id));
+
+	  buffer_copy(&g_buffer, &protocolIe_criticality,
+	  				sizeof(protocolIe_criticality));
+
+
+	  /* TODO needs proper handling*/
+	  unsigned char enb_ue_id[3];
+	  datalen = copyU16(enb_ue_id,
+	  		s1apPDU.value.data[1].val.enb_ue_s1ap_id);
+	  buffer_copy(&g_buffer, &datalen, sizeof(datalen));
+	  buffer_copy(&g_buffer, enb_ue_id, datalen);
+
+	  unsigned char cause[6] = {0,2,40,2,4, 0};
+	  buffer_copy(&g_buffer, cause, sizeof(cause));
+
+	  /* Copy length to s1ap length field */
+	  datalen = g_buffer.pos - s1ap_len_pos - 1;
+	  memcpy(g_buffer.buf + s1ap_len_pos, &datalen, sizeof(datalen));
+      return E_FAIL;
+    }
+	/* Assigning values to s1apPDU */
+	s1apPDU.procedurecode = id_downlinkNASTransport;
+	s1apPDU.criticality = CRITICALITY_IGNORE;
+
+	get_tau_rsp_protoie_value(&s1apPDU.value,g_tauRespInfo);
+ 
+	/* Copy values to buffer from s1apPDU */
+
+	g_buffer.pos = 0;
+
+	uint8_t initiating_message = 0; /* TODO: Add enum */
+	buffer_copy(&g_buffer, &initiating_message,
+			sizeof(initiating_message));
+
+	buffer_copy(&g_buffer, &s1apPDU.procedurecode,
+			sizeof(s1apPDU.procedurecode));
+
+	buffer_copy(&g_buffer, &s1apPDU.criticality,
+			sizeof(s1apPDU.criticality));
+
+	s1ap_len_pos = g_buffer.pos;
+
+	/* length of S1ap message */
+	u8value = 0;
+	buffer_copy(&g_buffer, &u8value, sizeof(u8value));
+
+	/* TODO remove hardcoded values */
+	unsigned char chProtoIENo[3] = {0,0,3};
+
+	buffer_copy(&g_buffer, chProtoIENo, 3);
+
+	unsigned char tmpStr[4];
+
+	/* id-MME-UE-S1AP-ID */
+	uint16_t protocolIe_Id = id_MME_UE_S1AP_ID;
+	copyU16(tmpStr, protocolIe_Id);
+	buffer_copy(&g_buffer, tmpStr,
+					sizeof(protocolIe_Id));
+
+	uint8_t protocolIe_criticality = CRITICALITY_REJECT;
+	buffer_copy(&g_buffer, &protocolIe_criticality,
+					sizeof(protocolIe_criticality));
+
+	/* TODO needs proper handling*/
+	unsigned char mme_ue_id[3];
+	datalen = copyU16(mme_ue_id,
+			s1apPDU.value.data[0].val.mme_ue_s1ap_id);
+	buffer_copy(&g_buffer, &datalen, sizeof(datalen));
+	buffer_copy(&g_buffer, mme_ue_id, datalen);
+
+	/* id-eNB-UE-S1AP-ID */
+
+	protocolIe_Id = id_eNB_UE_S1AP_ID;
+	copyU16(tmpStr, protocolIe_Id);
+	buffer_copy(&g_buffer, tmpStr,
+						sizeof(protocolIe_Id));
+
+	buffer_copy(&g_buffer, &protocolIe_criticality,
+					sizeof(protocolIe_criticality));
+
+	/* TODO needs proper handling*/
+	unsigned char enb_ue_id[3];
+	datalen = copyU16(enb_ue_id,
+			s1apPDU.value.data[1].val.enb_ue_s1ap_id);
+	buffer_copy(&g_buffer, &datalen, sizeof(datalen));
+	buffer_copy(&g_buffer, enb_ue_id, datalen);
+
+	/* id-NAS-PDU */
+	protocolIe_Id = id_NAS_PDU;
+	copyU16(tmpStr, protocolIe_Id);
+	buffer_copy(&g_buffer, tmpStr,
+						sizeof(protocolIe_Id));
+	buffer_copy(&g_buffer, &protocolIe_criticality,
+					sizeof(protocolIe_criticality));
+
+	nas_len_pos = g_buffer.pos;
+	datalen = 0;
+	buffer_copy(&g_buffer, &datalen, sizeof(datalen));
+	buffer_copy(&g_buffer, &datalen, sizeof(datalen));
+
+	struct nasPDU *nas = &(s1apPDU.value.data[2].val.nas);
+	struct nas_pdu_header *nas_hdr = &(s1apPDU.value.data[2].val.nas.header);
+
+    u8value = (nas->header.security_header_type << 4) |
+			nas->header.proto_discriminator;
+	buffer_copy(&g_buffer, &u8value, sizeof(u8value));
+
+	/* mac */
+	/* placeholder for mac. mac value will be calculated later */
+	buffer_copy(&g_buffer, nas_hdr->mac, MAC_SIZE);
+	mac_data_pos = g_buffer.pos;
+
+	/* sequence number */
+	buffer_copy(&g_buffer, &(nas_hdr->seq_no),
+			sizeof(nas_hdr->seq_no));
+
+	/* security header and protocol discriminator */
+	nas_hdr->security_header_type = Plain;
+	u8value = (0 << 4 | nas_hdr->proto_discriminator);
+	buffer_copy(&g_buffer, &u8value, sizeof(u8value));
+
+	/* message type */
+	buffer_copy(&g_buffer, &nas->header.message_type,
+						sizeof(nas->header.message_type));
+
+
+	u8value = 0; 
+	buffer_copy(&g_buffer, &u8value, sizeof(u8value));
+	u8value = 0x5a; 
+	buffer_copy(&g_buffer, &u8value, sizeof(u8value));
+#define DISABLE_TAU 0
+#if DISABLE_TAU
+	u8value = 0xe0; 
+#else
+	u8value = 0x21; 
+#endif
+	buffer_copy(&g_buffer, &u8value, sizeof(u8value));
+
+#if 1 
+    /* adding GUTI */
+	u8value = 0x50; /* element id TODO: define macro or enum */
+	buffer_copy(&g_buffer, &u8value, sizeof(u8value));
+	datalen = 11;
+	buffer_copy(&g_buffer, &datalen, sizeof(datalen));
+	u8value = 246; /* TODO: remove hard coding */
+	buffer_copy(&g_buffer, &u8value, sizeof(u8value));
+
+    unsigned char x3 = g_tauRespInfo->tai.plmn_id.idx[2]; 
+    unsigned char x2 = g_tauRespInfo->tai.plmn_id.idx[1]; 
+    unsigned char x31 = x3 >> 4;
+    unsigned char x32 = x3 & 0xf;
+    unsigned char x21 = x2 >> 4;
+    unsigned char x22  = x2 & 0xf;
+    x3 = x21 | (x32 <<4);
+    x2 = (x31 << 4) | x22;
+    g_tauRespInfo->tai.plmn_id.idx[1] = x2;
+    g_tauRespInfo->tai.plmn_id.idx[2] = x3;
+
+    buffer_copy(&g_buffer, &g_tauRespInfo->tai.plmn_id, 3);
+
+    uint16_t grpid = htons(g_s1ap_cfg.mme_group_id);
+	buffer_copy(&g_buffer, &grpid, sizeof(grpid)); 
+
+    u8value = g_s1ap_cfg.mme_code;
+	buffer_copy(&g_buffer, &u8value, sizeof(u8value));
+
+    uint32_t mtmsi = htonl(g_tauRespInfo->m_tmsi); 
+	buffer_copy(&g_buffer, &(mtmsi), sizeof(mtmsi));
+#endif
+
+
+
+#if 1
+    /*TODO : Experiment */
+	u8value = 0x23; /* element id TODO: define macro or enum */
+	buffer_copy(&g_buffer, &u8value, sizeof(u8value));
+	datalen = 0x05;
+	buffer_copy(&g_buffer, &datalen, sizeof(datalen));
+    
+    u8value = 0xf4; //
+	buffer_copy(&g_buffer, &u8value, sizeof(u8value));
+
+    mtmsi = htonl(g_tauRespInfo->ue_idx); 
+	buffer_copy(&g_buffer, &(mtmsi), sizeof(mtmsi));
+#endif
+	/* NAS PDU end */
+
+	/* Calculate mac */
+	uint8_t direction = 1;
+	uint8_t bearer = 0;
+
+	calculate_mac(g_tauRespInfo->int_key, nas_hdr->seq_no,
+			direction, bearer, &g_buffer.buf[mac_data_pos],
+			g_buffer.pos - mac_data_pos,
+			&g_buffer.buf[mac_data_pos - MAC_SIZE]);
+
+	
+	/* Copy nas length to nas length field */
+	datalen = g_buffer.pos - nas_len_pos - 1;
+	memcpy(&g_buffer.buf[nas_len_pos], &datalen, sizeof(datalen));
+
+	/* Copy nas length to nas length field */
+	datalen = g_buffer.pos - nas_len_pos - 2;
+	memcpy(&(g_buffer.buf[nas_len_pos + 1]), &datalen, sizeof(datalen));
+
+	/* Copy length to s1ap length field */
+	datalen = g_buffer.pos - s1ap_len_pos - 1;
+	memcpy(g_buffer.buf + s1ap_len_pos, &datalen, sizeof(datalen));
+
+   	send_sctp_msg(g_tauRespInfo->enb_fd, g_buffer.buf, g_buffer.pos,1);
+	log_msg(LOG_INFO, "\nTAU RESP received from MME\n");
+	return SUCCESS;
+}
+
+
+void*
+tau_response_handler(void *data)
+{
+
+	log_msg(LOG_INFO, "TAU response handler ready.\n");
+
+	tau_rsp_processing((struct tauResp_Q_msg *)data);
+	
+	return NULL;
+}
diff --git a/src/s1ap/handlers/s1setup.c b/src/s1ap/handlers/s1setup.c
new file mode 100644
index 0000000..60e92d7
--- /dev/null
+++ b/src/s1ap/handlers/s1setup.c
@@ -0,0 +1,162 @@
+/*
+ * 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 "err_codes.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"
+
+extern int g_enb_fd;
+extern s1ap_config g_s1ap_cfg;
+static struct Buffer resp_buf;
+
+int
+create_s1setup_response(/*enb info,*/unsigned char **s1_setup_resp)
+{
+	unsigned char data_len = 0;
+	unsigned char msg[50];
+	struct Buffer proto_ies;
+	struct Buffer gummies;
+	uint16_t proto_ie_id;
+	unsigned char tmp_str[4];
+	uint8_t criticality;
+
+	/*Leave a byte to fill length*/
+	resp_buf.pos = 0;
+	/*Only in case of s1setup resp, first byte is 0x20, not for any other
+	s1ap message. Nothing found in specs, please check.*/
+	/**procedureCode: id-S1Setup (17)**/
+	msg[0] = 0x20;
+	msg[1] = S1AP_SETUP_REQUEST_CODE;
+	msg[2] = CRITICALITY_REJECT;
+	buffer_copy(&resp_buf, msg, 3);
+
+	/**IE1*/
+	/**Item 0: id-MMEname*/
+	proto_ie_id = S1AP_IE_MMENAME;
+	copyU16(tmp_str, proto_ie_id);
+	buffer_copy(&proto_ies, tmp_str, sizeof(proto_ie_id));
+	criticality = CRITICALITY_IGNORE;
+	buffer_copy(&proto_ies, &criticality, sizeof(criticality));
+
+	data_len = strlen(g_s1ap_cfg.mme_name);
+	data_len = copyU16(tmp_str, data_len);
+	tmp_str[1] = tmp_str[1]+2;
+	buffer_copy(&proto_ies, &tmp_str[1], 1);
+	proto_ies.buf[proto_ies.pos++] = 0x06;/*quest: what is this in encoding?*/
+	proto_ies.buf[proto_ies.pos++] = 0x80;
+	buffer_copy(&proto_ies, g_s1ap_cfg.mme_name, strlen(g_s1ap_cfg.mme_name));
+
+	/*IE2*/
+	/**Item 1: id-ServedGUMMEIs*/
+	proto_ie_id = S1AP_IE_SERVED_GUMMEIES;
+	copyU16(tmp_str, proto_ie_id);
+	buffer_copy(&proto_ies, tmp_str, sizeof(proto_ie_id));
+	criticality = CRITICALITY_REJECT;
+	buffer_copy(&proto_ies, &criticality, sizeof(criticality));
+
+	//msg[i++] = 0x0b;//len
+	gummies.buf[0]=0x0;
+	gummies.buf[1]=0x0;
+	gummies.pos = 2;
+
+	/**Item 1: id-ServedGUMMEIs
+	 *       servedPLMNs: 1 item*/
+	buffer_copy(&gummies, &(g_s1ap_cfg.mme_plmn_id), sizeof(struct PLMN));
+	gummies.buf[gummies.pos++]=0x0;
+	gummies.buf[gummies.pos++]=0x0;
+
+	/**Item 1: id-ServedGUMMEIs
+	 *       servedGroupIDs: 1 item*/
+	data_len = copyU16(tmp_str, g_s1ap_cfg.mme_group_id);
+	buffer_copy(&gummies, tmp_str, data_len);
+
+	/**Item 1: id-ServedGUMMEIs
+	 *       servedMMECs: 1 item*/
+	gummies.buf[gummies.pos++]=0x0;
+	gummies.buf[gummies.pos++] = g_s1ap_cfg.mme_code;
+
+	data_len = copyU16(tmp_str, gummies.pos);
+	buffer_copy(&proto_ies, &(tmp_str[1]), 1);
+	buffer_copy(&proto_ies, &gummies.buf, gummies.pos);
+
+	/*IE3*/
+	/**id: id-RelativeMMECapacity (87)*/
+	proto_ie_id = S1AP_IE_REL_MME_CAPACITY;
+	copyU16(tmp_str, proto_ie_id);
+	buffer_copy(&proto_ies, tmp_str, sizeof(proto_ie_id));
+	criticality = CRITICALITY_IGNORE;
+	buffer_copy(&proto_ies, &criticality, sizeof(criticality));
+	data_len = 1;
+	buffer_copy(&proto_ies, &(data_len), 1);
+	g_s1ap_cfg.rel_cap = 1;
+	buffer_copy(&proto_ies, &(g_s1ap_cfg.rel_cap), 1);
+
+	/*number of proto IEs = 3*/
+	data_len = copyU16(tmp_str, 3);
+
+	data_len = data_len + proto_ies.pos + 1;
+	buffer_copy(&resp_buf, &data_len, 1);
+
+	resp_buf.buf[resp_buf.pos++] = 0;/*quest: packed value should be 2 bytes...
+									   here it needs 3 bytes*/
+	buffer_copy(&resp_buf, tmp_str, 2);
+
+	buffer_copy(&resp_buf, &proto_ies, proto_ies.pos);
+	*s1_setup_resp = resp_buf.buf;
+
+	return resp_buf.pos;
+}
+
+int
+s1_setup_handler(InitiatingMessage_t *msg, int enb_fd)
+{
+	unsigned char *resp_msg = NULL;
+	int resp_len = 0;
+	/*struct proto_IE s1_init_ies;
+
+	/*****Message structure***
+	*/
+	/*parse_IEs(msg+2, &s1_init_ies, S1AP_SETUP_REQUEST_CODE);
+
+	/*Validate all eNB info*/
+
+	/*Add eNB info to hash*/
+
+	/*Create S1Setup response*/
+	resp_len = create_s1setup_response(/*enb info,*/ &resp_msg);
+
+	/*Send S1Setup response*/
+	log_msg(LOG_INFO, "Send s1setup response.\n");
+	resp_len = send_sctp_msg(enb_fd, resp_msg, resp_len, 0);
+	log_msg(LOG_INFO, "send len %d\n", resp_len);
+	//free(resp_msg);
+
+	return SUCCESS;
+}
+
diff --git a/src/s1ap/handlers/service_req.c b/src/s1ap/handlers/service_req.c
new file mode 100644
index 0000000..eff8140
--- /dev/null
+++ b/src/s1ap/handlers/service_req.c
@@ -0,0 +1,123 @@
+/*
+ * 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 "err_codes.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 "msgType.h"
+
+extern int g_enb_fd;
+extern s1ap_config g_s1ap_cfg;
+extern ipc_handle ipc_S1ap_Hndl;
+
+int
+s1_init_ue_service_req_handler(struct proto_IE *service_req_ies, int enb_fd)
+{
+	struct  s1_incoming_msg_data_t req= {0};
+
+	/*****Message structure***
+	*/
+	log_msg(LOG_INFO, "Parse s1ap Service request message\n");
+
+	/*Validate all eNB info*/
+
+	/*Add eNB info to hash*/
+
+	/*Create Q structure for Service req to MME.
+	  contains init UE information.*/
+	/* TODO : Revisit, in InitialContextSetup Request we are sending
+	 * MME UE S1AP Id as M-TMSI.
+	 */
+    req.msg_type = service_request;
+    req.msg_data.service_req_Q_msg_m.enb_fd = enb_fd;
+    for(int i = 0; i < service_req_ies->no_of_IEs; i++)
+    {
+        switch(service_req_ies->data[i].IE_type)
+        {
+            case S1AP_IE_ENB_UE_ID:
+                {
+                    log_msg(LOG_INFO, "Service Req S1AP_IE_ENB_UE_ID.\n");
+                    req.s1ap_enb_ue_id = service_req_ies->data[i].val.enb_ue_s1ap_id;
+                }break;
+            case S1AP_IE_NAS_PDU:
+                {
+                    log_msg(LOG_INFO, "Service Req NAS PDU.\n");
+                    req.msg_data.service_req_Q_msg_m.ksi = service_req_ies->data[i].val.nas.header.ksi;;
+                    req.msg_data.service_req_Q_msg_m.seq_no = service_req_ies->data[i].val.nas.header.seq_no;
+                    memcpy(&req.msg_data.service_req_Q_msg_m.mac, service_req_ies->data[i].val.nas.header.short_mac, sizeof(uint16_t));
+                }break;
+            case S1AP_IE_TAI:
+                {
+                    log_msg(LOG_INFO, "Service Req TAI.\n");
+                    memcpy(&req.msg_data.service_req_Q_msg_m.tai, 
+                        &service_req_ies->data[i].val.tai, 
+                        sizeof(struct TAI));
+                }break;
+            case S1AP_IE_UTRAN_CGI:
+                {
+                    log_msg(LOG_INFO, "Service Req CGI.\n");
+                    memcpy(&req.msg_data.service_req_Q_msg_m.utran_cgi, 
+                        &service_req_ies->data[i].val.utran_cgi, 
+                        sizeof(struct CGI));
+                }break;
+            case S1AP_IE_S_TMSI:
+                {
+                    log_msg(LOG_INFO, "Service Req STMSI.\n");
+                    if(service_req_ies->data[i].val.s_tmsi.mme_code 
+                       == g_s1ap_cfg.mme_code)
+                    {
+                        log_msg(LOG_INFO, "Service Req MME Code matched.\n");
+                        req.ue_idx = ntohl(service_req_ies->data[i].val.s_tmsi.m_TMSI);
+                        memcpy(&req.msg_data.service_req_Q_msg_m.s_tmsi, 
+                        &service_req_ies->data[i].val.s_tmsi,
+                         sizeof(struct STMSI));
+                    }
+                    else
+                    {
+                        log_msg(LOG_ERROR, "MME code mismatch. Send Service Reject. TBD");
+                        return -E_FAIL;
+                    }
+                }break;
+            default:
+                log_msg(LOG_WARNING,"Unhandled IE");
+        }
+    }
+
+	req.destInstAddr = htonl(mmeAppInstanceNum_c);
+        req.srcInstAddr = htonl(s1apAppInstanceNum_c);
+        send_tipc_message(ipc_S1ap_Hndl, mmeAppInstanceNum_c, (char *)&req, S1_READ_MSG_BUF_SIZE);
+
+	
+	/*Send Service req to mme-app*/
+	log_msg(LOG_INFO, "Send to mme-app service req handler.\n");
+
+	return SUCCESS;
+}
+
+
diff --git a/src/s1ap/handlers/uectxtrelease_cmd.c b/src/s1ap/handlers/uectxtrelease_cmd.c
new file mode 100644
index 0000000..3e93a36
--- /dev/null
+++ b/src/s1ap/handlers/uectxtrelease_cmd.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2019, Infosys Ltd.
+ *
+ * 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 <pthread.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdint.h>
+#include "common_proc_info.h"
+#include "log.h"
+#include "err_codes.h"
+#include "message_queues.h"
+#include "ipc_api.h"
+#include "s1ap.h"
+#include "s1ap_config.h"
+#include "main.h"
+#include "msgType.h"
+
+
+/*static int
+get_uectxtrelcmd_protoie_value(struct proto_IE *value, struct s1relcmd_info *g_uectxtrelcmd)
+{
+	//uint8_t ieCnt = 0;
+
+	value->no_of_IEs = UE_CTX_RELEASE_NO_OF_IES;
+
+	value->data = (proto_IEs *) malloc(UE_CTX_RELEASE_NO_OF_IES *
+			sizeof(proto_IEs));
+
+	value->data[0].mme_ue_s1ap_id = g_uectxtrelcmd->ue_idx;
+	
+	value->data[1].enb_ue_s1ap_id = g_uectxtrelcmd->enb_s1ap_ue_id;
+	
+	log_msg(LOG_INFO, "mme_ue_s1ap_id %d and enb_ue_s1ap_id %d\n",
+					g_uectxtrelcmd->ue_idx,g_uectxtrelcmd->enb_s1ap_ue_id);
+	return SUCCESS;
+}*/
+
+/**
+* Stage specific message processing.
+*/
+static int
+relcmd_processing(struct s1relcmd_info *g_uectxtrelcmd)
+{
+	log_msg(LOG_DEBUG,"Process Ctx rel cmd.");
+	uint32_t length = 0;
+    	uint8_t *buffer = NULL;
+	
+	Buffer g_ctxrel_buffer;
+	struct s1ap_common_req_Q_msg req= {0};
+	
+        log_msg(LOG_DEBUG,"Inside relcmd processing\n");	
+
+    	req.IE_type = S1AP_CTX_REL_CMD;
+    	req.enb_fd = g_uectxtrelcmd->enb_fd;
+    	req.mme_s1ap_ue_id = g_uectxtrelcmd->ue_idx;
+	req.enb_s1ap_ue_id = g_uectxtrelcmd->enb_s1ap_ue_id;
+	req.cause.present = g_uectxtrelcmd->cause.present;
+    	req.cause.choice.radioNetwork = g_uectxtrelcmd->cause.choice.radioNetwork; 	
+	
+	log_msg(LOG_DEBUG,"Before s1ap_encoder\n");
+
+	int ret = s1ap_mme_encode_initiating(&req, &buffer, &length);
+	log_msg(LOG_DEBUG,"Invoked s1ap_encoder\n");
+    	if(ret == -1)
+    	{
+        	log_msg(LOG_ERROR, "Encoding ctx rel cmd failed.\n");
+        	return E_FAIL;
+    	}
+
+	buffer_copy(&g_ctxrel_buffer, buffer, length);
+	send_sctp_msg(g_uectxtrelcmd->enb_fd, g_ctxrel_buffer.buf, g_ctxrel_buffer.pos,1);
+	log_msg(LOG_INFO, "\n-----S1 Release Command sent to UE.---\n");
+	return SUCCESS;
+	
+}
+
+
+/**
+* Thread function for stage.
+*/
+void*
+s1_release_command_handler(void *data)
+{
+
+	log_msg(LOG_INFO, "s1 release command handler ready.\n");
+	
+	relcmd_processing((struct s1relcmd_info *)data);
+
+	return NULL;
+}
+
+