/* * 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 rrc_eNB_S1AP.c * \brief rrc S1AP procedures for eNB * \author Navid Nikaein, Laurent Winckel, Sebastien ROUX, and Lionel GAUTHIER * \date 2013-2016 * \version 1.0 * \company Eurecom * \email: navid.nikaein@eurecom.fr */ #include "rrc_defs.h" #include "rrc_extern.h" #include "RRC/L2_INTERFACE/openair_rrc_L2_interface.h" #include "RRC/LTE/MESSAGES/asn1_msg.h" #include "rrc_eNB_UE_context.h" #include "rrc_eNB_S1AP.h" #include "enb_config.h" #include "common/ran_context.h" #include "gtpv1u.h" #include "s1ap_eNB.h" #include "s1ap_eNB_defs.h" #include "s1ap_eNB_management_procedures.h" #include "s1ap_eNB_ue_context.h" #include "asn1_conversions.h" #include "intertask_interface.h" #include "pdcp.h" #include "pdcp_primitives.h" #include "UTIL/OSA/osa_defs.h" #include <common/utils/msc/msc.h> #include "LTE_UERadioAccessCapabilityInformation.h" #include "gtpv1u_eNB_task.h" #include <openair3/ocp-gtpu/gtp_itf.h> #include "RRC/LTE/rrc_eNB_GTPV1U.h" #include "TLVDecoder.h" #include "S1AP_NAS-PDU.h" #include "flexran_agent_common_internal.h" #include "executables/softmodem-common.h" extern RAN_CONTEXT_t RC; /* Value to indicate an invalid UE initial id */ static const uint16_t UE_INITIAL_ID_INVALID = 0; /* Masks for S1AP Encryption algorithms, EEA0 is always supported (not coded) */ static const uint16_t S1AP_ENCRYPTION_EEA1_MASK = 0x8000; static const uint16_t S1AP_ENCRYPTION_EEA2_MASK = 0x4000; /* Masks for S1AP Integrity algorithms, EIA0 is always supported (not coded) */ static const uint16_t S1AP_INTEGRITY_EIA1_MASK = 0x8000; static const uint16_t S1AP_INTEGRITY_EIA2_MASK = 0x4000; #define INTEGRITY_ALGORITHM_NONE LTE_SecurityAlgorithmConfig__integrityProtAlgorithm_eia0_v920 void extract_imsi(uint8_t *pdu_buf, uint32_t pdu_len, rrc_eNB_ue_context_t *ue_context_pP) { /* Process NAS message locally to get the IMSI */ nas_message_t nas_msg; memset(&nas_msg, 0, sizeof(nas_message_t)); int size = 0; nas_message_security_header_t *header = &nas_msg.header; /* Decode the first octet of the header (security header type or EPS * bearer identity, and protocol discriminator) */ DECODE_U8((char *) pdu_buf, *(uint8_t *) (header), size); /* Decode NAS message only if decodable*/ if (!(header->security_header_type <= SECURITY_HEADER_TYPE_INTEGRITY_PROTECTED && header->protocol_discriminator == EPS_MOBILITY_MANAGEMENT_MESSAGE && pdu_len > NAS_MESSAGE_SECURITY_HEADER_SIZE)) return; /* Decode plain NAS message */ EMM_msg *e_msg = &nas_msg.plain.emm; emm_msg_header_t *emm_header = &e_msg->header; if (header->security_header_type != SECURITY_HEADER_TYPE_NOT_PROTECTED) { /* Decode the message authentication code */ DECODE_U32((char *) pdu_buf+size, header->message_authentication_code, size); /* Decode the sequence number */ DECODE_U8((char *) pdu_buf+size, header->sequence_number, size); /* Decode the security header type and the protocol discriminator */ DECODE_U8(pdu_buf + size, *(uint8_t *)(emm_header), size); /* Check that this is the right message */ if (emm_header->protocol_discriminator != EPS_MOBILITY_MANAGEMENT_MESSAGE) return; } pdu_buf += size; pdu_len -= size; /* Check that buffer contains more than only the header */ if (pdu_len <= sizeof(emm_msg_header_t)) return; /* First decode the EMM message header */ int e_head_size = 0; /* Decode the message type */ DECODE_U8(pdu_buf + e_head_size, emm_header->message_type, e_head_size); pdu_buf += e_head_size; pdu_len -= e_head_size; if (emm_header->message_type == IDENTITY_RESPONSE) { decode_identity_response(&e_msg->identity_response, pdu_buf, pdu_len); if (e_msg->identity_response.mobileidentity.imsi.typeofidentity == MOBILE_IDENTITY_IMSI) { memcpy(&ue_context_pP->ue_context.imsi, &e_msg->identity_response.mobileidentity.imsi, sizeof(ImsiMobileIdentity_t)); } } else if (emm_header->message_type == ATTACH_REQUEST) { decode_attach_request(&e_msg->attach_request, pdu_buf, pdu_len); if (e_msg->attach_request.oldgutiorimsi.imsi.typeofidentity == MOBILE_IDENTITY_IMSI) { /* the following is very dirty, we cast (implicitly) from * ImsiEpsMobileIdentity_t to ImsiMobileIdentity_t*/ memcpy(&ue_context_pP->ue_context.imsi, &e_msg->attach_request.oldgutiorimsi.imsi, sizeof(ImsiMobileIdentity_t)); } } } //------------------------------------------------------------------------------ /* * Get the UE S1 struct containing hashtables S1_id/UE_id. * Is also used to set the S1_id of the UE, depending on inputs. */ struct rrc_ue_s1ap_ids_s * rrc_eNB_S1AP_get_ue_ids( eNB_RRC_INST *const rrc_instance_pP, const uint16_t ue_initial_id, const uint32_t eNB_ue_s1ap_id ) //------------------------------------------------------------------------------ { rrc_ue_s1ap_ids_t *result = NULL; rrc_ue_s1ap_ids_t *result2 = NULL; /*****************************/ instance_t instance = 0; s1ap_eNB_instance_t *s1ap_eNB_instance_p = NULL; s1ap_eNB_ue_context_t *ue_desc_p = NULL; /*****************************/ hashtable_rc_t h_rc; if (ue_initial_id != UE_INITIAL_ID_INVALID) { h_rc = hashtable_get(rrc_instance_pP->initial_id2_s1ap_ids, (hash_key_t)ue_initial_id, (void **)&result); if (h_rc == HASH_TABLE_OK) { if (eNB_ue_s1ap_id > 0) { h_rc = hashtable_get(rrc_instance_pP->s1ap_id2_s1ap_ids, (hash_key_t)eNB_ue_s1ap_id, (void **)&result2); if (h_rc != HASH_TABLE_OK) { // this case is equivalent to associate eNB_ue_s1ap_id and ue_initial_id result2 = malloc(sizeof(*result2)); if (NULL != result2) { *result2 = *result; result2->eNB_ue_s1ap_id = eNB_ue_s1ap_id; result->eNB_ue_s1ap_id = eNB_ue_s1ap_id; h_rc = hashtable_insert(rrc_instance_pP->s1ap_id2_s1ap_ids, (hash_key_t)eNB_ue_s1ap_id, result2); if (h_rc != HASH_TABLE_OK) { LOG_E(S1AP, "[eNB %ld] Error while hashtable_insert in s1ap_id2_s1ap_ids eNB_ue_s1ap_id %"PRIu32"\n", rrc_instance_pP - RC.rrc[0], eNB_ue_s1ap_id); } } } else { // here we should check that the association was done correctly if ((result->ue_initial_id != result2->ue_initial_id) || (result->eNB_ue_s1ap_id != result2->eNB_ue_s1ap_id)) { LOG_E(S1AP, "[eNB %ld] Error while hashtable_get, two rrc_ue_s1ap_ids_t that should be equal, are not:\n \ ue_initial_id 1 = %"PRIu16",\n \ ue_initial_id 2 = %"PRIu16",\n \ eNB_ue_s1ap_id 1 = %"PRIu32",\n \ eNB_ue_s1ap_id 2 = %"PRIu32"\n", rrc_instance_pP - RC.rrc[0], result->ue_initial_id, result2->ue_initial_id, result->eNB_ue_s1ap_id, result2->eNB_ue_s1ap_id); // Still return *result } } } // end if if (eNB_ue_s1ap_id > 0) } else { // end if (h_rc == HASH_TABLE_OK) LOG_E(S1AP, "[eNB %ld] In hashtable_get, couldn't find in initial_id2_s1ap_ids ue_initial_id %"PRIu16"\n", rrc_instance_pP - RC.rrc[0], ue_initial_id); return NULL; /* * At the moment this is written, this case shouldn't (cannot) happen and is equivalent to an error. * One could try to find the struct instance based on s1ap_id2_s1ap_ids and eNB_ue_s1ap_id (if > 0), * but this behavior is not expected at the moment. */ } // end else (h_rc != HASH_TABLE_OK) } else { // end if (ue_initial_id != UE_INITIAL_ID_INVALID) if (eNB_ue_s1ap_id > 0) { h_rc = hashtable_get(rrc_instance_pP->s1ap_id2_s1ap_ids, (hash_key_t)eNB_ue_s1ap_id, (void **)&result); if (h_rc != HASH_TABLE_OK) { /* * This case is uncommon, but can happen when: * -> if the first NAS message was a Detach Request (non exhaustiv), the UE RRC context exist * but is not associated with eNB_ue_s1ap_id * -> ... (?) */ LOG_E(S1AP, "[eNB %ld] In hashtable_get, couldn't find in s1ap_id2_s1ap_ids eNB_ue_s1ap_id %"PRIu32", trying to find it through S1AP context\n", rrc_instance_pP - RC.rrc[0], eNB_ue_s1ap_id); instance = ENB_MODULE_ID_TO_INSTANCE(rrc_instance_pP - RC.rrc[0]); // get eNB instance s1ap_eNB_instance_p = s1ap_eNB_get_instance(instance); // get s1ap_eNB_instance if (s1ap_eNB_instance_p != NULL) { ue_desc_p = s1ap_eNB_get_ue_context(s1ap_eNB_instance_p, eNB_ue_s1ap_id); // get s1ap_eNB_ue_context } else { LOG_E(S1AP, "[eNB instance %ld] Couldn't find the eNB S1AP context\n", instance); return NULL; } if (ue_desc_p != NULL) { struct s1ap_eNB_ue_context_s *s1ap_ue_context_p = NULL; if ((s1ap_ue_context_p = RB_REMOVE(s1ap_ue_map, &s1ap_eNB_instance_p->s1ap_ue_head, ue_desc_p)) != NULL) { LOG_E(RRC, "Removed UE context eNB_ue_s1ap_id %u\n", s1ap_ue_context_p->eNB_ue_s1ap_id); s1ap_eNB_free_ue_context(s1ap_ue_context_p); } else { LOG_E(RRC, "Removing UE context eNB_ue_s1ap_id %u: did not find context\n",ue_desc_p->eNB_ue_s1ap_id); } return NULL; } else { LOG_E(S1AP, "[eNB %ld] In hashtable_get, couldn't find in s1ap_id2_s1ap_ids eNB_ue_s1ap_id %"PRIu32", because ue_initial_id is invalid in S1AP context\n", rrc_instance_pP - RC.rrc[0], eNB_ue_s1ap_id); return NULL; } } // end if (h_rc != HASH_TABLE_OK) } // end if (eNB_ue_s1ap_id > 0) } // end else (ue_initial_id == UE_INITIAL_ID_INVALID) return result; } //------------------------------------------------------------------------------ /* * Remove UE ids (ue_initial_id and S1_id) from hashtables. */ void rrc_eNB_S1AP_remove_ue_ids( eNB_RRC_INST *const rrc_instance_pP, struct rrc_ue_s1ap_ids_s *const ue_ids_pP ) //------------------------------------------------------------------------------ { hashtable_rc_t h_rc; if (rrc_instance_pP == NULL) { LOG_E(RRC, "Bad RRC instance\n"); return; } if (ue_ids_pP == NULL) { LOG_E(RRC, "Trying to free a NULL S1AP UE IDs\n"); return; } const uint16_t ue_initial_id = ue_ids_pP->ue_initial_id; const uint32_t eNB_ue_s1ap_id = ue_ids_pP->eNB_ue_s1ap_id; if (eNB_ue_s1ap_id > 0) { h_rc = hashtable_remove(rrc_instance_pP->s1ap_id2_s1ap_ids, (hash_key_t)eNB_ue_s1ap_id); if (h_rc != HASH_TABLE_OK) { LOG_W(RRC, "S1AP Did not find entry in hashtable s1ap_id2_s1ap_ids for eNB_ue_s1ap_id %u\n", eNB_ue_s1ap_id); } else { LOG_W(RRC, "S1AP removed entry in hashtable s1ap_id2_s1ap_ids for eNB_ue_s1ap_id %u\n", eNB_ue_s1ap_id); } } if (ue_initial_id != UE_INITIAL_ID_INVALID) { h_rc = hashtable_remove(rrc_instance_pP->initial_id2_s1ap_ids, (hash_key_t)ue_initial_id); if (h_rc != HASH_TABLE_OK) { LOG_W(RRC, "S1AP Did not find entry in hashtable initial_id2_s1ap_ids for ue_initial_id %u\n", ue_initial_id); } else { LOG_W(RRC, "S1AP removed entry in hashtable initial_id2_s1ap_ids for ue_initial_id %u\n", ue_initial_id); } } } /*! \fn uint16_t get_next_ue_initial_id(uint8_t mod_id) *\brief provide an UE initial ID for S1AP initial communication. *\param mod_id Instance ID of eNB. *\return the UE initial ID. */ //------------------------------------------------------------------------------ static uint16_t get_next_ue_initial_id( const module_id_t mod_id ) //------------------------------------------------------------------------------ { static uint16_t ue_initial_id[NUMBER_OF_eNB_MAX]; ue_initial_id[mod_id]++; /* Never use UE_INITIAL_ID_INVALID this is the invalid id! */ if (ue_initial_id[mod_id] == UE_INITIAL_ID_INVALID) { ue_initial_id[mod_id]++; } return ue_initial_id[mod_id]; } /*! \fn uint8_t get_UE_index_from_s1ap_ids(uint8_t mod_id, uint16_t ue_initial_id, uint32_t eNB_ue_s1ap_id) *\brief retrieve UE index in the eNB from the UE initial ID if not equal to UE_INDEX_INVALID or *\brief from the eNB_ue_s1ap_id previously transmitted by S1AP. *\param mod_id Instance ID of eNB. *\param ue_initial_id The UE initial ID sent to S1AP. *\param eNB_ue_s1ap_id The value sent by S1AP. *\return the UE index or UE_INDEX_INVALID if not found. */ static struct rrc_eNB_ue_context_s * rrc_eNB_get_ue_context_from_s1ap_ids( const instance_t instanceP, const uint16_t ue_initial_idP, const uint32_t eNB_ue_s1ap_idP ) { rrc_ue_s1ap_ids_t *temp = NULL; temp = rrc_eNB_S1AP_get_ue_ids(RC.rrc[ENB_INSTANCE_TO_MODULE_ID(instanceP)], ue_initial_idP, eNB_ue_s1ap_idP); if (temp != NULL) { return rrc_eNB_get_ue_context(RC.rrc[ENB_INSTANCE_TO_MODULE_ID(instanceP)], temp->ue_rnti); } return NULL; } /*! \fn e_SecurityAlgorithmConfig__cipheringAlgorithm rrc_eNB_select_ciphering(uint16_t algorithms) *\brief analyze available encryption algorithms bit mask and return the relevant one. *\param algorithms The bit mask of available algorithms received from S1AP. *\return the selected algorithm. */ static LTE_CipheringAlgorithm_r12_t rrc_eNB_select_ciphering(uint16_t algorithms) { //#warning "Forced return SecurityAlgorithmConfig__cipheringAlgorithm_eea0, to be deleted in future" return LTE_CipheringAlgorithm_r12_eea0; if (algorithms & S1AP_ENCRYPTION_EEA2_MASK) { return LTE_CipheringAlgorithm_r12_eea2; } if (algorithms & S1AP_ENCRYPTION_EEA1_MASK) { return LTE_CipheringAlgorithm_r12_eea1; } return LTE_CipheringAlgorithm_r12_eea0; } /*! \fn e_SecurityAlgorithmConfig__integrityProtAlgorithm rrc_eNB_select_integrity(uint16_t algorithms) *\brief analyze available integrity algorithms bit mask and return the relevant one. *\param algorithms The bit mask of available algorithms received from S1AP. *\return the selected algorithm. */ static e_LTE_SecurityAlgorithmConfig__integrityProtAlgorithm rrc_eNB_select_integrity(uint16_t algorithms) { if (algorithms & S1AP_INTEGRITY_EIA2_MASK) { return LTE_SecurityAlgorithmConfig__integrityProtAlgorithm_eia2; } if (algorithms & S1AP_INTEGRITY_EIA1_MASK) { return LTE_SecurityAlgorithmConfig__integrityProtAlgorithm_eia1; } return INTEGRITY_ALGORITHM_NONE; } /*! \fn int rrc_eNB_process_security (uint8_t mod_id, uint8_t ue_index, security_capabilities_t *security_capabilities) *\brief save and analyze available security algorithms bit mask and select relevant ones. *\param mod_id Instance ID of eNB. *\param ue_index Instance ID of UE in the eNB. *\param security_capabilities The security capabilities received from S1AP. *\return TRUE if at least one algorithm has been changed else FALSE. */ int rrc_eNB_process_security( const protocol_ctxt_t *const ctxt_pP, rrc_eNB_ue_context_t *const ue_context_pP, security_capabilities_t *security_capabilities_pP ) { boolean_t changed = FALSE; LTE_CipheringAlgorithm_r12_t cipheringAlgorithm; e_LTE_SecurityAlgorithmConfig__integrityProtAlgorithm integrityProtAlgorithm; /* Save security parameters */ ue_context_pP->ue_context.security_capabilities = *security_capabilities_pP; // translation LOG_D(RRC, "[eNB %d] NAS security_capabilities.encryption_algorithms %u AS ciphering_algorithm %lu NAS security_capabilities.integrity_algorithms %u AS integrity_algorithm %u\n", ctxt_pP->module_id, ue_context_pP->ue_context.security_capabilities.encryption_algorithms, (unsigned long)ue_context_pP->ue_context.ciphering_algorithm, ue_context_pP->ue_context.security_capabilities.integrity_algorithms, ue_context_pP->ue_context.integrity_algorithm); /* Select relevant algorithms */ cipheringAlgorithm = rrc_eNB_select_ciphering (ue_context_pP->ue_context.security_capabilities.encryption_algorithms); if (ue_context_pP->ue_context.ciphering_algorithm != cipheringAlgorithm) { ue_context_pP->ue_context.ciphering_algorithm = cipheringAlgorithm; changed = TRUE; } integrityProtAlgorithm = rrc_eNB_select_integrity (ue_context_pP->ue_context.security_capabilities.integrity_algorithms); if (ue_context_pP->ue_context.integrity_algorithm != integrityProtAlgorithm) { ue_context_pP->ue_context.integrity_algorithm = integrityProtAlgorithm; changed = TRUE; } LOG_I (RRC, "[eNB %d][UE %x] Selected security algorithms (%p): %lx, %x, %s\n", ctxt_pP->module_id, ue_context_pP->ue_context.rnti, security_capabilities_pP, (unsigned long)cipheringAlgorithm, integrityProtAlgorithm, changed ? "changed" : "same"); return changed; } /*! \fn void process_eNB_security_key (const protocol_ctxt_t* const ctxt_pP, eNB_RRC_UE_t * const ue_context_pP, uint8_t *security_key) *\brief save security key. *\param ctxt_pP Running context. *\param ue_context_pP UE context. *\param security_key_pP The security key received from S1AP. */ //------------------------------------------------------------------------------ void process_eNB_security_key ( const protocol_ctxt_t *const ctxt_pP, rrc_eNB_ue_context_t *const ue_context_pP, uint8_t *security_key_pP ) //------------------------------------------------------------------------------ { char ascii_buffer[65]; uint8_t i; /* Saves the security key */ memcpy (ue_context_pP->ue_context.kenb, security_key_pP, SECURITY_KEY_LENGTH); memset (ue_context_pP->ue_context.nh, 0, SECURITY_KEY_LENGTH); ue_context_pP->ue_context.nh_ncc = -1; for (i = 0; i < 32; i++) { sprintf(&ascii_buffer[2 * i], "%02X", ue_context_pP->ue_context.kenb[i]); } ascii_buffer[2 * i] = '\0'; LOG_I (RRC, "[eNB %d][UE %x] Saved security key %s\n", ctxt_pP->module_id, ue_context_pP->ue_context.rnti, ascii_buffer); } //------------------------------------------------------------------------------ void rrc_pdcp_config_security( const protocol_ctxt_t *const ctxt_pP, rrc_eNB_ue_context_t *const ue_context_pP, const uint8_t send_security_mode_command ) //------------------------------------------------------------------------------ { LTE_SRB_ToAddModList_t *SRB_configList = ue_context_pP->ue_context.SRB_configList; uint8_t *kRRCenc = NULL; uint8_t *kRRCint = NULL; uint8_t *kUPenc = NULL; pdcp_t *pdcp_p = NULL; static int print_keys= 1; hashtable_rc_t h_rc; hash_key_t key; /* Derive the keys from kenb */ if (SRB_configList != NULL) { derive_key_up_enc(ue_context_pP->ue_context.ciphering_algorithm, ue_context_pP->ue_context.kenb, &kUPenc); } derive_key_rrc_enc(ue_context_pP->ue_context.ciphering_algorithm, ue_context_pP->ue_context.kenb, &kRRCenc); derive_key_rrc_int(ue_context_pP->ue_context.integrity_algorithm, ue_context_pP->ue_context.kenb, &kRRCint); if (!IS_SOFTMODEM_IQPLAYER) { SET_LOG_DUMP(DEBUG_SECURITY) ; } if ( LOG_DUMPFLAG( DEBUG_SECURITY ) ) { if (print_keys ==1 ) { print_keys =0; LOG_DUMPMSG(RRC, DEBUG_SECURITY, ue_context_pP->ue_context.kenb, 32,"\nKeNB:" ); LOG_DUMPMSG(RRC, DEBUG_SECURITY, kRRCenc, 32,"\nKRRCenc:" ); LOG_DUMPMSG(RRC, DEBUG_SECURITY, kRRCint, 32,"\nKRRCint:" ); } } key = PDCP_COLL_KEY_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, DCCH, SRB_FLAG_YES); h_rc = hashtable_get(pdcp_coll_p, key, (void **)&pdcp_p); if (h_rc == HASH_TABLE_OK) { pdcp_config_set_security( ctxt_pP, pdcp_p, DCCH, DCCH+2, (send_security_mode_command == TRUE) ? 0 | (ue_context_pP->ue_context.integrity_algorithm << 4) : (ue_context_pP->ue_context.ciphering_algorithm ) | (ue_context_pP->ue_context.integrity_algorithm << 4), kRRCenc, kRRCint, kUPenc); } else { LOG_E(RRC, PROTOCOL_RRC_CTXT_UE_FMT"Could not get PDCP instance for SRB DCCH %u\n", PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), DCCH); } } //------------------------------------------------------------------------------ void rrc_eNB_send_S1AP_INITIAL_CONTEXT_SETUP_RESP( const protocol_ctxt_t *const ctxt_pP, rrc_eNB_ue_context_t *const ue_context_pP ) //------------------------------------------------------------------------------ { MessageDef *msg_p = NULL; int e_rab; int e_rabs_done = 0; int e_rabs_failed = 0; msg_p = itti_alloc_new_message (TASK_RRC_ENB, 0, S1AP_INITIAL_CONTEXT_SETUP_RESP); S1AP_INITIAL_CONTEXT_SETUP_RESP (msg_p).eNB_ue_s1ap_id = ue_context_pP->ue_context.eNB_ue_s1ap_id; for (e_rab = 0; e_rab < ue_context_pP->ue_context.nb_of_e_rabs; e_rab++) { if (ue_context_pP->ue_context.e_rab[e_rab].status == E_RAB_STATUS_DONE || ue_context_pP->ue_context.e_rab[e_rab].status == E_RAB_STATUS_TOMODIFY) { e_rabs_done++; S1AP_INITIAL_CONTEXT_SETUP_RESP (msg_p).e_rabs[e_rab].e_rab_id = ue_context_pP->ue_context.e_rab[e_rab].param.e_rab_id; // TODO add other information from S1-U when it will be integrated S1AP_INITIAL_CONTEXT_SETUP_RESP (msg_p).e_rabs[e_rab].gtp_teid = ue_context_pP->ue_context.enb_gtp_teid[e_rab]; S1AP_INITIAL_CONTEXT_SETUP_RESP (msg_p).e_rabs[e_rab].eNB_addr = ue_context_pP->ue_context.enb_gtp_addrs[e_rab]; S1AP_INITIAL_CONTEXT_SETUP_RESP (msg_p).e_rabs[e_rab].eNB_addr.length = 4; if (ue_context_pP->ue_context.e_rab[e_rab].status == E_RAB_STATUS_DONE) { ue_context_pP->ue_context.e_rab[e_rab].status = E_RAB_STATUS_ESTABLISHED; S1AP_INITIAL_CONTEXT_SETUP_RESP (msg_p).nb_of_e_rabs = e_rabs_done; S1AP_INITIAL_CONTEXT_SETUP_RESP (msg_p).nb_of_e_rabs_failed = e_rabs_failed; itti_send_msg_to_task (TASK_S1AP, ctxt_pP->instance, msg_p); } } else { e_rabs_failed++; ue_context_pP->ue_context.e_rab[e_rab].status = E_RAB_STATUS_FAILED; S1AP_INITIAL_CONTEXT_SETUP_RESP (msg_p).e_rabs_failed[e_rab].e_rab_id = ue_context_pP->ue_context.e_rab[e_rab].param.e_rab_id; // TODO add cause when it will be integrated } } MSC_LOG_TX_MESSAGE( MSC_RRC_ENB, MSC_S1AP_ENB, (const char *)&S1AP_INITIAL_CONTEXT_SETUP_RESP (msg_p), sizeof(s1ap_initial_context_setup_resp_t), MSC_AS_TIME_FMT" INITIAL_CONTEXT_SETUP_RESP UE %X eNB_ue_s1ap_id %u e_rabs:%u succ %u fail", MSC_AS_TIME_ARGS(ctxt_pP), ue_context_pP->ue_id_rnti, S1AP_INITIAL_CONTEXT_SETUP_RESP (msg_p).eNB_ue_s1ap_id, e_rabs_done, e_rabs_failed); } //------------------------------------------------------------------------------ void rrc_eNB_send_S1AP_UPLINK_NAS( const protocol_ctxt_t *const ctxt_pP, rrc_eNB_ue_context_t *const ue_context_pP, LTE_UL_DCCH_Message_t *const ul_dcch_msg ) //------------------------------------------------------------------------------ { { LTE_ULInformationTransfer_t *ulInformationTransfer = &ul_dcch_msg->message.choice.c1.choice.ulInformationTransfer; if ((ulInformationTransfer->criticalExtensions.present == LTE_ULInformationTransfer__criticalExtensions_PR_c1) && (ulInformationTransfer->criticalExtensions.choice.c1.present == LTE_ULInformationTransfer__criticalExtensions__c1_PR_ulInformationTransfer_r8) && (ulInformationTransfer->criticalExtensions.choice.c1.choice.ulInformationTransfer_r8.dedicatedInfoType.present == LTE_ULInformationTransfer_r8_IEs__dedicatedInfoType_PR_dedicatedInfoNAS)) { /* This message hold a dedicated info NAS payload, forward it to NAS */ struct LTE_ULInformationTransfer_r8_IEs__dedicatedInfoType *dedicatedInfoType = &ulInformationTransfer->criticalExtensions.choice.c1.choice.ulInformationTransfer_r8.dedicatedInfoType; uint32_t pdu_length; uint8_t *pdu_buffer; MessageDef *msg_p; pdu_length = dedicatedInfoType->choice.dedicatedInfoNAS.size; pdu_buffer = dedicatedInfoType->choice.dedicatedInfoNAS.buf; msg_p = itti_alloc_new_message (TASK_RRC_ENB, 0, S1AP_UPLINK_NAS); S1AP_UPLINK_NAS (msg_p).eNB_ue_s1ap_id = ue_context_pP->ue_context.eNB_ue_s1ap_id; S1AP_UPLINK_NAS (msg_p).nas_pdu.length = pdu_length; S1AP_UPLINK_NAS (msg_p).nas_pdu.buffer = pdu_buffer; extract_imsi(S1AP_UPLINK_NAS (msg_p).nas_pdu.buffer, S1AP_UPLINK_NAS (msg_p).nas_pdu.length, ue_context_pP); itti_send_msg_to_task (TASK_S1AP, ctxt_pP->instance, msg_p); } } } //------------------------------------------------------------------------------ void rrc_eNB_send_S1AP_UE_CAPABILITIES_IND( const protocol_ctxt_t *const ctxt_pP, rrc_eNB_ue_context_t *const ue_context_pP, LTE_UL_DCCH_Message_t *ul_dcch_msg ) //------------------------------------------------------------------------------ { LTE_UECapabilityInformation_t *ueCapabilityInformation = &ul_dcch_msg->message.choice.c1.choice.ueCapabilityInformation; /* 4096 is arbitrary, should be big enough */ unsigned char buf[4096]; unsigned char *buf2; LTE_UERadioAccessCapabilityInformation_t rac; if (ueCapabilityInformation->criticalExtensions.present != LTE_UECapabilityInformation__criticalExtensions_PR_c1 || ueCapabilityInformation->criticalExtensions.choice.c1.present != LTE_UECapabilityInformation__criticalExtensions__c1_PR_ueCapabilityInformation_r8) { LOG_E(RRC, "[eNB %d][UE %x] bad UE capabilities\n", ctxt_pP->module_id, ue_context_pP->ue_context.rnti); return; } asn_enc_rval_t ret = uper_encode_to_buffer(&asn_DEF_LTE_UECapabilityInformation, NULL, ueCapabilityInformation, buf, 4096); if (ret.encoded == -1) abort(); memset(&rac, 0, sizeof(LTE_UERadioAccessCapabilityInformation_t)); rac.criticalExtensions.present = LTE_UERadioAccessCapabilityInformation__criticalExtensions_PR_c1; rac.criticalExtensions.choice.c1.present = LTE_UERadioAccessCapabilityInformation__criticalExtensions__c1_PR_ueRadioAccessCapabilityInformation_r8; rac.criticalExtensions.choice.c1.choice.ueRadioAccessCapabilityInformation_r8.ue_RadioAccessCapabilityInfo.buf = buf; rac.criticalExtensions.choice.c1.choice.ueRadioAccessCapabilityInformation_r8.ue_RadioAccessCapabilityInfo.size = (ret.encoded+7)/8; rac.criticalExtensions.choice.c1.choice.ueRadioAccessCapabilityInformation_r8.nonCriticalExtension = NULL; /* 8192 is arbitrary, should be big enough */ buf2 = malloc16(8192); if (buf2 == NULL) abort(); ret = uper_encode_to_buffer(&asn_DEF_LTE_UERadioAccessCapabilityInformation, NULL, &rac, buf2, 8192); if (ret.encoded == -1) abort(); MessageDef *msg_p; msg_p = itti_alloc_new_message (TASK_RRC_ENB, 0, S1AP_UE_CAPABILITIES_IND); S1AP_UE_CAPABILITIES_IND (msg_p).eNB_ue_s1ap_id = ue_context_pP->ue_context.eNB_ue_s1ap_id; S1AP_UE_CAPABILITIES_IND (msg_p).ue_radio_cap.length = (ret.encoded+7)/8; S1AP_UE_CAPABILITIES_IND (msg_p).ue_radio_cap.buffer = buf2; itti_send_msg_to_task (TASK_S1AP, ctxt_pP->instance, msg_p); } //------------------------------------------------------------------------------ /* * Initial UE NAS message on S1AP. */ void rrc_eNB_send_S1AP_NAS_FIRST_REQ( const protocol_ctxt_t *const ctxt_pP, rrc_eNB_ue_context_t *const ue_context_pP, LTE_RRCConnectionSetupComplete_r8_IEs_t *rrcConnectionSetupComplete ) //------------------------------------------------------------------------------ { eNB_RRC_INST *rrc = RC.rrc[ctxt_pP->module_id]; { MessageDef *message_p = NULL; rrc_ue_s1ap_ids_t *rrc_ue_s1ap_ids_p = NULL; hashtable_rc_t h_rc; message_p = itti_alloc_new_message(TASK_RRC_ENB, 0, S1AP_NAS_FIRST_REQ); memset(&message_p->ittiMsg.s1ap_nas_first_req, 0, sizeof(s1ap_nas_first_req_t)); ue_context_pP->ue_context.ue_initial_id = get_next_ue_initial_id(ctxt_pP->module_id); S1AP_NAS_FIRST_REQ(message_p).ue_initial_id = ue_context_pP->ue_context.ue_initial_id; rrc_ue_s1ap_ids_p = malloc(sizeof(*rrc_ue_s1ap_ids_p)); rrc_ue_s1ap_ids_p->ue_initial_id = ue_context_pP->ue_context.ue_initial_id; rrc_ue_s1ap_ids_p->eNB_ue_s1ap_id = UE_INITIAL_ID_INVALID; rrc_ue_s1ap_ids_p->ue_rnti = ctxt_pP->rnti; h_rc = hashtable_insert(RC.rrc[ctxt_pP->module_id]->initial_id2_s1ap_ids, (hash_key_t)ue_context_pP->ue_context.ue_initial_id, rrc_ue_s1ap_ids_p); if (h_rc != HASH_TABLE_OK) { LOG_E(S1AP, "[eNB %d] Error while hashtable_insert in initial_id2_s1ap_ids ue_initial_id %u\n", ctxt_pP->module_id, ue_context_pP->ue_context.ue_initial_id); } /* Assume that cause is coded in the same way in RRC and S1ap, just check that the value is in S1ap range */ AssertFatal(ue_context_pP->ue_context.establishment_cause < RRC_CAUSE_LAST, "Establishment cause invalid (%jd/%d) for eNB %d!", ue_context_pP->ue_context.establishment_cause, RRC_CAUSE_LAST, ctxt_pP->module_id); S1AP_NAS_FIRST_REQ (message_p).establishment_cause = ue_context_pP->ue_context.establishment_cause; /* Forward NAS message */ S1AP_NAS_FIRST_REQ (message_p).nas_pdu.buffer = rrcConnectionSetupComplete->dedicatedInfoNAS.buf; S1AP_NAS_FIRST_REQ (message_p).nas_pdu.length = rrcConnectionSetupComplete->dedicatedInfoNAS.size; extract_imsi(S1AP_NAS_FIRST_REQ (message_p).nas_pdu.buffer, S1AP_NAS_FIRST_REQ (message_p).nas_pdu.length, ue_context_pP); /* Fill UE identities with available information */ { S1AP_NAS_FIRST_REQ (message_p).ue_identity.presenceMask = UE_IDENTITIES_NONE; if (ue_context_pP->ue_context.Initialue_identity_s_TMSI.presence) { /* Fill s-TMSI */ UE_S_TMSI *s_TMSI = &ue_context_pP->ue_context.Initialue_identity_s_TMSI; S1AP_NAS_FIRST_REQ (message_p).ue_identity.presenceMask |= UE_IDENTITIES_s_tmsi; S1AP_NAS_FIRST_REQ (message_p).ue_identity.s_tmsi.mme_code = s_TMSI->mme_code; S1AP_NAS_FIRST_REQ (message_p).ue_identity.s_tmsi.m_tmsi = s_TMSI->m_tmsi; LOG_I(S1AP, "[eNB %d] Build S1AP_NAS_FIRST_REQ with s_TMSI: MME code %u M-TMSI %u ue %x\n", ctxt_pP->module_id, S1AP_NAS_FIRST_REQ (message_p).ue_identity.s_tmsi.mme_code, S1AP_NAS_FIRST_REQ (message_p).ue_identity.s_tmsi.m_tmsi, ue_context_pP->ue_context.rnti); } // end if S-TMSI presence /* selected_plmn_identity: IE is 1-based, convert to 0-based (C array) */ int selected_plmn_identity = rrcConnectionSetupComplete->selectedPLMN_Identity - 1; S1AP_NAS_FIRST_REQ(message_p).selected_plmn_identity = selected_plmn_identity; if (rrcConnectionSetupComplete->registeredMME != NULL) { /* Fill GUMMEI */ struct LTE_RegisteredMME *r_mme = rrcConnectionSetupComplete->registeredMME; S1AP_NAS_FIRST_REQ (message_p).ue_identity.presenceMask |= UE_IDENTITIES_gummei; if (r_mme->plmn_Identity != NULL) { if ((r_mme->plmn_Identity->mcc != NULL) && (r_mme->plmn_Identity->mcc->list.count == 3)) { S1AP_NAS_FIRST_REQ (message_p).ue_identity.gummei.mcc = (*r_mme->plmn_Identity->mcc->list.array[0] & 0xf) * 100 + (*r_mme->plmn_Identity->mcc->list.array[1] & 0xf) * 10 + (*r_mme->plmn_Identity->mcc->list.array[2] & 0xf); LOG_I(S1AP, "[eNB %d] Build S1AP_NAS_FIRST_REQ adding in s_TMSI: GUMMEI MCC %u ue %x\n", ctxt_pP->module_id, S1AP_NAS_FIRST_REQ (message_p).ue_identity.gummei.mcc, ue_context_pP->ue_context.rnti); } if(r_mme->plmn_Identity->mnc.list.count == 3) { S1AP_NAS_FIRST_REQ (message_p).ue_identity.gummei.mnc = (*r_mme->plmn_Identity->mnc.list.array[0] & 0xf) * 100 + (*r_mme->plmn_Identity->mnc.list.array[1] & 0xf) * 10 + (*r_mme->plmn_Identity->mnc.list.array[2] & 0xf); S1AP_NAS_FIRST_REQ (message_p).ue_identity.gummei.mnc_len = 3; LOG_I(S1AP, "[eNB %d] Build S1AP_NAS_FIRST_REQ adding in s_TMSI: GUMMEI MNC %u %udigit ue %x\n", ctxt_pP->module_id, S1AP_NAS_FIRST_REQ (message_p).ue_identity.gummei.mnc, S1AP_NAS_FIRST_REQ (message_p).ue_identity.gummei.mnc_len, ue_context_pP->ue_context.rnti); } else if(r_mme->plmn_Identity->mnc.list.count == 2) { S1AP_NAS_FIRST_REQ (message_p).ue_identity.gummei.mnc = (*r_mme->plmn_Identity->mnc.list.array[0] & 0xf) * 10 + (*r_mme->plmn_Identity->mnc.list.array[1] & 0xf); S1AP_NAS_FIRST_REQ (message_p).ue_identity.gummei.mnc_len = 2; LOG_I(S1AP, "[eNB %d] Build S1AP_NAS_FIRST_REQ adding in s_TMSI: GUMMEI MNC %u %udigit ue %x\n", ctxt_pP->module_id, S1AP_NAS_FIRST_REQ (message_p).ue_identity.gummei.mnc, S1AP_NAS_FIRST_REQ (message_p).ue_identity.gummei.mnc_len, ue_context_pP->ue_context.rnti); } } else { // end if plmn_Identity != NULL S1AP_NAS_FIRST_REQ(message_p).ue_identity.gummei.mcc = rrc->configuration.mcc[selected_plmn_identity]; S1AP_NAS_FIRST_REQ(message_p).ue_identity.gummei.mnc = rrc->configuration.mnc[selected_plmn_identity]; S1AP_NAS_FIRST_REQ(message_p).ue_identity.gummei.mnc_len = rrc->configuration.mnc_digit_length[selected_plmn_identity]; } // end else (plmn_Identity == NULL) S1AP_NAS_FIRST_REQ (message_p).ue_identity.gummei.mme_code = BIT_STRING_to_uint8 (&r_mme->mmec); S1AP_NAS_FIRST_REQ (message_p).ue_identity.gummei.mme_group_id = BIT_STRING_to_uint16 (&r_mme->mmegi); ue_context_pP->ue_context.ue_gummei.mcc = S1AP_NAS_FIRST_REQ (message_p).ue_identity.gummei.mcc; ue_context_pP->ue_context.ue_gummei.mnc = S1AP_NAS_FIRST_REQ (message_p).ue_identity.gummei.mnc; ue_context_pP->ue_context.ue_gummei.mnc_len = S1AP_NAS_FIRST_REQ (message_p).ue_identity.gummei.mnc_len; ue_context_pP->ue_context.ue_gummei.mme_code = S1AP_NAS_FIRST_REQ (message_p).ue_identity.gummei.mme_code; ue_context_pP->ue_context.ue_gummei.mme_group_id = S1AP_NAS_FIRST_REQ (message_p).ue_identity.gummei.mme_group_id; MSC_LOG_TX_MESSAGE(MSC_S1AP_ENB, MSC_S1AP_MME, (const char *)&message_p->ittiMsg.s1ap_nas_first_req, sizeof(s1ap_nas_first_req_t), MSC_AS_TIME_FMT" S1AP_NAS_FIRST_REQ eNB %u UE %x", MSC_AS_TIME_ARGS(ctxt_pP), ctxt_pP->module_id, ctxt_pP->rnti); LOG_I(S1AP, "[eNB %d] Build S1AP_NAS_FIRST_REQ adding in s_TMSI: GUMMEI mme_code %u mme_group_id %u ue %x\n", ctxt_pP->module_id, S1AP_NAS_FIRST_REQ (message_p).ue_identity.gummei.mme_code, S1AP_NAS_FIRST_REQ (message_p).ue_identity.gummei.mme_group_id, ue_context_pP->ue_context.rnti); } // end if MME info present } // end "Fill UE identities with available information" sub-part itti_send_msg_to_task (TASK_S1AP, ctxt_pP->instance, message_p); } } //------------------------------------------------------------------------------ int rrc_eNB_process_S1AP_DOWNLINK_NAS( MessageDef *msg_p, const char *msg_name, instance_t instance, mui_t *rrc_eNB_mui ) //------------------------------------------------------------------------------ { uint16_t ue_initial_id; uint32_t eNB_ue_s1ap_id; uint32_t length; uint8_t *buffer; uint8_t srb_id; struct rrc_eNB_ue_context_s *ue_context_p = NULL; protocol_ctxt_t ctxt; memset(&ctxt, 0, sizeof(protocol_ctxt_t)); ue_initial_id = S1AP_DOWNLINK_NAS (msg_p).ue_initial_id; eNB_ue_s1ap_id = S1AP_DOWNLINK_NAS (msg_p).eNB_ue_s1ap_id; ue_context_p = rrc_eNB_get_ue_context_from_s1ap_ids(instance, ue_initial_id, eNB_ue_s1ap_id); LOG_I(RRC, "[eNB %ld] Received %s: ue_initial_id %d, eNB_ue_s1ap_id %d\n", instance, msg_name, ue_initial_id, eNB_ue_s1ap_id); if (ue_context_p == NULL) { MSC_LOG_RX_MESSAGE( MSC_RRC_ENB, MSC_S1AP_ENB, NULL, 0, MSC_AS_TIME_FMT" DOWNLINK-NAS UE initial id %u eNB_ue_s1ap_id %u", 0,0,//MSC_AS_TIME_ARGS(ctxt_pP), ue_initial_id, eNB_ue_s1ap_id); /* Can not associate this message to an UE index, send a failure to S1AP and discard it! */ MessageDef *msg_fail_p; LOG_W(RRC, "[eNB %ld] In S1AP_DOWNLINK_NAS: unknown UE from S1AP ids (%d, %d)\n", instance, ue_initial_id, eNB_ue_s1ap_id); msg_fail_p = itti_alloc_new_message (TASK_RRC_ENB, 0, S1AP_NAS_NON_DELIVERY_IND); S1AP_NAS_NON_DELIVERY_IND (msg_fail_p).eNB_ue_s1ap_id = eNB_ue_s1ap_id; S1AP_NAS_NON_DELIVERY_IND (msg_fail_p).nas_pdu.length = S1AP_DOWNLINK_NAS (msg_p).nas_pdu.length; S1AP_NAS_NON_DELIVERY_IND (msg_fail_p).nas_pdu.buffer = S1AP_DOWNLINK_NAS (msg_p).nas_pdu.buffer; // TODO add failure cause when defined! MSC_LOG_TX_MESSAGE( MSC_RRC_ENB, MSC_S1AP_ENB, (const char *)NULL, 0, MSC_AS_TIME_FMT" S1AP_NAS_NON_DELIVERY_IND UE initial id %u eNB_ue_s1ap_id %u (ue ctxt !found)", 0,0,//MSC_AS_TIME_ARGS(ctxt_pP), ue_initial_id, eNB_ue_s1ap_id); itti_send_msg_to_task (TASK_S1AP, instance, msg_fail_p); return (-1); } else { PROTOCOL_CTXT_SET_BY_INSTANCE(&ctxt, instance, ENB_FLAG_YES, ue_context_p->ue_context.rnti, 0, 0); srb_id = ue_context_p->ue_context.Srb2.Srb_info.Srb_id; /* Is it the first income from S1AP ? */ if (ue_context_p->ue_context.eNB_ue_s1ap_id == 0) { ue_context_p->ue_context.eNB_ue_s1ap_id = S1AP_DOWNLINK_NAS (msg_p).eNB_ue_s1ap_id; } MSC_LOG_RX_MESSAGE( MSC_RRC_ENB, MSC_S1AP_ENB, (const char *)NULL, 0, MSC_AS_TIME_FMT" DOWNLINK-NAS UE initial id %u eNB_ue_s1ap_id %u", 0,0,//MSC_AS_TIME_ARGS(ctxt_pP), ue_initial_id, S1AP_DOWNLINK_NAS (msg_p).eNB_ue_s1ap_id); /* Create message for PDCP (DLInformationTransfer_t) */ length = do_DLInformationTransfer ( instance, &buffer, rrc_eNB_get_next_transaction_identifier (instance), S1AP_DOWNLINK_NAS (msg_p).nas_pdu.length, S1AP_DOWNLINK_NAS (msg_p).nas_pdu.buffer); LOG_DUMPMSG(RRC,DEBUG_RRC,buffer,length,"[MSG] RRC DL Information Transfer\n"); /* * switch UL or DL NAS message without RRC piggybacked to SRB2 if active. */ /* Transfer data to PDCP */ rrc_data_req ( &ctxt, srb_id, (*rrc_eNB_mui)++, SDU_CONFIRM_NO, length, buffer, PDCP_TRANSMISSION_MODE_CONTROL); return (0); } } /*------------------------------------------------------------------------------*/ int rrc_eNB_process_S1AP_INITIAL_CONTEXT_SETUP_REQ(MessageDef *msg_p, const char *msg_name, instance_t instance) { uint16_t ue_initial_id; uint32_t eNB_ue_s1ap_id; //MessageDef *message_gtpv1u_p = NULL; gtpv1u_enb_create_tunnel_req_t create_tunnel_req; gtpv1u_enb_create_tunnel_resp_t create_tunnel_resp; uint8_t inde_list[NB_RB_MAX - 3]= {0}; int ret; struct rrc_eNB_ue_context_s *ue_context_p = NULL; protocol_ctxt_t ctxt; ue_initial_id = S1AP_INITIAL_CONTEXT_SETUP_REQ (msg_p).ue_initial_id; eNB_ue_s1ap_id = S1AP_INITIAL_CONTEXT_SETUP_REQ (msg_p).eNB_ue_s1ap_id; ue_context_p = rrc_eNB_get_ue_context_from_s1ap_ids(instance, ue_initial_id, eNB_ue_s1ap_id); LOG_I(RRC, "[eNB %ld] Received %s: ue_initial_id %d, eNB_ue_s1ap_id %d, nb_of_e_rabs %d\n", instance, msg_name, ue_initial_id, eNB_ue_s1ap_id, S1AP_INITIAL_CONTEXT_SETUP_REQ (msg_p).nb_of_e_rabs); if (ue_context_p == NULL) { /* Can not associate this message to an UE index, send a failure to S1AP and discard it! */ MessageDef *msg_fail_p = NULL; LOG_W(RRC, "[eNB %ld] In S1AP_INITIAL_CONTEXT_SETUP_REQ: unknown UE from S1AP ids (%d, %d)\n", instance, ue_initial_id, eNB_ue_s1ap_id); msg_fail_p = itti_alloc_new_message (TASK_RRC_ENB, 0, S1AP_INITIAL_CONTEXT_SETUP_FAIL); S1AP_INITIAL_CONTEXT_SETUP_FAIL (msg_fail_p).eNB_ue_s1ap_id = eNB_ue_s1ap_id; // TODO add failure cause when defined! itti_send_msg_to_task (TASK_S1AP, instance, msg_fail_p); return (-1); } else { PROTOCOL_CTXT_SET_BY_INSTANCE(&ctxt, instance, ENB_FLAG_YES, ue_context_p->ue_context.rnti, 0, 0); ue_context_p->ue_context.eNB_ue_s1ap_id = S1AP_INITIAL_CONTEXT_SETUP_REQ (msg_p).eNB_ue_s1ap_id; ue_context_p->ue_context.mme_ue_s1ap_id = S1AP_INITIAL_CONTEXT_SETUP_REQ (msg_p).mme_ue_s1ap_id; /* Save e RAB information for later */ { int i; memset(&create_tunnel_req, 0, sizeof(create_tunnel_req)); ue_context_p->ue_context.nb_of_e_rabs = S1AP_INITIAL_CONTEXT_SETUP_REQ (msg_p).nb_of_e_rabs; for (i = 0; i < ue_context_p->ue_context.nb_of_e_rabs; i++) { ue_context_p->ue_context.e_rab[i].status = E_RAB_STATUS_NEW; ue_context_p->ue_context.e_rab[i].param = S1AP_INITIAL_CONTEXT_SETUP_REQ (msg_p).e_rab_param[i]; create_tunnel_req.eps_bearer_id[i] = S1AP_INITIAL_CONTEXT_SETUP_REQ (msg_p).e_rab_param[i].e_rab_id; create_tunnel_req.sgw_S1u_teid[i] = S1AP_INITIAL_CONTEXT_SETUP_REQ (msg_p).e_rab_param[i].gtp_teid; memcpy(&create_tunnel_req.sgw_addr[i], &S1AP_INITIAL_CONTEXT_SETUP_REQ (msg_p).e_rab_param[i].sgw_addr, sizeof(transport_layer_addr_t)); inde_list[create_tunnel_req.num_tunnels]= i; create_tunnel_req.num_tunnels++; } create_tunnel_req.rnti = ue_context_p->ue_context.rnti; // warning put zero above // create_tunnel_req.num_tunnels = i; ret = gtpv1u_create_s1u_tunnel( instance, &create_tunnel_req, &create_tunnel_resp); if ( ret != 0 ) { LOG_E(RRC,"rrc_eNB_process_S1AP_INITIAL_CONTEXT_SETUP_REQ : gtpv1u_create_s1u_tunnel failed,start to release UE %x\n",ue_context_p->ue_context.rnti); ue_context_p->ue_context.ue_release_timer_s1 = 1; ue_context_p->ue_context.ue_release_timer_thres_s1 = 100; ue_context_p->ue_context.ue_release_timer = 0; ue_context_p->ue_context.ue_reestablishment_timer = 0; ue_context_p->ue_context.ul_failure_timer = 20000; // set ul_failure to 20000 for triggering rrc_eNB_send_S1AP_UE_CONTEXT_RELEASE_REQ rrc_eNB_free_UE(ctxt.module_id,ue_context_p); ue_context_p->ue_context.ul_failure_timer = 0; return (0); } rrc_eNB_process_GTPV1U_CREATE_TUNNEL_RESP( &ctxt, &create_tunnel_resp, &inde_list[0]); ue_context_p->ue_context.setup_e_rabs=ue_context_p->ue_context.nb_of_e_rabs; } /* TODO parameters yet to process ... */ { // S1AP_INITIAL_CONTEXT_SETUP_REQ(msg_p).ue_ambr; } rrc_eNB_process_security ( &ctxt, ue_context_p, &S1AP_INITIAL_CONTEXT_SETUP_REQ(msg_p).security_capabilities); process_eNB_security_key ( &ctxt, ue_context_p, S1AP_INITIAL_CONTEXT_SETUP_REQ(msg_p).security_key); { uint8_t send_security_mode_command = TRUE; #ifndef EXMIMO_IOT if ((ue_context_p->ue_context.ciphering_algorithm == SecurityAlgorithmConfig__cipheringAlgorithm_eea0) && (ue_context_p->ue_context.integrity_algorithm == INTEGRITY_ALGORITHM_NONE)) { send_security_mode_command = FALSE; } #endif rrc_pdcp_config_security( &ctxt, ue_context_p, send_security_mode_command); if (send_security_mode_command) { rrc_eNB_generate_SecurityModeCommand ( &ctxt, ue_context_p); send_security_mode_command = FALSE; // apply ciphering after RRC security command mode rrc_pdcp_config_security( &ctxt, ue_context_p, send_security_mode_command); } else { rrc_eNB_generate_UECapabilityEnquiry (&ctxt, ue_context_p); } } ue_context_p->ue_context.nr_security.ciphering_algorithms = S1AP_INITIAL_CONTEXT_SETUP_REQ(msg_p).nr_security_capabilities.encryption_algorithms; ue_context_p->ue_context.nr_security.integrity_algorithms = S1AP_INITIAL_CONTEXT_SETUP_REQ(msg_p).nr_security_capabilities.integrity_algorithms; /* let's initialize sk_counter to 0 */ ue_context_p->ue_context.nr_security.sk_counter = 0; /* let's compute kgNB */ derive_skgNB(ue_context_p->ue_context.kenb, ue_context_p->ue_context.nr_security.sk_counter, ue_context_p->ue_context.nr_security.kgNB); // in case, send the S1SP initial context response if it is not sent with the attach complete message if (ue_context_p->ue_context.StatusRrc == RRC_RECONFIGURED) { LOG_I(RRC, "Sending rrc_eNB_send_S1AP_INITIAL_CONTEXT_SETUP_RESP, cause %ld\n", ue_context_p->ue_context.reestablishment_cause); //if(ue_context_p->ue_context.reestablishment_cause == ReestablishmentCause_spare1){} rrc_eNB_send_S1AP_INITIAL_CONTEXT_SETUP_RESP(&ctxt,ue_context_p); } if ((RC.rrc[ctxt.module_id]->node_type == ngran_eNB_CU) || (RC.rrc[ctxt.module_id]->node_type == ngran_ng_eNB_CU) || (RC.rrc[ctxt.module_id]->node_type == ngran_gNB_CU) ){ struct eNB_RRC_INST_s *rrc= RC.rrc[0]; MessageDef *message_p = itti_alloc_new_message (TASK_RRC_ENB, 0, F1AP_UE_CONTEXT_SETUP_REQ); f1ap_ue_context_setup_t *req=&F1AP_UE_CONTEXT_SETUP_REQ (message_p); req->gNB_CU_ue_id = 0; req->gNB_DU_ue_id = 0; req->rnti = ue_context_p->ue_context.rnti; req->mcc = rrc->configuration.mcc[0]; req->mnc = rrc->configuration.mnc[0]; req->mnc_digit_length = rrc->configuration.mnc_digit_length[0]; req->nr_cellid = rrc->nr_cellid; req->srbs_to_be_setup = malloc(sizeof(f1ap_srb_to_be_setup_t)); req->srbs_to_be_setup_length = 1; f1ap_srb_to_be_setup_t *SRBs=req->srbs_to_be_setup; SRBs[0].srb_id=CCCH; req->drbs_to_be_setup_length = S1AP_INITIAL_CONTEXT_SETUP_REQ (msg_p).nb_of_e_rabs; req->drbs_to_be_setup = malloc(req->drbs_to_be_setup_length * sizeof(f1ap_drb_to_be_setup_t)); f1ap_drb_to_be_setup_t *DRBs=req->drbs_to_be_setup; for (int i = 0; i < req->drbs_to_be_setup_length ; i++) { DRBs[i].drb_id=S1AP_INITIAL_CONTEXT_SETUP_REQ (msg_p).e_rab_param[i].e_rab_id; DRBs[i].rlc_mode = RLC_MODE_AM; DRBs[i].up_ul_tnl[0].tl_address = inet_addr(rrc->eth_params_s.my_addr); DRBs[i].up_ul_tnl[0].port=rrc->eth_params_s.my_portd; DRBs[i].up_ul_tnl_length = 1; DRBs[i].up_dl_tnl[0].tl_address = inet_addr(rrc->eth_params_s.remote_addr); DRBs[i].up_dl_tnl[0].port=rrc->eth_params_s.remote_portd; DRBs[i].up_dl_tnl_length = 1; } LOG_I(RRC, "Send F1AP_UE_CONTEXT_SETUP_REQ with ITTI\n"); itti_send_msg_to_task (TASK_CU_F1, 0, message_p); } } return (0); } /*------------------------------------------------------------------------------*/ int rrc_eNB_process_S1AP_UE_CTXT_MODIFICATION_REQ(MessageDef *msg_p, const char *msg_name, instance_t instance) { uint32_t eNB_ue_s1ap_id; struct rrc_eNB_ue_context_s *ue_context_p = NULL; protocol_ctxt_t ctxt; eNB_ue_s1ap_id = S1AP_UE_CTXT_MODIFICATION_REQ (msg_p).eNB_ue_s1ap_id; ue_context_p = rrc_eNB_get_ue_context_from_s1ap_ids(instance, UE_INITIAL_ID_INVALID, eNB_ue_s1ap_id); if (ue_context_p == NULL) { /* Can not associate this message to an UE index, send a failure to S1AP and discard it! */ MessageDef *msg_fail_p; LOG_W(RRC, "[eNB %ld] In S1AP_UE_CTXT_MODIFICATION_REQ: unknown UE from eNB_ue_s1ap_id (%d)\n", instance, eNB_ue_s1ap_id); msg_fail_p = itti_alloc_new_message (TASK_RRC_ENB, 0, S1AP_UE_CTXT_MODIFICATION_FAIL); S1AP_UE_CTXT_MODIFICATION_FAIL (msg_fail_p).eNB_ue_s1ap_id = eNB_ue_s1ap_id; // TODO add failure cause when defined! itti_send_msg_to_task (TASK_S1AP, instance, msg_fail_p); return (-1); } else { PROTOCOL_CTXT_SET_BY_INSTANCE(&ctxt, instance, ENB_FLAG_YES, ue_context_p->ue_context.rnti, 0, 0); /* TODO parameters yet to process ... */ { if (S1AP_UE_CTXT_MODIFICATION_REQ(msg_p).present & S1AP_UE_CONTEXT_MODIFICATION_UE_AMBR) { // S1AP_UE_CTXT_MODIFICATION_REQ(msg_p).ue_ambr; } } if (S1AP_UE_CTXT_MODIFICATION_REQ(msg_p).present & S1AP_UE_CONTEXT_MODIFICATION_UE_SECU_CAP) { if (rrc_eNB_process_security ( &ctxt, ue_context_p, &S1AP_UE_CTXT_MODIFICATION_REQ(msg_p).security_capabilities)) { /* transmit the new security parameters to UE */ rrc_eNB_generate_SecurityModeCommand ( &ctxt, ue_context_p); } } if (S1AP_UE_CTXT_MODIFICATION_REQ(msg_p).present & S1AP_UE_CONTEXT_MODIFICATION_SECURITY_KEY) { process_eNB_security_key ( &ctxt, ue_context_p, S1AP_UE_CTXT_MODIFICATION_REQ(msg_p).security_key); /* TODO reconfigure lower layers... */ } /* Send the response */ { MessageDef *msg_resp_p; msg_resp_p = itti_alloc_new_message(TASK_RRC_ENB, 0, S1AP_UE_CTXT_MODIFICATION_RESP); S1AP_UE_CTXT_MODIFICATION_RESP(msg_resp_p).eNB_ue_s1ap_id = eNB_ue_s1ap_id; itti_send_msg_to_task(TASK_S1AP, instance, msg_resp_p); } return (0); } } /*------------------------------------------------------------------------------*/ int rrc_eNB_process_S1AP_UE_CONTEXT_RELEASE_REQ (MessageDef *msg_p, const char *msg_name, instance_t instance) { uint32_t eNB_ue_s1ap_id; struct rrc_eNB_ue_context_s *ue_context_p = NULL; eNB_ue_s1ap_id = S1AP_UE_CONTEXT_RELEASE_REQ(msg_p).eNB_ue_s1ap_id; ue_context_p = rrc_eNB_get_ue_context_from_s1ap_ids(instance, UE_INITIAL_ID_INVALID, eNB_ue_s1ap_id); if (ue_context_p == NULL) { /* Can not associate this message to an UE index, send a failure to S1AP and discard it! */ MessageDef *msg_fail_p; LOG_W(RRC, "[eNB %ld] In S1AP_UE_CONTEXT_RELEASE_REQ: unknown UE from eNB_ue_s1ap_id (%d)\n", instance, eNB_ue_s1ap_id); msg_fail_p = itti_alloc_new_message(TASK_RRC_ENB, 0, S1AP_UE_CONTEXT_RELEASE_RESP); /* TODO change message ID. */ S1AP_UE_CONTEXT_RELEASE_RESP(msg_fail_p).eNB_ue_s1ap_id = eNB_ue_s1ap_id; // TODO add failure cause when defined! itti_send_msg_to_task(TASK_S1AP, instance, msg_fail_p); return (-1); } else { /* TODO release context. */ /* Send the response */ { MessageDef *msg_resp_p; msg_resp_p = itti_alloc_new_message(TASK_RRC_ENB, 0, S1AP_UE_CONTEXT_RELEASE_RESP); S1AP_UE_CONTEXT_RELEASE_RESP(msg_resp_p).eNB_ue_s1ap_id = eNB_ue_s1ap_id; itti_send_msg_to_task(TASK_S1AP, instance, msg_resp_p); } return (0); } } //------------------------------------------------------------------------------ /* * Send the S1 command UE_CONTEXT_RELEASE_REQUEST to the MME. */ void rrc_eNB_send_S1AP_UE_CONTEXT_RELEASE_REQ( const module_id_t enb_mod_idP, const rrc_eNB_ue_context_t *const ue_context_pP, const s1ap_Cause_t causeP, const long cause_valueP) //------------------------------------------------------------------------------ { if (ue_context_pP == NULL) { LOG_E(RRC, "[eNB] In S1AP_UE_CONTEXT_RELEASE_REQ: invalid UE\n"); } else { MSC_LOG_TX_MESSAGE(MSC_RRC_ENB, MSC_S1AP_ENB, NULL, 0, "0 S1AP_UE_CONTEXT_RELEASE_REQ eNB_ue_s1ap_id 0x%06"PRIX32" ", ue_context_pP->ue_context.eNB_ue_s1ap_id); MessageDef *msg_context_release_req_p = NULL; msg_context_release_req_p = itti_alloc_new_message(TASK_RRC_ENB, 0, S1AP_UE_CONTEXT_RELEASE_REQ); S1AP_UE_CONTEXT_RELEASE_REQ(msg_context_release_req_p).eNB_ue_s1ap_id = ue_context_pP->ue_context.eNB_ue_s1ap_id; S1AP_UE_CONTEXT_RELEASE_REQ(msg_context_release_req_p).cause = causeP; S1AP_UE_CONTEXT_RELEASE_REQ(msg_context_release_req_p).cause_value = cause_valueP; itti_send_msg_to_task(TASK_S1AP, ENB_MODULE_ID_TO_INSTANCE(enb_mod_idP), msg_context_release_req_p); } } void rrc_eNB_send_S1AP_UE_CONTEXT_RELEASE_CPLT( module_id_t enb_mod_idP, uint32_t eNB_ue_s1ap_id ) { MSC_LOG_TX_MESSAGE(MSC_RRC_ENB, MSC_S1AP_ENB, NULL, 0, "0 S1AP_UE_CONTEXT_RELEASE_COMPLETE eNB_ue_s1ap_id 0x%06"PRIX32" ", eNB_ue_s1ap_id); MessageDef *msg = itti_alloc_new_message(TASK_RRC_ENB, 0, S1AP_UE_CONTEXT_RELEASE_COMPLETE); S1AP_UE_CONTEXT_RELEASE_COMPLETE(msg).eNB_ue_s1ap_id = eNB_ue_s1ap_id; itti_send_msg_to_task(TASK_S1AP, ENB_MODULE_ID_TO_INSTANCE(enb_mod_idP), msg); } //----------------------------------------------------------------------------- /* * Process the S1 command UE_CONTEXT_RELEASE_COMMAND, sent by MME. * The eNB should remove all e-rab, S1 context, and other context of the UE. */ int rrc_eNB_process_S1AP_UE_CONTEXT_RELEASE_COMMAND( MessageDef *msg_p, const char *msg_name, instance_t instance) { //----------------------------------------------------------------------------- uint32_t eNB_ue_s1ap_id = 0; protocol_ctxt_t ctxt; struct rrc_eNB_ue_context_s *ue_context_p = NULL; struct rrc_ue_s1ap_ids_s *rrc_ue_s1ap_ids = NULL; eNB_ue_s1ap_id = S1AP_UE_CONTEXT_RELEASE_COMMAND(msg_p).eNB_ue_s1ap_id; ue_context_p = rrc_eNB_get_ue_context_from_s1ap_ids(instance, UE_INITIAL_ID_INVALID, eNB_ue_s1ap_id); if (ue_context_p == NULL) { /* Can not associate this message to an UE index */ MessageDef *msg_complete_p = NULL; LOG_W(RRC, "[eNB %ld] In S1AP_UE_CONTEXT_RELEASE_COMMAND: unknown UE from eNB_ue_s1ap_id (%d)\n", instance, eNB_ue_s1ap_id); MSC_LOG_EVENT(MSC_RRC_ENB, "0 S1AP_UE_CONTEXT_RELEASE_COMPLETE eNB_ue_s1ap_id 0x%06"PRIX32" context not found", eNB_ue_s1ap_id); MSC_LOG_TX_MESSAGE(MSC_RRC_ENB, MSC_S1AP_ENB, NULL, 0, "0 S1AP_UE_CONTEXT_RELEASE_COMPLETE eNB_ue_s1ap_id 0x%06"PRIX32" ", eNB_ue_s1ap_id); msg_complete_p = itti_alloc_new_message(TASK_RRC_ENB, 0, S1AP_UE_CONTEXT_RELEASE_COMPLETE); S1AP_UE_CONTEXT_RELEASE_COMPLETE(msg_complete_p).eNB_ue_s1ap_id = eNB_ue_s1ap_id; itti_send_msg_to_task(TASK_S1AP, instance, msg_complete_p); rrc_ue_s1ap_ids = rrc_eNB_S1AP_get_ue_ids(RC.rrc[instance], UE_INITIAL_ID_INVALID, eNB_ue_s1ap_id); if (rrc_ue_s1ap_ids != NULL) { rrc_eNB_S1AP_remove_ue_ids(RC.rrc[instance], rrc_ue_s1ap_ids); } return -1; } else { ue_context_p->ue_context.ue_release_timer_s1 = 0; PROTOCOL_CTXT_SET_BY_INSTANCE(&ctxt, instance, ENB_FLAG_YES, ue_context_p->ue_context.rnti, 0, 0); rrc_eNB_generate_RRCConnectionRelease(&ctxt, ue_context_p); return 0; } } int rrc_eNB_process_S1AP_E_RAB_SETUP_REQ(MessageDef *msg_p, const char *msg_name, instance_t instance) { uint16_t ue_initial_id; uint32_t eNB_ue_s1ap_id; gtpv1u_enb_create_tunnel_req_t create_tunnel_req; gtpv1u_enb_create_tunnel_resp_t create_tunnel_resp; uint8_t inde_list[NB_RB_MAX - 3]= {0}; struct rrc_eNB_ue_context_s *ue_context_p = NULL; protocol_ctxt_t ctxt; uint8_t e_rab_done; int ret = 0; ue_initial_id = S1AP_E_RAB_SETUP_REQ (msg_p).ue_initial_id; eNB_ue_s1ap_id = S1AP_E_RAB_SETUP_REQ (msg_p).eNB_ue_s1ap_id; ue_context_p = rrc_eNB_get_ue_context_from_s1ap_ids(instance, ue_initial_id, eNB_ue_s1ap_id); LOG_I(RRC, "[eNB %ld] Received %s: ue_initial_id %d, eNB_ue_s1ap_id %d, nb_of_e_rabs %d\n", instance, msg_name, ue_initial_id, eNB_ue_s1ap_id, S1AP_E_RAB_SETUP_REQ (msg_p).nb_e_rabs_tosetup); if (ue_context_p == NULL) { /* Can not associate this message to an UE index, send a failure to S1AP and discard it! */ MessageDef *msg_fail_p = NULL; LOG_W(RRC, "[eNB %ld] In S1AP_E_RAB_SETUP_REQ: unknown UE from S1AP ids (%d, %d)\n", instance, ue_initial_id, eNB_ue_s1ap_id); msg_fail_p = itti_alloc_new_message (TASK_RRC_ENB, 0, S1AP_E_RAB_SETUP_REQUEST_FAIL); S1AP_E_RAB_SETUP_REQ (msg_fail_p).eNB_ue_s1ap_id = eNB_ue_s1ap_id; // TODO add failure cause when defined! itti_send_msg_to_task (TASK_S1AP, instance, msg_fail_p); return (-1); } else { PROTOCOL_CTXT_SET_BY_INSTANCE(&ctxt, instance, ENB_FLAG_YES, ue_context_p->ue_context.rnti, 0, 0); ue_context_p->ue_context.eNB_ue_s1ap_id = S1AP_E_RAB_SETUP_REQ (msg_p).eNB_ue_s1ap_id; /* Save e RAB information for later */ { int i; memset(&create_tunnel_req, 0, sizeof(create_tunnel_req)); uint8_t nb_e_rabs_tosetup = S1AP_E_RAB_SETUP_REQ (msg_p).nb_e_rabs_tosetup; e_rab_done = 0; // keep the previous bearer // the index for the rec for (i = 0; // i < nb_e_rabs_tosetup; i < NB_RB_MAX - 3; // loop all e-rabs in e_rab[] i++) { //if (ue_context_p->ue_context.e_rab[i+ue_context_p->ue_context.setup_e_rabs].status == E_RAB_STATUS_DONE) // LOG_W(RRC,"E-RAB already configured, reconfiguring\n"); // check e-rab status, if e rab status is greater than E_RAB_STATUS_DONE, don't not config this one if(ue_context_p->ue_context.e_rab[i].status >= E_RAB_STATUS_DONE) continue; //ue_context_p->ue_context.e_rab[i+ue_context_p->ue_context.setup_e_rabs].status = E_RAB_STATUS_NEW; //ue_context_p->ue_context.e_rab[i+ue_context_p->ue_context.setup_e_rabs].param = S1AP_E_RAB_SETUP_REQ (msg_p).e_rab_setup_params[i]; ue_context_p->ue_context.e_rab[i].status = E_RAB_STATUS_NEW; ue_context_p->ue_context.e_rab[i].param = S1AP_E_RAB_SETUP_REQ (msg_p).e_rab_setup_params[e_rab_done]; create_tunnel_req.eps_bearer_id[e_rab_done] = S1AP_E_RAB_SETUP_REQ (msg_p).e_rab_setup_params[e_rab_done].e_rab_id; create_tunnel_req.sgw_S1u_teid[e_rab_done] = S1AP_E_RAB_SETUP_REQ (msg_p).e_rab_setup_params[e_rab_done].gtp_teid; memcpy(&create_tunnel_req.sgw_addr[e_rab_done], & S1AP_E_RAB_SETUP_REQ (msg_p).e_rab_setup_params[e_rab_done].sgw_addr, sizeof(transport_layer_addr_t)); LOG_I(RRC,"E_RAB setup REQ: local index %d teid %u, eps id %d \n", i, create_tunnel_req.sgw_S1u_teid[e_rab_done], create_tunnel_req.eps_bearer_id[i] ); inde_list[e_rab_done] = i; e_rab_done++; if(e_rab_done >= nb_e_rabs_tosetup) { break; } } ue_context_p->ue_context.nb_of_e_rabs=nb_e_rabs_tosetup; create_tunnel_req.rnti = ue_context_p->ue_context.rnti; // warning put zero above create_tunnel_req.num_tunnels = e_rab_done; // NN: not sure if we should create a new tunnel: need to check teid, etc. ret = gtpv1u_create_s1u_tunnel( instance, &create_tunnel_req, &create_tunnel_resp); if ( ret != 0 ) { LOG_E(RRC,"rrc_eNB_process_S1AP_E_RAB_SETUP_REQ : gtpv1u_create_s1u_tunnel failed,start to release UE %x\n",ue_context_p->ue_context.rnti); ue_context_p->ue_context.ue_release_timer_s1 = 1; ue_context_p->ue_context.ue_release_timer_thres_s1 = 100; ue_context_p->ue_context.ue_release_timer = 0; ue_context_p->ue_context.ue_reestablishment_timer = 0; ue_context_p->ue_context.ul_failure_timer = 20000; // set ul_failure to 20000 for triggering rrc_eNB_send_S1AP_UE_CONTEXT_RELEASE_REQ rrc_eNB_free_UE(ctxt.module_id,ue_context_p); ue_context_p->ue_context.ul_failure_timer = 0; return (0); } rrc_eNB_process_GTPV1U_CREATE_TUNNEL_RESP( &ctxt, &create_tunnel_resp, &inde_list[0]); ue_context_p->ue_context.setup_e_rabs+=nb_e_rabs_tosetup; } /* TODO parameters yet to process ... */ { // S1AP_INITIAL_CONTEXT_SETUP_REQ(msg_p).ue_ambr; } rrc_eNB_generate_dedicatedRRCConnectionReconfiguration(&ctxt, ue_context_p, 0); return (0); } } /*NN: careful about the typcast of xid (long -> uint8_t*/ int rrc_eNB_send_S1AP_E_RAB_SETUP_RESP(const protocol_ctxt_t *const ctxt_pP, rrc_eNB_ue_context_t *const ue_context_pP, uint8_t xid ) { MessageDef *msg_p = NULL; int e_rab; int e_rabs_done = 0; int e_rabs_failed = 0; msg_p = itti_alloc_new_message (TASK_RRC_ENB, 0, S1AP_E_RAB_SETUP_RESP); S1AP_E_RAB_SETUP_RESP (msg_p).eNB_ue_s1ap_id = ue_context_pP->ue_context.eNB_ue_s1ap_id; for (e_rab = 0; e_rab < ue_context_pP->ue_context.setup_e_rabs ; e_rab++) { /* only respond to the corresponding transaction */ //if (((xid+1)%4) == ue_context_pP->ue_context.e_rab[e_rab].xid) { if (xid == ue_context_pP->ue_context.e_rab[e_rab].xid) { if (ue_context_pP->ue_context.e_rab[e_rab].status == E_RAB_STATUS_DONE) { S1AP_E_RAB_SETUP_RESP (msg_p).e_rabs[e_rabs_done].e_rab_id = ue_context_pP->ue_context.e_rab[e_rab].param.e_rab_id; // TODO add other information from S1-U when it will be integrated S1AP_E_RAB_SETUP_RESP (msg_p).e_rabs[e_rabs_done].gtp_teid = ue_context_pP->ue_context.enb_gtp_teid[e_rab]; S1AP_E_RAB_SETUP_RESP (msg_p).e_rabs[e_rabs_done].eNB_addr = ue_context_pP->ue_context.enb_gtp_addrs[e_rab]; //S1AP_E_RAB_SETUP_RESP (msg_p).e_rabs[e_rab].eNB_addr.length += 4; ue_context_pP->ue_context.e_rab[e_rab].status = E_RAB_STATUS_ESTABLISHED; LOG_I (RRC,"enb_gtp_addr (msg index %d, e_rab index %d, status %d, xid %d): nb_of_e_rabs %d, e_rab_id %d, teid: %u, addr: %d.%d.%d.%d \n ", e_rabs_done, e_rab, ue_context_pP->ue_context.e_rab[e_rab].status, xid, ue_context_pP->ue_context.nb_of_e_rabs, S1AP_E_RAB_SETUP_RESP (msg_p).e_rabs[e_rabs_done].e_rab_id, S1AP_E_RAB_SETUP_RESP (msg_p).e_rabs[e_rabs_done].gtp_teid, S1AP_E_RAB_SETUP_RESP (msg_p).e_rabs[e_rabs_done].eNB_addr.buffer[0], S1AP_E_RAB_SETUP_RESP (msg_p).e_rabs[e_rabs_done].eNB_addr.buffer[1], S1AP_E_RAB_SETUP_RESP (msg_p).e_rabs[e_rabs_done].eNB_addr.buffer[2], S1AP_E_RAB_SETUP_RESP (msg_p).e_rabs[e_rabs_done].eNB_addr.buffer[3]); e_rabs_done++; } else if ((ue_context_pP->ue_context.e_rab[e_rab].status == E_RAB_STATUS_NEW) || (ue_context_pP->ue_context.e_rab[e_rab].status == E_RAB_STATUS_ESTABLISHED)) { LOG_D (RRC,"E-RAB is NEW or already ESTABLISHED\n"); } else { /* to be improved */ ue_context_pP->ue_context.e_rab[e_rab].status = E_RAB_STATUS_FAILED; S1AP_E_RAB_SETUP_RESP (msg_p).e_rabs_failed[e_rabs_failed].e_rab_id = ue_context_pP->ue_context.e_rab[e_rab].param.e_rab_id; e_rabs_failed++; // TODO add cause when it will be integrated } S1AP_E_RAB_SETUP_RESP (msg_p).nb_of_e_rabs = e_rabs_done; S1AP_E_RAB_SETUP_RESP (msg_p).nb_of_e_rabs_failed = e_rabs_failed; // NN: add conditions for e_rabs_failed } else { /*debug info for the xid */ LOG_D(RRC,"xid does not corresponds (context e_rab index %d, status %d, xid %d/%d) \n ", e_rab, ue_context_pP->ue_context.e_rab[e_rab].status, xid, ue_context_pP->ue_context.e_rab[e_rab].xid); } } if ((e_rabs_done > 0) ) { LOG_I(RRC,"S1AP_E_RAB_SETUP_RESP: sending the message: nb_of_erabs %d, total e_rabs %d, index %d\n", ue_context_pP->ue_context.nb_of_e_rabs, ue_context_pP->ue_context.setup_e_rabs, e_rab); MSC_LOG_TX_MESSAGE( MSC_RRC_ENB, MSC_S1AP_ENB, (const char *)&S1AP_E_RAB_SETUP_RESP (msg_p), sizeof(s1ap_e_rab_setup_resp_t), MSC_AS_TIME_FMT" E_RAB_SETUP_RESP UE %X eNB_ue_s1ap_id %u e_rabs:%u succ %u fail", MSC_AS_TIME_ARGS(ctxt_pP), ue_context_pP->ue_id_rnti, S1AP_E_RAB_SETUP_RESP (msg_p).eNB_ue_s1ap_id, e_rabs_done, e_rabs_failed); itti_send_msg_to_task (TASK_S1AP, ctxt_pP->instance, msg_p); } for(int i = 0; i < NB_RB_MAX; i++) { ue_context_pP->ue_context.e_rab[i].xid = -1; } return 0; } int rrc_eNB_process_S1AP_E_RAB_MODIFY_REQ(MessageDef *msg_p, const char *msg_name, instance_t instance) { int i; uint16_t ue_initial_id; uint32_t eNB_ue_s1ap_id; struct rrc_eNB_ue_context_s *ue_context_p = NULL; protocol_ctxt_t ctxt; ue_initial_id = S1AP_E_RAB_MODIFY_REQ (msg_p).ue_initial_id; eNB_ue_s1ap_id = S1AP_E_RAB_MODIFY_REQ (msg_p).eNB_ue_s1ap_id; ue_context_p = rrc_eNB_get_ue_context_from_s1ap_ids(instance, ue_initial_id, eNB_ue_s1ap_id); LOG_D(RRC, "[eNB %ld] Received %s: ue_initial_id %d, eNB_ue_s1ap_id %d, nb_of_e_rabs %d\n", instance, msg_name, ue_initial_id, eNB_ue_s1ap_id, S1AP_E_RAB_MODIFY_REQ (msg_p).nb_e_rabs_tomodify); if (ue_context_p == NULL) { /* Can not associate this message to an UE index, send a failure to S1AP and discard it! */ LOG_W(RRC, "[eNB %ld] In S1AP_E_RAB_MODIFY_REQ: unknown UE from S1AP ids (%d, %d)\n", instance, ue_initial_id, eNB_ue_s1ap_id); int nb_of_e_rabs_failed = 0; MessageDef *msg_fail_p = NULL; msg_fail_p = itti_alloc_new_message (TASK_RRC_ENB, 0, S1AP_E_RAB_MODIFY_RESP); S1AP_E_RAB_MODIFY_RESP (msg_fail_p).eNB_ue_s1ap_id = S1AP_E_RAB_MODIFY_REQ (msg_p).eNB_ue_s1ap_id; S1AP_E_RAB_MODIFY_RESP (msg_fail_p).nb_of_e_rabs = 0; for (nb_of_e_rabs_failed = 0; nb_of_e_rabs_failed < S1AP_E_RAB_MODIFY_REQ (msg_p).nb_e_rabs_tomodify; nb_of_e_rabs_failed++) { S1AP_E_RAB_MODIFY_RESP (msg_fail_p).e_rabs_failed[nb_of_e_rabs_failed].e_rab_id = S1AP_E_RAB_MODIFY_REQ (msg_p).e_rab_modify_params[nb_of_e_rabs_failed].e_rab_id; S1AP_E_RAB_MODIFY_RESP (msg_fail_p).e_rabs_failed[nb_of_e_rabs_failed].cause = S1AP_CAUSE_RADIO_NETWORK; S1AP_E_RAB_MODIFY_RESP (msg_fail_p).e_rabs_failed[nb_of_e_rabs_failed].cause_value = 31;//S1ap_CauseRadioNetwork_multiple_E_RAB_ID_instances; } S1AP_E_RAB_MODIFY_RESP (msg_fail_p).nb_of_e_rabs_failed = nb_of_e_rabs_failed; itti_send_msg_to_task(TASK_S1AP, instance, msg_fail_p); return (-1); } else { PROTOCOL_CTXT_SET_BY_INSTANCE(&ctxt, instance, ENB_FLAG_YES, ue_context_p->ue_context.rnti, 0, 0); ue_context_p->ue_context.eNB_ue_s1ap_id = eNB_ue_s1ap_id; /* Save e RAB information for later */ { int j; boolean_t is_treated[S1AP_MAX_E_RAB] = {FALSE}; uint8_t nb_of_failed_e_rabs = 0; // keep the previous bearer // the index for the rec for (i = 0; i < S1AP_E_RAB_MODIFY_REQ (msg_p).nb_e_rabs_tomodify; i++) { if (is_treated[i] == TRUE) { // already treated continue; } for (j = i+1; j < S1AP_E_RAB_MODIFY_REQ (msg_p).nb_e_rabs_tomodify; j++) { if (is_treated[j] == FALSE && S1AP_E_RAB_MODIFY_REQ(msg_p).e_rab_modify_params[j].e_rab_id == S1AP_E_RAB_MODIFY_REQ(msg_p).e_rab_modify_params[i].e_rab_id) { // handle multiple E-RAB ID ue_context_p->ue_context.modify_e_rab[j].status = E_RAB_STATUS_NEW; ue_context_p->ue_context.modify_e_rab[j].param.e_rab_id = S1AP_E_RAB_MODIFY_REQ(msg_p).e_rab_modify_params[j].e_rab_id; ue_context_p->ue_context.modify_e_rab[j].cause = S1AP_CAUSE_RADIO_NETWORK; ue_context_p->ue_context.modify_e_rab[j].cause_value = 31;//S1ap_CauseRadioNetwork_multiple_E_RAB_ID_instances; nb_of_failed_e_rabs++; is_treated[i] = TRUE; is_treated[j] = TRUE; } } if (is_treated[i] == TRUE) { // handle multiple E-RAB ID ue_context_p->ue_context.modify_e_rab[i].status = E_RAB_STATUS_NEW; ue_context_p->ue_context.modify_e_rab[i].param.e_rab_id = S1AP_E_RAB_MODIFY_REQ(msg_p).e_rab_modify_params[i].e_rab_id; ue_context_p->ue_context.modify_e_rab[i].cause = S1AP_CAUSE_RADIO_NETWORK; ue_context_p->ue_context.modify_e_rab[i].cause_value = 31;//S1ap_CauseRadioNetwork_multiple_E_RAB_ID_instances; nb_of_failed_e_rabs++; continue; } if (S1AP_E_RAB_MODIFY_REQ(msg_p).e_rab_modify_params[i].nas_pdu.length == 0) { // nas_pdu.length == 0 ue_context_p->ue_context.modify_e_rab[i].status = E_RAB_STATUS_NEW; ue_context_p->ue_context.modify_e_rab[i].param.e_rab_id = S1AP_E_RAB_MODIFY_REQ(msg_p).e_rab_modify_params[i].e_rab_id; ue_context_p->ue_context.modify_e_rab[i].cause = S1AP_CAUSE_NAS; ue_context_p->ue_context.modify_e_rab[i].cause_value = 3;//S1ap_CauseNas_unspecified; nb_of_failed_e_rabs++; is_treated[i] = TRUE; continue; } for (j = 0; j < NB_RB_MAX-3; j++) { if (ue_context_p->ue_context.e_rab[j].param.e_rab_id == S1AP_E_RAB_MODIFY_REQ(msg_p).e_rab_modify_params[i].e_rab_id) { if(ue_context_p->ue_context.e_rab[j].status == E_RAB_STATUS_TORELEASE || ue_context_p->ue_context.e_rab[j].status == E_RAB_STATUS_DONE) { break; } ue_context_p->ue_context.modify_e_rab[i].status = E_RAB_STATUS_NEW; ue_context_p->ue_context.modify_e_rab[i].cause = S1AP_CAUSE_NOTHING; ue_context_p->ue_context.modify_e_rab[i].param.e_rab_id = S1AP_E_RAB_MODIFY_REQ(msg_p).e_rab_modify_params[i].e_rab_id; ue_context_p->ue_context.modify_e_rab[i].param.qos = S1AP_E_RAB_MODIFY_REQ(msg_p).e_rab_modify_params[i].qos; ue_context_p->ue_context.modify_e_rab[i].param.nas_pdu.length = S1AP_E_RAB_MODIFY_REQ(msg_p).e_rab_modify_params[i].nas_pdu.length; ue_context_p->ue_context.modify_e_rab[i].param.nas_pdu.buffer = S1AP_E_RAB_MODIFY_REQ(msg_p).e_rab_modify_params[i].nas_pdu.buffer; ue_context_p->ue_context.modify_e_rab[i].param.sgw_addr = ue_context_p->ue_context.e_rab[j].param.sgw_addr; ue_context_p->ue_context.modify_e_rab[i].param.gtp_teid = ue_context_p->ue_context.e_rab[j].param.gtp_teid; is_treated[i] = TRUE; break; } } if (is_treated[i] == FALSE) { // handle Unknown E-RAB ID ue_context_p->ue_context.modify_e_rab[i].status = E_RAB_STATUS_NEW; ue_context_p->ue_context.modify_e_rab[i].param.e_rab_id = S1AP_E_RAB_MODIFY_REQ(msg_p).e_rab_modify_params[i].e_rab_id; ue_context_p->ue_context.modify_e_rab[i].cause = S1AP_CAUSE_RADIO_NETWORK; ue_context_p->ue_context.modify_e_rab[i].cause_value = 30;//S1ap_CauseRadioNetwork_unknown_E_RAB_ID; nb_of_failed_e_rabs++; is_treated[i] = TRUE; } } ue_context_p->ue_context.nb_of_modify_e_rabs = S1AP_E_RAB_MODIFY_REQ (msg_p).nb_e_rabs_tomodify; ue_context_p->ue_context.nb_of_failed_e_rabs = nb_of_failed_e_rabs; } /* TODO parameters yet to process ... */ { // S1AP_INITIAL_CONTEXT_SETUP_REQ(msg_p).ue_ambr; } if (ue_context_p->ue_context.nb_of_failed_e_rabs < ue_context_p->ue_context.nb_of_modify_e_rabs) { if (0 == rrc_eNB_modify_dedicatedRRCConnectionReconfiguration(&ctxt, ue_context_p, 0)) { return (0); } } { int nb_of_e_rabs_failed = 0; MessageDef *msg_fail_p = NULL; msg_fail_p = itti_alloc_new_message (TASK_RRC_ENB, 0, S1AP_E_RAB_MODIFY_RESP); S1AP_E_RAB_MODIFY_RESP (msg_fail_p).eNB_ue_s1ap_id = S1AP_E_RAB_MODIFY_REQ (msg_p).eNB_ue_s1ap_id; // S1AP_E_RAB_MODIFY_RESP (msg_fail_p).e_rabs[S1AP_MAX_E_RAB]; S1AP_E_RAB_MODIFY_RESP (msg_fail_p).nb_of_e_rabs = 0; for(nb_of_e_rabs_failed = 0; nb_of_e_rabs_failed < ue_context_p->ue_context.nb_of_failed_e_rabs; nb_of_e_rabs_failed++) { S1AP_E_RAB_MODIFY_RESP (msg_fail_p).e_rabs_failed[nb_of_e_rabs_failed].e_rab_id = ue_context_p->ue_context.modify_e_rab[nb_of_e_rabs_failed].param.e_rab_id; S1AP_E_RAB_MODIFY_RESP (msg_fail_p).e_rabs_failed[nb_of_e_rabs_failed].cause = ue_context_p->ue_context.modify_e_rab[nb_of_e_rabs_failed].cause; } S1AP_E_RAB_MODIFY_RESP (msg_fail_p).nb_of_e_rabs_failed = nb_of_e_rabs_failed; itti_send_msg_to_task (TASK_S1AP, instance, msg_fail_p); ue_context_p->ue_context.nb_of_modify_e_rabs = 0; ue_context_p->ue_context.nb_of_failed_e_rabs = 0; memset(ue_context_p->ue_context.modify_e_rab, 0, sizeof(ue_context_p->ue_context.modify_e_rab)); return (0); } } // end of ue_context_p != NULL } /*NN: careful about the typcast of xid (long -> uint8_t*/ int rrc_eNB_send_S1AP_E_RAB_MODIFY_RESP(const protocol_ctxt_t *const ctxt_pP, rrc_eNB_ue_context_t *const ue_context_pP, uint8_t xid ) { MessageDef *msg_p = NULL; int i; int e_rab; int e_rabs_done = 0; int e_rabs_failed = 0; msg_p = itti_alloc_new_message (TASK_RRC_ENB, 0, S1AP_E_RAB_MODIFY_RESP); S1AP_E_RAB_MODIFY_RESP (msg_p).eNB_ue_s1ap_id = ue_context_pP->ue_context.eNB_ue_s1ap_id; for (e_rab = 0; e_rab < ue_context_pP->ue_context.nb_of_modify_e_rabs; e_rab++) { /* only respond to the corresponding transaction */ if (xid == ue_context_pP->ue_context.modify_e_rab[e_rab].xid) { if (ue_context_pP->ue_context.modify_e_rab[e_rab].status == E_RAB_STATUS_DONE) { for (i = 0; i < ue_context_pP->ue_context.setup_e_rabs; i++) { if (ue_context_pP->ue_context.modify_e_rab[e_rab].param.e_rab_id == ue_context_pP->ue_context.e_rab[i].param.e_rab_id) { // Update ue_context_pP->ue_context.e_rab ue_context_pP->ue_context.e_rab[i].status = E_RAB_STATUS_ESTABLISHED; ue_context_pP->ue_context.e_rab[i].param.qos = ue_context_pP->ue_context.modify_e_rab[e_rab].param.qos; ue_context_pP->ue_context.e_rab[i].cause = S1AP_CAUSE_NOTHING; break; } } if (i < ue_context_pP->ue_context.setup_e_rabs) { S1AP_E_RAB_MODIFY_RESP (msg_p).e_rabs[e_rabs_done].e_rab_id = ue_context_pP->ue_context.modify_e_rab[e_rab].param.e_rab_id; // TODO add other information from S1-U when it will be integrated LOG_D (RRC,"enb_gtp_addr (msg index %d, e_rab index %d, status %d, xid %d): nb_of_modify_e_rabs %d, e_rab_id %d \n ", e_rabs_done, e_rab, ue_context_pP->ue_context.modify_e_rab[e_rab].status, xid, ue_context_pP->ue_context.nb_of_modify_e_rabs, S1AP_E_RAB_MODIFY_RESP (msg_p).e_rabs[e_rabs_done].e_rab_id); e_rabs_done++; } else { // unexpected S1AP_E_RAB_MODIFY_RESP (msg_p).e_rabs_failed[e_rabs_failed].e_rab_id = ue_context_pP->ue_context.modify_e_rab[e_rab].param.e_rab_id; S1AP_E_RAB_MODIFY_RESP (msg_p).e_rabs_failed[e_rabs_failed].cause = S1AP_CAUSE_RADIO_NETWORK; S1AP_E_RAB_MODIFY_RESP (msg_p).e_rabs_failed[e_rabs_failed].cause_value = 30;//S1ap_CauseRadioNetwork_unknown_E_RAB_ID; e_rabs_failed++; } } else if ((ue_context_pP->ue_context.modify_e_rab[e_rab].status == E_RAB_STATUS_NEW) || (ue_context_pP->ue_context.modify_e_rab[e_rab].status == E_RAB_STATUS_ESTABLISHED)) { LOG_D (RRC,"E-RAB is NEW or already ESTABLISHED\n"); } else { /* status == E_RAB_STATUS_FAILED; */ S1AP_E_RAB_MODIFY_RESP (msg_p).e_rabs_failed[e_rabs_failed].e_rab_id = ue_context_pP->ue_context.modify_e_rab[e_rab].param.e_rab_id; // add failure cause when defined S1AP_E_RAB_MODIFY_RESP (msg_p).e_rabs_failed[e_rabs_failed].cause = ue_context_pP->ue_context.modify_e_rab[e_rab].cause; e_rabs_failed++; } } else { /*debug info for the xid */ LOG_D(RRC,"xid does not corresponds (context e_rab index %d, status %d, xid %d/%d) \n ", e_rab, ue_context_pP->ue_context.modify_e_rab[e_rab].status, xid, ue_context_pP->ue_context.modify_e_rab[e_rab].xid); } } S1AP_E_RAB_MODIFY_RESP (msg_p).nb_of_e_rabs = e_rabs_done; S1AP_E_RAB_MODIFY_RESP (msg_p).nb_of_e_rabs_failed = e_rabs_failed; // NN: add conditions for e_rabs_failed if (e_rabs_done > 0 || e_rabs_failed > 0) { LOG_D(RRC,"S1AP_E_RAB_MODIFY_RESP: sending the message: nb_of_modify_e_rabs %d, total e_rabs %d, index %d\n", ue_context_pP->ue_context.nb_of_modify_e_rabs, ue_context_pP->ue_context.setup_e_rabs, e_rab); MSC_LOG_TX_MESSAGE( MSC_RRC_ENB, MSC_S1AP_ENB, (const char *)&S1AP_E_RAB_SETUP_RESP (msg_p), sizeof(s1ap_e_rab_setup_resp_t), MSC_AS_TIME_FMT" E_RAB_MODIFY_RESP UE %X eNB_ue_s1ap_id %u e_rabs:%u succ %u fail", MSC_AS_TIME_ARGS(ctxt_pP), ue_context_pP->ue_id_rnti, S1AP_E_RAB_MODIFY_RESP (msg_p).eNB_ue_s1ap_id, e_rabs_done, e_rabs_failed); itti_send_msg_to_task (TASK_S1AP, ctxt_pP->instance, msg_p); } else { itti_free (ITTI_MSG_ORIGIN_ID(msg_p), msg_p); } return 0; } int rrc_eNB_process_S1AP_E_RAB_RELEASE_COMMAND(MessageDef *msg_p, const char *msg_name, instance_t instance) { uint32_t eNB_ue_s1ap_id; struct rrc_eNB_ue_context_s *ue_context_p = NULL; protocol_ctxt_t ctxt; e_rab_release_t e_rab_release_params[S1AP_MAX_E_RAB]; uint8_t nb_e_rabs_torelease; int erab; int i; uint8_t b_existed,is_existed; uint8_t xid; uint8_t e_rab_release_drb; e_rab_release_drb = 0; memcpy(&e_rab_release_params[0], &(S1AP_E_RAB_RELEASE_COMMAND (msg_p).e_rab_release_params[0]), sizeof(e_rab_release_t)*S1AP_MAX_E_RAB); eNB_ue_s1ap_id = S1AP_E_RAB_RELEASE_COMMAND (msg_p).eNB_ue_s1ap_id; nb_e_rabs_torelease = S1AP_E_RAB_RELEASE_COMMAND (msg_p).nb_e_rabs_torelease; if (nb_e_rabs_torelease > S1AP_MAX_E_RAB) { return -1; } ue_context_p = rrc_eNB_get_ue_context_from_s1ap_ids(instance, UE_INITIAL_ID_INVALID, eNB_ue_s1ap_id); if(ue_context_p != NULL) { PROTOCOL_CTXT_SET_BY_INSTANCE(&ctxt, instance, ENB_FLAG_YES, ue_context_p->ue_context.rnti, 0, 0); xid = rrc_eNB_get_next_transaction_identifier(ctxt.module_id); LOG_D(RRC,"S1AP-E-RAB Release Command: MME_UE_S1AP_ID %d ENB_UE_S1AP_ID %d release_e_rabs %d \n", S1AP_E_RAB_RELEASE_COMMAND (msg_p).mme_ue_s1ap_id, eNB_ue_s1ap_id,nb_e_rabs_torelease); for(erab = 0; erab < nb_e_rabs_torelease; erab++) { b_existed = 0; is_existed = 0; for ( i = erab-1; i>= 0; i--) { if (e_rab_release_params[erab].e_rab_id == e_rab_release_params[i].e_rab_id) { is_existed = 1; break; } } if(is_existed == 1) { //e_rab_id is existed continue; } for ( i = 0; i < NB_RB_MAX; i++) { if (e_rab_release_params[erab].e_rab_id == ue_context_p->ue_context.e_rab[i].param.e_rab_id) { b_existed = 1; break; } } if(b_existed == 0) { //no e_rab_id ue_context_p->ue_context.e_rabs_release_failed[ue_context_p->ue_context.nb_release_of_e_rabs].e_rab_id = e_rab_release_params[erab].e_rab_id; ue_context_p->ue_context.e_rabs_release_failed[ue_context_p->ue_context.nb_release_of_e_rabs].cause = S1AP_CAUSE_RADIO_NETWORK; ue_context_p->ue_context.e_rabs_release_failed[ue_context_p->ue_context.nb_release_of_e_rabs].cause_value = 30; ue_context_p->ue_context.nb_release_of_e_rabs++; } else { if(ue_context_p->ue_context.e_rab[i].status == E_RAB_STATUS_FAILED) { ue_context_p->ue_context.e_rab[i].xid = xid; continue; } else if(ue_context_p->ue_context.e_rab[i].status == E_RAB_STATUS_ESTABLISHED) { ue_context_p->ue_context.e_rab[i].status = E_RAB_STATUS_TORELEASE; ue_context_p->ue_context.e_rab[i].xid = xid; e_rab_release_drb++; } else { //e_rab_id status NG ue_context_p->ue_context.e_rabs_release_failed[ue_context_p->ue_context.nb_release_of_e_rabs].e_rab_id = e_rab_release_params[erab].e_rab_id; ue_context_p->ue_context.e_rabs_release_failed[ue_context_p->ue_context.nb_release_of_e_rabs].cause = S1AP_CAUSE_RADIO_NETWORK; ue_context_p->ue_context.e_rabs_release_failed[ue_context_p->ue_context.nb_release_of_e_rabs].cause_value = 0; ue_context_p->ue_context.nb_release_of_e_rabs++; } } } if(e_rab_release_drb > 0) { //RRCConnectionReconfiguration To UE rrc_eNB_generate_dedicatedRRCConnectionReconfiguration_release(&ctxt, ue_context_p, xid, S1AP_E_RAB_RELEASE_COMMAND (msg_p).nas_pdu.length, S1AP_E_RAB_RELEASE_COMMAND (msg_p).nas_pdu.buffer); } else { //gtp tunnel delete gtpv1u_enb_delete_tunnel_req_t delete_tunnels={0}; delete_tunnels.rnti = ue_context_p->ue_context.rnti; delete_tunnels.from_gnb = 0; for(i = 0; i < NB_RB_MAX; i++) { if(xid == ue_context_p->ue_context.e_rab[i].xid) { delete_tunnels.eps_bearer_id[delete_tunnels.num_erab++] = ue_context_p->ue_context.enb_gtp_ebi[i]; ue_context_p->ue_context.enb_gtp_teid[i] = 0; memset(&ue_context_p->ue_context.enb_gtp_addrs[i], 0, sizeof(ue_context_p->ue_context.enb_gtp_addrs[i])); ue_context_p->ue_context.enb_gtp_ebi[i] = 0; } } gtpv1u_delete_s1u_tunnel(instance,&delete_tunnels); //S1AP_E_RAB_RELEASE_RESPONSE rrc_eNB_send_S1AP_E_RAB_RELEASE_RESPONSE(&ctxt, ue_context_p, xid); } } else { LOG_E(RRC,"S1AP-E-RAB Release Command: MME_UE_S1AP_ID %d ENB_UE_S1AP_ID %d Error ue_context_p NULL \n", S1AP_E_RAB_RELEASE_COMMAND (msg_p).mme_ue_s1ap_id, S1AP_E_RAB_RELEASE_COMMAND (msg_p).eNB_ue_s1ap_id); return -1; } return 0; } int rrc_eNB_send_S1AP_E_RAB_RELEASE_RESPONSE(const protocol_ctxt_t *const ctxt_pP, rrc_eNB_ue_context_t *const ue_context_pP, uint8_t xid) { int e_rabs_released = 0; MessageDef *msg_p; msg_p = itti_alloc_new_message (TASK_RRC_ENB, 0, S1AP_E_RAB_RELEASE_RESPONSE); S1AP_E_RAB_RELEASE_RESPONSE (msg_p).eNB_ue_s1ap_id = ue_context_pP->ue_context.eNB_ue_s1ap_id; for (int i = 0; i < NB_RB_MAX; i++) { if (xid == ue_context_pP->ue_context.e_rab[i].xid) { S1AP_E_RAB_RELEASE_RESPONSE (msg_p).e_rab_release[e_rabs_released].e_rab_id = ue_context_pP->ue_context.e_rab[i].param.e_rab_id; e_rabs_released++; //clear memset(&ue_context_pP->ue_context.e_rab[i],0,sizeof(e_rab_param_t)); } } S1AP_E_RAB_RELEASE_RESPONSE (msg_p).nb_of_e_rabs_released = e_rabs_released; S1AP_E_RAB_RELEASE_RESPONSE (msg_p).nb_of_e_rabs_failed = ue_context_pP->ue_context.nb_release_of_e_rabs; memcpy(&(S1AP_E_RAB_RELEASE_RESPONSE (msg_p).e_rabs_failed[0]),&ue_context_pP->ue_context.e_rabs_release_failed[0],sizeof(e_rab_failed_t)*ue_context_pP->ue_context.nb_release_of_e_rabs); ue_context_pP->ue_context.setup_e_rabs -= e_rabs_released; LOG_I(RRC,"S1AP-E-RAB RELEASE RESPONSE: ENB_UE_S1AP_ID %d release_e_rabs %d setup_e_rabs %d \n", S1AP_E_RAB_RELEASE_RESPONSE (msg_p).eNB_ue_s1ap_id, e_rabs_released, ue_context_pP->ue_context.setup_e_rabs); itti_send_msg_to_task (TASK_S1AP, ctxt_pP->instance, msg_p); //clear xid for(int i = 0; i < NB_RB_MAX; i++) { ue_context_pP->ue_context.e_rab[i].xid = -1; } //clear release e_rabs ue_context_pP->ue_context.nb_release_of_e_rabs = 0; memset(&ue_context_pP->ue_context.e_rabs_release_failed[0],0,sizeof(e_rab_failed_t)*S1AP_MAX_E_RAB); return 0; } /*------------------------------------------------------------------------------*/ int rrc_eNB_process_PAGING_IND(MessageDef *msg_p, const char *msg_name, instance_t instance) { const unsigned int Ttab[4] = {32,64,128,256}; uint8_t Tc,Tue; /* DRX cycle of UE */ uint32_t pcch_nB; /* 4T, 2T, T, T/2, T/4, T/8, T/16, T/32 */ uint32_t N; /* N: min(T,nB). total count of PF in one DRX cycle */ uint32_t Ns = 0; /* Ns: max(1,nB/T) */ uint8_t i_s; /* i_s = floor(UE_ID/N) mod Ns */ uint32_t T; /* DRX cycle */ for (uint16_t tai_size = 0; tai_size < S1AP_PAGING_IND(msg_p).tai_size; tai_size++) { LOG_D(RRC,"[eNB %ld] In S1AP_PAGING_IND: MCC %d, MNC %d, TAC %d\n", instance, S1AP_PAGING_IND(msg_p).plmn_identity[tai_size].mcc, S1AP_PAGING_IND(msg_p).plmn_identity[tai_size].mnc, S1AP_PAGING_IND(msg_p).tac[tai_size]); for (uint8_t j = 0; j < RC.rrc[instance]->configuration.num_plmn; j++) { if (RC.rrc[instance]->configuration.mcc[j] == S1AP_PAGING_IND(msg_p).plmn_identity[tai_size].mcc && RC.rrc[instance]->configuration.mnc[j] == S1AP_PAGING_IND(msg_p).plmn_identity[tai_size].mnc && RC.rrc[instance]->configuration.tac == S1AP_PAGING_IND(msg_p).tac[tai_size]) { for (uint8_t CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { lte_frame_type_t frame_type = RC.eNB[instance][CC_id]->frame_parms.frame_type; /* get nB from configuration */ /* get default DRX cycle from configuration */ Tc = (uint8_t)RC.rrc[instance]->configuration.radioresourceconfig[CC_id].pcch_defaultPagingCycle; if (Tc < LTE_PCCH_Config__defaultPagingCycle_rf32 || Tc > LTE_PCCH_Config__defaultPagingCycle_rf256) { continue; } Tue = (uint8_t)S1AP_PAGING_IND(msg_p).paging_drx; /* set T = min(Tc,Tue) */ T = Tc < Tue ? Ttab[Tc] : Ttab[Tue]; /* set pcch_nB = PCCH-Config->nB */ pcch_nB = (uint32_t)RC.rrc[instance]->configuration.radioresourceconfig[CC_id].pcch_nB; switch (pcch_nB) { case LTE_PCCH_Config__nB_fourT: Ns = 4; break; case LTE_PCCH_Config__nB_twoT: Ns = 2; break; default: Ns = 1; break; } /* set N = min(T,nB) */ if (pcch_nB > LTE_PCCH_Config__nB_oneT) { switch (pcch_nB) { case LTE_PCCH_Config__nB_halfT: N = T/2; break; case LTE_PCCH_Config__nB_quarterT: N = T/4; break; case LTE_PCCH_Config__nB_oneEighthT: N = T/8; break; case LTE_PCCH_Config__nB_oneSixteenthT: N = T/16; break; case LTE_PCCH_Config__nB_oneThirtySecondT: N = T/32; break; default: /* pcch_nB error */ LOG_E(RRC, "[eNB %ld] In S1AP_PAGING_IND: pcch_nB error (pcch_nB %d) \n", instance, pcch_nB); return (-1); } } else { N = T; } /* insert data to UE_PF_PO or update data in UE_PF_PO */ pthread_mutex_lock(&ue_pf_po_mutex); uint8_t i = 0; for (i = 0; i < MAX_MOBILES_PER_ENB; i++) { if ((UE_PF_PO[CC_id][i].enable_flag == TRUE && UE_PF_PO[CC_id][i].ue_index_value == (uint16_t)(S1AP_PAGING_IND(msg_p).ue_index_value)) || (UE_PF_PO[CC_id][i].enable_flag != TRUE)) { /* set T = min(Tc,Tue) */ UE_PF_PO[CC_id][i].T = T; /* set UE_ID */ UE_PF_PO[CC_id][i].ue_index_value = (uint16_t)S1AP_PAGING_IND(msg_p).ue_index_value; /* calculate PF and PO */ /* set PF_min : SFN mod T = (T div N)*(UE_ID mod N) */ UE_PF_PO[CC_id][i].PF_min = (T / N) * (UE_PF_PO[CC_id][i].ue_index_value % N); /* set PO */ /* i_s = floor(UE_ID/N) mod Ns */ i_s = (uint8_t)((UE_PF_PO[CC_id][i].ue_index_value / N) % Ns); if (Ns == 1) { UE_PF_PO[CC_id][i].PO = (frame_type==FDD) ? 9 : 0; } else if (Ns==2) { UE_PF_PO[CC_id][i].PO = (frame_type==FDD) ? (4+(5*i_s)) : (5*i_s); } else if (Ns==4) { UE_PF_PO[CC_id][i].PO = (frame_type==FDD) ? (4*(i_s&1)+(5*(i_s>>1))) : ((i_s&1)+(5*(i_s>>1))); } if (UE_PF_PO[CC_id][i].enable_flag == TRUE) { //paging exist UE log LOG_D(RRC,"[eNB %ld] CC_id %d In S1AP_PAGING_IND: Update exist UE %d, T %d, PF %d, PO %d\n", instance, CC_id, UE_PF_PO[CC_id][i].ue_index_value, T, UE_PF_PO[CC_id][i].PF_min, UE_PF_PO[CC_id][i].PO); } else { /* set enable_flag */ UE_PF_PO[CC_id][i].enable_flag = TRUE; //paging new UE log LOG_D(RRC,"[eNB %ld] CC_id %d In S1AP_PAGING_IND: Insert a new UE %d, T %d, PF %d, PO %d\n", instance, CC_id, UE_PF_PO[CC_id][i].ue_index_value, T, UE_PF_PO[CC_id][i].PF_min, UE_PF_PO[CC_id][i].PO); } break; } } pthread_mutex_unlock(&ue_pf_po_mutex); uint32_t length; uint8_t buffer[RRC_BUF_SIZE]; uint8_t *message_buffer; /* Transfer data to PDCP */ MessageDef *message_p; message_p = itti_alloc_new_message (TASK_RRC_ENB, 0, RRC_PCCH_DATA_REQ); /* Create message for PDCP (DLInformationTransfer_t) */ length = do_Paging (instance, buffer, sizeof(buffer), S1AP_PAGING_IND(msg_p).ue_paging_identity, S1AP_PAGING_IND(msg_p).cn_domain); if(length == -1) { LOG_I(RRC, "do_Paging error"); return -1; } message_buffer = itti_malloc (TASK_RRC_ENB, TASK_PDCP_ENB, length); /* Uses a new buffer to avoid issue with PDCP buffer content that could be changed by PDCP (asynchronous message handling). */ memcpy (message_buffer, buffer, length); RRC_PCCH_DATA_REQ (message_p).sdu_size = length; RRC_PCCH_DATA_REQ (message_p).sdu_p = message_buffer; RRC_PCCH_DATA_REQ (message_p).mode = PDCP_TRANSMISSION_MODE_TRANSPARENT; /* not used */ RRC_PCCH_DATA_REQ (message_p).rnti = P_RNTI; RRC_PCCH_DATA_REQ (message_p).ue_index = i; RRC_PCCH_DATA_REQ (message_p).CC_id = CC_id; LOG_D(RRC, "[eNB %ld] CC_id %d In S1AP_PAGING_IND: send encdoed buffer to PDCP buffer_size %d\n", instance, CC_id, length); itti_send_msg_to_task (TASK_PDCP_ENB, instance, message_p); } } } } return (0); } /*NN: careful about the typcast of xid (long -> uint8_t*/ int rrc_eNB_send_PATH_SWITCH_REQ(const protocol_ctxt_t *const ctxt_pP, rrc_eNB_ue_context_t *const ue_context_pP) { MessageDef *msg_p = NULL; int e_rab = 0; int e_rabs_done = 0; rrc_ue_s1ap_ids_t *rrc_ue_s1ap_ids_p = NULL; hashtable_rc_t h_rc; gtpv1u_enb_create_tunnel_req_t create_tunnel_req; gtpv1u_enb_create_tunnel_resp_t create_tunnel_resp; uint8_t inde_list[ue_context_pP->ue_context.nb_of_e_rabs]; memset(inde_list, 0, ue_context_pP->ue_context.nb_of_e_rabs*sizeof(uint8_t)); msg_p = itti_alloc_new_message (TASK_RRC_ENB, 0, S1AP_PATH_SWITCH_REQ); ue_context_pP->ue_context.ue_initial_id = get_next_ue_initial_id (ctxt_pP->module_id); S1AP_PATH_SWITCH_REQ (msg_p).ue_initial_id = ue_context_pP->ue_context.ue_initial_id; rrc_ue_s1ap_ids_p = malloc(sizeof(*rrc_ue_s1ap_ids_p)); rrc_ue_s1ap_ids_p->ue_initial_id = ue_context_pP->ue_context.ue_initial_id; rrc_ue_s1ap_ids_p->eNB_ue_s1ap_id = UE_INITIAL_ID_INVALID; rrc_ue_s1ap_ids_p->ue_rnti = ctxt_pP->rnti; h_rc = hashtable_insert(RC.rrc[ctxt_pP->module_id]->initial_id2_s1ap_ids, (hash_key_t)ue_context_pP->ue_context.ue_initial_id, rrc_ue_s1ap_ids_p); if (h_rc != HASH_TABLE_OK) { LOG_E(S1AP, "[eNB %d] Error while hashtable_insert in initial_id2_s1ap_ids ue_initial_id %u\n", ctxt_pP->module_id, ue_context_pP->ue_context.ue_initial_id); } S1AP_PATH_SWITCH_REQ (msg_p).eNB_ue_s1ap_id = ue_context_pP->ue_context.eNB_ue_s1ap_id; S1AP_PATH_SWITCH_REQ (msg_p).mme_ue_s1ap_id = ue_context_pP->ue_context.mme_ue_s1ap_id; S1AP_PATH_SWITCH_REQ (msg_p).ue_gummei.mcc = ue_context_pP->ue_context.ue_gummei.mcc; S1AP_PATH_SWITCH_REQ (msg_p).ue_gummei.mnc = ue_context_pP->ue_context.ue_gummei.mnc; S1AP_PATH_SWITCH_REQ (msg_p).ue_gummei.mnc_len = ue_context_pP->ue_context.ue_gummei.mnc_len; S1AP_PATH_SWITCH_REQ (msg_p).ue_gummei.mme_code = ue_context_pP->ue_context.ue_gummei.mme_code; S1AP_PATH_SWITCH_REQ (msg_p).ue_gummei.mme_group_id = ue_context_pP->ue_context.ue_gummei.mme_group_id; S1AP_PATH_SWITCH_REQ (msg_p).security_capabilities.encryption_algorithms=ue_context_pP->ue_context.security_capabilities.encryption_algorithms; S1AP_PATH_SWITCH_REQ (msg_p).security_capabilities.integrity_algorithms=ue_context_pP->ue_context.security_capabilities.integrity_algorithms; LOG_I (RRC,"Path switch request: nb nb_of_e_rabs %u status %u\n", ue_context_pP->ue_context.nb_of_e_rabs, ue_context_pP->ue_context.e_rab[e_rab].status); memset(&create_tunnel_req, 0, sizeof(create_tunnel_req)); // the context for UE to be handovered is obtained through ho_req message for (e_rab = 0; e_rab < ue_context_pP->ue_context.nb_of_e_rabs ; e_rab++) { if (ue_context_pP->ue_context.e_rab[e_rab].status == E_RAB_STATUS_ESTABLISHED) { create_tunnel_req.eps_bearer_id[e_rabs_done] = ue_context_pP->ue_context.e_rab[e_rab].param.e_rab_id; create_tunnel_req.sgw_S1u_teid[e_rabs_done] = ue_context_pP->ue_context.e_rab[e_rab].param.gtp_teid; memcpy(&create_tunnel_req.sgw_addr[e_rabs_done], &ue_context_pP->ue_context.e_rab[e_rab].param.sgw_addr, sizeof(transport_layer_addr_t)); inde_list[e_rabs_done] = e_rab; e_rabs_done++; } } S1AP_PATH_SWITCH_REQ (msg_p).nb_of_e_rabs = e_rabs_done; create_tunnel_req.rnti = ue_context_pP->ue_context.rnti; create_tunnel_req.num_tunnels = e_rabs_done; gtpv1u_create_s1u_tunnel( ctxt_pP->instance, &create_tunnel_req, &create_tunnel_resp); rrc_eNB_process_GTPV1U_CREATE_TUNNEL_RESP( ctxt_pP, &create_tunnel_resp, &inde_list[0]); for (e_rab = 0; e_rab < e_rabs_done; e_rab++) { S1AP_PATH_SWITCH_REQ (msg_p).e_rabs_tobeswitched[e_rab].e_rab_id = create_tunnel_resp.eps_bearer_id[e_rab]; S1AP_PATH_SWITCH_REQ (msg_p).e_rabs_tobeswitched[e_rab].gtp_teid = create_tunnel_resp.enb_S1u_teid[e_rab]; S1AP_PATH_SWITCH_REQ (msg_p).e_rabs_tobeswitched[e_rab].eNB_addr = create_tunnel_resp.enb_addr; LOG_I (RRC,"enb_gtp_addr (msg index %d, e_rab index %d, status %d): nb_of_e_rabs %d, e_rab_id %d, teid: %u, addr: %d.%d.%d.%d \n ", e_rabs_done, e_rab, ue_context_pP->ue_context.e_rab[inde_list[e_rab]].status, S1AP_PATH_SWITCH_REQ (msg_p).nb_of_e_rabs, S1AP_PATH_SWITCH_REQ (msg_p).e_rabs_tobeswitched[e_rab].e_rab_id, S1AP_PATH_SWITCH_REQ (msg_p).e_rabs_tobeswitched[e_rab].gtp_teid, S1AP_PATH_SWITCH_REQ (msg_p).e_rabs_tobeswitched[e_rab].eNB_addr.buffer[0], S1AP_PATH_SWITCH_REQ (msg_p).e_rabs_tobeswitched[e_rab].eNB_addr.buffer[1], S1AP_PATH_SWITCH_REQ (msg_p).e_rabs_tobeswitched[e_rab].eNB_addr.buffer[2], S1AP_PATH_SWITCH_REQ (msg_p).e_rabs_tobeswitched[e_rab].eNB_addr.buffer[3]); } // NN: add conditions for e_rabs_failed if (e_rabs_done > 0) { LOG_I(RRC,"S1AP_PATH_SWITCH_REQ: sending the message: nb_of_erabstobeswitched %d, total e_rabs %d, index %d\n", S1AP_PATH_SWITCH_REQ (msg_p).nb_of_e_rabs, ue_context_pP->ue_context.setup_e_rabs, e_rab); MSC_LOG_TX_MESSAGE( MSC_RRC_ENB, MSC_S1AP_ENB, (const char *)&S1AP_PATH_SWITCH_REQ (msg_p), sizeof(s1ap_path_switch_req_t), MSC_AS_TIME_FMT" PATH_SWITCH_REQ UE %X eNB_ue_s1ap_id %u e_rabs:%u succ", MSC_AS_TIME_ARGS(ctxt_pP), ue_context_pP->ue_id_rnti, S1AP_PATH_SWITCH_REQ (msg_p).eNB_ue_s1ap_id, e_rabs_done); itti_send_msg_to_task (TASK_S1AP, ctxt_pP->instance, msg_p); } else { itti_free(ITTI_MSG_ORIGIN_ID(msg_p), msg_p); } return 0; } int rrc_eNB_process_X2AP_TUNNEL_SETUP_REQ(instance_t instance, rrc_eNB_ue_context_t *const ue_context_target_p) { gtpv1u_enb_create_x2u_tunnel_req_t create_tunnel_req; gtpv1u_enb_create_x2u_tunnel_resp_t create_tunnel_resp; uint8_t e_rab_done; uint8_t inde_list[NB_RB_MAX - 3]= {0}; if (ue_context_target_p == NULL) { return (-1); } else { /* Save e RAB information for later */ { LOG_I(RRC, "[eNB %ld] rrc_eNB_process_X2AP_TUNNEL_SETUP_REQ: rnti %u nb_of_e_rabs %d\n", instance, ue_context_target_p->ue_context.rnti, ue_context_target_p->ue_context.nb_of_e_rabs); int i; memset(&create_tunnel_req, 0, sizeof(create_tunnel_req)); uint8_t nb_e_rabs_tosetup = ue_context_target_p->ue_context.nb_of_e_rabs; e_rab_done = 0; for (i = 0; i < nb_e_rabs_tosetup; i++) { if(ue_context_target_p->ue_context.e_rab[i].status >= E_RAB_STATUS_DONE) continue; create_tunnel_req.eps_bearer_id[e_rab_done] = ue_context_target_p->ue_context.e_rab[i].param.e_rab_id; LOG_I(RRC,"x2 tunnel setup: local index %d UE id %x, eps id %d \n", i, ue_context_target_p->ue_context.rnti, create_tunnel_req.eps_bearer_id[i] ); inde_list[i] = e_rab_done; e_rab_done++; } create_tunnel_req.rnti = ue_context_target_p->ue_context.rnti; // warning put zero above create_tunnel_req.num_tunnels = e_rab_done; // NN: not sure if we should create a new tunnel: need to check teid, etc. gtpv1u_create_x2u_tunnel( instance, &create_tunnel_req, &create_tunnel_resp); ue_context_target_p->ue_context.nb_x2u_e_rabs = create_tunnel_resp.num_tunnels; for (i = 0; i < create_tunnel_resp.num_tunnels; i++) { ue_context_target_p->ue_context.enb_gtp_x2u_teid[inde_list[i]] = create_tunnel_resp.enb_X2u_teid[i]; ue_context_target_p->ue_context.enb_gtp_x2u_addrs[inde_list[i]] = create_tunnel_resp.enb_addr; ue_context_target_p->ue_context.enb_gtp_x2u_ebi[inde_list[i]] = create_tunnel_resp.eps_bearer_id[i]; LOG_I(RRC, "rrc_eNB_process_X2AP_TUNNEL_SETUP_REQ tunnel (%u, %u) bearer UE context index %u, msg index %u, eps bearer id %u, gtp addr len %d \n", create_tunnel_resp.enb_X2u_teid[i], ue_context_target_p->ue_context.enb_gtp_x2u_teid[inde_list[i]], inde_list[i], i, create_tunnel_resp.eps_bearer_id[i], create_tunnel_resp.enb_addr.length); } } return (0); } } int rrc_eNB_process_S1AP_PATH_SWITCH_REQ_ACK (MessageDef *msg_p, const char *msg_name, instance_t instance) { uint16_t ue_initial_id; uint32_t eNB_ue_s1ap_id; //gtpv1u_enb_create_tunnel_req_t create_tunnel_req; //gtpv1u_enb_create_tunnel_resp_t create_tunnel_resp; gtpv1u_enb_delete_tunnel_req_t delete_tunnel_req; struct rrc_eNB_ue_context_s *ue_context_p = NULL; protocol_ctxt_t ctxt; int i; ue_initial_id = S1AP_PATH_SWITCH_REQ_ACK (msg_p).ue_initial_id; eNB_ue_s1ap_id = S1AP_PATH_SWITCH_REQ_ACK (msg_p).eNB_ue_s1ap_id; ue_context_p = rrc_eNB_get_ue_context_from_s1ap_ids(instance, ue_initial_id, eNB_ue_s1ap_id); LOG_I(RRC, "[eNB %ld] Received %s: ue_initial_id %d, eNB_ue_s1ap_id %d, nb_of_e_rabs %d\n", instance, msg_name, ue_initial_id, eNB_ue_s1ap_id, S1AP_E_RAB_SETUP_REQ (msg_p).nb_e_rabs_tosetup); if (ue_context_p == NULL) { /* Can not associate this message to an UE index, send a failure to S1AP and discard it! */ //MessageDef *msg_fail_p = NULL; LOG_W(RRC, "[eNB %ld] In S1AP_PATH_SWITCH_REQ_ACK: unknown UE from S1AP ids (%d, %d)\n", instance, ue_initial_id, eNB_ue_s1ap_id); //msg_fail_p = itti_alloc_new_message (TASK_RRC_ENB, 0, S1AP_PATH_SWITCH_REQ_ACK_FAIL); //S1AP_PATH_SWITCH_REQ_ACK (msg_fail_p).eNB_ue_s1ap_id = eNB_ue_s1ap_id; // TODO add failure cause when defined! //itti_send_msg_to_task (TASK_S1AP, instance, msg_fail_p); return (-1); } else { PROTOCOL_CTXT_SET_BY_INSTANCE(&ctxt, instance, ENB_FLAG_YES, ue_context_p->ue_context.rnti, 0, 0); ue_context_p->ue_context.eNB_ue_s1ap_id = S1AP_PATH_SWITCH_REQ_ACK (msg_p).eNB_ue_s1ap_id; ue_context_p->ue_context.mme_ue_s1ap_id = S1AP_PATH_SWITCH_REQ_ACK (msg_p).mme_ue_s1ap_id; /* Save e RAB information for later */ { ue_context_p->ue_context.nb_release_of_e_rabs = S1AP_PATH_SWITCH_REQ_ACK (msg_p).nb_e_rabs_tobereleased; for (i = 0; i < ue_context_p->ue_context.setup_e_rabs; // go over total number of e_rabs received through x2_ho_req msg i++) { // assume that we are releasing all the DRBs ue_context_p->ue_context.e_rab[i].status = E_RAB_STATUS_REESTABLISHED; if (ue_context_p->ue_context.nb_release_of_e_rabs==0) { LOG_I(RRC,"Bearer re-established with ID: %d\n", ue_context_p->ue_context.e_rab[i].param.e_rab_id); } } //memset(&create_tunnel_req, 0 , sizeof(create_tunnel_req)); uint8_t nb_e_rabs_tobeswitched = S1AP_PATH_SWITCH_REQ_ACK (msg_p).nb_e_rabs_tobeswitched; // keep the previous bearer // the index for the rec if (nb_e_rabs_tobeswitched>0) { int e_rab_switch_index=0; for (i = 0; i < ue_context_p->ue_context.setup_e_rabs; // go over total number of e_rabs received through x2_ho_req msg i++) { /* Harmonize with enb_gtp_teid, enb_gtp_addrs, and enb_gtp_rbi vars in the top level structure */ if (ue_context_p->ue_context.e_rab[i].param.e_rab_id == S1AP_PATH_SWITCH_REQ_ACK (msg_p).e_rabs_tobeswitched[e_rab_switch_index].e_rab_id) { ue_context_p->ue_context.e_rab[i].param.e_rab_id = S1AP_PATH_SWITCH_REQ_ACK (msg_p).e_rabs_tobeswitched[e_rab_switch_index].e_rab_id; ue_context_p->ue_context.e_rab[i].param.sgw_addr= S1AP_PATH_SWITCH_REQ_ACK (msg_p).e_rabs_tobeswitched[e_rab_switch_index].sgw_addr; ue_context_p->ue_context.e_rab[i].param.gtp_teid = S1AP_PATH_SWITCH_REQ_ACK (msg_p).e_rabs_tobeswitched[e_rab_switch_index].gtp_teid; e_rab_switch_index++; } } } } ue_context_p->ue_context.ue_ambr=S1AP_PATH_SWITCH_REQ_ACK (msg_p).ue_ambr; ue_context_p->ue_context.setup_e_rabs = ue_context_p->ue_context.setup_e_rabs - ue_context_p->ue_context.nb_release_of_e_rabs; ue_context_p->ue_context.nb_of_e_rabs = ue_context_p->ue_context.nb_of_e_rabs - ue_context_p->ue_context.nb_release_of_e_rabs; memset(&delete_tunnel_req, 0, sizeof(delete_tunnel_req)); if (ue_context_p->ue_context.nb_release_of_e_rabs>0) { int e_rab_release_index=0; for (i = 0; i < ue_context_p->ue_context.setup_e_rabs; i++) { if (ue_context_p->ue_context.e_rab[i].param.e_rab_id == S1AP_PATH_SWITCH_REQ_ACK (msg_p).e_rabs_tobereleased[e_rab_release_index].e_rab_id) { LOG_I(RRC,"Bearer released with ID: %d\n", ue_context_p->ue_context.e_rab[i].param.e_rab_id); ue_context_p->ue_context.e_rab[i].status = E_RAB_STATUS_TORELEASE; ue_context_p->ue_context.e_rabs_tobereleased[e_rab_release_index]=S1AP_PATH_SWITCH_REQ_ACK (msg_p).e_rabs_tobereleased[e_rab_release_index].e_rab_id; delete_tunnel_req.eps_bearer_id[e_rab_release_index] = S1AP_PATH_SWITCH_REQ_ACK (msg_p).e_rabs_tobereleased[e_rab_release_index].e_rab_id; e_rab_release_index++; } else { LOG_I(RRC,"Bearer re-established with ID: %d\n", ue_context_p->ue_context.e_rab[i].param.e_rab_id); } } } if (ue_context_p->ue_context.nb_release_of_e_rabs>0) { delete_tunnel_req.rnti= ue_context_p->ue_context.rnti; delete_tunnel_req.num_erab= ue_context_p->ue_context.nb_release_of_e_rabs; /* this could also be done through ITTI message */ gtpv1u_delete_s1u_tunnel(instance, &delete_tunnel_req); /* TBD: release the DRB not admitted */ //rrc_eNB_generate_dedicatedRRCConnectionReconfiguration(&ctxt, ue_context_p, 0); if ( ue_context_p->ue_context.ue_release_timer_rrc > 0 && (ue_context_p->ue_context.handover_info == NULL || (ue_context_p->ue_context.handover_info->state != HO_RELEASE && ue_context_p->ue_context.handover_info->state != HO_CANCEL ) ) ) ue_context_p->ue_context.ue_release_timer_rrc = ue_context_p->ue_context.ue_release_timer_thres_rrc; } /* Security key */ ue_context_p->ue_context.next_hop_chain_count=S1AP_PATH_SWITCH_REQ_ACK (msg_p).next_hop_chain_count; memcpy ( ue_context_p->ue_context.next_security_key, S1AP_PATH_SWITCH_REQ_ACK (msg_p).next_security_key, SECURITY_KEY_LENGTH); rrc_eNB_send_X2AP_UE_CONTEXT_RELEASE(&ctxt, ue_context_p); return (0); } } int rrc_eNB_send_X2AP_UE_CONTEXT_RELEASE(const protocol_ctxt_t *const ctxt_pP, rrc_eNB_ue_context_t *const ue_context_pP) { MessageDef *msg_p = NULL; msg_p = itti_alloc_new_message (TASK_RRC_ENB, 0, X2AP_UE_CONTEXT_RELEASE); X2AP_UE_CONTEXT_RELEASE (msg_p).rnti = ue_context_pP->ue_context.rnti; X2AP_UE_CONTEXT_RELEASE (msg_p).source_assoc_id = ue_context_pP->ue_context.handover_info->assoc_id; itti_send_msg_to_task (TASK_X2AP, ctxt_pP->instance, msg_p); return (0); } int s1ap_ue_context_release(instance_t instance, const uint32_t eNB_ue_s1ap_id) { s1ap_eNB_instance_t *s1ap_eNB_instance_p = NULL; struct s1ap_eNB_ue_context_s *ue_context_p = NULL; s1ap_eNB_instance_p = s1ap_eNB_get_instance(instance); DevAssert(s1ap_eNB_instance_p != NULL); if ((ue_context_p = s1ap_eNB_get_ue_context(s1ap_eNB_instance_p, eNB_ue_s1ap_id)) == NULL) { /* The context for this eNB ue s1ap id doesn't exist in the map of eNB UEs */ LOG_W(RRC,"Failed to find ue context associated with eNB ue s1ap id: %u\n", eNB_ue_s1ap_id); return -1; } // release UE context struct s1ap_eNB_ue_context_s *ue_context2_p = NULL; if ((ue_context2_p = RB_REMOVE(s1ap_ue_map, &s1ap_eNB_instance_p->s1ap_ue_head, ue_context_p)) != NULL) { LOG_W(RRC,"Removed UE context eNB_ue_s1ap_id %u\n", ue_context2_p->eNB_ue_s1ap_id); s1ap_eNB_free_ue_context(ue_context2_p); } else { LOG_W(RRC,"Removing UE context eNB_ue_s1ap_id %u: did not find context\n", ue_context_p->eNB_ue_s1ap_id); } /*RB_FOREACH(ue_context_p, s1ap_ue_map, &s1ap_eNB_instance_p->s1ap_ue_head) { S1AP_WARN("in s1ap_ue_map: UE context eNB_ue_s1ap_id %u mme_ue_s1ap_id %u state %u\n", ue_context_p->eNB_ue_s1ap_id, ue_context_p->mme_ue_s1ap_id, ue_context_p->ue_state); }*/ return 0; } int rrc_eNB_send_E_RAB_Modification_Indication(const protocol_ctxt_t *const ctxt_pP, rrc_eNB_ue_context_t *const ue_context_pP) { MessageDef *msg_p = NULL; int e_rab = 0; int e_rab_modify_index = 0; int e_rab_notmodify_index = 0; uint8_t inde_list[ue_context_pP->ue_context.nb_of_e_rabs]; memset(inde_list, 0, ue_context_pP->ue_context.nb_of_e_rabs*sizeof(uint8_t)); msg_p = itti_alloc_new_message (TASK_RRC_ENB, 0, S1AP_E_RAB_MODIFICATION_IND); S1AP_E_RAB_MODIFICATION_IND (msg_p).eNB_ue_s1ap_id = ue_context_pP->ue_context.eNB_ue_s1ap_id; S1AP_E_RAB_MODIFICATION_IND (msg_p).mme_ue_s1ap_id = ue_context_pP->ue_context.mme_ue_s1ap_id; LOG_I (RRC,"E-RAB modification indication: nb nb_of_e_rabs %u status %u\n", ue_context_pP->ue_context.nb_of_e_rabs, ue_context_pP->ue_context.e_rab[e_rab].status); if (ue_context_pP->ue_context.nb_of_modify_endc_e_rabs > 0){ S1AP_E_RAB_MODIFICATION_IND (msg_p).nb_of_e_rabs_tobemodified = ue_context_pP->ue_context.nb_of_modify_endc_e_rabs; for (e_rab = 0; e_rab < ue_context_pP->ue_context.setup_e_rabs ; e_rab++) { //Add E-RAB in the list of E-RABs to be modified if (ue_context_pP->ue_context.e_rab[e_rab].status == E_RAB_STATUS_TOMODIFY) { S1AP_E_RAB_MODIFICATION_IND (msg_p).e_rabs_tobemodified[e_rab_modify_index].e_rab_id = ue_context_pP->ue_context.e_rab[e_rab].param.e_rab_id; memcpy(S1AP_E_RAB_MODIFICATION_IND (msg_p).e_rabs_tobemodified[e_rab_modify_index].eNB_addr.buffer, ue_context_pP->ue_context.gnb_gtp_endc_addrs[e_rab].buffer, ue_context_pP->ue_context.gnb_gtp_endc_addrs[e_rab].length); S1AP_E_RAB_MODIFICATION_IND (msg_p).e_rabs_tobemodified[e_rab_modify_index].eNB_addr.length = ue_context_pP->ue_context.gnb_gtp_endc_addrs[e_rab].length; S1AP_E_RAB_MODIFICATION_IND (msg_p).e_rabs_tobemodified[e_rab_modify_index].gtp_teid = ue_context_pP->ue_context.gnb_gtp_endc_teid[e_rab]; e_rab_modify_index++; } //Add E-RAB in the list of E-RABs NOT to be modified else{ S1AP_E_RAB_MODIFICATION_IND (msg_p).e_rabs_nottobemodified[e_rab_notmodify_index].e_rab_id = ue_context_pP->ue_context.e_rab[e_rab].param.e_rab_id; memcpy(S1AP_E_RAB_MODIFICATION_IND (msg_p).e_rabs_nottobemodified[e_rab_notmodify_index].eNB_addr.buffer, ue_context_pP->ue_context.gnb_gtp_endc_addrs[e_rab].buffer, ue_context_pP->ue_context.gnb_gtp_endc_addrs[e_rab].length); S1AP_E_RAB_MODIFICATION_IND (msg_p).e_rabs_nottobemodified[e_rab_notmodify_index].eNB_addr.length = ue_context_pP->ue_context.gnb_gtp_endc_addrs[e_rab].length; S1AP_E_RAB_MODIFICATION_IND (msg_p).e_rabs_nottobemodified[e_rab_notmodify_index].gtp_teid = ue_context_pP->ue_context.gnb_gtp_endc_teid[e_rab]; e_rab_notmodify_index++; } } S1AP_E_RAB_MODIFICATION_IND (msg_p).nb_of_e_rabs_nottobemodified = e_rab_notmodify_index; } if (e_rab_modify_index > 0) { LOG_I(RRC,"S1AP_E_RAB_MODIFICATION_IND: sending the message: nb_of_erabstobemodified %d, total e_rabs %d, index %d\n", S1AP_E_RAB_MODIFICATION_IND (msg_p).nb_of_e_rabs_tobemodified, ue_context_pP->ue_context.setup_e_rabs, e_rab); MSC_LOG_TX_MESSAGE( MSC_RRC_ENB, MSC_S1AP_ENB, (const char *)&S1AP_E_RAB_MODIFICATION_IND (msg_p), sizeof(s1ap_e_rab_modification_ind_t), MSC_AS_TIME_FMT" E RAB MODIFICATION IND UE %X eNB_ue_s1ap_id %u e_rabs:%u succ", MSC_AS_TIME_ARGS(ctxt_pP), ue_context_pP->ue_id_rnti, S1AP_E_RAB_MODIFICATION_IND (msg_p).eNB_ue_s1ap_id, e_rab_modify_index); itti_send_msg_to_task (TASK_S1AP, ctxt_pP->instance, msg_p); } else { itti_free(ITTI_MSG_ORIGIN_ID(msg_p), msg_p); } return 0; }