151 lines
4.5 KiB
C++
Executable File
151 lines
4.5 KiB
C++
Executable File
//
|
||
// This file is a part of UERANSIM project.
|
||
// Copyright (c) 2023 ALİ GÜNGÖR.
|
||
//
|
||
// https://github.com/aligungr/UERANSIM/
|
||
// See README, LICENSE, and CONTRIBUTING files for licensing details.
|
||
//
|
||
|
||
#include "task.hpp"
|
||
|
||
#include <sstream>
|
||
|
||
#include <gnb/app/task.hpp>
|
||
#include <gnb/sctp/task.hpp>
|
||
|
||
namespace nr::gnb
|
||
{
|
||
|
||
// 切换清理定时器
|
||
static constexpr const int TIMER_ID_HANDOVER_CLEANUP = 3001;
|
||
static constexpr const int TIMER_PERIOD_HANDOVER_CLEANUP = 5000; // 5秒检查一次
|
||
|
||
NgapTask::NgapTask(TaskBase *base) : m_base{base}, m_ueNgapIdCounter{}, m_ueIdCounter{100}, m_downlinkTeidCounter{}, m_isInitialized{}
|
||
{
|
||
m_logger = base->logBase->makeUniqueLogger("ngap");
|
||
}
|
||
|
||
void NgapTask::onStart()
|
||
{
|
||
for (auto &amfConfig : m_base->config->amfConfigs)
|
||
createAmfContext(amfConfig);
|
||
if (m_amfCtx.empty())
|
||
m_logger->warn("No AMF configuration is provided");
|
||
|
||
for (auto &amfCtx : m_amfCtx)
|
||
{
|
||
auto msg = std::make_unique<NmGnbSctp>(NmGnbSctp::CONNECTION_REQUEST);
|
||
msg->clientId = amfCtx.second->ctxId;
|
||
msg->localAddress = m_base->config->ngapIp;
|
||
msg->localPort = 0;
|
||
msg->remoteAddress = amfCtx.second->address;
|
||
msg->remotePort = amfCtx.second->port;
|
||
msg->ppid = sctp::PayloadProtocolId::NGAP;
|
||
msg->associatedTask = this;
|
||
m_base->sctpTask->push(std::move(msg));
|
||
}
|
||
|
||
// 启动切换清理定时器
|
||
setTimer(TIMER_ID_HANDOVER_CLEANUP, TIMER_PERIOD_HANDOVER_CLEANUP);
|
||
}
|
||
|
||
void NgapTask::onLoop()
|
||
{
|
||
auto msg = take();
|
||
if (!msg)
|
||
return;
|
||
|
||
switch (msg->msgType)
|
||
{
|
||
case NtsMessageType::TIMER_EXPIRED: {
|
||
auto &w = dynamic_cast<NmTimerExpired &>(*msg);
|
||
if (w.timerId == TIMER_ID_HANDOVER_CLEANUP) {
|
||
checkAndCleanupExpiredHandovers();
|
||
setTimer(TIMER_ID_HANDOVER_CLEANUP, TIMER_PERIOD_HANDOVER_CLEANUP);
|
||
}
|
||
break;
|
||
}
|
||
case NtsMessageType::GNB_RRC_TO_NGAP: {
|
||
auto &w = dynamic_cast<NmGnbRrcToNgap &>(*msg);
|
||
switch (w.present)
|
||
{
|
||
case NmGnbRrcToNgap::INITIAL_NAS_DELIVERY: {
|
||
handleInitialNasTransport(w.ueId, w.pdu, w.rrcEstablishmentCause, w.sTmsi);
|
||
break;
|
||
}
|
||
case NmGnbRrcToNgap::UPLINK_NAS_DELIVERY: {
|
||
handleUplinkNasTransport(w.ueId, w.pdu);
|
||
break;
|
||
}
|
||
case NmGnbRrcToNgap::RADIO_LINK_FAILURE: {
|
||
handleRadioLinkFailure(w.ueId);
|
||
break;
|
||
}
|
||
case NmGnbRrcToNgap::HANDOVER_TRIGGER: {
|
||
// 处理来自RRC的切换触发
|
||
triggerHandover(w.ueId, w.targetCellId, w.targetGnbId);
|
||
break;
|
||
}
|
||
case NmGnbRrcToNgap::HANDOVER_REQUEST_ACK: {
|
||
// 处理来自RRC的切换请求确认
|
||
sendHandoverRequestAcknowledge(w.ueId, w.sourceToTargetContainer);
|
||
break;
|
||
}
|
||
case NmGnbRrcToNgap::HANDOVER_REQUEST_FAILURE: {
|
||
// 处理来自RRC的切换请求失败
|
||
m_logger->err("RRC reported handover request failure for UE {}", w.ueId);
|
||
// 清理切换上下文
|
||
auto *ueCtx = findUeContext(w.ueId);
|
||
if (ueCtx) {
|
||
// 删除为切换创建的UE上下文
|
||
deleteUeContext(w.ueId);
|
||
m_logger->info("Cleaned up UE context {} due to handover failure", w.ueId);
|
||
}
|
||
break;
|
||
}
|
||
case NmGnbRrcToNgap::HANDOVER_RRC_COMPLETE: {
|
||
// UE已在目标侧完成RRC重配置,正式发起Path Switch
|
||
sendPathSwitchRequest(w.ueId);
|
||
break;
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
case NtsMessageType::GNB_SCTP: {
|
||
auto &w = dynamic_cast<NmGnbSctp &>(*msg);
|
||
switch (w.present)
|
||
{
|
||
case NmGnbSctp::ASSOCIATION_SETUP:
|
||
handleAssociationSetup(w.clientId, w.associationId, w.inStreams, w.outStreams);
|
||
break;
|
||
case NmGnbSctp::RECEIVE_MESSAGE:
|
||
handleSctpMessage(w.clientId, w.stream, w.buffer);
|
||
break;
|
||
case NmGnbSctp::ASSOCIATION_SHUTDOWN:
|
||
handleAssociationShutdown(w.clientId);
|
||
break;
|
||
default:
|
||
m_logger->unhandledNts(*msg);
|
||
break;
|
||
}
|
||
break;
|
||
}
|
||
default: {
|
||
m_logger->unhandledNts(*msg);
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
void NgapTask::onQuit()
|
||
{
|
||
for (auto &i : m_ueCtx)
|
||
delete i.second;
|
||
for (auto &i : m_amfCtx)
|
||
delete i.second;
|
||
m_ueCtx.clear();
|
||
m_amfCtx.clear();
|
||
}
|
||
|
||
} // namespace nr::gnb
|