Commit 24916e33 authored by Tien-Thinh Nguyen's avatar Tien-Thinh Nguyen

Update the whole SMF App for PDU session establishment procedure

parent 953a3b93
......@@ -33,29 +33,6 @@ include_directories(${SRC_TOP_DIR}/../build/ext/spdlog/include)
add_library (SMF STATIC
${SRC_TOP_DIR}/common/ngap/ngap_common.c
${SRC_TOP_DIR}/ngap/ng_pdu_session_resource_setup_request.c
${SRC_TOP_DIR}/ngap/ng_pdu_session_resource_setup_response.c
${SRC_TOP_DIR}/ngap/ng_pdu_session_resource_release_command.c
${SRC_TOP_DIR}/ngap/ng_pdu_session_resource_release_response.c
${SRC_TOP_DIR}/ngap/ng_pdu_session_resource_modify_request.c
${SRC_TOP_DIR}/ngap/ng_pdu_session_resource_modify_response.c
${SRC_TOP_DIR}/ngap/ng_pdu_session_resource_notify.c
${SRC_TOP_DIR}/ngap/ng_pdu_session_resource_modify_indication.c
${SRC_TOP_DIR}/ngap/ng_pdu_session_resource_modify_confirm.c
${SRC_TOP_DIR}/ngap/ng_pdu_handover_required.c
${SRC_TOP_DIR}/ngap/ng_pdu_handover_command.c
${SRC_TOP_DIR}/ngap/ng_pdu_handover_preparation_failure.c
${SRC_TOP_DIR}/ngap/ng_pdu_handover_request.c
${SRC_TOP_DIR}/ngap/ng_pdu_handover_request_acknowledge.c
${SRC_TOP_DIR}/ngap/ng_pdu_handover_failure.c
${SRC_TOP_DIR}/ngap/ng_pdu_handover_notify.c
${SRC_TOP_DIR}/ngap/ng_pdu_path_switch_request.c
${SRC_TOP_DIR}/ngap/ng_pdu_path_switch_request_acknowledge.c
${SRC_TOP_DIR}/ngap/ng_pdu_path_switch_request_failure.c
${SRC_TOP_DIR}/ngap/ng_pdu_handover_cancel.c
${SRC_TOP_DIR}/ngap/ng_pdu_handover_cancel_acknowledge.c
${SRC_TOP_DIR}/ngap/ng_pdu_uplink_ran_status_transfer.c
${SRC_TOP_DIR}/ngap/ng_pdu_downlink_ran_status_transfer.c
smf_app.cpp
smf_config.cpp
smf_context.cpp
......
......@@ -25,7 +25,7 @@
\company Eurecom
\date 2019
\email: lionel.gauthier@eurecom.fr, tien-thinh.nguyen@eurecom.fr
*/
*/
#include "smf_app.hpp"
#include "async_shell_cmd.hpp"
......@@ -49,11 +49,12 @@
#include "ProblemDetails.h"
#include "smf_n1_n2.hpp"
#include "SmContextCreatedData.h"
#include "pfcp.hpp"
#include "itti_msg_nx.hpp"
extern "C"{
#include "nas_message.h"
#include "mmData.h"
#include "nas_sm_encode_to_json.h"
}
#include <stdexcept>
......@@ -166,7 +167,7 @@ void smf_app::delete_smf_context(std::shared_ptr<smf_context> spc)
}
//------------------------------------------------------------------------------
void smf_app::restore_sx_sessions(const seid_t& seid) const
void smf_app::restore_n4_sessions(const seid_t& seid) const
{
std::shared_lock lock(m_seid2smf_context);
//TODO
......@@ -201,6 +202,18 @@ void smf_app_task (void*)
}
break;
case N11_SESSION_N1N2_MESSAGE_TRANSFER_RESPONSE_STATUS:
if (itti_n11_n1n2_message_transfer_response_status* m = dynamic_cast<itti_n11_n1n2_message_transfer_response_status*>(msg)) {
smf_app_inst->handle_itti_msg(std::ref(*m));
}
break;
case N11_SESSION_UPDATE_PDU_SESSION_STATUS:
if (itti_n11_update_pdu_session_status* m = dynamic_cast<itti_n11_update_pdu_session_status*>(msg)) {
smf_app_inst->handle_itti_msg(std::ref(*m));
}
break;
case N4_SESSION_REPORT_REQUEST:
smf_app_inst->handle_itti_msg(std::static_pointer_cast<itti_n4_session_report_request>(shared_msg));
break;
......@@ -208,7 +221,15 @@ void smf_app_task (void*)
case TIME_OUT:
if (itti_msg_timeout* to = dynamic_cast<itti_msg_timeout*>(msg)) {
Logger::smf_app().info( "TIME-OUT event timer id %d", to->timer_id);
switch (to->arg1_user) {
case TASK_SMF_APP_TRIGGER_T3591:
smf_app_inst->timer_t3591_timeout(to->timer_id, to->arg2_user);
break;
default:
;
}
}
break;
case TERMINATE:
if (itti_msg_terminate *terminate = dynamic_cast<itti_msg_terminate*>(msg)) {
......@@ -247,9 +268,86 @@ smf_app::smf_app (const std::string& config_file) : m_seid2smf_context()
throw;
}
//TODO: should be done when SMF select UPF for a particular UE (should be verified)
for (std::vector<pfcp::node_id_t>::const_iterator it = smf_cfg.upfs.begin(); it != smf_cfg.upfs.end(); ++it) {
start_upf_association(*it);
}
Logger::smf_app().startup( "Started" );
}
//------------------------------------------------------------------------------
//From SPGWU
void smf_app::start_upf_association(const pfcp::node_id_t& node_id)
{
// TODO refine this, look at RFC5905
std::tm tm_epoch = {0};// Feb 8th, 2036
tm_epoch.tm_year = 2036 - 1900; // years count from 1900
tm_epoch.tm_mon = 2 - 1; // months count from January=0
tm_epoch.tm_mday = 8-1; // days count from 1
std::time_t time_epoch = std::mktime(&tm_epoch);
std::chrono::time_point<std::chrono::system_clock> now = std::chrono::system_clock::now();
std::time_t now_c = std::chrono::system_clock::to_time_t(now);
std::time_t ellapsed = now_c - time_epoch;
uint64_t recovery_time_stamp = ellapsed;
//char* dt = ctime(&now_c);
//Logger::smf_app().info( "Current time %s", dt);
// convert now to tm struct for UTC
tm *gmtm = gmtime(&now_c);
char* dt = asctime(gmtm);
Logger::smf_app().info( "Current time (UTC) %s", dt);
pfcp_associations::get_instance().add_peer_candidate_node(node_id);
std::shared_ptr<itti_n4_association_setup_request> n4_asc= std::shared_ptr<itti_n4_association_setup_request>(new itti_n4_association_setup_request(TASK_SMF_APP, TASK_SMF_N4));
//n4_asc->trxn_id = smf_n4_inst->generate_trxn_id();
pfcp::cp_function_features_s cp_function_features;
cp_function_features = {};
cp_function_features.load = 1;
cp_function_features.ovrl = 1;
/*
pfcp::up_function_features_s up_function_features;
// TODO load from config when features available ?
up_function_features = {};
up_function_features.bucp = 0;
up_function_features.ddnd = 0;
up_function_features.dlbd = 0;
up_function_features.trst = 0;
up_function_features.ftup = 1;
up_function_features.pfdm = 0;
up_function_features.heeu = 0;
up_function_features.treu = 0;
up_function_features.empu = 0;
up_function_features.pdiu = 0;
up_function_features.udbc = 0;
up_function_features.quoac = 0;
up_function_features.trace = 0;
up_function_features.frrt = 0;
*/
pfcp::node_id_t this_node_id = {};
if (smf_cfg.get_pfcp_node_id(this_node_id) == RETURNok) {
n4_asc->pfcp_ies.set(this_node_id);
pfcp::recovery_time_stamp_t r = {.recovery_time_stamp = (uint32_t)recovery_time_stamp};
n4_asc->pfcp_ies.set(r);
//n4_asc->pfcp_ies.set(up_function_features);
n4_asc->pfcp_ies.set(cp_function_features);
if (node_id.node_id_type == pfcp::NODE_ID_TYPE_IPV4_ADDRESS) {
n4_asc->r_endpoint = endpoint(node_id.u1.ipv4_address, pfcp::default_port);
int ret = itti_inst->send_msg(n4_asc);
if (RETURNok != ret) {
Logger::smf_app().error( "Could not send ITTI message %s to task TASK_SMF_N4", n4_asc.get()->get_msg_name());
}
} else {
Logger::smf_app().warn( "TODO start_association() node_id IPV6, FQDN!");
}
}
}
//------------------------------------------------------------------------------
void smf_app::handle_itti_msg (itti_n4_session_establishment_response& seresp)
{
......@@ -298,15 +396,50 @@ void smf_app::handle_itti_msg (std::shared_ptr<itti_n4_session_report_request> s
}
}
//------------------------------------------------------------------------------
void smf_app::handle_itti_msg (itti_n11_n1n2_message_transfer_response_status& m)
{
Logger::smf_app().info("Process N1N2MessageTransfer Response");
//Update PDU Session accordingly
//TODO: to be completed (process cause)
pdu_session_status_e status;
if (static_cast<http_response_codes_e> (m.response_code) == http_response_codes_e::HTTP_RESPONSE_CODE_OK)
{
if (m.msg_type == PDU_SESSION_ESTABLISHMENT_REJECT){
status = pdu_session_status_e::PDU_SESSION_INACTIVE;
} else if (m.msg_type == PDU_SESSION_ESTABLISHMENT_ACCEPT){
status = pdu_session_status_e::PDU_SESSION_ACTIVE;
}
update_pdu_session_status(m.scid, status);
Logger::smf_app().debug("Got successful response from AMF (Response code %d), set session status to %s", m.response_code, pdu_session_status_e2str[static_cast<int>(status)].c_str());
}
else if (static_cast<http_response_codes_e> (m.response_code) == http_response_codes_e::HTTP_RESPONSE_CODE_ACCEPTED){
//TODO:
Logger::smf_app().debug("Got successful response from AMF (Response code %d), set session status to ACTIVE", m.response_code);
} else{ //by default
//TODO
}
}
//------------------------------------------------------------------------------
void smf_app::handle_itti_msg (itti_n11_update_pdu_session_status& m)
{
Logger::smf_app().info("Set PDU Session Status to %s", pdu_session_status_e2str[static_cast<int> (m.pdu_session_status)]);
update_pdu_session_status(m.scid, m.pdu_session_status);
}
//------------------------------------------------------------------------------
void smf_app::handle_amf_msg (std::shared_ptr<itti_n11_create_sm_context_request> smreq)
void smf_app::handle_pdu_session_create_sm_context_request(std::shared_ptr<itti_n11_create_sm_context_request> smreq)
{
Logger::smf_app().info("Handle a PDU Session Create SM Context Request from an AMF");
//handle PDU Session Create SM Context Request as specified in section 4.3.2 3GPP TS 23.502
oai::smf_server::model::SmContextCreateError smContextCreateError;
oai::smf_server::model::ProblemDetails problem_details;
oai::smf_server::model::RefToBinaryData binary_data;
std::string n1_container; //N1 SM container
std::string n1_sm_message; //N1 SM container
smf_n1_n2 smf_n1_n2_inst;
nas_message_t decoded_nas_msg;
......@@ -319,33 +452,28 @@ void smf_app::handle_amf_msg (std::shared_ptr<itti_n11_create_sm_context_request
int decoder_rc = smf_n1_n2_inst.decode_n1_sm_container(decoded_nas_msg, n1_sm_msg);
if (decoder_rc != RETURNok) {
//error, should send reply to AMF with error code!!
Logger::smf_app().warn("N1 SM container cannot be decoded correctly!\n");
Logger::smf_app().warn("N1 SM container cannot be decoded correctly!");
problem_details.setCause(pdu_session_application_error_e2str[PDU_SESSION_APPLICATION_ERROR_N1_SM_ERROR]);
smContextCreateError.setError(problem_details);
//PDU Session Establishment Reject
//24.501: response with a 5GSM STATUS message including cause "#95 Semantically incorrect message"
smf_n1_n2_inst.create_n1_sm_container(context_req_msg, PDU_SESSION_ESTABLISHMENT_REJECT, n1_container, 95); //TODO: should define 5GSM cause in 24.501
binary_data.setContentId(n1_container);
smContextCreateError.setN1SmMsg(binary_data);
smf_n1_n2_inst.create_n1_sm_container(context_req_msg, PDU_SESSION_ESTABLISHMENT_REJECT, n1_sm_message, cause_value_5gsm_e::CAUSE_95_SEMANTICALLY_INCORRECT_MESSAGE); //TODO: should define 5GSM cause in 24.501
//Send response to AMF
nlohmann::json jsonData;
to_json(jsonData, smContextCreateError);
//httpResponse.headers().add<Pistache::Http::Header::Location>(url);
send_create_session_response(smreq->http_response, smContextCreateError, Pistache::Http::Code::Forbidden);
smf_n11_inst->send_pdu_session_create_sm_context_response(smreq->http_response, smContextCreateError, Pistache::Http::Code::Forbidden, n1_sm_message);
}
Logger::smf_app().debug("NAS header information: extended_protocol_discriminator %d, security_header_type:%d,sequence_number:%d,message_authentication_code:%d\n",
Logger::smf_app().debug("NAS header information: extended protocol discriminator %d, security headertype %d",
decoded_nas_msg.header.extended_protocol_discriminator,
decoded_nas_msg.header.security_header_type,
decoded_nas_msg.header.sequence_number,
decoded_nas_msg.header.message_authentication_code);
decoded_nas_msg.header.security_header_type);
//Extended protocol discriminator (Mandatory)
smreq->req.set_epd(decoded_nas_msg.header.extended_protocol_discriminator);
//Message type (Mandatory) (PDU SESSION ESTABLISHMENT REQUEST message identity)
Logger::smf_app().debug("NAS header information, Message Type %d\n", decoded_nas_msg.plain.sm.header.message_type);
Logger::smf_app().debug("NAS header information, Message Type %d", decoded_nas_msg.plain.sm.header.message_type);
smreq->req.set_message_type(decoded_nas_msg.plain.sm.header.message_type);
//Integrity protection maximum data rate (Mandatory)
......@@ -354,7 +482,7 @@ void smf_app::handle_amf_msg (std::shared_ptr<itti_n11_create_sm_context_request
smreq->req.set_pdu_session_type(PDU_SESSION_TYPE_E_IPV4); //set default value
if (decoded_nas_msg.plain.sm.header.message_type == PDU_SESSION_ESTABLISHMENT_REQUEST){
//TODO: Disable this command temporarily since can't get this info from tester
//sm_context_req_msg.set_pdu_session_type(decoded_nas_msg.plain.sm.specific_msg.pdu_session_establishment_request._pdusessiontype.pdu_session_type_value);
//sm_context_req_msg.set_pdu_session_type(decoded_nas_msg.plain.sm.pdu_session_establishment_request._pdusessiontype.pdu_session_type_value);
}
//Get necessary information
......@@ -377,45 +505,39 @@ void smf_app::handle_amf_msg (std::shared_ptr<itti_n11_create_sm_context_request
//Step 2. Verify Procedure transaction id, pdu session id, message type, request type, etc.
//check pti
if ((pti.procedure_transaction_id == PROCEDURE_TRANSACTION_IDENTITY_UNASSIGNED) || (pti.procedure_transaction_id > PROCEDURE_TRANSACTION_IDENTITY_LAST)){
Logger::smf_app().warn(" Invalid PTI value (pti = %d)\n", pti.procedure_transaction_id);
Logger::smf_app().warn(" Invalid PTI value (pti = %d)", pti.procedure_transaction_id);
problem_details.setCause(pdu_session_application_error_e2str[PDU_SESSION_APPLICATION_ERROR_N1_SM_ERROR]);
smContextCreateError.setError(problem_details);
//PDU Session Establishment Reject
//(24.501 (section 7.3.1)) NAS N1 SM message: response with a 5GSM STATUS message including cause "#81 Invalid PTI value"
smf_n1_n2_inst.create_n1_sm_container(context_req_msg, PDU_SESSION_ESTABLISHMENT_REJECT, n1_container, 81); //TODO: should define 5GSM cause in 24.501
binary_data.setContentId(n1_container);
smContextCreateError.setN1SmMsg(binary_data);
smf_n1_n2_inst.create_n1_sm_container(context_req_msg, PDU_SESSION_ESTABLISHMENT_REJECT, n1_sm_message, cause_value_5gsm_e::CAUSE_81_INVALID_PTI_VALUE); //TODO: should define 5GSM cause in 24.501
//Send response to AMF
send_create_session_response(smreq->http_response, smContextCreateError, Pistache::Http::Code::Forbidden);
smf_n11_inst->send_pdu_session_create_sm_context_response(smreq->http_response, smContextCreateError, Pistache::Http::Code::Forbidden, n1_sm_message);
}
//check pdu session id
if ((pdu_session_id == PDU_SESSION_IDENTITY_UNASSIGNED) || (pdu_session_id > PDU_SESSION_IDENTITY_LAST)){
Logger::smf_app().warn(" Invalid PDU Session ID value (psi = %d)\n", pdu_session_id);
//TODO: (24.501 (section 7.3.2)) NAS N1 SM message: ignore the message
//return;
Logger::smf_app().warn(" Invalid PDU Session ID value (psi = %d)", pdu_session_id);
//section 7.3.2@3GPP TS 24.501; NAS N1 SM message: ignore the message
return;
}
//check message type
if (message_type != PDU_SESSION_ESTABLISHMENT_REQUEST) {
Logger::smf_app().warn("Invalid message type (message type = %d)\n", message_type);
//TODO:
Logger::smf_app().warn("Invalid message type (message type = %d)", message_type);
problem_details.setCause(pdu_session_application_error_e2str[PDU_SESSION_APPLICATION_ERROR_N1_SM_ERROR]);
smContextCreateError.setError(problem_details);
//PDU Session Establishment Reject
//(24.501 (section 7.4)) implementation dependent->do similar to UE: response with a 5GSM STATUS message including cause "#98 message type not compatible with protocol state."
smf_n1_n2_inst.create_n1_sm_container(context_req_msg, PDU_SESSION_ESTABLISHMENT_REJECT, n1_container, 98); //TODO: should define 5GSM cause in 24.501
binary_data.setContentId(n1_container);
smContextCreateError.setN1SmMsg(binary_data);
smf_n1_n2_inst.create_n1_sm_container(context_req_msg, PDU_SESSION_ESTABLISHMENT_REJECT, n1_sm_message, cause_value_5gsm_e::CAUSE_98_MESSAGE_TYPE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE); //TODO: should define 5GSM cause in 24.501
//Send response to AMF
send_create_session_response(smreq->http_response, smContextCreateError, Pistache::Http::Code::Forbidden);
smf_n11_inst->send_pdu_session_create_sm_context_response(smreq->http_response, smContextCreateError, Pistache::Http::Code::Forbidden, n1_sm_message);
}
//check request type
if (request_type.compare("INITIAL_REQUEST") !=0 ){
Logger::smf_app().warn("Invalid request type (request type = %s)\n", "INITIAL_REQUEST");
Logger::smf_app().warn("Invalid request type (request type = %s)", "INITIAL_REQUEST");
//TODO:
//return
}
......@@ -425,16 +547,13 @@ void smf_app::handle_amf_msg (std::shared_ptr<itti_n11_create_sm_context_request
//Step 3. check if the DNN requested is valid
if (not smf_cfg.is_dotted_dnn_handled(dnn, pdu_session_type)) {
// Not a valid request...
Logger::smf_app().warn("Received PDU_SESSION_CREATESMCONTEXT_REQUEST unknown requested APN %s, ignore message!", dnn.c_str());
Logger::smf_app().warn("Received PDU_SESSION_CREATESMCONTEXT_REQUEST unknown requested DNN %s, ignore message!", dnn.c_str());
problem_details.setCause(pdu_session_application_error_e2str[PDU_SESSION_APPLICATION_ERROR_DNN_DENIED]);
smContextCreateError.setError(problem_details);
//PDU Session Establishment Reject
//(24.501 cause "#27 Missing or unknown DNN"
smf_n1_n2_inst.create_n1_sm_container(context_req_msg, PDU_SESSION_ESTABLISHMENT_REJECT, n1_container, CAUSE_27_MISSING_OR_UNKNOWN_DNN);
binary_data.setContentId(n1_container);
smContextCreateError.setN1SmMsg(binary_data);
//PDU Session Establishment Reject, 24.501 cause "#27 Missing or unknown DNN"
smf_n1_n2_inst.create_n1_sm_container(context_req_msg, PDU_SESSION_ESTABLISHMENT_REJECT, n1_sm_message, cause_value_5gsm_e::CAUSE_27_MISSING_OR_UNKNOWN_DNN);
//Send response to AMF
send_create_session_response(smreq->http_response, smContextCreateError, Pistache::Http::Code::Forbidden);
smf_n11_inst->send_pdu_session_create_sm_context_response(smreq->http_response, smContextCreateError, Pistache::Http::Code::Forbidden, n1_sm_message);
return;
}
......@@ -457,7 +576,7 @@ void smf_app::handle_amf_msg (std::shared_ptr<itti_n11_create_sm_context_request
if (!sc.get()->find_dnn_context(snssai, dnn, sd)) {
if (nullptr == sd.get()){
//create a new one and insert to the list
Logger::smf_app().debug("Create a DNN context and add to the SMF context\n");
Logger::smf_app().debug("Create a DNN context and add to the SMF context");
sd = std::shared_ptr<dnn_context>(new dnn_context(dnn));
sd.get()->in_use = true;
sd.get()->dnn_in_use = dnn;
......@@ -466,7 +585,7 @@ void smf_app::handle_amf_msg (std::shared_ptr<itti_n11_create_sm_context_request
}
}
// step 6. retrieve Session Management Subscription data from UDM if not available (step 4, section 4.3.2 3GPP TS 23.502)
//Step 6. retrieve Session Management Subscription data from UDM if not available (step 4, section 4.3.2 3GPP TS 23.502)
std::string dnn_selection_mode = smreq->req.get_dnn_selection_mode();
if (not use_local_configuration_subscription_data(dnn_selection_mode) && not is_supi_dnn_snssai_subscription_data(supi, dnn, snssai))
{
......@@ -484,13 +603,10 @@ void smf_app::handle_amf_msg (std::shared_ptr<itti_n11_create_sm_context_request
Logger::smf_app().warn("Received PDU_SESSION_CREATESMCONTEXT_REQUEST, couldn't retrieve the Session Management Subscription from UDM, ignore message!");
problem_details.setCause(pdu_session_application_error_e2str[PDU_SESSION_APPLICATION_ERROR_SUBSCRIPTION_DENIED]);
smContextCreateError.setError(problem_details);
//PDU Session Establishment Reject
//24.501 which cause should be use "29 User authentication or authorization failed"?
smf_n1_n2_inst.create_n1_sm_container(context_req_msg, PDU_SESSION_ESTABLISHMENT_REJECT, n1_container, CAUSE_29_USER_AUTHENTICATION_OR_AUTHORIZATION_FAILED);
binary_data.setContentId(n1_container);
smContextCreateError.setN1SmMsg(binary_data);
//PDU Session Establishment Reject, with cause "29 User authentication or authorization failed"?
smf_n1_n2_inst.create_n1_sm_container(context_req_msg, PDU_SESSION_ESTABLISHMENT_REJECT, n1_sm_message, cause_value_5gsm_e::CAUSE_29_USER_AUTHENTICATION_OR_AUTHORIZATION_FAILED);
//Send response (PDU Session Establishment Reject) to AMF
send_create_session_response(smreq->http_response, smContextCreateError, Pistache::Http::Code::Forbidden);
smf_n11_inst->send_pdu_session_create_sm_context_response(smreq->http_response, smContextCreateError, Pistache::Http::Code::Forbidden, n1_sm_message);
return;
}
}
......@@ -504,23 +620,26 @@ void smf_app::handle_amf_msg (std::shared_ptr<itti_n11_create_sm_context_request
scf.get()->pdu_session_id = pdu_session_id;
set_scid_2_smf_context(scid, scf);
smreq->set_scid(scid);
//store scid in the context itself
sc.get()->set_scid(scid);
Logger::smf_app().debug("Generated a SCID " SCID_FMT " ", scid);
//Step 8. let the context handle the message
//in this step, SMF will send N4 Session Establishment/Modification to UPF (step 10a, section 4.3.2 3GPP 23.502)
//SMF, then, sends response to AMF
sc.get()->handle_amf_msg(smreq);
sc.get()->handle_pdu_session_create_sm_context_request(smreq);
}
//------------------------------------------------------------------------------
void smf_app::handle_amf_msg (std::shared_ptr<itti_n11_update_sm_context_request> smreq)
void smf_app::handle_pdu_session_update_sm_context_request (std::shared_ptr<itti_n11_update_sm_context_request> smreq)
{
//handle PDU Session Update SM Context Request as specified in section 4.3.2 3GPP TS 23.502
Logger::smf_app().info("Handle a PDU Session Update SM Context Request from an AMF");
oai::smf_server::model::SmContextUpdateError smContextUpdateError;
oai::smf_server::model::ProblemDetails problem_details;
oai::smf_server::model::RefToBinaryData binary_data;
std::string n1_container; //N1 SM container
std::string n1_sm_message; //N1 SM container
smf_n1_n2 smf_n1_n2_inst; //to encode Ngap IE
//Step 1. get supi, dnn, nssai, pdu_session id from sm_context
......@@ -537,15 +656,13 @@ void smf_app::handle_amf_msg (std::shared_ptr<itti_n11_update_sm_context_request
catch (const std::exception& err) {
//TODO: send PDUSession_SMUpdateContext Response (including PDU Session EStablishment Reject) to AMF with CAUSE: invalid context
Logger::smf_app().warn("Received PDU_SESSION_UPDATESMCONTEXT_REQUEST, couldn't retrieve the corresponding SMF context, ignore message!");
problem_details.setCause(pdu_session_application_error_e2str[PDU_SESSION_APPLICATION_ERROR_CONTEXT_NOT_FOUND]);
smContextUpdateError.setError(problem_details);
//PDU Session Update Reject
//Create N1 container
smf_n1_n2_inst.create_n1_sm_container(smreq->req, PDU_SESSION_ESTABLISHMENT_REJECT, n1_container, CAUSE_54_PDU_SESSION_DOES_NOT_EXIST);
binary_data.setContentId(n1_container);
smContextUpdateError.setN1SmMsg(binary_data);
smf_n1_n2_inst.create_n1_sm_container(smreq->req, PDU_SESSION_ESTABLISHMENT_REJECT, n1_sm_message, cause_value_5gsm_e::CAUSE_54_PDU_SESSION_DOES_NOT_EXIST);
//Send response to AMF
send_update_session_response(smreq->http_response, smContextUpdateError, Pistache::Http::Code::Forbidden);
smf_n11_inst->send_pdu_session_update_sm_context_response(smreq->http_response, smContextUpdateError, Pistache::Http::Code::Forbidden, n1_sm_message);
return;
}
......@@ -582,13 +699,11 @@ void smf_app::handle_amf_msg (std::shared_ptr<itti_n11_update_sm_context_request
Logger::smf_app().warn("Received PDU_SESSION_UPDATESMCONTEXT_REQUEST with Supi " SUPI_64_FMT "couldn't retrieve the corresponding SMF context, ignore message!", supi64);
problem_details.setCause(pdu_session_application_error_e2str[PDU_SESSION_APPLICATION_ERROR_CONTEXT_NOT_FOUND]);
smContextUpdateError.setError(problem_details);
//PDU Session Update Reject
//Create N1 container
smf_n1_n2_inst.create_n1_sm_container(context_req_msg, PDU_SESSION_ESTABLISHMENT_REJECT, n1_container, CAUSE_29_USER_AUTHENTICATION_OR_AUTHORIZATION_FAILED);
binary_data.setContentId(n1_container);
smContextUpdateError.setN1SmMsg(binary_data);
smf_n1_n2_inst.create_n1_sm_container(context_req_msg, PDU_SESSION_ESTABLISHMENT_REJECT, n1_sm_message, cause_value_5gsm_e::CAUSE_29_USER_AUTHENTICATION_OR_AUTHORIZATION_FAILED);
//Send response to AMF
send_update_session_response(smreq->http_response, smContextUpdateError, Pistache::Http::Code::Forbidden);
smf_n11_inst->send_pdu_session_update_sm_context_response(smreq->http_response, smContextUpdateError, Pistache::Http::Code::Forbidden, n1_sm_message);
return;
}
......@@ -602,27 +717,58 @@ void smf_app::handle_amf_msg (std::shared_ptr<itti_n11_update_sm_context_request
Logger::smf_app().warn("Received PDU_SESSION_UPDATESMCONTEXT_REQUEST, couldn't retrieve the corresponding SMF context, ignore message!");
problem_details.setCause(pdu_session_application_error_e2str[PDU_SESSION_APPLICATION_ERROR_CONTEXT_NOT_FOUND]);
smContextUpdateError.setError(problem_details);
//PDU Session Update Reject
//Create N1 container
smf_n1_n2_inst.create_n1_sm_container(context_req_msg, PDU_SESSION_ESTABLISHMENT_REJECT, n1_container, CAUSE_27_MISSING_OR_UNKNOWN_DNN);
binary_data.setContentId(n1_container);
smContextUpdateError.setN1SmMsg(binary_data);
smf_n1_n2_inst.create_n1_sm_container(context_req_msg, PDU_SESSION_ESTABLISHMENT_REJECT, n1_sm_message, cause_value_5gsm_e::CAUSE_27_MISSING_OR_UNKNOWN_DNN);
//Send response to AMF
send_update_session_response(smreq->http_response, smContextUpdateError, Pistache::Http::Code::Forbidden);
smf_n11_inst->send_pdu_session_update_sm_context_response(smreq->http_response, smContextUpdateError, Pistache::Http::Code::Forbidden, n1_sm_message);
return;
}
}
//Step 3. Verify AMF??
//TODO: based on AMF ID > get the fteid -> get the SMF context (we should also verify AMF_ID)
//TODO: Step 2.1. if not exist -> send reply to AMF (reject)
//TODO: create N1 container and send reject message to AMF
//Step 4. handle the message in smf_context
sc.get()->handle_amf_msg(smreq);
sc.get()->handle_pdu_session_update_sm_context_request(smreq);
}
//------------------------------------------------------------------------------
void smf_app::handle_network_requested_pdu_session_modification()
{
std::shared_ptr<itti_nx_modify_pdu_session_request_network_requested> itti_msg = std::make_shared<itti_nx_modify_pdu_session_request_network_requested>(TASK_SMF_N11, TASK_SMF_APP);
supi_t supi;
std::string dnn;
pdu_session_id_t pdu_session_id ;
snssai_t nssai ;
supi64_t supi64 = smf_supi_to_u64(supi);
//Step 2. find the smf context
std::shared_ptr<smf_context> sc;
if (is_supi_2_smf_context(supi64)) {
sc = supi_2_smf_context(supi64);
Logger::smf_app().debug("Retrieve SMF context with SUPI " SUPI_64_FMT "", supi64);
} else {
return;
}
//get dnn context
std::shared_ptr<dnn_context> sd;
if (!sc.get()->find_dnn_context(nssai, dnn, sd)) {
if (nullptr == sd.get()){
return;
}
}
// handle the message in smf_context
// sc.get()->handle_network_requested_pdu_session_modification(itti_msg);
}
//------------------------------------------------------------------------------
bool smf_app::is_supi_2_smf_context(const supi64_t& supi) const
{
......@@ -687,34 +833,10 @@ bool smf_app::is_create_sm_context_request_valid()
}
//------------------------------------------------------------------------------
void smf_app::send_create_session_response(Pistache::Http::ResponseWriter& httpResponse, oai::smf_server::model::SmContextCreateError& smContextCreateError, Pistache::Http::Code code)
{
//Send reply to AMF
nlohmann::json jsonData;
to_json(jsonData, smContextCreateError);
std::string resBody = jsonData.dump();
//httpResponse.headers().add<Pistache::Http::Header::Location>(url);
httpResponse.send(code, resBody);
}
//------------------------------------------------------------------------------
void smf_app::send_update_session_response(Pistache::Http::ResponseWriter& httpResponse, oai::smf_server::model::SmContextUpdateError& smContextUpdateError, Pistache::Http::Code code)
{
//Send reply to AMF
nlohmann::json jsonData;
to_json(jsonData, smContextUpdateError);
std::string resBody = jsonData.dump();
//httpResponse.headers().add<Pistache::Http::Header::Location>(url);
httpResponse.send(code, resBody);
}
//---------------------------------------------------------------------------------------------
void smf_app::convert_string_2_hex(std::string& input_str, std::string& output_str){
Logger::smf_app().debug("Convert std::string to Hex\n");
Logger::smf_app().debug("Convert string to Hex");
unsigned char *data = (unsigned char *) malloc (input_str.length() + 1);
memset(data, 0, input_str.length() + 1);
memcpy ((void *)data, (void *)input_str.c_str(), input_str.length());
......@@ -723,7 +845,7 @@ void smf_app::convert_string_2_hex(std::string& input_str, std::string& output_s
for(int i = 0; i < input_str.length(); i++) {
printf("%02x ", data[i]);
}
printf("\n");
char *datahex = (char *) malloc (input_str.length() * 2 + 1);
memset(datahex, 0, input_str.length() *2 + 1);
......@@ -731,5 +853,139 @@ void smf_app::convert_string_2_hex(std::string& input_str, std::string& output_s
sprintf(datahex + i*2, "%02x", data[i]);
output_str = reinterpret_cast<char*> (datahex);
Logger::smf_app().debug("Output str: %s\n ", output_str.c_str());
Logger::smf_app().debug("Output str: \n %s ", output_str.c_str());
}
//---------------------------------------------------------------------------------------------
unsigned char * smf_app::format_string_as_hex(std::string str){
unsigned int str_len = str.length();
unsigned char * datavalue = (unsigned char *)malloc(str_len/2 + 1);
unsigned char *data = (unsigned char *)malloc(str_len + 1);
memset(data,0,str_len + 1);
memcpy ((void *)data, (void *)str.c_str(),str_len);
std::cout << "[Format string as Hex] Input string (" << str_len <<" bytes): \n" << str.c_str() <<std::endl;
/* for(int i = 0;i < str_len; i++)
{
printf("%02x ", data[i]);
}
*/
std::cout <<"Data (formatted): \n";
for(int i=0; i < str_len; i++)
{
//printf("%02x ", data[i]);
char datatmp[3] = {0};
memcpy(datatmp,&data[i],2);
// Ensure both characters are hexadecimal
bool bBothDigits = true;
for(int j = 0; j < 2; ++j)
{
if(!isxdigit(datatmp[j]))
bBothDigits = false;
}
//if(!bBothDigits)
// break;
// Convert two hexadecimal characters into one character
unsigned int nAsciiCharacter;
sscanf(datatmp, "%x", &nAsciiCharacter);
printf("%x ",nAsciiCharacter);
// Concatenate this character onto the output
datavalue[i/2] = (unsigned char)nAsciiCharacter;
// Skip the next character
i++;
}
printf("\n");
free(data);
data = nullptr;
return datavalue;
}
//---------------------------------------------------------------------------------------------
void smf_app::print_string_as_hex(std::string str){
Logger::smf_app().debug("print_string_as_hex, input %s", str.c_str());
unsigned int str_len = str.length();
unsigned char *data = (unsigned char *)malloc(str_len + 1);
memset(data,0,str_len + 1);
memcpy ((void *)data, (void *)str.c_str(),str_len);
printf ("\nData as Hex: ");
for(int i=0;i<str_len;i++)
{
printf("%02x ",data[i]);
}
printf (" (%d bytes) \n", str_len);
free(data);
data = nullptr;
}
//---------------------------------------------------------------------------------------------
void smf_app::update_pdu_session_status(const scid_t scid, const pdu_session_status_e status)
{
Logger::smf_app().info("Update PDU Session Status");
//get the smf context
std::shared_ptr<smf_context_ref> scf;
if (is_scid_2_smf_context(scid)) {
scf = scid_2_smf_context(scid);
} else {
Logger::smf_app().warn("Context associated with this id " SCID_FMT " does not exit!", scid);
}
supi_t supi = scf.get()->supi;
supi64_t supi64 = smf_supi_to_u64(supi);
pdu_session_id_t pdu_session_id = scf.get()->pdu_session_id;
std::shared_ptr<smf_context> sc;
if (is_supi_2_smf_context(supi64)) {
sc = supi_2_smf_context(supi64);
Logger::smf_app().debug("Retrieve SMF context with SUPI " SUPI_64_FMT "", supi64);
} else {
Logger::smf_app().error("Could not retrieve the corresponding SMF context with Supi " SUPI_64_FMT "!", supi64);
//TODO:
}
//get dnn context
std::shared_ptr<dnn_context> sd;
if (!sc.get()->find_dnn_context(scf.get()->nssai, scf.get()->dnn, sd)) {
if (nullptr == sd.get()){
//Error, DNN context doesn't exist
Logger::smf_app().warn("Could not retrieve the corresponding DNN context!");
}
}
//get smd_pdu_session
std::shared_ptr<smf_pdu_session> sp;
bool find_pdn = sd.get()->find_pdu_session(pdu_session_id, sp);
if (nullptr == sp.get()){
Logger::smf_app().warn("Could not retrieve the corresponding SMF PDU Session context!");
}
sp.get()->set_pdu_session_status(status);
Logger::smf_app().info("Set PDU Session Status to %s", pdu_session_status_e2str[static_cast<int> (status)].c_str());
}
//---------------------------------------------------------------------------------------------
void smf_app::timer_t3591_timeout(timer_id_t timer_id, uint64_t arg2_user)
{
//send session modification request again...
}
//---------------------------------------------------------------------------------------------
n2_sm_info_type_e smf_app::n2_sm_info_type_str2e(std::string n2_info_type)
{
std::size_t number_of_types = n2_sm_info_type_e2str.size();
for (auto i = 0; i < number_of_types; ++i){
if (n2_info_type.compare(n2_sm_info_type_e2str[i]) == 0){
return static_cast<n2_sm_info_type_e> (i);
}
}
}
......@@ -32,6 +32,7 @@
#include "smf.h"
#include "3gpp_29.274.h"
#include "3gpp_29.502.h"
#include "itti_msg_n4.hpp"
#include "itti_msg_n11.hpp"
#include "smf_context.hpp"
......@@ -53,6 +54,19 @@
namespace smf {
#define TASK_SMF_APP_TRIGGER_T3591 (0)
#define TASK_SMF_APP_TIMEOUT_T3591 (1)
//Table 10.3.2 @3GPP TS 24.501 V16.1.0 (2019-06)
#define T3591_TIMER_VALUE_SEC 16
#define T3591_TIMER_MAX_RETRIES 4
typedef enum {
PDU_SESSION_ESTABLISHMENT = 1,
PDU_SESSION_MODIFICATION = 2,
PDU_SESSION_RELEASE = 3
} pdu_session_procedure_t;
class smf_config; // same namespace
class smf_context_ref {
......@@ -133,7 +147,22 @@ public:
void handle_itti_msg (std::shared_ptr<itti_n4_session_report_request> snr);
void handle_itti_msg (itti_n4_association_setup_request& m);
void restore_sx_sessions(const seid_t& seid) const;
/*
* Handle ITTI message from N11 to update PDU session status
* @param [itti_n11_update_pdu_session_status&] itti_n11_update_pdu_session_status
* @return void
*/
void handle_itti_msg (itti_n11_update_pdu_session_status& m);
/*
* Handle ITTI message from N11 (N1N2MessageTransfer Response)
* @param [itti_n11_n1n2_message_transfer_response_status&] itti_n11_n1n2_message_transfer_response_status
* @return void
*/
void handle_itti_msg (itti_n11_n1n2_message_transfer_response_status& m);
void restore_n4_sessions(const seid_t& seid) const;
uint64_t generate_seid();
bool is_seid_n4_exist(const uint64_t& s) const;
......@@ -152,14 +181,21 @@ public:
* @param [std::shared_ptr<itti_n11_create_sm_context_request>&] Request message
* @return void
*/
void handle_amf_msg (std::shared_ptr<itti_n11_create_sm_context_request> smreq);
void handle_pdu_session_create_sm_context_request (std::shared_ptr<itti_n11_create_sm_context_request> smreq);
/*
* Handle PDUSession_UpdateSMContextRequest from AMF
* @param [std::shared_ptr<itti_n11_update_sm_context_request>&] Request message
* @return void
*/
void handle_amf_msg (std::shared_ptr<itti_n11_update_sm_context_request> smreq);
void handle_pdu_session_update_sm_context_request (std::shared_ptr<itti_n11_update_sm_context_request> smreq);
/*
* Handle network-requested pdu session modification
* @param should be updated
* @return void
*/
void handle_network_requested_pdu_session_modification();
/*
* Verify if SM Context is existed for this Supi
......@@ -206,23 +242,6 @@ public:
*/
bool is_create_sm_context_request_valid();
/*
* Send create session response to AMF
* @param [Pistache::Http::ResponseWriter] httpResponse
* @param [ oai::smf_server::model::SmContextCreateError] smContextCreateError
* @param [Pistache::Http::Code] code, response code
*
*/
void send_create_session_response(Pistache::Http::ResponseWriter& httpResponse, oai::smf_server::model::SmContextCreateError& smContextCreateError, Pistache::Http::Code code);
/*
* Send update session response to AMF
* @param [Pistache::Http::ResponseWriter] httpResponse
* @param [ oai::smf_server::model::SmContextUpdateError] smContextUpdateError
* @param [Pistache::Http::Code] code, response code
*
*/
void send_update_session_response(Pistache::Http::ResponseWriter& httpResponse, oai::smf_server::model::SmContextUpdateError& smContextUpdateError, Pistache::Http::Code code);
/*
* Convert a string to hex representing this string
......@@ -232,6 +251,23 @@ public:
*/
void convert_string_2_hex(std::string& input_str, std::string& output_str);
unsigned char * format_string_as_hex(std::string str);
void print_string_as_hex(std::string str);
void start_upf_association(const pfcp::node_id_t& node_id);
/*
* Update PDU session status
* @param [const scid_t] id SM Context ID
* @param [const pdu_session_status_e] status PDU Session Status
* @return void
*/
void update_pdu_session_status(const scid_t id, const pdu_session_status_e status);
void timer_t3591_timeout(timer_id_t timer_id, uint64_t arg2_user);
n2_sm_info_type_e n2_sm_info_type_str2e(std::string n2_info_type);
};
}
#include "smf_config.hpp"
......
......@@ -137,15 +137,8 @@ int smf_config::load_itti(const Setting& itti_cfg, itti_cfg_t& cfg)
}
try {
const Setting& s5s8_sched_params_cfg = itti_cfg[SMF_CONFIG_STRING_S5S8_SCHED_PARAMS];
load_thread_sched_params(s5s8_sched_params_cfg, cfg.s5s8_sched_params);
} catch(const SettingNotFoundException &nfex) {
Logger::smf_app().info("%s : %s, using defaults", nfex.what(), nfex.getPath());
}
try {
const Setting& sx_sched_params_cfg = itti_cfg[SMF_CONFIG_STRING_SX_SCHED_PARAMS];
load_thread_sched_params(sx_sched_params_cfg, cfg.sx_sched_params);
const Setting& n4_sched_params_cfg = itti_cfg[SMF_CONFIG_STRING_N4_SCHED_PARAMS];
load_thread_sched_params(n4_sched_params_cfg, cfg.n4_sched_params);
} catch(const SettingNotFoundException &nfex) {
Logger::smf_app().info("%s : %s, using defaults", nfex.what(), nfex.getPath());
}
......@@ -265,9 +258,6 @@ int smf_config::load(const string& config_file)
try {
const Setting &nw_if_cfg = smf_cfg[SMF_CONFIG_STRING_INTERFACES];
const Setting& sx_cfg = nw_if_cfg[SMF_CONFIG_STRING_INTERFACE_SX];
load_interface(sx_cfg, sx);
const Setting& n4_cfg = nw_if_cfg[SMF_CONFIG_STRING_INTERFACE_N4];
load_interface(n4_cfg, n4);
......@@ -376,11 +366,11 @@ int smf_config::load(const string& config_file)
apn_cfg.lookupValue(SMF_CONFIG_STRING_IPV6_POOL, apn[apn_idx].pool_id_iv6);
if ((0 <= apn[apn_idx].pool_id_iv4) && (apn[apn_idx].pdn_type.pdn_type == PDN_TYPE_E_IPV6)) {
Logger::smf_app().error("PDN_TYPE versus pool identifier %d 'th APN in config file\n", i+1);
Logger::smf_app().error("PDN_TYPE versus pool identifier %d 'th APN in config file", i+1);
throw ("PDN_TYPE versus pool identifier APN");
}
if ((0 <= apn[apn_idx].pool_id_iv6) && (apn[apn_idx].pdn_type.pdn_type == PDN_TYPE_E_IPV4)) {
Logger::smf_app().error("PDN_TYPE versus pool identifier %d 'th APN in config file\n", i+1);
Logger::smf_app().error("PDN_TYPE versus pool identifier %d 'th APN in config file", i+1);
throw ("PDN_TYPE versus pool identifier APN");
}
......@@ -390,7 +380,7 @@ int smf_config::load(const string& config_file)
for (int j = 0; j < apn_idx; j++) {
if (boost::iequals(apn[j].apn, apn[apn_idx].apn)) {
doublon = true;
Logger::smf_app().info("%d'th APN %s already found in config file (%d 'th APN %s), bypassing\n", i+1, apn[apn_idx].apn.c_str(), j+1, apn[j].apn.c_str());
Logger::smf_app().info("%d'th APN %s already found in config file (%d 'th APN %s), bypassing", i+1, apn[apn_idx].apn.c_str(), j+1, apn[j].apn.c_str());
}
}
if (not doublon) {
......@@ -398,7 +388,7 @@ int smf_config::load(const string& config_file)
num_apn++;
}
} else {
Logger::smf_app().error("Bypass %d'th APN %s in config file\n", i+1, apn[apn_idx].apn.c_str());
Logger::smf_app().error("Bypass %d'th APN %s in config file", i+1, apn[apn_idx].apn.c_str());
}
}
smf_cfg.lookupValue(SMF_CONFIG_STRING_DEFAULT_DNS_IPV4_ADDRESS, astring);
......@@ -469,6 +459,29 @@ int smf_config::load(const string& config_file)
udm_addr.port = udm_port;
//UPF list
unsigned char buf_in_addr[sizeof (struct in_addr)+1];
const Setting& upf_list_cfg = smf_cfg[SMF_CONFIG_STRING_UPF_LIST];
count = upf_list_cfg.getLength();
for (int i = 0; i < count; i++) {
const Setting &upf_cfg = upf_list_cfg[i];
string address = {};
if (upf_cfg.lookupValue(SMF_CONFIG_STRING_UPF_IPV4_ADDRESS, address)) {
pfcp::node_id_t n = {};
n.node_id_type = pfcp::NODE_ID_TYPE_IPV4_ADDRESS; // actually
if (inet_pton (AF_INET, util::trim(address).c_str(), buf_in_addr) == 1) {
memcpy (&n.u1.ipv4_address, buf_in_addr, sizeof (struct in_addr));
} else {
Logger::smf_app().error("CONFIG: BAD IPV4 ADDRESS in " SMF_CONFIG_STRING_UPF_LIST " item %d", i);
throw ("CONFIG: BAD ADDRESS in " SMF_CONFIG_STRING_UPF_LIST);
}
upfs.push_back(n);
} else {
// TODO IPV6_ADDRESS, FQDN
throw ("Bad value in section %s : item no %d in config file %s", SMF_CONFIG_STRING_UPF_LIST, i, config_file.c_str());
}
}
}
catch(const SettingNotFoundException &nfex)
{
......@@ -486,11 +499,6 @@ void smf_config::display ()
Logger::smf_app().info( "- Instance ..............: %d\n", instance);
Logger::smf_app().info( "- PID dir ...............: %s\n", pid_dir.c_str());
Logger::smf_app().info( "- SX Networking:");
Logger::smf_app().info( " iface ................: %s", sx.if_name.c_str());
Logger::smf_app().info( " ip ...................: %s", inet_ntoa (sx.addr4));
Logger::smf_app().info( " port .................: %d", sx.port);
Logger::smf_app().info( "- N4 Networking:");
Logger::smf_app().info( " iface ................: %s", n4.if_name.c_str());
Logger::smf_app().info( " ip ...................: %s", inet_ntoa (n4.addr4));
......@@ -501,12 +509,6 @@ void smf_config::display ()
Logger::smf_app().info( " ip ...................: %s", inet_ntoa (n11.addr4));
Logger::smf_app().info( " port .................: %d", n11.port);
Logger::smf_app().info( "- SX Threading:");
Logger::smf_app().info( " CPU id............: %d", sx.thread_rd_sched_params.cpu_id);
Logger::smf_app().info( " Scheduling policy : %d", sx.thread_rd_sched_params.sched_policy);
Logger::smf_app().info( " Scheduling prio .: %d", sx.thread_rd_sched_params.sched_priority);
Logger::smf_app().info( "- N4 Threading:");
Logger::smf_app().info( " CPU id............: %d", n4.thread_rd_sched_params.cpu_id);
Logger::smf_app().info( " Scheduling policy : %d", n4.thread_rd_sched_params.sched_policy);
......@@ -516,14 +518,10 @@ void smf_config::display ()
Logger::smf_app().info( " CPU id............: %d", itti.itti_timer_sched_params.cpu_id);
Logger::smf_app().info( " Scheduling policy : %d", itti.itti_timer_sched_params.sched_policy);
Logger::smf_app().info( " Scheduling prio .: %d", itti.itti_timer_sched_params.sched_priority);
Logger::smf_app().info( "- ITTI S5S8 Task Threading:");
Logger::smf_app().info( " CPU id............: %d", itti.s5s8_sched_params.cpu_id);
Logger::smf_app().info( " Scheduling policy : %d", itti.s5s8_sched_params.sched_policy);
Logger::smf_app().info( " Scheduling prio .: %d", itti.s5s8_sched_params.sched_priority);
Logger::smf_app().info( "- ITTI Sx Task Threading:");
Logger::smf_app().info( " CPU id............: %d", itti.sx_sched_params.cpu_id);
Logger::smf_app().info( " Scheduling policy : %d", itti.sx_sched_params.sched_policy);
Logger::smf_app().info( " Scheduling prio .: %d", itti.sx_sched_params.sched_priority);
Logger::smf_app().info( "- ITTI N4 Task Threading:");
Logger::smf_app().info( " CPU id............: %d", itti.n4_sched_params.cpu_id);
Logger::smf_app().info( " Scheduling policy : %d", itti.n4_sched_params.sched_policy);
Logger::smf_app().info( " Scheduling prio .: %d", itti.n4_sched_params.sched_priority);
Logger::smf_app().info( "- ITTI SMF_APP task Threading:");
Logger::smf_app().info( " CPU id............: %d", itti.smf_app_sched_params.cpu_id);
Logger::smf_app().info( " Scheduling policy : %d", itti.smf_app_sched_params.sched_policy);
......@@ -645,8 +643,8 @@ bool smf_config::is_dotted_dnn_handled(const std::string& dnn, const pdu_session
Logger::smf_app().debug( "apn_label: %s, apn: %s", smf_cfg.apn[i].apn_label.c_str(),smf_cfg.apn[i].apn.c_str() );
//if (0 == dnn.compare(smf_cfg.apn[i].apn_label)) {
if (0 == dnn.compare(smf_cfg.apn[i].apn)) {
Logger::smf_app().debug( "DNN matched! \n");
Logger::smf_app().debug( "pdu session type %d, pdn_type %d \n", pdn_session_type.pdu_session_type, smf_cfg.apn[i].pdn_type.pdn_type);
Logger::smf_app().debug( "DNN matched!");
Logger::smf_app().debug( "pdu session type %d, pdn_type %d", pdn_session_type.pdu_session_type, smf_cfg.apn[i].pdn_type.pdn_type);
if (pdn_session_type.pdu_session_type == smf_cfg.apn[i].pdn_type.pdn_type) {
return true;
}
......
......@@ -54,7 +54,6 @@
#define SMF_CONFIG_STRING_INTERFACE_NAME "INTERFACE_NAME"
#define SMF_CONFIG_STRING_IPV4_ADDRESS "IPV4_ADDRESS"
#define SMF_CONFIG_STRING_PORT "PORT"
#define SMF_CONFIG_STRING_INTERFACE_SX "SX"
#define SMF_CONFIG_STRING_INTERFACE_N4 "N4"
#define SMF_CONFIG_STRING_INTERFACE_N11 "N11"
......@@ -120,8 +119,7 @@
#define SMF_CONFIG_STRING_ITTI_TASKS "ITTI_TASKS"
#define SMF_CONFIG_STRING_ITTI_TIMER_SCHED_PARAMS "ITTI_TIMER_SCHED_PARAMS"
#define SMF_CONFIG_STRING_S11_SCHED_PARAMS "S11_SCHED_PARAMS"
#define SMF_CONFIG_STRING_S5S8_SCHED_PARAMS "S5S8_SCHED_PARAMS"
#define SMF_CONFIG_STRING_SX_SCHED_PARAMS "SX_SCHED_PARAMS"
#define SMF_CONFIG_STRING_N4_SCHED_PARAMS "N4_SCHED_PARAMS"
#define SMF_CONFIG_STRING_SMF_APP_SCHED_PARAMS "SMF_APP_SCHED_PARAMS"
#define SMF_CONFIG_STRING_ASYNC_CMD_SCHED_PARAMS "ASYNC_CMD_SCHED_PARAMS"
......@@ -133,6 +131,9 @@
#define SMF_CONFIG_STRING_UDM_IPV4_ADDRESS "IPV4_ADDRESS"
#define SMF_CONFIG_STRING_UDM_PORT "PORT"
#define SMF_CONFIG_STRING_UPF_LIST "UPF_LIST"
#define SMF_CONFIG_STRING_UPF_IPV4_ADDRESS "IPV4_ADDRESS"
#define PGW_MAX_ALLOCATED_PDN_ADDRESSES 1024
namespace smf {
......@@ -149,8 +150,7 @@ typedef struct interface_cfg_s {
typedef struct itti_cfg_s {
util::thread_sched_params itti_timer_sched_params;
util::thread_sched_params sx_sched_params;
util::thread_sched_params s5s8_sched_params;
util::thread_sched_params n4_sched_params;
util::thread_sched_params smf_app_sched_params;
util::thread_sched_params async_cmd_sched_params;
} itti_cfg_t;
......@@ -167,7 +167,6 @@ public:
std::string pid_dir;
unsigned int instance = 0;
interface_cfg_t sx;
interface_cfg_t n4;
interface_cfg_t n11;
itti_cfg_t itti;
......@@ -223,7 +222,9 @@ public:
unsigned int port;
} udm_addr;
smf_config() : m_rw_lock(), pcef(), num_apn(0), pid_dir(), instance(0), sx(), n4(), n11(), itti() {
std::vector<pfcp::node_id_t> upfs;
smf_config() : m_rw_lock(), pcef(), num_apn(0), pid_dir(), instance(0), n4(), n11(), itti(), upfs() {
for (int i = 0; i < PGW_NUM_APN_MAX; i++) {
apn[i] = {};
}
......@@ -247,14 +248,10 @@ public:
ue_mtu = 1500;
itti.itti_timer_sched_params.sched_priority = 85;
itti.sx_sched_params.sched_priority = 84;
itti.s5s8_sched_params.sched_priority = 84;
itti.n4_sched_params.sched_priority = 84;
itti.smf_app_sched_params.sched_priority = 84;
itti.async_cmd_sched_params.sched_priority = 84;
sx.thread_rd_sched_params.sched_priority = 90;
sx.port = pfcp::default_port;
n4.thread_rd_sched_params.sched_priority = 90;
n4.port = pfcp::default_port;
......
......@@ -30,6 +30,7 @@
#include "itti.hpp"
#include "logger.hpp"
#include "smf_app.hpp"
#include "smf_n11.hpp"
#include "smf_config.hpp"
#include "smf_context.hpp"
#include "smf_paa_dynamic.hpp"
......@@ -40,13 +41,20 @@
#include "SmContextCreatedData.h"
#include <algorithm>
#include "smf_n1_n2.hpp"
extern "C"{
#include "Ngap_PDUSessionResourceSetupResponseTransfer.h"
#include "Ngap_PDUSessionResourceModifyResponseTransfer.h"
#include "Ngap_GTPTunnel.h"
#include "Ngap_AssociatedQosFlowItem.h"
#include "Ngap_QosFlowAddOrModifyResponseList.h"
#include "Ngap_QosFlowAddOrModifyResponseItem.h"
}
using namespace smf;
extern itti_mw *itti_inst;
extern smf::smf_app *smf_app_inst;
extern smf::smf_n11 *smf_n11_inst;
extern smf::smf_config smf_cfg;
//------------------------------------------------------------------------------
......@@ -91,6 +99,47 @@ void smf_pdu_session::add_qos_flow(smf_qos_flow& flow)
}
}
//------------------------------------------------------------------------------
bool smf_pdu_session::get_qos_flow(const pfcp::pdr_id_t& pdr_id, smf_qos_flow& q) {
for (auto it : qos_flows) {
if (it.second.pdr_id_ul.rule_id == pdr_id.rule_id) {
q = it.second;
return true;
}
if (it.second.pdr_id_dl.rule_id == pdr_id.rule_id) {
q = it.second;
return true;
}
}
return false;
}
//------------------------------------------------------------------------------
bool smf_pdu_session::get_qos_flow(const pfcp::far_id_t& far_id, smf_qos_flow& q) {
for (auto it : qos_flows) {
if ((it.second.far_id_ul.first) && (it.second.far_id_ul.second.far_id == far_id.far_id)) {
q = it.second;
return true;
}
if ((it.second.far_id_dl.first) && (it.second.far_id_dl.second.far_id == far_id.far_id)) {
q = it.second;
return true;
}
}
return false;
}
//------------------------------------------------------------------------------
bool smf_pdu_session::get_qos_flow(const pfcp::qfi_t& qfi, smf_qos_flow& q) {
for (auto it : qos_flows) {
if (it.second.qfi == qfi) {
q = it.second;
return true;
}
}
return false;
}
//------------------------------------------------------------------------------
smf_qos_flow& smf_pdu_session::get_qos_flow(const pfcp::qfi_t& qfi)
......@@ -135,8 +184,6 @@ void smf_pdu_session::remove_qos_flow(smf_qos_flow& flow)
qos_flows.erase(qfi.qfi);
}
//------------------------------------------------------------------------------
void smf_pdu_session::deallocate_ressources(const std::string& apn)
{
......@@ -203,6 +250,29 @@ std::string smf_pdu_session::toString() const
return s;
}
//------------------------------------------------------------------------------
void smf_pdu_session::set_pdu_session_status (const pdu_session_status_e& status)
{
pdu_session_status = status;
}
//------------------------------------------------------------------------------
pdu_session_status_e smf_pdu_session::get_pdu_session_status () const
{
return pdu_session_status;
}
//------------------------------------------------------------------------------
void smf_pdu_session::set_upCnx_state (const upCnx_state_e& state)
{
upCnx_state = state;
}
//------------------------------------------------------------------------------
upCnx_state_e smf_pdu_session::get_upCnx_state () const
{
return upCnx_state;
}
//------------------------------------------------------------------------------
void smf_context::insert_procedure(std::shared_ptr<smf_procedure>& sproc)
{
......@@ -239,7 +309,7 @@ void smf_context::handle_itti_msg (itti_n4_session_establishment_response& seres
{
std::shared_ptr<smf_procedure> proc = {};
if (find_procedure(seresp.trxn_id, proc)) {
Logger::smf_app().debug("Received N4 SESSION ESTABLISHMENT RESPONSE sender teid " TEID_FMT " pfcp_tx_id %" PRIX64"\n", seresp.seid, seresp.trxn_id);
Logger::smf_app().debug("Received N4 SESSION ESTABLISHMENT RESPONSE sender teid " TEID_FMT " pfcp_tx_id %" PRIX64"", seresp.seid, seresp.trxn_id);
proc->handle_itti_msg(seresp, shared_from_this());
remove_procedure(proc.get());
} else {
......@@ -251,20 +321,20 @@ void smf_context::handle_itti_msg (itti_n4_session_modification_response& smresp
{
std::shared_ptr<smf_procedure> proc = {};
if (find_procedure(smresp.trxn_id, proc)) {
Logger::smf_app().debug("Received N4 SESSION MODIFICATION RESPONSE sender teid " TEID_FMT " pfcp_tx_id %" PRIX64"\n", smresp.seid, smresp.trxn_id);
Logger::smf_app().debug("Received N4 SESSION MODIFICATION RESPONSE sender teid " TEID_FMT " pfcp_tx_id %" PRIX64" ", smresp.seid, smresp.trxn_id);
proc->handle_itti_msg(smresp, shared_from_this());
remove_procedure(proc.get());
} else {
Logger::smf_app().debug("Received N4 SESSION MODIFICATION RESPONSE sender teid " TEID_FMT " pfcp_tx_id %" PRIX64", smf_procedure not found, discarded!", smresp.seid, smresp.trxn_id);
}
std::cout << toString() << std::endl;
Logger::smf_app().info("Handle N4 SESSION MODIFICATION RESPONSE with SMF context %s", toString().c_str());
}
//------------------------------------------------------------------------------
void smf_context::handle_itti_msg (itti_n4_session_deletion_response& sdresp)
{
std::shared_ptr<smf_procedure> proc = {};
if (find_procedure(sdresp.trxn_id, proc)) {
Logger::smf_app().debug("Received N4 SESSION DELETION RESPONSE sender teid " TEID_FMT " pfcp_tx_id %" PRIX64"\n", sdresp.seid, sdresp.trxn_id);
Logger::smf_app().debug("Received N4 SESSION DELETION RESPONSE sender teid " TEID_FMT " pfcp_tx_id %" PRIX64" ", sdresp.seid, sdresp.trxn_id);
proc->handle_itti_msg(sdresp, shared_from_this());
remove_procedure(proc.get());
} else {
......@@ -288,6 +358,7 @@ std::string smf_context::toString() const
for (auto it : dnns) {
s.append(it->toString());
}
s.append("\tSUPI:\t\t\t\t").append(smf_supi_to_string(supi)).append("\n");
//s.append("\tIMSI:\t"+toString(p.msisdn));
//apns.reserve(MAX_APN_PER_UE);
......@@ -314,14 +385,15 @@ void smf_context::get_default_qos(const snssai_t& snssai, const std::string& dnn
}
//------------------------------------------------------------------------------
void smf_context::handle_amf_msg (std::shared_ptr<itti_n11_create_sm_context_request> smreq)
void smf_context::handle_pdu_session_create_sm_context_request (std::shared_ptr<itti_n11_create_sm_context_request> smreq)
{
Logger::smf_app().info("Handle a PDU Session Create SM Context Request message from AMF");
pdu_session_create_sm_context_request sm_context_req_msg = smreq->req;
oai::smf_server::model::SmContextCreateError smContextCreateError;
oai::smf_server::model::ProblemDetails problem_details;
std::string n1_sm_message; //N1 SM container
std::string n1_sm_msg_hex;
smf_n1_n2 smf_n1_n2_inst;
bool request_accepted = true;
//Step 1. get necessary information
......@@ -336,12 +408,16 @@ void smf_context::handle_amf_msg (std::shared_ptr<itti_n11_create_sm_context_req
if (!verify_sm_context_request(smreq)){ //TODO: Need to implement this function
// Not a valid request...
Logger::smf_app().warn("Received PDU_SESSION_CREATESMCONTEXT_REQUEST, the request is not valid!");
problem_details.setCause(pdu_session_application_error_e2str[PDU_SESSION_APPLICATION_ERROR_SUBSCRIPTION_DENIED]); //TODO: add causes to header file
problem_details.setCause(pdu_session_application_error_e2str[PDU_SESSION_APPLICATION_ERROR_SUBSCRIPTION_DENIED]);
smContextCreateError.setError(problem_details);
//TODO: to be completed when finishing NAS implementation
//TODO: create a PDU Session Establishment Response by relying on NAS and assign to smContextCeateError.m_N1SmMsg
send_create_session_response_error(smContextCreateError, Pistache::Http::Code::Forbidden, smreq->http_response);
//PDU Session Establishment Reject
//TODO: check cause
smf_n1_n2_inst.create_n1_sm_container(sm_context_req_msg, PDU_SESSION_ESTABLISHMENT_REJECT, n1_sm_message, cause_value_5gsm_e::CAUSE_82_MAXIMUM_DATA_RATE_PER_UE_FOR_USER_PLANE_INTEGRITY_PROTECTION_IS_TOO_LOW);
smf_n11_inst->send_pdu_session_create_sm_context_response(smreq->http_response, smContextCreateError, Pistache::Http::Code::Forbidden, n1_sm_message);
//TODO:
//SMF unsubscribes to the modifications of Session Management Subscription data for (SUPI, DNN, S-NSSAI)
//using Nudm_SDM_Unsubscribe()
return;
}
......@@ -354,7 +430,7 @@ void smf_context::handle_amf_msg (std::shared_ptr<itti_n11_create_sm_context_req
sm_context_resp->res.set_pdu_session_id(pdu_session_id);
sm_context_resp->res.set_snssai(snssai);
sm_context_resp->res.set_dnn(dnn);
sm_context_resp->set_scid(smreq->scid);
//Step 3. find pdu_session
std::shared_ptr<dnn_context> sd;
......@@ -422,7 +498,7 @@ void smf_context::handle_amf_msg (std::shared_ptr<itti_n11_create_sm_context_req
//Step 7. address allocation based on PDN type
switch (sp->pdn_type.pdn_type) {
case PDN_TYPE_E_IPV4: {
if (!pco_ids.ci_ipv4_address_allocation_via_dhcpv4) { //use NAS signalling
if (!pco_ids.ci_ipv4_address_allocation_via_dhcpv4) { //use SM NAS signalling
//use NAS signalling
//static or dynamic address allocation
bool paa_res = false; //how to define static or dynamic
......@@ -471,11 +547,11 @@ void smf_context::handle_amf_msg (std::shared_ptr<itti_n11_create_sm_context_req
default:
Logger::smf_app().error( "Unknown PDN type %d", sp->pdn_type.pdn_type);
problem_details.setCause(pdu_session_application_error_e2str[PDU_SESSION_APPLICATION_ERROR_PDUTYPE_NOT_SUPPORTED]);
problem_details.setCause(pdu_session_application_error_e2str[PDU_SESSION_APPLICATION_ERROR_PDUTYPE_DENIED]);
smContextCreateError.setError(problem_details);
//TODO: to be completed when finishing NAS implementation
//TODO: create a PDU Session Establishment Response by relying on NAS and assign to smContextCeateError.m_N1SmMsg
send_create_session_response_error(smContextCreateError, Pistache::Http::Code::Forbidden, sm_context_resp->http_response);
//PDU Session Establishment Reject
smf_n1_n2_inst.create_n1_sm_container(sm_context_req_msg, PDU_SESSION_ESTABLISHMENT_REJECT, n1_sm_message, cause_value_5gsm_e::CAUSE_28_UNKNOWN_PDU_SESSION_TYPE);
smf_n11_inst->send_pdu_session_create_sm_context_response(sm_context_resp->http_response, smContextCreateError, Pistache::Http::Code::Forbidden, n1_sm_message);
request_accepted = false;
break;
}
......@@ -499,21 +575,18 @@ void smf_context::handle_amf_msg (std::shared_ptr<itti_n11_create_sm_context_req
//(step 5 (4.3.2.2.1 TS 23.502)) Send reply to AMF (PDUSession_CreateSMContextResponse including Cause, SMContextId)
//location header contains the URI of the created resource
Logger::smf_app().info("Sending response to AMF!");
nlohmann::json jsonData;
oai::smf_server::model::SmContextCreatedData smContextCreatedData;
//include only SmfServiceInstanceId (See section 6.1.6.2.3, 3GPP TS 29.502 v16.0.0)
to_json(jsonData, smContextCreatedData);
std::string resBody = jsonData.dump();
//Enable to test with tester
// std::string smContextRef = sm_context_req_msg.get_supi_prefix() + "-" + smf_supi_to_string(sm_context_req_msg.get_supi());
// std::string smContextRef = sm_context_req_msg.get_supi_prefix() + "-" + smf_supi_to_string(sm_context_req_msg.get_supi());
std::string smContextRef = std::to_string(smreq->scid);
//headers: Location:
//Contains the URI of the newly created resource, according to the structure: {apiRoot}/nsmf-pdusession/{apiVersion}/sm-contexts/{smContextRef}
//headers: Location: contains the URI of the newly created resource, according to the structure: {apiRoot}/nsmf-pdusession/{apiVersion}/sm-contexts/{smContextRef}
std::string uri = sm_context_req_msg.get_api_root() + "/" + smContextRef.c_str();
sm_context_resp->http_response.headers().add<Pistache::Http::Header::Location>(uri);
sm_context_resp->http_response.send(Pistache::Http::Code::Created, resBody);
smf_n11_inst->send_pdu_session_create_sm_context_response(sm_context_resp->http_response, smContextCreatedData, Pistache::Http::Code::Created);
//TODO: PDU Session authentication/authorization (Optional)
//see section 4.3.2.3@3GPP TS 23.502 and section 6.3.1@3GPP TS 24.501
Logger::smf_app().info( "Create a procedure to process this message!");
session_create_sm_context_procedure* proc = new session_create_sm_context_procedure(sp);
......@@ -524,8 +597,8 @@ void smf_context::handle_amf_msg (std::shared_ptr<itti_n11_create_sm_context_req
// error !
Logger::smf_app().info( "PDU SESSION CREATE SM CONTEXT REQUEST procedure failed");
remove_procedure(proc);
//TODO: Send N1N2MessageTransfer including PDU Session Establishment Reject to AMF
//Set cause to error to trigger PDU session establishment reject (step 9)
sm_context_resp->res.set_cause(UNKNOWN_ERROR);
}
}else{ //if request is rejected
......@@ -533,7 +606,8 @@ void smf_context::handle_amf_msg (std::shared_ptr<itti_n11_create_sm_context_req
//un-subscribe to the modifications of Session Management Subscription data for (SUPI, DNN, S-NSSAI)
}
//step 9. if error when establishing the pdu session, send ITTI message to APP to trigger N1N2MessageTransfer towards AMFs
//step 9. if error when establishing the pdu session,
//send ITTI message to APP to trigger N1N2MessageTransfer towards AMFs (PDU Session Establishment Reject)
if (sm_context_resp->res.get_cause() != REQUEST_ACCEPTED) {
//clear pco, ambr
//TODO:
......@@ -565,78 +639,368 @@ void smf_context::handle_amf_msg (std::shared_ptr<itti_n11_create_sm_context_req
//sm_context_resp->res.add_bearer_context_created(bcc);
}
*/
//Create PDU Session Establishment Reject
smf_n1_n2 smf_n1_n2_inst;
std::string n1_sm_msg,n1_sm_msg_hex;
Logger::smf_app().debug("Create PDU Session Establishment Reject");
smf_n1_n2_inst.create_n1_sm_container(sm_context_resp_pending->res, PDU_SESSION_ESTABLISHMENT_REJECT, n1_sm_msg, cause_value_5gsm_e::CAUSE_26_INSUFFICIENT_RESOURCES);
sm_context_resp_pending->res.set_n1_sm_message(n1_sm_message);
//get supi and put into URL
std::string supi_str;
supi_t supi = sm_context_resp_pending->res.get_supi();
supi_str = sm_context_resp_pending->res.get_supi_prefix() + "-" + smf_supi_to_string (supi);
std::string url = std::string(inet_ntoa (*((struct in_addr *)&smf_cfg.amf_addr.ipv4_addr))) + ":" + std::to_string(smf_cfg.amf_addr.port) + "/namf-comm/v2/ue-contexts/" + supi_str.c_str() +"/n1-n2-messages";
sm_context_resp_pending->res.set_amf_url(url);
//Fill the json part
sm_context_resp_pending->res.n1n2_message_transfer_data["n1MessageContainer"]["n1MessageClass"] = "SM";
sm_context_resp_pending->res.n1n2_message_transfer_data["n1MessageContainer"]["n1MessageContent"]["contentId"] = "n1SmMsg";
//sm_context_resp_pending->res.n1n2_message_transfer_data["ppi"] = 1; //Don't need this info for the moment
sm_context_resp_pending->res.n1n2_message_transfer_data["pduSessionId"] = sm_context_resp_pending->res.get_pdu_session_id();
//sm_context_resp_pending->res.n1n2_message_transfer_data["arp"]["priorityLevel"] = 1;
//sm_context_resp_pending->res.n1n2_message_transfer_data["arp"]["preemptCap"] = "NOT_PREEMPT";
//sm_context_resp_pending->res.n1n2_message_transfer_data["arp"]["preemptVuln"] = "NOT_PREEMPTABLE";
//sm_context_resp_pending->res.n1n2_message_transfer_data["5qi"] = ;
//send ITTI message to N11 interface to trigger N1N2MessageTransfer towards AMFs
//with N1SM container with a PDU Session Establishment Reject message
//TODO
//sm_context_resp_pending->res.set
Logger::smf_app().info( "Sending ITTI message %s to task TASK_SMF_N11", sm_context_resp_pending->get_msg_name());
int ret = itti_inst->send_msg(sm_context_resp_pending);
if (RETURNok != ret) {
Logger::smf_app().error( "Could not send ITTI message %s to task TASK_SMF_N11", sm_context_resp_pending->get_msg_name());
}
}
}
//-------------------------------------------------------------------------------------
void smf_context::handle_amf_msg (std::shared_ptr<itti_n11_update_sm_context_request> smreq)
void smf_context::handle_pdu_session_update_sm_context_request (std::shared_ptr<itti_n11_update_sm_context_request> smreq)
{
Logger::smf_app().info("Handle a PDU Session Update SM Context Request message from AMF");
pdu_session_update_sm_context_request sm_context_req_msg = smreq->req;
smf_n1_n2 smf_n1_n2_inst;
oai::smf_server::model::SmContextCreateError smContextCreateError;
oai::smf_server::model::ProblemDetails problem_details;
oai::smf_server::model::RefToBinaryData binary_data;
bool update_upf = false;
session_management_procedures_type_e procedure_type (session_management_procedures_type_e::PDU_SESSION_ESTABLISHMENT_UE_REQUESTED);
//Step 1. get DNN, SMF PDU session context. At this stage, dnn_context and pdu_session must be existed
std::shared_ptr<dnn_context> sd;
std::shared_ptr<smf_pdu_session> sp;
bool find_dnn = find_dnn_context (sm_context_req_msg.get_snssai(), sm_context_req_msg.get_dnn(), sd);
bool find_pdn = sd.get()->find_pdu_session(sm_context_req_msg.get_pdu_session_id(), sp);
//Step 1. get necessary information (N2 SM information)
std::string n2_sm_info_type = smreq->req.get_n2_sm_info_type();
std::string n2_sm_infomation = smreq->req.get_n2_sm_information();
//decode Ngap_PDUSessionResourceSetupResponseTransfer
if (n2_sm_info_type.compare(n2_sm_info_type_e2str[PDU_RES_SETUP_RSP]) == 0){
std::unique_ptr<Ngap_PDUSessionResourceSetupResponseTransfer_t> decoded_msg = std::unique_ptr<Ngap_PDUSessionResourceSetupResponseTransfer_t>();
//Decode N2 SM info into decoded nas msg
asn_dec_rval_t rc = asn_decode(NULL,ATS_ALIGNED_CANONICAL_PER, &asn_DEF_Ngap_PDUSessionResourceSetupResponseTransfer, (void **)&decoded_msg, (void *)n2_sm_infomation.c_str(), n2_sm_infomation.length());
if(rc.code != RC_OK)
{
Logger::smf_api_server().warn("asn_decode failed %d...\n",rc.code );
//TODO: send error to AMF??
//we need to store HttpResponse and session-related information to be used when receiving the response from UPF
itti_n11_update_sm_context_response *sm_context_resp = new itti_n11_update_sm_context_response(TASK_SMF_APP, TASK_SMF_N11, smreq->http_response);
std::shared_ptr<itti_n11_update_sm_context_response> sm_context_resp_pending = std::shared_ptr<itti_n11_update_sm_context_response>(sm_context_resp);
sm_context_resp->res.set_supi(sm_context_req_msg.get_supi());
sm_context_resp->res.set_supi_prefix(sm_context_req_msg.get_supi_prefix());
sm_context_resp->res.set_cause(REQUEST_ACCEPTED);
sm_context_resp->res.set_pdu_session_id(sm_context_req_msg.get_pdu_session_id());
sm_context_resp->res.set_snssai(sm_context_req_msg.get_snssai());
sm_context_resp->res.set_dnn(sm_context_req_msg.get_dnn());
//Step 2.1. Decode N1 (if content is available)
if (sm_context_req_msg.n1_sm_msg_is_set()){
std::string n1_sm_msg; //N1 SM container
std::string n1_sm_msg_hex; //N1 SM container
nas_message_t decoded_nas_msg;
//Decode NAS and get the necessary information
n1_sm_msg = sm_context_req_msg.get_n1_sm_message();
memset (&decoded_nas_msg, 0, sizeof (nas_message_t));
int decoder_rc = smf_n1_n2_inst.decode_n1_sm_container(decoded_nas_msg, n1_sm_msg);
if (decoder_rc != RETURNok) {
//error, should send reply to AMF with error code!!
Logger::smf_app().warn("N1 SM container cannot be decoded correctly!");
problem_details.setCause(pdu_session_application_error_e2str[PDU_SESSION_APPLICATION_ERROR_N1_SM_ERROR]);
smContextCreateError.setError(problem_details);
//PDU Session Establishment Reject
//24.501: response with a 5GSM STATUS message including cause "#95 Semantically incorrect message"
smf_n1_n2_inst.create_n1_sm_container(sm_context_req_msg, PDU_SESSION_ESTABLISHMENT_REJECT, n1_sm_msg, cause_value_5gsm_e::CAUSE_95_SEMANTICALLY_INCORRECT_MESSAGE); //TODO: should define 5GSM cause in 24.501
//Send response to AMF
smf_n11_inst->send_pdu_session_create_sm_context_response(smreq->http_response, smContextCreateError, Pistache::Http::Code::Forbidden, n1_sm_msg);
}
Logger::smf_app().debug("NAS header information: extended_protocol_discriminator %d, security_header_type:%d,sequence_number:%d,message_authentication_code:%d",
decoded_nas_msg.header.extended_protocol_discriminator,
decoded_nas_msg.header.security_header_type,
decoded_nas_msg.header.sequence_number,
decoded_nas_msg.header.message_authentication_code);
Logger::smf_app().debug("NAS header information, Message Type %d", decoded_nas_msg.plain.sm.header.message_type);
switch (decoded_nas_msg.plain.sm.header.message_type){
case PDU_SESSION_MODIFICATION_REQUEST:{
//PDU Session Modification procedure (UE-initiated, step 1.a, Section 4.3.3.2@3GPP TS 23.502)
procedure_type = session_management_procedures_type_e::PDU_SESSION_MODIFICATION_UE_INITIATED;
//step 1. assign the necessary information from pdu_session_modification_request to sm_context_req_msg to be used to create N1 SM, N2 SM information
//decoded_nas_msg.plain.sm.pdu_session_modification_request;
//need the following IEs
// PTI,
/* ExtendedProtocolDiscriminator extendedprotocoldiscriminator;
PDUSessionIdentity pdusessionidentity;
ProcedureTransactionIdentity proceduretransactionidentity;
MessageType messagetype;
uint16_t presence;
_5GSMCapability _5gsmcapability;
_5GSMCause _5gsmcause;
MaximumNumberOfSupportedPacketFilters maximumnumberofsupportedpacketfilters;
AlwaysonPDUSessionRequested alwaysonpdusessionrequested;
IntergrityProtectionMaximumDataRate intergrityprotectionmaximumdatarate;
QOSRules qosrules;
QOSFlowDescriptions qosflowdescriptions;
MappedEPSBearerContexts mappedepsbearercontexts;
ExtendedProtocolConfigurationOptions extendedprotocolconfigurationoptions;
*/
//pdu_session_update_sm_context_request sm_context_req_msg;
//section 6.3.2. Network-requested PDU Session modification procedure @ 3GPP TS 24.501
//requested QoS rules (including packet filters) and/or requested QoS flow descriptions
//session-AMBR, session TMBR
// PTI
//or UE capability
//Create a N1 SM (PDU Session Modification Command) and N2 SM (PDU Session Resource Setup Request Transfer IE)
std::string n1_sm_message;
std::string n2_sm_info ;
smf_n1_n2 smf_n1_n2_inst;
//N1 SM (PDU Session Modification Command)
smf_n1_n2_inst.create_n1_sm_container(sm_context_req_msg, PDU_SESSION_MODIFICATION_COMMAND, n1_sm_message, cause_value_5gsm_e::CAUSE_0_UNKNOWN); //TODO: need cause?
//N2 SM (PDU Session Resource Modify Request Transfer IE)
smf_n1_n2_inst.create_n2_sm_information(sm_context_req_msg, 1, n2_sm_info_type_e::PDU_RES_MOD_REQ, n2_sm_info);
sm_context_resp_pending->res.set_n1_sm_message(n1_sm_message);
sm_context_resp_pending->res.set_n1_sm_msg_type("PDU_SESSION_MODIFICATION_COMMAND");
sm_context_resp_pending->res.set_n2_sm_information(n2_sm_info);
sm_context_resp_pending->res.set_n2_sm_info_type("PDU_RES_MOD_REQ");
//Store pdu_session_modification_request in itti_n11_update_sm_context_response
Logger::smf_app().info( "Sending ITTI message %s to task TASK_SMF_N11", sm_context_resp_pending->get_msg_name());
//Update PDU Session status
sp.get()->set_pdu_session_status(pdu_session_status_e::PDU_SESSION_MODIFICATION_PENDING);
//start timer T3591
//get smf_pdu_session and set the corresponding timer
sp.get()->timer_T3591 = itti_inst->timer_setup(T3591_TIMER_VALUE_SEC, 0, TASK_SMF_APP, TASK_SMF_APP_TRIGGER_T3591, sm_context_req_msg.get_pdu_session_id());
int ret = itti_inst->send_msg(sm_context_resp_pending);
if (RETURNok != ret) {
Logger::smf_app().error( "Could not send ITTI message %s to task TASK_SMF_N11", sm_context_resp_pending->get_msg_name());
}
//don't need to create a procedure to update UPF
break;
}
case PDU_SESSION_MODIFICATION_COMPLETE:{
//PDU Session Modification procedure (Section 4.3.3.2@3GPP TS 23.502)
//TODO: should be verified since mentioned PDU_SESSION_MODIFICATION_COMMAND ACK in spec (see Step 11, section 4.3.3.2@3GPP TS 23.502)
//send response
/* see section 6.3.2.3@3GPP TS 24.501 V16.1.0
Upon receipt of a PDU SESSION MODIFICATION COMPLETE message, the SMF shall stop timer T3591 and shall
consider the PDU session as modified. If the selected SSC mode of the PDU session is "SSC mode 3" and the PDU
SESSION MODIFICATION COMMAND message included 5GSM cause #39 "reactivation requested", the SMF shall
start timer T3593. If the PDU Session Address Lifetime value is sent to the UE in the PDU SESSION
MODIFICATION COMMAND message then timer T3593 shall be started with the same value, otherwise it shall use a
default value.
*/
//Update PDU Session status -> ACTIVE
sp.get()->set_pdu_session_status(pdu_session_status_e::PDU_SESSION_ACTIVE);
//stop T3591
itti_inst->timer_remove(sp.get()->timer_T3591);
break;
}
case PDU_SESSION_RELEASE_REQUEST:{
//PDU Session Release procedure (Section 4.3.4@3GPP TS 23.502)
//TODO:
break;
}
case PDU_SESSION_RELEASE_COMMAND:{
//PDU Session Release procedure (Section 4.3.4@3GPP TS 23.502)
//TODO:
break;
}
default: {
//Message Type Unknown
}
}
// Ngap_QosFlowPerTNLInformation_t qosFlowPerTNLInformation;
// struct Ngap_QosFlowPerTNLInformation *additionalQosFlowPerTNLInformation; /* OPTIONAL */
// struct Ngap_SecurityResult *securityResult; /* OPTIONAL */
// struct Ngap_QosFlowList *qosFlowFailedToSetupList; /* OPTIONAL */
// struct Ngap_ProtocolExtensionContainer *iE_Extensions; /* OPTIONAL */
}
//TODO:
//get dnn context
//get SMF PDU Session context
std::shared_ptr<smf_pdu_session> sp;
//TODO:
//Step 2.2. Decode N2 (if content is available)
if (sm_context_req_msg.n2_sm_info_is_set()){
//get necessary information (N2 SM information)
std::string n2_sm_info_type_str = smreq->req.get_n2_sm_info_type();
std::string n2_sm_information = smreq->req.get_n2_sm_information();
n2_sm_info_type_e n2_sm_info_type = smf_app_inst->n2_sm_info_type_str2e(n2_sm_info_type_str);
unsigned int data_len = n2_sm_information.length();
unsigned char *data = (unsigned char *)malloc(data_len + 1);
memset(data, 0, data_len + 1);
memcpy ((void *)data, (void *)n2_sm_information.c_str(), data_len);
//decode N2 SM Info
switch (n2_sm_info_type){
//UE-Requested PDU Session Establishment procedure (Section 4.3.2.2.1@3GPP TS 23.502)
case n2_sm_info_type_e::PDU_RES_SETUP_RSP:{
Logger::smf_app().info("PDU Session Establishment Request, processing N2 SM Information");
//Ngap_PDUSessionResourceSetupResponseTransfer_t
// Ngap_QosFlowPerTNLInformation_t qosFlowPerTNLInformation;
// struct Ngap_QosFlowPerTNLInformation *additionalQosFlowPerTNLInformation; /* OPTIONAL */
// struct Ngap_SecurityResult *securityResult; /* OPTIONAL */
// struct Ngap_QosFlowList *qosFlowFailedToSetupList; /* OPTIONAL */
// struct Ngap_ProtocolExtensionContainer *iE_Extensions; /* OPTIONAL */
//TEST - enable to create a N2 SM information and send to AMF
/* std::string n2_sm_info, n2_sm_info_hex ;
smf_n1_n2 smf_n1_n2_inst;
//N1 SM (PDU Session Modification Command)
smf_n1_n2_inst.create_n2_sm_information(sm_context_req_msg, 1, n2_sm_info_type_e::PDU_RES_SETUP_RSP, n2_sm_info);
*/
procedure_type = session_management_procedures_type_e::PDU_SESSION_ESTABLISHMENT_UE_REQUESTED;
//Ngap_PDUSessionResourceSetupResponseTransfer
std::shared_ptr<Ngap_PDUSessionResourceSetupResponseTransfer_t> decoded_msg = std::make_shared<Ngap_PDUSessionResourceSetupResponseTransfer_t>();
asn_dec_rval_t rc = asn_decode(nullptr,ATS_ALIGNED_CANONICAL_PER, &asn_DEF_Ngap_PDUSessionResourceSetupResponseTransfer, (void **)&decoded_msg, (void *)data, data_len);
if(rc.code != RC_OK)
{
Logger::smf_api_server().warn("asn_decode failed with code %d",rc.code );
//TODO: send error to AMF??
}
//we need to store HttpResponse and session-related information to be used when receiving the response from UPF
itti_n11_update_sm_context_response *sm_context_resp = new itti_n11_update_sm_context_response(TASK_SMF_APP, TASK_SMF_N11, smreq->http_response);
std::shared_ptr<itti_n11_update_sm_context_response> sm_context_resp_pending = std::shared_ptr<itti_n11_update_sm_context_response>(sm_context_resp);
//TODO: store AN Tunnel Info + list of accepted QFIs
fteid_t dl_teid;
//TODO: to be verified which one is teid_gre_key, ipv4_address
memcpy (&dl_teid.teid_gre_key, decoded_msg->qosFlowPerTNLInformation.uPTransportLayerInformation.choice.gTPTunnel->gTP_TEID.buf, sizeof (struct in_addr));
memcpy (&dl_teid.ipv4_address, decoded_msg->qosFlowPerTNLInformation.uPTransportLayerInformation.choice.gTPTunnel->transportLayerAddress.buf, 4);
printf("\ngTP_TEID:");
printf("%02x ", decoded_msg->qosFlowPerTNLInformation.uPTransportLayerInformation.choice.gTPTunnel->gTP_TEID.buf[0]);
printf("%02x ", decoded_msg->qosFlowPerTNLInformation.uPTransportLayerInformation.choice.gTPTunnel->gTP_TEID.buf[1]);
printf("%02x ", decoded_msg->qosFlowPerTNLInformation.uPTransportLayerInformation.choice.gTPTunnel->gTP_TEID.buf[2]);
printf("%02x ", decoded_msg->qosFlowPerTNLInformation.uPTransportLayerInformation.choice.gTPTunnel->gTP_TEID.buf[3]);
Logger::smf_app().debug("gTP_TEID " "0x%" PRIx32 " ", htonl(dl_teid.teid_gre_key));
Logger::smf_app().debug("uPTransportLayerInformation IP Addr %s", conv::toString(dl_teid.ipv4_address).c_str());
sm_context_req_msg.set_dl_fteid(dl_teid);
for (int i =0; i< decoded_msg->qosFlowPerTNLInformation.associatedQosFlowList.list.count; i++ ){
pfcp::qfi_t qfi((uint8_t)(decoded_msg->qosFlowPerTNLInformation.associatedQosFlowList.list.array[i])->qosFlowIdentifier);
sm_context_req_msg.add_qfi(qfi);
Logger::smf_app().debug("associatedQosFlowList %d",(decoded_msg->qosFlowPerTNLInformation.associatedQosFlowList.list.array[i])->qosFlowIdentifier );
}
//need to update UPF accordingly
update_upf = true;
break;
}
// if these contexts existed > create a procedure for update sm context and let the procedure handle the request
//else
//TODO:
session_update_sm_context_procedure* proc = new session_update_sm_context_procedure(sp);
std::shared_ptr<smf_procedure> sproc = std::shared_ptr<smf_procedure>(proc);
//PDU Session Modification procedure (UE-initiated, Section 4.3.3.2@3GPP TS 23.502)
case n2_sm_info_type_e::PDU_RES_MOD_RSP:{
procedure_type = session_management_procedures_type_e::PDU_SESSION_MODIFICATION_UE_INITIATED;
//PDU Session Resource Modify Request Transfer
//Ngap_PDUSessionResourceModifyResponseTransfer
std::shared_ptr<Ngap_PDUSessionResourceModifyResponseTransfer_t> decoded_msg = std::make_shared<Ngap_PDUSessionResourceModifyResponseTransfer_t>();
asn_dec_rval_t rc = asn_decode(nullptr,ATS_ALIGNED_CANONICAL_PER, &asn_DEF_Ngap_PDUSessionResourceModifyResponseTransfer, (void **)&decoded_msg, (void *)data, data_len);
if(rc.code != RC_OK)
{
Logger::smf_api_server().warn("asn_decode failed %d...",rc.code );
//TODO: send error to AMF??
}
insert_procedure(sproc);
if (proc->run(smreq, sm_context_resp_pending, shared_from_this())) {
// error !
Logger::smf_app().info( "PDU SESSION CREATE SM CONTEXT REQUEST procedure failed");
remove_procedure(proc);
//Ngap_PDUSessionResourceModifyResponseTransfer_t
// struct Ngap_UPTransportLayerInformation *dL_NGU_UP_TNLInformation; /* OPTIONAL */
// struct Ngap_UPTransportLayerInformation *uL_NGU_UP_TNLInformation; /* OPTIONAL */
// struct Ngap_QosFlowAddOrModifyResponseList *qosFlowAddOrModifyResponseList; /* OPTIONAL */
// struct Ngap_QosFlowPerTNLInformation *additionalQosFlowPerTNLInformation; /* OPTIONAL */
// struct Ngap_QosFlowList *qosFlowFailedToAddOrModifyList; /* OPTIONAL */
//struct Ngap_ProtocolExtensionContainer *iE_Extensions; /* OPTIONAL */
//if dL_NGU_UP_TNLInformation is included, it shall be considered as the new DL transfort layer addr for the PDU session (should be verified)
fteid_t dl_teid;
memcpy (&dl_teid.ipv4_address, decoded_msg->dL_NGU_UP_TNLInformation->choice.gTPTunnel->gTP_TEID.buf, sizeof (struct in_addr));
memcpy (&dl_teid.teid_gre_key, decoded_msg->dL_NGU_UP_TNLInformation->choice.gTPTunnel->transportLayerAddress.buf, 4);
sm_context_req_msg.set_dl_fteid(dl_teid);
//list of Qos Flows which have been successfully setup or modified
for (int i =0; i< decoded_msg->qosFlowAddOrModifyResponseList->list.count; i++ ){
sm_context_req_msg.add_qfi((decoded_msg->qosFlowAddOrModifyResponseList->list.array[i])->qosFlowIdentifier);
}
//TODO:
//list of QoS Flows which have failed to be modified
//qosFlowFailedToAddOrModifyList
//need to update UPF accordingly
update_upf = true;
break;
}
case n2_sm_info_type_e::PDU_RES_MOD_FAIL:{
}
break;
default: {
}
}
free(data);
data = nullptr;
}
//Step 3. For Service Request
if (!sm_context_req_msg.n1_sm_msg_is_set() and !sm_context_req_msg.n2_sm_info_is_set() and sm_context_req_msg.upCnx_state_is_set()){
procedure_type = session_management_procedures_type_e::SERVICE_REQUEST_UE_TRIGGERED;
//if request accepted-> set unCnxState to ACTIVATING
//Update upCnxState
sp.get()->set_upCnx_state(upCnx_state_e::UPCNX_STATE_ACTIVATING);
//need update UPF
update_upf = true;
//TODO: to be completed
}
//Step 4. Create a procedure for update sm context and let the procedure handle the request if necessary
if (update_upf){
//TODO:
session_update_sm_context_procedure* proc = new session_update_sm_context_procedure(sp);
std::shared_ptr<smf_procedure> sproc = std::shared_ptr<smf_procedure>(proc);
proc->session_procedure_type = procedure_type;
smreq->req = sm_context_req_msg;
insert_procedure(sproc);
if (proc->run(smreq, sm_context_resp_pending, shared_from_this())) {
// error !
Logger::smf_app().info( "PDU SESSION CREATE SM CONTEXT REQUEST procedure failed");
remove_procedure(proc);
}
}
//TODO, Step 5.
/* If the PDU Session establishment is not successful, the SMF informs the AMF by invoking Nsmf_PDUSession_SMContextStatusNotify (Release). The SMF also releases any N4
session(s) created, any PDU Session address if allocated (e.g. IP address) and releases the association with PCF,
if any. In this case, step 19 is skipped.
see step 18, section 4.3.2.2.1@3GPP TS 23.502)
*/
}
......@@ -655,14 +1019,6 @@ bool smf_context::find_dnn_subscription(const snssai_t& snssai, std::shared_ptr<
{
Logger::smf_app().info( "find_dnn_subscription: %d, map size %d", (uint8_t)snssai.sST, dnn_subscriptions.size());
//std::unique_lock<std::recursive_mutex> lock(m_context);
/* std::map<uint8_t,std::shared_ptr<session_management_subscription>>::const_iterator it = dnn_subscriptions.find((uint8_t)snssai.sST);
if (it != dnn_subscriptions.end()){
ss = it->second;
return true;
}
*/
if (dnn_subscriptions.count((uint8_t)snssai.sST) > 0 ){
ss = dnn_subscriptions.at((uint8_t)snssai.sST);
return true;
......@@ -701,16 +1057,6 @@ bool smf_context::verify_sm_context_request(std::shared_ptr<itti_n11_create_sm_c
return true;
}
//------------------------------------------------------------------------------
void smf_context::send_create_session_response_error(oai::smf_server::model::SmContextCreateError& smContextCreateError, Pistache::Http::Code code, Pistache::Http::ResponseWriter& httpResponse)
{
//Send reply to AMF
nlohmann::json jsonData;
to_json(jsonData, smContextCreateError);
std::string resBody = jsonData.dump();
httpResponse.send(code, resBody);
}
//-----------------------------------------------------------------------------
supi_t smf_context::get_supi() const
{
......@@ -723,10 +1069,24 @@ void smf_context::set_supi(supi_t const& s)
supi = s;
}
//-----------------------------------------------------------------------------
std::size_t smf_context::get_number_dnn_contexts()
{
return dnns.size();
}
//-----------------------------------------------------------------------------
void smf_context::set_scid(scid_t const& id)
{
scid = id;
}
//-----------------------------------------------------------------------------
scid_t smf_context::get_scid() const
{
return scid;
}
//------------------------------------------------------------------------------
bool dnn_context::find_pdu_session(const uint32_t pdu_session_id , std::shared_ptr<smf_pdu_session>& pdn)
{
......@@ -807,3 +1167,5 @@ void smf_qos_flow::deallocate_ressources()
Logger::smf_app().info( "smf_qos_flow::deallocate_ressources(%d)", (uint8_t)qfi.qfi);
clear();
}
......@@ -41,6 +41,7 @@
#include "3gpp_29.274.h"
#include "3gpp_29.244.h"
#include "3gpp_29.503.h"
#include "3gpp_29.502.h"
#include "common_root_types.h"
#include "smf_procedure.hpp"
#include "uint_generator.hpp"
......@@ -50,6 +51,7 @@
#include "pistache/router.h"
#include "SmContextCreateError.h"
#include "smf_msg.hpp"
#include "itti.hpp"
namespace smf {
......@@ -62,6 +64,7 @@ public:
void clear() {
ul_fteid = {};
dl_fteid = {};
eps_bearer_qos = {};
pdr_id_ul = {};
pdr_id_dl = {};
......@@ -77,7 +80,8 @@ public:
pfcp::qfi_t qfi; //QoS Flow Identifier
fteid_t ul_fteid; //Uplink fteid of UPF
fteid_t ul_fteid; //fteid of UPF
fteid_t dl_fteid; //fteid of AN
bearer_qos_t eps_bearer_qos; // EPS Bearer QoS: ARP, GBR, MBR, QCI.
......@@ -113,48 +117,18 @@ public:
up_fseid = {};
qos_flows.clear();
released = false;
pdu_session_status = pdu_session_status_e::PDU_SESSION_INACTIVE;
timer_T3590 = ITTI_INVALID_TIMER_ID;
timer_T3591 = ITTI_INVALID_TIMER_ID;
}
smf_pdu_session(smf_pdu_session& b) = delete;
void set(const paa_t& paa);
bool get_qos_flow(const pfcp::pdr_id_t& pdr_id, smf_qos_flow& q) {
for (auto it : qos_flows) {
if (it.second.pdr_id_ul.rule_id == pdr_id.rule_id) {
q = it.second;
return true;
}
if (it.second.pdr_id_dl.rule_id == pdr_id.rule_id) {
q = it.second;
return true;
}
}
return false;
}
bool get_qos_flow(const pfcp::far_id_t& far_id, smf_qos_flow& q) {
for (auto it : qos_flows) {
if ((it.second.far_id_ul.first) && (it.second.far_id_ul.second.far_id == far_id.far_id)) {
q = it.second;
return true;
}
if ((it.second.far_id_dl.first) && (it.second.far_id_dl.second.far_id == far_id.far_id)) {
q = it.second;
return true;
}
}
return false;
}
bool get_qos_flow(const pfcp::qfi_t& qfi, smf_qos_flow& q) {
for (auto it : qos_flows) {
if (it.second.qfi == qfi) {
q = it.second;
return true;
}
}
return false;
}
bool get_qos_flow(const pfcp::pdr_id_t& pdr_id, smf_qos_flow& q);
bool get_qos_flow(const pfcp::far_id_t& far_id, smf_qos_flow& q);
bool get_qos_flow(const pfcp::qfi_t& qfi, smf_qos_flow& q);
void add_qos_flow(smf_qos_flow& flow);
smf_qos_flow& get_qos_flow(const pfcp::qfi_t& qfi);
......@@ -163,6 +137,23 @@ public:
void remove_qos_flow(const pfcp::qfi_t& qfi);
void remove_qos_flow(smf_qos_flow& flow);
void set_pdu_session_status (const pdu_session_status_e& status);
pdu_session_status_e get_pdu_session_status () const;
/*
* Set upCnxState for a N3 Tunnel
* @param [upCnx_state_e&] state: new state of the N3 tunnel
* @return void
*/
void set_upCnx_state (const upCnx_state_e& state);
/*
* Get upCnxState of a N3 Tunnel
* @param void
* @return upCnx_state_e: current state of this N3 tunnel
*/
upCnx_state_e get_upCnx_state () const;
// Called by GTPV2-C DELETE_SESSION_REQUEST
// deallocate_ressources is for releasing LTE resources prior to the deletion of objects
......@@ -223,6 +214,15 @@ public:
std::string amf_id;
// QFI
std::map<uint8_t,smf_qos_flow> qos_flows;
//pdu session status
pdu_session_status_e pdu_session_status;
timer_id_t timer_T3590;
timer_id_t timer_T3591;
//N3 tunnel status (ACTIVATED, DEACTIVATED, ACTIVATING)
upCnx_state_e upCnx_state;
};
......@@ -299,14 +299,15 @@ public:
* @param [std::shared_ptr<itti_n11_create_sm_context_request] smreq Request message
* @return void
*/
void handle_amf_msg (std::shared_ptr<itti_n11_create_sm_context_request> smreq);
void handle_pdu_session_create_sm_context_request (std::shared_ptr<itti_n11_create_sm_context_request> smreq);
/*
* Handle messages from AMF (e.g., PDU_SESSION_UPDATESMContextRequest)
* @param [std::shared_ptr<itti_n11_update_sm_context_request] smreq Request message
* @param [pdu_session_procedure_t procedure] pdu session procedure: session establishment/modification/release
* @return void
*/
void handle_amf_msg (std::shared_ptr<itti_n11_update_sm_context_request> smreq);
void handle_pdu_session_update_sm_context_request (std::shared_ptr<itti_n11_update_sm_context_request> smreq);
/*
* Find DNN context with name
......@@ -323,15 +324,6 @@ public:
*/
void insert_dnn(std::shared_ptr<dnn_context>& sd);
/*
* Send a response error to AMF (PDU Session Establishment Reject)
* @param [oai::smf_server::model::SmContextCreateError&] smContextCreateError
* @param [Pistache::Http::Code] code response code
* @param [Pistache::Http::ResponseWriter] httpResponse to reply to AMF
* @return void
*/
void send_create_session_response_error(oai::smf_server::model::SmContextCreateError& smContextCreateError, Pistache::Http::Code code, Pistache::Http::ResponseWriter& httpResponse);
/*
* Check the validity of the request according to user subscription and local policies
* @param [std::shared_ptr<itti_n11_create_sm_context_request>] smreq
......@@ -391,6 +383,8 @@ public:
* @return std::size_t: the number of contexts
*/
std::size_t get_number_dnn_contexts();
void set_scid(scid_t const& id);
scid_t get_scid() const;
private:
......@@ -417,6 +411,7 @@ private:
std::map<uint8_t, std::shared_ptr<session_management_subscription>> dnn_subscriptions;
supi_t supi;
scid_t scid;
};
}
......
......@@ -407,7 +407,7 @@ bool pdu_session_update_sm_context_request::n2_sm_info_is_set() const
//-----------------------------------------------------------------------------
void pdu_session_update_sm_context_request::add_qfi(pfcp::qfi_t const& qfi)
{
qfis.push_back(qfi);
qfis.push_back(qfi);
}
//-----------------------------------------------------------------------------
......
......@@ -63,7 +63,7 @@ public:
uint8_t cause_value;
pfcp::qfi_t qfi;
fteid_t ul_fteid;
fteid_t ul_fteid;
arp_5gc_t arp;
uint8_t priority_level;//1-127
......@@ -77,7 +77,7 @@ public:
uint8_t cause_value;
pfcp::qfi_t qfi;
fteid_t ul_fteid;
fteid_t ul_fteid;
};
......@@ -377,108 +377,46 @@ private:
oai::smf_server::model::Guami m_guami;
oai::smf_server::model::PlmnId m_serving_network;
//BackupAmfInfo
/*
backupAmfInfo:
type: array
items:
$ref: '../TS29571_CommonData.yaml#/components/schemas/BackupAmfInfo'
minItems: 1
nullable: true
*/
std::string m_an_type;
/*
*
secondAnType:
$ref: '../TS29571_CommonData.yaml#/components/schemas/AccessType'
*/
std::string m_rat_type;
std::string m_rat_type; //ratType: $ref: '../TS29571_CommonData.yaml#/components/schemas/RatType
/* SmContextUpdateData:
presenceInLadn:
$ref: '../TS29571_CommonData.yaml#/components/schemas/PresenceState'
ueLocation:
$ref: '../TS29571_CommonData.yaml#/components/schemas/UserLocation'
ueTimeZone:
$ref: '../TS29571_CommonData.yaml#/components/schemas/TimeZone'
addUeLocation:
$ref: '../TS29571_CommonData.yaml#/components/schemas/UserLocation'
hoState:
$ref: '#/components/schemas/HoState'
toBeSwitched:
type: boolean
default: false
failedToBeSwitched:
type: boolean
/* SmContextUpdateData:
presenceInLadn:
ueLocation:
ueTimeZone:
addUeLocation:
hoState:
toBeSwitched:
failedToBeSwitched:
*/
std::string m_upCnx_state; //'#/components/schemas/UpCnxState'
bool m_upCnx_state_is_set; //'#/components/schemas/UpCnxState'
std::string m_upCnx_state;
bool m_upCnx_state_is_set;
oai::smf_server::model::RefToBinaryData m_n1_sm_msg; //n1SmMsg
oai::smf_server::model::RefToBinaryData m_n2_sm_info; //n2SmInfo
std::string m_n2_sm_info_type; //$ref: '#/components/schemas/N2SmInfoType'
oai::smf_server::model::RefToBinaryData m_n1_sm_msg;
oai::smf_server::model::RefToBinaryData m_n2_sm_info;
std::string m_n2_sm_info_type;
oai::smf_server::model::NgRanTargetId m_target_id; //$ref: '../amf/TS29518_Namf_Communication.yaml#/components/schemas/NgRanTargetId'
std::string m_target_serving_nfId; // $ref: '../TS29571_CommonData.yaml#/components/schemas/NfInstanceId'
std::string m_sm_context_status_uri; //smContextStatusUri $ref: '../TS29571_CommonData.yaml#/components/schemas/Uri'
/*
dataForwarding:
type: boolean
default: false
*/
std::string m_sm_context_status_uri;
bool m_data_forwarding;
/*
epsBearerSetup:
type: array
items:
$ref: '#/components/schemas/EpsBearerContainer'
minItems: 0
*/
std::vector<std::string> m_eps_bearer_setup;
/*
revokeEbiList:
type: array
items:
$ref: '#/components/schemas/EpsBearerId'
minItems: 1
EpsBearerId:
type: integer
minimum: 0
maximum: 15
*/
std::vector<int> m_revoke_ebi_list;
/*
release:
type: boolean
default: false
cause:
$ref: '#/components/schemas/Cause'
*/
//NgApCause m_ngAp_cause; // $ref: '../TS29571_CommonData.yaml#/components/schemas/NgApCause
uint8_t m_5gMm_cause_value; // 5GMmCause, $ref: '../TS29571_CommonData.yaml#/components/schemas/5GMmCause'
//NgApCause m_ngAp_cause;
uint8_t m_5gMm_cause_value;
/*
sNssai:
$ref: '../TS29571_CommonData.yaml#/components/schemas/Snssai'
traceData:
$ref: '../TS29571_CommonData.yaml#/components/schemas/TraceData'
epsInterworkingInd:
$ref: '#/components/schemas/EpsInterworkingIndication'
anTypeCanBeChanged:
type: boolean
default: false
n2SmInfoExt1:
$ref: '../TS29571_CommonData.yaml#/components/schemas/RefToBinaryData'
n2SmInfoTypeExt1:
$ref: '#/components/schemas/N2SmInfoType'
maReleaseInd:
$ref: '#/components/schemas/MaReleaseIndication'
exemptionInd:
$ref: '#/components/schemas/ExemptionInd'
*/
EpsBearerId:
release:
cause:
traceData:
epsInterworkingInd:
anTypeCanBeChanged:
n2SmInfoExt1:
n2SmInfoTypeExt1:
maReleaseInd:
exemptionInd:
*/
};
......
......@@ -39,6 +39,12 @@
#include <nlohmann/json.hpp>
#include <stdexcept>
#include <pistache/http.h>
#include <pistache/mime.h>
using namespace Pistache::Http;
using namespace Pistache::Http::Mime;
//TODO: move to a common file
#define AMF_CURL_TIMEOUT_MS 100L
#define AMF_NUMBER_RETRIES 3
......@@ -123,23 +129,25 @@ smf_n11::smf_n11 ()
//------------------------------------------------------------------------------
void smf_n11::send_n1n2_message_transfer_request(std::shared_ptr<itti_n11_create_sm_context_response> sm_context_res)
{
//TODO: should create N1 SM, N2 SM from Procedure to make sure that in this class we simply do send the message to AMF
//Transfer N1/N2 message via AMF by using N_amf_Communication_N1N2MessageTransfer (see TS29518_Namf_Communication.yaml)
//use curl to send data for the moment
Logger::smf_n11().debug("[SMF N11: N1N2MessageTransfer] Send Communication_N1N2MessageTransfer to AMF");
//TODO: use RestSDK for client, use curl to send data for the moment
Logger::smf_n11().debug("Send Communication_N1N2MessageTransfer to AMF");
nlohmann::json message_transfer_req_data;
std::string n1_message;
std::string n2_message;
smf_n1_n2 smf_n1_n2_inst;
pdu_session_create_sm_context_response context_res_msg = sm_context_res->res;
std::string n1_message = context_res_msg.get_n1_sm_message();
std::string n2_message = context_res_msg.get_n2_sm_information();
//format string as hex
unsigned char *n1_msg_hex = smf_app_inst->format_string_as_hex(n1_message);
unsigned char *n2_msg_hex = smf_app_inst->format_string_as_hex(n2_message);
CURL *curl = curl_easy_init();
//N1N2MessageTransfer Notification URI??
std::string json_part = context_res_msg.n1n2_message_transfer_data.dump();
Logger::smf_n11().debug("[SMF N11: N1N2MessageTransfer] Sending message to AMF....\n ");
Logger::smf_n11().debug("Sending message to AMF....");
if(curl) {
CURLcode res;
......@@ -165,23 +173,22 @@ void smf_n11::send_n1n2_message_transfer_request(std::shared_ptr<itti_n11_create
curl_mime_type(part, "application/json");
//N1 SM Container
Logger::smf_n11().debug("Add N1 SM Container (NAS) into the message: %s (bytes %d)", context_res_msg.get_n1_sm_message().c_str(), context_res_msg.get_n1_sm_message().length()/2);
part = curl_mime_addpart(mime);
curl_mime_data(part, context_res_msg.get_n1_sm_message().c_str(), CURL_ZERO_TERMINATED);
curl_mime_data(part, reinterpret_cast<const char*>(n1_msg_hex), context_res_msg.get_n1_sm_message().length()/2);
curl_mime_type(part, "application/vnd.3gpp.5gnas");
curl_mime_name (part, context_res_msg.n1n2_message_transfer_data["n1MessageContainer"]["n1MessageContent"]["contentId"].dump().c_str());
if (context_res_msg.get_cause() == REQUEST_ACCEPTED) {
Logger::smf_n11().debug("[SMF N11: N1N2MessageTransfer] add NGAP into the message....\n ");
//N2 SM Information
part = curl_mime_addpart(mime);
//TODO:
curl_mime_data(part, context_res_msg.get_n2_sm_information().substr(0,86).c_str(), CURL_ZERO_TERMINATED); //TODO: ISSUE need to be solved
curl_mime_type(part, "application/vnd.3gpp.ngap");
curl_mime_name (part, context_res_msg.n1n2_message_transfer_data["n2InfoContainer"]["smInfo"]["n2InfoContent"]["ngapData"]["contentId"].dump().c_str());
Logger::smf_n11().debug("Add N2 SM Information (NGAP) into the message: %s (bytes %d)", context_res_msg.get_n2_sm_information().c_str(), context_res_msg.get_n2_sm_information().length()/2);
part = curl_mime_addpart(mime);
//curl_mime_data(part, reinterpret_cast<const char*>(n2_msg_hex), context_res_msg.get_n2_sm_information().length()/2); //TODO: ISSUE need to be solved
curl_mime_data(part, reinterpret_cast<const char*>(n2_msg_hex), 80); //TODO: ISSUE need to be solved
curl_mime_type(part, "application/vnd.3gpp.ngap");
curl_mime_name (part, context_res_msg.n1n2_message_transfer_data["n2InfoContainer"]["smInfo"]["n2InfoContent"]["ngapData"]["contentId"].dump().c_str());
}
curl_easy_setopt(curl, CURLOPT_MIMEPOST, mime);
res = curl_easy_perform(curl);
// Response information.
long httpCode(0);
......@@ -203,13 +210,18 @@ void smf_n11::send_n1n2_message_transfer_request(std::shared_ptr<itti_n11_create
//Set the default Cause
response_data["cause"] = "504 Gateway Timeout";
}
Logger::smf_n11().debug("[SMF N11: N1N2MessageTransfer] Response from AMF, Http Code: %d, cause %s", httpCode, response_data["cause"]);
Logger::smf_n11().debug("Response from AMF, Http Code: %d, cause %s", httpCode, response_data["cause"].dump().c_str());
//send response to APP to process
itti_n11_n1n2_message_transfer_response_status *itti_msg = new itti_n11_n1n2_message_transfer_response_status(TASK_SMF_N11, TASK_SMF_APP);
itti_msg->set_response_code(httpCode);
itti_msg->set_scid(sm_context_res->scid);
itti_msg->set_cause(response_data["cause"]);
if (context_res_msg.get_cause() == REQUEST_ACCEPTED) {
itti_msg->set_msg_type(PDU_SESSION_ESTABLISHMENT_ACCEPT);
}else {
itti_msg->set_msg_type(PDU_SESSION_ESTABLISHMENT_REJECT);
}
std::shared_ptr<itti_n11_n1n2_message_transfer_response_status> i = std::shared_ptr<itti_n11_n1n2_message_transfer_response_status>(itti_msg);
int ret = itti_inst->send_msg(i);
if (RETURNok != ret) {
......@@ -226,44 +238,64 @@ void smf_n11::send_n1n2_message_transfer_request(std::shared_ptr<itti_n11_create
//------------------------------------------------------------------------------
void smf_n11::send_pdu_session_update_sm_context_response(std::shared_ptr<itti_n11_update_sm_context_response> sm_context_res)
{
Logger::smf_n11().debug("[SMF N11] Send PDUSessionUpdateContextResponse to AMF ");
//TODO: to be completed
Logger::smf_n11().debug("Send PDUSessionUpdateContextResponse to AMF ");
//Send reply to AMF
/* Pistache::Http::Code code;
nlohmann::json jsonData;
//to_json(jsonData, smContextCreateError);
std::string resBody = jsonData.dump();
sm_context_res->http_response.send(code,body);
*/
nlohmann::json sm_context_updated_data;
sm_context_updated_data["cause"] = sm_context_res->res.get_cause();
//sm_context_res->http_response.send(Pistache::Http::Code::Ok,sm_context_updated_data.dump());
sm_context_res->http_response.send(Pistache::Http::Code::No_Content);
}
//------------------------------------------------------------------------------
void smf_n11::send_pdu_session_create_sm_context_response(Pistache::Http::ResponseWriter& httpResponse, oai::smf_server::model::SmContextCreateError& smContextCreateError, Pistache::Http::Code code)
void smf_n11::send_pdu_session_update_sm_context_response(Pistache::Http::ResponseWriter& httpResponse, oai::smf_server::model::SmContextUpdateError& smContextUpdateError, Pistache::Http::Code code)
{
//TODO: Send multipart message
nlohmann::json jsonData;
to_json(jsonData, smContextCreateError);
to_json(jsonData, smContextUpdateError);
std::string resBody = jsonData.dump();
//httpResponse.headers().add<Pistache::Http::Header::Location>(url);
httpResponse.send(code, resBody);
}
//------------------------------------------------------------------------------
void smf_n11::send_pdu_session_update_sm_context_response(Pistache::Http::ResponseWriter& httpResponse, oai::smf_server::model::SmContextUpdateError& smContextUpdateError, Pistache::Http::Code code, std::string& n1_sm_msg )
{
Logger::smf_n11().debug("[SMF N11] Send PDUSessionUpdateContextResponse to AMF!");
//TODO: Send multipart message
nlohmann::json jsonData;
to_json(jsonData, smContextUpdateError);
std::string resBody = jsonData.dump();
//http_response.headers().add<Pistache::Http::Header::Location>(uri);
httpResponse.send(code, resBody);
}
void smf_n11::send_pdu_session_create_sm_context_response(Pistache::Http::ResponseWriter& httpResponse, oai::smf_server::model::SmContextCreateError& smContextCreateError, Pistache::Http::Code code, std::string& n1_sm_msg )
{
Logger::smf_n11().debug("[SMF N11] Send PDUSessionCreateContextResponse to AMF!");
//TODO: Send multipart message
nlohmann::json jsonData;
to_json(jsonData, smContextCreateError);
jsonData["n1SmMsg"]["contentId"] = "n1SmMsg"; //multipart
std::string resBody = jsonData.dump();
auto m1 = MIME(Multipart, Json);
auto m2 = MIME(Multipart, Star);
Pistache::Http::Mime::MediaType m3("application/vnd.3gpp.5gnas", Pistache::Http::Mime::MediaType::DontParse);
//httpResponse.headers().add<Pistache::Http::Header::Location>(url);
httpResponse.send(code, resBody);
httpResponse.send(code, resBody, m3);
}
......
......@@ -33,6 +33,7 @@
#include "3gpp_29.503.h"
#include "smf_context.hpp"
#include "SmContextCreatedData.h"
#include "SmContextUpdateError.h"
#include <thread>
#include <map>
......@@ -52,6 +53,8 @@ public:
void send_n1n2_message_transfer_request(std::shared_ptr<itti_n11_create_sm_context_response> sm_context_res);
void send_pdu_session_update_sm_context_response(std::shared_ptr<itti_n11_update_sm_context_response> sm_context_res);
void send_n1n2_message_transfer_request(std::shared_ptr<itti_n11_modify_session_request_smf_requested> sm_context_mod);
void send_pdu_session_update_sm_context_response(Pistache::Http::ResponseWriter& httpResponse, oai::smf_server::model::SmContextUpdateError& smContextUpdateError, Pistache::Http::Code code);
//void send_pdu_session_update_sm_context_response(Pistache::Http::ResponseWriter& httpResponse, oai::smf_server::model::SmContextUpdateError& smContextUpdateError, Pistache::Http::Code code, std::string& n1_sm_msg );
/*
......@@ -64,14 +67,25 @@ public:
void send_pdu_session_create_sm_context_response(Pistache::Http::ResponseWriter& httpResponse, oai::smf_server::model::SmContextCreateError& smContextCreateError, Pistache::Http::Code code);
/*
* Send create session response to AMF
* @param [Pistache::Http::ResponseWriter] httpResponse
* @param [ oai::smf_server::model::SmContextCreateError] smContextCreateError
* @param [Pistache::Http::Code] code, response code
* @param [std::string] n1_sm_msg, N1 SM message content
*
*/
void send_pdu_session_create_sm_context_response(Pistache::Http::ResponseWriter& httpResponse, oai::smf_server::model::SmContextCreateError& smContextCreateError, Pistache::Http::Code code, std::string& n1_sm_msg );
* Send create session response to AMF
* @param [Pistache::Http::ResponseWriter] httpResponse
* @param [ oai::smf_server::model::SmContextCreateError] smContextCreateError
* @param [Pistache::Http::Code] code, response code
* @param [std::string] n1_sm_msg, N1 SM message content
*
*/
void send_pdu_session_create_sm_context_response(Pistache::Http::ResponseWriter& httpResponse, oai::smf_server::model::SmContextCreateError& smContextCreateError, Pistache::Http::Code code, std::string& n1_sm_msg );
/*
* Send update session response to AMF
* @param [Pistache::Http::ResponseWriter] httpResponse
* @param [ oai::smf_server::model::SmContextUpdateError] smContextUpdateError
* @param [Pistache::Http::Code] code, response code
* @param [std::string] n1_sm_msg, N1 SM message content
*
*/
void send_pdu_session_update_sm_context_response(Pistache::Http::ResponseWriter& httpResponse, oai::smf_server::model::SmContextUpdateError& smContextUpdateError, Pistache::Http::Code code, std::string& n1_sm_msg );
/*
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -76,10 +76,7 @@ public:
* @param [uint8_t] sm_cause store NAS Cause
*
*/
void create_n1_sm_container(pdu_session_msg& msg, uint8_t msg_type, std::string& nas_msg_str, uint8_t sm_cause);
//for testing purpose!!
void create_n1_sm_container(uint8_t msg_type, std::string& nas_msg_str, uint8_t sm_cause = 0);
void create_n1_sm_container(pdu_session_msg& msg, uint8_t msg_type, std::string& nas_msg_str, cause_value_5gsm_e sm_cause);
/*
* Create N2 SM Information to send to AMF (using NAS lib)
......
......@@ -72,8 +72,8 @@ void smf_n4_task (void *args_p)
case N4_ASSOCIATION_SETUP_REQUEST:
if (itti_n4_association_setup_request* m = dynamic_cast<itti_n4_association_setup_request*>(msg)) {
// m->trxn_id = smf_n4_inst->generate_trxn_id();
smf_n4_inst->send_association_setup_request(ref(*m));
// m->trxn_id = smf_n4_inst->generate_trxn_id();
smf_n4_inst->send_association_setup_request(ref(*m));
//smf_n4_inst->handle_itti_msg(ref(*m));
}
break;
......@@ -358,7 +358,7 @@ void smf_n4::handle_receive_association_setup_request(pfcp::pfcp_msg& msg, const
//------------------------------------------------------------------------------
void smf_n4::handle_receive_association_setup_response(pfcp::pfcp_msg& msg, const endpoint& remote_endpoint)
{
//TODO: To be completed
//TODO: To be completed
Logger::smf_n4().info("Received N4 ASSOCIATION SETUP RESPONSE from an UPF");
bool error = true;
uint64_t trxn_id = 0;
......@@ -561,7 +561,7 @@ void smf_n4::time_out_itti_event(const uint32_t timer_id)
//------------------------------------------------------------------------------
void smf_n4::send_association_setup_request(itti_n4_association_setup_request& i)
{
i.trxn_id = generate_trxn_id();
send_request(i.r_endpoint, i.pfcp_ies, TASK_SMF_N4, i.trxn_id);
i.trxn_id = generate_trxn_id();
send_request(i.r_endpoint, i.pfcp_ies, TASK_SMF_N4, i.trxn_id);
}
......@@ -59,7 +59,7 @@ public:
timer_id_t timer_association;
explicit pfcp_association(const pfcp::node_id_t& node_id) :
node_id(node_id), recovery_time_stamp(), function_features(), m_sessions(), sessions() {
node_id(node_id), recovery_time_stamp(), function_features(), m_sessions(), sessions() {
hash_node_id = std::hash<pfcp::node_id_t>{}(node_id);
timer_heartbeat = ITTI_INVALID_TIMER_ID;
num_retries_timer_heartbeat = 0;
......
......@@ -98,7 +98,6 @@ int session_create_sm_context_procedure::run(std::shared_ptr<itti_n11_create_sm_
return RETURNerror;
}
//-------------------
n11_trigger = sm_context_req;
n11_triggered_pending = sm_context_resp;
......@@ -126,7 +125,6 @@ int session_create_sm_context_procedure::run(std::shared_ptr<itti_n11_create_sm_
cp_fseid.seid = ppc->seid;
n4_ser->pfcp_ies.set(cp_fseid);
//*******************
// UPLINK
//*******************
......@@ -265,7 +263,7 @@ void session_create_sm_context_procedure::handle_itti_msg (itti_n4_session_estab
//set tunnel id
xgpp_conv::pfcp_to_core_fteid(local_up_fteid, q.ul_fteid);
//TODO: should be updated to 5G N3/N9 interface
q.ul_fteid.interface_type = S1_U_SGW_GTP_U;
q.ul_fteid.interface_type = S1_U_SGW_GTP_U; //UPF's N3 interface
// comment if SPGW-C allocate up fteid
//Update Qos Flow
smf_qos_flow q2 = q;
......@@ -308,27 +306,32 @@ void session_create_sm_context_procedure::handle_itti_msg (itti_n4_session_estab
n11_triggered_pending->res.set_qos_flow_context(qos_flow);
//fill content for N1N2MessageTransfer (inlcuding N1, N2 SM)
//fill content for N1N2MessageTransfer (including N1, N2 SM)
// Create N1 SM container & N2 SM Information
smf_n1_n2 smf_n1_n2_inst;
std::string n1_sm_msg,n1_sm_msg_hex;
std::string n2_sm_info, n2_sm_info_hex;
//TODO: should uncomment this line when including UPF in the test
//n11_triggered_pending->res.set_cause(REQUEST_ACCEPTED);//for testing purpose
n11_triggered_pending->res.set_cause(REQUEST_ACCEPTED);//for testing purpose
if (n11_triggered_pending->res.get_cause() != REQUEST_ACCEPTED) { //PDU Session Establishment Reject
Logger::smf_n11().debug("[SMF N11: N1N2MessageTransfer] PDU Session Establishment Reject\n");
smf_n1_n2_inst.create_n1_sm_container(n11_triggered_pending->res, PDU_SESSION_ESTABLISHMENT_REJECT, n1_sm_msg, 0); //TODO: need cause?
Logger::smf_app().debug("PDU Session Establishment Reject");
smf_n1_n2_inst.create_n1_sm_container(n11_triggered_pending->res, PDU_SESSION_ESTABLISHMENT_REJECT, n1_sm_msg, cause_value_5gsm_e::CAUSE_0_UNKNOWN); //TODO: need cause?
smf_app_inst->convert_string_2_hex(n1_sm_msg, n1_sm_msg_hex);
n11_triggered_pending->res.set_n1_sm_message(n1_sm_msg_hex);
} else { //PDU Session Establishment Accept
Logger::smf_n11().debug("[SMF N11: N1N2MessageTransfer] PDU Session Establishment Accept \n");
smf_n1_n2_inst.create_n1_sm_container(n11_triggered_pending->res, PDU_SESSION_ESTABLISHMENT_ACCEPT, n1_sm_msg, 0); //TODO: need cause?
Logger::smf_app().debug("PDU Session Establishment Accept");
smf_n1_n2_inst.create_n1_sm_container(n11_triggered_pending->res, PDU_SESSION_ESTABLISHMENT_ACCEPT, n1_sm_msg, cause_value_5gsm_e::CAUSE_0_UNKNOWN); //TODO: need cause?
smf_app_inst->convert_string_2_hex(n1_sm_msg, n1_sm_msg_hex);
n11_triggered_pending->res.set_n1_sm_message(n1_sm_msg_hex);
//TODO: N2 SM Information (Step 11, section 4.3.2.2.1 @ 3GPP TS 23.502)
smf_n1_n2_inst.create_n2_sm_information(n11_triggered_pending->res, 1, n2_sm_info_type_e::PDU_RES_SETUP_REQ, n2_sm_info);
smf_app_inst->convert_string_2_hex(n2_sm_info, n2_sm_info_hex);
n11_triggered_pending->res.set_n2_sm_information(n2_sm_info_hex);
}
//Fill N1N2MesasgeTransferRequestData
......@@ -392,6 +395,7 @@ int session_update_sm_context_procedure::run(std::shared_ptr<itti_n11_update_sm_
if (not pfcp_associations::get_instance().select_up_node(up_node_id, NODE_SELECTION_CRITERIA_MIN_PFCP_SESSIONS)) {
// TODO
sm_context_resp->res.set_cause(REMOTE_PEER_NOT_RESPONDING); //verify for 5G??
Logger::smf_app().info("[SMF Procedure] REMOTE_PEER_NOT_RESPONDING");
return RETURNerror;
}
......@@ -413,8 +417,12 @@ int session_update_sm_context_procedure::run(std::shared_ptr<itti_n11_update_sm_
std::vector<pfcp::qfi_t> list_of_qfis_to_be_modified;
sm_context_req_msg.get_qfis(list_of_qfis_to_be_modified);
for (auto i:list_of_qfis_to_be_modified){
Logger::smf_app().debug( "qfi to be modified: %d", i.qfi);
}
::fteid_t dl_fteid = {};
sm_context_req_msg.get_dl_fteid(dl_fteid);
sm_context_req_msg.get_dl_fteid(dl_fteid); //eNB's fteid
for (auto qfi: list_of_qfis_to_be_modified){
smf_qos_flow qos_flow;
......@@ -593,11 +601,12 @@ int session_update_sm_context_procedure::run(std::shared_ptr<itti_n11_update_sm_
return RETURNerror;
}
} else {
// send N11
Logger::smf_app().info( "Sending ITTI message %s to task TASK_PGWC_S5S8", n11_triggered_pending->get_msg_name());
// send to AMF, update response
//TODO: to be completed
Logger::smf_app().info( "Sending ITTI message %s to task TASK_SMF_N11", n11_triggered_pending->get_msg_name());
int ret = itti_inst->send_msg(n11_triggered_pending);
if (RETURNok != ret) {
Logger::smf_app().error( "Could not send ITTI message %s to task TASK_PGWC_S5S8", n11_triggered_pending->get_msg_name());
Logger::smf_app().error( "Could not send ITTI message %s to task TASK_SMF_N11", n11_triggered_pending->get_msg_name());
}
return RETURNclear;
}
......@@ -626,20 +635,48 @@ void session_update_sm_context_procedure::handle_itti_msg (itti_n4_session_modif
::fteid_t dl_fteid = {};
n11_trigger->req.get_dl_fteid(dl_fteid);
bool bearer_context_found = false;
std::map<uint8_t, qos_flow_context_modified> qos_flow_context_to_be_modifieds;
n11_triggered_pending->res.get_all_qos_flow_context_modifieds(qos_flow_context_to_be_modifieds);
for (auto it_created_pdr : resp.pfcp_ies.created_pdrs) {
bearer_context_found = false;
pfcp::pdr_id_t pdr_id = {};
if (it_created_pdr.get(pdr_id)) {
smf_qos_flow flow = {};
if (ppc->get_qos_flow(pdr_id, flow)) {
std::map<uint8_t, qos_flow_context_modified> qos_flow_context_to_be_modifieds;
n11_triggered_pending->res.get_all_qos_flow_context_modifieds(qos_flow_context_to_be_modifieds);
for (auto qfi: list_of_qfis_to_be_modified){
bearer_context_found = true;
for (auto it: qos_flow_context_to_be_modifieds){
flow.dl_fteid = dl_fteid;
flow.dl_fteid.interface_type = S1_U_ENODEB_GTP_U; //eNB's N3 interface
// flow.ul_fteid = it.second.ul_fteid;
pfcp::fteid_t local_up_fteid = {};
if (it_created_pdr.get(local_up_fteid)) {
xgpp_conv::pfcp_to_core_fteid(local_up_fteid, flow.ul_fteid);
flow.ul_fteid.interface_type = S1_U_SGW_GTP_U; //UPF's N3 interface, TODO: should be modified
Logger::smf_app().warn( "got local_up_fteid from created_pdr %s", flow.ul_fteid.toString().c_str());
} else {
Logger::smf_app().warn( "Could not get local_up_fteid from created_pdr");
}
flow.released = false;
smf_qos_flow flow2 = flow;
ppc->add_qos_flow(flow2);
qos_flow_context_modified qcm = {};
qcm.set_cause(REQUEST_ACCEPTED);
qcm.set_qfi(pfcp::qfi_t(it.first));
qcm.set_ul_fteid(flow.ul_fteid);
n11_triggered_pending->res.add_qos_flow_context_modified(qcm);
//TODO: remove this QFI from the list (as well as in n11_trigger->req)
break;
}
/*
for (auto qfi: list_of_qfis_to_be_modified){
pfcp::fteid_t local_up_fteid = {};
if (it_created_pdr.get(local_up_fteid)) {
xgpp_conv::pfcp_to_core_fteid(local_up_fteid, flow.ul_fteid);
......@@ -663,6 +700,7 @@ void session_update_sm_context_procedure::handle_itti_msg (itti_n4_session_modif
break;
}
*/
}
} else {
Logger::smf_app().error( "Could not get pdr_id for created_pdr in %s", resp.pfcp_ies.get_msg_name());
......@@ -677,22 +715,23 @@ void session_update_sm_context_procedure::handle_itti_msg (itti_n4_session_modif
if (it_update_far.get(far_id)) {
smf_qos_flow flow = {};
if (ppc->get_qos_flow(far_id, flow)) {
for (auto qfi: list_of_qfis_to_be_modified){
if (qfi.qfi == flow.qfi.qfi){
//for (auto qfi: list_of_qfis_to_be_modified){
for (auto it: qos_flow_context_to_be_modifieds){
if (it.first == flow.qfi.qfi){
flow.dl_fteid = dl_fteid;
smf_qos_flow flow2 = flow;
ppc->add_qos_flow(flow2);
qos_flow_context_modified qcm = {};
qcm.set_cause(REQUEST_ACCEPTED);
qcm.set_qfi(qfi);
qcm.set_qfi(pfcp::qfi_t(it.first));
qcm.set_ul_fteid(flow.ul_fteid);
n11_triggered_pending->res.add_qos_flow_context_modified(qcm);
break;
}
}
} else {
Logger::smf_app().error( "Could not get eps bearer for far_id for update_far in %s", resp.pfcp_ies.get_msg_name());
Logger::smf_app().error( "Could not get qos flow for far_id for update_far in %s", resp.pfcp_ies.get_msg_name());
}
} else {
Logger::smf_app().error( "Could not get far_id for update_far in %s", resp.pfcp_ies.get_msg_name());
......@@ -700,12 +739,14 @@ void session_update_sm_context_procedure::handle_itti_msg (itti_n4_session_modif
}
}
n11_triggered_pending->res.set_cause(cause_gtp.cause_value);
// TODO
// check we got all responses vs n11_triggered_pending->res.flow_context_modified
//Optional: send ITTI message to N10 to trigger UDM registration (Nudm_UECM_Registration)
//TODO: Optional: send ITTI message to N10 to trigger UDM registration (Nudm_UECM_Registration)
//see TS29503_Nudm_UECM.yaml ( /{ueId}/registrations/smf-registrations/{pduSessionId}:)
/* std::shared_ptr<itti_n10_create_smf_registration_request> itti_msg = std::make_shared<itti_n10_create_smf_registration_request>(TASK_SMF_APP, TASK_SMF_N10, response);
int ret = itti_inst->send_msg(itti_msg);
......@@ -717,6 +758,23 @@ void session_update_sm_context_procedure::handle_itti_msg (itti_n4_session_modif
if (RETURNok != ret) {
Logger::smf_app().error( "Could not send ITTI message %s to task TASK_SMF_N11", n11_triggered_pending->get_msg_name());
}
//The SMF may subscribe to the UE mobility event notification from the AMF (e.g. location reporting, UE
//moving into or out of Area Of Interest), by invoking Namf_EventExposure_Subscribe service operation
// For LADN, the SMF subscribes to the UE moving into or out of LADN service area event notification by providing the LADN DNN as an indicator for the Area Of Interest
//see step 17@section 4.3.2.2.1@3GPP TS 23.502
if (cause.cause_value != CAUSE_VALUE_REQUEST_ACCEPTED)
{
//TODO: Nsmf_PDUSession_SMContextStatusNotify
/* If the PDU Session establishment is not successful, the SMF informs the AMF by invoking Nsmf_PDUSession_SMContextStatusNotify (Release). The SMF also releases any N4
session(s) created, any PDU Session address if allocated (e.g. IP address) and releases the association with PCF,
if any. In this case, step 19 is skipped.
see step 18, section 4.3.2.2.1@3GPP TS 23.502)
*/
}
}
......@@ -141,6 +141,8 @@ public:
std::shared_ptr<itti_n11_update_sm_context_request> n11_trigger;
std::shared_ptr<itti_n11_update_sm_context_response> n11_triggered_pending;
session_management_procedures_type_e session_procedure_type;
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment