/*
 * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The OpenAirInterface Software Alliance licenses this file to You under
 * the OAI Public License, Version 1.1  (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.openairinterface.org/?page_id=698
 *
 * 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.
 *-------------------------------------------------------------------------------
 * For more information about the OpenAirInterface (OAI) Software Alliance:
 *      contact@openairinterface.org
 */

/*! \file m3ap_MME_interface_management.c
 * \brief m3ap interface management for MME
 * \author Javier Morgade
 * \date 2019
 * \version 0.1
 * \company Vicomtech
 * \email: javier.morgade@ieee.org
 * \note
 * \warning
 */

#include "m3ap_common.h"
#include "m3ap_encoder.h"
#include "m3ap_decoder.h"
#include "m3ap_itti_messaging.h"
#include "m3ap_MME_interface_management.h"

#include "conversions.h"

#include "M3AP_ECGI.h"

extern m3ap_setup_req_t *m3ap_mme_data_from_mce;



uint8_t m3ap_start_message[] = {
  0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x07, 0x00,
  0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00,
  0x07, 0x00, 0x55, 0xf5, 0x01, 0x00, 0x00, 0x01,
  0x00, 0x04, 0x00, 0x0d, 0x60, 0x01, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x40, 0x01,
  0x7a, 0x00, 0x05, 0x00, 0x03, 0x07, 0x08, 0x00,
  0x00, 0x06, 0x00, 0x04, 0x03, 0x00, 0x00, 0x00,
  0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x07, 0x00,
  0x0e, 0x00, 0xe8, 0x0a, 0x0a, 0x0a, 0x00, 0x0a,
  0xc8, 0x0a, 0xfe, 0x00, 0x00, 0x00, 0x01
};


/*
 * MBMS Session start
 */
int MME_send_MBMS_SESSION_START_REQUEST(instance_t instance/*, uint32_t assoc_id*/,m3ap_session_start_req_t* m3ap_session_start_req){

  //AssertFatal(1==0,"Not implemented yet\n");
    
  //module_id_t enb_mod_idP=0;
  //module_id_t du_mod_idP=0;

  M3AP_M3AP_PDU_t          pdu; 
  M3AP_MBMSSessionStartRequest_t       *out;
  M3AP_MBMSSessionStartRequest_IEs_t   *ie;

  uint8_t *buffer;
  uint32_t len;
  //int	   i=0; 
  //int 	   j=0;

  /* Create */
  /* 0. pdu Type */
  memset(&pdu, 0, sizeof(pdu));
  pdu.present = M3AP_M3AP_PDU_PR_initiatingMessage;
  //pdu.choice.initiatingMessage = (M3AP_InitiatingMessage_t *)calloc(1, sizeof(M3AP_InitiatingMessage_t));
  pdu.choice.initiatingMessage.procedureCode = M3AP_ProcedureCode_id_mBMSsessionStart;
  pdu.choice.initiatingMessage.criticality   = M3AP_Criticality_reject;
  pdu.choice.initiatingMessage.value.present = M3AP_InitiatingMessage__value_PR_MBMSSessionStartRequest;
  out = &pdu.choice.initiatingMessage.value.choice.MBMSSessionStartRequest; 

  /* mandatory */
  /* c1. MME_MBMS_M3AP_ID (integer value) */ //long
  ie = (M3AP_MBMSSessionStartRequest_IEs_t *)calloc(1, sizeof(M3AP_MBMSSessionStartRequest_IEs_t));
  ie->id                        = M3AP_ProtocolIE_ID_id_MME_MBMS_M3AP_ID;
  ie->criticality               = M3AP_Criticality_reject;
  ie->value.present             = M3AP_MBMSSessionStartRequest_IEs__value_PR_MME_MBMS_M3AP_ID;
  //ie->value.choice.MME_MBMS_M3AP_ID = /*F1AP_get_next_transaction_identifier(enb_mod_idP, du_mod_idP);*/ //?
  ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);

  /* mandatory */
  /* c2. TMGI */ 
  ie = (M3AP_MBMSSessionStartRequest_IEs_t *)calloc(1, sizeof(M3AP_MBMSSessionStartRequest_IEs_t));
  ie->id                        = M3AP_ProtocolIE_ID_id_TMGI; 
  ie->criticality               = M3AP_Criticality_reject;
  ie->value.present             = M3AP_MBMSSessionStartRequest_IEs__value_PR_TMGI;
  M3AP_TMGI_t	*tmgi 		= &ie->value.choice.TMGI;
  {
	  MCC_MNC_TO_PLMNID(0,0,3,&tmgi->pLMNidentity);
	  uint8_t TMGI[5] = {4,3,2,1,0};
	  OCTET_STRING_fromBuf(&tmgi->serviceID,(const char*)&TMGI[2],3);
  }
  ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
  /* optional */
  /* c2. MBMS_Session_ID */
  if(0){
	  ie = (M3AP_MBMSSessionStartRequest_IEs_t *)calloc(1, sizeof(M3AP_MBMSSessionStartRequest_IEs_t));
	  ie->id                        = M3AP_ProtocolIE_ID_id_MBMS_Session_ID;
	  ie->criticality               = M3AP_Criticality_ignore;
	  ie->value.present             = M3AP_MBMSSessionStartRequest_IEs__value_PR_MBMS_Session_ID;
	  //M3AP_MBMS_Session_ID_t * mbms_session_id = &ie->value.choice.MBMS_Session_ID;

	  ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
  }
  /* mandatory */
  /* c2. MBMS_E_RAB_QoS_Parameters */ 
  ie = (M3AP_MBMSSessionStartRequest_IEs_t *)calloc(1, sizeof(M3AP_MBMSSessionStartRequest_IEs_t));
  ie->id                        = M3AP_ProtocolIE_ID_id_MBMS_E_RAB_QoS_Parameters; 
  ie->criticality               = M3AP_Criticality_reject;
  ie->value.present             = M3AP_MBMSSessionStartRequest_IEs__value_PR_MBMS_E_RAB_QoS_Parameters;
  M3AP_MBMS_E_RAB_QoS_Parameters_t * mbms_e_rab_qos_parameters = &ie->value.choice.MBMS_E_RAB_QoS_Parameters;
  {
	//M3AP_QCI_t * qci = &mbms_e_rab_qos_parameters->qCI; //long
	mbms_e_rab_qos_parameters->qCI = 1;
	//struct M3AP_GBR_QosInformation  *gbrQosInformation;     /* OPTIONAL */
  }

  ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
  /* mandatory */
  /* c2. MBMS_Session_Duration */ 
  ie = (M3AP_MBMSSessionStartRequest_IEs_t *)calloc(1, sizeof(M3AP_MBMSSessionStartRequest_IEs_t));
  ie->id                        = M3AP_ProtocolIE_ID_id_MBMS_Session_Duration; 
  ie->criticality               = M3AP_Criticality_reject;
  ie->value.present             = M3AP_MBMSSessionStartRequest_IEs__value_PR_MBMS_Session_Duration; 
  M3AP_MBMS_Session_Duration_t * mbms_session_duration = &ie->value.choice.MBMS_Session_Duration;
  {
	uint8_t duration[5] = {4,3,2,1,0};
	OCTET_STRING_fromBuf(mbms_session_duration,(const char*)&duration[2],3);
  }
  ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
  /* mandatory */
  /* c2 MBMS_Service_Area */
  ie = (M3AP_MBMSSessionStartRequest_IEs_t *)calloc(1, sizeof(M3AP_MBMSSessionStartRequest_IEs_t));
  ie->id                        = M3AP_ProtocolIE_ID_id_MBMS_Service_Area;
  ie->criticality               = M3AP_Criticality_ignore;
  ie->value.present             = M3AP_MBMSSessionStartRequest_IEs__value_PR_MBMS_Service_Area;
  M3AP_MBMS_Service_Area_t * mbms_service_area = &ie->value.choice.MBMS_Service_Area;
  {
	uint8_t duration[5] = {4,3,2,1,0};
	OCTET_STRING_fromBuf(mbms_service_area,(const char*)&duration[2],1);
  }
  ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
  /* mandatory */
  /* c2 MinimumTimeToMBMSDataTransfer */
  ie = (M3AP_MBMSSessionStartRequest_IEs_t *)calloc(1, sizeof(M3AP_MBMSSessionStartRequest_IEs_t));
  ie->id                        = M3AP_ProtocolIE_ID_id_MinimumTimeToMBMSDataTransfer; 
  ie->criticality               = M3AP_Criticality_reject;
  ie->value.present             = M3AP_MBMSSessionStartRequest_IEs__value_PR_MinimumTimeToMBMSDataTransfer; 
  M3AP_MinimumTimeToMBMSDataTransfer_t * minimumtimetombmsdatatransfer = &ie->value.choice.MinimumTimeToMBMSDataTransfer;
  {
	uint8_t duration[5] = {4,3,2,1,0};
	OCTET_STRING_fromBuf(minimumtimetombmsdatatransfer,(const char*)&duration[2],1);
  }

  ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
  /* mandatory */
  /* c2 TNL_Information */
  ie = (M3AP_MBMSSessionStartRequest_IEs_t *)calloc(1, sizeof(M3AP_MBMSSessionStartRequest_IEs_t));
  ie->id                        = M3AP_ProtocolIE_ID_id_TNL_Information; 
  ie->criticality               = M3AP_Criticality_ignore;
  ie->value.present             = M3AP_MBMSSessionStartRequest_IEs__value_PR_TNL_Information; 
  M3AP_TNL_Information_t * tnl_information = &ie->value.choice.TNL_Information;
  {
        //OCTET_STRING_fromBuf(&tnl_information->iPMCAddress,"1204",strlen("1234"));
        //OCTET_STRING_fromBuf(&tnl_information->iPSourceAddress,"1204",strlen("1234"));
        //OCTET_STRING_fromBuf(&tnl_information->gTP_DLTEID,"1204",strlen("1234"));
	uint32_t gtp_dlteid = 1;
	GTP_TEID_TO_ASN1(gtp_dlteid,&tnl_information->gTP_DLTEID);
	//tnl_information->iPMCAddress.buf = calloc(4,sizeof(uint8_t));
	//tnl_information->iPMCAddress.buf[0]
	//tnl_information->iPMCAddress.buf[1]
	//tnl_information->iPMCAddress.buf[2]
	//tnl_information->iPMCAddress.buf[3]
	//tnl_information->iPMCAddress.buf.size = 4;
	uint32_t ip= (224<<24) | (0) << 16 | (0) << 8 | (2);
	INT32_TO_OCTET_STRING(ip,&tnl_information->iPMCAddress);
	ip= (224<<24) | (0) << 16 | (0) << 8 | (2);
	INT32_TO_OCTET_STRING(ip,&tnl_information->iPSourceAddress);
  }
  ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
  /* optional */
  /* c2 Time_ofMBMS_DataTransfer */
  if(0){
	  ie = (M3AP_MBMSSessionStartRequest_IEs_t *)calloc(1, sizeof(M3AP_MBMSSessionStartRequest_IEs_t));
	  ie->id                        = M3AP_ProtocolIE_ID_id_Time_ofMBMS_DataTransfer; 
	  ie->criticality               = M3AP_Criticality_ignore;
	  ie->value.present             = M3AP_MBMSSessionStartRequest_IEs__value_PR_Absolute_Time_ofMBMS_Data; 
	  //M3AP_Absolute_Time_ofMBMS_Data_t * absolute_time_ofmbms_data	= &ie->value.choice.Absolute_Time_ofMBMS_Data;
	  //{
		//char duration[5] = {4,3,2,1,0};
		//OCTET_STRING_fromBuf(absolute_time_ofmbms_data,(const char*)&duration[2],3);
	  //}
	  ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
  }
  /* optional */
  /* c2 MBMS_Cell_List */
  if(0){
	  ie = (M3AP_MBMSSessionStartRequest_IEs_t *)calloc(1, sizeof(M3AP_MBMSSessionStartRequest_IEs_t));
	  ie->id                        = M3AP_ProtocolIE_ID_id_MBMS_Cell_List; 
	  ie->criticality               = M3AP_Criticality_ignore;
	  ie->value.present             = M3AP_MBMSSessionStartRequest_IEs__value_PR_MBMS_Cell_List; 
	  M3AP_MBMS_Cell_List_t * mbms_cell_list = &ie->value.choice.MBMS_Cell_List;
	  M3AP_ECGI_t * ecgi = (M3AP_ECGI_t*)calloc(1,sizeof(M3AP_ECGI_t));	
	  {
		//MCC_MNC_TO_PLMNID(0,0,3,ecgi->pLMN_Identity);
		//MACRO_ENB_ID_TO_CELL_IDENTITY(1,0,ecgi->eUTRANcellIdentifier);
		ASN_SEQUENCE_ADD(&mbms_cell_list->list,ecgi);
	  }
	  ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
  }

  /* encode */
  if (m3ap_encode_pdu(&pdu,&buffer,&len) < 0){
        return -1;
  }

  
