git-svn-id: http://svn.eurecom.fr/openair4G/trunk@7382 818b1a75-f10b-46b9-bf7c-635c3b92a50f
766 lines
30 KiB
C
766 lines
30 KiB
C
/*******************************************************************************
|
|
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 <http://www.gnu.org/licenses/>.
|
|
|
|
Contact Information
|
|
OpenAirInterface Admin: openair_admin@eurecom.fr
|
|
OpenAirInterface Tech : openair_tech@eurecom.fr
|
|
OpenAirInterface Dev : openair4g-devel@eurecom.fr
|
|
|
|
Address : Eurecom, Compus SophiaTech 450, route des chappes, 06451 Biot, France.
|
|
|
|
*******************************************************************************/
|
|
|
|
#include <stdio.h>
|
|
#include <stdint.h>
|
|
|
|
|
|
#include "s1ap_common.h"
|
|
#include "s1ap_ies_defs.h"
|
|
#include "s1ap_mme_encoder.h"
|
|
#include "s1ap_mme_handlers.h"
|
|
#include "s1ap_mme_nas_procedures.h"
|
|
#include "s1ap_mme_retransmission.h"
|
|
|
|
#include "s1ap_mme_itti_messaging.h"
|
|
|
|
#include "s1ap_mme.h"
|
|
|
|
#include "intertask_interface.h"
|
|
#include "timer.h"
|
|
|
|
#include "assertions.h"
|
|
#include "conversions.h"
|
|
#include "msc.h"
|
|
|
|
/* Every time a new UE is associated, increment this variable.
|
|
* But care if it wraps to increment also the mme_ue_s1ap_id_has_wrapped
|
|
* variable. Limit: UINT32_MAX (in stdint.h).
|
|
*/
|
|
static uint32_t mme_ue_s1ap_id = 0;
|
|
static uint8_t mme_ue_s1ap_id_has_wrapped = 0;
|
|
|
|
extern const char *s1ap_direction2String[];
|
|
|
|
|
|
int s1ap_mme_handle_initial_ue_message(uint32_t assoc_id, uint32_t stream,
|
|
struct s1ap_message_s *message)
|
|
{
|
|
S1ap_InitialUEMessageIEs_t *initialUEMessage_p;
|
|
ue_description_t *ue_ref;
|
|
eNB_description_t *eNB_ref;
|
|
uint32_t eNB_ue_s1ap_id;
|
|
|
|
initialUEMessage_p = &message->msg.s1ap_InitialUEMessageIEs;
|
|
|
|
MSC_LOG_RX_MESSAGE(
|
|
MSC_S1AP_MME,
|
|
MSC_S1AP_ENB,
|
|
NULL,0,
|
|
"0 initialUEMessage/%s assoc_id %u stream %u "S1AP_UE_ID_FMT" ",
|
|
s1ap_direction2String[message->direction],
|
|
assoc_id, stream, initialUEMessage_p->eNB_UE_S1AP_ID);
|
|
|
|
if ((eNB_ref = s1ap_is_eNB_assoc_id_in_list(assoc_id)) == NULL) {
|
|
S1AP_DEBUG("Unkwnon eNB on assoc_id %d\n", assoc_id);
|
|
return -1;
|
|
}
|
|
|
|
// eNB UE S1AP ID is limited to 24 bits
|
|
eNB_ue_s1ap_id = (uint32_t)(initialUEMessage_p->eNB_UE_S1AP_ID & 0x00ffffff);
|
|
|
|
S1AP_DEBUG("New Initial UE message received with eNB UE S1AP ID: "S1AP_UE_ID_FMT"\n",
|
|
eNB_ue_s1ap_id);
|
|
|
|
ue_ref = s1ap_is_ue_eNB_id_in_list(eNB_ref, eNB_ue_s1ap_id);
|
|
|
|
if (ue_ref == NULL) {
|
|
uint16_t tac = 0;
|
|
|
|
/* This UE eNB Id has currently no known s1 association.
|
|
* Create new UE context by associating new mme_ue_s1ap_id.
|
|
* Update eNB UE list.
|
|
* Forward message to NAS.
|
|
*/
|
|
if ((ue_ref = s1ap_new_ue(assoc_id)) == NULL)
|
|
// If we failed to allocate a new UE return -1
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
ue_ref->s1_ue_state = S1AP_UE_WAITING_CSR;
|
|
ue_ref->eNB_ue_s1ap_id = eNB_ue_s1ap_id;
|
|
ue_ref->mme_ue_s1ap_id = (uint32_t)ue_ref;
|
|
// On which stream we received the message
|
|
ue_ref->sctp_stream_recv = stream;
|
|
ue_ref->sctp_stream_send = ue_ref->eNB->next_sctp_stream;
|
|
|
|
/* Increment the sctp stream for the eNB association.
|
|
* If the next sctp stream is >= outstream negociated between eNB and MME,
|
|
* wrap to first stream.
|
|
* TODO: search for the first available stream instead.
|
|
*/
|
|
if (ue_ref->eNB->next_sctp_stream++ >= ue_ref->eNB->outstreams) {
|
|
ue_ref->eNB->next_sctp_stream = 1;
|
|
}
|
|
|
|
/* Increment the unique UE mme s1ap id and
|
|
* take care about overflow case.
|
|
*/
|
|
if (mme_ue_s1ap_id_has_wrapped == 0) {
|
|
mme_ue_s1ap_id++;
|
|
|
|
if (mme_ue_s1ap_id == 0) {
|
|
mme_ue_s1ap_id_has_wrapped = 1;
|
|
}
|
|
} else {
|
|
/* TODO: should take the first available mme_ue_s1ap_id instead of
|
|
* the mme_ue_s1ap_id variable.
|
|
*/
|
|
DevMessage("mme ue s1ap id has wrapped -> case not handled\n");
|
|
}
|
|
|
|
s1ap_dump_eNB(ue_ref->eNB);
|
|
|
|
OCTET_STRING_TO_TAC(&initialUEMessage_p->tai.tAC, tac);
|
|
|
|
/* We received the first NAS transport message: initial UE message.
|
|
* Send a NAS ESTABLISH IND to NAS layer
|
|
*/
|
|
#if defined(ORIGINAL_CODE)
|
|
s1ap_mme_itti_nas_establish_ind(
|
|
ue_ref->mme_ue_s1ap_id,
|
|
initialUEMessage_p->nas_pdu.buf,
|
|
initialUEMessage_p->nas_pdu.size,
|
|
initialUEMessage_p->rrC_Establishment_Cause,
|
|
tac);
|
|
#else
|
|
s1ap_mme_itti_mme_app_establish_ind(
|
|
ue_ref->mme_ue_s1ap_id,
|
|
initialUEMessage_p->nas_pdu.buf,
|
|
initialUEMessage_p->nas_pdu.size,
|
|
initialUEMessage_p->rrC_Establishment_Cause,
|
|
tac);
|
|
#endif
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int s1ap_mme_handle_uplink_nas_transport(uint32_t assoc_id, uint32_t stream,
|
|
struct s1ap_message_s *message)
|
|
{
|
|
S1ap_UplinkNASTransportIEs_t *uplinkNASTransport_p;
|
|
ue_description_t *ue_ref;
|
|
|
|
uplinkNASTransport_p = &message->msg.s1ap_UplinkNASTransportIEs;
|
|
|
|
MSC_LOG_RX_MESSAGE(
|
|
MSC_S1AP_MME,
|
|
MSC_S1AP_ENB,
|
|
NULL,0,
|
|
"0 uplinkNASTransport/%s mme_ue_s1ap_id "S1AP_UE_ID_FMT" eNB_ue_s1ap_id "S1AP_UE_ID_FMT" nas len %u",
|
|
s1ap_direction2String[message->direction],
|
|
uplinkNASTransport_p->mme_ue_s1ap_id,
|
|
uplinkNASTransport_p->eNB_UE_S1AP_ID,
|
|
uplinkNASTransport_p->nas_pdu.size);
|
|
|
|
if ((ue_ref = s1ap_is_ue_mme_id_in_list(uplinkNASTransport_p->mme_ue_s1ap_id))
|
|
== NULL) {
|
|
S1AP_DEBUG("No UE is attached to this mme UE s1ap id: "S1AP_UE_ID_FMT"\n",
|
|
(int)uplinkNASTransport_p->mme_ue_s1ap_id);
|
|
return -1;
|
|
}
|
|
|
|
if (ue_ref->s1_ue_state != S1AP_UE_CONNECTED) {
|
|
S1AP_DEBUG("Received uplink NAS transport while UE in state != S1AP_UE_CONNECTED\n");
|
|
return -1;
|
|
}
|
|
|
|
//TODO: forward NAS PDU to NAS
|
|
#if defined(DISABLE_USE_NAS)
|
|
DevMessage("Can't go further (TODO)\n");
|
|
#else
|
|
s1ap_mme_itti_nas_uplink_ind(uplinkNASTransport_p->mme_ue_s1ap_id, uplinkNASTransport_p->nas_pdu.buf,
|
|
uplinkNASTransport_p->nas_pdu.size);
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int s1ap_mme_handle_nas_non_delivery(uint32_t assoc_id, uint32_t stream,
|
|
struct s1ap_message_s *message)
|
|
{
|
|
S1ap_NASNonDeliveryIndication_IEs_t *nasNonDeliveryIndication_p = NULL;
|
|
ue_description_t *ue_ref = NULL;
|
|
|
|
/* UE associated signalling on stream == 0 is not valid. */
|
|
if (stream == 0) {
|
|
S1AP_DEBUG("Received new nas non delivery on stream == 0\n");
|
|
return -1;
|
|
}
|
|
|
|
nasNonDeliveryIndication_p = &message->msg.s1ap_NASNonDeliveryIndication_IEs;
|
|
|
|
MSC_LOG_RX_MESSAGE(
|
|
MSC_S1AP_MME,
|
|
MSC_S1AP_ENB,
|
|
NULL,0,
|
|
"0 NASNonDeliveryIndication/%s mme_ue_s1ap_id "S1AP_UE_ID_FMT" eNB_ue_s1ap_id "S1AP_UE_ID_FMT" cause %u nas len %u",
|
|
s1ap_direction2String[message->direction],
|
|
nasNonDeliveryIndication_p->mme_ue_s1ap_id,
|
|
nasNonDeliveryIndication_p->eNB_UE_S1AP_ID,
|
|
nasNonDeliveryIndication_p->cause,
|
|
nasNonDeliveryIndication_p->nas_pdu.size);
|
|
|
|
if ((ue_ref = s1ap_is_ue_mme_id_in_list(nasNonDeliveryIndication_p->mme_ue_s1ap_id))
|
|
== NULL) {
|
|
S1AP_DEBUG("No UE is attached to this mme UE s1ap id: "S1AP_UE_ID_FMT"\n",
|
|
(int)nasNonDeliveryIndication_p->mme_ue_s1ap_id);
|
|
return -1;
|
|
}
|
|
|
|
if (ue_ref->s1_ue_state != S1AP_UE_CONNECTED) {
|
|
S1AP_DEBUG("Received uplink NASNonDeliveryIndication while UE in state != S1AP_UE_CONNECTED\n");
|
|
return -1;
|
|
}
|
|
|
|
//TODO: forward NAS PDU to NAS
|
|
s1ap_mme_itti_nas_non_delivery_ind(
|
|
nasNonDeliveryIndication_p->mme_ue_s1ap_id,
|
|
nasNonDeliveryIndication_p->nas_pdu.buf,
|
|
nasNonDeliveryIndication_p->nas_pdu.size);
|
|
return 0;
|
|
}
|
|
|
|
int s1ap_generate_downlink_nas_transport(const uint32_t ue_id, void * const data,
|
|
const uint32_t size)
|
|
{
|
|
ue_description_t *ue_ref;
|
|
uint8_t *buffer_p;
|
|
uint32_t length;
|
|
|
|
if ((ue_ref = s1ap_is_ue_mme_id_in_list(ue_id)) == NULL) {
|
|
/* If the UE-associated logical S1-connection is not established,
|
|
* the MME shall allocate a unique MME UE S1AP ID to be used for the UE.
|
|
*/
|
|
S1AP_DEBUG("Unknown UE MME ID "S1AP_UE_ID_FMT", This case is not handled right now\n", ue_id);
|
|
|
|
return -1;
|
|
} else {
|
|
/* We have fount the UE in the list.
|
|
* Create new IE list message and encode it.
|
|
*/
|
|
S1ap_DownlinkNASTransportIEs_t *downlinkNasTransport = NULL;
|
|
|
|
s1ap_message message;
|
|
|
|
memset(&message, 0, sizeof(s1ap_message));
|
|
|
|
message.procedureCode = S1ap_ProcedureCode_id_downlinkNASTransport;
|
|
message.direction = S1AP_PDU_PR_initiatingMessage;
|
|
|
|
ue_ref->s1_ue_state = S1AP_UE_CONNECTED;
|
|
|
|
downlinkNasTransport = &message.msg.s1ap_DownlinkNASTransportIEs;
|
|
|
|
/* Setting UE informations with the ones fount in ue_ref */
|
|
downlinkNasTransport->mme_ue_s1ap_id = ue_ref->mme_ue_s1ap_id;
|
|
downlinkNasTransport->eNB_UE_S1AP_ID = ue_ref->eNB_ue_s1ap_id;
|
|
|
|
/* Fill in the NAS pdu */
|
|
OCTET_STRING_fromBuf(&downlinkNasTransport->nas_pdu, (char*)data, size);
|
|
|
|
if (s1ap_mme_encode_pdu(&message, &buffer_p, &length) < 0) {
|
|
// TODO: handle something
|
|
return -1;
|
|
}
|
|
|
|
S1AP_DEBUG("Send S1ap_ProcedureCode_id_downlinkNASTransport ue_id = "S1AP_UE_ID_FMT" mme_ue_s1ap_id = "S1AP_UE_ID_FMT" eNB_UE_S1AP_ID = "S1AP_UE_ID_FMT"\n",
|
|
ue_id,
|
|
downlinkNasTransport->mme_ue_s1ap_id,
|
|
downlinkNasTransport->eNB_UE_S1AP_ID);
|
|
|
|
MSC_LOG_TX_MESSAGE(
|
|
MSC_S1AP_MME,
|
|
MSC_S1AP_ENB,
|
|
NULL,0,
|
|
"0 downlinkNASTransport/initiatingMessage ue_id "S1AP_UE_ID_FMT" mme_ue_s1ap_id "S1AP_UE_ID_FMT" eNB_ue_s1ap_id"S1AP_UE_ID_FMT" nas length %u",
|
|
ue_id,
|
|
downlinkNasTransport->mme_ue_s1ap_id,
|
|
downlinkNasTransport->eNB_UE_S1AP_ID,
|
|
size);
|
|
|
|
s1ap_mme_itti_send_sctp_request(buffer_p, length,
|
|
ue_ref->eNB->sctp_assoc_id,
|
|
ue_ref->sctp_stream_send);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
#if defined(DISABLE_USE_NAS)
|
|
int s1ap_handle_attach_accepted(nas_attach_accept_t *attach_accept_p)
|
|
{
|
|
/* We received create session response from S-GW on S11 interface abstraction.
|
|
* At least one bearer has been established. We can now send s1ap initial context setup request
|
|
* message to eNB.
|
|
*/
|
|
uint8_t supportedAlgorithms[] = { 0x00, 0x02 };
|
|
uint8_t offset = 0;
|
|
uint8_t *buffer_p;
|
|
uint32_t length;
|
|
|
|
ue_description_t *ue_ref = NULL;
|
|
s1ap_message message;
|
|
s1ap_initial_ctxt_setup_req_t *initial_p;
|
|
|
|
S1ap_InitialContextSetupRequestIEs_t *initialContextSetupRequest_p;
|
|
S1ap_E_RABToBeSetupItemCtxtSUReq_t e_RABToBeSetup;
|
|
|
|
DevAssert(attach_accept_p != NULL);
|
|
|
|
initial_p = &attach_accept_p->transparent;
|
|
|
|
if ((ue_ref = s1ap_is_ue_mme_id_in_list(initial_p->mme_ue_s1ap_id)) == NULL) {
|
|
S1AP_DEBUG("This mme ue s1ap id ("S1AP_UE_ID_FMT") is not attached to any UE context\n",
|
|
initial_p->mme_ue_s1ap_id);
|
|
return -1;
|
|
}
|
|
|
|
/* Start the outcome response timer.
|
|
* When time is reached, MME consider that procedure outcome has failed.
|
|
*/
|
|
// timer_setup(mme_config.s1ap_config.outcome_drop_timer_sec, 0, TASK_S1AP, INSTANCE_DEFAULT,
|
|
// TIMER_ONE_SHOT,
|
|
// NULL,
|
|
// &ue_ref->outcome_response_timer_id);
|
|
/* Insert the timer in the MAP of mme_ue_s1ap_id <-> timer_id */
|
|
// s1ap_timer_insert(ue_ref->mme_ue_s1ap_id, ue_ref->outcome_response_timer_id);
|
|
|
|
memset(&message, 0, sizeof(s1ap_message));
|
|
memset(&e_RABToBeSetup, 0, sizeof(S1ap_E_RABToBeSetupItemCtxtSUReq_t));
|
|
|
|
message.procedureCode = S1ap_ProcedureCode_id_InitialContextSetup;
|
|
message.direction = S1AP_PDU_PR_initiatingMessage;
|
|
|
|
initialContextSetupRequest_p = &message.msg.s1ap_InitialContextSetupRequestIEs;
|
|
|
|
initialContextSetupRequest_p->mme_ue_s1ap_id = (unsigned long)ue_ref->mme_ue_s1ap_id;
|
|
initialContextSetupRequest_p->eNB_UE_S1AP_ID = (unsigned long)ue_ref->eNB_ue_s1ap_id;
|
|
|
|
/* uEaggregateMaximumBitrateDL and uEaggregateMaximumBitrateUL expressed in term of bits/sec */
|
|
initialContextSetupRequest_p->uEaggregateMaximumBitrate.uEaggregateMaximumBitRateDL = initial_p->ambr.br_dl;
|
|
initialContextSetupRequest_p->uEaggregateMaximumBitrate.uEaggregateMaximumBitRateUL = initial_p->ambr.br_ul;
|
|
|
|
e_RABToBeSetup.e_RAB_ID = initial_p->ebi;
|
|
e_RABToBeSetup.e_RABlevelQoSParameters.qCI = initial_p->qci;
|
|
e_RABToBeSetup.e_RABlevelQoSParameters.allocationRetentionPriority.priorityLevel
|
|
= initial_p->prio_level; //No priority
|
|
e_RABToBeSetup.e_RABlevelQoSParameters.allocationRetentionPriority.pre_emptionCapability
|
|
= initial_p->pre_emp_capability;
|
|
e_RABToBeSetup.e_RABlevelQoSParameters.allocationRetentionPriority.pre_emptionVulnerability
|
|
= initial_p->pre_emp_vulnerability;
|
|
|
|
/* Set the GTP-TEID. This is the S1-U S-GW TEID */
|
|
INT32_TO_OCTET_STRING(initial_p->teid, &e_RABToBeSetup.gTP_TEID);
|
|
|
|
/* S-GW IP address(es) for user-plane */
|
|
if ((initial_p->s_gw_address.pdn_type == IPv4) ||
|
|
(initial_p->s_gw_address.pdn_type == IPv4_AND_v6)) {
|
|
e_RABToBeSetup.transportLayerAddress.buf = calloc(4, sizeof(uint8_t));
|
|
/* Only IPv4 supported */
|
|
memcpy(e_RABToBeSetup.transportLayerAddress.buf,
|
|
initial_p->s_gw_address.address.ipv4_address,
|
|
4);
|
|
offset += 4;
|
|
e_RABToBeSetup.transportLayerAddress.size = 4;
|
|
e_RABToBeSetup.transportLayerAddress.bits_unused = 0;
|
|
}
|
|
|
|
if ((initial_p->s_gw_address.pdn_type == IPv6) ||
|
|
(initial_p->s_gw_address.pdn_type == IPv4_AND_v6)) {
|
|
if (offset == 0) {
|
|
/* Both IPv4 and IPv6 provided */
|
|
/* TODO: check memory allocation */
|
|
e_RABToBeSetup.transportLayerAddress.buf = calloc(16, sizeof(uint8_t));
|
|
} else {
|
|
/* Only IPv6 supported */
|
|
/* TODO: check memory allocation */
|
|
e_RABToBeSetup.transportLayerAddress.buf
|
|
= realloc(e_RABToBeSetup.transportLayerAddress.buf, (16 + offset) * sizeof(uint8_t));
|
|
}
|
|
|
|
memcpy(&e_RABToBeSetup.transportLayerAddress.buf[offset],
|
|
initial_p->s_gw_address.address.ipv6_address,
|
|
16);
|
|
e_RABToBeSetup.transportLayerAddress.size = 16 + offset;
|
|
e_RABToBeSetup.transportLayerAddress.bits_unused = 0;
|
|
}
|
|
|
|
ASN_SEQUENCE_ADD(&initialContextSetupRequest_p->e_RABToBeSetupListCtxtSUReq,
|
|
&e_RABToBeSetup);
|
|
|
|
initialContextSetupRequest_p->ueSecurityCapabilities.encryptionAlgorithms.buf =
|
|
(uint8_t *)supportedAlgorithms;
|
|
initialContextSetupRequest_p->ueSecurityCapabilities.encryptionAlgorithms.size = 2;
|
|
initialContextSetupRequest_p->ueSecurityCapabilities.encryptionAlgorithms.bits_unused
|
|
= 0;
|
|
|
|
initialContextSetupRequest_p->ueSecurityCapabilities.integrityProtectionAlgorithms.buf
|
|
= (uint8_t *)supportedAlgorithms;
|
|
initialContextSetupRequest_p->ueSecurityCapabilities.integrityProtectionAlgorithms.size
|
|
= 2;
|
|
initialContextSetupRequest_p->ueSecurityCapabilities.integrityProtectionAlgorithms.bits_unused
|
|
= 0;
|
|
|
|
initialContextSetupRequest_p->securityKey.buf = initial_p->keNB; /* 256 bits length */
|
|
initialContextSetupRequest_p->securityKey.size = 32;
|
|
initialContextSetupRequest_p->securityKey.bits_unused = 0;
|
|
|
|
if (s1ap_mme_encode_pdu(&message, &buffer_p, &length) < 0) {
|
|
// TODO: handle something
|
|
return -1;
|
|
}
|
|
|
|
return s1ap_mme_itti_send_sctp_request(buffer_p, length, ue_ref->eNB->sctp_assoc_id,
|
|
ue_ref->sctp_stream_send);
|
|
}
|
|
#else
|
|
//void s1ap_handle_conn_est_cnf(nas_conn_est_cnf_t *nas_conn_est_cnf_p)
|
|
//{
|
|
// /* We received create session response from S-GW on S11 interface abstraction.
|
|
// * At least one bearer has been established. We can now send s1ap initial context setup request
|
|
// * message to eNB.
|
|
// */
|
|
// uint8_t supportedAlgorithms[] = { 0x00, 0x00 };
|
|
// uint8_t offset = 0;
|
|
// uint8_t *buffer_p;
|
|
// uint32_t length, teid = 12;
|
|
//
|
|
// ue_description_t *ue_ref = NULL;
|
|
// s1ap_message message;
|
|
//
|
|
// S1ap_InitialContextSetupRequestIEs_t *initialContextSetupRequest_p;
|
|
// S1ap_E_RABToBeSetupItemCtxtSUReq_t e_RABToBeSetup;
|
|
// S1ap_NAS_PDU_t nas_pdu;
|
|
//
|
|
// DevAssert(nas_conn_est_cnf_p != NULL);
|
|
//
|
|
// if ((ue_ref = s1ap_is_ue_mme_id_in_list(nas_conn_est_cnf_p->UEid)) == NULL) {
|
|
// S1AP_DEBUG("This mme ue s1ap id (%08x) is not attached to any UE context\n",
|
|
// nas_conn_est_cnf_p->UEid);
|
|
// DevParam(nas_conn_est_cnf_p->UEid, 0, 0);
|
|
// }
|
|
//
|
|
// /* Start the outcome response timer.
|
|
// * When time is reached, MME consider that procedure outcome has failed.
|
|
// */
|
|
//// timer_setup(mme_config.s1ap_config.outcome_drop_timer_sec, 0, TASK_S1AP, INSTANCE_DEFAULT,
|
|
//// TIMER_ONE_SHOT,
|
|
//// NULL,
|
|
//// &ue_ref->outcome_response_timer_id);
|
|
// /* Insert the timer in the MAP of mme_ue_s1ap_id <-> timer_id */
|
|
//// s1ap_timer_insert(ue_ref->mme_ue_s1ap_id, ue_ref->outcome_response_timer_id);
|
|
//
|
|
// memset(&message, 0, sizeof(s1ap_message));
|
|
// memset(&e_RABToBeSetup, 0, sizeof(S1ap_E_RABToBeSetupItemCtxtSUReq_t));
|
|
//
|
|
// message.procedureCode = S1ap_ProcedureCode_id_InitialContextSetup;
|
|
// message.direction = S1AP_PDU_PR_initiatingMessage;
|
|
//
|
|
// initialContextSetupRequest_p = &message.msg.s1ap_InitialContextSetupRequestIEs;
|
|
//
|
|
// initialContextSetupRequest_p->mme_ue_s1ap_id = (unsigned long)ue_ref->mme_ue_s1ap_id;
|
|
// initialContextSetupRequest_p->eNB_UE_S1AP_ID = (unsigned long)ue_ref->eNB_ue_s1ap_id;
|
|
//
|
|
// /* uEaggregateMaximumBitrateDL and uEaggregateMaximumBitrateUL expressed in term of bits/sec */
|
|
//// initialContextSetupRequest_p->uEaggregateMaximumBitrate.uEaggregateMaximumBitRateDL = initial_p->ambr.br_dl;
|
|
//// initialContextSetupRequest_p->uEaggregateMaximumBitrate.uEaggregateMaximumBitRateUL = initial_p->ambr.br_ul;
|
|
//
|
|
// initialContextSetupRequest_p->uEaggregateMaximumBitrate.uEaggregateMaximumBitRateDL = 1024 * 1024;
|
|
// initialContextSetupRequest_p->uEaggregateMaximumBitrate.uEaggregateMaximumBitRateDL = 512 * 1024;
|
|
//
|
|
//// e_RABToBeSetup.e_RAB_ID = initial_p->ebi;
|
|
// e_RABToBeSetup.e_RAB_ID = 5;
|
|
//// e_RABToBeSetup.e_RABlevelQoSParameters.qCI = initial_p->qci;
|
|
// e_RABToBeSetup.e_RABlevelQoSParameters.qCI = 0;
|
|
//
|
|
// memset(&nas_pdu, 0, sizeof(nas_pdu));
|
|
//
|
|
// nas_pdu.size = nas_conn_est_cnf_p->nasMsg.length;
|
|
// nas_pdu.buf = nas_conn_est_cnf_p->nasMsg.data;
|
|
//
|
|
// e_RABToBeSetup.nAS_PDU = &nas_pdu;
|
|
// e_RABToBeSetup.e_RABlevelQoSParameters.allocationRetentionPriority.priorityLevel =
|
|
// S1ap_PriorityLevel_lowest;
|
|
// e_RABToBeSetup.e_RABlevelQoSParameters.allocationRetentionPriority.pre_emptionCapability =
|
|
// S1ap_Pre_emptionCapability_shall_not_trigger_pre_emption;
|
|
// e_RABToBeSetup.e_RABlevelQoSParameters.allocationRetentionPriority.pre_emptionVulnerability =
|
|
// S1ap_Pre_emptionVulnerability_not_pre_emptable;
|
|
// INT32_TO_OCTET_STRING(teid, &e_RABToBeSetup.gTP_TEID);
|
|
//// e_RABToBeSetup.e_RABlevelQoSParameters.allocationRetentionPriority.priorityLevel
|
|
//// = initial_p->prio_level; //No priority
|
|
//// e_RABToBeSetup.e_RABlevelQoSParameters.allocationRetentionPriority.pre_emptionCapability
|
|
//// = initial_p->pre_emp_capability;
|
|
//// e_RABToBeSetup.e_RABlevelQoSParameters.allocationRetentionPriority.pre_emptionVulnerability
|
|
//// = initial_p->pre_emp_vulnerability;
|
|
//
|
|
// /* Set the GTP-TEID. This is the S1-U S-GW TEID */
|
|
//// INT32_TO_OCTET_STRING(initial_p->teid, &e_RABToBeSetup.gTP_TEID);
|
|
//
|
|
// /* S-GW IP address(es) for user-plane */
|
|
//// if ((initial_p->s_gw_address.pdn_type == IPv4) ||
|
|
//// (initial_p->s_gw_address.pdn_type == IPv4_AND_v6))
|
|
//// {
|
|
//// e_RABToBeSetup.transportLayerAddress.buf = calloc(4, sizeof(uint8_t));
|
|
//// /* Only IPv4 supported */
|
|
//// memcpy(e_RABToBeSetup.transportLayerAddress.buf,
|
|
//// initial_p->s_gw_address.address.ipv4_address,
|
|
//// 4);
|
|
//// offset += 4;
|
|
//// e_RABToBeSetup.transportLayerAddress.size = 4;
|
|
//// e_RABToBeSetup.transportLayerAddress.bits_unused = 0;
|
|
//// }
|
|
//// if ((initial_p->s_gw_address.pdn_type == IPv6) ||
|
|
//// (initial_p->s_gw_address.pdn_type == IPv4_AND_v6))
|
|
//// {
|
|
//// if (offset == 0) {
|
|
//// /* Both IPv4 and IPv6 provided */
|
|
//// /* TODO: check memory allocation */
|
|
//// e_RABToBeSetup.transportLayerAddress.buf = calloc(16, sizeof(uint8_t));
|
|
//// } else {
|
|
//// /* Only IPv6 supported */
|
|
//// /* TODO: check memory allocation */
|
|
//// e_RABToBeSetup.transportLayerAddress.buf
|
|
//// = realloc(e_RABToBeSetup.transportLayerAddress.buf, (16 + offset) * sizeof(uint8_t));
|
|
//// }
|
|
//// memcpy(&e_RABToBeSetup.transportLayerAddress.buf[offset],
|
|
//// initial_p->s_gw_address.address.ipv6_address,
|
|
//// 16);
|
|
//// e_RABToBeSetup.transportLayerAddress.size = 16 + offset;
|
|
//// e_RABToBeSetup.transportLayerAddress.bits_unused = 0;
|
|
//// }
|
|
//
|
|
// ASN_SEQUENCE_ADD(&initialContextSetupRequest_p->e_RABToBeSetupListCtxtSUReq,
|
|
// &e_RABToBeSetup);
|
|
//
|
|
// initialContextSetupRequest_p->ueSecurityCapabilities.encryptionAlgorithms.buf =
|
|
// (uint8_t *)supportedAlgorithms;
|
|
// initialContextSetupRequest_p->ueSecurityCapabilities.encryptionAlgorithms.size = 2;
|
|
// initialContextSetupRequest_p->ueSecurityCapabilities.encryptionAlgorithms.bits_unused
|
|
// = 0;
|
|
//
|
|
// initialContextSetupRequest_p->ueSecurityCapabilities.integrityProtectionAlgorithms.buf
|
|
// = (uint8_t *)supportedAlgorithms;
|
|
// initialContextSetupRequest_p->ueSecurityCapabilities.integrityProtectionAlgorithms.size
|
|
// = 2;
|
|
// initialContextSetupRequest_p->ueSecurityCapabilities.integrityProtectionAlgorithms.bits_unused
|
|
// = 0;
|
|
//
|
|
//// initialContextSetupRequest_p->securityKey.buf = initial_p->keNB; /* 256 bits length */
|
|
// uint8_t keNB[32];
|
|
// memset(keNB, 0, sizeof(keNB));
|
|
//
|
|
// initialContextSetupRequest_p->securityKey.buf = keNB;
|
|
// initialContextSetupRequest_p->securityKey.size = 32;
|
|
// initialContextSetupRequest_p->securityKey.bits_unused = 0;
|
|
//
|
|
// if (s1ap_mme_encode_pdu(&message, &buffer_p, &length) < 0) {
|
|
// // TODO: handle something
|
|
// DevMessage("Failed to encode initial context setup request message\n");
|
|
// }
|
|
//
|
|
// free(nas_conn_est_cnf_p->nasMsg.data);
|
|
//
|
|
// s1ap_mme_itti_send_sctp_request(buffer_p, length, ue_ref->eNB->sctp_assoc_id,
|
|
// ue_ref->sctp_stream_send);
|
|
//}
|
|
|
|
void s1ap_handle_conn_est_cnf(const mme_app_connection_establishment_cnf_t * const conn_est_cnf_pP)
|
|
{
|
|
/* We received create session response from S-GW on S11 interface abstraction.
|
|
* At least one bearer has been established. We can now send s1ap initial context setup request
|
|
* message to eNB.
|
|
*/
|
|
uint8_t offset = 0;
|
|
uint8_t *buffer_p = NULL;
|
|
uint32_t length = 0;
|
|
ue_description_t *ue_ref = NULL;
|
|
S1ap_InitialContextSetupRequestIEs_t *initialContextSetupRequest_p = NULL;
|
|
S1ap_E_RABToBeSetupItemCtxtSUReq_t e_RABToBeSetup;
|
|
S1ap_NAS_PDU_t nas_pdu;
|
|
s1ap_message message;
|
|
|
|
DevAssert(conn_est_cnf_pP != NULL);
|
|
|
|
if ((ue_ref = s1ap_is_ue_mme_id_in_list(conn_est_cnf_pP->nas_conn_est_cnf.UEid)) == NULL) {
|
|
S1AP_DEBUG("This mme ue s1ap id ("S1AP_UE_ID_FMT") is not attached to any UE context\n",
|
|
conn_est_cnf_pP->nas_conn_est_cnf.UEid);
|
|
|
|
DevParam(conn_est_cnf_pP->nas_conn_est_cnf.UEid, 0, 0);
|
|
}
|
|
|
|
/* Start the outcome response timer.
|
|
* When time is reached, MME consider that procedure outcome has failed.
|
|
*/
|
|
// timer_setup(mme_config.s1ap_config.outcome_drop_timer_sec, 0, TASK_S1AP, INSTANCE_DEFAULT,
|
|
// TIMER_ONE_SHOT,
|
|
// NULL,
|
|
// &ue_ref->outcome_response_timer_id);
|
|
/* Insert the timer in the MAP of mme_ue_s1ap_id <-> timer_id */
|
|
// s1ap_timer_insert(ue_ref->mme_ue_s1ap_id, ue_ref->outcome_response_timer_id);
|
|
|
|
memset(&message, 0, sizeof(s1ap_message));
|
|
memset(&e_RABToBeSetup, 0, sizeof(S1ap_E_RABToBeSetupItemCtxtSUReq_t));
|
|
|
|
message.procedureCode = S1ap_ProcedureCode_id_InitialContextSetup;
|
|
message.direction = S1AP_PDU_PR_initiatingMessage;
|
|
|
|
initialContextSetupRequest_p = &message.msg.s1ap_InitialContextSetupRequestIEs;
|
|
|
|
initialContextSetupRequest_p->mme_ue_s1ap_id = (unsigned long)ue_ref->mme_ue_s1ap_id;
|
|
initialContextSetupRequest_p->eNB_UE_S1AP_ID = (unsigned long)ue_ref->eNB_ue_s1ap_id;
|
|
|
|
/* uEaggregateMaximumBitrateDL and uEaggregateMaximumBitrateUL expressed in term of bits/sec */
|
|
asn_uint642INTEGER(&initialContextSetupRequest_p->uEaggregateMaximumBitrate.uEaggregateMaximumBitRateDL, conn_est_cnf_pP->ambr.br_dl);
|
|
asn_uint642INTEGER(&initialContextSetupRequest_p->uEaggregateMaximumBitrate.uEaggregateMaximumBitRateUL, conn_est_cnf_pP->ambr.br_ul);
|
|
|
|
e_RABToBeSetup.e_RAB_ID = conn_est_cnf_pP->eps_bearer_id; //5;
|
|
e_RABToBeSetup.e_RABlevelQoSParameters.qCI = conn_est_cnf_pP->bearer_qos_qci;
|
|
|
|
|
|
memset(&nas_pdu, 0, sizeof(nas_pdu));
|
|
nas_pdu.size = conn_est_cnf_pP->nas_conn_est_cnf.nasMsg.length;
|
|
nas_pdu.buf = conn_est_cnf_pP->nas_conn_est_cnf.nasMsg.data;
|
|
e_RABToBeSetup.nAS_PDU = &nas_pdu;
|
|
|
|
#if defined(ORIGINAL_S1AP_CODE)
|
|
e_RABToBeSetup.e_RABlevelQoSParameters.allocationRetentionPriority.priorityLevel =
|
|
S1ap_PriorityLevel_lowest;
|
|
e_RABToBeSetup.e_RABlevelQoSParameters.allocationRetentionPriority.pre_emptionCapability =
|
|
S1ap_Pre_emptionCapability_shall_not_trigger_pre_emption;
|
|
e_RABToBeSetup.e_RABlevelQoSParameters.allocationRetentionPriority.pre_emptionVulnerability =
|
|
S1ap_Pre_emptionVulnerability_not_pre_emptable;
|
|
#else
|
|
e_RABToBeSetup.e_RABlevelQoSParameters.allocationRetentionPriority.priorityLevel =
|
|
conn_est_cnf_pP->bearer_qos_prio_level;
|
|
e_RABToBeSetup.e_RABlevelQoSParameters.allocationRetentionPriority.pre_emptionCapability =
|
|
conn_est_cnf_pP->bearer_qos_pre_emp_capability;
|
|
e_RABToBeSetup.e_RABlevelQoSParameters.allocationRetentionPriority.pre_emptionVulnerability =
|
|
conn_est_cnf_pP->bearer_qos_pre_emp_vulnerability;
|
|
#endif
|
|
/* Set the GTP-TEID. This is the S1-U S-GW TEID */
|
|
INT32_TO_OCTET_STRING(conn_est_cnf_pP->bearer_s1u_sgw_fteid.teid, &e_RABToBeSetup.gTP_TEID);
|
|
|
|
/* S-GW IP address(es) for user-plane */
|
|
if (conn_est_cnf_pP->bearer_s1u_sgw_fteid.ipv4) {
|
|
e_RABToBeSetup.transportLayerAddress.buf = calloc(4, sizeof(uint8_t));
|
|
/* Only IPv4 supported */
|
|
memcpy(e_RABToBeSetup.transportLayerAddress.buf,
|
|
&conn_est_cnf_pP->bearer_s1u_sgw_fteid.ipv4_address,
|
|
4);
|
|
offset += 4;
|
|
e_RABToBeSetup.transportLayerAddress.size = 4;
|
|
e_RABToBeSetup.transportLayerAddress.bits_unused = 0;
|
|
}
|
|
|
|
if (conn_est_cnf_pP->bearer_s1u_sgw_fteid.ipv6) {
|
|
if (offset == 0) {
|
|
/* Both IPv4 and IPv6 provided */
|
|
/* TODO: check memory allocation */
|
|
e_RABToBeSetup.transportLayerAddress.buf = calloc(16, sizeof(uint8_t));
|
|
} else {
|
|
/* Only IPv6 supported */
|
|
/* TODO: check memory allocation */
|
|
e_RABToBeSetup.transportLayerAddress.buf
|
|
= realloc(e_RABToBeSetup.transportLayerAddress.buf, (16 + offset) * sizeof(uint8_t));
|
|
}
|
|
|
|
memcpy(&e_RABToBeSetup.transportLayerAddress.buf[offset],
|
|
conn_est_cnf_pP->bearer_s1u_sgw_fteid.ipv6_address,
|
|
16);
|
|
e_RABToBeSetup.transportLayerAddress.size = 16 + offset;
|
|
e_RABToBeSetup.transportLayerAddress.bits_unused = 0;
|
|
}
|
|
|
|
ASN_SEQUENCE_ADD(&initialContextSetupRequest_p->e_RABToBeSetupListCtxtSUReq,
|
|
&e_RABToBeSetup);
|
|
|
|
initialContextSetupRequest_p->ueSecurityCapabilities.encryptionAlgorithms.buf =
|
|
(uint8_t *)&conn_est_cnf_pP->security_capabilities_encryption_algorithms;
|
|
initialContextSetupRequest_p->ueSecurityCapabilities.encryptionAlgorithms.size = 2;
|
|
initialContextSetupRequest_p->ueSecurityCapabilities.encryptionAlgorithms.bits_unused
|
|
= 0;
|
|
|
|
initialContextSetupRequest_p->ueSecurityCapabilities.integrityProtectionAlgorithms.buf =
|
|
(uint8_t *)&conn_est_cnf_pP->security_capabilities_integrity_algorithms;
|
|
initialContextSetupRequest_p->ueSecurityCapabilities.integrityProtectionAlgorithms.size
|
|
= 2;
|
|
initialContextSetupRequest_p->ueSecurityCapabilities.integrityProtectionAlgorithms.bits_unused
|
|
= 0;
|
|
|
|
S1AP_DEBUG("security_capabilities_encryption_algorithms 0x%04X\n",
|
|
conn_est_cnf_pP->security_capabilities_encryption_algorithms);
|
|
S1AP_DEBUG("security_capabilities_integrity_algorithms 0x%04X\n",
|
|
conn_est_cnf_pP->security_capabilities_integrity_algorithms);
|
|
|
|
if (conn_est_cnf_pP->keNB) {
|
|
initialContextSetupRequest_p->securityKey.buf = malloc(32);
|
|
memcpy(initialContextSetupRequest_p->securityKey.buf,
|
|
conn_est_cnf_pP->keNB,
|
|
32);
|
|
|
|
initialContextSetupRequest_p->securityKey.size = 32;
|
|
} else {
|
|
S1AP_DEBUG("No keNB\n");
|
|
initialContextSetupRequest_p->securityKey.buf = NULL;
|
|
initialContextSetupRequest_p->securityKey.size = 0;
|
|
}
|
|
|
|
initialContextSetupRequest_p->securityKey.bits_unused = 0;
|
|
|
|
if (s1ap_mme_encode_pdu(&message, &buffer_p, &length) < 0) {
|
|
// TODO: handle something
|
|
DevMessage("Failed to encode initial context setup request message\n");
|
|
}
|
|
|
|
free(conn_est_cnf_pP->nas_conn_est_cnf.nasMsg.data);
|
|
|
|
MSC_LOG_TX_MESSAGE(
|
|
MSC_S1AP_MME,
|
|
MSC_S1AP_ENB,
|
|
NULL,0,
|
|
"0 InitialContextSetup/initiatingMessage mme_ue_s1ap_id "S1AP_UE_ID_FMT" eNB_ue_s1ap_id "S1AP_UE_ID_FMT" nas length %u",
|
|
initialContextSetupRequest_p->mme_ue_s1ap_id,
|
|
initialContextSetupRequest_p->eNB_UE_S1AP_ID,
|
|
nas_pdu.size);
|
|
|
|
s1ap_mme_itti_send_sctp_request(
|
|
buffer_p,
|
|
length,
|
|
ue_ref->eNB->sctp_assoc_id,
|
|
ue_ref->sctp_stream_send);
|
|
}
|
|
|
|
#endif
|