/*******************************************************************************
OpenAirInterface
Copyright(c) 1999 - 2014 Eurecom
OpenAirInterface is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenAirInterface is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
see .
Contact Information
OpenAirInterface Admin: openair_admin@eurecom.fr
OpenAirInterface Tech : openair_tech@eurecom.fr
OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr
Address : Eurecom, Compus SophiaTech 450, route des chappes, 06451 Biot, France.
*******************************************************************************/
#include
#include
#include
#include "assertions.h"
#include "conversions.h"
#include "intertask_interface.h"
#include "s1ap_common.h"
#include "s1ap_eNB_defs.h"
#include "s1ap_eNB_itti_messaging.h"
#include "s1ap_ies_defs.h"
#include "s1ap_eNB_encoder.h"
#include "s1ap_eNB_nnsf.h"
#include "s1ap_eNB_ue_context.h"
#include "s1ap_eNB_nas_procedures.h"
#include "s1ap_eNB_management_procedures.h"
#include "msc.h"
//------------------------------------------------------------------------------
int s1ap_eNB_handle_nas_first_req(
instance_t instance, s1ap_nas_first_req_t *s1ap_nas_first_req_p)
//------------------------------------------------------------------------------
{
s1ap_eNB_instance_t *instance_p = NULL;
struct s1ap_eNB_mme_data_s *mme_desc_p = NULL;
struct s1ap_eNB_ue_context_s *ue_desc_p = NULL;
s1ap_message message;
S1ap_InitialUEMessageIEs_t *initial_ue_message_p = NULL;
uint8_t *buffer = NULL;
uint32_t length = 0;
DevAssert(s1ap_nas_first_req_p != NULL);
/* Retrieve the S1AP eNB instance associated with Mod_id */
instance_p = s1ap_eNB_get_instance(instance);
DevAssert(instance_p != NULL);
memset(&message, 0, sizeof(s1ap_message));
message.direction = S1AP_PDU_PR_initiatingMessage;
message.procedureCode = S1ap_ProcedureCode_id_initialUEMessage;
initial_ue_message_p = &message.msg.s1ap_InitialUEMessageIEs;
/* Select the MME corresponding to the provided GUMMEI. */
if (s1ap_nas_first_req_p->ue_identity.presenceMask & UE_IDENTITIES_gummei) {
mme_desc_p = s1ap_eNB_nnsf_select_mme_by_gummei(
instance_p,
s1ap_nas_first_req_p->establishment_cause,
s1ap_nas_first_req_p->ue_identity.gummei);
}
if (mme_desc_p == NULL) {
/* Select the MME corresponding to the provided s-TMSI. */
if (s1ap_nas_first_req_p->ue_identity.presenceMask & UE_IDENTITIES_s_tmsi) {
mme_desc_p = s1ap_eNB_nnsf_select_mme_by_mme_code(
instance_p,
s1ap_nas_first_req_p->establishment_cause,
s1ap_nas_first_req_p->ue_identity.s_tmsi.mme_code);
}
}
if (mme_desc_p == NULL) {
/*
* If no MME corresponds to the GUMMEI or the s-TMSI, selects the MME with the
* highest capacity.
*/
mme_desc_p = s1ap_eNB_nnsf_select_mme(
instance_p,
s1ap_nas_first_req_p->establishment_cause);
}
if (mme_desc_p == NULL) {
/*
* In case eNB has no MME associated, the eNB should inform RRC and discard
* this request.
*/
S1AP_WARN("No MME is associated to the eNB\n");
// TODO: Inform RRC
return -1;
}
/* The eNB should allocate a unique eNB UE S1AP ID for this UE. The value
* will be used for the duration of the connectivity.
*/
ue_desc_p = s1ap_eNB_allocate_new_UE_context();
DevAssert(ue_desc_p != NULL);
/* Keep a reference to the selected MME */
ue_desc_p->mme_ref = mme_desc_p;
ue_desc_p->ue_initial_id = s1ap_nas_first_req_p->ue_initial_id;
ue_desc_p->eNB_instance = instance_p;
do {
struct s1ap_eNB_ue_context_s *collision_p;
/* Peek a random value for the eNB_ue_s1ap_id */
ue_desc_p->eNB_ue_s1ap_id = (random() + random()) & 0x00ffffff;
if ((collision_p = RB_INSERT(s1ap_ue_map, &instance_p->s1ap_ue_head, ue_desc_p))
== NULL) {
S1AP_DEBUG("Found usable eNB_ue_s1ap_id: 0x%06x %d(10)\n",
ue_desc_p->eNB_ue_s1ap_id,
ue_desc_p->eNB_ue_s1ap_id);
/* Break the loop as the id is not already used by another UE */
break;
}
} while(1);
initial_ue_message_p->eNB_UE_S1AP_ID = ue_desc_p->eNB_ue_s1ap_id;
/* Prepare the NAS PDU */
initial_ue_message_p->nas_pdu.buf = s1ap_nas_first_req_p->nas_pdu.buffer;
initial_ue_message_p->nas_pdu.size = s1ap_nas_first_req_p->nas_pdu.length;
/* Set the establishment cause according to those provided by RRC */
DevCheck(s1ap_nas_first_req_p->establishment_cause < RRC_CAUSE_LAST,
s1ap_nas_first_req_p->establishment_cause, RRC_CAUSE_LAST, 0);
initial_ue_message_p->rrC_Establishment_Cause = s1ap_nas_first_req_p->establishment_cause;
if (s1ap_nas_first_req_p->ue_identity.presenceMask & UE_IDENTITIES_s_tmsi) {
S1AP_DEBUG("S_TMSI_PRESENT\n");
initial_ue_message_p->presenceMask |= S1AP_INITIALUEMESSAGEIES_S_TMSI_PRESENT;
MME_CODE_TO_OCTET_STRING(s1ap_nas_first_req_p->ue_identity.s_tmsi.mme_code,
&initial_ue_message_p->s_tmsi.mMEC);
M_TMSI_TO_OCTET_STRING(s1ap_nas_first_req_p->ue_identity.s_tmsi.m_tmsi,
&initial_ue_message_p->s_tmsi.m_TMSI);
}
if (s1ap_nas_first_req_p->ue_identity.presenceMask & UE_IDENTITIES_gummei) {
S1AP_DEBUG("GUMMEI_ID_PRESENT\n");
initial_ue_message_p->presenceMask |= S1AP_INITIALUEMESSAGEIES_GUMMEI_ID_PRESENT;
MCC_MNC_TO_PLMNID(
s1ap_nas_first_req_p->ue_identity.gummei.mcc,
s1ap_nas_first_req_p->ue_identity.gummei.mnc,
s1ap_nas_first_req_p->ue_identity.gummei.mnc_len,
&initial_ue_message_p->gummei_id.pLMN_Identity);
MME_GID_TO_OCTET_STRING(s1ap_nas_first_req_p->ue_identity.gummei.mme_group_id,
&initial_ue_message_p->gummei_id.mME_Group_ID);
MME_CODE_TO_OCTET_STRING(s1ap_nas_first_req_p->ue_identity.gummei.mme_code,
&initial_ue_message_p->gummei_id.mME_Code);
}
/* Assuming TAI is the TAI from the cell */
INT16_TO_OCTET_STRING(instance_p->tac, &initial_ue_message_p->tai.tAC);
MCC_MNC_TO_PLMNID(instance_p->mcc,
instance_p->mnc,
instance_p->mnc_digit_length,
&initial_ue_message_p->tai.pLMNidentity);
/* Set the EUTRAN CGI
* The cell identity is defined on 28 bits but as we use macro enb id,
* we have to pad.
*/
//#warning "TODO get cell id from RRC"
MACRO_ENB_ID_TO_CELL_IDENTITY(instance_p->eNB_id,
0, // Cell ID
&initial_ue_message_p->eutran_cgi.cell_ID);
MCC_MNC_TO_TBCD(instance_p->mcc,
instance_p->mnc,
instance_p->mnc_digit_length,
&initial_ue_message_p->eutran_cgi.pLMNidentity);
if (s1ap_eNB_encode_pdu(&message, &buffer, &length) < 0) {
/* Failed to encode message */
DevMessage("Failed to encode initial UE message\n");
}
/* Update the current S1AP UE state */
ue_desc_p->ue_state = S1AP_UE_WAITING_CSR;
/* Assign a stream for this UE :
* From 3GPP 36.412 7)Transport layers:
* Within the SCTP association established between one MME and eNB pair:
* - a single pair of stream identifiers shall be reserved for the sole use
* of S1AP elementary procedures that utilize non UE-associated signalling.
* - At least one pair of stream identifiers shall be reserved for the sole use
* of S1AP elementary procedures that utilize UE-associated signallings.
* However a few pairs (i.e. more than one) should be reserved.
* - A single UE-associated signalling shall use one SCTP stream and
* the stream should not be changed during the communication of the
* UE-associated signalling.
*/
mme_desc_p->nextstream = (mme_desc_p->nextstream + 1) % mme_desc_p->out_streams;
if ((mme_desc_p->nextstream == 0) && (mme_desc_p->out_streams > 1)) {
mme_desc_p->nextstream += 1;
}
ue_desc_p->tx_stream = mme_desc_p->nextstream;
MSC_LOG_TX_MESSAGE(
MSC_S1AP_ENB,
MSC_S1AP_MME,
(const char *)NULL,
0,
MSC_AS_TIME_FMT" initialUEMessage initiatingMessage eNB_ue_s1ap_id %u",
0,0,//MSC_AS_TIME_ARGS(ctxt_pP),
initial_ue_message_p->eNB_UE_S1AP_ID);
/* Send encoded message over sctp */
s1ap_eNB_itti_send_sctp_data_req(instance_p->instance, mme_desc_p->assoc_id,
buffer, length, ue_desc_p->tx_stream);
return 0;
}
//------------------------------------------------------------------------------
int s1ap_eNB_handle_nas_downlink(const uint32_t assoc_id,
const uint32_t stream,
struct s1ap_message_s* message_p)
//------------------------------------------------------------------------------
{
const S1ap_DownlinkNASTransportIEs_t *downlink_NAS_transport_p = NULL;
s1ap_eNB_mme_data_t *mme_desc_p = NULL;
s1ap_eNB_ue_context_t *ue_desc_p = NULL;
s1ap_eNB_instance_t *s1ap_eNB_instance = NULL;
DevAssert(message_p != NULL);
downlink_NAS_transport_p = &message_p->msg.s1ap_DownlinkNASTransportIEs;
/* UE-related procedure -> stream != 0 */
if (stream == 0) {
S1AP_ERROR("[SCTP %d] Received UE-related procedure on stream == 0\n",
assoc_id);
return -1;
}
if ((mme_desc_p = s1ap_eNB_get_MME(NULL, assoc_id, 0)) == NULL) {
S1AP_ERROR(
"[SCTP %d] Received NAS downlink message for non existing MME context\n",
assoc_id);
return -1;
}
s1ap_eNB_instance = mme_desc_p->s1ap_eNB_instance;
if ((ue_desc_p = s1ap_eNB_get_ue_context(s1ap_eNB_instance,
downlink_NAS_transport_p->eNB_UE_S1AP_ID)) == NULL) {
MSC_LOG_RX_DISCARDED_MESSAGE(
MSC_S1AP_ENB,
MSC_S1AP_MME,
(const char *)downlink_NAS_transport_p,
sizeof(S1ap_DownlinkNASTransportIEs_t),
MSC_AS_TIME_FMT" downlinkNASTransport eNB_ue_s1ap_id %u mme_ue_s1ap_id %u",
0,0,//MSC_AS_TIME_ARGS(ctxt_pP),
downlink_NAS_transport_p->eNB_UE_S1AP_ID,
downlink_NAS_transport_p->mme_ue_s1ap_id);
S1AP_ERROR("[SCTP %d] Received NAS downlink message for non existing UE context eNB_UE_S1AP_ID: 0x%"PRIx32" %u\n",
assoc_id,
downlink_NAS_transport_p->eNB_UE_S1AP_ID,
downlink_NAS_transport_p->eNB_UE_S1AP_ID);
return -1;
}
if (0 == ue_desc_p->rx_stream) {
ue_desc_p->rx_stream = stream;
} else if (stream != ue_desc_p->rx_stream) {
S1AP_ERROR("[SCTP %d] Received UE-related procedure on stream %u, expecting %u\n",
assoc_id, stream, ue_desc_p->rx_stream);
return -1;
}
/* Is it the first outcome of the MME for this UE ? If so store the mme
* UE s1ap id.
*/
if (ue_desc_p->mme_ue_s1ap_id == 0) {
ue_desc_p->mme_ue_s1ap_id = downlink_NAS_transport_p->mme_ue_s1ap_id;
} else {
/* We already have a mme ue s1ap id check the received is the same */
if (ue_desc_p->mme_ue_s1ap_id != downlink_NAS_transport_p->mme_ue_s1ap_id) {
S1AP_ERROR("[SCTP %d] Mismatch in MME UE S1AP ID (0x%"PRIx32" != 0x%"PRIx32")\n",
assoc_id,
downlink_NAS_transport_p->mme_ue_s1ap_id,
ue_desc_p->mme_ue_s1ap_id
);
return -1;
}
}
MSC_LOG_RX_MESSAGE(
MSC_S1AP_ENB,
MSC_S1AP_MME,
(const char *)downlink_NAS_transport_p,
sizeof(S1ap_DownlinkNASTransportIEs_t),
MSC_AS_TIME_FMT" downlinkNASTransport eNB_ue_s1ap_id %u mme_ue_s1ap_id %u",
0,0,//MSC_AS_TIME_ARGS(ctxt_pP),
downlink_NAS_transport_p->eNB_UE_S1AP_ID,
downlink_NAS_transport_p->mme_ue_s1ap_id);
/* Forward the NAS PDU to RRC */
s1ap_eNB_itti_send_nas_downlink_ind(s1ap_eNB_instance->instance,
ue_desc_p->ue_initial_id,
ue_desc_p->eNB_ue_s1ap_id,
downlink_NAS_transport_p->nas_pdu.buf,
downlink_NAS_transport_p->nas_pdu.size);
// LG: Why set to 0 ??
//ue_desc_p->ue_initial_id = 0;
return 0;
}
//------------------------------------------------------------------------------
int s1ap_eNB_nas_uplink(instance_t instance, s1ap_uplink_nas_t *s1ap_uplink_nas_p)
//------------------------------------------------------------------------------
{
struct s1ap_eNB_ue_context_s *ue_context_p;
s1ap_eNB_instance_t *s1ap_eNB_instance_p;
S1ap_UplinkNASTransportIEs_t *uplink_NAS_transport_p;
s1ap_message message;
uint8_t *buffer;
uint32_t length;
DevAssert(s1ap_uplink_nas_p != NULL);
/* Retrieve the S1AP eNB instance associated with Mod_id */
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, s1ap_uplink_nas_p->eNB_ue_s1ap_id)) == NULL) {
/* The context for this eNB ue s1ap id doesn't exist in the map of eNB UEs */
S1AP_WARN("Failed to find ue context associated with eNB ue s1ap id: %06x\n",
s1ap_uplink_nas_p->eNB_ue_s1ap_id);
return -1;
}
/* Uplink NAS transport can occur either during an s1ap connected state
* or during initial attach (for example: NAS authentication).
*/
if (!(ue_context_p->ue_state == S1AP_UE_CONNECTED ||
ue_context_p->ue_state == S1AP_UE_WAITING_CSR)) {
S1AP_WARN("You are attempting to send NAS data over non-connected "
"eNB ue s1ap id: %u, current state: %d\n",
s1ap_uplink_nas_p->eNB_ue_s1ap_id, ue_context_p->ue_state);
return -1;
}
/* Prepare the S1AP message to encode */
memset(&message, 0, sizeof(s1ap_message));
message.direction = S1AP_PDU_PR_initiatingMessage;
message.procedureCode = S1ap_ProcedureCode_id_uplinkNASTransport;
uplink_NAS_transport_p = &message.msg.s1ap_UplinkNASTransportIEs;
uplink_NAS_transport_p->mme_ue_s1ap_id = ue_context_p->mme_ue_s1ap_id;
uplink_NAS_transport_p->eNB_UE_S1AP_ID = ue_context_p->eNB_ue_s1ap_id;
uplink_NAS_transport_p->nas_pdu.buf = s1ap_uplink_nas_p->nas_pdu.buffer;
uplink_NAS_transport_p->nas_pdu.size = s1ap_uplink_nas_p->nas_pdu.length;
MCC_MNC_TO_PLMNID(
s1ap_eNB_instance_p->mcc,
s1ap_eNB_instance_p->mnc,
s1ap_eNB_instance_p->mnc_digit_length,
&uplink_NAS_transport_p->eutran_cgi.pLMNidentity);
//#warning "TODO get cell id from RRC"
MACRO_ENB_ID_TO_CELL_IDENTITY(s1ap_eNB_instance_p->eNB_id,
0,
&uplink_NAS_transport_p->eutran_cgi.cell_ID);
/* MCC/MNC should be repeated in TAI and EUTRAN CGI */
MCC_MNC_TO_PLMNID(
s1ap_eNB_instance_p->mcc,
s1ap_eNB_instance_p->mnc,
s1ap_eNB_instance_p->mnc_digit_length,
&uplink_NAS_transport_p->tai.pLMNidentity);
TAC_TO_ASN1(s1ap_eNB_instance_p->tac, &uplink_NAS_transport_p->tai.tAC);
if (s1ap_eNB_encode_pdu(&message, &buffer, &length) < 0) {
S1AP_ERROR("Failed to encode uplink NAS transport\n");
/* Encode procedure has failed... */
return -1;
}
MSC_LOG_TX_MESSAGE(
MSC_S1AP_ENB,
MSC_S1AP_MME,
(const char *)NULL,
0,
MSC_AS_TIME_FMT" uplinkNASTransport initiatingMessage eNB_ue_s1ap_id %u mme_ue_s1ap_id %u",
0,0,//MSC_AS_TIME_ARGS(ctxt_pP),
uplink_NAS_transport_p->eNB_UE_S1AP_ID,
uplink_NAS_transport_p->mme_ue_s1ap_id);
/* UE associated signalling -> use the allocated stream */
s1ap_eNB_itti_send_sctp_data_req(s1ap_eNB_instance_p->instance,
ue_context_p->mme_ref->assoc_id, buffer,
length, ue_context_p->tx_stream);
return 0;
}
//------------------------------------------------------------------------------
void s1ap_eNB_nas_non_delivery_ind(instance_t instance,
s1ap_nas_non_delivery_ind_t *s1ap_nas_non_delivery_ind)
//------------------------------------------------------------------------------
{
struct s1ap_eNB_ue_context_s *ue_context_p;
s1ap_eNB_instance_t *s1ap_eNB_instance_p;
S1ap_NASNonDeliveryIndication_IEs_t *nas_non_delivery_p;
s1ap_message message;
uint8_t *buffer;
uint32_t length;
DevAssert(s1ap_nas_non_delivery_ind != NULL);
/* Retrieve the S1AP eNB instance associated with Mod_id */
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, s1ap_nas_non_delivery_ind->eNB_ue_s1ap_id)) == NULL) {
/* The context for this eNB ue s1ap id doesn't exist in the map of eNB UEs */
S1AP_WARN("Failed to find ue context associated with eNB ue s1ap id: %06x\n",
s1ap_nas_non_delivery_ind->eNB_ue_s1ap_id);
MSC_LOG_EVENT(
MSC_S1AP_ENB,
MSC_AS_TIME_FMT" Sent of NAS_NON_DELIVERY_IND to MME failed, no context for eNB_ue_s1ap_id %06x",
s1ap_nas_non_delivery_ind->eNB_ue_s1ap_id);
return;
}
/* Prepare the S1AP message to encode */
memset(&message, 0, sizeof(s1ap_message));
message.direction = S1AP_PDU_PR_initiatingMessage;
message.procedureCode = S1ap_ProcedureCode_id_NASNonDeliveryIndication;
nas_non_delivery_p = &message.msg.s1ap_NASNonDeliveryIndication_IEs;
nas_non_delivery_p->eNB_UE_S1AP_ID = ue_context_p->eNB_ue_s1ap_id;
nas_non_delivery_p->mme_ue_s1ap_id = ue_context_p->mme_ue_s1ap_id;
nas_non_delivery_p->nas_pdu.buf = s1ap_nas_non_delivery_ind->nas_pdu.buffer;
nas_non_delivery_p->nas_pdu.size = s1ap_nas_non_delivery_ind->nas_pdu.length;
/* Send a dummy cause */
nas_non_delivery_p->cause.present = S1ap_Cause_PR_radioNetwork;
nas_non_delivery_p->cause.choice.radioNetwork = S1ap_CauseRadioNetwork_radio_connection_with_ue_lost;
if (s1ap_eNB_encode_pdu(&message, &buffer, &length) < 0) {
S1AP_ERROR("Failed to encode NAS NON delivery indication\n");
/* Encode procedure has failed... */
MSC_LOG_EVENT(
MSC_S1AP_ENB,
MSC_AS_TIME_FMT" Sent of NAS_NON_DELIVERY_IND to MME failed (encoding)");
return;
}
MSC_LOG_TX_MESSAGE(
MSC_S1AP_ENB,
MSC_S1AP_MME,
(const char *)s1ap_nas_non_delivery_ind,
sizeof(s1ap_nas_non_delivery_ind_t),
MSC_AS_TIME_FMT" NASNonDeliveryIndication initiatingMessage eNB_ue_s1ap_id %u mme_ue_s1ap_id %u",
0,0,//MSC_AS_TIME_ARGS(ctxt_pP),
nas_non_delivery_p->eNB_UE_S1AP_ID,
nas_non_delivery_p->mme_ue_s1ap_id);
/* UE associated signalling -> use the allocated stream */
s1ap_eNB_itti_send_sctp_data_req(s1ap_eNB_instance_p->instance,
ue_context_p->mme_ref->assoc_id, buffer,
length, ue_context_p->tx_stream);
}
//------------------------------------------------------------------------------
int s1ap_eNB_initial_ctxt_resp(
instance_t instance, s1ap_initial_context_setup_resp_t *initial_ctxt_resp_p)
//------------------------------------------------------------------------------
{
s1ap_eNB_instance_t *s1ap_eNB_instance_p = NULL;
struct s1ap_eNB_ue_context_s *ue_context_p = NULL;
S1ap_InitialContextSetupResponseIEs_t *initial_ies_p = NULL;
s1ap_message message;
uint8_t *buffer = NULL;
uint32_t length;
int ret = -1;
int i;
/* Retrieve the S1AP eNB instance associated with Mod_id */
s1ap_eNB_instance_p = s1ap_eNB_get_instance(instance);
DevAssert(initial_ctxt_resp_p != NULL);
DevAssert(s1ap_eNB_instance_p != NULL);
if ((ue_context_p = s1ap_eNB_get_ue_context(s1ap_eNB_instance_p,
initial_ctxt_resp_p->eNB_ue_s1ap_id)) == NULL) {
/* The context for this eNB ue s1ap id doesn't exist in the map of eNB UEs */
S1AP_WARN("Failed to find ue context associated with eNB ue s1ap id: 0x%06x\n",
initial_ctxt_resp_p->eNB_ue_s1ap_id);
return -1;
}
/* Uplink NAS transport can occur either during an s1ap connected state
* or during initial attach (for example: NAS authentication).
*/
if (!(ue_context_p->ue_state == S1AP_UE_CONNECTED ||
ue_context_p->ue_state == S1AP_UE_WAITING_CSR)) {
S1AP_WARN("You are attempting to send NAS data over non-connected "
"eNB ue s1ap id: %06x, current state: %d\n",
initial_ctxt_resp_p->eNB_ue_s1ap_id, ue_context_p->ue_state);
return -1;
}
/* Prepare the S1AP message to encode */
memset(&message, 0, sizeof(s1ap_message));
message.direction = S1AP_PDU_PR_successfulOutcome;
message.procedureCode = S1ap_ProcedureCode_id_InitialContextSetup;
initial_ies_p = &message.msg.s1ap_InitialContextSetupResponseIEs;
initial_ies_p->eNB_UE_S1AP_ID = initial_ctxt_resp_p->eNB_ue_s1ap_id;
initial_ies_p->mme_ue_s1ap_id = ue_context_p->mme_ue_s1ap_id;
for (i = 0; i < initial_ctxt_resp_p->nb_of_e_rabs; i++) {
S1ap_E_RABSetupItemCtxtSURes_t *new_item;
new_item = calloc(1, sizeof(S1ap_E_RABSetupItemCtxtSURes_t));
new_item->e_RAB_ID = initial_ctxt_resp_p->e_rabs[i].e_rab_id;
GTP_TEID_TO_ASN1(initial_ctxt_resp_p->e_rabs[i].gtp_teid, &new_item->gTP_TEID);
new_item->transportLayerAddress.buf = initial_ctxt_resp_p->e_rabs[i].eNB_addr.buffer;
new_item->transportLayerAddress.size = initial_ctxt_resp_p->e_rabs[i].eNB_addr.length;
new_item->transportLayerAddress.bits_unused = 0;
ASN_SEQUENCE_ADD(&initial_ies_p->e_RABSetupListCtxtSURes.s1ap_E_RABSetupItemCtxtSURes,
new_item);
}
if (s1ap_eNB_encode_pdu(&message, &buffer, &length) < 0) {
S1AP_ERROR("Failed to encode uplink NAS transport\n");
/* Encode procedure has failed... */
return -1;
}
MSC_LOG_TX_MESSAGE(
MSC_S1AP_ENB,
MSC_S1AP_MME,
(const char *)buffer,
length,
MSC_AS_TIME_FMT" InitialContextSetup successfulOutcome eNB_ue_s1ap_id %u mme_ue_s1ap_id %u",
0,0,//MSC_AS_TIME_ARGS(ctxt_pP),
initial_ies_p->eNB_UE_S1AP_ID,
initial_ies_p->mme_ue_s1ap_id);
/* UE associated signalling -> use the allocated stream */
s1ap_eNB_itti_send_sctp_data_req(s1ap_eNB_instance_p->instance,
ue_context_p->mme_ref->assoc_id, buffer,
length, ue_context_p->tx_stream);
return ret;
}
//------------------------------------------------------------------------------
int s1ap_eNB_ue_capabilities(instance_t instance,
s1ap_ue_cap_info_ind_t *ue_cap_info_ind_p)
//------------------------------------------------------------------------------
{
s1ap_eNB_instance_t *s1ap_eNB_instance_p;
struct s1ap_eNB_ue_context_s *ue_context_p;
S1ap_UECapabilityInfoIndicationIEs_t *ue_cap_info_ind_ies_p;
s1ap_message message;
uint8_t *buffer;
uint32_t length;
int ret = -1;
/* Retrieve the S1AP eNB instance associated with Mod_id */
s1ap_eNB_instance_p = s1ap_eNB_get_instance(instance);
DevAssert(ue_cap_info_ind_p != NULL);
DevAssert(s1ap_eNB_instance_p != NULL);
if ((ue_context_p = s1ap_eNB_get_ue_context(s1ap_eNB_instance_p,
ue_cap_info_ind_p->eNB_ue_s1ap_id)) == NULL) {
/* The context for this eNB ue s1ap id doesn't exist in the map of eNB UEs */
S1AP_WARN("Failed to find ue context associated with eNB ue s1ap id: %u\n",
ue_cap_info_ind_p->eNB_ue_s1ap_id);
return -1;
}
/* UE capabilities message can occur either during an s1ap connected state
* or during initial attach (for example: NAS authentication).
*/
if (!(ue_context_p->ue_state == S1AP_UE_CONNECTED ||
ue_context_p->ue_state == S1AP_UE_WAITING_CSR)) {
S1AP_WARN("You are attempting to send NAS data over non-connected "
"eNB ue s1ap id: %u, current state: %d\n",
ue_cap_info_ind_p->eNB_ue_s1ap_id, ue_context_p->ue_state);
return -1;
}
/* Prepare the S1AP message to encode */
memset(&message, 0, sizeof(s1ap_message));
message.direction = S1AP_PDU_PR_initiatingMessage;
message.procedureCode = S1ap_ProcedureCode_id_UECapabilityInfoIndication;
ue_cap_info_ind_ies_p = &message.msg.s1ap_UECapabilityInfoIndicationIEs;
ue_cap_info_ind_ies_p->ueRadioCapability.buf = ue_cap_info_ind_p->ue_radio_cap.buffer;
ue_cap_info_ind_ies_p->ueRadioCapability.size = ue_cap_info_ind_p->ue_radio_cap.length;
ue_cap_info_ind_ies_p->eNB_UE_S1AP_ID = ue_cap_info_ind_p->eNB_ue_s1ap_id;
ue_cap_info_ind_ies_p->mme_ue_s1ap_id = ue_context_p->mme_ue_s1ap_id;
if (s1ap_eNB_encode_pdu(&message, &buffer, &length) < 0) {
/* Encode procedure has failed... */
S1AP_ERROR("Failed to encode UE capabilities indication\n");
return -1;
}
MSC_LOG_TX_MESSAGE(
MSC_S1AP_ENB,
MSC_S1AP_MME,
(const char *)buffer,
length,
MSC_AS_TIME_FMT" UECapabilityInfoIndication initiatingMessage eNB_ue_s1ap_id %u mme_ue_s1ap_id %u",
0,0,//MSC_AS_TIME_ARGS(ctxt_pP),
ue_cap_info_ind_ies_p->eNB_UE_S1AP_ID,
ue_cap_info_ind_ies_p->mme_ue_s1ap_id);
/* UE associated signalling -> use the allocated stream */
s1ap_eNB_itti_send_sctp_data_req(s1ap_eNB_instance_p->instance,
ue_context_p->mme_ref->assoc_id, buffer,
length, ue_context_p->tx_stream);
return ret;
}