//  buffer = &m3ap_start_message[0];
//  len=8*9+7;
//
  m3ap_MME_itti_send_sctp_data_req(instance, m3ap_mme_data_from_mce->assoc_id, buffer, len, 0);
  
  return 0;

}

int MME_handle_MBMS_SESSION_START_RESPONSE(instance_t instance,
                                uint32_t assoc_id,
                                uint32_t stream,
                                M3AP_M3AP_PDU_t *pdu){
//  AssertFatal(1==0,"Not implemented yet\n");
  LOG_D(M3AP, "MME_handle_MBMS_SESSION_START_RESPONSE\n");

   AssertFatal(pdu->present == M3AP_M3AP_PDU_PR_successfulOutcome,
               "pdu->present != M3AP_M3AP_PDU_PR_successfulOutcome\n");
   AssertFatal(pdu->choice.successfulOutcome.procedureCode  == M3AP_ProcedureCode_id_mBMSsessionStart,
               "pdu->choice.successfulOutcome->procedureCode != M3AP_ProcedureCode_id_sessionStart\n");
   AssertFatal(pdu->choice.successfulOutcome.criticality  == M3AP_Criticality_reject,
               "pdu->choice.successfulOutcome->criticality != M3AP_Criticality_reject\n");
   AssertFatal(pdu->choice.successfulOutcome.value.present  == M3AP_SuccessfulOutcome__value_PR_MBMSSessionStartResponse,
               "pdu->choice.successfulOutcome.value.present != M3AP_SuccessfulOutcome__value_PR_MBMSSessionStartResponse\n");


  M3AP_MBMSSessionStartResponse_t    *in = &pdu->choice.successfulOutcome.value.choice.MBMSSessionStartResponse;
  M3AP_MBMSSessionStartResponse_IEs_t  *ie;
  int MME_MBMS_M3AP_ID=-1;
  int MCE_MBMS_M3AP_ID=-1;


  MessageDef *msg_g = itti_alloc_new_message(TASK_M3AP_MME, 0,M3AP_MBMS_SESSION_START_RESP); //TODO

  LOG_D(M3AP, "M3AP: SessionStart-Resp: protocolIEs.list.count %d\n",
         in->protocolIEs.list.count);
  for (int i=0;i < in->protocolIEs.list.count; i++) {
     ie = in->protocolIEs.list.array[i];
     switch (ie->id) {
     case M3AP_ProtocolIE_ID_id_MME_MBMS_M3AP_ID:
       AssertFatal(ie->criticality == M3AP_Criticality_reject,
                   "ie->criticality != M3AP_Criticality_reject\n");
       AssertFatal(ie->value.present == M3AP_MBMSSessionStartResponse_IEs__value_PR_MME_MBMS_M3AP_ID,
                   "ie->value.present != M3AP_sessionStartResponse_IEs__value_PR_MME_MBMS_M3AP_ID\n");
       MME_MBMS_M3AP_ID=ie->value.choice.MME_MBMS_M3AP_ID;
       LOG_D(M3AP, "M3AP: SessionStart-Resp: MME_MBMS_M3AP_ID %d\n",
             MME_MBMS_M3AP_ID);
       break;
      case M3AP_ProtocolIE_ID_id_MCE_MBMS_M3AP_ID:
       AssertFatal(ie->criticality == M3AP_Criticality_reject,
                   "ie->criticality != M3AP_Criticality_reject\n");
       AssertFatal(ie->value.present == M3AP_MBMSSessionStartResponse_IEs__value_PR_MCE_MBMS_M3AP_ID,
                   "ie->value.present != M3AP_sessionStartResponse_IEs__value_PR_MCE_MBMS_M3AP_ID\n");
       MCE_MBMS_M3AP_ID=ie->value.choice.MCE_MBMS_M3AP_ID;
       LOG_D(M3AP, "M3AP: SessionStart-Resp: MCE_MBMS_M3AP_ID %d\n",
             MCE_MBMS_M3AP_ID);
       break;
     }
  }

  //AssertFatal(MME_MBMS_M3AP_ID!=-1,"MME_MBMS_M3AP_ID was not sent\n");
  //AssertFatal(MCE_MBMS_M3AP_ID!=-1,"MCE_MBMS_M3AP_ID was not sent\n");
  ////M3AP_SESSION_START_RESP(msg_p).
////  MSC_LOG_RX_MESSAGE(
////    MSC_M3AP_MME,
////    MSC_M3AP_MCE,
  //      //return 0;
////    0,
////    0,
////    MSC_AS_TIME_FMT" MME_handle_M2_SESSION_START_RESPONSE successfulOutcome assoc_id %d",
////    0,0,//MSC_AS_TIME_ARGS(ctxt_pP),
////    assoc_id);
////
  // LOG_W(M3AP, "Sending M3AP_SESSION_START_RESP ITTI message to MCE_APP with assoc_id (%d->%d)\n",
  //       assoc_id,ENB_MODULE_ID_TO_INSTANCE(assoc_id));
  itti_send_msg_to_task(TASK_MME_APP, ENB_MODULE_ID_TO_INSTANCE(assoc_id), msg_g);
  return 0;

}
int MME_handle_MBMS_SESSION_START_FAILURE(instance_t instance,
                                uint32_t assoc_id,
                                uint32_t stream,
                                M3AP_M3AP_PDU_t *pdu){
  AssertFatal(1==0,"Not implemented yet\n");
}

