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

Merge branch 'n2_handover' into 'develop'

N2 handover

See merge request !62
parents fab3bec1 40751a58
......@@ -55,6 +55,6 @@ Based on document **3GPP TS 23.501 v16.0.0 (Section 6.2.2)**.
| 12 | Determine SSC mode of a session​ | :heavy_check_mark: | Only support SSC mode 1​ |
| 13 | Initiator of AN specific SM information, sent via AMF over N2 to AN | :heavy_check_mark: | |
| 14 | Support for Control Plane CIoT 5GS Optimisation | :x: | |
| 15 | Support of header compression. ​ | :x: | |
| 15 | Support of header compression ​ | :x: | |
| 16 | Act as I-SMF in deployments | :x: | |
| 17 | Provisioning of external parameters | :x: | |
......@@ -96,9 +96,12 @@ void IndividualSMContextApi::release_sm_context_handler(
Logger::smf_api_server().debug("Request body: %s\n", request.body().c_str());
SmContextReleaseMessage smContextReleaseMessage = {};
// simple parser
// Simple parser
mime_parser sp = {};
sp.parse(request.body());
if (!sp.parse(request.body())) {
response.send(Pistache::Http::Code::Bad_Request);
return;
}
std::vector<mime_part> parts = {};
sp.get_mime_parts(parts);
......@@ -178,9 +181,12 @@ void IndividualSMContextApi::update_sm_context_handler(
Logger::smf_api_server().debug("Request body: %s\n", request.body().c_str());
SmContextUpdateMessage smContextUpdateMessage = {};
// simple parser
// Simple parser
mime_parser sp = {};
sp.parse(request.body());
if (!sp.parse(request.body())) {
response.send(Pistache::Http::Code::Bad_Request);
return;
}
std::vector<mime_part> parts = {};
sp.get_mime_parts(parts);
......
......@@ -88,25 +88,28 @@ void SMContextsCollectionApi::post_sm_contexts_handler(
SmContextMessage smContextMessage = {};
SmContextCreateData smContextCreateData = {};
// simple parser
// Simple parser
mime_parser sp = {};
sp.parse(request.body());
if (!sp.parse(request.body())) {
response.send(Pistache::Http::Code::Bad_Request);
return;
}
std::vector<mime_part> parts = {};
sp.get_mime_parts(parts);
uint8_t size = parts.size();
Logger::smf_api_server().debug("Number of MIME parts %d", size);
// at least 2 parts for Json data and N1 (+ N2)
// At least 2 parts for Json data and N1 (+ N2)
if (size < 2) {
response.send(Pistache::Http::Code::Bad_Request);
return;
}
// step 2. process the request
// Step 2. process the request
try {
nlohmann::json::parse(parts[0].body.c_str()).get_to(smContextCreateData);
smContextMessage.setJsonData(smContextCreateData);
// must include N1 NAS msg
// Must include N1 NAS msg
if (parts[1].content_type.compare("application/vnd.3gpp.5gnas") == 0) {
smContextMessage.setBinaryDataN1SmMessage(parts[1].body);
} else {
......
......@@ -53,7 +53,7 @@ void SubscriptionsCollectionApi::create_individual_subcription_handler(
Pistache::Http::ResponseWriter response) {
// Getting the body param
NsmfEventExposure nsmfEventExposure;
NsmfEventExposure nsmfEventExposure = {};
try {
nlohmann::json::parse(request.body()).get_to(nsmfEventExposure);
......
......@@ -17,7 +17,21 @@ namespace oai {
namespace smf_server {
namespace model {
GlobalRanNodeId::GlobalRanNodeId() {}
GlobalRanNodeId::GlobalRanNodeId() {
m_N3IwfId = "";
m_N3IwfIdIsSet = false;
m_GNbIdIsSet = false;
m_NgeNbId = "";
m_NgeNbIdIsSet = false;
m_WagfId = "";
m_WagfIdIsSet = false;
m_TngfId = "";
m_TngfIdIsSet = false;
m_Nid = "";
m_NidIsSet = false;
m_ENbId = "";
m_ENbIdIsSet = false;
}
GlobalRanNodeId::~GlobalRanNodeId() {}
......@@ -26,10 +40,146 @@ void GlobalRanNodeId::validate() {
}
void to_json(nlohmann::json& j, const GlobalRanNodeId& o) {
j = nlohmann::json();
j = nlohmann::json();
j["plmnId"] = o.m_PlmnId;
if (o.n3IwfIdIsSet()) j["n3IwfId"] = o.m_N3IwfId;
if (o.gNbIdIsSet()) j["gNbId"] = o.m_GNbId;
if (o.ngeNbIdIsSet()) j["ngeNbId"] = o.m_NgeNbId;
if (o.wagfIdIsSet()) j["wagfId"] = o.m_WagfId;
if (o.tngfIdIsSet()) j["tngfId"] = o.m_TngfId;
if (o.nidIsSet()) j["nid"] = o.m_Nid;
if (o.eNbIdIsSet()) j["eNbId"] = o.m_ENbId;
}
void from_json(const nlohmann::json& j, GlobalRanNodeId& o) {
j.at("plmnId").get_to(o.m_PlmnId);
if (j.find("n3IwfId") != j.end()) {
j.at("n3IwfId").get_to(o.m_N3IwfId);
o.m_N3IwfIdIsSet = true;
}
if (j.find("gNbId") != j.end()) {
j.at("gNbId").get_to(o.m_GNbId);
o.m_GNbIdIsSet = true;
}
if (j.find("ngeNbId") != j.end()) {
j.at("ngeNbId").get_to(o.m_NgeNbId);
o.m_NgeNbIdIsSet = true;
}
if (j.find("wagfId") != j.end()) {
j.at("wagfId").get_to(o.m_WagfId);
o.m_WagfIdIsSet = true;
}
if (j.find("tngfId") != j.end()) {
j.at("tngfId").get_to(o.m_TngfId);
o.m_TngfIdIsSet = true;
}
if (j.find("nid") != j.end()) {
j.at("nid").get_to(o.m_Nid);
o.m_NidIsSet = true;
}
if (j.find("eNbId") != j.end()) {
j.at("eNbId").get_to(o.m_ENbId);
o.m_ENbIdIsSet = true;
}
}
void from_json(const nlohmann::json& j, GlobalRanNodeId& o) {}
PlmnId GlobalRanNodeId::getPlmnId() const {
return m_PlmnId;
}
void GlobalRanNodeId::setPlmnId(PlmnId const& value) {
m_PlmnId = value;
}
std::string GlobalRanNodeId::getN3IwfId() const {
return m_N3IwfId;
}
void GlobalRanNodeId::setN3IwfId(std::string const& value) {
m_N3IwfId = value;
m_N3IwfIdIsSet = true;
}
bool GlobalRanNodeId::n3IwfIdIsSet() const {
return m_N3IwfIdIsSet;
}
void GlobalRanNodeId::unsetN3IwfId() {
m_N3IwfIdIsSet = false;
}
GNbId GlobalRanNodeId::getGNbId() const {
return m_GNbId;
}
void GlobalRanNodeId::setGNbId(GNbId const& value) {
m_GNbId = value;
m_GNbIdIsSet = true;
}
bool GlobalRanNodeId::gNbIdIsSet() const {
return m_GNbIdIsSet;
}
void GlobalRanNodeId::unsetGNbId() {
m_GNbIdIsSet = false;
}
std::string GlobalRanNodeId::getNgeNbId() const {
return m_NgeNbId;
}
void GlobalRanNodeId::setNgeNbId(std::string const& value) {
m_NgeNbId = value;
m_NgeNbIdIsSet = true;
}
bool GlobalRanNodeId::ngeNbIdIsSet() const {
return m_NgeNbIdIsSet;
}
void GlobalRanNodeId::unsetNgeNbId() {
m_NgeNbIdIsSet = false;
}
std::string GlobalRanNodeId::getWagfId() const {
return m_WagfId;
}
void GlobalRanNodeId::setWagfId(std::string const& value) {
m_WagfId = value;
m_WagfIdIsSet = true;
}
bool GlobalRanNodeId::wagfIdIsSet() const {
return m_WagfIdIsSet;
}
void GlobalRanNodeId::unsetWagfId() {
m_WagfIdIsSet = false;
}
std::string GlobalRanNodeId::getTngfId() const {
return m_TngfId;
}
void GlobalRanNodeId::setTngfId(std::string const& value) {
m_TngfId = value;
m_TngfIdIsSet = true;
}
bool GlobalRanNodeId::tngfIdIsSet() const {
return m_TngfIdIsSet;
}
void GlobalRanNodeId::unsetTngfId() {
m_TngfIdIsSet = false;
}
std::string GlobalRanNodeId::getNid() const {
return m_Nid;
}
void GlobalRanNodeId::setNid(std::string const& value) {
m_Nid = value;
m_NidIsSet = true;
}
bool GlobalRanNodeId::nidIsSet() const {
return m_NidIsSet;
}
void GlobalRanNodeId::unsetNid() {
m_NidIsSet = false;
}
std::string GlobalRanNodeId::getENbId() const {
return m_ENbId;
}
void GlobalRanNodeId::setENbId(std::string const& value) {
m_ENbId = value;
m_ENbIdIsSet = true;
}
bool GlobalRanNodeId::eNbIdIsSet() const {
return m_ENbIdIsSet;
}
void GlobalRanNodeId::unsetENbId() {
m_ENbIdIsSet = false;
}
} // namespace model
} // namespace smf_server
......
......@@ -19,6 +19,9 @@
#ifndef GlobalRanNodeId_H_
#define GlobalRanNodeId_H_
#include <string>
#include "GNbId.h"
#include "PlmnId.h"
#include <nlohmann/json.hpp>
namespace oai {
......@@ -38,10 +41,81 @@ class GlobalRanNodeId {
/////////////////////////////////////////////
/// GlobalRanNodeId members
/// <summary>
///
/// </summary>
PlmnId getPlmnId() const;
void setPlmnId(PlmnId const& value);
/// <summary>
///
/// </summary>
std::string getN3IwfId() const;
void setN3IwfId(std::string const& value);
bool n3IwfIdIsSet() const;
void unsetN3IwfId();
/// <summary>
///
/// </summary>
GNbId getGNbId() const;
void setGNbId(GNbId const& value);
bool gNbIdIsSet() const;
void unsetGNbId();
/// <summary>
///
/// </summary>
std::string getNgeNbId() const;
void setNgeNbId(std::string const& value);
bool ngeNbIdIsSet() const;
void unsetNgeNbId();
/// <summary>
///
/// </summary>
std::string getWagfId() const;
void setWagfId(std::string const& value);
bool wagfIdIsSet() const;
void unsetWagfId();
/// <summary>
///
/// </summary>
std::string getTngfId() const;
void setTngfId(std::string const& value);
bool tngfIdIsSet() const;
void unsetTngfId();
/// <summary>
///
/// </summary>
std::string getNid() const;
void setNid(std::string const& value);
bool nidIsSet() const;
void unsetNid();
/// <summary>
///
/// </summary>
std::string getENbId() const;
void setENbId(std::string const& value);
bool eNbIdIsSet() const;
void unsetENbId();
friend void to_json(nlohmann::json& j, const GlobalRanNodeId& o);
friend void from_json(const nlohmann::json& j, GlobalRanNodeId& o);
protected:
PlmnId m_PlmnId;
std::string m_N3IwfId;
bool m_N3IwfIdIsSet;
GNbId m_GNbId;
bool m_GNbIdIsSet;
std::string m_NgeNbId;
bool m_NgeNbIdIsSet;
std::string m_WagfId;
bool m_WagfIdIsSet;
std::string m_TngfId;
bool m_TngfIdIsSet;
std::string m_Nid;
bool m_NidIsSet;
std::string m_ENbId;
bool m_ENbIdIsSet;
};
} // namespace model
......
......@@ -27,9 +27,12 @@ void HoState::validate() {
void to_json(nlohmann::json& j, const HoState& o) {
j = nlohmann::json();
j = o.state;
}
void from_json(const nlohmann::json& j, HoState& o) {}
void from_json(const nlohmann::json& j, HoState& o) {
o.state = j.get<std::string>();
}
} // namespace model
} // namespace smf_server
......
......@@ -37,6 +37,7 @@ class HoState {
/////////////////////////////////////////////
/// HoState members
std::string state;
friend void to_json(nlohmann::json& j, const HoState& o);
friend void from_json(const nlohmann::json& j, HoState& o);
......
......@@ -85,7 +85,13 @@ void smf_http2_server::start() {
// simple parser
mime_parser sp = {};
sp.parse(msg);
if (!sp.parse(msg)) {
// send reply!!!
response.write_head(
http_status_code_e::HTTP_STATUS_CODE_400_BAD_REQUEST);
response.end();
return;
}
std::vector<mime_part> parts = {};
sp.get_mime_parts(parts);
......@@ -176,7 +182,13 @@ void smf_http2_server::start() {
// simple parser
mime_parser sp = {};
sp.parse(msg);
if (!sp.parse(msg)) {
// send reply!!!
response.write_head(
http_status_code_e::HTTP_STATUS_CODE_400_BAD_REQUEST);
response.end();
return;
}
std::vector<mime_part> parts = {};
sp.get_mime_parts(parts);
......@@ -235,7 +247,13 @@ void smf_http2_server::start() {
// simple parser
mime_parser sp = {};
sp.parse(msg);
if (!sp.parse(msg)) {
// send reply!!!
response.write_head(
http_status_code_e::HTTP_STATUS_CODE_400_BAD_REQUEST);
response.end();
return;
}
std::vector<mime_part> parts = {};
sp.get_mime_parts(parts);
......
......@@ -148,4 +148,15 @@ static const std::vector<std::string> upCnx_state_e2str = {
"UPCNX_STATE_ACTIVATED", "UPCNX_STATE_DEACTIVATED",
"UPCNX_STATE_ACTIVATING"};
enum class ho_state_e {
HO_STATE_NONE = 0,
HO_STATE_PREPARING = 1,
HO_STATE_PREPARED = 2,
HO_STATE_COMPLETED = 3,
HO_STATE_CANCELLED = 4
};
static const std::vector<std::string> ho_state_e2str = {
"NONE", "PREPARING", "PREPARED", "COMPLETED", "CANCELLED"};
#endif
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this
* file except in compliance with the License. You may obtain a copy of the
* License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#ifndef FILE_3GPP_29_518_SMF_SEEN
#define FILE_3GPP_29_518_SMF_SEEN
#include "3gpp_29.571.h"
#include "3gpp_23.003.h"
typedef struct ng_ran_target_id_s {
global_ran_node_id_t global_ran_node_id;
tai_t tai;
} ng_ran_target_id_t;
#endif
......@@ -51,4 +51,16 @@ enum reflective_qos_attribute_e { RQOS = 1, NO_RQOS = 2 };
static const std::vector<std::string> reflective_qos_attribute_e2str = {
"ERROR", "RQOS", "NO_RQOS"};
typedef struct gNB_id_s {
uint8_t bit_length;
std::string gNB_value;
} gNB_id_t; // 22bits to 32bits
typedef struct global_ran_node_id_s {
plmn_t plmn_id;
// n3IwfId:
gNB_id_t gNbId;
// ngeNbId:
} global_ran_node_id_t;
#endif
......@@ -182,35 +182,6 @@ class itti_n11_update_sm_context_response : public itti_n11_msg {
session_management_procedures_type_e session_procedure_type;
};
//-----------------------------------------------------------------------------
class itti_n11_update_pdu_session_status : public itti_n11_msg {
public:
itti_n11_update_pdu_session_status(const task_id_t orig, const task_id_t dest)
: itti_n11_msg(N11_SESSION_UPDATE_PDU_SESSION_STATUS, orig, dest),
scid(0),
pdu_session_status(pdu_session_status_e::PDU_SESSION_INACTIVE) {}
itti_n11_update_pdu_session_status(
const itti_n11_update_pdu_session_status& i)
: itti_n11_msg(i),
scid(i.scid),
pdu_session_status(i.pdu_session_status) {}
itti_n11_update_pdu_session_status(
const itti_n11_update_pdu_session_status& i, const task_id_t orig,
const task_id_t dest)
: itti_n11_msg(i, orig, dest),
scid(i.scid),
pdu_session_status(i.pdu_session_status) {}
const char* get_msg_name() {
return "N11_SESSION_UPDATE_PDU_SESSION_STATUS";
};
void set_scid(scid_t id) { scid = id; };
scid_t scid; // SM Context ID
pdu_session_status_e pdu_session_status;
void set_pdu_session_status(pdu_session_status_e status) {
pdu_session_status = status;
};
};
//-----------------------------------------------------------------------------
class itti_n11_n1n2_message_transfer_response_status : public itti_n11_msg {
public:
......
......@@ -123,11 +123,17 @@ enum class session_management_procedures_type_e {
PDU_SESSION_RELEASE_SMF_INITIATED = 13,
PDU_SESSION_RELEASE_AMF_INITIATED = 14,
PDU_SESSION_RELEASE_AN_INITIATED = 15,
PDU_SESSION_TEST = 16
HO_PATH_SWITCH_REQ = 16,
N2_HO_PREPARATION_PHASE_STEP1 = 17,
N2_HO_PREPARATION_PHASE_STEP2 = 18,
N2_HO_EXECUTION_PHASE = 19,
N2_HO_CANCELLATION_PHASE = 20,
PDU_SESSION_TEST = 21
};
static const std::vector<std::string> session_management_procedures_type_e2str =
{"PDU_SESSION_ESTABLISHMENT_UE_REQUESTED",
{"PROCEDURE_TYPE_UNKNOWN",
"PDU_SESSION_ESTABLISHMENT_UE_REQUESTED",
"SERVICE_REQUEST_UE_TRIGGERED_STEP1",
"SERVICE_REQUEST_UE_TRIGGERED_STEP2",
"SERVICE_REQUEST_NETWORK_TRIGGERED",
......@@ -142,6 +148,10 @@ static const std::vector<std::string> session_management_procedures_type_e2str =
"PDU_SESSION_RELEASE_SMF_INITIATED",
"PDU_SESSION_RELEASE_AMF_INITIATED",
"PDU_SESSION_RELEASE_AN_INITIATED",
"HO_PATH_SWITCH_REQ",
"N2_HO_PREPARATION_PHASE_STEP1",
"N2_HO_PREPARATION_PHASE_STEP2",
"N2_HO_EXECUTION_PHASE",
"PDU_SESSION_TEST"
};
......
......@@ -38,6 +38,7 @@
#include "3gpp_29.500.h"
#include "3gpp_24.501.h"
#include "conversions.hpp"
#include "NgRanTargetId.h"
//------------------------------------------------------------------------------
void xgpp_conv::paa_to_pfcp_ue_ip_address(
......@@ -365,6 +366,62 @@ void xgpp_conv::sm_context_update_from_openapi(
// Flow is released) step 7a, SM Context ID, N2 SM information, UE location
// information Step 11, SM Context ID, N1 SM (PDU Session Modification Command
// ACK), User location
// For Xn Handover
if (context_data.toBeSwitchedIsSet()) {
pur.set_to_be_switched(context_data.isToBeSwitched());
}
// TODO: additional N2 SM information received from the source 5G-AN
if (context_data.failedToBeSwitchedIsSet()) {
pur.set_failed_to_be_switched(context_data.isFailedToBeSwitched());
}
// For N2 Handover,
// HO state
if (context_data.hoStateIsSet()) {
std::string state = context_data.getHoState().state;
pur.set_ho_state(state);
}
// Target ID
if (context_data.targetIdIsSet()) {
oai::smf_server::model::NgRanTargetId api_target_id =
context_data.getTargetId();
ng_ran_target_id_t ran_target_id = {};
if (!conv::plmnFromString(
ran_target_id.global_ran_node_id.plmn_id,
api_target_id.getTai().getPlmnId().getMcc(),
api_target_id.getTai().getPlmnId().getMnc())) {
Logger::smf_app().warn("Error while converting MCC, MNC to PLMN");
}
ran_target_id.global_ran_node_id.gNbId.bit_length =
api_target_id.getRanNodeId().getGNbId().getBitLength();
ran_target_id.global_ran_node_id.gNbId.gNB_value =
api_target_id.getRanNodeId().getGNbId().getGNBValue();
if (!conv::plmnFromString(
ran_target_id.tai.plmn, api_target_id.getTai().getPlmnId().getMcc(),
api_target_id.getTai().getPlmnId().getMnc())) {
Logger::smf_app().warn("Error while converting MCC, MNC to PLMN");
}
try {
// string to uint16_t
ran_target_id.tai.tac =