Files
ueransim/src/gnb/ngap/task.cpp
2025-09-11 06:16:32 +00:00

151 lines
4.5 KiB
C++
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//
// 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