/*
 * MBMS Session stop
 */
int MME_send_MBMS_SESSION_STOP_REQUEST(instance_t instance, m3ap_session_stop_req_t* m3ap_session_stop_req){

    
 // module_id_t enb_mod_idP=0;
 // module_id_t du_mod_idP=0;

  M3AP_M3AP_PDU_t          pdu; 
  M3AP_MBMSSessionStopRequest_t        *out;
  M3AP_MBMSSessionStopRequest_IEs_t    *ie;

  uint8_t *buffer;
  uint32_t len;
  //int	   i=0; 
  //int 	   j=0;

  /* Create */
  /* 0. pdu Type */
  memset(&pdu, 0, sizeof(pdu));
  pdu.present = M3AP_M3AP_PDU_PR_initiatingMessage;
  //pdu.choice.initiatingMessage = (M3AP_InitiatingMessage_t *)calloc(1, sizeof(M3AP_InitiatingMessage_t));
  pdu.choice.initiatingMessage.procedureCode = M3AP_ProcedureCode_id_mBMSsessionStop;
  pdu.choice.initiatingMessage.criticality   = M3AP_Criticality_reject;
  pdu.choice.initiatingMessage.value.present = M3AP_InitiatingMessage__value_PR_MBMSSessionStopRequest;
  out = &pdu.choice.initiatingMessage.value.choice.MBMSSessionStopRequest; 

  /* mandatory */
  /* c1. MME_MBMS_M3AP_ID (integer value) */ //long
  ie = (M3AP_MBMSSessionStopRequest_IEs_t *)calloc(1, sizeof(M3AP_MBMSSessionStopRequest_IEs_t));
  ie->id                        = M3AP_ProtocolIE_ID_id_MME_MBMS_M3AP_ID;
  ie->criticality               = M3AP_Criticality_reject;
  ie->value.present             = M3AP_MBMSSessionStopRequest_IEs__value_PR_MME_MBMS_M3AP_ID;
  //ie->value.choice.MME_MBMS_M3AP_ID = /*F1AP_get_next_transaction_identifier(enb_mod_idP, du_mod_idP);*/ //?
  ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);

  /* mandatory */
  /* c2. MCE_MBMS_M3AP_ID (integer value) */ //long
  ie = (M3AP_MBMSSessionStopRequest_IEs_t *)calloc(1, sizeof(M3AP_MBMSSessionStopRequest_IEs_t));
  ie->id                        = M3AP_ProtocolIE_ID_id_MCE_MBMS_M3AP_ID;
  ie->criticality               = M3AP_Criticality_reject;
  ie->value.present             = M3AP_MBMSSessionStopRequest_IEs__value_PR_MCE_MBMS_M3AP_ID;
  //ie->value.choice.MCE_MBMS_M3AP_ID = /*F1AP_get_next_transaction_identifier(enb_mod_idP, du_mod_idP);*/ //?

  ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);


  /* encode */
  if (m3ap_encode_pdu(&pdu,&buffer,&len) < 0){
        return -1;
  }

  //MME_m3ap_itti_send_sctp_data_req(instance, m3ap_mce_data_from_mce->assoid,buffer,len,0); 
  m3ap_MME_itti_send_sctp_data_req(instance, m3ap_mme_data_from_mce->assoc_id,buffer,len,0);
  return 0;


                        
}

int MME_handle_MBMS_SESSION_STOP_RESPONSE(instance_t instance,
                                uint32_t assoc_id,
                                uint32_t stream,
                                M3AP_M3AP_PDU_t *pdu){
  //AssertFatal(1==0,"Not implemented yet\n");
  LOG_D(M3AP, "eNB_handle_MBMS_SESSION_STOP_RESPONSE\n");

   AssertFatal(pdu->present == M3AP_M3AP_PDU_PR_successfulOutcome,
	       "pdu->present != M3AP_M3AP_PDU_PR_successfulOutcome\n");
   AssertFatal(pdu->choice.successfulOutcome.procedureCode  == M3AP_ProcedureCode_id_mBMSsessionStop,
	       "pdu->choice.successfulOutcome->procedureCode != M3AP_ProcedureCode_id_sessionStop\n");
   AssertFatal(pdu->choice.successfulOutcome.criticality  == M3AP_Criticality_reject,
	       "pdu->choice.successfulOutcome->criticality != M3AP_Criticality_reject\n");
   AssertFatal(pdu->choice.successfulOutcome.value.present  == M3AP_SuccessfulOutcome__value_PR_MBMSSessionStopResponse,
	       "pdu->choice.successfulOutcome->value.present != M3AP_SuccessfulOutcome__value_PR_MBMSSessionStopResponse\n");


  M3AP_MBMSSessionStopResponse_t    *in = &pdu->choice.successfulOutcome.value.choice.MBMSSessionStopResponse;
  M3AP_MBMSSessionStopResponse_IEs_t  *ie;
  int MME_MBMS_M3AP_ID=-1;
  int MCE_MBMS_M3AP_ID=-1;


  MessageDef *msg_g = itti_alloc_new_message(TASK_M3AP_MME, 0,M3AP_MBMS_SESSION_STOP_RESP); //TODO

  LOG_D(M3AP, "M3AP: MBMSSessionStop-Resp: protocolIEs.list.count %d\n",
         in->protocolIEs.list.count);
  for (int i=0;i < in->protocolIEs.list.count; i++) {
     ie = in->protocolIEs.list.array[i];
     switch (ie->id) {
     case M3AP_ProtocolIE_ID_id_MME_MBMS_M3AP_ID:
       AssertFatal(ie->criticality == M3AP_Criticality_reject,
                   "ie->criticality != M3AP_Criticality_reject\n");
       AssertFatal(ie->value.present == M3AP_MBMSSessionStopResponse_IEs__value_PR_MME_MBMS_M3AP_ID,
                   "ie->value.present != M3AP_MBMSStopResponse_IEs__value_PR_MME_MBMS_M3AP_ID\n");
       MME_MBMS_M3AP_ID=ie->value.choice.MME_MBMS_M3AP_ID;
       LOG_D(M3AP, "M3AP: MBMSSessionStop-Resp: MME_MBMS_M3AP_ID %d\n",
             MME_MBMS_M3AP_ID);
       break;
      case M3AP_ProtocolIE_ID_id_MCE_MBMS_M3AP_ID:
       AssertFatal(ie->criticality == M3AP_Criticality_reject,
                   "ie->criticality != M3AP_Criticality_reject\n");
       AssertFatal(ie->value.present == M3AP_MBMSSessionStopResponse_IEs__value_PR_MCE_MBMS_M3AP_ID,
                   "ie->value.present != M3AP_MBMSStopResponse_IEs__value_PR_MCE_MBMS_M3AP_ID\n");
       MCE_MBMS_M3AP_ID=ie->value.choice.MCE_MBMS_M3AP_ID;
       LOG_D(M3AP, "M3AP: MBMSSessionStop-Resp: MCE_MBMS_M3AP_ID %d\n",
             MCE_MBMS_M3AP_ID);
       break;
     }
  }

  //AssertFatal(MME_MBMS_M3AP_ID!=-1,"MME_MBMS_M3AP_ID was not sent\n");
  //AssertFatal(MCE_MBMS_M3AP_ID!=-1,"MCE_MBMS_M3AP_ID was not sent\n");
 // M3AP_SESSION_STOP_RESP(msg_p).
 // MSC_LOG_RX_MESSAGE(
 //   MSC_M3AP_MME,
 //   MSC_M3AP_MCE,
 //   0,
 //   0,
 //   MSC_AS_TIME_FMT" MME_handle_M2_SESSION_STOP_RESPONSE successfulOutcome assoc_id %d",
 //   0,0,//MSC_AS_TIME_ARGS(ctxt_pP),
 //   assoc_id);

 //  LOG_D(M3AP, "Sending M3AP_SESSION_START_RESP ITTI message to MCE_APP with assoc_id (%d->%d)\n",
 //        assoc_id,MCE_MODULE_ID_TO_INSTANCE(assoc_id));
   itti_send_msg_to_task(TASK_MME_APP, ENB_MODULE_ID_TO_INSTANCE(assoc_id), msg_g);
// //                      
	return 0;
}



