Commit 2cb6671b authored by Tien-Thinh Nguyen's avatar Tien-Thinh Nguyen

Merge branch 'fix_n2_handover' into 'develop'

Fix n2 handover

See merge request oai/cn5g/oai-cn5g-amf!36
parents 8f5c3c14 2025ea76
......@@ -45,7 +45,7 @@ Based on document **3GPP TS 23.501 V16.0.0 §6.2.1**.
| 4 | Registration management | :heavy_check_mark: | |
| 5 | Connection management | :heavy_check_mark: | |
| 6 | Reachability management | :x: | |
| 7 | Mobility Management | :x: | |
| 7 | Mobility Management | :heavy_check_mark: | (Experimental) Support N2 Handover |
| 8 | Lawful intercept (for AMF events and interface to LI System) | :x: | |
| 9 | Provide transport for SM messages between UE and SMF | :heavy_check_mark: | |
| 10 | Transparent proxy for routing SM messages | :x: | |
......
......@@ -224,6 +224,8 @@ void amf_n11::handle_itti_message(
pdu_session_update_request["hoState"] = "PREPARING";
} else if (itti_msg.n2sm_info_type.compare("HANDOVER_REQ_ACK") == 0) {
pdu_session_update_request["hoState"] = "PREPARED";
} else if (itti_msg.n2sm_info_type.compare("SECONDARY_RAT_USAGE") == 0) {
pdu_session_update_request["hoState"] = "COMPLETED";
}
curl_http_client(
......@@ -666,37 +668,45 @@ void amf_n11::curl_http_client(
}
}
// Transfer N1/N2 to gNB/UE if available
if (number_parts > 1) {
try {
response_data = nlohmann::json::parse(json_data_response);
} catch (nlohmann::json::exception& e) {
Logger::amf_n11().warn(
"Could not get Json content from the response");
curl_slist_free_all(headers);
curl_easy_cleanup(curl);
curl_global_cleanup();
free_wrapper((void**) &body_data);
// TODO:
return;
}
try {
response_data = nlohmann::json::parse(json_data_response);
} catch (nlohmann::json::exception& e) {
Logger::amf_n11().warn("Could not get Json content from the response");
curl_slist_free_all(headers);
curl_easy_cleanup(curl);
curl_global_cleanup();
free_wrapper((void**) &body_data);
// TODO:
return;
}
// For N2 HO
bool is_ho_procedure = false;
if (response_data.find("hoState") != response_data.end()) {
is_ho_procedure = true;
}
// Notify to the result
if ((promise_id > 0) and (is_ho_procedure)) {
amf_app_inst->trigger_process_response(
promise_id, n1sm); // actually, N2 SM Info
curl_slist_free_all(headers);
curl_easy_cleanup(curl);
curl_global_cleanup();
free_wrapper((void**) &body_data);
return;
// For N2 HO
bool is_ho_procedure = false;
std::string promise_result = {};
if (response_data.find("hoState") != response_data.end()) {
is_ho_procedure = true;
std::string ho_state = {};
response_data.at("hoState").get_to(ho_state);
if (ho_state.compare("COMPLETED") == 0) {
if (response_data.find("pduSessionId") != response_data.end())
response_data.at("pduSessionId").get_to(promise_result);
} else if (number_parts > 1) {
promise_result = n1sm; // actually, N2 SM Info
}
}
// Notify to the result
if ((promise_id > 0) and (is_ho_procedure)) {
amf_app_inst->trigger_process_response(promise_id, promise_result);
curl_slist_free_all(headers);
curl_easy_cleanup(curl);
curl_global_cleanup();
free_wrapper((void**) &body_data);
return;
}
// Transfer N1/N2 to gNB/UE if available
if (number_parts > 1) {
itti_n1n2_message_transfer_request* itti_msg =
new itti_n1n2_message_transfer_request(TASK_AMF_N11, TASK_AMF_APP);
......
......@@ -1402,6 +1402,10 @@ void amf_n2::handle_itti_message(itti_handover_request_Ack& itti_msg) {
(long) QosFlowWithDataForwardinglist[0].qosFlowIdentifier;
Logger::ngap().debug("QFI %lu", qosflowidentifiervalue);
std::shared_ptr<nas_context> nc =
amf_n1_inst->amf_ue_id_2_nas_context(amf_ue_ngap_id);
string supi = "imsi-" + nc.get()->imsi;
// Send PDUSessionUpdateSMContextRequest to SMF for each active PDU sessions
std::map<uint8_t, boost::shared_future<std::string>> curl_responses;
......@@ -1449,8 +1453,6 @@ void amf_n2::handle_itti_message(itti_handover_request_Ack& itti_msg) {
handovercommand->setAmfUeNgapId(amf_ue_ngap_id);
handovercommand->setRanUeNgapId(unc.get()->ran_ue_ngap_id);
handovercommand->setHandoverType(Ngap_HandoverType_intra5gs);
std::shared_ptr<nas_context> nc =
amf_n1_inst->amf_ue_id_2_nas_context(amf_ue_ngap_id);
std::vector<PDUSessionResourceHandoverItem_t> handover_list;
PDUSessionResourceHandoverItem_t item = {};
......@@ -1483,7 +1485,11 @@ void amf_n2::handle_itti_message(itti_handover_request_Ack& itti_msg) {
handover_list.push_back(item);
// free memory
free_wrapper((void**) &data);
std::shared_ptr<pdu_session_context> psc = {};
if (amf_app_inst->find_pdu_session_context(
supi, item.pduSessionId, psc)) {
psc.get()->is_ho_accepted = true;
}
} else {
result = false;
}
......@@ -1562,6 +1568,84 @@ void amf_n2::handle_itti_message(itti_handover_notify& itti_msg) {
return;
}
std::shared_ptr<nas_context> nc =
amf_n1_inst->amf_ue_id_2_nas_context(amf_ue_ngap_id);
string supi = "imsi-" + nc.get()->imsi;
std::vector<std::shared_ptr<pdu_session_context>> sessions_ctx;
if (!amf_app_inst->get_pdu_sessions_context(supi, sessions_ctx)) {
}
// Send PDUSessionUpdateSMContextRequest to SMF for accepted PDU sessions
std::map<uint8_t, boost::shared_future<std::string>> curl_responses;
for (auto pdu_session : sessions_ctx) {
if (pdu_session.get()->is_ho_accepted) {
// Generate a promise and associate this promise to the curl handle
uint32_t promise_id = amf_app_inst->generate_promise_id();
Logger::amf_n2().debug("Promise ID generated %d", promise_id);
boost::shared_ptr<boost::promise<std::string>> p =
boost::make_shared<boost::promise<std::string>>();
boost::shared_future<std::string> f = p->get_future();
amf_app_inst->add_promise(promise_id, p);
curl_responses.emplace(pdu_session.get()->pdu_session_id, f);
Logger::amf_n2().debug(
"Sending ITTI to trigger PDUSessionUpdateSMContextRequest to SMF to "
"task TASK_AMF_N11");
itti_nsmf_pdusession_update_sm_context* itti_msg =
new itti_nsmf_pdusession_update_sm_context(TASK_NGAP, TASK_AMF_N11);
itti_msg->pdu_session_id = pdu_session.get()->pdu_session_id;
// TODO: Secondary RAT Usage
itti_msg->n2sm = blk2bstr("", 0);
itti_msg->is_n2sm_set = true;
itti_msg->n2sm_info_type = "SECONDARY_RAT_USAGE";
itti_msg->amf_ue_ngap_id = amf_ue_ngap_id;
itti_msg->ran_ue_ngap_id = ran_ue_ngap_id;
itti_msg->promise_id = promise_id;
std::shared_ptr<itti_nsmf_pdusession_update_sm_context> i =
std::shared_ptr<itti_nsmf_pdusession_update_sm_context>(itti_msg);
int ret = itti_inst->send_msg(i);
if (0 != ret) {
Logger::ngap().error(
"Could not send ITTI message %s to task TASK_AMF_N11",
i->get_msg_name());
}
}
}
bool result = true;
while (!curl_responses.empty()) {
boost::future_status status;
// wait for timeout or ready
status = curl_responses.begin()->second.wait_for(
boost::chrono::milliseconds(FUTURE_STATUS_TIMEOUT_MS));
if (status == boost::future_status::ready) {
assert(curl_responses.begin()->second.is_ready());
assert(curl_responses.begin()->second.has_value());
assert(!curl_responses.begin()->second.has_exception());
// Wait for the result from APP and send reply to AMF
std::string pdu_session_id_str = curl_responses.begin()->second.get();
Logger::ngap().debug(
"Got result for PDU Session ID %d", curl_responses.begin()->first);
if (pdu_session_id_str.size() > 0) {
result = result && true;
} else {
result = false;
}
} else {
result = true;
}
curl_responses.erase(curl_responses.begin());
}
// Send UE Release Command to Source gNB
std::unique_ptr<UEContextReleaseCommandMsg> ueContextReleaseCommand =
std::make_unique<UEContextReleaseCommandMsg>();
ueContextReleaseCommand->setMessageType();
......@@ -1574,8 +1658,7 @@ void amf_n2::handle_itti_message(itti_handover_notify& itti_msg) {
int encoded_size =
ueContextReleaseCommand->encode2buffer(buffer, BUFFER_SIZE_1024);
bstring b = blk2bstr(buffer, encoded_size);
std::shared_ptr<nas_context> nc =
amf_n1_inst->amf_ue_id_2_nas_context(amf_ue_ngap_id);
sctp_s_38412.sctp_send_msg(unc.get()->gnb_assoc_id, 0, &b);
/*std::shared_ptr<nas_context> nc =
......
......@@ -55,5 +55,7 @@ class pdu_session_context {
snssai_t snssai;
plmn_t plmn;
std::string smf_context_location;
bool is_ho_accepted;
};
#endif
......@@ -30,14 +30,17 @@ extern "C" {
using namespace std;
namespace ngap {
DownlinkRANStatusTransfer::DownlinkRANStatusTransfer() {
amfUeNgapId = NULL;
ranUeNgapId = NULL;
ranStatusTransfer_TransparentContainer = NULL;
DownlinkranstatustransferIEs = NULL;
DownlinkranstatustransferPDU = NULL;
amfUeNgapId = nullptr;
ranUeNgapId = nullptr;
ranStatusTransfer_TransparentContainer = nullptr;
DownlinkranstatustransferIEs = nullptr;
DownlinkranstatustransferPDU = nullptr;
}
DownlinkRANStatusTransfer::~DownlinkRANStatusTransfer() {}
void DownlinkRANStatusTransfer::setAmfUeNgapId(unsigned long id) {
if (!amfUeNgapId) amfUeNgapId = new AMF_UE_NGAP_ID();
amfUeNgapId->setAMF_UE_NGAP_ID(id);
......@@ -61,6 +64,7 @@ void DownlinkRANStatusTransfer::setAmfUeNgapId(unsigned long id) {
if (ret != 0) cout << "encode AMF_UE_NGAP_ID IE error" << endl;
// free_wrapper((void**) &ie);
}
void DownlinkRANStatusTransfer::setRanUeNgapId(uint32_t id) {
if (!ranUeNgapId) ranUeNgapId = new RAN_UE_NGAP_ID();
ranUeNgapId->setRanUeNgapId(id);
......@@ -152,6 +156,7 @@ void DownlinkRANStatusTransfer::setRANStatusTransfer_TransparentContainer(
free_wrapper((void**) &ie);
*/
}
void DownlinkRANStatusTransfer::setmessagetype() {
if (!DownlinkranstatustransferPDU) {
DownlinkranstatustransferPDU =
......@@ -180,6 +185,7 @@ void DownlinkRANStatusTransfer::setmessagetype() {
<< endl;
}
}
int DownlinkRANStatusTransfer::encodetobuffer(uint8_t* buf, int buf_size) {
asn_fprint(stderr, &asn_DEF_Ngap_NGAP_PDU, DownlinkranstatustransferPDU);
asn_enc_rval_t er = aper_encode_to_buffer(
......
......@@ -41,25 +41,31 @@ using namespace std;
namespace ngap {
HandoverCommandMsg::HandoverCommandMsg() {
amfUeNgapId = NULL;
ranUeNgapId = NULL;
ngap_handovertype = NULL;
NASSecurityParametersFromNGRAN = NULL;
PDUSessionResourceHandoverList = NULL;
PDUSessionResourceToReleaseListHOCmd = NULL;
TargetToSource_TransparentContainer = NULL;
CriticalityDiagnostics = NULL;
handoverCommandPdu = NULL;
handoverCommandIEs = NULL;
amfUeNgapId = nullptr;
ranUeNgapId = nullptr;
ngap_handovertype = nullptr;
NASSecurityParametersFromNGRAN = nullptr;
PDUSessionResourceHandoverList = nullptr;
PDUSessionResourceToReleaseListHOCmd = nullptr;
TargetToSource_TransparentContainer = nullptr;
CriticalityDiagnostics = nullptr;
handoverCommandPdu = nullptr;
handoverCommandIEs = nullptr;
}
HandoverCommandMsg::~HandoverCommandMsg() {}
unsigned long HandoverCommandMsg::getAmfUeNgapId() {
if (amfUeNgapId) return amfUeNgapId->getAMF_UE_NGAP_ID();
if (amfUeNgapId)
return amfUeNgapId->getAMF_UE_NGAP_ID();
else
return 0;
}
uint32_t HandoverCommandMsg::getRanUeNgapId() {
if (ranUeNgapId) return ranUeNgapId->getRanUeNgapId();
if (ranUeNgapId)
return ranUeNgapId->getRanUeNgapId();
else
return 0;
}
bool HandoverCommandMsg::decodefrompdu(Ngap_NGAP_PDU_t* ngap_msg_pdu) {
......
......@@ -40,21 +40,27 @@ using namespace std;
namespace ngap {
HandoverPreparationFailure::HandoverPreparationFailure() {
amfUeNgapId = NULL;
ranUeNgapId = NULL;
cause = NULL;
hoPreparationFailureIEs = NULL;
CriticalityDiagnostics = NULL;
amfUeNgapId = nullptr;
ranUeNgapId = nullptr;
cause = nullptr;
hoPreparationFailureIEs = nullptr;
CriticalityDiagnostics = nullptr;
}
HandoverPreparationFailure::~HandoverPreparationFailure() {}
unsigned long HandoverPreparationFailure::getAmfUeNgapId() const {
if (amfUeNgapId) return amfUeNgapId->getAMF_UE_NGAP_ID();
if (amfUeNgapId)
return amfUeNgapId->getAMF_UE_NGAP_ID();
else
return 0;
}
uint32_t HandoverPreparationFailure::getRanUeNgapId() const {
if (ranUeNgapId) return ranUeNgapId->getRanUeNgapId();
if (ranUeNgapId)
return ranUeNgapId->getRanUeNgapId();
else
return 0;
}
bool HandoverPreparationFailure::decodefrompdu(Ngap_NGAP_PDU_t* ngap_msg_pdu) {
......
......@@ -40,24 +40,27 @@ using namespace std;
namespace ngap {
HandoverRequest::HandoverRequest() {
amfUeNgapId = NULL;
handovertype = NULL;
cause = NULL;
ueAggregateMaximumBitRate = NULL;
ueSecurityCapabilities = NULL;
SecurityContext = NULL;
PDUSessionResourceSetupList = NULL;
allowedNSSAI = NULL;
SourceToTarget_TransparentContainer = NULL;
mobilityrestrictionlist = NULL;
guami = NULL;
handoverRequestPdu = NULL;
handoverRequestIEs = NULL;
amfUeNgapId = nullptr;
handovertype = nullptr;
cause = nullptr;
ueAggregateMaximumBitRate = nullptr;
ueSecurityCapabilities = nullptr;
SecurityContext = nullptr;
PDUSessionResourceSetupList = nullptr;
allowedNSSAI = nullptr;
SourceToTarget_TransparentContainer = nullptr;
mobilityrestrictionlist = nullptr;
guami = nullptr;
handoverRequestPdu = nullptr;
handoverRequestIEs = nullptr;
}
HandoverRequest::~HandoverRequest() {}
unsigned long HandoverRequest::getAmfUeNgapId() {
if (amfUeNgapId) return amfUeNgapId->getAMF_UE_NGAP_ID();
if (amfUeNgapId)
return amfUeNgapId->getAMF_UE_NGAP_ID();
else
return 0;
}
/*bool HandoverRequest::decodefrompdu(Ngap_NGAP_PDU_t *ngap_msg_pdu)
......
......@@ -100,6 +100,8 @@ void HandoverRequiredMsg::getTAI(TAI*& ptr) {
OCTET_STRING_t HandoverRequiredMsg::getSourceToTarget_TransparentContainer() {
if (SourceToTarget_TransparentContainer)
return *SourceToTarget_TransparentContainer;
else
return OCTET_STRING_t();
}
bool HandoverRequiredMsg::getPDUSessionResourceList(
......@@ -128,6 +130,8 @@ bool HandoverRequiredMsg::getPDUSessionResourceList(
long HandoverRequiredMsg::getDirectForwardingPathAvailability() {
if (directforwardingPathAvailability)
return *directforwardingPathAvailability;
else
return 0;
}
bool HandoverRequiredMsg::decodefrompdu(Ngap_NGAP_PDU_t* ngap_msg_pdu) {
......
......@@ -32,27 +32,38 @@
using namespace std;
namespace ngap {
UplinkRANStatusTransfer::UplinkRANStatusTransfer() {
amfUeNgapId = NULL;
ranUeNgapId = NULL;
ranStatusTransfer_TransparentContainer = NULL;
amfUeNgapId = nullptr;
ranUeNgapId = nullptr;
ranStatusTransfer_TransparentContainer = nullptr;
UplinkRANStatusTransferPDU = nullptr;
UplinkRANStatusTransferIEs = nullptr;
}
UplinkRANStatusTransfer::~UplinkRANStatusTransfer() {}
unsigned long UplinkRANStatusTransfer::getAmfUeNgapId() {
return amfUeNgapId->getAMF_UE_NGAP_ID();
if (amfUeNgapId)
return amfUeNgapId->getAMF_UE_NGAP_ID();
else
return 0;
}
uint32_t UplinkRANStatusTransfer::getRanUeNgapId() {
return ranUeNgapId->getRanUeNgapId();
if (ranUeNgapId)
return ranUeNgapId->getRanUeNgapId();
else
return 0;
}
void UplinkRANStatusTransfer::getRANStatusTransfer_TransparentContainer(
RANStatusTransferTransparentContainer*&
ranstatustransfer_transparentcontainer) {
ranstatustransfer_transparentcontainer =
ranStatusTransfer_TransparentContainer;
}
bool UplinkRANStatusTransfer::defromPDU(Ngap_NGAP_PDU_t* ngap_msg_pdu) {
UplinkRANStatusTransferPDU = ngap_msg_pdu;
if (UplinkRANStatusTransferPDU->present ==
......
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