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;
+}
+
+