int MME_handle_MBMS_SESSION_STOP_FAILURE(instance_t instance,
                                uint32_t assoc_id,
                                uint32_t stream,
                                M3AP_M3AP_PDU_t *pdu){
  AssertFatal(1==0,"Not implemented yet\n");
                      
}





/*
 * Reset
 */

int MME_send_RESET(instance_t instance, m3ap_reset_t * m3ap_reset) {
  AssertFatal(1==0,"Not implemented yet\n");
  //M3AP_Reset_t     Reset;
                        
}


int MME_handle_RESET_ACKKNOWLEDGE(instance_t instance,
                                  uint32_t assoc_id,
                                  uint32_t stream,
                                  M3AP_M3AP_PDU_t *pdu) {
  AssertFatal(1==0,"Not implemented yet\n");

}

int MME_handle_RESET(instance_t instance,
                     uint32_t assoc_id,
                     uint32_t stream,
                     M3AP_M3AP_PDU_t *pdu) {
  AssertFatal(1==0,"Not implemented yet\n");
}

int MME_send_RESET_ACKNOWLEDGE(instance_t instance, M3AP_ResetAcknowledge_t *ResetAcknowledge) {
  AssertFatal(1==0,"Not implemented yet\n");
}

/*
 *    M3 Setup
 */
int MME_handle_M3_SETUP_REQUEST(instance_t instance,
                               uint32_t assoc_id,
                               uint32_t stream,
                               M3AP_M3AP_PDU_t *pdu)
{
  LOG_D(M2AP, "MCE_handle_M3_SETUP_REQUEST assoc_id %d\n",assoc_id);

  //AssertFatal(1==0,"Not implemented yet\n");
//  LOG_W(M3AP, "MME_handle_M3_SETUP_REQUEST assoc_id %d\n",assoc_id);
//
    MessageDef                         *message_p;
//  M3AP_M3SetupRequest_t              *container;
//  M3AP_M3SetupRequestIEs_t           *ie;
//  int i = 0,j=0;
//
//  DevAssert(pdu != NULL);
//
//  container = &pdu->choice.initiatingMessage.value.choice.M3SetupRequest;
//
//  /* M3 Setup Request == Non UE-related procedure -> stream 0 */
//  if (stream != 0) {
//    LOG_W(M3AP, "[SCTP %d] Received m3 setup request on stream != 0 (%d)\n",
//              assoc_id, stream);
//  }
//
    message_p = itti_alloc_new_message(TASK_M3AP_MME, 0, M3AP_SETUP_REQ); 
    //printf("M3AP_SETUP_REQ(message_p).assoc_id %d\n",M3AP_SETUP_REQ(message_p).assoc_id);
//  
//  /* assoc_id */
    M3AP_SETUP_REQ(message_p).assoc_id = assoc_id;
//
// /* GlobalMCE_id */
// // this function exits if the ie is mandatory
//  M3AP_FIND_PROTOCOLIE_BY_ID(M3AP_M3SetupRequestIEs_t, ie, container,
//                             M3AP_ProtocolIE_ID_id_Global_MCE_ID, true);
//  asn_INTEGER2ulong(&ie->value.choice.GlobalMCE_ID, &M3AP_SETUP_REQ(message_p).GlobalMCE_ID);
//  LOG_W(M3AP, "M3AP_SETUP_REQ(message_p).GlobalMCE_ID %lu \n", M3AP_SETUP_REQ(message_p).GlobalMCE_ID);
//
//  /* MCE_name */
//  M3AP_FIND_PROTOCOLIE_BY_ID(M3AP_M3SetupRequestIEs_t, ie, container,
//                              M3AP_ProtocolIE_ID_id_MCEname, true);
//  M3AP_SETUP_REQ(message_p).MCEname = calloc(ie->value.choice.MCEname.size + 1, sizeof(char));
//  memcpy(M3AP_SETUP_REQ(message_p).MCEname, ie->value.choice.MCEname.buf,
//         ie->value.choice.MCEname.size);
//
//  /* Convert the mme name to a printable string */
//  M3AP_SETUP_REQ(message_p).MCEname[ie->value.choice.MCEname.size] = '\0';
//  LOG_W(M3AP, "M3AP_SETUP_REQ(message_p).gNB_DU_name %s \n", M3AP_SETUP_REQ(message_p).MCEname);
//   /* MCE_MBMS_Configuration_data_List */
//  M3AP_FIND_PROTOCOLIE_BY_ID(M3AP_M3SetupRequestIEs_t, ie, container,
//                              M3AP_ProtocolIE_ID_id_MCE_MBMS_Configuration_data_List, true);
//  M3AP_SETUP_REQ(message_p).num_mbms_available = ie->value.choice.MCE_MBMS_Configuration_data_List.list.count;
//  LOG_W(M3AP, "M3AP_SETUP_REQ(message_p).num_mbms_available %d \n",
//        M3AP_SETUP_REQ(message_p).num_mbms_available);
//  int num_mbms_available = M3AP_SETUP_REQ(message_p).num_mbms_available;
//  for (i=0; i<num_mbms_available; i++) {
//	 M3AP_MCE_MBMS_Configuration_data_Item_t *mbms_configuration_item_p;
//         mbms_configuration_item_p = &(((M3AP_MCE_MBMS_Configuration_data_ItemIEs_t *)ie->value.choice.MCE_MBMS_Configuration_data_List.list.array[i])->value.choice.MCE_MBMS_Configuration_data_Item);
//    /* eCGI */
//       //mbms_configuration_item_p->eCGI ... (M3AP_ECGI_t)
//
//    OCTET_STRING_TO_INT16(&(mbms_configuration_item_p->eCGI.pLMN_Identity),M3AP_SETUP_REQ(message_p).plmn_identity[i]);
//    //OCTET_STRING_TO_INT16(&(mbms_configuration_item_p->eCGI.eUTRANcellIdentifier),M3AP_SETUP_REQ(message_p).eutran_cell_identifier[i]);
//    /* mbsfnSynchronisationArea */
//       //mbms_configuration_item_p->mbsfnSynchronisationArea ... (M3AP_MBSFN_SynchronisationArea_ID_t)
//
//    M3AP_SETUP_REQ(message_p).mbsfn_synchronization_area[i]=mbms_configuration_item_p->mbsfnSynchronisationArea;
//    /* mbmsServiceAreaList */
//       //mbms_configuration_item_p->mbmsServiceAreaList ... (M3AP_MBMS_Service_Area_ID_List_t)
//   for(j=0;j<1;j++){
//   	//OCTET_STRING_TO_INT16(&(mbms_configuration_item_p->mbmsServiceAreaList.list.array[j]), M3AP_SETUP_REQ(message_p).service_area_id[i][j]);
//   }
//
// }
//    
////    /* tac */
////    OCTET_STRING_TO_INT16(&(served_celles_item_p->served_Cell_Information.fiveGS_TAC), M3AP_SETUP_REQ(message_p).tac[i]);
////    LOG_D(M3AP, "M3AP_SETUP_REQ(message_p).tac[%d] %d \n",
////          i, M3AP_SETUP_REQ(message_p).tac[i]);
////
////    /* - nRCGI */
////    TBCD_TO_MCC_MNC(&(served_celles_item_p->served_Cell_Information.nRCGI.pLMN_Identity), M3AP_SETUP_REQ(message_p).mcc[i],
////                    M3AP_SETUP_REQ(message_p).mnc[i],
////                    M3AP_SETUP_REQ(message_p).mnc_digit_length[i]);
////    
////    
////    // NR cellID
////    BIT_STRING_TO_NR_CELL_IDENTITY(&served_celles_item_p->served_Cell_Information.nRCGI.nRCellIdentity,
////				   M3AP_SETUP_REQ(message_p).nr_cellid[i]);
////    LOG_D(M3AP, "[SCTP %d] Received nRCGI: MCC %d, MNC %d, CELL_ID %llu\n", assoc_id,
////          M3AP_SETUP_REQ(message_p).mcc[i],
////          M3AP_SETUP_REQ(message_p).mnc[i],
////          (long long unsigned int)M3AP_SETUP_REQ(message_p).nr_cellid[i]);
////    LOG_D(M3AP, "nr_cellId : %x %x %x %x %x\n",
////          served_celles_item_p->served_Cell_Information.nRCGI.nRCellIdentity.buf[0],
////          served_celles_item_p->served_Cell_Information.nRCGI.nRCellIdentity.buf[1],
////          served_celles_item_p->served_Cell_Information.nRCGI.nRCellIdentity.buf[2],
////          served_celles_item_p->served_Cell_Information.nRCGI.nRCellIdentity.buf[3],
////          served_celles_item_p->served_Cell_Information.nRCGI.nRCellIdentity.buf[4]);
////    /* - nRPCI */
////    M3AP_SETUP_REQ(message_p).nr_pci[i] = served_celles_item_p->served_Cell_Information.nRPCI;
////    LOG_D(M3AP, "M3AP_SETUP_REQ(message_p).nr_pci[%d] %d \n",
////          i, M3AP_SETUP_REQ(message_p).nr_pci[i]);
////  
////    // System Information
////    /* mib */
////    M3AP_SETUP_REQ(message_p).mib[i] = calloc(served_celles_item_p->gNB_DU_System_Information->mIB_message.size + 1, sizeof(char));
////    memcpy(M3AP_SETUP_REQ(message_p).mib[i], served_celles_item_p->gNB_DU_System_Information->mIB_message.buf,
////           served_celles_item_p->gNB_DU_System_Information->mIB_message.size);
////    /* Convert the mme name to a printable string */
////    M3AP_SETUP_REQ(message_p).mib[i][served_celles_item_p->gNB_DU_System_Information->mIB_message.size] = '\0';
////    M3AP_SETUP_REQ(message_p).mib_length[i] = served_celles_item_p->gNB_DU_System_Information->mIB_message.size;
////    LOG_D(M3AP, "M3AP_SETUP_REQ(message_p).mib[%d] %s , len = %d \n",
////          i, M3AP_SETUP_REQ(message_p).mib[i], M3AP_SETUP_REQ(message_p).mib_length[i]);
////
////    /* sib1 */
////    M3AP_SETUP_REQ(message_p).sib1[i] = calloc(served_celles_item_p->gNB_DU_System_Information->sIB1_message.size + 1, sizeof(char));
////    memcpy(M3AP_SETUP_REQ(message_p).sib1[i], served_celles_item_p->gNB_DU_System_Information->sIB1_message.buf,
////           served_celles_item_p->gNB_DU_System_Information->sIB1_message.size);
////    /* Convert the mme name to a printable string */
////    M3AP_SETUP_REQ(message_p).sib1[i][served_celles_item_p->gNB_DU_System_Information->sIB1_message.size] = '\0';
////    M3AP_SETUP_REQ(message_p).sib1_length[i] = served_celles_item_p->gNB_DU_System_Information->sIB1_message.size;
////    LOG_D(M3AP, "M3AP_SETUP_REQ(message_p).sib1[%d] %s , len = %d \n",
////          i, M3AP_SETUP_REQ(message_p).sib1[i], M3AP_SETUP_REQ(message_p).sib1_length[i]);
////  }
//
//
    //printf("m3ap_mme_data_from_mce->assoc_id %d %d\n",m3ap_mme_data_from_mce->assoc_id,assoc_id);
    *m3ap_mme_data_from_mce = M3AP_SETUP_REQ(message_p);
    //printf("m3ap_mme_data_from_mce->assoc_id %d %d\n",m3ap_mme_data_from_mce->assoc_id,assoc_id);
//
////  MSC_LOG_TX_MESSAGE(
////  MSC_M3AP_MME,
////  MSC_RRC_MCE,
////  0,
////  0,
////  MSC_AS_TIME_FMT" MME_handle_M3_SETUP_REQUEST",
////  0,0//MSC_AS_TIME_ARGS(ctxt_pP),
////  );
////
    itti_send_msg_to_task(TASK_MME_APP, ENB_MODULE_ID_TO_INSTANCE(instance), message_p);
//  if (num_mbms_available > 0) {
//    itti_send_msg_to_task(TASK_MME_APP, MCE_MODULE_ID_TO_INSTANCE(instance), message_p);
//  } else {
//       //MME_send_M3_SETUP_FAILURE(instance);
//       return -1;
//  }
////  return 0;
//    //TEST POINT MME -> eNB
//    if(1){
//	printf("instance %d\n",instance);
//	//MME_send_M3_SETUP_RESPONSE(instance,assoc_id,m3ap_mce_data_from_enb->assoc_id);
//	//MME_send_MBMS_SESSION_START_REQUEST(instance,assoc_id);
//	//MME_send_MBMS_SESSION_STOP_REQUEST(instance,assoc_id);
//	//MME_send_MBMS_SCHEDULING_INFORMATION(instance,assoc_id,NULL); //TODO
//    }
//    else 
//	MME_send_M3_SETUP_FAILURE(instance,assoc_id);
//
    return 0;
}

