/*******************************************************************************
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@eurecom.fr
Address : Eurecom, Compus SophiaTech 450, route des chappes, 06451 Biot, France.
*******************************************************************************/
/*! \file mme_app_bearer.c
* \brief
* \author Sebastien ROUX, Lionel Gauthier
* \company Eurecom
* \email: lionel.gauthier@eurecom.fr
*/
#include
#include
#include
#include "intertask_interface.h"
#include "mme_config.h"
#include "mme_app_extern.h"
#include "mme_app_ue_context.h"
#include "mme_app_defs.h"
#include "sgw_lite_ie_defs.h"
#include "secu_defs.h"
#include "assertions.h"
#include "common_types.h"
#include "msc.h"
//------------------------------------------------------------------------------
int
mme_app_send_s11_release_access_bearers_req(
struct ue_context_s * const ue_context_pP)
//------------------------------------------------------------------------------
{
uint8_t i = 0;
task_id_t to_task = TASK_UNKNOWN;
/* Keep the identifier to the default APN */
context_identifier_t context_identifier;
MessageDef *message_p = NULL;
SgwReleaseAccessBearersRequest *release_access_bearers_request_p = NULL;
DevAssert(ue_context_pP != NULL);
#if !defined(ENABLE_STANDALONE_EPC)
to_task = TASK_S11;
#else
to_task = TASK_SPGW_APP;
#endif
message_p = itti_alloc_new_message(TASK_MME_APP, SGW_RELEASE_ACCESS_BEARERS_REQUEST);
release_access_bearers_request_p = &message_p->ittiMsg.sgwReleaseAccessBearersRequest;
memset(release_access_bearers_request_p, 0, sizeof(SgwReleaseAccessBearersRequest));
release_access_bearers_request_p->teid = ue_context_pP->sgw_s11_teid;
release_access_bearers_request_p->num_rabs = 1;
release_access_bearers_request_p->list_of_rabs[0] = ue_context_pP->default_bearer_id;
release_access_bearers_request_p->originating_node = NODE_TYPE_MME;
MSC_LOG_TX_MESSAGE(
MSC_MMEAPP_MME,
(to_task == TASK_S11) ? MSC_S11_MME:MSC_SP_GWAPP_MME,
NULL,0,
"0 SGW_RELEASE_ACCESS_BEARERS_REQUEST teid %u ebi %u",
release_access_bearers_request_p->teid,
release_access_bearers_request_p->list_of_rabs[0]);
itti_send_msg_to_task(to_task, INSTANCE_DEFAULT, message_p);
}
//------------------------------------------------------------------------------
int
mme_app_send_s11_create_session_req(
struct ue_context_s * const ue_context_pP)
//------------------------------------------------------------------------------
{
uint8_t i = 0;
task_id_t to_task = TASK_UNKNOWN;
/* Keep the identifier to the default APN */
context_identifier_t context_identifier;
MessageDef *message_p = NULL;
SgwCreateSessionRequest *session_request_p = NULL;
struct apn_configuration_s *default_apn_p = NULL;
DevAssert(ue_context_pP != NULL);
#if !defined(ENABLE_STANDALONE_EPC)
to_task = TASK_S11;
#else
to_task = TASK_SPGW_APP;
#endif
MME_APP_DEBUG("Handling imsi %"IMSI_FORMAT"\n", ue_context_pP->imsi);
if (ue_context_pP->sub_status != SS_SERVICE_GRANTED) {
/* HSS rejected the bearer creation or roaming is not allowed for this
* UE. This result will trigger an ESM Failure message sent to UE.
*/
DevMessage("Not implemented: ACCESS NOT GRANTED, send ESM Failure to NAS\n");
}
message_p = itti_alloc_new_message(TASK_MME_APP, SGW_CREATE_SESSION_REQUEST);
/* WARNING:
* Some parameters should be provided by NAS Layer:
* - ue_time_zone
* - mei
* - uli
* - uci
* Some parameters should be provided by HSS:
* - PGW address for CP
* - paa
* - ambr
* and by MME Application layer:
* - selection_mode
* Set these parameters with random values for now.
*/
session_request_p = &message_p->ittiMsg.sgwCreateSessionRequest;
memset(session_request_p, 0, sizeof(SgwCreateSessionRequest));
/* As the create session request is the first exchanged message and as
* no tunnel had been previously setup, the distant teid is set to 0.
* The remote teid will be provided in the response message.
*/
session_request_p->teid = 0;
MME_APP_IMSI_TO_STRING(ue_context_pP->imsi, (char *)session_request_p->imsi.digit);
// message content was set to 0
session_request_p->imsi.length = strlen((const char *)session_request_p->imsi.digit);
/* Copy the MSISDN */
memcpy(
session_request_p->msisdn.digit,
ue_context_pP->msisdn,
ue_context_pP->msisdn_length);
session_request_p->msisdn.length = ue_context_pP->msisdn_length;
session_request_p->rat_type = RAT_EUTRAN;
/* Copy the subscribed ambr to the sgw create session request message */
memcpy(
&session_request_p->ambr,
&ue_context_pP->subscribed_ambr,
sizeof(ambr_t));
if (ue_context_pP->apn_profile.nb_apns == 0) {
DevMessage("No APN returned by the HSS");
}
context_identifier = ue_context_pP->apn_profile.context_identifier;
for (i = 0; i < ue_context_pP->apn_profile.nb_apns; i++) {
default_apn_p = &ue_context_pP->apn_profile.apn_configuration[i];
/* OK we got our default APN */
if (default_apn_p->context_identifier == context_identifier)
break;
}
if (!default_apn_p) {
/* Unfortunately we didn't find our default APN... */
DevMessage("No default APN found");
}
memcpy(&session_request_p->bearer_to_create.bearer_level_qos.gbr,
&default_apn_p->ambr, sizeof(ambr_t));
memcpy(&session_request_p->bearer_to_create.bearer_level_qos.mbr,
&default_apn_p->ambr, sizeof(ambr_t));
session_request_p->bearer_to_create.bearer_level_qos.qci =
default_apn_p->subscribed_qos.qci;
session_request_p->bearer_to_create.bearer_level_qos.pvi =
default_apn_p->subscribed_qos.allocation_retention_priority.pre_emp_vulnerability;
session_request_p->bearer_to_create.bearer_level_qos.pci =
default_apn_p->subscribed_qos.allocation_retention_priority.pre_emp_capability;
session_request_p->bearer_to_create.bearer_level_qos.pl =
default_apn_p->subscribed_qos.allocation_retention_priority.priority_level;
/* Asking for default bearer in initial UE message.
* Use the address of ue_context as unique TEID: Need to find better here
* and will generate unique id only for 32 bits platforms.
*/
session_request_p->sender_fteid_for_cp.teid = (uint32_t)ue_context_pP;
session_request_p->sender_fteid_for_cp.interface_type = S11_MME_GTP_C;
session_request_p->bearer_to_create.eps_bearer_id = 5;
ue_context_pP->mme_s11_teid = session_request_p->sender_fteid_for_cp.teid;
ue_context_pP->sgw_s11_teid = 0;
memcpy(session_request_p->apn, default_apn_p->service_selection,
default_apn_p->service_selection_length);
/* Set PDN type for pdn_type and PAA even if this IE is redundant */
session_request_p->pdn_type = default_apn_p->pdn_type;
session_request_p->paa.pdn_type = default_apn_p->pdn_type;
if (default_apn_p->nb_ip_address == 0) {
/* UE DHCPv4 allocated ip address */
memset(session_request_p->paa.ipv4_address, 0, 4);
memset(session_request_p->paa.ipv6_address, 0, 16);
} else {
uint8_t j;
for (j = 0; j < default_apn_p->nb_ip_address; j++) {
ip_address_t *ip_address;
ip_address = &default_apn_p->ip_address[j];
if (ip_address->pdn_type == IPv4) {
memcpy(session_request_p->paa.ipv4_address, ip_address->address.ipv4_address, 4);
} else if (ip_address->pdn_type == IPv6) {
memcpy(session_request_p->paa.ipv6_address, ip_address->address.ipv6_address, 16);
}
// free(ip_address);
}
}
if ((ue_context_pP->pending_pdn_connectivity_req_pco.length >= PCO_MIN_LENGTH) && (ue_context_pP->pending_pdn_connectivity_req_pco.length <= PCO_MAX_LENGTH)) {
memcpy(&session_request_p->pco.byte[0],
&ue_context_pP->pending_pdn_connectivity_req_pco.byte[0],
ue_context_pP->pending_pdn_connectivity_req_pco.length);
session_request_p->pco.length = ue_context_pP->pending_pdn_connectivity_req_pco.length;
}
config_read_lock(&mme_config);
session_request_p->peer_ip = mme_config.ipv4.sgw_ip_address_for_S11;
config_unlock(&mme_config);
session_request_p->serving_network.mcc[0] = ue_context_pP->e_utran_cgi.plmn.MCCdigit1;
session_request_p->serving_network.mcc[1] = ue_context_pP->e_utran_cgi.plmn.MCCdigit2;
session_request_p->serving_network.mcc[2] = ue_context_pP->e_utran_cgi.plmn.MCCdigit3;
session_request_p->serving_network.mnc[0] = ue_context_pP->e_utran_cgi.plmn.MNCdigit1;
session_request_p->serving_network.mnc[1] = ue_context_pP->e_utran_cgi.plmn.MNCdigit2;
session_request_p->serving_network.mnc[2] = ue_context_pP->e_utran_cgi.plmn.MNCdigit3;
session_request_p->selection_mode = MS_O_N_P_APN_S_V;
MSC_LOG_TX_MESSAGE(
MSC_MMEAPP_MME,
(to_task == TASK_S11) ? MSC_S11_MME:MSC_SP_GWAPP_MME,
NULL,0,
"0 SGW_CREATE_SESSION_REQUEST imsi %"IMSI_FORMAT,ue_context_pP->imsi);
return itti_send_msg_to_task(to_task, INSTANCE_DEFAULT, message_p);
}
//------------------------------------------------------------------------------
int
mme_app_handle_nas_pdn_connectivity_req(
nas_pdn_connectivity_req_t * const nas_pdn_connectivity_req_pP)
//------------------------------------------------------------------------------
{
struct ue_context_s *ue_context_p = NULL;
uint64_t imsi = 0;
MME_APP_DEBUG("Received NAS_PDN_CONNECTIVITY_REQ from NAS\n");
DevAssert(nas_pdn_connectivity_req_pP != NULL);
MME_APP_STRING_TO_IMSI((char *)nas_pdn_connectivity_req_pP->imsi, &imsi);
MME_APP_DEBUG("Handling imsi %"IMSI_FORMAT"\n", imsi);
if ((ue_context_p = mme_ue_context_exists_imsi(&mme_app_desc.mme_ue_contexts,
imsi)) == NULL) {
MSC_LOG_EVENT(
MSC_MMEAPP_MME,
"NAS_PDN_CONNECTIVITY_REQ Unknown imsi %"IMSI_FORMAT,imsi);
MME_APP_ERROR("That's embarrassing as we don't know this IMSI\n");
return -1;
}
/* Consider the UE authenticated */
ue_context_p->imsi_auth = IMSI_AUTHENTICATED;
// Temp: save request, in near future merge wisely params in context
memset(ue_context_p->pending_pdn_connectivity_req_imsi,0, 16);
AssertFatal((nas_pdn_connectivity_req_pP->imsi_length > 0) &&
(nas_pdn_connectivity_req_pP->imsi_length < 16),
"BAD IMSI LENGTH %d", nas_pdn_connectivity_req_pP->imsi_length);
AssertFatal((nas_pdn_connectivity_req_pP->imsi_length > 0) &&
(nas_pdn_connectivity_req_pP->imsi_length < 16),
"STOP ON IMSI LENGTH %d", nas_pdn_connectivity_req_pP->imsi_length);
memcpy(ue_context_p->pending_pdn_connectivity_req_imsi,
nas_pdn_connectivity_req_pP->imsi,
nas_pdn_connectivity_req_pP->imsi_length);
ue_context_p->pending_pdn_connectivity_req_imsi_length = nas_pdn_connectivity_req_pP->imsi_length;
DUP_OCTET_STRING(nas_pdn_connectivity_req_pP->apn, ue_context_p->pending_pdn_connectivity_req_apn);
FREE_OCTET_STRING(nas_pdn_connectivity_req_pP->apn)
// dup OctetString
DUP_OCTET_STRING(nas_pdn_connectivity_req_pP->pdn_addr, ue_context_p->pending_pdn_connectivity_req_pdn_addr);
FREE_OCTET_STRING(nas_pdn_connectivity_req_pP->pdn_addr)
ue_context_p->pending_pdn_connectivity_req_pti = nas_pdn_connectivity_req_pP->pti;
ue_context_p->pending_pdn_connectivity_req_ue_id = nas_pdn_connectivity_req_pP->ue_id;
memcpy(&ue_context_p->pending_pdn_connectivity_req_pco.byte[0],
&nas_pdn_connectivity_req_pP->pco.byte[0],
nas_pdn_connectivity_req_pP->pco.length);
ue_context_p->pending_pdn_connectivity_req_pco.length = nas_pdn_connectivity_req_pP->pco.length;
memcpy(&ue_context_p->pending_pdn_connectivity_req_qos,
&nas_pdn_connectivity_req_pP->qos,
sizeof(network_qos_t));
ue_context_p->pending_pdn_connectivity_req_proc_data = nas_pdn_connectivity_req_pP->proc_data;
nas_pdn_connectivity_req_pP->proc_data = NULL;
ue_context_p->pending_pdn_connectivity_req_request_type = nas_pdn_connectivity_req_pP->request_type;
//if ((nas_pdn_connectivity_req_pP->apn.value == NULL) || (nas_pdn_connectivity_req_pP->apn.length == 0)) {
/* TODO: Get keys... */
/* Now generate S6A ULR */
return mme_app_send_s6a_update_location_req(ue_context_p);
//} else {
//return mme_app_send_s11_create_session_req(ue_context_p);
//}
//return -1;
}
// sent by NAS
//------------------------------------------------------------------------------
void
mme_app_handle_conn_est_cnf(
const nas_conn_est_cnf_t * const nas_conn_est_cnf_pP)
//------------------------------------------------------------------------------
{
struct ue_context_s *ue_context_p = NULL;
MessageDef *message_p = NULL;
mme_app_connection_establishment_cnf_t *establishment_cnf_p = NULL;
bearer_context_t *current_bearer_p = NULL;
ebi_t bearer_id = 0;
uint8_t keNB[32];
MME_APP_DEBUG("Received NAS_CONNECTION_ESTABLISHMENT_CNF from NAS\n");
ue_context_p = mme_ue_context_exists_nas_ue_id(&mme_app_desc.mme_ue_contexts, nas_conn_est_cnf_pP->UEid);
if (ue_context_p == NULL) {
MSC_LOG_EVENT(
MSC_MMEAPP_MME,
"NAS_CONNECTION_ESTABLISHMENT_CNF Unknown ue %u",nas_conn_est_cnf_pP->UEid);
MME_APP_ERROR("UE context doesn't exist for UE %06"PRIX32"/dec%u\n",
nas_conn_est_cnf_pP->UEid,
nas_conn_est_cnf_pP->UEid);
return;
}
message_p = itti_alloc_new_message(TASK_MME_APP, MME_APP_CONNECTION_ESTABLISHMENT_CNF);
establishment_cnf_p = &message_p->ittiMsg.mme_app_connection_establishment_cnf;
memset(establishment_cnf_p, 0, sizeof(mme_app_connection_establishment_cnf_t));
memcpy(&establishment_cnf_p->nas_conn_est_cnf,
nas_conn_est_cnf_pP,
sizeof(nas_conn_est_cnf_t));
bearer_id = ue_context_p->default_bearer_id;
current_bearer_p = &ue_context_p->eps_bearers[bearer_id];
establishment_cnf_p->eps_bearer_id = bearer_id;
establishment_cnf_p->bearer_s1u_sgw_fteid.interface_type = S1_U_SGW_GTP_U;
establishment_cnf_p->bearer_s1u_sgw_fteid.teid = current_bearer_p->s_gw_teid;
if ((current_bearer_p->s_gw_address.pdn_type == IPv4) ||
(current_bearer_p->s_gw_address.pdn_type == IPv4_AND_v6)) {
establishment_cnf_p->bearer_s1u_sgw_fteid.ipv4 = 1;
memcpy(&establishment_cnf_p->bearer_s1u_sgw_fteid.ipv4_address,
current_bearer_p->s_gw_address.address.ipv4_address,
4);
}
if ((current_bearer_p->s_gw_address.pdn_type == IPv6) ||
(current_bearer_p->s_gw_address.pdn_type == IPv4_AND_v6)) {
establishment_cnf_p->bearer_s1u_sgw_fteid.ipv6 = 1;
memcpy(establishment_cnf_p->bearer_s1u_sgw_fteid.ipv6_address,
current_bearer_p->s_gw_address.address.ipv6_address,
16);
}
establishment_cnf_p->bearer_qos_qci = current_bearer_p->qci;
establishment_cnf_p->bearer_qos_prio_level = current_bearer_p->prio_level;
establishment_cnf_p->bearer_qos_pre_emp_vulnerability = current_bearer_p->pre_emp_vulnerability;
establishment_cnf_p->bearer_qos_pre_emp_capability = current_bearer_p->pre_emp_capability;
#warning "Check ue_context_p ambr"
establishment_cnf_p->ambr.br_ul = ue_context_p->subscribed_ambr.br_ul;
establishment_cnf_p->ambr.br_dl = ue_context_p->subscribed_ambr.br_dl;
establishment_cnf_p->security_capabilities_encryption_algorithms = nas_conn_est_cnf_pP->selected_encryption_algorithm;
establishment_cnf_p->security_capabilities_integrity_algorithms = nas_conn_est_cnf_pP->selected_integrity_algorithm;
MME_APP_DEBUG("security_capabilities_encryption_algorithms 0x%04X\n", establishment_cnf_p->security_capabilities_encryption_algorithms);
MME_APP_DEBUG("security_capabilities_integrity_algorithms 0x%04X\n", establishment_cnf_p->security_capabilities_integrity_algorithms);
MME_APP_DEBUG("Derive keNB with UL NAS COUNT %x\n", nas_conn_est_cnf_pP->ul_nas_count);
derive_keNB(ue_context_p->vector_in_use->kasme, nas_conn_est_cnf_pP->ul_nas_count, keNB); //156
memcpy(establishment_cnf_p->keNB, keNB, 32);
MSC_LOG_TX_MESSAGE(
MSC_MMEAPP_MME,
MSC_S1AP_MME,
NULL,0,
"0 MME_APP_CONNECTION_ESTABLISHMENT_CNF ebi %u s1u_sgw teid %u qci %u prio level %u sea 0x%x sia 0x%x",
establishment_cnf_p->eps_bearer_id,
establishment_cnf_p->bearer_s1u_sgw_fteid.teid,
establishment_cnf_p->bearer_qos_qci,
establishment_cnf_p->bearer_qos_prio_level,
establishment_cnf_p->security_capabilities_encryption_algorithms,
establishment_cnf_p->security_capabilities_integrity_algorithms);
itti_send_msg_to_task(TASK_S1AP, INSTANCE_DEFAULT, message_p);
}
// sent by S1AP
//------------------------------------------------------------------------------
void
mme_app_handle_conn_est_ind(
const mme_app_connection_establishment_ind_t * const conn_est_ind_pP)
//------------------------------------------------------------------------------
{
struct ue_context_s *ue_context_p = NULL;
MessageDef *message_p = NULL;
MME_APP_DEBUG("Received MME_APP_CONNECTION_ESTABLISHMENT_IND from S1AP\n");
ue_context_p = mme_ue_context_exists_mme_ue_s1ap_id(
&mme_app_desc.mme_ue_contexts,
conn_est_ind_pP->mme_ue_s1ap_id);
if (ue_context_p == NULL) {
MME_APP_DEBUG("We didn't find this mme_ue_s1ap_id in list of UE: %06"PRIX32"/dec%u\n",
conn_est_ind_pP->mme_ue_s1ap_id,
conn_est_ind_pP->mme_ue_s1ap_id);
MME_APP_DEBUG("UE context doesn't exist -> create one\n");
if ((ue_context_p = mme_create_new_ue_context()) == NULL) {
/* Error during ue context malloc */
/* TODO */
DevMessage("mme_create_new_ue_context");
return;
}
// S1AP UE ID AND NAS UE ID ARE THE SAME
ue_context_p->mme_ue_s1ap_id = conn_est_ind_pP->mme_ue_s1ap_id;
ue_context_p->ue_id = conn_est_ind_pP->mme_ue_s1ap_id;
DevAssert(mme_insert_ue_context(&mme_app_desc.mme_ue_contexts, ue_context_p) == 0);
// tests
ue_context_p = mme_ue_context_exists_mme_ue_s1ap_id(
&mme_app_desc.mme_ue_contexts,
conn_est_ind_pP->mme_ue_s1ap_id);
AssertFatal(ue_context_p != NULL, "mme_ue_context_exists_mme_ue_s1ap_id Failed");
ue_context_p = mme_ue_context_exists_nas_ue_id(
&mme_app_desc.mme_ue_contexts,
conn_est_ind_pP->mme_ue_s1ap_id);
AssertFatal(ue_context_p != NULL, "mme_ue_context_exists_nas_ue_id Failed");
}
message_p = itti_alloc_new_message(TASK_MME_APP, NAS_CONNECTION_ESTABLISHMENT_IND);
memcpy(&NAS_CONN_EST_IND(message_p).nas,
&conn_est_ind_pP->nas,
sizeof (nas_establish_ind_t));
MSC_LOG_TX_MESSAGE(
MSC_MMEAPP_MME,
MSC_NAS_MME,
NULL,0,
"0 NAS_CONNECTION_ESTABLISHMENT_IND");
itti_send_msg_to_task(TASK_NAS_MME, INSTANCE_DEFAULT, message_p);
}
//------------------------------------------------------------------------------
int
mme_app_handle_create_sess_resp(
const SgwCreateSessionResponse * const create_sess_resp_pP)
//------------------------------------------------------------------------------
{
struct ue_context_s *ue_context_p = NULL;
bearer_context_t *current_bearer_p = NULL;
MessageDef *message_p = NULL;
int16_t bearer_id;
DevAssert(create_sess_resp_pP != NULL);
MME_APP_DEBUG("Received SGW_CREATE_SESSION_RESPONSE from S+P-GW\n");
ue_context_p = mme_ue_context_exists_s11_teid(&mme_app_desc.mme_ue_contexts,
create_sess_resp_pP->teid);
if (ue_context_p == NULL) {
MME_APP_DEBUG("We didn't find this teid in list of UE: %08x\n",
create_sess_resp_pP->teid);
return -1;
}
/* Store the S-GW teid */
ue_context_p->sgw_s11_teid = create_sess_resp_pP->s11_sgw_teid.teid;
//---------------------------------------------------------
// Process SgwCreateSessionResponse.bearer_context_created
//---------------------------------------------------------
bearer_id = create_sess_resp_pP->bearer_context_created.eps_bearer_id/* - 5*/;
/* Depending on s11 result we have to send reject or accept for bearers */
DevCheck((bearer_id < BEARERS_PER_UE) && (bearer_id >= 0),
bearer_id,
BEARERS_PER_UE,
0);
ue_context_p->default_bearer_id = bearer_id;
if (create_sess_resp_pP->bearer_context_created.cause != REQUEST_ACCEPTED) {
DevMessage("Cases where bearer cause != REQUEST_ACCEPTED are not handled\n");
}
DevAssert(create_sess_resp_pP->bearer_context_created.s1u_sgw_fteid.interface_type == S1_U_SGW_GTP_U);
/* Updating statistics */
mme_app_desc.mme_ue_contexts.nb_bearers_managed++;
mme_app_desc.mme_ue_contexts.nb_bearers_since_last_stat++;
current_bearer_p = &ue_context_p->eps_bearers[bearer_id];
current_bearer_p->s_gw_teid = create_sess_resp_pP->bearer_context_created.s1u_sgw_fteid.teid;
switch (create_sess_resp_pP->bearer_context_created.s1u_sgw_fteid.ipv4 +
(create_sess_resp_pP->bearer_context_created.s1u_sgw_fteid.ipv6 << 1)) {
default:
case 0: {
/* No address provided: impossible case */
DevMessage("No ip address for user-plane provided...\n");
}
break;
case 1: {
/* Only IPv4 address */
current_bearer_p->s_gw_address.pdn_type = IPv4;
memcpy(current_bearer_p->s_gw_address.address.ipv4_address,
&create_sess_resp_pP->bearer_context_created.s1u_sgw_fteid.ipv4_address, 4);
}
break;
case 2: {
/* Only IPv6 address */
current_bearer_p->s_gw_address.pdn_type = IPv6;
memcpy(current_bearer_p->s_gw_address.address.ipv6_address,
create_sess_resp_pP->bearer_context_created.s1u_sgw_fteid.ipv6_address, 16);
}
break;
case 3: {
/* Both IPv4 and Ipv6 */
current_bearer_p->s_gw_address.pdn_type = IPv4_AND_v6;
memcpy(current_bearer_p->s_gw_address.address.ipv4_address,
&create_sess_resp_pP->bearer_context_created.s1u_sgw_fteid.ipv4_address, 4);
memcpy(current_bearer_p->s_gw_address.address.ipv6_address,
create_sess_resp_pP->bearer_context_created.s1u_sgw_fteid.ipv6_address, 16);
}
break;
}
current_bearer_p->p_gw_teid = create_sess_resp_pP->bearer_context_created.s5_s8_u_pgw_fteid.teid;
memset(¤t_bearer_p->p_gw_address,0, sizeof(ip_address_t));
if (create_sess_resp_pP->bearer_context_created.bearer_level_qos != NULL) {
current_bearer_p->qci = create_sess_resp_pP->bearer_context_created.bearer_level_qos->qci;
current_bearer_p->prio_level = create_sess_resp_pP->bearer_context_created.bearer_level_qos->pl;
current_bearer_p->pre_emp_vulnerability = create_sess_resp_pP->bearer_context_created.bearer_level_qos->pvi;
current_bearer_p->pre_emp_capability = create_sess_resp_pP->bearer_context_created.bearer_level_qos->pci;
MME_APP_DEBUG("%s set qci %u in bearer %u\n",
__FUNCTION__,
current_bearer_p->qci,
ue_context_p->default_bearer_id);
} else {
// if null, it is not modified
//current_bearer_p->qci = ue_context_p->pending_pdn_connectivity_req_qos.qci;
#warning "may force QCI here to 9"
current_bearer_p->qci = 9;
current_bearer_p->prio_level = 1;
current_bearer_p->pre_emp_vulnerability = 0;
current_bearer_p->pre_emp_capability = 0;
MME_APP_DEBUG("%s set qci %u in bearer %u (qos not modified by S/P-GW)\n",
__FUNCTION__,
current_bearer_p->qci,
ue_context_p->default_bearer_id);
}
mme_app_dump_ue_contexts(&mme_app_desc.mme_ue_contexts);
{
//uint8_t *keNB = NULL;
message_p = itti_alloc_new_message(TASK_MME_APP, NAS_PDN_CONNECTIVITY_RSP);
memset((void*)&message_p->ittiMsg.nas_pdn_connectivity_rsp,
0,
sizeof(nas_pdn_connectivity_rsp_t));
// moved to NAS_CONNECTION_ESTABLISHMENT_CONF, keNB not handled in NAS MME
//derive_keNB(ue_context_p->vector_in_use->kasme, 156, &keNB);
//memcpy(NAS_PDN_CONNECTIVITY_RSP(message_p).keNB, keNB, 32);
//free(keNB);
NAS_PDN_CONNECTIVITY_RSP(message_p).pti = ue_context_p->pending_pdn_connectivity_req_pti; // NAS internal ref
NAS_PDN_CONNECTIVITY_RSP(message_p).ue_id = ue_context_p->pending_pdn_connectivity_req_ue_id; // NAS internal ref
// TO REWORK:
if ((ue_context_p->pending_pdn_connectivity_req_apn.value != NULL)
&& (ue_context_p->pending_pdn_connectivity_req_apn.length != 0)) {
DUP_OCTET_STRING(
ue_context_p->pending_pdn_connectivity_req_apn,
NAS_PDN_CONNECTIVITY_RSP(message_p).apn);
MME_APP_DEBUG("SET APN FROM NAS PDN CONNECTIVITY CREATE: %s\n", NAS_PDN_CONNECTIVITY_RSP(message_p).apn.value);
} else {
int i;
context_identifier_t context_identifier = ue_context_p->apn_profile.context_identifier;
for (i = 0; i < ue_context_p->apn_profile.nb_apns; i++) {
if (ue_context_p->apn_profile.apn_configuration[i].context_identifier == context_identifier) {
AssertFatal(ue_context_p->apn_profile.apn_configuration[i].service_selection_length > 0, "Bad APN string (len = 0)");
if (ue_context_p->apn_profile.apn_configuration[i].service_selection_length > 0) {
NAS_PDN_CONNECTIVITY_RSP(message_p).apn.value = malloc(ue_context_p->apn_profile.apn_configuration[i].service_selection_length + 1);
NAS_PDN_CONNECTIVITY_RSP(message_p).apn.length = ue_context_p->apn_profile.apn_configuration[i].service_selection_length;
AssertFatal(ue_context_p->apn_profile.apn_configuration[i].service_selection_length <= APN_MAX_LENGTH,
"Bad APN string length %d",
ue_context_p->apn_profile.apn_configuration[i].service_selection_length);
memcpy(NAS_PDN_CONNECTIVITY_RSP(message_p).apn.value,
ue_context_p->apn_profile.apn_configuration[i].service_selection,
ue_context_p->apn_profile.apn_configuration[i].service_selection_length);
NAS_PDN_CONNECTIVITY_RSP(message_p).apn.value[ue_context_p->apn_profile.apn_configuration[i].service_selection_length] = '\0';
MME_APP_DEBUG("SET APN FROM HSS ULA: %s\n", NAS_PDN_CONNECTIVITY_RSP(message_p).apn.value);
break;
}
}
}
}
MME_APP_DEBUG("APN: %s\n", NAS_PDN_CONNECTIVITY_RSP(message_p).apn.value);
switch (create_sess_resp_pP->paa.pdn_type) {
case IPv4:
NAS_PDN_CONNECTIVITY_RSP(message_p).pdn_addr.length = 4;
NAS_PDN_CONNECTIVITY_RSP(message_p).pdn_addr.value = malloc(NAS_PDN_CONNECTIVITY_RSP(message_p).pdn_addr.length+1);
DevAssert(NAS_PDN_CONNECTIVITY_RSP(message_p).pdn_addr.value != NULL);
memcpy(
NAS_PDN_CONNECTIVITY_RSP(message_p).pdn_addr.value,
create_sess_resp_pP->paa.ipv4_address,
NAS_PDN_CONNECTIVITY_RSP(message_p).pdn_addr.length);
NAS_PDN_CONNECTIVITY_RSP(message_p).pdn_addr.value[NAS_PDN_CONNECTIVITY_RSP(message_p).pdn_addr.length] = '0';
break;
case IPv6:
DevAssert(create_sess_resp_pP->paa.ipv6_prefix_length == 64); // NAS seems to only support 64 bits
NAS_PDN_CONNECTIVITY_RSP(message_p).pdn_addr.length = create_sess_resp_pP->paa.ipv6_prefix_length/8;
NAS_PDN_CONNECTIVITY_RSP(message_p).pdn_addr.value = malloc(NAS_PDN_CONNECTIVITY_RSP(message_p).pdn_addr.length+1);
DevAssert(NAS_PDN_CONNECTIVITY_RSP(message_p).pdn_addr.value != NULL);
memcpy(
NAS_PDN_CONNECTIVITY_RSP(message_p).pdn_addr.value,
create_sess_resp_pP->paa.ipv6_address,
NAS_PDN_CONNECTIVITY_RSP(message_p).pdn_addr.length);
NAS_PDN_CONNECTIVITY_RSP(message_p).pdn_addr.value[NAS_PDN_CONNECTIVITY_RSP(message_p).pdn_addr.length] = '0';
break;
case IPv4_AND_v6:
DevAssert(create_sess_resp_pP->paa.ipv6_prefix_length == 64); // NAS seems to only support 64 bits
NAS_PDN_CONNECTIVITY_RSP(message_p).pdn_addr.length = 4 + create_sess_resp_pP->paa.ipv6_prefix_length/8;
NAS_PDN_CONNECTIVITY_RSP(message_p).pdn_addr.value = malloc(NAS_PDN_CONNECTIVITY_RSP(message_p).pdn_addr.length+1);
DevAssert(NAS_PDN_CONNECTIVITY_RSP(message_p).pdn_addr.value != NULL);
memcpy(
NAS_PDN_CONNECTIVITY_RSP(message_p).pdn_addr.value,
create_sess_resp_pP->paa.ipv4_address,
4);
memcpy(
&NAS_PDN_CONNECTIVITY_RSP(message_p).pdn_addr.value[4],
create_sess_resp_pP->paa.ipv6_address,
create_sess_resp_pP->paa.ipv6_prefix_length/8);
NAS_PDN_CONNECTIVITY_RSP(message_p).pdn_addr.value[NAS_PDN_CONNECTIVITY_RSP(message_p).pdn_addr.length] = '0';
break;
case IPv4_OR_v6:
NAS_PDN_CONNECTIVITY_RSP(message_p).pdn_addr.length = 4;
NAS_PDN_CONNECTIVITY_RSP(message_p).pdn_addr.value = malloc(NAS_PDN_CONNECTIVITY_RSP(message_p).pdn_addr.length+1);
DevAssert(NAS_PDN_CONNECTIVITY_RSP(message_p).pdn_addr.value != NULL);
memcpy(
NAS_PDN_CONNECTIVITY_RSP(message_p).pdn_addr.value,
create_sess_resp_pP->paa.ipv4_address,
NAS_PDN_CONNECTIVITY_RSP(message_p).pdn_addr.length);
NAS_PDN_CONNECTIVITY_RSP(message_p).pdn_addr.value[NAS_PDN_CONNECTIVITY_RSP(message_p).pdn_addr.length] = '0';
break;
default:
DevAssert(0);
}
NAS_PDN_CONNECTIVITY_RSP(message_p).pdn_type = create_sess_resp_pP->paa.pdn_type;
NAS_PDN_CONNECTIVITY_RSP(message_p).proc_data = ue_context_p->pending_pdn_connectivity_req_proc_data; // NAS internal ref
ue_context_p->pending_pdn_connectivity_req_proc_data = NULL;
#warning "QOS hardcoded here"
//memcpy(&NAS_PDN_CONNECTIVITY_RSP(message_p).qos,
// &ue_context_p->pending_pdn_connectivity_req_qos,
// sizeof(network_qos_t));
NAS_PDN_CONNECTIVITY_RSP(message_p).qos.gbrUL = 64; /* 64=64kb/s Guaranteed Bit Rate for uplink */
NAS_PDN_CONNECTIVITY_RSP(message_p).qos.gbrDL = 120; /* 120=512kb/s Guaranteed Bit Rate for downlink */
NAS_PDN_CONNECTIVITY_RSP(message_p).qos.mbrUL = 72; /* 72=128kb/s Maximum Bit Rate for uplink */
NAS_PDN_CONNECTIVITY_RSP(message_p).qos.mbrDL = 135; /*135=1024kb/s Maximum Bit Rate for downlink */
NAS_PDN_CONNECTIVITY_RSP(message_p).qos.qci = 9; /* QoS Class Identifier */
NAS_PDN_CONNECTIVITY_RSP(message_p).request_type = ue_context_p->pending_pdn_connectivity_req_request_type; // NAS internal ref
ue_context_p->pending_pdn_connectivity_req_request_type = 0;
// here at this point OctetString are saved in resp, no loss of memory (apn, pdn_addr)
NAS_PDN_CONNECTIVITY_RSP(message_p).eNB_ue_s1ap_id = ue_context_p->eNB_ue_s1ap_id;
NAS_PDN_CONNECTIVITY_RSP(message_p).mme_ue_s1ap_id = ue_context_p->mme_ue_s1ap_id;
NAS_PDN_CONNECTIVITY_RSP(message_p).ebi = bearer_id;
NAS_PDN_CONNECTIVITY_RSP(message_p).qci = current_bearer_p->qci;
NAS_PDN_CONNECTIVITY_RSP(message_p).prio_level = current_bearer_p->prio_level;
NAS_PDN_CONNECTIVITY_RSP(message_p).pre_emp_vulnerability = current_bearer_p->pre_emp_vulnerability;
NAS_PDN_CONNECTIVITY_RSP(message_p).pre_emp_capability = current_bearer_p->pre_emp_capability;
NAS_PDN_CONNECTIVITY_RSP(message_p).sgw_s1u_teid = current_bearer_p->s_gw_teid;
memcpy(&NAS_PDN_CONNECTIVITY_RSP(message_p).sgw_s1u_address,
¤t_bearer_p->s_gw_address, sizeof(ip_address_t));
NAS_PDN_CONNECTIVITY_RSP(message_p).ambr.br_ul = ue_context_p->subscribed_ambr.br_ul;
NAS_PDN_CONNECTIVITY_RSP(message_p).ambr.br_dl = ue_context_p->subscribed_ambr.br_dl;
memcpy(&NAS_PDN_CONNECTIVITY_RSP(message_p).pco.byte[0],
&create_sess_resp_pP->pco.byte[0],
create_sess_resp_pP->pco.length);
NAS_PDN_CONNECTIVITY_RSP(message_p).pco.length = create_sess_resp_pP->pco.length;
MSC_LOG_TX_MESSAGE(
MSC_MMEAPP_MME,
MSC_NAS_MME,
NULL,0,
"0 NAS_PDN_CONNECTIVITY_RSP sgw_s1u_teid %u ebi %u qci %u prio %u",
current_bearer_p->s_gw_teid,
bearer_id,
current_bearer_p->qci,
current_bearer_p->prio_level);
return itti_send_msg_to_task(TASK_NAS_MME, INSTANCE_DEFAULT, message_p);
}
return 0;
}
//------------------------------------------------------------------------------
void
mme_app_handle_initial_context_setup_rsp(
const mme_app_initial_context_setup_rsp_t * const initial_ctxt_setup_rsp_pP)
//------------------------------------------------------------------------------
{
struct ue_context_s *ue_context_p = NULL;
MessageDef *message_p = NULL;
task_id_t to_task = TASK_UNKNOWN;
MME_APP_DEBUG("Received MME_APP_INITIAL_CONTEXT_SETUP_RSP from S1AP\n");
ue_context_p = mme_ue_context_exists_mme_ue_s1ap_id(
&mme_app_desc.mme_ue_contexts,
initial_ctxt_setup_rsp_pP->mme_ue_s1ap_id);
if (ue_context_p == NULL) {
MME_APP_DEBUG("We didn't find this mme_ue_s1ap_id in list of UE: %08x %d(dec)\n",
initial_ctxt_setup_rsp_pP->mme_ue_s1ap_id,
initial_ctxt_setup_rsp_pP->mme_ue_s1ap_id);
MSC_LOG_EVENT(
MSC_MMEAPP_MME,
"MME_APP_INITIAL_CONTEXT_SETUP_RSP Unknown ue %u",initial_ctxt_setup_rsp_pP->mme_ue_s1ap_id);
return;
}
#if !defined(ENABLE_STANDALONE_EPC)
to_task = TASK_S11;
#else
to_task = TASK_SPGW_APP;
#endif
message_p = itti_alloc_new_message(TASK_MME_APP, SGW_MODIFY_BEARER_REQUEST);
AssertFatal(message_p != NULL, "itti_alloc_new_message Failed");
memset((void*)&message_p->ittiMsg.sgwModifyBearerRequest,
0,
sizeof(SgwModifyBearerRequest));
SGW_MODIFY_BEARER_REQUEST(message_p).teid = ue_context_p->sgw_s11_teid;
/* Delay Value in integer multiples of 50 millisecs, or zero */
SGW_MODIFY_BEARER_REQUEST(message_p).delay_dl_packet_notif_req = 0; // TO DO
SGW_MODIFY_BEARER_REQUEST(message_p).bearer_context_to_modify.eps_bearer_id = initial_ctxt_setup_rsp_pP->eps_bearer_id;
memcpy(&SGW_MODIFY_BEARER_REQUEST(message_p).bearer_context_to_modify.s1_eNB_fteid,
&initial_ctxt_setup_rsp_pP->bearer_s1u_enb_fteid,
sizeof(SGW_MODIFY_BEARER_REQUEST(message_p).bearer_context_to_modify.s1_eNB_fteid));
SGW_MODIFY_BEARER_REQUEST(message_p).mme_fq_csid.node_id_type = GLOBAL_UNICAST_IPv4; // TO DO
SGW_MODIFY_BEARER_REQUEST(message_p).mme_fq_csid.csid = 0; // TO DO ...
SGW_MODIFY_BEARER_REQUEST(message_p).indication_flags = 0; // TO DO
SGW_MODIFY_BEARER_REQUEST(message_p).rat_type = RAT_EUTRAN;
/* S11 stack specific parameter. Not used in standalone epc mode */
SGW_MODIFY_BEARER_REQUEST(message_p).trxn = NULL;
MSC_LOG_TX_MESSAGE(
MSC_MMEAPP_MME,
(to_task == TASK_S11) ? MSC_S11_MME:MSC_SP_GWAPP_MME,
NULL,0,
"0 SGW_MODIFY_BEARER_REQUEST teid %u ebi %u",
SGW_MODIFY_BEARER_REQUEST(message_p).teid,
SGW_MODIFY_BEARER_REQUEST(message_p).bearer_context_to_modify.eps_bearer_id);
itti_send_msg_to_task(to_task, INSTANCE_DEFAULT, message_p);
}
//------------------------------------------------------------------------------
void mme_app_handle_release_access_bearers_resp(
const SgwReleaseAccessBearersResponse * const rel_access_bearers_rsp_pP)
//------------------------------------------------------------------------------
{
MessageDef *message_p = NULL;
struct ue_context_s *ue_context_p = NULL;
ue_context_p = mme_ue_context_exists_s11_teid(&mme_app_desc.mme_ue_contexts,
rel_access_bearers_rsp_pP->teid);
if (ue_context_p == NULL) {
MME_APP_DEBUG("We didn't find this teid in list of UE: %06"PRIX32"\n",
rel_access_bearers_rsp_pP->teid);
return;
}
message_p = itti_alloc_new_message(TASK_MME_APP, S1AP_UE_CONTEXT_RELEASE_COMMAND);
AssertFatal(message_p != NULL, "itti_alloc_new_message Failed");
memset((void*)&message_p->ittiMsg.s1ap_ue_context_release_command,
0,
sizeof(s1ap_ue_context_release_command_t));
S1AP_UE_CONTEXT_RELEASE_COMMAND(message_p).mme_ue_s1ap_id = ue_context_p->mme_ue_s1ap_id;
MSC_LOG_TX_MESSAGE(
MSC_MMEAPP_MME,
MSC_S1AP_MME,
NULL,0,
"0 S1AP_UE_CONTEXT_RELEASE_COMMAND mme_ue_s1ap_id %06"PRIX32" ",
S1AP_UE_CONTEXT_RELEASE_COMMAND(message_p).mme_ue_s1ap_id);
itti_send_msg_to_task(TASK_S1AP, INSTANCE_DEFAULT, message_p);
}