MME2 changes - Propped commits from openmme/paging branch. Added scripts
for code gen
Change-Id: Ie55032217232214ac8544ca76ea34335205329e4
diff --git a/src/s1ap/handlers/s1ap_msg_delegator.c 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;
+}
+