int MME_send_M3_SETUP_RESPONSE(instance_t instance, /*uint32_t assoc_id,*/
                               m3ap_setup_resp_t *m3ap_setup_resp) {
 M3AP_M3AP_PDU_t           pdu;
 M3AP_M3SetupResponse_t    *out;
 M3AP_M3SetupResponseIEs_t *ie;

 uint8_t  *buffer;
 uint32_t  len;
 //int       i = 0;

 /* Create */
 /* 0. Message Type */
 memset(&pdu, 0, sizeof(pdu));
 pdu.present = M3AP_M3AP_PDU_PR_successfulOutcome;
 //pdu.choice.successfulOutcome = (M3AP_SuccessfulOutcome_t *)calloc(1, sizeof(M3AP_SuccessfulOutcome_t));
 pdu.choice.successfulOutcome.procedureCode = M3AP_ProcedureCode_id_m3Setup;
 pdu.choice.successfulOutcome.criticality   = M3AP_Criticality_reject;
 pdu.choice.successfulOutcome.value.present = M3AP_SuccessfulOutcome__value_PR_M3SetupResponse;
 out = &pdu.choice.successfulOutcome.value.choice.M3SetupResponse;

 /* mandatory */
  /* c4. CriticalityDiagnostics*/
  if (0) {
    ie = (M3AP_M3SetupResponseIEs_t *)calloc(1, sizeof(M3AP_M3SetupResponseIEs_t));
    ie->id                        = M3AP_ProtocolIE_ID_id_CriticalityDiagnostics;
    ie->criticality               = M3AP_Criticality_ignore;
    ie->value.present             = M3AP_M3SetupFailureIEs__value_PR_CriticalityDiagnostics;
    ie->value.choice.CriticalityDiagnostics.procedureCode = (M3AP_ProcedureCode_t *)calloc(1, sizeof(M3AP_ProcedureCode_t));
    *ie->value.choice.CriticalityDiagnostics.procedureCode = M3AP_ProcedureCode_id_m3Setup;
    ie->value.choice.CriticalityDiagnostics.triggeringMessage = (M3AP_TriggeringMessage_t *)calloc(1, sizeof(M3AP_TriggeringMessage_t));
    *ie->value.choice.CriticalityDiagnostics.triggeringMessage = M3AP_TriggeringMessage_initiating_message;
    ie->value.choice.CriticalityDiagnostics.procedureCriticality = (M3AP_Criticality_t *)calloc(1, sizeof(M3AP_Criticality_t));
    *ie->value.choice.CriticalityDiagnostics.procedureCriticality = M3AP_Criticality_reject;
    //ie->value.choice.CriticalityDiagnostics.transactionID = (M2AP_TransactionID_t *)calloc(1, sizeof(M3AP_TransactionID_t));
    //*ie->value.choice.CriticalityDiagnostics.transactionID = 0;
    ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
  }

  /* encode */
  if (m3ap_encode_pdu(&pdu, &buffer, &len) < 0) {
    LOG_E(M3AP, "Failed to encode M3 response\n");
    return -1;
  }

  //printf(",m3ap_mme_data_from_mce->assoc_id %d\n",m3ap_mme_data_from_mce->assoc_id);

  m3ap_MME_itti_send_sctp_data_req(instance,m3ap_mme_data_from_mce->assoc_id,buffer,len,0);

  return 0;
}

