Commit 0d1c5fd6 authored by Tien-Thinh Nguyen's avatar Tien-Thinh Nguyen
Browse files

add Release SM Context procedure

parent 0590fb18
......@@ -87,84 +87,16 @@ void IndividualSMContextApi::setupRoutes() {
void IndividualSMContextApi::release_sm_context_handler(
const Pistache::Rest::Request &request,
Pistache::Http::ResponseWriter response) {
// Getting the path params
auto smContextRef = request.param(":smContextRef").as<std::string>();
//TODO: to be updated as update_sm_context_handler
Logger::smf_api_server().info(
"Received a Nsmf_PDUSession_UpdateSMContext: PDU Session Release request from AMF");
Logger::smf_api_server().debug("Request body: %s\n", request.body().c_str());
SmContextReleaseMessage smContextReleaseMessage = { };
//find boundary
std::size_t found = request.body().find("Content-Type");
std::string boundary_str = request.body().substr(2, found - 4);
Logger::smf_api_server().debug("Boundary: %s", boundary_str.c_str());
//step 1. use multipartparser to decode the request
multipartparser_callbacks_init(&g_callbacks);
g_callbacks.on_body_begin = &on_body_begin;
g_callbacks.on_part_begin = &on_part_begin;
g_callbacks.on_header_field = &on_header_field;
g_callbacks.on_header_value = &on_header_value;
g_callbacks.on_headers_complete = &on_headers_complete;
g_callbacks.on_data = &on_data;
g_callbacks.on_part_end = &on_part_end;
g_callbacks.on_body_end = &on_body_end;
multipartparser parser = { };
init_globals();
multipartparser_init(&parser,
reinterpret_cast<const char*>(boundary_str.c_str()));
unsigned int str_len = request.body().length();
unsigned char *data = (unsigned char*) malloc(str_len + 1);
memset(data, 0, str_len + 1);
memcpy((void*) data, (void*) request.body().c_str(), str_len);
//if ((multipartparser_execute(&parser, &g_callbacks, request.body().c_str(), strlen(request.body().c_str())) != strlen(request.body().c_str())) or (!g_body_begin_called)){
if ((multipartparser_execute(&parser, &g_callbacks,
reinterpret_cast<const char*>(data), str_len)
!= strlen(request.body().c_str())) or (!g_body_begin_called)) {
Logger::smf_api_server().warn(
"The received message can not be parsed properly!");
//TODO: fix this issue
//response.send(Pistache::Http::Code::Bad_Request, "");
//return;
}
free_wrapper((void**) &data);
uint8_t size = g_parts.size();
Logger::smf_api_server().debug("Number of g_parts %d", g_parts.size());
part p0 = g_parts.front();
g_parts.pop_front();
Logger::smf_api_server().debug("Request body, part 1: %s", p0.body.c_str());
part p1 = { };
if (size > 1) {
p1 = g_parts.front();
g_parts.pop_front();
Logger::smf_api_server().debug("Request body, part 2: %s (%d bytes)",
p1.body.c_str(), p1.body.length());
//part p2 = g_parts.front(); g_parts.pop_front();
//Logger::smf_api_server().debug("Request body, part 3: \n %s",p2.body.c_str());
}
// Getting the body param
SmContextReleaseData smContextReleaseData = { };
try {
nlohmann::json::parse(p0.body.c_str()).get_to(smContextReleaseData);
smContextReleaseMessage.setJsonData(smContextReleaseData);
if (size > 1) {
if (smContextReleaseData.n2SmInfoIsSet()) {
//N2 SM (for Session establishment, or for session modification)
Logger::smf_api_server().debug("N2 SM information is set");
smContextReleaseMessage.setBinaryDataN2SmInformation(p1.body);
}
}
// Getting the path params
auto smContextRef = request.param(":smContextRef").as<std::string>();
this->release_sm_context(smContextRef, smContextReleaseMessage, response);
SmContextReleaseData smContextReleaseData;
try {
nlohmann::json::parse(request.body()).get_to(smContextReleaseData);
this->release_sm_context(smContextRef, smContextReleaseData, response);
} catch (nlohmann::detail::exception &e) {
//send a 400 error
response.send(Pistache::Http::Code::Bad_Request, e.what());
......@@ -176,6 +108,7 @@ void IndividualSMContextApi::release_sm_context_handler(
}
}
void IndividualSMContextApi::retrieve_sm_context_handler(
const Pistache::Rest::Request &request,
Pistache::Http::ResponseWriter response) {
......
......@@ -98,7 +98,7 @@ class IndividualSMContextApi {
/// <param name="smContextReleaseData">representation of the data to be sent to the SMF when releasing the SM context (optional)</param>
virtual void release_sm_context(
const std::string &smContextRef,
const SmContextReleaseMessage &smContextReleaseMessage,
const SmContextReleaseData &smContextReleaseData,
Pistache::Http::ResponseWriter &response) = 0;
/// <summary>
......
......@@ -50,7 +50,7 @@ IndividualSMContextApiImpl::IndividualSMContextApiImpl(
void IndividualSMContextApiImpl::release_sm_context(
const std::string &smContextRef,
const SmContextReleaseMessage &smContextReleaseMessage,
const SmContextReleaseData &smContextReleaseData,
Pistache::Http::ResponseWriter &response) {
//TODO: to be updated as update_sm_context_handler
......@@ -58,30 +58,15 @@ void IndividualSMContextApiImpl::release_sm_context(
//handle Nsmf_PDUSession_UpdateSMContext Request
Logger::smf_api_server().info(
"Received a PDUSession_UpdateSMContext Request: PDU Session Release request from AMF.");
//Get the SmContextUpdateData from this message and process in smf_app
smf::pdu_session_update_sm_context_request sm_context_req_msg = { };
SmContextReleaseData smContextReleaseData = smContextReleaseMessage
.getJsonData();
if (smContextReleaseData.n2SmInfoIsSet()) {
//N2 SM (for Session establishment)
std::string n2_sm_information = smContextReleaseMessage
.getBinaryDataN2SmInformation();
Logger::smf_api_server().debug("smContextMessage, n2 sm information %s",
n2_sm_information.c_str());
std::string n2_sm_info_type = smContextReleaseData.getN2SmInfoType();
sm_context_req_msg.set_n2_sm_information(n2_sm_information);
sm_context_req_msg.set_n2_sm_info_type(n2_sm_info_type);
}
//Step 2. TODO: initialize necessary values for sm context req from smContextReleaseData
"Received a PDUSession_ReleaseSMContext Request: PDU Session Release request from AMF.");
std::shared_ptr<itti_n11_release_sm_context_request> itti_msg =
std::make_shared<itti_n11_release_sm_context_request>(TASK_SMF_N11,
TASK_SMF_APP,
response,
smContextRef);
//Step 3. Handle the itti_n11_update_sm_context_request message in smf_app
//std::shared_ptr<itti_n11_update_sm_context_request> itti_msg = std::make_shared<itti_n11_update_sm_context_request>(TASK_SMF_N11, TASK_SMF_APP, response, smContextRef);
//itti_msg->req = sm_context_req_msg;
//itti_msg->scid = smContextRef;
//m_smf_app->handle_pdu_session_update_sm_context_request(itti_msg);
itti_msg->scid = smContextRef;
m_smf_app->handle_pdu_session_release_sm_context_request(itti_msg);
}
......
......@@ -76,7 +76,7 @@ class IndividualSMContextApiImpl :
void release_sm_context(
const std::string &smContextRef,
const SmContextReleaseMessage &smContextReleaseMessage,
const SmContextReleaseData &smContextReleaseData,
Pistache::Http::ResponseWriter &response);
void retrieve_sm_context(const std::string &smContextRef,
const SmContextRetrieveData &smContextRetrieveData,
......
......@@ -346,4 +346,86 @@ class itti_n11_n1n2_message_transfer_response_status : public itti_n11_msg {
};
//-----------------------------------------------------------------------------
class itti_n11_release_sm_context_request : public itti_n11_msg {
public:
itti_n11_release_sm_context_request(const task_id_t orig,
const task_id_t dest,
Pistache::Http::ResponseWriter &response)
:
itti_n11_msg(N11_SESSION_RELEASE_SM_CONTEXT_REQUEST, orig, dest),
http_response(response) {
}
itti_n11_release_sm_context_request(const task_id_t orig,
const task_id_t dest,
Pistache::Http::ResponseWriter &response,
const std::string id)
:
itti_n11_msg(N11_SESSION_RELEASE_SM_CONTEXT_REQUEST, orig, dest),
http_response(response),
scid(id) {
}
itti_n11_release_sm_context_request(
const itti_n11_release_sm_context_request &i)
:
itti_n11_msg(i),
http_response(i.http_response),
scid(i.scid),
req(i.req) {
}
itti_n11_release_sm_context_request(
const itti_n11_release_sm_context_request &i, const task_id_t orig,
const task_id_t dest)
:
itti_n11_msg(i, orig, dest),
http_response(i.http_response),
scid(i.scid),
req(i.req) {
}
const char* get_msg_name() {
return "N11_SESSION_RELEASE_SM_CONTEXT_REQUEST";
}
;
smf::pdu_session_release_sm_context_request req;
Pistache::Http::ResponseWriter &http_response;
std::string scid; //SM Context ID
};
//-----------------------------------------------------------------------------
class itti_n11_release_sm_context_response : public itti_n11_msg {
public:
itti_n11_release_sm_context_response(const task_id_t orig,
const task_id_t dest,
Pistache::Http::ResponseWriter &response)
:
itti_n11_msg(N11_SESSION_RELEASE_SM_CONTEXT_RESPONSE, orig, dest),
http_response(response.clone()),
res() {
}
itti_n11_release_sm_context_response(
const itti_n11_release_sm_context_response &i)
:
itti_n11_msg(i),
res(i.res),
http_response(i.http_response.clone()) {
}
itti_n11_release_sm_context_response(
const itti_n11_release_sm_context_response &i, const task_id_t orig,
const task_id_t dest)
:
itti_n11_msg(i, orig, dest),
res(i.res),
http_response(i.http_response.clone()) {
}
const char* get_msg_name() {
return "N11_SESSION_RELEASE_SM_CONTEXT_RESPONSE";
}
;
smf::pdu_session_release_sm_context_response res;
Pistache::Http::ResponseWriter http_response;
};
#endif /* ITTI_MSG_N11_HPP_INCLUDED_ */
......@@ -114,6 +114,8 @@ typedef enum {
N11_SESSION_MODIFICATION_REQUEST_SMF_REQUESTED,
N11_SESSION_UPDATE_PDU_SESSION_STATUS,
N11_SESSION_N1N2_MESSAGE_TRANSFER_RESPONSE_STATUS,
N11_SESSION_RELEASE_SM_CONTEXT_REQUEST,
N11_SESSION_RELEASE_SM_CONTEXT_RESPONSE,
NX_SESSION_MODIFICATION_REQUEST_NETWORK_REQUESTED,
UDP_INIT,
UDP_DATA_REQ,
......
......@@ -542,7 +542,7 @@ void smf_app::handle_pdu_session_create_sm_context_request(
smContextCreateError.setN1SmMsg(refToBinaryData);
//PDU Session Establishment Reject
smf_n1_n2_inst.create_n1_sm_container(smreq->req,
PDU_SESSION_ESTABLISHMENT_REJECT,
PDU_SESSION_ESTABLISHMENT_REJECT,
n1_sm_message, cause_n1);
smf_app_inst->convert_string_2_hex(n1_sm_message, n1_sm_message_hex);
smf_n11_inst->send_pdu_session_create_sm_context_response(
......@@ -844,6 +844,85 @@ void smf_app::handle_pdu_session_update_sm_context_request(
}
//------------------------------------------------------------------------------
void smf_app::handle_pdu_session_release_sm_context_request(
std::shared_ptr<itti_n11_release_sm_context_request> smreq) {
//TODO:
//handle PDU Session Release SM Context Request
Logger::smf_app().info(
"Handle a PDU Session Release SM Context Request from an AMF");
//Step 1. get supi, dnn, nssai, pdu_session id from sm_context
//SM Context ID - uint32_t in our case
scid_t scid = { };
try {
scid = std::stoi(smreq->scid);
} catch (const std::exception &err) {
Logger::smf_app().warn(
"Received a PDU Session Release SM Context Request, couldn't retrieve the corresponding SMF context, ignore message!");
smf_n11_inst->send_pdu_session_release_sm_context_response(
smreq->http_response, Pistache::Http::Code::Not_Found);
return;
}
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);
smf_n11_inst->send_pdu_session_release_sm_context_response(
smreq->http_response, Pistache::Http::Code::Not_Found);
return;
}
//Step 2. store supi, dnn, nssai in itti_n11_update_sm_context_request to be processed later on
supi64_t supi64 = smf_supi_to_u64(scf.get()->supi);
smreq->req.set_supi(scf.get()->supi);
smreq->req.set_dnn(scf.get()->dnn);
smreq->req.set_snssai(scf.get()->nssai);
smreq->req.set_pdu_session_id(scf.get()->pdu_session_id);
//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 {
//send PDUSession_SMReleaseContext Response to AMF
Logger::smf_app().warn(
"Received PDU Session Release SM Context Request with Supi " SUPI_64_FMT "couldn't retrieve the corresponding SMF context, ignore message!",
supi64);
smf_n11_inst->send_pdu_session_release_sm_context_response(
smreq->http_response, Pistache::Http::Code::Not_Found);
return;
}
//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, send PDUSession_SMUpdateContext Response to AMF
Logger::smf_app().warn(
"Received PDU Session Release SM Context Request, couldn't retrieve the corresponding SMF context, ignore message!");
smf_n11_inst->send_pdu_session_release_sm_context_response(
smreq->http_response, Pistache::Http::Code::Not_Found);
return;
}
}
//Step 3. handle the message in smf_context
sc.get()->handle_pdu_session_release_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 =
......
......@@ -209,6 +209,14 @@ class smf_app {
void handle_pdu_session_update_sm_context_request(
std::shared_ptr<itti_n11_update_sm_context_request> smreq);
/*
* Handle PDUSession_ReleaseSMContextRequest from AMF
* @param [std::shared_ptr<itti_n11_release_sm_context_request>&] Request message
* @return void
*/
void handle_pdu_session_release_sm_context_request(
std::shared_ptr<itti_n11_release_sm_context_request> smreq);
/*
* Handle network-requested pdu session modification
* @param should be updated
......
......@@ -2269,6 +2269,64 @@ void smf_context::handle_pdu_session_update_sm_context_request(
}
//-------------------------------------------------------------------------------------
void smf_context::handle_pdu_session_release_sm_context_request(
std::shared_ptr<itti_n11_release_sm_context_request> smreq) {
Logger::smf_app().info(
"Handle a PDU Session Release SM Context Request message from AMF");
bool update_upf = false;
//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(smreq->req.get_snssai(),
smreq->req.get_dnn(), sd);
bool find_pdu = false;
if (find_dnn) {
find_pdu = sd.get()->find_pdu_session(
smreq->req.get_pdu_session_id(), sp);
}
if (!find_dnn or !find_pdu) {
//error, send reply to AMF with error code "Context Not Found"
Logger::smf_app().warn("DNN or PDU session context does not exist!");
smf_n11_inst->send_pdu_session_release_sm_context_response(
smreq->http_response,
Pistache::Http::Code::Not_Found);
return;
}
//we need to store HttpResponse and session-related information to be used when receiving the response from UPF
itti_n11_release_sm_context_response *n11_sm_context_resp =
new itti_n11_release_sm_context_response(TASK_SMF_APP, TASK_SMF_N11,
smreq->http_response);
std::shared_ptr<itti_n11_release_sm_context_response> sm_context_resp_pending =
std::shared_ptr<itti_n11_release_sm_context_response>(n11_sm_context_resp);
n11_sm_context_resp->res.set_supi(smreq->req.get_supi());
n11_sm_context_resp->res.set_supi_prefix(
smreq->req.get_supi_prefix());
n11_sm_context_resp->res.set_cause(REQUEST_ACCEPTED);
n11_sm_context_resp->res.set_pdu_session_id(
smreq->req.get_pdu_session_id());
n11_sm_context_resp->res.set_snssai(smreq->req.get_snssai());
n11_sm_context_resp->res.set_dnn(smreq->req.get_dnn());
session_release_sm_context_procedure *proc =
new session_release_sm_context_procedure(sp);
std::shared_ptr<smf_procedure> sproc = std::shared_ptr<smf_procedure>(proc);
insert_procedure(sproc);
if (proc->run(smreq, sm_context_resp_pending, shared_from_this())) {
// error !
Logger::smf_app().info(
"PDU Release SM Context Request procedure failed");
}
}
//------------------------------------------------------------------------------
void smf_context::insert_dnn_subscription(
const snssai_t &snssai,
......
......@@ -340,7 +340,7 @@ class smf_context : public std::enable_shared_from_this<smf_context> {
void handle_itti_msg(std::shared_ptr<itti_n4_session_report_request>&);
/*
* Handle messages from AMF (e.g., PDU_SESSION_CREATESMContextRequest)
* Handle messages from AMF (e.g., PDU_SESSION_CreateSMContextRequest)
* @param [std::shared_ptr<itti_n11_create_sm_context_request] smreq Request message
* @return void
*/
......@@ -348,14 +348,21 @@ class smf_context : public std::enable_shared_from_this<smf_context> {
std::shared_ptr<itti_n11_create_sm_context_request> smreq);
/*
* Handle messages from AMF (e.g., PDU_SESSION_UPDATESMContextRequest)
* 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_pdu_session_update_sm_context_request(
std::shared_ptr<itti_n11_update_sm_context_request> smreq);
/*
* Handle messages from AMF (e.g., PDU_SESSION_ReleaseSMContextRequest)
* @param [std::shared_ptr<itti_n11_release_sm_context_request] smreq Request message
* @return void
*/
void handle_pdu_session_release_sm_context_request(
std::shared_ptr<itti_n11_release_sm_context_request> smreq);
/*
* Find DNN context with name
* @param [const std::string&] dnn
......
......@@ -556,3 +556,14 @@ void pdu_session_update_sm_context_response::remove_all_qos_flow_context_updated
qos_flow_context_updateds.clear();
}
//-----------------------------------------------------------------------------
void pdu_session_release_sm_context_response::set_cause(uint8_t cause) {
m_cause = cause;
}
//-----------------------------------------------------------------------------
uint8_t pdu_session_release_sm_context_response::get_cause() {
return m_cause;
}
......@@ -51,6 +51,8 @@ typedef enum {
PDU_SESSION_CREATE_SM_CONTEXT_RESPONSE,
PDU_SESSION_UPDATE_SM_CONTEXT_REQUEST,
PDU_SESSION_UPDATE_SM_CONTEXT_RESPONSE,
PDU_SESSION_RELEASE_SM_CONTEXT_REQUEST,
PDU_SESSION_RELEASE_SM_CONTEXT_RESPONSE,
PDU_SESSION_MSG_TYPE_MAX
} pdu_session_msg_type_t;
......@@ -550,6 +552,34 @@ class pdu_session_update_sm_context_response : public pdu_session_msg {
};
class pdu_session_release_sm_context_request : public pdu_session_msg {
public:
pdu_session_release_sm_context_request()
:
pdu_session_msg(PDU_SESSION_RELEASE_SM_CONTEXT_REQUEST) {
}
;
private:
};
class pdu_session_release_sm_context_response : public pdu_session_msg {
public:
pdu_session_release_sm_context_response()
:
pdu_session_msg(PDU_SESSION_RELEASE_SM_CONTEXT_RESPONSE) {
m_cause = 0;
}
;
void set_cause(uint8_t cause);
uint8_t get_cause();
private:
uint8_t m_cause;
};
}
#endif
......@@ -474,6 +474,18 @@ void smf_n11::send_pdu_session_update_sm_context_response(
}
break;
case session_management_procedures_type_e::PDU_SESSION_RELEASE_UE_REQUESTED_STEP2: {
Logger::smf_n11().info("PDU_SESSION_RELEASE_UE_REQUESTED (step 2)");
sm_context_res->http_response.send(Pistache::Http::Code::No_Content);
}
break;
case session_management_procedures_type_e::PDU_SESSION_RELEASE_UE_REQUESTED_STEP3: {
Logger::smf_n11().info("PDU_SESSION_RELEASE_UE_REQUESTED (step 3)");
sm_context_res->http_response.send(Pistache::Http::Code::No_Content);
}
break;
default: {
Logger::smf_n11().debug("Session management procedure: unknown!");
}
......@@ -592,6 +604,33 @@ void smf_n11::send_n1n2_message_transfer_request(
//TODO:
}
//------------------------------------------------------------------------------
void smf_n11::send_pdu_session_release_sm_context_response(
Pistache::Http::ResponseWriter &httpResponse, Pistache::Http::Code code) {
Logger::smf_n11().debug(
"[SMF N11] Send PDUSessionReleaseContextResponse to AMF!");
httpResponse.send(code);
}
//------------------------------------------------------------------------------
void smf_n11::send_pdu_session_release_sm_context_response(
Pistache::Http::ResponseWriter &httpResponse,
oai::smf_server::model::ProblemDetails &problem,
Pistache::Http::Code code) {
Logger::smf_n11().debug(
"[SMF N11] Send PDUSessionReleaseContextResponse to AMF!");
nlohmann::json json_data = { };
to_json(json_data, problem);
if (!json_data.empty()) {
httpResponse.headers().add<Pistache::Http::Header::ContentType>(
Pistache::Http::Mime::MediaType("application/json"));
httpResponse.send(code, json_data.dump().c_str());
} else {
httpResponse.send(code);
}
}
//------------------------------------------------------------------------------
void smf_n11::create_multipart_related_content(std::string &body,
std::string &json_part,
......
......@@ -152,6 +152,27 @@ class smf_n11 {
oai::smf_server::model::SmContextCreatedData &smContextCreatedData,
Pistache::Http::Code code);
/*
* Send release session response to AMF
* @param [Pistache::Http::ResponseWriter] httpResponse
* @param [Pistache::Http::Code] code, response code
*
*/
void send_pdu_session_release_sm_context_response(
Pistache::Http::ResponseWriter &httpResponse, Pistache::Http::Code code);
/*
* Send release session response to AMF
* @param [Pistache::Http::ResponseWriter] httpResponse
* @param [oai::smf_server::model::ProblemDetails] problem
* @param [Pistache::Http::Code] code, response code
*