int MME_send_M3_SETUP_FAILURE(instance_t instance,m3ap_setup_failure_t* m3ap_setup_failure) {
  AssertFatal(1==0,"Not implemented yet\n");
  
//  module_id_t enb_mod_idP;
//  module_id_t mce_mod_idP;
//
//  // This should be fixed
//  enb_mod_idP = (module_id_t)0;
//  mce_mod_idP  = (module_id_t)0;
//
//  M3AP_M3AP_PDU_t           pdu;
//  M3AP_M3SetupFailure_t    *out;
//  M3AP_M3SetupFailureIEs_t *ie;
//
//  uint8_t  *buffer;
//  uint32_t  len;
//
//  /* Create */
//  /* 0. Message Type */
//  memset(&pdu, 0, sizeof(pdu));
//  pdu.present = M3AP_M3AP_PDU_PR_unsuccessfulOutcome;
//  //pdu.choice.unsuccessfulOutcome = (M3AP_UnsuccessfulOutcome_t *)calloc(1, sizeof(M3AP_UnsuccessfulOutcome_t));
//  pdu.choice.unsuccessfulOutcome.procedureCode = M3AP_ProcedureCode_id_m3Setup;
//  pdu.choice.unsuccessfulOutcome.criticality   = M3AP_Criticality_reject;
//  pdu.choice.unsuccessfulOutcome.value.present = M3AP_UnsuccessfulOutcome__value_PR_M2SetupFailure;
//  out = &pdu.choice.unsuccessfulOutcome.value.choice.M2SetupFailure;
//
//  /* mandatory */
//  /* c1. Transaction ID (integer value)*/
// // ie = (M3AP_M3SetupFailure_Ies_t *)calloc(1, sizeof(M3AP_M3SetupFailure_Ies_t));
// // ie->id                        = M3AP_ProtocolIE_ID_id_GlobalMCE_ID;
// // ie->criticality               = M3AP_Criticality_reject;
// // ie->value.present             = M3AP_M3SetupFailure_Ies__value_PR_GlobalMCE_ID;
// // ie->value.choice.GlobalMCE_ID = M3AP_get_next_transaction_identifier(enb_mod_idP, mce_mod_idP);
// // ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
//
//  /* mandatory */
//  /* c2. Cause */
//  ie = (M3AP_M3SetupFailureIEs_t *)calloc(1, sizeof(M3AP_M3SetupFailureIEs_t));
//  ie->id                        = M3AP_ProtocolIE_ID_id_Cause;
//  ie->criticality               = M3AP_Criticality_ignore;
//  ie->value.present             = M3AP_M3SetupFailure_Ies__value_PR_Cause;
//  ie->value.choice.Cause.present = M3AP_Cause_PR_radioNetwork;
//  ie->value.choice.Cause.choice.radioNetwork = M3AP_CauseRadioNetwork_unspecified;
//  ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
//
//  /* optional */
//  /* c3. TimeToWait */
//  if (0) {
//    ie = (M3AP_M3SetupFailureIEs_t *)calloc(1, sizeof(M3AP_M3SetupFailureIEs_t));
//    ie->id                        = M3AP_ProtocolIE_ID_id_TimeToWait;
//    ie->criticality               = M3AP_Criticality_ignore;
//    ie->value.present             = M3AP_M3SetupFailure_Ies__value_PR_TimeToWait;
//    ie->value.choice.TimeToWait = M3AP_TimeToWait_v10s;
//    ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
//  }
//
//  /* optional */
//  /* c4. CriticalityDiagnostics*/
//  if (0) {
//    ie = (M3AP_M3SetupFailureIEs_t *)calloc(1, sizeof(M3AP_M3SetupFailureIEs_t));
//    ie->id                        = M3AP_ProtocolIE_ID_id_CriticalityDiagnostics;
//    ie->criticality               = M3AP_Criticality_ignore;
//    ie->value.present             = M3AP_M3SetupFailure_Ies__value_PR_CriticalityDiagnostics;
//    ie->value.choice.CriticalityDiagnostics.procedureCode = (M3AP_ProcedureCode_t *)calloc(1, sizeof(M3AP_ProcedureCode_t));
//    *ie->value.choice.CriticalityDiagnostics.procedureCode = M3AP_ProcedureCode_id_m3Setup;
//    ie->value.choice.CriticalityDiagnostics.triggeringMessage = (M3AP_TriggeringMessage_t *)calloc(1, sizeof(M3AP_TriggeringMessage_t));
//    *ie->value.choice.CriticalityDiagnostics.triggeringMessage = M3AP_TriggeringMessage_initiating_message;
//    ie->value.choice.CriticalityDiagnostics.procedureCriticality = (M3AP_Criticality_t *)calloc(1, sizeof(M3AP_Criticality_t));
//    *ie->value.choice.CriticalityDiagnostics.procedureCriticality = M3AP_Criticality_reject;
//    //ie->value.choice.CriticalityDiagnostics.transactionID = (M3AP_TransactionID_t *)calloc(1, sizeof(M3AP_TransactionID_t));
//    //*ie->value.choice.CriticalityDiagnostics.transactionID = 0;
//    ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
//  }
//
//  /* encode */
//  if (m3ap_encode_pdu(&pdu, &buffer, &len) < 0) {
//    LOG_E(M3AP, "Failed to encode M2 setup request\n");
//    return -1;
//  }
//
//  //mce_m3ap_itti_send_sctp_data_req(instance, m3ap_mce_data_from_enb->assoc_id, buffer, len, 0);
//  m3ap_MME_itti_send_sctp_data_req(instance,m3ap_mme_data_from_mce->assoc_id,buffer,len,0);

  return 0;
}

/*
 * MME Configuration Update
 */


int MME_handle_MME_CONFIGURATION_UPDATE_FAILURE(instance_t instance,
                                                  uint32_t assoc_id,
                                                  uint32_t stream,
                                                  M3AP_M3AP_PDU_t *pdu){
  AssertFatal(1==0,"Not implemented yet\n");
}


int MME_handle_MME_CONFIGURATION_UPDATE_ACKNOWLEDGE(instance_t instance,
                                                      uint32_t assoc_id,
                                                      uint32_t stream,
                                                      M3AP_M3AP_PDU_t *pdu){
  AssertFatal(1==0,"Not implemented yet\n");
}


/*
 * MCE Configuration Update
 */


int MME_handle_MCE_CONFIGURATION_UPDATE(instance_t instance,
                                          uint32_t assoc_id,
                                          uint32_t stream,
                                          M3AP_M3AP_PDU_t *pdu){
  AssertFatal(1==0,"Not implemented yet\n");
}






/*
 * Error Indication
 */

int MME_handle_ERROR_INDICATION(instance_t instance,
                                uint32_t assoc_id,
                                uint32_t stream,
                                M3AP_M3AP_PDU_t *pdu) {
  AssertFatal(1==0,"Not implemented yet\n");


}

int MME_send_ERROR_INDICATION(instance_t instance, M3AP_ErrorIndication_t *ErrorIndication) {
  AssertFatal(1==0,"Not implemented yet\n");
}




/*
 * Session Update Request
 */
int MME_send_MBMS_SESSION_UPDATE_REQUEST(instance_t instance, m3ap_mbms_session_update_req_t * m3ap_mbms_session_update_req){
  M3AP_M3AP_PDU_t          pdu; 
  M3AP_MBMSSessionUpdateRequest_t        *out;
  M3AP_MBMSSessionUpdateRequest_IEs_t    *ie;

  uint8_t *buffer;
  uint32_t len;
  //int	   i=0; 
  //int 	   j=0;

  /* Create */
  /* 0. pdu Type */
  memset(&pdu, 0, sizeof(pdu));
  pdu.present = M3AP_M3AP_PDU_PR_initiatingMessage;
  //pdu.choice.initiatingMessage = (M3AP_InitiatingMessage_t *)calloc(1, sizeof(M3AP_InitiatingMessage_t));
  pdu.choice.initiatingMessage.procedureCode = M3AP_ProcedureCode_id_mBMSsessionUpdate;
  pdu.choice.initiatingMessage.criticality   = M3AP_Criticality_reject;
  pdu.choice.initiatingMessage.value.present = M3AP_InitiatingMessage__value_PR_MBMSSessionUpdateRequest;
  out = &pdu.choice.initiatingMessage.value.choice.MBMSSessionUpdateRequest; 

  /* mandatory */
  /* c1. MME_MBMS_M3AP_ID (integer value) */ //long
  ie = (M3AP_MBMSSessionUpdateRequest_IEs_t *)calloc(1, sizeof(M3AP_MBMSSessionUpdateRequest_IEs_t));
  ie->id                        = M3AP_ProtocolIE_ID_id_MME_MBMS_M3AP_ID;
  ie->criticality               = M3AP_Criticality_reject;
  ie->value.present             = M3AP_MBMSSessionUpdateRequest_IEs__value_PR_MME_MBMS_M3AP_ID;
  //ie->value.choice.MME_MBMS_M3AP_ID = /*F1AP_get_next_transaction_identifier(enb_mod_idP, du_mod_idP);*/ //?
  ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);

  /* mandatory */
  /* c2. MCE_MBMS_M3AP_ID (integer value) */ //long
  ie = (M3AP_MBMSSessionUpdateRequest_IEs_t *)calloc(1, sizeof(M3AP_MBMSSessionUpdateRequest_IEs_t));
  ie->id                        = M3AP_ProtocolIE_ID_id_MCE_MBMS_M3AP_ID;
  ie->criticality               = M3AP_Criticality_reject;
  ie->value.present             = M3AP_MBMSSessionUpdateRequest_IEs__value_PR_MCE_MBMS_M3AP_ID;
  //ie->value.choice.MCE_MBMS_M3AP_ID = /*F1AP_get_next_transaction_identifier(enb_mod_idP, du_mod_idP);*/ //?

  ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);

   /* mandatory */
  /* c2. TMGI */ 
  ie = (M3AP_MBMSSessionUpdateRequest_IEs_t *)calloc(1, sizeof(M3AP_MBMSSessionUpdateRequest_IEs_t));
  ie->id                        = M3AP_ProtocolIE_ID_id_TMGI; 
  ie->criticality               = M3AP_Criticality_reject;
  ie->value.present             = M3AP_MBMSSessionUpdateRequest_IEs__value_PR_TMGI;
  M3AP_TMGI_t	*tmgi 		= &ie->value.choice.TMGI;
  {
	  MCC_MNC_TO_PLMNID(0,0,3,&tmgi->pLMNidentity);
	  uint8_t TMGI[5] = {4,3,2,1,0};
	  OCTET_STRING_fromBuf(&tmgi->serviceID,(const char*)&TMGI[2],3);
  }
  ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
  /* optional */
  /* c2. MBMS_Session_ID */
  if(0){
	  ie = (M3AP_MBMSSessionUpdateRequest_IEs_t *)calloc(1, sizeof(M3AP_MBMSSessionUpdateRequest_IEs_t));
	  ie->id                        = M3AP_ProtocolIE_ID_id_MBMS_Session_ID;
	  ie->criticality               = M3AP_Criticality_ignore;
	  ie->value.present             = M3AP_MBMSSessionUpdateRequest_IEs__value_PR_MBMS_Session_ID;
	  //M3AP_MBMS_Session_ID_t * mbms_session_id = &ie->value.choice.MBMS_Session_ID;

	  ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
  }
  /* mandatory */
  /* c2. MBMS_E_RAB_QoS_Parameters */ 
  ie = (M3AP_MBMSSessionUpdateRequest_IEs_t *)calloc(1, sizeof(M3AP_MBMSSessionUpdateRequest_IEs_t));
  ie->id                        = M3AP_ProtocolIE_ID_id_MBMS_E_RAB_QoS_Parameters; 
  ie->criticality               = M3AP_Criticality_reject;
  ie->value.present             = M3AP_MBMSSessionUpdateRequest_IEs__value_PR_MBMS_E_RAB_QoS_Parameters;
  M3AP_MBMS_E_RAB_QoS_Parameters_t * mbms_e_rab_qos_parameters = &ie->value.choice.MBMS_E_RAB_QoS_Parameters;
  {
	//M3AP_QCI_t * qci = &mbms_e_rab_qos_parameters->qCI; //long
	mbms_e_rab_qos_parameters->qCI=1;
	//struct M3AP_GBR_QosInformation  *gbrQosInformation;     /* OPTIONAL */
  }

  ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
  /* mandatory */
  /* c2. MBMS_Session_Duration */ 
  ie = (M3AP_MBMSSessionUpdateRequest_IEs_t *)calloc(1, sizeof(M3AP_MBMSSessionUpdateRequest_IEs_t));
  ie->id                        = M3AP_ProtocolIE_ID_id_MBMS_Session_Duration; 
  ie->criticality               = M3AP_Criticality_reject;
  ie->value.present             = M3AP_MBMSSessionUpdateRequest_IEs__value_PR_MBMS_Session_Duration; 
  M3AP_MBMS_Session_Duration_t * mbms_session_duration = &ie->value.choice.MBMS_Session_Duration;
  {
	uint8_t duration[5] = {4,3,2,1,0};
	OCTET_STRING_fromBuf(mbms_session_duration,(const char*)&duration[2],3);
  }
  ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
  /* optional */
  /* c2 MBMS_Service_Area */
  if(0){
	  ie = (M3AP_MBMSSessionUpdateRequest_IEs_t *)calloc(1, sizeof(M3AP_MBMSSessionUpdateRequest_IEs_t));
	  ie->id                        = M3AP_ProtocolIE_ID_id_MBMS_Service_Area;
	  ie->criticality               = M3AP_Criticality_ignore;
	  ie->value.present             = M3AP_MBMSSessionUpdateRequest_IEs__value_PR_MBMS_Service_Area;
	  //M3AP_MBMS_Service_Area_t * mbms_service_area = &ie->value.choice.MBMS_Service_Area;

	  ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
  }
  /* mandatory */
  /* c2 MinimumTimeToMBMSDataTransfer */
  ie = (M3AP_MBMSSessionUpdateRequest_IEs_t *)calloc(1, sizeof(M3AP_MBMSSessionUpdateRequest_IEs_t));
  ie->id                        = M3AP_ProtocolIE_ID_id_MinimumTimeToMBMSDataTransfer; 
  ie->criticality               = M3AP_Criticality_reject;
  ie->value.present             = M3AP_MBMSSessionUpdateRequest_IEs__value_PR_MinimumTimeToMBMSDataTransfer; 
  M3AP_MinimumTimeToMBMSDataTransfer_t * minimumtimetombmsdatatransfer = &ie->value.choice.MinimumTimeToMBMSDataTransfer;
  {
	uint8_t duration[5] = {4,3,2,1,0};
	OCTET_STRING_fromBuf(minimumtimetombmsdatatransfer,(const char*)&duration[2],1);
  }

  ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
  /* optional */
  /* c2 TNL_Information */
  if(0){
	  ie = (M3AP_MBMSSessionUpdateRequest_IEs_t *)calloc(1, sizeof(M3AP_MBMSSessionUpdateRequest_IEs_t));
	  ie->id                        = M3AP_ProtocolIE_ID_id_TNL_Information; 
	  ie->criticality               = M3AP_Criticality_ignore;
	  ie->value.present             = M3AP_MBMSSessionUpdateRequest_IEs__value_PR_TNL_Information; 
	  M3AP_TNL_Information_t * tnl_information = &ie->value.choice.TNL_Information;
	  {
		OCTET_STRING_fromBuf(&tnl_information->iPMCAddress,"1204",strlen("1234"));
		OCTET_STRING_fromBuf(&tnl_information->iPSourceAddress,"1204",strlen("1234"));
		OCTET_STRING_fromBuf(&tnl_information->gTP_DLTEID,"1204",strlen("1234"));
	  }
	  ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
  }
  /* optional */
  /* c2 Time_ofMBMS_DataTransfer */
  if(0){
	  ie = (M3AP_MBMSSessionUpdateRequest_IEs_t *)calloc(1, sizeof(M3AP_MBMSSessionUpdateRequest_IEs_t));
	  ie->id                        = M3AP_ProtocolIE_ID_id_Time_ofMBMS_DataTransfer; 
	  ie->criticality               = M3AP_Criticality_ignore;
	  ie->value.present             = M3AP_MBMSSessionUpdateRequest_IEs__value_PR_Absolute_Time_ofMBMS_Data; 
	  //M3AP_Absolute_Time_ofMBMS_Data_t * absolute_time_ofmbms_data	= &ie->value.choice.Absolute_Time_ofMBMS_Data;
	  //{
		//char duration[5] = {4,3,2,1,0};
		//OCTET_STRING_fromBuf(absolute_time_ofmbms_data,(const char*)&duration[2],3);
	  //}
	  ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
  }
  /* optional */
  /* c2 MBMS_Cell_List */
  if(0){
	  ie = (M3AP_MBMSSessionUpdateRequest_IEs_t *)calloc(1, sizeof(M3AP_MBMSSessionUpdateRequest_IEs_t));
	  ie->id                        = M3AP_ProtocolIE_ID_id_MBMS_Cell_List; 
	  ie->criticality               = M3AP_Criticality_ignore;
	  ie->value.present             = M3AP_MBMSSessionUpdateRequest_IEs__value_PR_MBMS_Cell_List; 
	  M3AP_MBMS_Cell_List_t * mbms_cell_list = &ie->value.choice.MBMS_Cell_List;
	  M3AP_ECGI_t * ecgi = (M3AP_ECGI_t*)calloc(1,sizeof(M3AP_ECGI_t));	
	  {
		//MCC_MNC_TO_PLMNID(0,0,3,ecgi->pLMN_Identity);
		//MACRO_ENB_ID_TO_CELL_IDENTITY(1,0,ecgi->eUTRANcellIdentifier);
		ASN_SEQUENCE_ADD(&mbms_cell_list->list,ecgi);
	  }
	  ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
  }

  /* encode */
  if (m3ap_encode_pdu(&pdu,&buffer,&len) < 0){
        return -1;
  }

  //MME_m3ap_itti_send_sctp_data_req(instance, m3ap_mce_data_from_mce->assoid,buffer,len,0); 
  m3ap_MME_itti_send_sctp_data_req(instance, m3ap_mme_data_from_mce->assoc_id,buffer,len,0);
  return 0;



}



int MME_handle_MBMS_SESSION_UPDATE_RESPONSE(instance_t instance,
                                                  uint32_t assoc_id,
                                                  uint32_t stream,
                                                  M3AP_M3AP_PDU_t *pdu){
  //AssertFatal(1==0,"Not implemented yet\n");
  LOG_D(M3AP, "MME_handle_MBMS_SESSION_UPDATE_RESPONSE\n");

   AssertFatal(pdu->present == M3AP_M3AP_PDU_PR_successfulOutcome,
               "pdu->present != M3AP_M3AP_PDU_PR_successfulOutcome\n");
   AssertFatal(pdu->choice.successfulOutcome.procedureCode  == M3AP_ProcedureCode_id_mBMSsessionUpdate,
               "pdu->choice.successfulOutcome->procedureCode != M3AP_ProcedureCode_id_sessionUpdate\n");
   AssertFatal(pdu->choice.successfulOutcome.criticality  == M3AP_Criticality_reject,
               "pdu->choice.successfulOutcome->criticality != M3AP_Criticality_reject\n");
   AssertFatal(pdu->choice.successfulOutcome.value.present  == M3AP_SuccessfulOutcome__value_PR_MBMSSessionUpdateResponse,
               "pdu->choice.successfulOutcome.value.present != M3AP_SuccessfulOutcome__value_PR_MBMSSessionUpdateResponse\n");


  M3AP_MBMSSessionUpdateResponse_t    *in = &pdu->choice.successfulOutcome.value.choice.MBMSSessionUpdateResponse;
  M3AP_MBMSSessionUpdateResponse_IEs_t  *ie;
  int MME_MBMS_M3AP_ID=-1;
  int MCE_MBMS_M3AP_ID=-1;


  MessageDef *msg_g = itti_alloc_new_message(TASK_M3AP_MME, 0,M3AP_MBMS_SESSION_UPDATE_RESP); //TODO

  LOG_D(M3AP, "M3AP: SessionUpdate-Resp: protocolIEs.list.count %d\n",
         in->protocolIEs.list.count);
  for (int i=0;i < in->protocolIEs.list.count; i++) {
     ie = in->protocolIEs.list.array[i];
     switch (ie->id) {
     case M3AP_ProtocolIE_ID_id_MME_MBMS_M3AP_ID:
       AssertFatal(ie->criticality == M3AP_Criticality_reject,
                   "ie->criticality != M3AP_Criticality_reject\n");
       AssertFatal(ie->value.present == M3AP_MBMSSessionUpdateResponse_IEs__value_PR_MME_MBMS_M3AP_ID,
                   "ie->value.present != M3AP_sessionUpdateResponse_IEs__value_PR_MME_MBMS_M3AP_ID\n");
       MME_MBMS_M3AP_ID=ie->value.choice.MME_MBMS_M3AP_ID;
       LOG_D(M3AP, "M3AP: SessionUpdate-Resp: MME_MBMS_M3AP_ID %d\n",
             MME_MBMS_M3AP_ID);
       break;
      case M3AP_ProtocolIE_ID_id_MCE_MBMS_M3AP_ID:
       AssertFatal(ie->criticality == M3AP_Criticality_reject,
                   "ie->criticality != M3AP_Criticality_reject\n");
       AssertFatal(ie->value.present == M3AP_MBMSSessionUpdateResponse_IEs__value_PR_MCE_MBMS_M3AP_ID,
                   "ie->value.present != M3AP_sessionUpdateResponse_IEs__value_PR_MCE_MBMS_M3AP_ID\n");
       MCE_MBMS_M3AP_ID=ie->value.choice.MCE_MBMS_M3AP_ID;
       LOG_D(M3AP, "M3AP: SessionUpdate-Resp: MCE_MBMS_M3AP_ID %d\n",
             MCE_MBMS_M3AP_ID);
       break;
     }
  }

  //AssertFatal(MME_MBMS_M3AP_ID!=-1,"MME_MBMS_M3AP_ID was not sent\n");
  //AssertFatal(MCE_MBMS_M3AP_ID!=-1,"MCE_MBMS_M3AP_ID was not sent\n");
  ////M3AP_SESSION_START_RESP(msg_p).
////  MSC_LOG_RX_MESSAGE(
////    MSC_M3AP_MME,
////    MSC_M3AP_MCE,
  //      //return 0;
////    0,
////    0,
////    MSC_AS_TIME_FMT" MME_handle_M2_SESSION_START_RESPONSE successfulOutcome assoc_id %d",
////    0,0,//MSC_AS_TIME_ARGS(ctxt_pP),
////    assoc_id);
////
  // LOG_W(M3AP, "Sending M3AP_SESSION_START_RESP ITTI message to MCE_APP with assoc_id (%d->%d)\n",
  //       assoc_id,ENB_MODULE_ID_TO_INSTANCE(assoc_id));
  itti_send_msg_to_task(TASK_MME_APP, ENB_MODULE_ID_TO_INSTANCE(assoc_id), msg_g);

  return 0;

}



int MME_handle_MBMS_SESSION_UPDATE_FAILURE(instance_t instance,
                                                      uint32_t assoc_id,
                                                      uint32_t stream,
                                                      M3AP_M3AP_PDU_t *pdu){
  AssertFatal(1==0,"Not implemented yet\n");
}



int MME_handle_MBMS_SERVICE_COUNTING_RESPONSE(instance_t instance,
                                                  uint32_t assoc_id,
                                                  uint32_t stream,
                                                  M3AP_M3AP_PDU_t *pdu){
  AssertFatal(1==0,"Not implemented yet\n");
}



int MME_handle_MBMS_SESSION_COUNTING_FAILURE(instance_t instance,
                                                      uint32_t assoc_id,
                                                      uint32_t stream,
                                                      M3AP_M3AP_PDU_t *pdu){
  AssertFatal(1==0,"Not implemented yet\n");

}


/*
 * Service Counting Results Report
 */

int MME_handle_MBMS_SESSION_COUNTING_RESULTS_REPORT(instance_t instance,
                                                      uint32_t assoc_id,
                                                      uint32_t stream,
                                                      M3AP_M3AP_PDU_t *pdu){
  AssertFatal(1==0,"Not implemented yet\n");

}


/*
 * Overload Notification
 */
int MME_handle_MBMS_OVERLOAD_NOTIFICATION(instance_t instance,
                                                      uint32_t assoc_id,
                                                      uint32_t stream,
                                                      M3AP_M3AP_PDU_t *pdu){
  AssertFatal(1==0,"Not implemented yet\n");
 
}




